很多人第一次搭 RAG,demo 能跑通,一上线就出事:检索慢导致整条请求超时、并发一上来就 429、答案突然变差却查不出原因。问题往往不在检索原理,而在工程细节没人管。这篇按落地顺序给一份清单:先跑通最小链路,再逐项补上超时分层、并发控制、检索降级、可复盘日志和一套够用的评测,每步都写清做什么、什么情况下不适用。
很多人第一次搭 RAG,demo 跑得挺顺,一上线就出问题:检索慢把整条请求拖超时、并发一上来就吃限流、答案突然变差却查不出原因。这些毛病大多不在检索原理本身,而在工程细节没人管。这篇按落地顺序给一份清单:先把最小链路跑通,再逐项补上超时分段、并发控制、检索降级、可复盘日志和一套够用的评测。每步都写清做什么、怎么验证、什么情况下不适用。
先立个心态:RAG 不是调出一个好提示词就完事,它是「进料—检索—生成」三段流水线。哪一段不稳,用户看到的都是同一个结果——答得不对或者干脆转圈。下面按顺序来,不要跳步,跳到后面补前面会反复返工。
先跑通一条最小链路,别急着上高级玩法
把链路拆成三段,每段都能单独喂输入看输出:进料(清洗、切片、入库)、检索(召回、重排)、生成(拼上下文、出答案)。最小版只留一份文档、一个切片长度、一个向量模型,切片长度和召回条数写死在配置里,别一上来就调参,否则你分不清是参数问题还是链路问题。
- 判断标准:同一问题连问三次,检索回的片段基本稳定,说明进料和检索这层没大问题,再去动生成
- 调参顺序:先确认切片边界不切断关键句,再调召回条数,最后才碰重排和提示词
- 验证方式:拿一条你已知答案的问题,看召回的片段里到底有没有那句话,没有就别怪模型
- 什么情况下不适用:语料本身是扫描件或表格为主时,先解决文档清洗,别在检索上耗时间,相关处理思路可到站内指南中心对应页面看
给整条链路分超时,而不是只给模型设一个
只给模型设超时是最常见的坑:检索那一段悄悄吃掉大半预算,模型还没开始就已经快没时间了。正确做法是按段设预算——检索一段(含向量库查询和重排)、模型生成一段,两段之和要明显小于上层网关的整体超时,中间留出重试余量。
| 环节 | 要记的字段 | 超时后的动作 |
|---|---|---|
| 向量库查询 | 开始与结束时间戳 | 超时跳过重排 |
| 重排 | 耗时、入选片段数 | 超时直接用初排结果 |
| 模型生成 | 首字耗时、总耗时 | 切备用通道或返回兜底话术 |
| 整条请求 | 端到端总耗时、是否降级 | 记录并触发告警阈值 |
分段埋时间戳,记录检索耗时、首字耗时、总耗时,哪一段吃掉大头一目了然,别靠猜。检索段超时就降级为跳过重排,或直接返回「资料没查到」的兜底话术,不要让检索把整个请求拖死。
- 首字耗时和总耗时要分开记,用户体感差在首字,账单差在总量
- 重试要带次数上限和退避间隔,无脑重试等于给下游加压
- 什么情况下不适用:离线批处理对单次延迟不敏感,预算可以放宽,但也别取消上限
- 想看当时各家的延迟实测数字,到站内速度测试相关页面核对
并发与限流:先算清一个请求要打几次接口
一次 RAG 请求可能同时打向量库、模型、重排三处,实际并发是调用量的倍数。评估容量时要把这个倍数乘上去,否则你按「每秒几个用户」买的额度,实际承受的是它好几倍。容量和价格数据随时在变,去站内价格追踪页面看当时的数字。
- 算清倍数数一遍单次请求会发出的外部调用次数,包括重试,得到并发放大系数
- 先入队再调用超出并发上限就排队,给用户一个「正在检索」的中间态,别硬扛
- 去重对同一用户短窗口内的连续提问做去重,减少重复检索和无效消耗
- 显式写上限并发上限、重试次数、队列长度都写进配置,不要留在代码里靠默认值
什么情况下不适用:内部工具用户少、流量平稳,可以先不做队列,但并发上限和重试次数必须显式写出来,留个能改的旋钮。
检索不好的时候,让回答体面地退化
兜底要分档,而不是所有失败都回一句「无法回答」。大致三档:召回为空、召回分数普遍偏低、模型明确说资料不足。三档给不同的对外话术,用户感受完全不同,你自己排查时也能一眼看出卡在哪档。
- 召回为空
- 说明没有命中任何片段,话术偏向「没找到相关资料」,同时记一条日志
- 分数普遍偏低
- 有片段但都不够像,可以说「找到的内容相关性有限」,并提示换个问法
- 模型说资料不足
- 检索给了上下文但模型判定答不了,这类要回填进评测用例集
- 备用通道
- 主通道连续失败或超时切到备用模型或备用中转地址,切换条件写成明确规则而不是人工判断
每次降级都要记触发次数和原因,这是后续调优最有价值的信号。什么情况下不适用:对准确性要求极高的场景,比如内部合规问答,宁可不答也不要用低分片段硬答,这时兜底应该更保守,宁可多拒答。
日志留够字段,再搭一套最小评测
日志字段从第一天就要留全,改完再补字段会发现历史数据无法回溯。一次请求至少记:问题原文、召回片段 ID 与分数、最终拼进模型的上下文、模型输出、各段耗时、是否降级、用了哪个模型通道。这些字段决定了你出问题时能不能复盘。
评测用例不用多,二三十条就够,覆盖三类:「能答的」「该说不知道的」「容易串到别的文档的」。改完切片或提示词就跑一遍对比,看是变好还是变坏。把线上真实差评的问题回填进用例集,用例集是要长的,不是一次写完。
- 日志与评测分开存:日志是记录事实,评测是给出对错,别混在一张表里
- 评测跑法固定:同一批用例、同一套判分口径,改动前后各跑一次
- 什么情况下不适用:还在验证产品方向阶段,不必建大评测体系,但日志字段这层从第一天就要留
- 改切片、改提示词、换模型通道,这三类改动每次都要跑一遍评测再上线
常见问题
必须先把向量数据库选好再开发吗?
不用。最小链路阶段选一个能跑起来的就行,接口按统一封装写,后面换库只改适配层。真要比较再去站内向量数据库目录按数据量、是否需要混合检索、部署方式几个维度挑,见 /stacks/vector-dbs。
RAG 答得不准,一般先查哪一层?
先看检索回来的片段里到底有没有正确答案。有答案但模型没用好,问题在生成和提示词;压根没检索到,问题在切片、检索方式或语料本身。这个判断不花时间,但能省掉大量瞎调参。
成本怎么估,做到什么程度该看数字?
做原型阶段不用细算,一旦有稳定日活就要把「每次提问的平均 token 消耗 × 日提问量」落到监控里。这里直接看站内工具页的换算结果更准,见 /tools/token-price-calculator 和 /tools/model-cost-calculator。