rag 最小可行系统怎么搭

接入与开发

从零搭一个最小可用 RAG 系统的工程落地顺序:先跑通链路,再补超时、并发、降级、日志和评测。

想给自己的资料做个问答,看了一圈 RAG 教程,结果卡在两处:一是不知道先搭哪块、后搭哪块,二是拿到的示例代码能跑通一次,接上真实文档和线上流量就开始超时、断流、答非所问。这篇不重复讲原理,只给一条能落地的搭建顺序,以及每一步该定的参数、该记的日志、该留的退路。

想给自己的资料做个问答,看了一圈教程,结果卡在两处:一是不知道先搭哪块、后搭哪块,二是拿到的示例代码能跑通一次,接上真实文档和线上流量就开始超时、断流、答非所问。这篇不重复讲原理,只给一条能落地的搭建顺序,以及每一步该定的参数、该记的日志、该留的退路。

先记住一句话:最小可行系统的目标是「链路先跑通、坏了能看出来」,不是效果最好。先把一条闭环走顺,你才知道瓶颈在哪一环;反过来,一上来就上多路召回和重排,出了问题连查都无从查起。

先定边界:最小系统的四块拼图

最小可行系统只包含四块:进料(把文档切成段并入库)、召回(按问题取回若干段)、拼装(把段落和问题塞进一次请求)、生成(拿回答并附来源)。多路召回、重排、Agent 循环这些先不要碰,它们是在你确认召回质量本身不达标之后才加的东西。

进料
把原始文档切成小段,算出向量写进库,顺带存好原文位置
召回
拿问题去向量库里取回最相近的若干段,取几段是个要调的参数
拼装
把取回的段落和用户问题按固定模板拼成一次请求的上下文
生成
把上下文发给模型,拿回答案,并把引用到的段落一起返回
  • 选型原则是按你手上已有的东西选:向量库优先挑托管或单机版,嵌入用平台现成接口,别在第一天就自建推理
  • 具体有哪些可选项、当前各家的能力和限制,去 /stacks/vector-dbs 和 /embeddings 翻当时的清单,别凭记忆挑
  • 先写一个离线脚本,拿二十条你自己的真实问题跑一遍,肉眼比对答案对不对
  • 链路能对上一半以上再谈优化;如果连一半都不到,问题多半在进料,不在模型

超时和并发:把数字定在代码里

一次问答应拆成三段超时:嵌入调用、向量库查询、生成调用,三段各自设阈值,不要共用一个总超时。共用一个总超时的后果是,你只知道整体慢,不知道慢在哪一段,也就没法优化。具体秒数参考 /tools/speed-test 量出的你自己的延迟基线,没有基线就凭感觉设,等于没设。

环节超时设在哪超了之后怎么处理
嵌入调用单次请求级别重试一次,仍失败则整个请求快速失败
向量库查询单次查询级别记日志并返回空召回,走降级路径
生成调用整个请求级别中断本次生成,返回已召回片段列表
整条链路用户可感知的上限超过就返回「正在处理」或直接告知失败

并发要按最窄的那一环卡。嵌入接口、向量库、生成模型三者的限制通常不一样,取最小值做上限,超出的请求排队或直接拒绝,别让它无限堆着。堆着的请求会一起超时,最后你看到的是大面积失败,反而找不到真正的瓶颈。

  • 重试只对幂等的读操作做,写库和计费类调用不要盲目重试
  • 重试要有次数上限和退避间隔,否则限流时会自己把自己打死
  • 排队队列要有长度上限,满了就拒绝,拒绝的时候告诉用户稍后再试
  • 把每段的实际耗时打点记下来,这是后面调超时的唯一依据

降级路径:坏了以后返回什么

至少准备两条退路。检索为空时怎么办:直接让模型基于自身知识回答并明确标注「未命中资料」,别硬塞几段不相关的段落进去,那样模型会被带偏。生成调用失败时怎么办:返回原文片段列表,让用户自己去读,这比返回一个报错页面有用得多。

生成模型可以配一个备选,但切换的判断条件要写清楚,比如连续失败几次、或单次耗时超过阈值。不要用「返回内容不好」当切换条件,那个没法自动判断,只会变成永远不切或乱切。

  1. 标出降级状态返回结果里带一个字段说明本次是否走了降级,前端或调用方能看见
  2. 验证退路真的能走手动把生成接口的地址改错一次,看系统是不是按预期返回片段列表而不是报错
  3. 给内部使用者提示对内部工具,降级返回时在界面上加一句「本次为降级结果」,避免被当成正常答案使用

日志和评测:让问题可复盘

每次问答至少记这几项:问题原文、召回到的段落 ID 与相似度、拼装后的上下文长度、生成耗时、用了哪个模型、是否走了降级。没有这些字段,用户说「答错了」你只能重跑一遍猜,猜十次也未必复现。

日志字段为什么记什么时候会用到
问题原文复现问题的基础用户反馈答错时
召回段落 ID 与相似度判断是召回不行还是生成不行答案缺关键信息时
上下文长度看是否被截断、是否太长拖慢生成生成变慢或答不全时
是否降级区分正常返回和兜底返回排查偶发错误时

准备一组固定问题当回归集,改动分块方式、换嵌入模型、换生成模型之后都跑一遍同一组,比对命中率和人工评分。检索相关的指标口径,可对照 /benchmarks/registry 里的榜单说明理解,但别把榜单分数当成你自家数据上的结论。

  • 评测不用上工具,一张表格加人工打分就够起步
  • 关键是同一组问题、同一套评分标准,换个人评也大致能对齐
  • 回归集要覆盖:能在资料里找到答案的、资料里没有的、问题本身有歧义的
  • 每次改动后记录改了哪一项、分数怎么变,形成你自己的小账本
先跑通再优化:能复盘的烂系统,比说不清楚的「好系统」有用得多。
下一步搭之前先去站内把可选组件和速度基线看一眼,别凭印象选型;第一版能不能跑顺,很大程度上取决于你一开始挑的这几块配不配得上你的资料量。

常见问题

最小可行系统到底要不要上重排和混合检索?

先不上。单路向量召回跑通、有一组固定问题能测出命中率之后,再判断是不是召回质量拖了后腿。如果问题本身是关键词型的(编号、专有名词、代号),那才优先补关键词召回;否则加了重排也只是把同一批段落换个顺序,问题不在那儿。

文档多长要切多细,有没有通用值?

没有通用值,判断依据是「一段能不能独立回答一个问题」。可以先按段落或标题层级切,再针对切完太碎的段做合并、太长的段做二次切分。切完之后抽十条真实问题,看召回的段落里有没有刚好包含答案,命中率明显偏低就先调切法,别急着换模型。

上线后发现答得慢,先查哪一步?

按链路顺序量一遍:嵌入调用多久、向量库查询多久、生成首字多久、整体多久。多数时候瓶颈在生成那一段,其次是召回条数给太多把上下文撑长。先减少召回条数看效果有没有变化,这比换模型快得多,也便宜得多。

本文依据各平台公开文档与官方公告整理,只做中文归纳;具体做法、参数与限制以官方文档为准。