跳到主要内容

向量数据库与 RAG — 按「意思的距离」查

这一章讲三件事: 「按意思搜索」到底是怎么实现的——每段文本变成一串数,查询变成找最近的邻居; 嵌入从哪来、嵌多大块、存在哪(本地 FAISS 还是托管 Pinecone); 以及这套检索怎么接回提示,变成防幻觉的 RAG 管线。 对应原书第 5 章全章。

1. 这一章讲什么

第 05 章留下了一个问题:窗口是预算,资料塞不下全部,得有个办法按相关性挑着塞。传统数据库帮不上:按字面子串查,mouse 只能命中写着 mouse 的记录,意思相近但没写这个词的一律漏掉1

主走查:一个员工手册问答系统。 公司为手册建了一个「独角兽企业」人设——手册里写着员工福利包括「无限量独角兽骑行」。用户问:「do we get free unicorn rides?」(我们有免费独角兽骑吗?)我们跟着这个问题走全程:手册切块、转成数串、存进 FAISS、查询命中、塞进提示、模型照着手册回答。

2. 顶层全景:RAG 四步

建库时(离线,一次): 查询时(在线,每次):
┌─────────────┐ 用户问题
│ 手册/文档 │ │
│ ↓ 切块 │ ↓ 转成数串(同一个嵌入模型)
│ 776 个文档块 │ 在库里找最近的 k 块
│ ↓ 嵌入模型 │ │
│ 每块一串数 │ ↓
│ ↓ 入库 │ 塞进提示当上下文
│ 向量数据库 │ ↓
└─────────────┘ 模型照着上下文回答,不知道就说不知道

图说:RAG(检索增强生成)的全部结构:先按意思查出相关资料,再让模型照资料回答。
检索挡在前面,幻觉的概率就降下来——这是第 06 章「只许用给定文本」战术的工程化。

这套做法的正式名字叫 RAG(Retrieval-Augmented Generation,检索增强生成:检索来资料、增强提示、再生成回答)2。书里说透了两端:小规模(资料装得进窗口)用不着它;大规模时,它比「把整个语料(全部文本材料)塞进提示」省钱得多——128,000 标记的 gpt-4 窗口够大,但当时每标记比 gpt-3.5-turbo 贵 10 倍,塞得多就是烧得多3

3. 核心原理

3.1 向量:把意思变成地图上的坐标

第 02 章讲过嵌入:词变成一串数,意思相近的词数串也相近——「意思」在这行有个学名:语义(semantic,一段文字在讲什么这件事)。这一章把这串数用到底:一串数就是一个坐标,所有文本一起构成一张地图。书里给了一个只有两维的玩具模型来建立直觉——假设全世界只能用「卡程度」和「卫生程度」两个坐标描述:从 mouse(老鼠)出发,拉高卡通度会走向 mickey mouse(米老鼠),拉低卫生度会走向 rat(人人喊打的那种耗子)4

查询动作因此有了几何形态:k 近邻(k-nearest neighbors:找到离查询坐标最近的 k 个点)。书里的例子:k=3 时,mouse 的邻居是 mickey mouse、cheese(奶酪)、trap(捕鼠夹);rat 排第四,要 k=4 才轮到它。对照组(用来对比的另一组)是关系型数据库:用「文本包含 mouse」去查,只能命中 mickey mouse 一条,cheese 和 trap 字面上没有 mouse,永远查不到——尽管意思上它们紧挨着5

真实的嵌入不是两维:OpenAI 的 text-embedding-ada-002 给每段文本编 1,536 个数。维度(这串数的长度)多是能力:两维的地图只够把猫和狗分开,300 维就能分出品种、体型、毛色的差别6

3.2 嵌入从哪来:模型决定一切

嵌入不是随便生成的,是嵌入模型(专门把文本转成数串的模型,只产数串不写文章)算出来的。这条引出一串工程事实:

  • 同一段文本、同一个模型,永远得到同一串数——所以嵌入可以算一次、存起来、反复复用,不用每次重算7;
  • 换个模型,地图整张换掉——两个模型的数串之间没有任何可比性,混用等于拿两张投影不同的地图对坐标8;
  • 要花钱,但便宜:ada-002 当时每千标记 $0.0004,把钦定版圣经(约 80 万词、400 万标记)整部嵌入一遍,大约 $1.609;
  • 模型有知识截止(ada-002 的训练数据到 2020 年 8 月),也有偏见;领域里的小众黑话它可能根本没见过,那时才需要自训嵌入10

还有一个分代差异值得记:老一代的词向量(如 word2vec)是静态的——bank 只有一个坐标。

现代的 Transformer 模型给的是上下文嵌入——bank 在 riverbank(河岸)和 financial bank(银行)里坐标不同8

