第 12 章:RAG —— 当模型“不知道”时,系统该如何补偿?
在前面的章节中,我们已经逐步解决了:
- 如何约束模型行为(Prompt)
- 如何管理对话与上下文(Context / Memory)
但到这里,一个更根本的问题开始浮现:
如果用户的问题,本身就超出了模型的知识边界,或者企业私有知识范围,系统还能做什么?
这就是我们前面提到 RAG(Retrieval-Augmented Generation)存在的原因。
12.1 先别急着实现:什么是 RAG
在上一篇中,已经从工程的视角介绍了RAG: 动态构造一个“最小且相关的知识上下文”
我们对齐进行展开
RAG 是一种: 在模型生成之前, 通过外部检索机制, 为模型“临时补充其本不具备的知识”的系统架构。
注意几个关键词:
- 生成之前
- 外部
- 临时
- 补充
这意味着:
- 知识不进入模型参数
- 不依赖模型“记住”
- 不污染长期上下文
12.2 RAG 解决的,其实是“知识时效与边界问题”
为什么只靠模型本身一定不够?
在企业知识库助手中,典型问题包括:
- 企业制度频繁变化
- 内部流程不对外公开
- 文档体量远超上下文窗口
- 法规 / 合同 / SOP 有明确版本边界
这些问题有一个共同特征:
它们不是“模型不聪明”,而是“模型不可能知道”。
RAG 的核心价值就在于:
把“知道什么”这个问题,从模型能力中剥离出来,交给系统解决。
12.3 从系统角度看:RAG 在整体架构中的位置

从这里你可以看到:
RAG 不是“总会发生”
它是一个条件触发的系统能力
并且发生在:
上下文构建阶段,而不是 Prompt 阶段
12.4 一个常见误区:RAG ≠ 万能增强器
在引入 RAG 后,很多团队会产生一个错误预期:
“只要接了 RAG,模型就不会胡说了。”
现实往往相反:
- 检索结果不相关
- 模型曲解文档
- 回答看似“有依据”,但其实错误
这引出一个非常重要的事实:
RAG 的失败,大多数并不是发生在“生成阶段”,而是发生在“检索之前”。
一旦你真正理解了 RAG 的系统定位,下一个、也是更残酷的问题就会出现:
为什么我已经“接了 RAG”,效果还是不好?
很多失败的 RAG 项目,会把问题归因于:
- 向量模型不够好
- 大模型不够聪明
但在绝大多数情况下,真正的瓶颈出现在一个更早、也更基础的地方: —— 文档是“如何被拆解与表达的” 。
就像用渔网捕鱼:如果网眼太大,小鱼会漏走;如果网眼太小,会被水草缠住。渔网的设计(对应 Chunk 设计),比 “用什么材质做渔网”(对应向量模型)更重要。
12.5 文档 → Chunk → Embedding:检索效果的真正上限
12.5.1 Chunk 设计:被严重低估的工程决策
Chunk(文档片段)是 RAG 的 “原子单元”—— 系统检索的是 Chunk,注入上下文的也是 Chunk。Chunk 的大小与切分方式,直接决定了:
- 能否被检索到:如果 Chunk 包含的信息与问题无关,再先进的检索器也找不到它;
- 被检索到后是否 “刚好有用”:如果 Chunk 太大,包含大量无关信息(噪声),模型会被干扰;如果太小,关键信息被切碎(比如一个流程的 “步骤 1” 和 “步骤 2” 被分到两个 Chunk),模型无法理解完整逻辑。
在企业知识库助手中,Chunk 设计的常见问题:
Chunk 太大:
- 典型场景:直接把整篇文档作为一个 Chunk(比如一份 10 页的产品手册)。
- 问题:检索时容易 “误中”—— 比如文档里只有 1 段讲 “定价”,但因为整个文档被检索到,模型需要从 5000 字中找答案,很容易被其他内容干扰
Chunk 太小:
- 典型场景:按固定字数强制拆分(比如每 100 字切一段)。
- 问题:语义被切碎 —— 比如 “审批流程需要部门经理签字后提交给 HR”,如果被拆成 “审批流程需要部门经理签字” 和 “后提交给 HR” 两个 Chunk,单独检索到任何一个都无法理解完整流程。
Chunk 设计,本质上是在做信息密度的权衡:既要让每个 Chunk 包含 “足够完整的语义”,又要避免 “包含过多无关信息”。
12.5.2 一个工程化的 Chunk 决策思路
你可以从这样的问题开始思考:
- 用户的问题,通常对应文档的哪一层?是段落级?章节级?还是流程级?
- 文档本身的结构是什么?是否有天然的语义边界(比如标题、列表、表格)?
Chunk 应该尽量与 “被提问的最小语义单元” 对齐。举几个企业场景的例子:
场景 1:FAQ 文档(比如 “IT 支持常见问题”)
- 特点:每个问题对应一个独立答案(比如 “如何重置密码?”→ 步骤 1-3)。
- 最优 Chunk:按 “问题 + 答案” 成对切分(每个 Chunk 包含一个完整的问答)。
- 理由:用户的问题往往直接匹配 FAQ 中的问题,精准切分能确保检索到的 Chunk 刚好包含答案。
场景 2:产品手册(比如 “CRM 系统操作指南”)
- 特点:按功能模块划分章节(比如 “客户管理”→“新增客户”→“字段说明”)。
- 最优 Chunk:按 “功能子模块” 切分(比如 “新增客户的 5 个必填字段” 作为一个 Chunk)。
- 理由:用户的问题多是 “如何操作 XX 功能”,与子模块的语义边界高度匹配。
场景 3:会议纪要(比如 “Q3 销售策略会记录”)
- 特点:包含多个讨论点(比如 “目标调整”“资源分配”“风险应对”)。
- 最优 Chunk:按 “讨论主题” 切分(每个主题的讨论过程 + 结论作为一个 Chunk)。
- 理由:用户可能问 “Q3 的销售目标是多少”,需要定位到 “目标调整” 主题的 Chunk。
此外,Chunk 的元数据(Metadata)也很重要 —— 比如给每个 Chunk 标记 “文档类型”“更新时间”“所属部门”,能帮助检索器进一步筛选(比如优先检索 “2024 年更新” 的文档)。
12.6 RAG工程化建设
12.6.1 从“调用 RAG”到“集成 RAG”:系统视角的转变
很多教程里的 RAG 看起来像这样:
query → embedding → 向量检索 → 拼 prompt → 调模型
这在 Demo 中没问题,但在真实系统中,这种方式是不可持续的。
原因在于:
- RAG 不是一个函数
- 它是一个长期存在的系统能力
当我们需要集成RAG能力时,必须完成一个视角转变:
RAG 不是“我什么时候用一下”,而是“系统在什么条件下,必须依赖它”。
12.6.2 RAG 的第一个工程问题:何时触发?
一个成熟系统,不会对所有请求都使用 RAG。
典型触发条件包括:
用户问题包含:
- 企业私有名词
- 内部流程 / 制度
问题涉及:
- 时效性
- 明确版本
模型置信度不足(如多次自我矛盾)

