RAG 系统实现指南
从检索目标、数据准备、索引方案到回答验证,系统理解 RAG 应该如何落地,而不只是拼接一条向量检索链路。
先别急着做 RAG
很多团队一遇到“知识更新”就想上 RAG,但真正的问题有时并不是缺少向量数据库,而是:
- 文档本身就没有整理好
- 查询意图没有分类
- 回答验收标准不明确
- 其实应该先做关键词检索或 FAQ
RAG 不是“接一个 embedding 就会更聪明”,它本质上是一个检索系统加一个回答系统。
什么场景真的适合 RAG?
更适合 RAG 的场景通常有这些特征:
- 需要回答基于私有知识或最新知识的问题
- 回答必须引用或贴近原始材料
- 文档规模已经超过 prompt 能直接容纳的范围
- 用户查询经常不是精确关键词,而是语义型问题
如果你的知识库很小、问题模式非常固定,先做高质量搜索或结构化 FAQ 往往更划算。
前置准备
在设计 RAG 之前,先确认:
- 你知道用户会问什么问题
- 你知道答案来自哪些文档
- 你能定义“命中对了”是什么意思
- 你能接受怎样的延迟与成本
没有这些前提时,RAG 很容易做成“能跑,但不稳定”。
一个完整的 RAG 视角
RAG 至少包含 5 个环节:
文档准备 -> 切分策略 -> 索引存储 -> 检索排序 -> 回答生成与验证真正影响结果的,不只是模型,而是每一环都是否匹配你的问题类型。
第一步:先定义检索目标
最先要回答的问题不是“用哪家向量库”,而是:
- 你的查询更像问答、摘要、比对还是定位片段?
- 你希望返回整段文档、若干 chunk,还是结构化答案?
- 你是否需要引用来源?
例如:
- 客服知识库:强调命中率与可追溯性
- 代码文档问答:强调精确定位和版本过滤
- 研究材料总结:强调多来源聚合与重排序
第二步:文档质量往往比检索算法更重要
如果原始文档本身:
- 标题混乱
- 没有更新时间
- 段落粒度不合理
- 同一主题分散在多个地方
那么你后面的 embedding、rerank、prompt 优化都会事倍功半。
建议先整理:
- 文档来源
- 文档类型
- 更新时间
- 版本信息
- 访问权限
第三步:决定 chunk 策略
Chunk 不是越小越好,也不是越大越稳。
一个实用思路是:
- 优先按语义边界切
- 保持 chunk 内信息完整
- 让 chunk 足够小,便于召回
- 但又足够大,能支持回答
例如:
- FAQ / API 文档:可更小粒度
- 教程 / 长文:需要保留段落上下文
- 代码仓库:常要带上文件路径与模块边界
第四步:选向量库时别只看性能表
常见选择包括:
| 数据库 | 更适合什么场景 | |--------|----------------| | Pinecone | 轻运维、托管式生产环境 | | Weaviate | 希望更强 schema / 自托管能力 | | Chroma | 本地原型、轻量实验 | | Milvus | 更大规模向量场景 | | Qdrant | 需要灵活过滤与较强实时性 |
比“谁最快”更重要的问题是:
- 你是否需要 metadata filter?
- 是否要多租户隔离?
- 索引更新频率高不高?
- 你能接受多高的运维复杂度?
一个更可信的实现示意
下面的代码是架构示意,展示一个 RAG pipeline 常见的几个部件,不代表你的运行时一定提供完全同名的 DocumentLoader、TextSplitter、Retriever 或 VectorStore。
const ragPipeline = {
loader: 'document-loader',
splitter: 'text-splitter',
store: 'vector-store',
retriever: 'hybrid-retriever',
answerer: 'llm-with-citations',
};你真正需要落地的是职责,而不是类名:
- 谁负责导入文档
- 谁负责切分
- 谁负责索引与更新
- 谁负责检索与重排序
- 谁负责回答与引用输出
第五步:检索不是结束,排序与过滤也很关键
很多“RAG 效果差”的系统,问题不是向量召回,而是后处理太弱。
常见可优化点:
- metadata 过滤
- 关键词 + 向量混合检索
- reranker 重排序
- 按版本、语言、时间范围裁剪候选
如果你的业务很依赖精确性,后处理往往比单纯换 embedding 更有效。
第六步:回答阶段必须告诉模型怎么用上下文
检索回来 5 段内容,不代表模型一定会好好使用。
你需要明确回答策略,例如:
- 只允许根据已检索内容回答
- 缺证据时必须承认不知道
- 输出里要包含引用来源
- 多个来源冲突时必须指出冲突
这一步决定了系统到底是“检索增强回答”,还是“检索完继续幻觉”。
如何验证 RAG 是否真的有效?
不要只看 demo。至少要验证:
- 召回是否命中正确文档
- 排序后前几条是否真的相关
- 回答有没有引用错文档
- 缺资料时是否会乱编
- 更新知识后结果是否同步改善
常见坑
1. 先建索引,后想问题类型
如果你还不知道用户怎么问,就很难设计好 chunk 和检索逻辑。
2. 把所有文档混在一个桶里
没有 metadata 和边界控制的知识库,很容易让不相关内容相互污染。
3. 把“召回到了”当成“回答正确了”
文档被检索到只是第一步,模型是否正确消费上下文才是真正的质量点。
4. 没有基准集
如果没有一组测试问题和预期答案,你就无法判断系统是否在迭代中变好。
落地前检查清单
- [ ] 是否明确了查询类型?
- [ ] 是否整理好了文档与 metadata?
- [ ] chunk 策略是否与文档类型匹配?
- [ ] 检索后是否有过滤 / 重排序?
- [ ] 回答策略是否限制幻觉并要求引用?
- [ ] 是否有最小评测集?
下一步读什么?
- 如果你想把检索能力封装成可复用能力,继续看 构建自定义 Skills
- 如果你的 RAG 系统要接入团队式协作,继续看 多智能体协作实战
- 如果你还在做基础环境搭建,回到 OpenClaw 快速入门指南