不想调 API 也有开源选项:Hugging Face 的 Sentence Transformers 库,常用的 all-MiniLM-L6-v2 给 384 维向量——它是 BERT(第 02 章讲过的编码器类模型:负责「读」而不是「写」的那一族)的一个小号后代,为句子级任务优化11

3.3 两种数串:小语料上老办法更稳

嵌入模型给的数串,几乎每个位置都非零、每一位都承载着学来的语义。这种数串叫稠密向量(dense vector)。

还有另一类叫稀疏向量(sparse vector:维数动辄十万以上,但绝大多数位置是零——每个维度对应一个具体的词,这个词出现了就记数)。

稀疏向量的代表是关键词搜索(按词面匹配查找)的老办法。

书里点名的代表是 TF-IDF(词频-逆文档频率:一个词在本文里出现越多越重要,但在整个语料里太常见就要打折——「的」人人用,不值钱)12

为什么要提老办法?书里的理由很实际:语料小的时候,神经嵌入学不动,TF-IDF 反而稳。 书里用一个玩具语料演示:几句关于 cake 的句子里,用 TF-IDF 加余弦(三角形里邻边比斜边的那个比值)相似度——量两串数方向有多一致,接近 1 为像,第 07 章讲过——算出来,cake 和 lie 的相似度是 0.89,cake 和 sing 只有 0.01——和人的直觉一致;而同一个玩具语料自训的 word2vec 给出的相近度只有 0.234,还是反复换随机种子挑出来的结果13。今天的检索系统越来越多把两者混着用(语义 + 关键词,书里叫混合搜索)8

3.4 嵌什么:块大小的权衡

嵌入的输入单位是第 05 章切好的块,块大小直接决定检索质量。书里把两端的失败都讲了14:

  • 块太大(极端情况:整本书嵌成一串数):向量是书里所有词的坐标的平均——回归均值,越平均越不含任何具体的语义,搜索结果变成「什么都沾点边」;
  • 块太小:断句断义,单个碎片撑不起一个意思。

所以「嵌什么」和「怎么切」是同一个决策的两面,书里给的预算例子接着第 05 章:8,192 标记的窗口,留约 3,000 给提示和回答,剩下放 5 块 × 1,000 标记的最相关块15。检索到的块相不相关,重度依赖分块策略——太碎没有答案,太臃塞会稀释匹配还多花标记16

3.5 主走查:FAISS 与独角兽问题

零件齐了,走全程。书里的演示用 FAISS(Facebook AI 开源的相似度检索库,本地跑,不需要服务)17:

第 1 步|建库:员工手册切成块,每块嵌入成 1,536 维向量,
存进 faiss.IndexFlatL2 索引。
——IndexFlatL2 是「暴力比对」:查询来了,它把库里的向量
逐条算 L2 距离(两坐标间的直线距离),一个不漏[^17]。
第 2 步|查询:"do we get free unicorn rides?"
→ 嵌入成向量 → 暴力比对 → 命中最近的块:
"You'll enjoy a treasure chest of perks, including
unlimited unicorn…"(你会享受一宝箱福利,包括无限量独角兽…)[^18]
第 3 步|拼装:命中的块填进提示模板当 Context,配上系统消息:
「只用给你的上下文回答;不知道就说 I don't know」[^19]
第 4 步|生成:gpt-3.5-turbo 照着手册原文回答。

第 3 步那条系统消息就是第 06 章的「引用文本防幻觉」战术——书里用它收尾同一章,不是巧合:检索负责把「给定的文本」选对,战术负责把模型拴在文本上。 书里的对照实验:问手册里没有的内容(「美国总统是谁」),模型照纪律回答「I don't know」18

两个工程收尾:索引(存起来供快速查找的数据结构)可以 faiss.write_index 存盘、下次 read_index 直接加载,不用每次重嵌一遍19;两个索引可以合并,但原来的 ID 不会跟着搬,合并后是新 ID20

3.6 Pinecone:托管换省心,也换来三本账

FAISS 是库,自己跑。托管服务(Pinecone、Chroma、Weaviate 等;书里选 Pinecone,当时的市场老大)把「维护、扩容、可靠、性能、支持、安全合规」打包卖给你21。书里把代价也列得明白,三本账22:

内容
成本托管费之外还有「配错一次烧掉几千刀」的超支事故,云服务的经典风险
锁定各家功能相似但不对齐(接口不一一对应),迁移并不顺(vendor lock-in)
隐私数据交给第三方,有安全与法律含义

托管版还有一个 FAISS 没有的能力:元数据(数据附带的属性字段,如分组编号、页码)过滤——入库时每块除了向量,还能带一组字段(字符串、数、布尔、字符串列表),查询时先按字段过滤再按相似度排:filter={"batch": {"$eq": 1}} 只在第 1 组里找23。书里的判词:元数据策略和分块策略同等重要——比如把所有租户的对话存进同一个库,靠元数据只查当前租户那部分24

