📚 从文档到答案:一个RAG系统的完整故事


第一章:准备工作——把文档”搬进”系统

想象你有一个大书架,上面堆满了各种资料。现在你要做一个智能助手,能让用户问问题,然后从这些资料里找到答案。

第一步:把书拆成”纸条”

你不可能把整本书直接塞给系统,因为:

  • 系统一次处理不了太多文字
  • 用户问的是具体问题,你需要找到具体段落

所以你要做的是:**把每本书拆成一张张”小纸条”**,每张纸条大概几百个字。

比如一本5000字的说明书,你会拆成10张纸条,每张500字左右。而且为了让上下文不丢失,相邻两张纸条之间会重叠几十个字——就像你撕纸条时,两张之间会有一部分连着。

第二步:给每张纸条做三份”档案”

这是最核心的一步。每张纸条产生后,你同时给它做三份不同的”档案”,分别放进三个不同的”柜子”里:

档案一:做一张”关键词地图”(倒排索引)

你拿一张纸条,比如内容是”苹果手机性能很强,拍照效果很好”。你用Jieba(中文分词工具)把它切成词:”苹果”、”手机”、”性能”、”很强”、”拍照”、”效果”、”很好”。

然后你在一本大笔记本上记下来:

  • “苹果” → 这张纸条的编号
  • “手机” → 这张纸条的编号
  • “性能” → 这张纸条的编号
  • …

这个笔记本就叫倒排索引。它的作用是:当用户搜索”手机”时,你能立刻翻到”手机”这一页,看到所有包含”手机”的纸条编号。

档案二:把纸条原封不动存起来(正排索引)

你拿一个盒子,把纸条原文”苹果手机性能很强,拍照效果很好”完整地放进去,在盒子外面贴上纸条编号。

这个盒子就叫正排索引。它的作用是:当你确定了要拿哪几张纸条时,能立刻根据编号找到原文内容。

档案三:给纸条拍一张”语义照片”(向量化)

这一步最神奇。你用一个叫Embedding模型的”翻译官”,把纸条的内容翻译成一组数字。这组数字大概有几百个,比如 [0.12, -0.56, 0.78, ...]。

这组数字不是乱码,它代表了这段话的”语义位置”。什么意思呢?你可以想象一个巨大的地图:

  • “苹果手机”和”华为手机”的语义位置离得很近
  • “苹果手机”和”西红柿炒蛋”的语义位置离得很远

然后你把这张”语义照片”连同纸条编号一起,存进一个专门的仓库——向量数据库。


第二章:用户提问——系统开始”破案”

现在,一个用户来了,他问:”苹果手机值得买吗?”

第三步:把问题也”处理”一遍

系统拿到问题后,做两件事:

第一件事:用Jieba切词
把”苹果手机值得买吗”切成:”苹果”、”手机”、”值得”、”买”。

第二件事:用Embedding翻译官翻译
把整个问题”苹果手机值得买吗”翻译成一组数字(向量),这组数字代表了问题的”语义位置”。

第四步:兵分两路,同时搜索

系统派出两路人马,同时去找答案:

一路人马:拿着”关键词地图”搜索

这路人拿着切好的词——“苹果”、”手机”、”值得”、”买”——去翻之前那本大笔记本(倒排索引)。

  • 翻到”苹果”这一页,看到有纸条A、纸条C
  • 翻到”手机”这一页,看到有纸条A、纸条B、纸条D
  • 翻到”值得”这一页,发现没有
  • 翻到”买”这一页,发现也没有

然后统计:纸条A出现了两次(苹果和手机),纸条B出现一次,纸条C一次,纸条D一次。按出现次数排序,纸条A排第一。

这路人找到的结果,是靠”关键词匹配”的。它的优点是精确——用户问”苹果”,它就能找到包含”苹果”的纸条。缺点是太死板——如果用户问”iPhone”,而文档里写的是”苹果手机”,它就找不到了。

另一路人马:拿着”语义照片”去向量仓库比对

这路人拿着问题的”语义照片”(向量),走进向量数据库仓库。仓库里存着所有纸条的”语义照片”。这路人说:”帮我找一下,哪些照片跟我的这张最像?”

仓库里的系统开始计算:问题照片跟纸条A的照片距离多远?跟纸条B呢?跟纸条C呢?……然后选出距离最近的10张。

