Skip to content

第 6 章:RAG 进阶优化

章节定位

上一章你已经搭出基础 RAG:文档进来,检索片段,模型生成答案。

但基础 RAG 往往只能证明“能跑”,不能证明“好用”。这章要解决的就是四个问题:

  • 检索出来的内容准不准
  • 切分后的片段是不是太碎
  • 上下文是不是塞了太多无关信息
  • 模型回答是不是过度发挥了

AI 学习助手 中,这一章会把“能回答课程资料”升级成“回答更稳、更准、更可控”。

配套示例

  • 目录:examples/chapter-06
  • 入口:examples/chapter-06/main.py
  • 依赖:examples/chapter-06/requirements.txt
  • 运行:cd examples/chapter-06 && python3 main.py

示例层级与边界

  • 层级:教学版
  • 本章重点:训练你识别 RAG 问题出在切分、检索、上下文还是生成阶段。
  • 不要误判:示例中的优化策略是教学化对比,不等于真实生产环境里的召回评测、索引调参或在线实验体系。

本章目标

学完这一章,你应该能:

  • 判断基础 RAG 的主要失败点
  • 根据资料类型调整切分策略
  • 优化 Retriever 的检索质量
  • 对上下文拼装方式做基本控制
  • 让模型回答更贴近资料、更少编造

前置知识

你需要先理解:

  • RAG 的基本流程
  • 文档切分、Embedding、Vector Store、Retriever 的作用
  • 模型生成阶段为什么需要提示词约束

为什么基础 RAG 还不够

很多人第一次做 RAG 时,系统看起来能跑,但一用就暴露问题:

  • 问题稍微复杂一点就检索偏了
  • 文档一多,返回的片段很杂
  • 模型会根据检索内容“补脑”
  • 回答里混进很多没必要的上下文

基础 RAG 的问题不是单点,而是链路上的每一步都可能影响结果。

所以优化 RAG 的思路不是“换一个更大模型就行了”,而是要逐层排查:

  1. 文档有没有切对
  2. 检索有没有找对
  3. 上下文有没有组织好
  4. 生成有没有被约束住

优化的四个方向

1. 切分优化

切分决定了后续检索的“候选池”质量。

切得太碎:

  • 段落信息不完整
  • 检索命中后上下文不够

切得太粗:

  • 片段里混了太多主题
  • 检索结果不够精准

因此切分要结合内容类型:

  • 课程说明文档适合中等粒度切分
  • FAQ 适合问答对粒度切分
  • 长篇技术文档适合按标题层级和语义段落切分

2. 检索优化

Retriever 不只是“取相似度最高的几段”。

你可以在检索阶段做一些控制:

  • 调整 top_k
  • 设置相似度阈值
  • 查询改写
  • 多查询融合

这一步的目标是减少“看起来相近,实际上无关”的片段。

3. 上下文优化

检索到内容后,并不是越多越好。

如果上下文太长,模型会:

  • 分心
  • 被噪音干扰
  • 更容易忽略真正相关的部分

所以要控制上下文组织方式:

  • 去掉重复片段
  • 排序相关性
  • 只保留必要段落
  • 必要时做压缩总结

4. 生成优化

最后一步仍然是生成,但这一步经常被低估。

你要明确告诉模型:

  • 只能基于资料回答
  • 资料不足时要说明不足
  • 不要自行扩展课程外结论
  • 尽量引用相关片段中的表述

这会显著降低“模型一本正经胡说八道”的概率。

优化思路怎么落到工程里

可以把优化流程理解成一个调试漏斗:

  • 先看资料切得是否合理
  • 再看检索命中的片段是否相关
  • 再看上下文是否过长或过乱
  • 最后看模型输出是否忠于资料

这意味着你不应该只盯着最终答案,而要记录每一层的中间结果。

AI 学习助手 中,最好给每次问答都保留:

  • 原始问题
  • 检索到的片段
  • 拼装后的上下文
  • 最终回答

这样才知道问题到底出在前面还是后面。

最小示例:从基础 RAG 升级到可控 RAG

下面这个示例展示的是优化思路,不是特定版本 API。

python
# 伪代码:重点看策略,不看具体库函数名

question = "RAG 和普通问答相比,为什么更适合课程学习站?"

# 1. 先把问题改写得更适合检索
search_query = rewrite_query(question)

# 2. 检索多个候选片段
candidates = retriever.retrieve(search_query, top_k=8)

# 3. 按相关性过滤、去重、排序
filtered_chunks = filter_and_rank(candidates)

# 4. 必要时压缩上下文
context = compress_context(filtered_chunks, max_chars=3000)

# 5. 用更严格的提示词生成答案
prompt = """
你是课程学习助手。只能基于资料回答。
如果资料不能支持结论,请明确说明“不足以判断”。

资料:
{context}

问题:
{question}
"""

answer = llm.generate(prompt.format(context=context, question=question))

这个示例说明一个关键点:优化不只是“调一个参数”,而是对完整链路进行控制。

真实框架版对照

examples/chapter-06/main.py 增加了一组 framework-baselineframework-optimized 对照输出。