3.7 自查询:让 LLM 自己写过滤器

元数据过滤还有一个自动化版本:自查询(self-querying)。用户说「找 2023 年以后的科幻书」,LLM 读这句话,自己拆成两半——语义部分(「科幻书」走向量检索:按意思的坐标找最近的几块,§3.5 主走查的那套)和过滤部分(「2023 年以后」变成元数据过滤条件)。字段的可选范围用 AttributeInfo(给每个元数据字段登记名字、描述、类型的声明)提前告诉模型25。为了稳定,这一步把温度拧到 0(温度在第 01 章讲过:0 意味着永远挑可能性最高的输出)26

书里还点了一排更花哨的取回器,各一行27:MultiQuery(把一个问题改写成多个视角分别查)、Contextual Compression(长文档先压缩掉不相关部分)、Ensemble(多个取回器混合出击)、ParentDocument(小块匹配、返回所属的大块)、TimeWeighted(兼顾相关性新鲜度)。它们的共同母题:距离检索不够用的地方,用「多查几次」「先压缩」「混合算法」去补。

4. 作者的判断与证据

  • mouse 的三个邻居、cake-lie 0.89、独角兽命中,全是书里跑出来的真实输出;
  • 「嵌入模型决定搜索质量」「元数据策略与分块策略同级」是作者的工程判词,没有实验对照,但和全章的演示自洽;
  • word2vec 玩具例的 0.234 书里自己承认是「换随机种子挑出来的」——作者的诚实,照录13;
  • 选 Pinecone 是因为「写作时的市场老大」,书里明说概念可迁移到其他家21

判断(我们的,不是书里的): 这一章和姊妹书《Prompt Engineering for LLMs》的第 07 章讲的是同一件事的两个面:那本从「文档怎么变检索料」讲,这本从「坐标怎么比远近」讲。本书独有的贡献在把「块大小—嵌入模型—元数据」说成了同一个设计决策:三者都在决定「一个查询会落在哪里」。只调其中一个,通常救不回检索质量。 如果错,会错在: 如果任务的关键词信号极强(错误码、零件编号、专有名词),纯关键词或混合检索可能压过一切语义侧调优——书里混合搜索「正在兴起」那句8正是这个方向的证据。

5. 边界与局限

  • IndexFlatL2 是暴力比对:库里每条都算一遍距离,演示够用,百万级向量要换近似索引(FAISS 有别的索引类型,书里没展开);
  • 书里所有价格与模型名是 2024 年快照:ada-002、$0.0004/千标记、128k 窗口贵 10 倍——今天都变了,机制不变;
  • 自查询依赖 LLM 正确拆出过滤条件,拆错就查空;温度拧 0 只是降抖,不是保证;
  • 「不知道就说不知道」拴得住回答,拴不住检索:检索本身选错块,模型只会照着错块答——垃圾进,垃圾出;
  • 微调与 RAG 的取舍书里给了一句:微调是一次性大成本,RAG 是每次调用的持续成本28

6. 可带走的

  1. 字面子串查不到「意思相近」——按意思查,就要把文本变成坐标、按距离找邻居;
  2. k 是开关:k=3 拿不到排第四的 rat,检索调参先调 k;
  3. 嵌入可复用:同一模型同一文本同一向量,算一次存起来;
  4. 嵌入模型就是地图本身——换模型等于换地图,全库重嵌;
  5. 语料小,先用 TF-IDF 这类老办法,别急着上神经嵌入;
  6. 块大小是检索质量的阀门:大了回归均值,小了断义;
  7. 本地用 FAISS,索引存盘复用;托管换省心,但把成本、锁定、隐私三本账先算清;
  8. 元数据过滤和分块策略同等重要——先想好「以后要按什么字段筛」再入库;
  9. 检索 +「不知道就说不知道」的系统消息,是防幻觉的工程闭环;
  10. 距离检索不够用:多视角改写、先压缩、混合检索,总有一款补得上。

7. 原文地图

