RAG
RAG, Retrieval-Augmented Generation, 是大模型应用最常见的架构之一。它通过检索外部知识,把相关内容放进上下文,再让模型生成答案。
RAG 解决什么问题
RAG 主要解决三类问题:
| 问题 | 为什么需要 RAG |
|---|---|
| 私有知识 | 模型训练时不知道你的公司制度、内部文档、客户资料 |
| 实时变化 | 业务数据、政策、产品说明会不断更新 |
| 长文档 | 文档太长,不能全部放进上下文窗口 |
RAG 不等于让模型“学会”这些资料,而是在每次提问时把相关资料临时找出来,作为回答依据。
RAG 和微调的区别
| 方式 | 适合解决 | 不适合解决 |
|---|---|---|
| RAG | 私有知识、频繁更新、需要引用来源 | 固定风格、复杂格式习惯 |
| 微调 | 特定风格、格式、任务模式 | 频繁变化的事实知识 |
| Prompt | 简单任务约束和输出格式 | 大规模知识注入 |
大多数知识库、客服助手、制度问答项目,应该先做 RAG,再考虑是否需要微调。
基本流程
文档采集 -> 清洗 -> 切分 -> 向量化 -> 存储 -> 检索 -> 重排 -> 生成 -> 引用 -> 反馈
用一个例子理解 RAG
假设你要做一个公司制度问答助手。模型本身不知道你公司的制度,所以不能直接问模型“年假怎么算”。正确做法是:
- 把公司制度文档导入系统。
- 将文档切成小段。
- 为每个小段生成 Embedding。
- 用户提问时,先检索相关制度片段。
- 把检索结果和问题一起交给模型。
- 模型只基于这些片段回答,并给出引用。
RAG 的核心思想是:不要让模型凭空记忆私有知识,而是把相关知识临时放进上下文。
关键模块
| 模块 | 关注点 |
|---|---|
| 文档解析 | PDF、网页、Markdown、Office 文档的结构保留 |
| Chunking | 切分大小、重叠、标题层级、语义完整性 |
| Embedding | 模型选择、语言支持、成本、更新频率 |
| Vector Store | 过滤、权限、混合检索、性能 |
| Retrieval | top-k、metadata filter、query rewrite |
| Rerank | 提高召回片段排序质量 |
| Generation | 引用来源、拒答、答案风格 |
| Evaluation | 命中率、忠实度、答案质量、延迟和成本 |
文档进入系统前要处理什么
文档质量决定 RAG 上限。导入文档时要关注:
- 格式解析:PDF、网页、Markdown、Word 的结构不同。
- 噪声清理:页眉页脚、导航栏、广告、重复版权声明会污染检索。
- 结构保留:标题、表格、列表、代码块、页码最好保留。
- 去重:重复文档会让检索结果偏向重复内容。
- 权限标签:导入时就记录部门、用户组、文件来源和可见范围。
不要把“文档解析”当成简单读文本。很多 RAG 效果差,根源在文档进入系统时就已经乱了。
常见问题
- 文档切得太碎,答案缺少上下文
- 文档切得太大,检索不准且成本高
- 只用向量检索,忽略关键词和元数据过滤
- 没有权限控制,导致用户看到不该看的内容
- 没有引用来源,用户无法验证答案
- 没有评测集,只靠主观感觉调参
推荐路线
- 先做单用户、本地文档 RAG。
- 加入引用来源和无法回答策略。
- 引入 metadata filter,例如文件名、部门、时间。
- 加入混合检索和 rerank。
- 建立 50 到 200 条真实问题的评测集。
- 上线后记录 bad case,持续优化切分和检索。
Chunking 怎么做
新手可以先用这套默认策略:
- Markdown 按标题切分
- 普通文本每 500 到 1000 字切一段
- 相邻 chunk 保留 10% 到 20% 重叠
- 每个 chunk 保留标题、文件名、页码等 metadata
- 不要把表格和代码块随便切断
判断切分好不好,不是看 chunk 数量,而是看用户提问时能不能检索到足够完整的答案依据。
Chunk 设计取舍
Chunk 太小,可能缺少上下文;chunk 太大,检索不准且浪费 token。可以用下面方式判断:
| 现象 | 可能原因 | 调整方向 |
|---|---|---|
| 检索到片段但回答不完整 | chunk 太小或没有标题上下文 | 增大 chunk,保留父标题 |
| 检索结果经常不相关 | chunk 太大或 embedding 区分度低 | 减小 chunk,优化 query |
| 表格答案经常错 | 表格被切断或格式丢失 | 单独处理表格 |
| 法规条款引用不准 | metadata 不完整 | 保存章节号、页码、条款号 |
生产系统中,chunking 往往需要按文档类型分别设计。
检索策略
| 策略 | 适合场景 |
|---|---|
| 向量检索 | 语义相似问题 |
| 关键词检索 | 专有名词、编号、代码、产品名 |
| 混合检索 | 大多数生产场景 |
| metadata filter | 权限、时间、部门、文件类型过滤 |
| rerank | 提高 top-k 排序质量 |
Query Rewrite
用户问题通常不等于适合检索的查询。例如用户问“这个怎么算”,如果没有上下文,检索系统很难找到资料。Query rewrite 的作用是把用户问题改写成更适合检索的形式。
常见做法:
- 补全代词和上下文,例如把“这个政策”改成“年假政策”。
- 提取关键词,例如产品名、部门、日期、编号。
- 生成多个查询,从不同角度检索。
- 对多轮对话,把当前问题改写成独立问题。
注意:query rewrite 也可能引入错误,所以需要在评测中单独观察检索命中率。
引用和拒答
RAG 回答应该尽量带引用。引用的作用不是装饰,而是让用户能验证答案。
好的引用应该包含:
- 文档标题。
- 页码、章节或 chunk id。
- 原文片段或可点击来源。
- 引用和回答结论之间的对应关系。
当检索不到足够资料时,系统应该拒答或说明缺少资料。不要让模型为了“显得有帮助”而编造。
RAG 评测指标
- 检索命中率:相关资料有没有被找出来
- 上下文相关性:放进 prompt 的内容是否真的有用
- 答案忠实度:回答是否基于资料,而不是编造
- 引用准确性:引用是否能支持答案
- 拒答准确性:资料没有答案时能否说不知道
常见优化顺序
RAG 效果不好时,建议按这个顺序排查:
- 原始文档是否解析正确。
- chunk 是否保留足够语义。
- metadata 是否完整,权限过滤是否正确。
- top-k 检索结果是否包含答案。
- rerank 后相关片段是否排在前面。
- prompt 是否要求只基于资料回答。
- 输出引用是否能支持结论。
不要一上来就换向量数据库或换模型。先看检索结果,很多问题会很快暴露。
实战练习
- 选 3 篇 Markdown 文档,分别尝试按标题切分和固定长度切分。
- 为每个 chunk 增加 title、source、page、section metadata。
- 准备 20 个问题,手动检查 top-5 检索结果是否包含答案。
- 给 RAG 回答增加引用和“资料不足无法回答”的输出。
实战项目
优先完成:个人知识库问答助手