你可能已经把 RAG 的原理看过一遍,也知道要分块、要向量化,但真打开编辑器就卡在第一步:装哪个包、数据怎么喂进去、检索出来的东西怎么拼给模型。这篇按一条能跑通的路线走一遍,从最小可运行版本开始,再补上模型接入和出错时怎么定位。跑通之后怎么调参、怎么换库,看后面的验证清单。
你可能已经把 RAG 的原理看过一遍,也知道要分块、要向量化,但真打开编辑器就卡在第一步:装哪个包、数据怎么喂进去、检索出来的东西怎么拼给模型。这篇按一条能跑通的路线走一遍,从最小可运行版本开始,再补上模型接入和出错时怎么定位。
全程只做一件事:让你对着一份自己的文档问出答案,并且答案里能看到引用来源。跑通之后怎么调参、怎么换库,看后面的验证清单。先别急着上生产,先把链路走直。
先跑通一个最小可运行版本
装包之前先把环境弄干净。确认 Python 版本别太老,建一个独立虚拟环境,把依赖装进去,避免和已有项目打架。很多人第一步就翻车,不是代码写错,是旧环境里的包版本互相顶牛,报错信息还看不懂。
- 读文档把本地一份 PDF、Markdown 或纯文本放进项目目录,用内置的读取器加载成文档对象。先只放一份,别一次塞一堆,出问题好定位。
- 切块对加载进来的文档做切分,得到一批文本块。默认切分器能用就先不调,先看切出来的块长什么样,有没有把一句话切成两半。
- 建索引把切好的块交给索引结构,它会自动完成向量化并落到本地存储。这一步最慢,留意终端有没有报网络或鉴权错误。
- 查询从索引上发起一次提问,观察返回的答案后面有没有跟来源片段。有引用,说明检索这一环真的在工作。
跑通的标准不是「程序没报错」,而是:你换一份自己的文档,问一个只有这份文档里才有答案的问题,它答对了,并且你能看到这条答案是从哪个片段来的。做不到这一点,后面的调参都是空谈。
把默认模型换成你自己的接口
LlamaIndex 里模型分两块:生成答案用的大模型,和把文本变成向量的嵌入模型。两者可以来自完全不同的地方,配置项也分开写,别混在一起改。
| 要配的东西 | 填在哪 | 常见的翻车点 |
|---|---|---|
| 接口地址 | 初始化模型时的 base_url 参数 | 少写或多写一段路径,直接返回 404 |
| 密钥 | 环境变量或初始化参数 | 变量名拼错,程序读到空值 |
| 模型名 | 初始化模型时的 model 字段 | 复制了别的平台的名字,接口不认 |
| 嵌入模型 | 单独的嵌入模型初始化处 | 和大模型用同一个名字,维度对不上 |
换成中转站或自建网关之后,最快的验证方式不是跑完整问答,而是单独调一次模型:发一句最短的提示,看能不能拿到回复。通了再回到索引链路,不通就先把地址和密钥对一遍。
- 嵌入模型一旦换掉,必须重建索引,否则新旧向量不在一个空间,检索结果会莫名其妙
- 只换生成模型不用重建索引,检索部分照旧,改完直接重跑提问就行
- 不确定时先用小样本重建,确认检索命中的片段是相关的,再全量重灌
- 本地试玩、数据量很小的时候,默认模型够用就别折腾,换模型的时间不如多测几个问题
切块与检索:效果不好先调这两个
答案不对,八成不是模型笨,是喂进去的上下文不对。切块和召回条数是两个最值得先动的旋钮,但别同时改,一次只动一个,否则你不知道是谁起的作用。
| 参数 | 调大之后 | 调小之后 | 什么时候别动 |
|---|---|---|---|
| 切块大小 | 单块信息更完整,但噪声也多 | 命中更精准,但容易把上下文切断 | 文档本身就是短条目时,按结构切比按字数切稳 |
| 切块重叠 | 跨块的句子不容易被切断 | 省空间,但边界信息可能丢 | 重叠过大等于把同一段喂两遍,反而挤占上下文 |
| 召回条数 | 命中率上来,但上下文被塞满,回答可能变差 | 回答更快更聚焦,但可能漏掉关键片段 | 文档里有大量表格和扫描件时,调它没用,得先清洗文档 |
没有评测集也能判断改没改好:固定三到五组你确定答案的问题,每改一次参数就跑一遍,重点看召回出来的片段里有没有正确答案,而不是只盯最终那句话。最终答案受生成模型影响太大,片段命中才反映检索质量。
检索没召回的东西,生成模型再强也编不出来;先把召回看住,再谈回答风格。
上线前要补的工程细节
本地跑通和对外提供接口是两件事。链路里有一段是检索、一段是生成,两段都是外部调用,都可能慢、都可能失败,不处理就会表现为「接口偶尔卡住」。
- 超时分开设:检索和生成各设一个超时,别共用一个,否则你不知道是哪一段拖慢的
- 重试要退避:被限流时不要立刻重打,隔一段再试,连试几次还失败就明确报错,别静默吞掉
- 批量灌数据控并发:并发开太大容易触发限流,开太小灌不完,先小批量试出安全值再放大
- 日志记全:把原始问题、召回片段的标识、用的模型名、各段耗时都记下来,出问题才能复盘是哪一步的锅
- 成本与延迟按当时的数字估:到站内成本计算与测速页面核对,别凭感觉
常见问题
LlamaIndex 和 LangChain 搭 RAG 该选哪个?
两者都能跑通同一条链路。LlamaIndex 的抽象更偏检索和索引,写 RAG 时代码短、默认值多;LangChain 覆盖面更广,链路里的每一步都能自己换。如果只是想快速做出一个能用的问答,先用 LlamaIndex;如果后面要接一堆工具和流程,再考虑换或混着用。
为什么我检索到了内容,模型还是答非所问?
先分清是检索没召回对,还是召回对了但模型没用好。把召回的片段单独打印出来看,如果里面没有答案,是切块或嵌入的问题;如果答案就在里面却答错,是提示词拼装或上下文太长被挤掉的问题。两步分开排查,比反复改提示词快得多。
索引建好之后文档更新了怎么办?
全量重建最简单,数据量小的时候直接删了重来。文档多、更新频繁的话,用增量方式按文档 ID 替换,只对变动的文件重新切块和向量化。注意别让新旧版本同时留在库里,否则同一个问题可能召回两条互相矛盾的片段。