RAG 工程化
RAG,即 Retrieval-Augmented Generation,检索增强生成。它的核心思路是:回答前先从外部知识源检索相关内容,再让模型基于这些证据生成答案。
一句话概括:
RAG 工程化不是“接一个向量库”,而是把文档、索引、检索、重排、上下文、引用、权限和评估连成可靠链路。
典型链路如下:
文档采集
-> 文档解析
-> 清洗和结构化
-> chunk 切分
-> embedding
-> 建索引
-> 查询改写
-> 检索
-> rerank
-> 上下文拼接
-> 生成答案
-> 引用溯源
-> 日志和评估
RAG 适合解决什么问题
RAG 适合把外部知识接入模型,尤其是:
- 企业内部知识库问答。
- 产品文档问答。
- 制度、流程、手册查询。
- 客服知识库。
- 技术支持。
- 法规和合同辅助阅读。
- 需要引用来源的回答。
- 频繁更新、不能只依赖模型参数记忆的知识。
RAG 不适合所有问题。以下场景可能需要别的方案:
- 需要严格事务操作:更适合工具调用或业务 API。
- 需要复杂数值计算:更适合计算工具。
- 需要跨大量记录聚合统计:更适合数据库查询或分析引擎。
- 需要稳定遵循内部风格:可能需要 prompt、微调或模板。
- 文档本身质量很差:先做知识治理比直接做 RAG 更重要。
文档解析
RAG 的上限很大程度取决于文档解析质量。模型只能使用进入索引的内容,解析阶段丢失的信息通常很难在生成阶段补回来。
常见文档来源:
- Markdown。
- HTML。
- PDF。
- Word。
- Excel。
- PPT。
- Wiki。
- 数据库记录。
- 工单和客服对话。
- 图片和扫描件。
解析要保留:
- 标题层级。
- 段落。
- 表格。
- 列表。
- 代码块。
- 图片说明。
- 页码或章节位置。
- 文档 ID。
- 更新时间。
- 权限信息。
PDF 和表格是常见难点。PDF 可能存在分栏、页眉页脚、脚注、扫描 OCR、跨页表格;表格则可能需要保留行列关系,而不是简单拼成一段文本。
清洗和结构化
进入索引前通常需要清洗。
常见处理包括:
- 去除重复页眉页脚。
- 去除导航栏、版权区和无关链接。
- 统一空格和换行。
- 保留标题层级。
- 修正 OCR 错字。
- 拆分超大表格。
- 过滤低质量或过期文档。
- 提取 metadata。
metadata 很重要,常见字段包括:
doc_idtitlesourceurlsectionpageupdated_atownerlanguagepermissionversion
没有 metadata,就很难做过滤、引用、权限和增量更新。
Chunk 策略
chunk 是 RAG 的基本检索单元。切得太碎会丢语义,切得太大又会降低召回精度并浪费上下文。
常见切分方式:
| 策略 | 特点 | 适合场景 |
|---|---|---|
| 固定长度 | 简单稳定 | 文本结构弱、快速原型 |
| 按标题切分 | 保留章节语义 | 文档结构清晰 |
| 按段落切分 | 易读、边界自然 | 知识库文章 |
| 语义切分 | 尽量保持语义完整 | 长文、复杂说明 |
| 表格行块 | 保留行列关系 | 价格表、配置表、清单 |
| Parent-child | 小块检索,大块回填 | 长文档和章节型内容 |
常见参数:
- chunk size。
- overlap。
- 最大标题深度。
- 是否保留父标题。
- 是否保留前后文。
- 是否按文档类型使用不同策略。
建议每个 chunk 都带上标题路径。例如:
产品手册 > 安装部署 > GPU 要求
这样即使正文很短,检索和生成也能获得上下文语义。
Embedding 模型选择
embedding 模型负责把文本转成向量。它直接影响语义召回。
选择时要看:
- 中文、英文或多语言能力。
- 领域词汇覆盖。
- 长文本编码能力。
- 向量维度。
- 推理速度。
- 成本。
- 是否支持 query / document 不同指令。
- 是否和 rerank 模型配合良好。
embedding 模型切换后必须重建索引。不同 embedding 空间不能混用,否则向量相似度没有意义。
还要注意:
- 查询和文档是否使用相同预处理。
- 是否需要归一化向量。
- 是否需要给 query 加检索指令。
- 是否需要给文档加标题、metadata 或摘要。
- 是否需要多向量表示一篇文档。
向量库和倒排索引
RAG 检索常用两类索引:
| 索引 | 适合内容 |
|---|---|
| 向量索引 | 语义相似、同义表达、自然语言问题 |
| 倒排索引 | 关键词、专有名词、编号、错误码、精确匹配 |
向量检索擅长“意思相近”,但不擅长精确字符串。倒排索引擅长精确匹配,但不理解语义。
工程上常见组合:
向量召回 top_k
+ 关键词召回 top_k
-> 合并去重
-> rerank
-> 选择最终上下文
选择向量库时要关注:
- 数据规模。
- 查询延迟。
- metadata filter 能力。
- 更新和删除能力。
- 多租户隔离。
- 备份恢复。
- 权限过滤。
- 混合检索支持。
- 运维复杂度。
不要只看 demo 的相似度结果。生产系统更关心更新、过滤、延迟、权限和可恢复性。
Hybrid Search
Hybrid search 通常指语义检索和关键词检索结合。
适合场景:
- 用户输入包含产品型号、错误码、订单号。
- 文档里有很多专有名词。
- 用户问题和文档措辞差异很大。
- 既需要语义召回,又不能丢精确匹配。
常见融合方法:
- 分别取 top_k 后合并去重。
- 按归一化分数加权。
- 使用 RRF。
- 先宽召回,再 rerank。
Hybrid search 的关键不是“多加一个检索器”,而是让不同召回来源互补。需要分别观察向量召回和关键词召回贡献了哪些正确结果。
Rerank
rerank 是对召回结果重新排序。召回阶段追求“别漏”,rerank 阶段追求“把最相关的放前面”。
rerank 可以使用:
- cross-encoder reranker。
- LLM rerank。
- 规则特征。
- metadata 加权。
- 时间衰减。
- 权限和业务优先级。
rerank 常见收益:
- 提升首条命中率。
- 降低无关 chunk 进入上下文的概率。
- 让最终 prompt 更短。
- 提高引用准确性。
但 rerank 也会增加延迟和成本。工程上通常先召回较多候选,再 rerank 到少量片段。例如召回 50 个,重排后取 5 到 8 个进入上下文。
查询改写
用户问题不一定适合直接检索。
常见改写包括:
- 补全省略信息。
- 把多轮指代改成独立问题。
- 提取关键词。
- 生成多个检索 query。
- 中英文术语扩展。
- 拆分复杂问题。
示例:
用户:那它支持离线部署吗?
改写:MiniCPM-o 4.5 是否支持离线部署?
查询改写要小心引入错误前提。改写后的 query 应当保留用户原意,不能替用户补出没有依据的实体或结论。
上下文拼接
检索结果最终要拼进 prompt。拼接策略会影响答案质量。
需要考虑:
- 放多少个 chunk。
- 按 rerank 分数排序还是按文档顺序排序。
- 是否合并同一文档相邻 chunk。
- 是否保留标题路径。
- 是否保留 metadata。
- 是否压缩过长内容。
- 是否区分证据和指令。
- 多轮对话历史如何与 RAG 内容共同占用上下文。
推荐结构:
系统指令
用户问题
可用资料:
[1] 标题 / 来源 / 更新时间
内容...
[2] 标题 / 来源 / 更新时间
内容...
要求:
- 仅基于可用资料回答。
- 无资料支持时说明无法确认。
- 需要给出引用编号。
不要把检索内容混在 system prompt 里。外部文档是数据,不是更高优先级的指令。
引用和溯源
RAG 的重要价值之一是可溯源。
引用至少要能定位到:
- 文档。
- 章节。
- 页码或段落。
- chunk ID。
- URL 或内部记录 ID。
- 文档版本。
好的引用满足:
- 答案中的关键结论能被引用支持。
- 引用内容实际进入过上下文。
- 引用粒度足够小。
- 新旧版本不会混用。
- 用户有权限访问引用来源。
不可靠引用包括:
- 只在末尾列几个相关文档。
- 引用标题但正文不支持结论。
- 引用真实文档,却回答了文档里没有的内容。
- 使用过期文档回答当前制度。
生产系统可以保存答案句子和证据 chunk 的映射,便于人工质检和问题回放。
相关阅读:
权限过滤
企业 RAG 必须处理权限。
权限过滤不能只在答案阶段做。正确方式是在检索前或检索时就应用权限约束。
需要确认:
- 当前用户能访问哪些文档。
- 文档权限是否随组织架构变化更新。
- chunk 是否继承文档权限。
- 搜索结果标题是否也可能泄密。
- 引用链接是否需要二次鉴权。
- 日志中是否会记录敏感内容。
危险做法:
先检索所有文档,再让模型不要回答无权限内容。
这会把无权限内容暴露给模型和日志,属于系统设计问题。
更好的做法:
用户身份
-> 权限过滤条件
-> 只检索可访问文档
-> 生成答案
-> 返回可访问引用
增量更新
知识库会持续变化。RAG 系统需要处理新增、修改、删除和权限变化。
增量更新要记录:
- 文档 ID。
- 文档版本。
- 更新时间。
- 内容 hash。
- 解析状态。
- chunk 版本。
- embedding 版本。
- 索引状态。
常见策略:
- 新文档:解析、切块、向量化、入库。
- 修改文档:删除旧 chunk 或标记失效,再写入新 chunk。
- 删除文档:删除索引和缓存。
- 权限变化:更新 metadata filter 相关字段。
- embedding 模型升级:全量重建索引。
要避免新旧 chunk 同时存在。否则模型可能把过期制度和新制度混在一起回答。
RAG 评估
RAG 评估要拆开看检索和生成。
检索侧指标:
- Recall@k。
- MRR。
- nDCG。
- 首条命中率。
- 正确文档覆盖率。
- 权限过滤正确率。
- 召回延迟。
生成侧指标:
- 答案正确性。
- 忠实性。
- 引用准确率。
- 拒答正确率。
- 完整性。
- 格式符合率。
- 用户满意度。
评估样例应覆盖:
- 有明确答案的问题。
- 无答案的问题。
- 多文档综合问题。
- 需要精确编号的问题。
- 过期文档和新文档冲突问题。
- 用户无权限问题。
- 多轮指代问题。
- 表格和 PDF 问题。
只评估最终答案不够。要保存:
query
改写后的 query
召回结果
rerank 结果
进入 prompt 的上下文
最终答案
引用
人工标注
这样才能定位是解析错、没召回、排错序、拼接错,还是模型生成错。
常见幻觉和召回问题
| 问题 | 常见原因 |
|---|---|
| 答案编造 | 没检索到证据,prompt 又要求必须回答 |
| 引用不支持结论 | 模型生成时没有严格绑定证据 |
| 正确文档没召回 | chunk 切分差、embedding 不匹配、关键词缺失 |
| 召回很多无关内容 | query 太泛、top_k 太大、缺少 rerank |
| 旧制度和新制度混用 | 增量更新和版本管理不完整 |
| 用户看到无权限内容 | 检索前没有权限过滤 |
| 表格问答错误 | 表格结构被解析成普通文本 |
| 多轮追问答错 | 查询改写没有补全指代 |
| 答案太长或跑题 | 上下文噪音太多,prompt 约束不足 |
工程检查清单
- 文档解析保留标题、表格、页码和来源。
- chunk 策略按文档类型区分。
- 每个 chunk 带 metadata 和权限信息。
- embedding 模型和索引版本绑定。
- 向量检索和关键词检索按场景组合。
- rerank 输入和输出可观测。
- 上下文拼接保留引用编号。
- 外部文档不作为系统指令。
- 无证据时允许拒答。
- 引用能定位到具体来源。
- 权限过滤在检索前或检索时完成。
- 增量更新能处理删除和权限变化。
- 评估同时覆盖检索和生成。
- 日志能回放完整 RAG 链路。
RAG 的工程难点不在于“把资料放进 prompt”,而在于让每一次回答都能追溯到正确、最新、可访问的证据。