这路人找到的结果,是靠”语义相似度”的。它的优点是聪明——用户问”iPhone”,它能把写有”苹果手机”的纸条也找出来,因为它俩的语义位置离得很近。缺点是可能漏掉一些精确的关键词。

第五步:把两路结果”融合”在一起

现在你有两份名单了:

  • 关键词那路:纸条A(第1名)、纸条B(第2名)、纸条C(第3名)……
  • 语义那路:纸条E(第1名)、纸条A(第2名)、纸条F(第3名)……

两份名单各有各的好,你怎么合并呢?

你用RRF(倒数排名融合)算法:给每张纸条算一个综合得分。大致逻辑是:

  • 纸条A在两边都排得很靠前 → 得分非常高 → 排第一
  • 纸条B只在关键词那路排第二 → 得分中等
  • 纸条E只在语义那路排第一 → 得分也不低

最后你选出综合得分最高的5张纸条,作为”最佳候选”。

这就是混合搜索——关键词搜索和语义搜索都用了,取长补短,又准又全。


第三章:生成答案——把”候选”变成”回答”

第六步:取出纸条原文

你现在手里有5个纸条编号:A、B、E、G、H。

你走到正排索引那个盒子前,按照编号:

  • 拿出纸条A,上面写着”苹果手机性能很强,拍照效果很好,电池续航也不错……”
  • 拿出纸条B,上面写着”苹果手机价格较高,但保值率不错……”
  • 拿出纸条E,上面写着”新款iPhone在处理器性能上领先安卓旗舰……”
  • ……

你把这5张纸条的原文全部拿出来了。

第七步:把原文和问题一起”喂”给大模型

你写一段话(这叫Prompt),大概长这样:

1
2
3
4
5
6
7
8
9
10
11
你是我的助手。下面是一些参考资料,请根据这些资料回答用户的问题。

参考资料:
1. 苹果手机性能很强,拍照效果很好,电池续航也不错……
2. 苹果手机价格较高,但保值率不错……
3. 新款iPhone在处理器性能上领先安卓旗舰……
(一共5条)

用户问题:苹果手机值得买吗?

请你只根据参考资料回答,如果资料里没有答案就告诉我不知道。

然后你把这段话发给大模型(比如GPT-4)。

第八步:大模型给出最终答案

大模型看完后,给出回答:

“根据资料,苹果手机在性能、拍照和保值率方面表现不错,但价格相对较高。如果你看重性能和保值,且预算充足,它是值得考虑的选择。不过建议结合自己的实际需求来判断。”

第九步:把答案和引用一起返回给用户

你不仅把答案还给用户,还贴心地附上”我根据以下资料回答的”:

1
2
3
4
5
答案:……(上面那段话)

参考来源:
- 资料1:苹果手机性能很强,拍照效果很好……
- 资料2:苹果手机价格较高,但保值率不错……

这样用户就知道答案是从哪儿来的,可信度更高。


🎯 整个流程的核心逻辑,用三句话总结

入库时:把文档切成小段 → 同时做三件事(①切词做关键词地图,②存原文,③拍照做语义照片)→ 分别放进三个仓库。

查询时:用户问题 → 同时走两条路(①关键词地图找,②语义照片比对)→ 两路结果融合 → 选出最佳候选。

出答案时:按编号取出原文 → 把原文和问题一起给大模型 → 大模型给出答案 → 答案+来源一起返回。


💡 几个容易混淆的地方,我再说清楚

一问:向量数据库里存的是原文还是分词?
答:存的是原文。分词的词元只用来做”关键词地图”(倒排索引)。向量化是对整段原文做的,不是对词元做的。就像你给一个人拍照,拍的是整个人,不是把他的名字拍进去。

二问:Jieba到底在哪儿用?
答:用两次。第一次在入库时,用来做”关键词地图”(倒排索引)。第二次在查询时,用来处理用户问题里的关键词。它的作用就是”切词”,把句子切成有意义的词。

三问:为什么不能只用一种搜索方式?
答:关键词搜索像”老实人”,你说”苹果”它就找”苹果”,但你说”iPhone”它就傻了。语义搜索像”聪明人”,你说”iPhone”它能找到”苹果手机”,但可能漏掉一些包含精确型号的文档。两个都用,互相补短板。

四问:最终给大模型的是向量还是原文?
答:给的是原文。向量只是用来”找位置”的,找到位置后你要把那里的”实物”(原文)拿出来。就像导航找到了一个地址,你得开车到那个地方,而不是只看地图上的点。