检索增强(RAG)接入实战:何时加、怎么加最划算(架构、流程、评测、成本全链路)
·
专栏第 10 篇
目标:不是“把 RAG 接上”,而是“在可控成本下稳定提升正确率与可解释性”。
一、问题描述:为什么很多团队做了 RAG,效果却不升反降?
你可能见过这种情况:
- 接入 RAG 之后,回答变长了,但正确率没有明显提高;
- 召回了很多“看起来相关”的片段,最终答案仍然答非所问;
- 时延从 2 秒涨到 6 秒,用户体验变差;
- token 成本持续上涨,团队开始怀疑 RAG 的价值。
这不是 RAG 技术本身的问题,核心是工程落地顺序错了:
- 没有先判断接入时机;
- 没有明确检索目标(召回什么、为什么召回);
- 没有评测基线(改前改后无法对比);
- 没有成本治理(只追质量,不控成本)。
结论:RAG 不是“一个组件”,而是一条需要评测闭环的生产链路。
二、何时该加 RAG?先做“接入时机判断”
如果你的系统满足以下条件中的 3 条以上,再进入 RAG 接入阶段:
- 问题高度依赖私域知识(内部文档、流程规范、知识库)
- 纯 Prompt 已到瓶颈,幻觉率明显影响业务
- 知识更新频繁(每周/每天),无法靠静态 Prompt 维护
- 已有基础可观测能力(日志、指标、错误归因)
- 有最小维护能力(文档清洗、索引更新、评测回归)
如果不满足,建议优先做:
- Prompt 版本化 + 评测基线;
- 工具层稳定性;
- 上下文治理。
不要为“追热点”而接 RAG。
三、最小可用 RAG 架构(MVP)
建议先用下面这条标准链路:
Query -> Query Rewrite -> Retrieve -> Rerank -> Context Pack -> Generate -> Verify
各环节职责:
- Query Rewrite(查询改写)
- 目的:减少歧义、补全实体、统一术语。
- Retrieve(召回)
- 目的:尽可能不漏掉候选信息(高召回)。
- Rerank(重排)
- 目的:把“真正有用”的片段排到前面(高精度)。
- Context Pack(上下文打包)
- 目的:在 token 预算内注入最有效信息。
- Generate(生成)
- 目的:基于上下文回答,并给出来源线索。
- Verify(可选校验)
- 目的:关键场景下做事实一致性检查。
四、知识入库:先把“脏文档”变“可检索资产”
RAG 效果的 50% 取决于数据质量,而不是模型大小。
4.1 入库前处理建议
- 文档去噪:去掉导航、页脚、重复模板
- 结构保留:保留标题层级(H1/H2/H3)
- 语义切分:按自然段与小节切分,而非硬按字符
- 元数据补齐:
source,title,section,updated_at,version
4.2 Chunk 策略(起步参数)
- chunk 长度:
300~500 tokens - overlap:
60~100 tokens - 每个 chunk 保留可追溯源信息
过小 chunk:上下文不完整;过大 chunk:噪音增加、成本上升。
五、检索策略:混合检索比单一路径更稳
实战推荐:向量检索 + 关键词检索(BM25)混合。
- 向量检索:擅长语义相似
- BM25:擅长命中关键词、ID、错误码、专有名词
5.1 典型流程
- 向量召回 top-k(如 20)
- BM25 召回 top-k(如 20)
- 合并去重(union)
- 重排 top-n(如 8)
- 最终注入 top-3~5
5.2 为何必须重排?
没有重排时,常见问题是“召回相关,但不够关键”。
重排能显著提升答案稳定性,尤其在多文档场景。
六、上下文打包:决定生成质量与成本上限
RAG 不是“塞越多越好”。建议规则:
- 只注入 top-3~5 片段;
- 每个片段限制长度(如 <= 220 tokens);
- 同源片段做合并去重;
- 强制保留
source字段用于可解释引用。
6.1 推荐 Prompt 模板片段
你将基于检索上下文回答用户问题。
要求:
1) 仅使用上下文中的事实,不得臆测;
2) 若上下文不足,明确说明“信息不足”;
3) 输出时附上来源标识(source/title/section)。
七、评测体系:没有评测,就没有优化
先建立一个 30~80 条的评测集,覆盖:
- 核心高频问题
- 易混淆问题(近义概念)
- 边界问题(长 query、模糊问法)
- 时效问题(更新后的知识)
7.1 核心指标(建议)
- Recall@k:正确片段是否被召回
- MRR / nDCG:正确片段排位是否靠前
- Faithfulness:答案是否忠于检索内容
- Answer Success Rate:用户目标是否达成
- Cost per Request:单请求综合成本
- Latency p95:线上体验关键指标
7.2 评测门禁示例
只有同时满足以下条件才允许上线:
- Faithfulness 提升 >= 5%
- Success Rate 不下降
- p95 增幅 <= 20%
- 单请求成本增幅 <= 25%
八、成本控制:RAG 的关键不是便宜,而是“单位收益最大化”
成本治理建议按优先级做:
- 减少无效召回:优化 query rewrite + minScore
- 减少无效注入:top-3~5,限制 chunk 长度
- 缓存高频问题:query 归一化后缓存
- 分层模型:检索环节用轻模型,生成环节按场景升级
- 异步化非关键步骤:降低前台等待时延
九、常见报错与排查(高频)
1)“召回命中,但回答仍错”
- 可能原因:重排质量低,优质片段没进上下文
- 处理:引入 rerank + 调整 top-n
2)“回答总说信息不足”
- 可能原因:chunk 过碎,上下文断裂
- 处理:增大 chunk 或改善切分策略
3)“延迟过高”
- 可能原因:召回量过大 + 重排过重
- 处理:降低候选量、做缓存、优化并行度
4)“更新文档后效果不稳定”
- 可能原因:索引未及时刷新或混入旧版本
- 处理:索引版本化 + 增量更新 + 定时全量校验
十、实现伪代码(简化版)
def rag_answer(query, kb, retriever, reranker, llm):
q = rewrite_query(query)
v_hits = retriever.vector_search(q, top_k=20)
b_hits = retriever.bm25_search(q, top_k=20)
merged = dedup_union(v_hits, b_hits)
ranked = reranker.rank(q, merged)[:8]
context = pack_context(ranked, max_chunks=5, max_tokens=900)
prompt = build_prompt(query, context)
answer = llm.generate(prompt)
return {
"answer": answer,
"sources": [x.meta for x in ranked[:5]],
"debug": {
"retrieved": len(merged),
"used": len(context)
}
}
十一、本篇总结
RAG 的价值不在“接了没有”,而在“能否稳定提升正确率,并且成本可控”。
一句话总结:先判时机,再做最小链路,用评测和成本指标驱动迭代。
更多推荐
所有评论(0)