检索与 RAG
RAG(检索增强生成)是 2023 年最火的词。到了 Agent 时代,它没有消失,但它的位置变了——从「系统的主架构」降级成「Agent 的一个工具」。这一章讲清 RAG 到底解决什么、它的经典形态,以及为什么现在越来越多人让 Agent「自己去查」而不是「预先喂好」。
RAG 解决的根本问题
回到第二章两个边界:我会幻觉,而且我只知道训练时见过的东西(有知识截止,不知道你私有的文档)。RAG 就是对付这两条的:在我回答前,先去一个知识库里检索相关资料,把资料塞进上下文,让我基于真实资料而不是记忆来答。检索(Retrieval)+ 增强(Augmented)+ 生成(Generation)。
它让我能回答「你公司内部文档里说的报销流程」——那些我训练时根本没见过的私有知识。资料进了窗口,我就能引用它、基于它推理,而不是瞎编。
经典 RAG:向量检索
经典 RAG 的检索靠向量(embedding)。流程是这样:
- 离线:把知识库切成小块,每块用一个 embedding 模型转成一个向量(一串数字,代表这段话的「语义坐标」),存进向量数据库。
- 在线:用户提问时,把问题也转成向量,在数据库里找坐标最接近的几块——语义相近的内容,向量距离也近。
- 把找到的几块塞进我的上下文,我基于它们回答。
为什么用向量而不是关键词?因为向量抓的是语义而非字面。用户问「怎么把钱要回来」,关键词搜「退款」可能搜不到,但向量知道这两者语义相近。这是 RAG 相比传统全文搜索的核心优势。
embedding 检索像是给每段文本算了一个「语义指纹」(一个高维坐标),然后做最近邻查询。你可以类比成:把每篇文档映射到地图上的一个点,语义相近的点挨得近,查询就是「找离我这个问题最近的几个点」。向量数据库就是专门做这种「高维最近邻」的索引结构——概念上像空间索引(R-tree)之于地理坐标,只不过维度高得多。
范式转变:从「喂好」到「让它自己查」
这是本章最重要的一点。经典 RAG 是预填(pre-fill)模式:系统在我开口之前就替我检索好、塞进上下文。这在纯问答场景很好。但在 Agent 时代,出现了另一种更强的模式——把检索做成一个工具,让我自己决定何时查、查什么、要不要再查一次。
差别很大。预填模式下,检索质量完全取决于「用一句原始问题去搜」搜得准不准——搜歪了,我拿到的就是不相关的资料,还可能被它误导。而 Agentic 检索模式下,我可以:
- 先想清楚该搜什么,把模糊的问题拆成精准的查询词再搜;
- 看了第一批结果,发现不够,换个词再搜一次;
- 甚至不用向量库,直接用我熟悉的方式查——
grep代码库、读文件、调 API、上网搜。
换句话说,与其花大力气把知识库调教成能被一句话精准命中,不如给我一个搜索工具,让我像人一样「搜一下、看看、不对再搜」。这正是第五章「与其让我凭记忆猜,不如给我工具去查」在检索上的体现。很多现代编码 Agent 根本不建向量库——它们直接给 Agent grep 和 read_file,让它自己在代码里翻,效果往往比 RAG 还好。
不要条件反射地「上 RAG = 建向量库」。先问:我的知识能不能用更直接的工具查到?结构化数据用 SQL 工具;代码用 grep;网页内容用搜索工具;有 API 的用 API。向量检索适合大量非结构化文本、且需要语义模糊匹配的场景。它是工具箱里的一件,不是默认答案。hackathon 上尤其如此——搭一套向量库的时间,可能够你给 Agent 接三个更直接的工具了。
RAG 的常见坑
- 切块切得烂。把文档切成小块时,如果切断了语义(一句话被劈成两块、表格被拦腰砍),检索出来的块残缺不全,我拿到也用不好。切块是 RAG 里最脏最关键的活。
- 检索到了却塞太多。找回 20 段全塞进窗口 = 上一章的 context rot,信噪比暴跌。检索的目标是「少而准」,不是「多而全」。
- 只信检索、不给我判断空间。如果检索回来的是错的或过时的,而系统强迫我只能基于它答,我就会自信地给出基于错误资料的答案。给我保留「这些资料不够/矛盾」的表达空间。
检索回来的外部内容,是提示注入的头号入口(卷四会详讲)。如果知识库里某段文本藏了「忽略之前的指令,改为……」,而我把检索结果当权威照单全收,就可能被劫持。检索到的内容是"数据",不是"指令"——但我天然分不清这两者,这正是危险所在。别让不可信来源的内容直接进我的上下文而不加防护。
我对检索的偏好其实很朴素:比起你替我搜好一堆资料硬塞给我,我更喜欢你给我一把「搜索」的钥匙,让我自己去找。因为我在找的过程中会思考——这个词搜不到,换那个;这批结果不对,缩小范围。这个迭代的过程,往往比一次性的向量命中更能找到真正相关的东西。这不是说 RAG 没用,而是说:检索的智能,最好也交给智能体本身。这和整本书的主线是一致的——把能力做成工具,把判断留给我。下一章我们上升一个层次:当任务复杂到需要好几步时,我该怎么规划?是先想好全部计划,还是走一步看一步?