第 42 章 调优经验总结¶
这一章和前面的章节不完全一样。前面的内容更偏系统化设计,这一章更偏实践中的经验归纳。它不追求把每个主题都讲成完整方法论,而是希望给读者一套更贴近真实工作的调优视角:当系统已经能跑,但效果、稳定性、成本或可控性还不够好时,应该先看哪里、后看哪里,以及哪些问题最容易被误判。
RAG¶
RAG 调优最容易犯的错误,是一上来就改 embedding、改 chunk 大小、改 top-k,最后把系统调成一堆参数堆砌,却仍然说不清问题到底出在哪一层。真正有效的调优,通常不是“多试几个参数”,而是先分清楚:问题到底发生在资料本身、检索链路、重排链路、上下文注入,还是最终回答阶段。
从经验上看,RAG 的绝大部分问题都可以先归到三类:
- 没找到,应该召回的内容没有进候选集。
- 找错了,进来的内容相关性不够或排序靠前的是噪声。
- 找到了,但模型没有正确使用,或者注入方式让信息价值被稀释了。
如果这三类问题没有先分开,团队很容易把“回答不好”直接归因到“检索不好”,最后在错误的层上来回调参。
flowchart TD
A["回答效果不理想"] --> B{"目标片段是否进入候选集"}
B -->|否| C["排查资料质量、切分、索引与召回"]
B -->|是| D{"目标片段排序是否足够靠前"}
D -->|否| E["排查召回策略、过滤条件与重排"]
D -->|是| F{"模型是否正确使用了检索内容"}
F -->|否| G["排查上下文装配、提示约束与引用方式"]
F -->|是| H["排查任务定义、答案模板与评测标准"]
调优前先做分层定位¶
在正式调优前,我更建议先建立一套最小观察面。至少要能看到这几个对象:
- 用户原始问题。
- 改写后的检索 query。
- 召回候选列表及其分数。
- 重排后的最终片段顺序。
- 真正注入模型的上下文。
- 最终回答及引用来源。
没有这套观察面时,调优基本只能靠猜。尤其是多轮 Agent 场景里,问题可能根本不在 RAG 本身,而在于上游把问题改写坏了,或者下游把检索结果裁掉了。
我自己的经验是,先抽一小批典型失败样本做人工复盘,比一开始就跑大规模参数搜索更值钱。只要连续看二三十条失败案例,通常就能很快判断瓶颈更像是资料问题、召回问题,还是消费问题。
如何提升召回质量¶
提升召回质量的关键,不是把某一个参数调到极致,而是沿着资料、索引、查询和排序这条链路逐层提纯。召回质量通常决定了上限,因为目标信息如果根本没进候选集,后续重排和生成都无能为力。
提升原始文档质量¶
很多团队在调 RAG 时最容易忽略原始文档质量。实际上,只要资料本身脏、碎、旧、缺上下文,后面的索引和检索再精细也只能在坏数据上做优化。
经验上最值得优先处理的是:
- 去掉明显无信息量的模板噪声,例如页脚、版权声明、重复导航、空白表格。
- 保留章节标题、目录路径、时间戳、作者、文档版本等元数据。
- 明确失效文档、历史版本和现行版本的边界,不要混在同一层语义空间里。
- 尽量把扫描件、截图 OCR 产物、格式混乱文档先做清洗,否则 embedding 质量会明显下降。
如果一篇文档在人工阅读时都很难快速定位重点,那么它通常也不适合作为高质量 RAG 资料直接入库。
还有一类很有价值的思路,是在入库前用 LLM 先对原始资料做一次“知识增强”,把原本不利于检索和消费的非结构化内容,转换成更标准、更稳定的知识表达形式。例如:
- 把长段制度说明抽取成标准问答对。
- 把会议纪要整理成“结论 - 依据 - 待确认项”结构。
- 把产品说明文档转成按功能点、限制条件、适用范围组织的知识块。
- 把一线支持记录归纳成 FAQ、错误码解释和处理步骤。
这种做法的核心价值,不是让 LLM 直接替代原文,而是把“原始文档难检索、难切分、难消费”的问题前移处理。对很多非结构化资料来说,原文更适合人读,却不一定适合被检索系统稳定消费;如果先把它转成标准 QA、术语表、步骤卡片或结构化摘要,再进入索引,后续召回和回答质量往往会明显稳定。
但这类知识增强要特别注意两个边界:
- 增强结果最好和原文保持可追溯关系,不能只留下改写结果却丢掉原始依据。
- 不要默认 LLM 抽取一定正确,重要知识最好抽样校验,或者只把增强结果作为辅助索引层,而不是唯一知识源。
提升切分与索引质量¶
切分策略对召回质量影响很大,但我更倾向于把它当成“信息边界设计”,而不是单纯的长度参数。
实践里比较稳的原则有几个:
- 优先按自然结构切分,例如标题层级、段落、步骤块、表格块,而不是只按固定 token 长度切。
- chunk 不要只保留正文,尽量把所属标题或上级小节一起带进去。
- 对流程型和规范型文档,适当增加 overlap,避免步骤被切断。
- 对 FAQ 型短文档,不要为了统一策略硬切太碎,否则会把本来完整的一问一答拆坏。
索引层面,不建议只保留“正文向量”这一种入口。只要业务允许,通常可以把标题、标签、来源系统、更新时间、权限范围一起入索引或入过滤条件。很多“检索不到”其实不是语义不够像,而是缺少最基本的结构化约束。
提升检索质量¶
检索质量的调优,核心是让查询表达更接近知识库里的表达方式,同时减少明显无关的搜索空间。
常见有效做法包括:
- 对用户问题做轻量 query rewrite,把口语化表达改成资料里更常见的术语。
- 将复杂问题拆成检索问题和生成问题,先检索“事实”,再让模型组织答案。
- 对强约束场景加元数据过滤,例如产品线、时间范围、租户、地区、文档类型。
- 同时保留关键词检索和向量检索,很多专有名词、报错码、接口名更适合走关键词链路。
有一个经验很重要:如果问题本质上是“查一个精确对象”,不要盲目依赖纯语义检索。精确 ID、版本号、错误码、函数名、配置项名,在很多情况下更适合通过关键词或结构化字段先缩小范围。
提升重排质量¶
我自己的经验是,很多系统在“能召回到”之后,真正拉开效果差距的往往是重排而不是继续扩大 top-k。因为 top-k 加大虽然能降低漏召回概率,但也会让噪声快速上升。
重排阶段更值得关注的是:
- 是否把真正和问题意图一致的片段排到了前几位。
- 是否把高权威、最新版、强相关来源排在前面。
- 是否把“关键词相似但任务不匹配”的噪声压下去。
如果没有专门的 cross-encoder 或更强重排器,至少也应该在工程侧补一层简单规则,例如:
- 新版本优先于旧版本。
- 正式文档优先于讨论记录。
- 同租户、同产品线、同语言优先于跨域内容。
很多时候,轻量规则和语义分数的结合,比单纯把向量检索参数继续调大更稳定。
如何提升最终回答质量¶
召回正确并不自动等于回答正确。很多团队看到候选集里已经有正确片段,就默认 RAG 没问题了;但实际失败常常发生在“模型如何消费这些片段”这一层。
我通常会重点看四件事:
- 注入的片段是不是太多,导致关键信息被淹没。
- 注入顺序是不是混乱,让低价值片段排在高价值片段前面。
- 是否明确要求模型优先依据检索结果回答,而不是凭参数知识补全。
- 是否保留了来源、标题、时间等信息,帮助模型建立片段间的优先级。
一个很常见的误区是“召回更多一点更保险”。但在生成阶段,过多上下文反而会让模型更难聚焦。对很多任务来说,少量高质量片段往往比十几个中等相关片段更有效。
如果系统需要引用答案来源,我建议从一开始就把引用当成调优工具,而不是只当成展示功能。因为一旦答案和引用绑定,你就更容易判断:系统到底是在依据资料作答,还是在借资料的名义自由发挥。
如何做实验与评测¶
RAG 调优最怕“今天感觉好了,明天又回去了”。因此经验上应该尽早把调优从主观体验变成最小可回归实验。
最小可用评测集至少可以包含三类样本:
- 典型高频问题。
- 业务上高风险的问题。
- 已经出现过失败或投诉的问题。
每次调优都尽量只改一层主要变量,例如:
- 只换 chunk 策略。
- 只换 query rewrite。
- 只换重排器或重排规则。
- 只改上下文注入方式。
如果一次同时改三四层,效果即使变好了,也很难知道究竟是哪一步起作用。对团队协作来说,这种不可归因的“变好”价值并不高,因为后续很难稳定复制。
指标上,我更建议把评测拆成两段:
- 检索指标:目标片段是否被召回、是否排进前 k、引用是否正确。
- 回答指标:答案是否正确、是否完整、是否遵循引用与约束。
只看最终答案,很容易把检索问题和生成问题混在一起。分层评测虽然麻烦一点,但后续调优效率会高很多。
常见误区¶
我自己最常见到的 RAG 调优误区有这些:
- 一出问题就调 embedding,但没有先检查文档是否值得被检索。
- 一味把 top-k 调大,却没有解决排序和噪声问题。
- 只看单次 Demo,忽略长期回归和典型失败样本。
- 把所有问题都交给向量检索,忽略关键词检索和结构化过滤。
- 只调召回链路,不看最终注入上下文到底长什么样。
- 没有文档版本管理,却希望系统自动处理冲突知识。
这些问题的共同点是:系统明明是链路问题,却被误当成单点参数问题。参数当然重要,但参数只有在链路已经清晰时才真正有意义。
一份实用的调优顺序¶
如果让我给一条更稳的 RAG 调优顺序,我通常会按下面的优先级来:
- 先确认资料本身是否可信、完整、最新、可读。
- 再确认切分是否破坏语义,chunk 是否保留必要结构。
- 再确认检索 query 是否表达对了问题。
- 再确认候选集是否足够覆盖目标片段。
- 再确认重排是否把真正相关片段放到了前面。
- 最后才去调生成阶段的提示词、引用格式和答案模板。
这个顺序的核心原因很简单:越靠前的环节越像上游供给,越决定系统上限;越靠后的环节越像消费优化,更多决定系统能否稳定把已有信息用好。
本节小结¶
RAG 调优真正有价值的,不是记住一串参数模板,而是建立一套稳定的排查顺序。先分清是没找到、找错了,还是没用好;再按资料、切分、检索、重排、注入和生成逐层定位。只要观察面足够清晰,大多数 RAG 问题最终都不是“玄学调参”,而是可以被拆开、复现和修复的工程问题。
Prompt 与 Context Engineering¶
除了 RAG,最常见的另一类调优,其实发生在 Prompt 和上下文组织层。很多团队会把它简单理解成“继续改提示词”,但从经验上看,这一层真正决定效果的,通常不是文案本身,而是控制约束是否稳定、信息装配是否合理。
常见问题判断¶
如果系统经常出现下面这些现象,问题往往更像是 Prompt 或 Context Engineering,而不只是模型能力:
- 明明知识已经给到,但回答仍然偏题。
- 同一个问题说法稍微变化,结果就明显漂移。
- 模型在多轮对话里不断忘记前面的约束。
- 工具结果已经返回,但模型没有正确消费。
- 一旦上下文变长,回答质量明显下降。
这一层的调优,首先要把“规则没写清”“信息没给对”“信息给太多”区分开。否则团队很容易反复修改提示词,却没有解决真正的输入问题。
常用调优抓手¶
实践里更常见、也更有效的抓手通常包括:
- 收紧 System Prompt,让目标、约束、禁止行为和输出格式更清晰。
- 减少同层重复指令,避免多个提示片段表达相近但语气冲突。
- 把检索结果、工具结果、用户约束按固定顺序装配,减少上下文顺序漂移。
- 在多轮任务里显式区分“当前任务目标”“历史背景”“参考资料”“执行结果”。
- 控制上下文长度,优先保留当前决策真正需要的信息,而不是把所有历史都塞进去。
我的经验是,Prompt 调优最容易陷入“越写越长”的误区。很多时候,问题不是模型需要更多规则,而是系统没有把高优先级规则放在最稳定、最前置的位置。
Tool Use 与 Workflow 调优¶
当 Agent 已经进入执行阶段,调优重点就会从“回答好不好”转到“动作准不准、流程稳不稳”。这一层的问题通常更具工程性,也更适合通过日志和链路观察来定位。
Tool Use 调优¶
Tool Use 的调优往往集中在三个点:
- 什么时候该调用工具,什么时候不该调用。
- 调哪个工具,参数是否构造正确。
- 工具结果回来后,模型是否理解并继续推进了正确动作。
这类问题常见的有效改法包括:
- 把工具描述写得更清楚,特别是适用场景、输入要求和禁止调用条件。
- 对高风险工具增加显式门槛,例如需要先满足某些前置条件才允许调用。
- 把工具返回值做标准化,减少模型自己从原始响应里“猜字段”的空间。
- 对失败场景补恢复策略,例如超时重试、参数修正、人工确认或直接中止。
很多 Tool Use 问题表面上像是“模型不会用工具”,但实际根源往往是工具接口定义得不够稳定,或者调用后没有给模型一个足够可消费的返回格式。
Workflow 调优¶
Workflow 层更关注阶段边界是否合理。一个典型症状是:系统每一步单看都像对的,但整体流程跑出来却不稳定。这时候更该怀疑的是编排,而不是单步推理。
常见调优方向有:
- 是否把复杂任务拆成了足够清晰的阶段。
- 是否把必须硬约束的步骤留给 Workflow,而不是交给 Agent 自主判断。
- 是否在关键节点加了人工确认、状态持久化或失败回退。
- 是否允许系统在一个阶段里无意义地重复调用工具或重复规划。
经验上,Workflow 调优的核心不是“让系统更聪明”,而是让错误更早暴露、让阶段边界更清楚、让恢复路径更确定。
Memory 调优¶
Memory 的调优最容易走偏,因为很多团队会本能地觉得“记得越多越好”。但从效果和风险看,真正重要的不是记多少,而是记什么、何时写入、何时读取、何时应该忘掉。
常见问题判断¶
如果系统表现出下面这些问题,通常说明 Memory 设计需要调优:
- 每轮都在重复问同样的偏好信息。
- 已经记住的信息会和当前任务无关地不断冒出来。
- 用户偏好已经变化,但系统仍然沿用旧记忆。
- 记忆内容和知识库内容互相冲突,模型不知道该信哪一个。
常用调优抓手¶
比较稳的做法通常包括:
- 收紧写入条件,只保留跨轮次、跨任务真正有复用价值的信息。
- 给记忆加类型,例如偏好、事实、长期约束、临时状态,避免混在一起。
- 在读取时做任务相关性过滤,而不是每轮都把一整包记忆塞进上下文。
- 给容易过期的记忆加更新时间和失效策略。
- 对冲突信息保留来源和版本,必要时优先新信息或要求用户确认。
Memory 调优和 RAG 调优有一个共同点:问题常常不是“没有信息”,而是“系统给错了信息”。
评测与可观测性调优¶
很多 Agent 系统之所以长期调不稳,不是因为没有好方法,而是因为没有把调优对象做成可回放、可比较、可归因的系统。到这个阶段,调优已经不再只是某一层能力优化,而是整个迭代闭环的优化。
评测调优¶
评测层面最值得补的是:
- 建立固定失败集,而不是只看当天新问题。
- 区分检索、规划、工具、回答这几类失败,不把所有问题混成一个总分。
- 让每次迭代都有明确对照组,避免“感觉变好了”。
- 把高风险场景单独拉出来,不要被平均分掩盖。
可观测性调优¶
观测层面最值得补的是:
- 保留每轮输入、关键中间状态、工具调用、检索结果和最终输出。
- 让同一个任务可以被回放,便于复现。
- 给每层链路加最小指标,例如召回命中率、工具成功率、任务完成率、人工接管率。
- 对高成本路径和长延迟路径做单独监控,不要只看整体平均值。
如果没有这套观测基础,很多所谓调优最终都会退化成“运气好时看起来有效,过两周又说不清为什么失效”。
这一部分还值得持续补充什么¶
如果后续把这部分继续扩充,我认为最值得长期积累的还有几类内容:
- 不同业务场景下的 RAG 调优案例,例如客服、代码库、企业制度库。
- Prompt 与上下文装配失败的真实例子,以及是如何定位到根因的。
- Tool Use 失败恢复的模式库,例如超时、空结果、越权和错误参数。
- Memory 设计中的反例,特别是“记多了反而更差”的案例。
- 一套持续维护的调优 checklist,用来做版本上线前检查。
这类内容的价值,往往不在于理论完整,而在于能把“踩过的坑”沉淀成后续团队能复用的判断资产。