
1. 这次拆解什么从“能对话”到“能落地”上篇把基座模型选型、API接入和一轮对话的最小闭环讲完了。结果后台私信最多的不是“怎么把模型接进来”而是“接进来之后怎么让它真正扛得住业务”。这其实是所有LLM聊天助手项目最尴尬的阶段Demo跑得通一上生产就露馅——答非所问、上下文一长就乱、token烧钱快、出了问题还不知道怎么查。这篇《拆解二》就是冲着这几个痛点来的。我会按我自己实际做项目的顺序拆四块硬骨头上下文与Token管理、RAG知识库接入、工具调用与质量评估、网关与部署优化。每一块都会给出可直接抄作业的参数、代码片段和排障经验适合那种“已经有一个能跑的基础版想往生产级推进一步”的团队和个人开发者。先交代一句我这边项目的基本盘是基座模型走API主力是GPT类也接了开源的Qwen系做分流业务场景是“企业知识问答工单辅助”日均对话量在几千到几万轮之间。这个量级不算大但足够把那些“小规模跑不出来、大规模立刻爆”的问题全部暴露一遍。下面讲的所有坑都是在这个量级下真实踩过的。1.1 上一版留下的四个问题第一版聊天助手其实只有三个模块前端对话框、后端转发服务、模型API。看起来能用了但上线两周就发现四类问题。第一个是上下文一长就“失忆”。用户问十轮之后模型开始忘掉最开始的需求回答质量断崖式下跌。原因很直接我们把整段历史都塞进上下文既没有裁剪也没有压缩长文本把注意力稀释了。第二个是知识时效性完全没解决。模型训练数据有截止日期公司内部文档、最新政策、产品变更一概不知道。你问它“上个月发布的退款规则”它只能一本正经地编。第三个是成本不可控。一次长对话动辄消耗几千token用户没问几个问题账单先涨起来了。而且流量一上来同一个用户反复问相同的问题缓存完全没做等于白扔钱。第四个是没法评估。改了一版Prompt到底是变好了还是变坏了全凭感觉。没有测试集、没有评分标准回归完全靠人工肉眼扫几十条对话效率极低。这四个问题就是这版架构升级要解决的核心目标。后面所有设计决策都是围绕“可观测、可控制、可评估”这三个词展开的。1.2 新版架构的分层设计与选型逻辑新版我拆成了五层每一层只干一件事层与层之间全部走标准接口。这样做的原因很简单LLM领域变化太快模型、框架、向量库几乎三个月换一轮如果模块之间耦合太紧任何一次升级都会牵一发动全身。接入层负责鉴权、限流、API Key管理统一对接多个模型提供商支持主备切换。编排层这是最核心的一层负责意图识别、上下文组装、工具调用调度、结果整合。所有Prompt模板和业务逻辑都在这一层。知识层向量库、文档解析、索引任务、RAG检索服务对外只暴露一个“检索(query) - 返回chunk列表”的接口。评估层Golden Set测试集、LLM as Judge评分服务、回归报告生成每次上线前自动跑一遍。可观测层全链路日志、Token消耗统计、延迟监控、用户反馈采集。为什么要把“评估层”单独提出来当一层我见过太多项目把评估当成上线前的一次性动作跑完一遍就再也不管了。实际上LLM应用最需要的恰恰是持续回归——因为Prompt改了、模型厂商升级了、知识库更新了任何一个环节变化都可能让整体表现下降。把评估做成独立服务才能做到每次改动都自动触发回归。网关这层我放在了接入层里。一开始我们直接用SDK直连模型API后来发现多个业务方共用一个Key没法分账、没法限流、没法单独查某个业务方的调用日志才意识到网关不是可选项是必需品。这个后面第6章单独展开。2. 上下文与Token管理把每轮对话的成本算明白这一块是聊天助手项目中“看起来简单、做起来全是坑”的典型。很多人觉得上下文不就是把历史消息拼起来发给模型吗真这么干账单和效果会一起教育你。2.1 先理解Token计费、窗口与KQV三层心智模型Token是模型处理文本的基本单位既不是字也不是词。英文里一个词通常拆成1到2个token中文一个汉字大约对应0.6到1.5个token取决于分词方式。我自己实测过一批中文文本常见的“cl100k_base”编码器下平均一个汉字约等于1.3个token。这意味着1万字的上下文约等于1.3万token按现在主流API价格算单是输入成本就是一笔不小的钱。这里要引入一个我后来一直在用的心智模型也是在社区里看到的一个特别精辟的说法LLM交互可以拆成三个点——Key我是谁、Query我在找什么、Value我能提供什么。Key模型的角色设定和身份。放在系统提示词里告诉模型“你是客服助手你的语气是……”。Query用户当下的真实意图。这是每轮对话中变化最快、最需要识别的部分。Value为了回答这个问题你需要提供给模型的支撑材料。这就是检索出来的知识片段、历史上下文、工具返回结果。别小看这个三分法。它直接决定了你怎么组织Prompt、怎么裁剪上下文。凡是回答质量不稳定的对话你拿这三个点一套多半能定位出问题要么Key没写清楚模型不知道自己是干嘛的要么Query被历史噪音淹没最新意图没被突出要么Value给得不够或者太杂模型抓不住重点。Token成本公式也值得记一下。单轮调用成本大致是(系统提示词 历史消息 检索内容 用户当前消息) × 输入单价 输出token数 × 输出单价。系统提示词和检索内容是每轮都要付的固定开销历史消息是随对话长度线性增长的变量所以省钱和提质的核心都落在“控制历史消息”和“压缩检索内容”上。2.2 三种上下文策略滑动窗口、摘要与裁剪我在项目里实际验证过三种策略分别适合不同场景。第一种是滑动窗口只保留最近N轮对话。实现最简单效果也最直接。我用的窗口大小是最近8轮也就是大约16条消息用户助手各算一条。超过窗口的旧消息直接丢弃。好处是Token占用稳定坏处是用户隔了很久回来问“我之前说的那个需求还记得吗”模型就懵了。第二种是滚动摘要。每次对话达到窗口上限时把即将被丢掉的旧消息交给模型总结成一两句话存入一个“长期记忆摘要”字段下一轮再把摘要加回系统提示词。这个策略适合那种需要跨很多轮记住用户偏好、但不需要逐字回忆细节的场景比如“用户偏好简洁回答”“用户之前提到过公司规模是200人”。第三种是按相关性裁剪。不按轮次切而是交给一个轻量分类模型判断每条历史消息对当前问题的相关性只保留Top K条。这个效果最好但成本最高适合历史特别长、问题又高度依赖前后文的场景比如法务咨询、技术支持排查。实际项目里我采用的是“滑动窗口滚动摘要”的组合窗口保持8轮另设一个容量为500词的摘要区。摘要不是每轮都重新生成而是每新增5轮对话触发一次增量摘要更新把老摘要和新增消息一起交给模型重写。这样既控制成本又能保住长期记忆。这里给一个实用参数模板直接照抄也能用参数建议值说明滑动窗口轮数6~8轮超过8轮后质量提升边际递减摘要触发频率每5轮太频繁费钱太稀疏会丢信息摘要上限400~600词控制固定开销单轮最大输出token512~1024防止模型废话连篇2.3 缓存设计语义缓存与Prompt缓存Token优化里最容易被忽略的是缓存。我见过不少项目同一个用户连续三次问“退款周期是多久”每次都完整走一遍“拼Prompt - 调模型 - 解析返回”三次烧了三份钱。其实这种高频重复问题完全可以用缓存吞掉。我做的第一层是语义缓存。把用户query做embedding和缓存池里的历史query算余弦相似度超过0.95就直接返回缓存回答不再调模型。用的是cachetools的TTLCache加上一个简单的向量检索TTL设了10分钟。实测下来高峰期命中率能到15%~25%这部分钱等于是白捡的。第二层是Prompt缓存。现在主流模型API基本都支持对系统提示词做服务端缓存也就是同一段前缀在短时间内多次调用只收一次处理费。做法是把系统提示词、角色设定、固定few-shot示例放在Prompt最前面保证前缀一致。我踩过一个坑为了动态插入用户姓名模板引擎一开始把变量放在系统提示词中间导致前缀每次都变缓存完全失效。后来把所有动态变量全部移到用户消息那一侧系统提示词固定不变缓存命中率立刻上来了。3. RAG与GraphRAG让助手真正读懂你自己的资料知识库接入是聊天助手从“玩具”变成“工具”的分水岭。不做RAG模型只会一本正经地胡说做了RAG至少能把答案锚定在你给的资料里。3.1 为什么绕不开RAG模型的知识截止日期是硬伤企业内部资料更是模型在训练时根本接触不到的东西。有人问能不能把资料全部塞进上下文可以但你有多少资料一个中大型企业随便就是几百份文档几十万字别说放不进上下文窗口就算硬塞进去模型也会被大量无关信息干扰。RAG的思路是用“检索”代替“回忆”先把知识库切成小块、向量化用户提问时先从库里检索出最相关的几块拼进Prompt再让模型基于这些内容作答。这个过程本质上是在给模型递答案小抄而不是逼它全背下来。我见过最典型的翻车案例部门领导嫌RAG麻烦直接把10万字的规章制度全文塞进Prompt让模型“基于以下内容回答”。结果模型既抓不住重点还经常引用不相干章节回答质量远不如用RAG检索5个片段的效果。检索不是越多越好精炼的Top K永远优于海量原文。3.2 一条能落地的RAG链路完整的RAG链路分为离线索引和在线检索两段。离线索引负责把资料库变成可检索的向量索引在线检索负责实时寻找相关内容。我逐个环节讲配置和参数。离线索引第一步是文档解析。不同格式用不同工具PDF用PyMuPDFWord用python-docxMarkdown直接读文本扫描件得先OCR。这里有个容易被忽视的细节表格要单独处理直接按纯文本抽取会把行列关系打乱。我们的做法是把表格转成Markdown格式再进索引检索效果明显提升。第二步是切块。这是RAG里最影响效果的单点因素。块太大检索出来噪音多、token浪费块太小语义不完整模型看不懂上下文。我试过从200到2000字符的一系列块大小最终稳定在450~600字符重叠50~100字符。同时做了“语义边界切分”优先在段落结尾、标题处切而不是硬按字符数切。方法是先按段落粗切段落超过上限再回退到按句子切这样能保证每个chunk至少是一个语义完整的小单元。第三步是Embedding选型。中文场景不要直接用通用英文向量模型效果差得离谱。我这边对比过几个主流中文Embedding模型最终选了性价比合适的中文embedding模型维度1024把每条资料和查询都编码成向量存进向量数据库做近似检索。这里给一个配置速查参数建议值说明chunk_size450~600字符需要按实际语料微调chunk_overlap50~100字符防止语义被拦腰截断embedding维度1024维度越高精度越好但存储和延迟也更高top_k4~6检索结果太少答不全太多噪音大相似度阈值0.45~0.5低于阈值视为无答案宁可不答也别瞎编在线检索段我用的是“向量检索BM25关键词检索”的双路召回再把两路结果合并用Rerank模型重排。为什么这么做向量检索擅长语义匹配但遇到精确的产品编号、政策条款号就很吃力BM25正好互补能精准匹配字面词。合并后取Top K再交给Rerank模型打分排序最终只把前4~6个chunk拼进Prompt。3.3 GraphRAG和本体增强要不要上市面上的GraphRAG讨论度很高原理是把知识库内容抽取成实体和关系构建知识图谱再基于图谱检索。它的优势在于回答“全局性问题”比如“我们公司所有产品线里哪些涉及数据安全”而普通RAG擅长“局部性问题”比如“退款政策是什么”。全局性问题需要跨文档整合向量检索天然不擅长GraphRAG正好补上这个短板。但代价也很现实GraphRAG的索引阶段非常消耗算力和时间。一个小型知识库跑一次实体抽取和关系构建可能就要几小时甚至几十小时而且成本高。我这个项目里知识量不算小所以没有整体上GraphRAG而是做了一个“轻量本体”方案给每条知识打业务标签比如“合同”“退款”“物流”检索时先用一个轻量分类器识别用户问题所属标签再限定到对应标签的子集合里去检索。这个做法我们内部叫“本体约束的RAG”效果提升明显成本却几乎没增加。如果你也在纠结要不要上GraphRAG我的建议是先把你最痛的问题类型列出来如果绝大多数是“单一文档内的细节查询”普通RAG足够别给自己找麻烦如果确实有大量“跨文档归纳总结”的需求再考虑GraphRAG而且要提前做好计算资源预算。4. Prompt工程与工具调用从“答得对”到“做得成”聊天助手光会回答问题是不够的很多时候用户要的是“办成一件事”比如查一下订单状态、发起一笔退款、创建一个工单。这就涉及两个能力把意图理解清楚以及把动作执行到位。4.1 系统提示词的结构化写法我见过太多团队把系统提示词写成一段意识流“你是一个友好的AI助手你要帮助用户解决问题回答要详细、要准确……”这种写法等于没写。系统提示词应该像一份岗位说明书结构化、可检查、可版本管理。我现在用的模板分四段角色定位你是谁、你的边界、行为规范能做什么、不能做什么、输出格式何时用纯文本、何时用结构化数据、参考材料检索到的知识片段放在什么位置。每段之间用明确的标记词分隔这样既方便模型遵循也方便我们自己调试和做版本diff。这里还要强调一下第2章那个KQV模型的实战用法。系统提示词主体就是“Key”部分用来定义“我是谁”用户问题经过意图识别后把核心诉求提炼出来放在Prompt醒目位置就是“Query”检索资料和工具返回结果统一放在“Value”区域。三个区域物理隔离、职责清晰模型很少再出现“读了一大段资料却不知道用户到底要什么”的情况。另外few-shot示例不要贪多。我测试过3到5个高质量示例带来的效果提升最明显超过10个示例后边际收益极小反而白白吃掉大量上下文token。示例也要挑“难例”就是那些模型容易搞错的边界情况而不是简单重复正确套路。4.2 Function Calling与工具Schema的坑工具调用是让助手真正“做事”的关键。主流程是模型根据用户请求生成一个结构化的工具调用请求你的服务端收到后执行真实函数再把结果返回给模型继续生成最终回答。这个流程里最容易出问题的就是工具Schema定义。几乎所有主流模型API都把工具参数定义为JSON Schema格式要求必须是“type为object、包含properties字段、必要时声明required”。我踩过的最典型的坑是某个工具的参数里引用了其他的Schema定义用的是$ref方式结果调用时直接收到报错提示llm request failed: provider rejected the request schema or tool payload.。原因就是部分模型提供商不支持$ref解析必须把嵌套Schema全部内联展开。另一个高频坑是空参数工具。有些工具确实不需要参数比如“获取当前时间”你在Schema里写了parameters: {type: object, properties: {}}有些模型API会直接拒绝要求至少有一个有效属性。我的解法是给这类工具加一个固定参数比如{request_id: {type: string, description: 请求追踪ID}}既满足Schema要求又顺手拿到追踪信息。还有一类问题是参数类型与真实函数不匹配。模型生成的参数值偶尔会出现字符串被填入整数类型字段、枚举值超出你定义范围的情况。服务端必须做一层严格校验不能直接把模型输出透传给真实函数。我在所有工具入口加了一个统一校验器用pydantic定义每个工具的参数模型校验不过就返回一个标准错误提示给模型让它重新生成。实测这个环节能拦截掉约5%~8%的脏调用。4.3 工具调用回合的流程控制工具调用通常不是一次就结束的。比如“帮我查最近一个订单然后退款”可能先要调用“查订单”工具拿到订单号再调用“退款”工具。这要求服务端实现一个工具调用循环模型请求工具 - 执行工具 - 把结果返回给模型 - 模型可能再次请求工具或生成最终回答。这个循环必须设定上限否则模型可能陷入无限循环。我的经验值是最多5轮工具调用达到上限后强制让模型基于已有信息回答。同时每轮工具调用的结果都要记录到日志里方便事后排查“模型为什么做出一连串奇怪操作”。工具返回的内容也要控制大小。有一次我们让工具返回了一个完整订单的全部字段包括一堆我们根本用不到的内部状态码token直接翻倍模型还容易被无关字段误导。后来约定所有工具返回只保留关键字段原则上不超过200个token效果立竿见影。5. 质量评估与自动化测试用LLM as Judge把回归跑起来这一步是我认为整个项目里投入产出比最高的一环但也是绝大多数团队最不愿意做的一环。原因很简单写评估脚本不产生“可见成果”而且没有代码评审会去检查评估覆盖率。但恰恰是这一步决定了你后续每一次Prompt调整是“优化”还是“翻车”。5.1 手工回归为什么不够没有评估体系的时候我们改Prompt全靠肉眼抽查20条对话觉得“看起来不错”就上线。结果经常是改完之后A类问题变好了B类问题悄悄变差了而B类问题恰好是线上最常出现的场景。手工回归的局限在于样本量太小、标准不统一、不可重复。你今天觉得“这个回答不错”下周可能就因为心情或疲劳觉得“不行”。所以必须把评估标准化、自动化。我的做法是建立三个层次的测试单元测试针对纯函数逻辑比如工具调用参数解析、Token计数器、chunk切分器。这些不依赖模型跑得快、发现问题准。集成测试给定输入走完整个RAG编排流程断言返回内容是否包含关键信息。这类测试需要调模型成本较高但覆盖面广。Golden Set回归固定100条带有参考答案的评测问题每次改动后用LLM as Judge批量打分输出分数对比报告。5.2 搭一套LLM as Judge评估管线LLM as Judge的核心思想是用一个大模型扮演评委对候选回答按预定义维度打分。为什么不用计算指标如ROUGE、BLEU因为聊天助手的回答是开放式的没有标准答案文本可以硬比对语义层面的好坏必须靠同样具备语义理解能力的模型来判断。评估Prompt我用的是这种格式你是对话质量评估员。请根据以下三个维度为模型回答打分0-5分 1. 准确性回答是否有事实错误是否与检索资料一致 2. 完整性是否覆盖用户问题的所有要点 3. 可读性语言是否通顺、结构是否清晰 用户问题... 检索资料... 模型回答... 输出JSON格式{score: 分数, dimensions: {准确性: 分, 完整性: 分, 可读性: 分}, reason: 一句话理由}这里有几个使用了才发现的关键细节。第一不能只给模型回答不给检索资料。没有参考答案的模型很可能因为“编得流畅”而给高分必须把检索内容一并提供让Judge核对回答是否忠实于资料。第二给Judge设定严格的分数锚点。0分代表“完全答非所问”5分代表“可以直接发给客户”中间档位要有行为描述否则Judge会倾向打3到4分区分度极差。第三也是最重要的同一个Judge模型不能和回答模型完全一样。如果回答模型和Judge模型是同一种会出现轻微的“自我偏好”倾向也就是给自己的输出打高分。我的做法是回答用主力模型Judge用另一家或另一档的模型并在打分时把两边的身份都匿名化只标“回答A”“回答B”。5.3 基于LLM的单元测试与CI集成很多人一听“LLM单元测试”就觉得没法做因为输出不确定。但换个思路就通了不是去断言模型生成的文本而是去断言围绕模型的核心逻辑。举个真实例子。我们的编排层有一段代码负责从模型返回里解析工具调用。正常情况下模型会返回一段JSON但偶尔会包裹在Markdown代码块里或者有多余的前后空白。解析失败时整个流程会中断。这类函数就可以做单元测试def test_parse_tool_call_with_markdown_wrapper(): raw json\n{name: search_kb, arguments: {query: 退款政策}}\n result parse_tool_call(raw) assert result[name] search_kb assert result[arguments][query] 退款政策这种测试不需要调任何模型纯函数逻辑跑在CI里毫秒级完成但能防住最经典的“模型输出格式漂移”问题。另外我还给编排层做了超时控制测试、工具参数校验测试、上下文裁剪边界测试都属于这一类。模型行为的回归则交给Golden Set来完成。我们团队的做法是每次改动Prompt、RAG参数或工具定义就在CI里跑一遍100条评测集Judge给出平均分和分维度明细低于上一版本0.2分就自动阻止合并。一开始大家嫌麻烦后来发现这套机制帮我们拦下了至少五次本会上线的质量回退值回票价。6. 部署优化网关、ONNX与成本平衡当聊天助手从实验走向生产部署层的优化决定你每个月的账单数字和用户的等待时长。这一章讲三块网关解决的是什么问题本地部署模型什么时候值得做以及怎么在成本和速度之间找平衡。6.1 LLM网关解决的问题早期我图省事所有服务直接拿着API Key调模型SDK。后来问题一堆多个环境共用一个Key没法分账某家模型提供商出故障没有自动切换机制想查某个业务线的调用量和延迟日志散落在不同服务里根本统计不了。于是搭了一个轻量网关层所有模型调用统一走它。网关的核心功能有四块Key管理与鉴权一个网关统一管理上游Key业务方只能用网关分发的Key、路由与负载均衡按业务线、按模型价格档位路由请求支持主备切换、限流与配额每个业务方有独立的每分钟调用上限、可观测性记录每次调用的模型、token数、延迟、错误码统一输出到日志平台。开源方案里LiteLLM这类网关中间件已经能做大部分功能直接架在业务服务和模型API之间省去自己造轮子。选型时要留意网关本身不能成为性能瓶颈。我们压测过网关转发带来的额外延迟大约在5到15毫秒对聊天场景几乎无感但如果你自己写网关逻辑还带数据库查询可能直接把这个数字放大十倍。网关要尽量做无状态转发需要持久化的数据统统交给下游日志系统。还有一个细节多个模型API的响应格式并不一致。网关层最好统一把响应转成OpenAI兼容格式业务服务永远只面对一个标准接口。这样以后换模型提供商只需要改网关配置业务代码一行都不用动。6.2 ONNX部署本地模型的取舍聊到部署很多团队会问能不能搞一个本地模型不花钱调API数据也安全。这个方向本身没错但ONNX部署LLM这个事必须有一本很清楚的账。ONNX是微软主推的开放神经网络交换格式可以把训练好的模型导出成统一的计算图再用ONNX Runtime在不同硬件上加速推理。对LLM来说好处是部署形态统一、支持CPU/GPU多种执行引擎、还有量化支持。但代价也很直接大模型在普通CPU上跑推理速度慢到无法接受。我实测下来一个1.5B参数量的中小模型用ONNX Runtime在CPU上跑int8量化生成一个token大约需要30到80毫秒生成一段100字的回答要好几秒还不算Prompt处理时间。作为对照调API的延迟通常在1到3秒内完成整段回答。所以本地ONNX部署的定位很明确只适合小模型低速实时性要求的任务。我的实际用法是“大小模型分层”把意图识别、问题分类、内容审核这类简单但高频的任务用本地的1.5B小模型跑准确率够用、延迟低、不计API费而真正面向用户的复杂问答仍然交给云端API的大模型。这样既控制了成本又保住了核心体验。如果你需要更大的7B以上模型老实上GPU或者考虑GGUF格式配合llama.cpp这类推理方案ONNX在这一点上反而不是最优选择。量化操作时的坑也得说一句量化前一定要用验证集测一遍效果。int8量化对质量的影响通常在可接受范围但int4量化会让小模型能力衰减到肉眼可见的程度。另外ONNX导出时Tokenizer容易出问题有些模型在导出后tokenizer和计算图配套不完整推理时输出乱码。我的建议是导出后用同一批测试句子跑一轮对比确保生成内容和原模型接近再考虑进生产。6.3 响应速度与成本的三板斧最后讲三个我在项目里用到、实测有效的“提速省钱”组合拳。第一板斧是流式输出。用户等待首字的时间比等待完整回答的时间敏感得多。把模型输出改成SSE流式推送给前端首字延迟能压到几百毫秒用户体感直接翻倍。这一条看起来简单但很多团队第一版都是等全部生成完再一次性返回体感差距非常大。第二板斧是模型按任务分流。不是所有请求都需要最强的模型。我们把请求分成三档意图识别和工具调度用最快的远距离小模型普通问答用中等模型复杂推理和长文本生成才用旗舰模型。网关根据路由规则自动分流。实测下来总成本降了接近30%用户体验几乎没有变化。第三板斧是给输出长度设上限。很多“废话连篇”的回答根源在于max_tokens没设或设太大模型就会放飞自我。结合业务场景我们默认把输出控制在512 token以内需要长文时再单独放开。这一项不仅省成本还让回答变得更精炼。部署优化这块整体思路就一句话能用便宜的不用贵的能缓存的别重复调能本地跑的绝不上云但前提是先用数据证明这行得通而不是拍脑袋决定。7. 排障实录与个人心得这一章把项目上线以来踩过的高频问题整理成速查表再讲几条用真金白银换来的经验。7.1 高频问题速查表现象根因解法对话变长后回答质量明显下降上下文窗口被无关历史撑爆滑动窗口滚动摘要控制历史只保留关键信息同一问题反复回答结果不一致系统提示词前缀动态变化缓存失效变量全移到用户消息侧保证提示词前缀固定检索到的内容和问题无关chunk切块把语义切碎了按段落/句子边界切块大小调到450~600字符回答编造资料里没有的信息相似度阈值太低混入了无关chunk提高阈值到0.45以上屏蔽低相关片段模型调用报schema或tool payload被拒工具Schema使用了不支持的$ref或空properties内联展开所有定义空参数工具加固定参数工具调用循环停不下来缺少调用上限控制设置最多5轮工具调用超限强制结束Judge打分和人工判断差异大Judge没看检索资料分数锚点不清晰把检索内容一起给Judge严格定义各分数行为ONNX本地模型输出乱码导出时tokenizer配套不完整导出后跑同句子对比测试必要时另配tokenizer7.2 几条用钱换不来的经验第一条从第一天就把全链路日志做起来。每条请求都要能查到走了哪个模型、输入多少token、输出多少token、检索了哪几个chunk、调用了哪个工具、耗时多少、最终评分多少。没有这套日志你后面所有优化都是盲人摸象。我们就是靠日志发现某个业务线的工具调用失败率高达15%追查半天才发现是工具Schema里一个字段名拼错了。第二条Prompt也要做版本管理。Prompt和代码一样会演进、会回滚。我们用Git管理所有Prompt模板每次改动都提交并记录改动了什么。配合Golden Set回归任何一次Prompt变更都能追溯到效果变化。第三条给用户一个“反馈入口”。在聊天界面上放“回答有用/无用”的按钮把负面反馈自动回流到评估集里。这个做法让我们的测试集从最初50条涨到了300多条而且全是线上真实场景的难例比任何团队自己编的测试问题都管用。我个人做这个项目的最大体会是LLM聊天助手的技术门槛其实不在“接模型”而在“接好之后的那一堆工程细节”。Token管理、RAG检索质量、工具调用的健壮性、评估回归的自动化每一项单独看都不算惊艳但串起来之后一个“偶尔聪明”的Demo才真正变成了“稳定可靠”的产品。如果你也正在这一阶段挣扎照着这几个方向先打基础比追任何新概念都实在。