返回实战列表
RAG 32 分钟阅读

RAG 系统实现指南

从检索目标、数据准备、索引方案到回答验证,系统理解 RAG 应该如何落地,而不只是拼接一条向量检索链路。

C
ClawList Team
· 发布于 2025-03-10 · 更新于 2026-03-24

先别急着做 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 常见的几个部件,不代表你的运行时一定提供完全同名的 DocumentLoaderTextSplitterRetrieverVectorStore

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 策略是否与文档类型匹配?
  • [ ] 检索后是否有过滤 / 重排序?
  • [ ] 回答策略是否限制幻觉并要求引用?
  • [ ] 是否有最小评测集?

下一步读什么?