你可能已经跑通过一次「向量库 + 大模型」的问答 demo,但一放进真实场景就出问题:回答慢、偶发断流、知识库更新后答案还是旧的、出错时不知道是检索还是生成环节挂了。这篇不讲原理,只给一条能落地的搭建顺序,以及每个环节该设的默认值和排查入口,让你把小 demo 变成能长期跑的服务。
你可能已经跑通过一次「向量库 + 大模型」的问答 demo,但一放进真实场景就出问题:回答慢、偶发断流、知识库更新后答案还是旧的、出错时不知道是检索还是生成环节挂了。这篇不讲原理,只给一条能落地的搭建顺序,以及每个环节该设的默认值和排查入口,让你把小 demo 变成能长期跑的服务。
整条链路其实就四段:把问题改写成检索语句、召回候选片段、拼接上下文、交给模型生成带出处的回答。先把这四段串成一个同步单轮接口跑通,再谈多路召回、重排和工具循环。下面按搭建顺序拆,每节都给你判断标准和该动手做的事。
先跑通最小闭环:一次提问到一次回答
第一版别追求聪明,追求「可观测」。每个环节都留一个中间产物:改写后的查询、召回的片段 id 与相似度、最终拼进 prompt 的字符数。这样线上出问题时,你能一眼看出是检索没召回,还是召回对了但拼接时被截断,还是模型没按资料答。
- 定接口形状输入一个问题,输出一个结构化对象:answer、citations 数组(片段 id + 原文片段)、以及可选的 trace_id。先定死这个返回结构,后面所有改动都不动它。
- 写死检索路径先用单一向量库、单一相似度检索,不做重排和多路召回。跑通标准是同一批问题反复问三次,答案结构稳定、引用不飘,而不是答对某一道题。
- 加人工核对入口先只做单轮问答,返回里必须带引用来源,方便人工点开原文核对答案是否真来自你的资料。引用对不上,后面调什么都是空转。
上下文和分片:决定回答质量的真正变量
很多人调了半天提示词,其实瓶颈在分片。分片别只按固定字数切,标题、表格、代码块要尽量保持完整,切碎了检索再准也拼不出完整答案。切分规则一旦定下,就写成脚本固定下来,不要每次手动切。
- 召回条数不要凭感觉定,先定「拼进 prompt 的总字符预算」,再倒推每个片段的最大长度和条数上限
- 检索相似度低于阈值时不要硬塞给模型,宁可回答「资料里没有」,这比编一个更省事,也更可信
- 知识库更新频繁时,要有一套重新入库或增量更新的固定动作,否则模型答的是旧版本内容
- 每个片段带上来源标识和更新时间,回答时一并返回,方便用户判断这条资料还新不新
预算怎么定没有通用答案,取决于你接入的模型上下文窗口和你的延迟容忍度。到站内模型资料库核对当时各模型的上下文规格,再结合你自己的平均片段长度去算,别无脑照抄别人的参数。
超时、并发与降级:让它在真实流量下别崩
demo 和服务的差别就在这一节。检索和生成是两个独立的外部依赖,各自会超时、会限流,必须分开设阈值分开处理,不要一个 try 包到底。
| 环节 | 失败时的动作 | 对外表现 |
|---|---|---|
| 检索超时 | 降级为纯模型回答 | 响应标注「未检索到资料」 |
| 生成超时或限流 | 换备用模型或缩短上下文重试一次 | 两次都失败返回明确错误码 |
| 向量库不可用 | 走缓存或直接拒答 | 接口不卡死,前端能收到结果 |
| 用户重复提交 | 幂等或请求去重 | 不触发两次检索和两次计费 |
并发不是越大越好。先量出你这条链路的单次耗时基线,再按接口的限流额度决定并发数与排队策略。对外接口要做幂等或请求去重,用户连点两次不该触发两次完整检索和两次计费。
日志与评测:改完到底变好没有
每次请求记四个字段就够排查:问题原文、召回片段 id、拼进 prompt 的 token 数、各段耗时。少了哪一个都会让你卡在猜。日志要能按 trace_id 串起来,检索和生成两段日志不要分散在两个系统里找不到。
评测分两层:检索层看召回是否命中该命中的资料,生成层看答案是否忠于资料。两层混在一起看会误判,常见的就是检索明明没召回,你却去改提示词。
- 回归用例
- 一批固定问题,改分片、改提示词、换模型后跑一遍,比凭感觉靠谱
- 失败样例库
- 把答错、引用错、拒答过多的case单独存下来,各自有对应调整方向
- 耗时基线
- 记录正常情况下的分位耗时,作为判断「这次是不是变慢了」的参照
什么时候才该上工具调用循环
只有当一个问题需要多次检索或多步操作(先查 A 再根据结果查 B)时,才值得把检索包成工具交给 Agent 循环。简单一问一答用固定流水线更快更便宜,套上循环只会增加延迟和费用。
- 上循环必须配步数上限和总成本上限,否则模型可能在检索和回答之间反复横跳
- 循环里每一轮都要记日志,不然出问题你只看到最终答案,看不到它中间查了什么
- 循环不适合强实时场景,用户对首字延迟敏感时优先固定流水线
- 判断标准很简单:去掉循环后答案明显变差,才说明循环有价值,否则就是白加延迟
成本这块别凭估算,串联循环的实际花费跟调用轮数强相关。到站内价格追踪页面看当时各家接口的计费方式,再乘上你的平均轮数去估,比拍脑袋准。
先把一条同步链路跑稳、能观测、能降级,再谈让它变聪明。下一步搭建前先去站内模型资料库核对上下文规格和计费方式,再回来定你的分片预算和并发上限,这一步能省掉后面大量返工。→
常见问题
必须要用 Agent 框架才能搭 RAG Agent 吗?
不必须。如果你的场景就是「一个问题检索一次然后回答」,直接用普通函数串起来最省事,调试也直观。只有当问题需要多轮检索、需要根据中间结果决定下一步做什么时,引入 Agent 循环才有收益,否则只是多了一层黑盒。
检索到的资料明明是对的,模型还是答错,问题出在哪?
多半在拼接环节。检查片段有没有被截断在半句话上、多个片段之间有没有互相矛盾、提示词里有没有明确要求「只依据给定资料回答并标注来源」。这几项里任何一项没做好,模型都会自行补全,看起来就像没检索。
知识库更新之后要重新跑一遍全部数据吗?
看更新方式。整批替换或换分片策略,就得全量重跑;只是新增或修改少量文档,做增量更新即可。关键是给文档留稳定的标识,避免同一份资料在库里存了两份不同版本,检索时召回旧的。