这两组对照重点不是追求“更强”,而是让你看到真实工程里常见的接口拆分:

  • query rewrite 先把问题改写成更适合检索的查询
  • retriever 负责返回候选片段
  • 重排和压缩负责把上下文收敛成可交给模型的证据
  • 最后仍然是 prompt + model 的生成阶段

从这里开始,你应该逐渐把“优化 RAG”理解成一条可调试的数据流,而不是只调某个模型参数。

切分优化怎么做

切分优化的原则很简单:让片段保持语义完整。

你可以观察三类指标:

  • 片段是否能独立表达一个意思
  • 片段之间是否有适度重叠
  • 片段是否保留标题和上下文信息

对于课程站这类资料,建议保留章节标题、模块标题等结构信息。因为用户问的往往不是某一句话,而是“这一节讲了什么”。

检索优化怎么做

检索优化的思路不是追求“最多”,而是追求“更准”。

常用方法:

  • 增加候选数,再二次过滤
  • 对问题做简短改写
  • 针对不同问题类型使用不同检索策略

比如:

  • “第几章讲什么”这类问题,标题信息很重要
  • “为什么这样设计”这类问题,解释段落更重要
  • “怎么写示例”这类问题,代码块附近的说明更重要

也就是说,检索策略应该和问题类型匹配。

上下文优化怎么做

上下文优化最重要的原则是:只放对回答有帮助的内容。

常见做法:

  • 去重
  • 排序
  • 截断
  • 压缩

尤其是在课程站这种文档很多但单次问题很明确的场景里,不要把全部候选都塞给模型。你要让模型看的是“证据”,不是“噪音合集”。

生成优化怎么做

生成优化主要靠提示词控制。

你需要明确写出三类约束:

  • 回答边界:只基于资料
  • 不足处理:资料不足就说不足
  • 输出风格:尽量简洁、结构化、可追溯

如果你希望答案更稳,还可以让模型:

  • 先给结论
  • 再给依据
  • 再指出资料中的相关位置

这样用户更容易判断答案是否可信。

本章实践

这一章最值得做的实践,是给 AI 学习助手 做一次系统优化。

建议你按下面的顺序推进:

  1. 先保存基础 RAG 的问答日志
  2. 找 10 个典型问题做测试
  3. 观察哪些问题经常答偏
  4. 分别检查切分、检索、上下文、提示词四个环节
  5. 每次只改一个变量,避免你不知道到底是哪一步起作用

实践目标不是“追求绝对正确”,而是建立可重复的优化流程。

常见坑

坑 1:只调模型,不调检索

很多 RAG 问题本质是检索问题,不是模型问题。
如果片段都找错了,模型再强也只能在错误上下文里回答。

坑 2:上下文过长

把太多片段塞给模型,只会增加噪音。
RAG 的关键不是“喂更多”,而是“喂更相关”。

坑 3:不记录中间过程

如果你不记录检索结果和上下文拼装过程,就很难定位问题。
RAG 调试应该看链路,不该只看最终答案。

坑 4:答案看起来很顺,但其实没依据

这通常说明生成约束太弱。
你要让模型明确知道:资料不足时,不要硬编。

练习题

  1. 如果一个问题经常检索到无关内容,你会优先检查哪三个环节?
  2. 为什么课程站不适合把所有候选片段都直接送给模型?
  3. 试着为 AI 学习助手 写一段更严格的回答提示词,要求模型只根据资料作答。
  4. 说明“切分优化”和“检索优化”的区别。

本章总结

基础 RAG 解决的是“能不能查资料再回答”,优化 RAG 解决的是“能不能答得准、稳、可解释”。

这章的核心不是某个单独技巧,而是一个系统思维:

  • 切分影响候选质量
  • 检索影响相关性
  • 上下文影响模型注意力
  • 提示词影响回答边界

把这四层理顺,你的 RAG 系统才算进入可用状态。

学完本章,你现在应该会

  • 把一个 RAG 问题拆到切分、检索、上下文、生成四层里定位
  • 说明为什么“答偏”不一定是模型能力问题
  • 设计一次小规模、可重复的 RAG 优化实验
  • AI 学习助手 写出更严格的资料边界和回答约束

最小验收 checklist

  • [ ] 我至少记录过一次基础 RAG 的问题案例和中间过程
  • [ ] 我能说出本次优化到底改的是哪一层,而不是“整体感觉更好”
  • [ ] 我知道什么时候该减少上下文,而不是继续增加片段数量
  • [ ] 我能解释为什么优化要一次只改一个变量

建议你动手改一版

  • 选 5 到 10 个问题做一个小评测表,对比优化前后的命中率或完整性
  • 给回答模板补上“先结论、再依据、最后说明资料边界”的结构
  • 试着只改 top-k 或切分粒度中的一个参数,记录它对结果的影响

卡住时先回看这里

下一章预告

下一章会从“知识问答”转向“动作执行”。

你会学习:

  • 什么是 Tool Calling
  • 为什么 Agent 需要工具
  • 如何让 AI 学习助手 不只会回答,还能调用外部能力