12.6.3 RAG 的第二个工程问题:接口如何定义?
在进阶系统中,RAG 模块不应该“直接拼 Prompt”,而应该返回一个结构化结果:
{
"documents": [
{
"id": "doc-123",
"content": "...",
"score": 0.87,
"source": "HR-policy-v3"
}
],
"query_intent": "policy_explanation",
"confidence": "high"
}
这样做的好处是:
- Prompt 构建不被 RAG 实现绑死
- 便于调试与评估
- 便于多模型 / 多策略切换
RAG 的输出,是系统资产,不是 Prompt 片段。
12.6.4 RAG 的第三个工程问题:模型如何“被迫使用”检索结果?
这是最容易被忽略、但最致命的一点。
即使你检索回了正确文档,模型仍然可能:
- 忽略它
- 曲解它
- 混合自身知识胡说
因此你必须在系统层面做约束。
一种常见的工程策略
- 所有结论必须引用提供的文档
- 不允许基于“常识”补充
- 文档不足时,必须回答“不确定”

RAG 的成功,50% 取决于“生成约束”,而不是“检索准确率”。
12.6.5 RAG 的第四个工程问题:失败如何被定位?
在应用的实际表现中,一定会遇到这个问题:
“现在效果不好,但我不知道是哪里出了问题。”
一个可诊断的 RAG 系统,至少能回答:
- 是不是根本没召回?
- 召回的内容是否相关?
- 模型是否使用了召回内容?
- 回答是否超出了引用范围?
这要求你在系统中明确区分:
检索失败 / 召回噪声 / 生成违约
否则,你永远只能“凭感觉调”。
12.6.6 企业知识库助手中的 RAG 集成示例
最后以企业知识库为例,我们看一下RAG的集成示例图

12.7 本章小结:RAG 是系统工程,而不是检索技巧
通过这一章,你应该已经形成一个完整认知:
- RAG 不是模型增强,也不是简单的“查资料”
而是:
一种用于突破模型知识边界的系统补偿机制。
同时你也应该清楚地意识到:
- RAG 的效果上限,很早就被文档结构与数据工程决定了
这意味着:
RAG 是一个数据工程与系统设计问题,远早于它是一个模型问题。
即便我们通过精心的 Chunk 设计为 RAG 打下了坚实基础,也无法完全避免检索失败的可能 —— 毕竟用户的问题可能天马行空,知识库的覆盖也总有边界。那么,当检索真的 “空手而归” 时,系统该如何应对才能避免陷入 “胡编乱造” 的陷阱?