主题原书章原文位置
关系型数据库查不到 cheese/trapCh.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:26(搜「relational database」)
两维玩具模型:Cartoon/HygieneCh.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:16(搜「mickey mouse」)
k 近邻与 mouse 的邻居Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:22(搜「k closest records」)
1536 维Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:9(搜「1,536 numbers」) · text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:85(搜「1,536 dimensions」)
同文同向量、稠密稀疏Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:201(搜「contextual rather than static」)
$1.60 嵌入整部圣经Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:129(搜「King James」)
TF-IDF 与 cake-lie 0.89Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:298(搜「TF-IDF」) · text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:358(搜「0.8926」)
回归均值Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:381(搜「regression to the mean」)
8192 预算分配Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:389(搜「8,192 token limit」)
FAISS 暴力比对Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:482(搜「IndexFlatL2」) · text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:516(搜「brute-force」)
独角兽查询命中Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:494(搜「free unicorn rides」) · text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:501(搜「treasure chest of perks」)
「不知道就说不知道」Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:548(搜「I don't know」) · text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:688(搜「president of the US」)
索引存盘与合并Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:598(搜「write_index」) · text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:619(搜「will not move any IDs」)
托管三本账Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:725(搜「vendor lock-in」)
元数据过滤Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:958(搜「metadata strategy」) · text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:961(搜「$eq」)
自查询Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:970(搜「Self-Querying」) · text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:1120(搜「temperature=0」)
五种替代取回器Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:1168(搜「MultiQueryRetriever」)
128k 窗口贵 10 倍Ch.5 向量数据库text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:42(搜「10 times more」)

Footnotes

  1. 出处:「Ch.5 向量数据库」第 26 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:26,搜「relational database」)。

  2. 出处:「Ch.5 向量数据库」第 44 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:44,搜「Retrieval Augmented Generation」)与第 46 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:46,搜「inserting them into the prompt」)。

  3. 出处:「Ch.5 向量数据库」第 42 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:42,搜「10 times more」)。

  4. 出处:「Ch.5 向量数据库」第 16 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:16,搜「Cartoon」)。

  5. 出处:「Ch.5 向量数据库」第 22 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:22,搜「k closest records」)与第 26 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:26,搜「relational database」)。

  6. 出处:「Ch.5 向量数据库」第 9 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:9,搜「1,536 numbers」)与第 85 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:85,搜「1,536 dimensions」)。

  7. 出处:「Ch.5 向量数据库」第 470 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:470,搜「the vectors won't change」)。

  8. 出处:「Ch.5 向量数据库」第 201 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:201,搜「contextual rather than static」)。同段讲稠密/稀疏与混合搜索的兴起。 2 3 4

  9. 出处:「Ch.5 向量数据库」第 129 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:129,搜「King James」)。

  10. 出处:「Ch.5 向量数据库」第 203 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:203,搜「cutoff date」)与第 207 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:207,搜「word2vec」)。

  11. 出处:「Ch.5 向量数据库」第 131 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:131,搜「Sentence Transformers」)与第 177 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:177,搜「all-MiniLM-L6-v2」)。原文:「a smaller version of BERT」。

  12. 出处:「Ch.5 向量数据库」第 298 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:298,搜「TF-IDF」)。

  13. 出处:「Ch.5 向量数据库」第 358 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:358,搜「0.8926」)与第 296 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:296,搜「heavily repetitive」)。word2vec 玩具例的局限(语料太小、要换种子)在相邻段落,书里明说通常需要大得多、更多样的语料。 2

  14. 出处:「Ch.5 向量数据库」第 381 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:381,搜「regression to the mean」)。

  15. 出处:「Ch.5 向量数据库」第 389 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:389,搜「8,192 token limit」)。

  16. 出处:「Ch.5 向量数据库」第 466 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:466,搜「chunking strategy」)。

  17. 出处:「Ch.5 向量数据库」第 470 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:470,搜「FAISS」)。

  18. 出处:「Ch.5 向量数据库」第 688 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:688,搜「president of the US」)。

  19. 出处:「Ch.5 向量数据库」第 598 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:598,搜「write_index」)。

  20. 出处:「Ch.5 向量数据库」第 619 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:619,搜「will not move any IDs」)。

  21. 出处:「Ch.5 向量数据库」第 697 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:697,搜「current leader」)。 2

  22. 出处:「Ch.5 向量数据库」第 725 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:725,搜「vendor lock-in」)。

  23. 出处:「Ch.5 向量数据库」第 940 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:940,搜「filter」)与第 961 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:961,搜「$eq」)。

  24. 出处:「Ch.5 向量数据库」第 958 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:958,搜「metadata strategy」)与第 964 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:964,搜「chatbot ID」)。

  25. 出处:「Ch.5 向量数据库」第 970 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:970,搜「Self-Querying」)与第 1033 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:1033,搜「AttributeInfo」)。

  26. 出处:「Ch.5 向量数据库」第 1120 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:1120,搜「temperature=0」)。

  27. 出处:「Ch.5 向量数据库」第 1168-1188 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:1168,搜「MultiQueryRetriever」)。

  28. 出处:「Ch.5 向量数据库」第 1188 段(text/37-ch05-chapter-5-vector-databases-with-faiss-and-pineco.txt:1188,搜「up-front cost of fine-tuning」)。原文:重负载下,微调的一次性前期成本可能胜过「提示+嵌入+向量存储」的持续成本;但按相似度动态拉上下文,RAG 没有替代品。