很多人的 RAG 在 demo 里效果不错,一上生产就出问题:检索慢、切块切碎、召回不稳、模型偶尔超时、成本突然涨、出问题还查不到是哪一步。这篇不讲原理,只讲工程做法:每个环节该定什么参数、怎么设超时和并发、降级顺序怎么排、日志记哪些字段、上线前后用什么小评测盯住效果。适合已经把 RAG 跑通、准备接进真实业务的开发者。
很多人的 RAG 在 demo 里效果不错,一上生产就出问题:检索慢、切块切碎、召回不稳、模型偶尔超时、成本突然涨、出问题还查不到是哪一步。这篇不讲原理,只讲工程做法:每个环节该定什么参数、怎么设超时和并发、降级顺序怎么排、日志记哪些字段、上线前后用什么小评测盯住效果。适合已经把 RAG 跑通、准备接进真实业务的开发者。
先记住一件事:RAG 的坑大多不在算法,而在链路的哪一段没有被单独观测。下面按进料、切块、向量化、召回、重排、拼装上下文、生成这七段逐段拆,先讲哪几段最容易拖垮整体、错了能不能被发现,再讲参数怎么定档。
先想清楚 RAG 链路里哪几段会出问题
把链路拆成进料(文档解析与清洗)、切块、向量化、召回、重排、拼装上下文、生成七段,逐段问自己两个问题:「这段慢了会不会拖垮整体」「这段错了能不能被发现」。答不上来的那一段,就是上线后第一个出问题的地方。
切块是最容易埋雷的一段:按固定字数硬切会把表格和标题切断,按标题层级切又会让短块语义太弱。比较稳的做法是按文档结构切块,再补一点重叠,让跨块的句子不至于断在关键处。
| 环节 | 能离线做吗 | 失败的后果 |
|---|---|---|
| 解析与清洗 | 能,可重跑 | 垃圾进垃圾出,检索再准也白搭 |
| 切块 | 能,可重跑 | 语义断裂,召回命中但答非所问 |
| 向量化与建索引 | 能,可重跑 | 整批数据不可用,但可重建 |
| 召回与重排 | 不能,只能降级 | 用户直接等待或超时 |
| 生成 | 不能,只能降级 | 答不上来或答错,需兜底 |
离线失败的可以重跑,在线失败只能降级
解析、切块、向量化、建索引这些步骤可以离线批量做,跑失败了大不了重来。召回、重排、生成必须在线完成,出问题就只能降级或返回兜底。所以工程重心应该放在在线那几段的可观测和可降级上,而不是反复调离线参数。
超时、并发、重试怎么定档
给每一段单独设超时,不要只设一个总超时。召回的合理超时通常比生成宽松,因为前者涉及索引扫描和网络往返,后者是流式输出。如果两段共用一个总超时,检索一慢就会把生成直接杀掉,用户看到的是空回答而不是慢回答。
并发按下游最窄的那一环定:向量库、重排模型、生成接口三个上限取最小值,再留一点余量。具体限额到站内官方 API 页面核对当时的说明,别照搬别人博客里的数字,那些数字一过期就会误导你。
- 先给每段标一个基线超时从保守值起步,上线后用日志里的 P95、P99 慢慢收紧,不要一次调到极限。
- 再算并发上限取向量库、重排、生成三方限额的最小值,乘以一个安全系数(比如不到一),剩下的留给突发。
- 最后决定哪些能重试只对幂等且大概率瞬时失败的调用开重试,比如模型调用;检索重试一般没意义,重试只会让延迟翻倍。
- 超过次数就降级重试一两次还失败,直接走降级分支,不要死等,用户等不起。
降级顺序和兜底回答
降级顺序要提前排好,而不是等线上报错再临时想。一个常见的排列是:重排失败就用原始召回顺序;召回为空就退回纯模型回答并标注「未引用资料」;生成超时就返回已召回片段让前端自己处理。顺序一旦确定,就写进代码里当成默认路径。
- 重排失败:退回原始召回顺序,至少保住相关性
- 召回为空:退回纯模型回答,但必须标注未引用资料
- 生成超时:返回已召回片段,交给前端决定怎么展示
- 向量库不可用:直接走兜底话术,不要让请求挂死
降级要能被观测到:每次触发降级都打一条带原因的日志。否则线上你会以为一切正常,其实用户早就在看兜底答案了。兜底回答也不能装作查到了,明确告诉用户这次没有命中知识库,比硬编一个看起来很确定的答案安全得多。
什么情况下不适合降级
如果业务本身对准确性要求极高(比如涉及合规、医疗建议),那就不该让模型在无引用的情况下自由作答,而应该直接返回「暂无相关资料,请人工确认」。降级不等于凑合回答,有些场景宁可明说查不到。
日志字段与上线前的小评测
一次请求至少要记这些字段:请求 id、命中的文档 id 列表、召回条数、重排后条数、各段耗时、最终用的是哪个模型、是否降级。字段缺一个,排查时就多猜一层。请求 id 要能串起整条链路,方便按 id 捞全量日志。
| 字段 | 用途 | 缺了会怎样 |
|---|---|---|
| 请求 id | 串联全链路日志 | 排查时对不上前后步骤 |
| 命中文档 id | 判断召回是否相关 | 不知道答错是召回错还是生成错 |
| 召回/重排条数 | 定位上下文长度变化 | 成本涨了找不到原因 |
| 各段耗时 | 找瓶颈段 | 只能猜是哪段慢 |
| 是否降级 | 确认服务质量 | 以为一切正常,其实全是兜底 |
准备一批固定问题(几十条就够),每次改切块、换嵌入模型、换生成模型都跑一遍,比对命中率和答案是否还带上正确出处。评测不只看答得对不对,还要看「该说不知道的时候有没有说不知道」,这部分建议人工抽查一部分结果。想找现成的对照做法,可以到站内工具目录里看看大家常用的评测脚本和排查思路。
成本与规模变化时先动哪里
成本涨通常来自三处:召回条数变多、上下文变长、重排频繁调用。先定位是哪一处再调,别直接换便宜模型。换模型会影响答案质量,而定位到具体环节往往能只动参数就解决问题。想知道当前各家接口的价格量级,到站内价格追踪页面核对当时的数字,别凭记忆估算。
- 召回条数变多:先看是不是切块太碎导致条数虚高
- 上下文变长:检查是否把整篇文档塞进了 prompt
- 重排频繁调用:确认是不是每个请求都跑重排,能否缓存
- 数据量翻倍:优先看索引和召回延迟,而不是先扩生成侧并发
- 强时效数据:靠 RAG 救不了,得配合定期重建索引
什么时候这套做法不适用:知识库极小(几十页)时,直接把内容塞进上下文可能比搭检索更省事;强时效数据靠 RAG 也救不了,必须配合定期重建索引。判断标准很简单:如果检索带来的延迟和复杂度超过了它节省的上下文成本,那就先别上检索。
下一步先照着上面的七段拆一次自己的链路,把超时、并发、降级、日志四件事各定一个基线;想横向对比各家接口的稳定性和价格量级,去站内价格追踪和 API 资料库核对当时的数字再决定怎么调。→常见问题
RAG 上线后答得不准,先查哪一步?
先看日志里命中的文档对不对,再看重排后有没有把正确片段挤下去。大多数「答不准」其实卡在召回没命中,而不是生成模型不行。把命中文档列表人工看一批,基本能定位是切块问题还是检索参数问题。
检索和生成能不能接不同的模型或中转站?
可以,而且要分开评估。嵌入模型、重排模型、生成模型各自看延迟和稳定性,任一段不稳定都可以单独换。换之前先到站内模型库和价格页面对一下当时的规格,再决定要不要同步调整调用预算。
小团队要不要一开始就上重排和混合检索?
看知识库规模和问题类型。文档量不大、问题偏关键词匹配时,先用向量召回跑通全流程,把日志和评测补齐;等发现召回明显不够再加重排或关键词混合,避免一上来堆组件却定位不了问题。