你上传了一份 200 页的 PDF,问一个只有里面写过的问题,它三秒钟回你两行字。你大概想象不出中间发生了什么:它是把整本书读完了吗?读了一遍还是三遍?它怎么知道答案在第 137 页?
答案跟直觉正好相反:它一页都没读完。它只是从整本书里挑出一小把段落,塞到你问题旁边。
这不是偷懒,而是一整套独立的技术。名字有两层:外面那层叫 RAG(检索增强生成,Retrieval-Augmented Generation),里面真正干活的那个零件叫向量检索。这篇只靠两个类比就能把它们讲完:
- 给每段话发一张体检报告——解释什么叫向量、远近是怎么比出来的;
- 把闭卷考试改成开卷——解释 AI 为什么需要检索,以及检索到的东西到底给了谁。
看完你会拿到三道具体的判断题,可以当场去验你现在正在用的那个知识库是不是真的在检索。很多人花几百块建的知识库,其实从来没翻开过你的文件。
先把整件事压缩成三步
一套检索系统干活的顺序是固定的三段:
- 存的时候:把文档切成一小段一小段,每一段算出一串数字,把“原文+这串数字”一起存起来。这一步只做一次,行话叫索引(indexing)。
- 问的时候:把你的问题也算成一串同规格的数字,去那堆数字里找最接近的若干条。这一步叫检索(retrieval)。
- 答的时候:把问题、和找回来的这几段原文一起交给模型,让它照着材料回答。这一步叫生成(generation)。
关键认知:模型从头到尾没读过你的文件。它读到的只是第 2 步挑出来的那一小把。 挑得好,它答得准;挑错了,它就只能凭印象编。这也是绝大部分“知识库答错”的真正原因,而不是模型太笨。
那这三步里“算出一串数字”“找最接近”到底是什么意思?下面一格一格拆开。
第一个零件:给每段话发一张体检报告
先解释最核心的词。嵌入(embedding,动词是 embed)就是用一段文字,换一串固定长度的小数。这串数字叫向量(vector),你只要理解成“一串有顺序的数字”,比如长度是 5 的话可能长这样:
[0.12, -0.88, 0.03, 0.51, -1.07]
真实系统里这串数字的长度叫维度,常见是 1024、1536 或者 3072。为什么要这么多项?因为每一个位置大致对应一个说不清名字的“特征”。你可以把它当成一张体检报告:身高、血压、血脂……一项一项打分,一个 40 岁的男人和另一个 41 岁的男人,报告上大部分项目都接近。文字也一样:说的事越接近,这 1024 项得分的整体形状就越接近。
这里要提醒两件容易想错的事。
第一,这不是分类,不是打标签。 标签是“这属于财务类”,只有或者没有;向量是一个连续的位置。两张报告可以“像到 87%”,也可以完全不相干,中间是渐变的。所以它能回答“有多像”,而不只是“像不像”。这就是为什么它能排序:50 段材料可以按像的程度排出先后。
第二,这 1024 项没有人手写规则,是模型从海量文本里学出来的。 你不需要知道第 7 项到底在测什么(没人知道),只需要知道“经过训练之后,意思接近的文字会拿到接近的报告”。
各家的规格都是公开的,而且价格比多数人想象的低得多:
| 嵌入模型 | 向量维度 | 单段输入上限 | 价格 |
|---|---|---|---|
| 阿里云百炼 text-embedding-v4 | 默认 1024,可改成 2048/1536/512/64 等 | 每段最长 8192 tokens | 0.0005 元/千 tokens,约 0.5 元/百万 |
| OpenAI text-embedding-3-small | 1536 | 8192 tokens(微软那份文档一处写 8191) | 0.02 美元/百万 tokens |
| OpenAI text-embedding-3-large | 3072 | 8192 tokens | 0.13 美元/百万 tokens |
| 智谱 embedding-2 | 1024 | 8K tokens | 0.5 元/百万 tokens |
| BGE-M3(智源,开源) | 1024 | 8192 tokens | 自己跑,只花机器钱 |
token 是大模型计量文字的单元,各家切法不同,粗略地说一个汉字算 1 个上下。它跟钱到底怎么换算,看每百万 tokens 到底是多少字:三步算清一次 AI 调用要花多少钱。
这张表对普通人的实际意义是一句话:建知识库的钱,几乎全在“回答”那一步,不在“存”这一步。 把一整本书算成向量,用的是上面这个便宜价;而你每问一次、模型每答一次,走的是对话模型的价格,那是另一个量级。所以“我文档很大,会不会很贵”这个担心,多半放错了地方。
表里“自己跑”那一行也值得说一句:BGE-M3 是 MIT 协议开源的(可以免费商用),维度 1024,官方模型卡写着支持超过 100 种工作语言。这意味着“算坐标”这一步完全可以不出你的电脑。私密性要求高的场景里,这是最容易本地化的一环。
远近怎么算:比的是方向,不是长短
有了两串数字,“像不像”就变成一道数学题。最常用的算法叫余弦相似度(cosine similarity):把两串数字想象成两个方向,算它们夹角有多大,结果落在 -1 到 1 之间,越接近 1 越像。
这里有一个反直觉但很关键的性质:它比的是方向,不是长度。 同一个意思,你用 20 个字说,也可以用 200 个字说,两段话算出来的向量方向差不多——啰嗦不会让它觉得你不像。 这在搜索场景里太重要了:文档里的句子往往又长又书面,你的提问往往又短又口语,长度差十倍,方向却可以一致。
微软官方文档给的标准例子是:“dog”和“canine”(犬科)概念上很接近,但字面上完全不同(原文是 conceptually similar but linguistically distinct)。同一页还列了跨语言(英文 dog 对德文 hund)和跨形态(一段文字对一张狗的图片)。这三种在关键词匹配里都是零分,在向量空间里都是有分的。
再说“找最近的多少条”。这个参数就叫 k(或者 top-k),意思是“取回最像的前 k 段”。微软搜索服务的文档里,不指定时默认返回 50 条;而当你要在向量结果上再做一层语义重排时,官方的写法是把 k 设成 50。翻译成大白话:先把 50 段候选捞上来摊在桌上,再从里面挑真正相关的几条交给模型。 一次检索从来不是只找一条答案,而是找一把相关材料。
顺带说一个几乎没人讲的事实:文档有上百万段的时候,跟你的问题逐一比对 1024 项,慢到不可用。所以工程上用的是近似算法。最流行的一族叫 HNSW(分层可导航小世界图),出自 2016 年 3 月 30 日的一篇论文,摘要里对它的定义是“approximate K-nearest neighbor search”(近似 K 最近邻搜索),并提到分层之后能带来“对数级的复杂度增长”。思路很像你在一个陌生城市找人:不挨家挨户敲门,先看城市地图圈一个区,再看街道图圈一条街,最后进巷子里一家家看。
“近似”这两个字请记住。 它意味着检索天生就不保证一定能找回全局最像的那一段。所以“文档里明明有,它却说没有”是这类系统的固有失败模式,不一定是谁配置错了。这个区别,后面判断题那节会给你一条可以用的分界线。
第二个零件:先把书撕成卡片
向量算得再好,也得先决定“给哪一段算”。整本算一个向量是不行的——那等于把一整本书押在一个位置上,里面讲了八件事,结果哪件都不像。微软那份切块文档里就有这句话:如果内容用单个向量表示得很差,切块同样有益,并且专门举了“一个 wiki 页面讲了许多彼此无关的子话题”当例子,建议切得更细。
所以第一步永远是切段,行话叫切块(chunking),切出来的一小段叫一个 chunk(块/卡片)。
这一步是全流程里最不性感、却最影响成败的。好消息是:它有非常具体的官方参考值,而且微软用一本书做过真实对照实验。
参考值出自同一个页面,有三组:起点建议是每块 512 tokens(约 2000 个字符),块间重叠 25%,也就是重叠 128 tokens;它自带的文本切分技能默认参数是每块 2000 字符、重叠 500;同一篇里另一段 LangChain 的例子用的是 1000/200。三个数不一样,不是文档打架,而是这类参数没有标准答案,只有起点。
真正让人感受到切块分量的,是那张实验表。同一本 NASA 的电子书《地球夜晚》(Earth at Night),一共 200 页,用不同参数切,得到的块数是这样的:
| 每块长度(字符) | 重叠长度(字符) | 切出多少块 |
|---|---|---|
| 1000 | 0 | 172 |
| 1000 | 200 | 216 |
| 2000 | 0 | 85 |
| 2000 | 500 | 113 |
| 5000 | 0 | 34 |
| 5000 | 500 | 38 |
| 按句子切 | 不适用 | 13361 |
同一本书,最少 34 块,最多 13361 块,差了近 393 倍。 这就是为什么两个用同一个模型的知识库,效果能差到天上去:模型那一环完全一样,卡片箱却根本不是一个东西。
用类比把这张表读成人话:
- 块切太大(5000 字符,全书只剩 34 张卡)=一张卡片抄了四页纸,里面什么都有。你问“极光是怎么形成的”,这张卡里确实有答案,但同时混着火山、城市灯光和叶绿浮游生物。它的体检报告被这些无关内容拉了平均,位置变得谁都不太像。大而杂的一段,坐标是模糊的。
- 块切太小(按句子切,13361 张卡)=一句话一张卡。上下文丢了。“它指的是上个月那次调整”——这句单独看没有任何意义,“它”指什么在上一张卡里。切得太碎,等于把句子之间的手指剪断了。
- 重叠(那个 500/200/128)是缝合线:每张卡尾部重复一点下一张的开头,让被切开的那句话在两张卡里都出现,怎么切都不至于丢。
再补两个反直觉的细节。
一个是:加上重叠之后块数会变多(2000 字符那组,85 块变成 113 块),因为它在重复存内容。很多人以为重叠是浪费,其实它是用存储换连续性——而“存”这一环恰好便宜到可以忽略(前面那张价格表就是依据)。这是一笔明确划算的买卖。
另一个是微软文档里明写的一个坑:重叠值设得太大,最后可能出现完全不重叠的情况(原文:setting an overlap value that's too large can result in no overlap appearing at all)。参数不是设了就生效,是设得合理才生效。
关键词搜索为什么会漏:这是一个有名字的老问题
到这里你可能想问:我不搞这些花活,老老实实用关键词搜自己写的笔记,为什么会找不到?
因为这件事在信息检索领域里一直有个正式的名字:vocabulary mismatch(词汇失配,字面意思就是“你用的词和文档里的词对不上”)。近年的论文里还会直接写 “the vocabulary mismatch problem”,并把它当作需要额外补救的已知难题。
它有多老?到今天仍然在当默认打分算法的 BM25,是 Robertson 等人在 1994 年 TREC 会议上提出的(Apache Lucene 的官方注释里就是这么标注的),三十多年过去,Elasticsearch 的官方文档仍然写着它是“Elasticsearch 和 Lucene 中默认使用的算法”。换句话说,你现在用的绝大多数搜索框,本质上跑的是一套 1994 年的打分逻辑:你的词和文档的词重合多少、重合的那几个词多重要,就排多前。
这套逻辑有三个结构性缺口:
- 同义不同词:文档写“发票抬头”,你搜“报销单上的名字”。零重合,零分。
- 口语对书面:文档写“该参数仅在启用二级缓存时生效”,你问“这个开关为啥没用”。
- 一词多义:你搜“部署”,文档里有 40 处,其中 38 处说的是另一件事。
向量检索天生处理这三个,因为它比的是“体检报告的整体形状”,不是“这个字出现过没有”。
但向量不是万能的。 它有自己的死角:那些必须精确命中的东西。一个错误码 ERR-2041、一个函数名 getUserProfileById、一份合同编号——这些在向量空间里几乎没有“意义”可言,字面匹配反而一击必中。所以正经系统两条都做,叫混合检索(hybrid search)。微软的定义写得很干脆:“在同一次请求里同时执行向量搜索和关键词搜索”,并且明确说两条一起跑再合并结果“通常比只做向量或只做关键词提供更好的结果”。
两份榜单怎么合成一份,有个名字叫 RRF(倒数排名融合)。算法简单到能口算:一份名单里第 1 名得 1/(1+k) 分,第 2 名得 1/(2+k) 分,越靠后加分越小,两份名单的分数相加再排一次。微软文档里这个 k 的建议值就是 60,原话是“实验显示把 k 设成一个小值、比如 60 的时候效果最好”。
站内有一篇把这个思路做到代码库场景的架构长文。要给几万行文件建索引的话,看混合搜索与 AST 代码索引架构:打造万级文件代码库的高精度定位引擎,本文不重复它的工程部分。
RAG:把闭卷考试改成开卷
零件讲完,现在把它们拼成那件事:检索增强生成(RAG)。
最准确的类比是这个:模型自己背下来的东西是闭卷,RAG 是把相关材料印在草稿纸上带进考场。
模型在训练时读过的海量公开文本,就是它“背下来的那本书”。你的公司规章、上个月的会议记录、项目的配置文件——它一个字都没背过。你不递材料,它只有两个选择:说不知道,或者按“这类东西一般长什么样”给你编一个。为什么它常常选后者,见AI 为什么会一本正经地胡说八道:它认得出自己的错,却不会主动说。
“递材料”这个动作的正式出处,是 2020 年 5 月 22 日的一篇论文(arXiv 编号 2005.11401,被 NeurIPS 2020 收录,作者来自 Facebook AI Research、伦敦大学学院和纽约大学,一共 12 人)。它当时那句定义值得原样搬过来:模型“combine pre-trained parametric and non-parametric memory for language generation”(把参数化记忆和非参数化记忆结合起来生成语言)。这句太学术,翻译成人话就是:一半知识长在模型权重里(参数化记忆),一半知识放在外面的一个索引里(非参数记忆),回答的时候两边一起用。
同一篇论文里还有两句更实用的话,那才是它今天被全行业采用的原因:
- 知识“can be directly revised and expanded”(可以被直接修订和扩充),而且论文另外明说“非参数记忆可以被替换掉,从而更新模型的知识”。因为那半记忆是外面的一个索引,改文档就行,不用重训模型。
- 取用过的知识“can be inspected and interpreted”(可以被检查和解读)。因为它能告诉你这句话是从哪一段取的。
这两句决定了你今天习不习惯的两个体验:知识库能跟着文件更新,以及回答能带出处。一个只会给答案、永远说不出来源的“知识库”,多半连第一步都没做对。
论文当年的组合是一个检索器(DPR,稠密段落检索)配一个生成模型(BART):检索器负责找材料,生成器负责照着材料写。今天所有产品里的“文档问答”都是这个骨架,只是换成了更大的模型和更讲究的检索层。
后来一篇 2023 年 12 月的综述(arXiv:2312.10997,十位作者)把这条路线分成三代,措辞非常好懂:Naive RAG(朴素版)就是“索引 → 检索 → 生成”三步直线;Advanced RAG 是为补朴素版的短板,在检索前后加处理,比如把你的问题改写几遍再分别去搜、或者把找回来的 50 段重排一遍;Modular RAG 则把每一步拆成可替换的模块。你听到的“我们做了 rerank”“我们做了查询改写”,都落在第二、第三代里。
那不如整本塞进去?上下文不是越来越大吗
这是最多人问的:现在动辄百万 token 的上下文窗口(上下文窗口到底限制了什么,看AI 为什么聊着聊着就忘了你说的话:它没有“记住”这一步,只有“这次递进去多少”),我把整本书直接塞给它不是更省事?
诚实的回答是:塞得下,读不好,而且贵。 三条都有出处。
读不好。 Chroma 在 2025 年 7 月发布的一份测试(《Context Rot》,注意这是技术报告、不是同行评审论文,测了 18 个模型)里的结论是,模型对自己上下文的使用并不均匀;其中有一条特别关键:输入越长、性能下滑越快的,正是“问题和材料本身相似度低”的那一组。也就是说,真正需要模型费劲做关联的时候,长输入最先顶不住——而这恰好是知识库场景的常态。同一份报告还给了一个反常识的结果:“结构连贯性一贯地损害模型表现”(structural coherence consistently hurts model performance),即把材料按原文顺序、结构完整地递进去,反而比打乱更差。
贵。 微软那份切块文档里给了一个尺度参照:text-embedding-3-small 的 8191 tokens 上限,大约相当于 6000 个英文单词的正文。你的 200 页 PDF 换成 token 是几十万的量级,而且每次提问都要重新付一次这笔输入费;检索路线每次只递几千 token。差价从哪来、怎么算,站内长上下文经济学:Prompt Caching 如何改变大模型商业变现与应用形态 讲得更细。
而这两条的取舍,有论文直接对比过。 谷歌研究院 2024 年 7 月的一篇(arXiv:2407.16833)专门比较长上下文(LC)和 RAG,摘要原话是:“when resourced sufficiently, LC consistently outperforms RAG in terms of average performance. However, RAG's significantly lower cost remains a distinct advantage.”(资源给足时,长上下文在平均表现上稳定强于 RAG;但 RAG 显著更低的成本仍然是它的一项明显优势。)
这句话要读仔细:它没有说检索更好。 它说的是长上下文在钱给够的时候更强,检索在便宜这条轴上无解。所以正确的结论不是“要不要检索”,而是这两件事是分工:装得下、而且需要全局理解的(比如让模型总结整本书),直接给全文;装不下、或者你只关心其中三段的,检索。
顺手把两个常被混为一谈的概念分清楚。
Prompt Caching(提示词缓存)不是检索。 它是“我这次塞进去的那一大坨前缀,下次再塞时打个折”,省的是重复输入的钱;检索是“我根本不塞那么多”。两者经常一起用,但机制完全不同,企业侧的降本组合拳在降低企业 LLM 调用成本 70%:Prompt Caching、智能分流与小模型蒸馏策略 里有实操版本。
微调(fine-tuning,再训练模型让它“学会”你的东西)也不是检索。 一句话分别:检索是每次给它材料,微调是把它教会。 前者改文件立刻生效,后者要重训、改一次训一次,而且学进去的东西拿不出来给你看出处。这一层的技术权衡站内有专文,见大模型微调 vs 提示词上下文工具感知:工具调用的工程架构权衡。
你的知识库为什么答错:三道当场能做的判断题
前面全是解释,这一节给你能立刻做的事。判断一个“知识库/文档问答”是不是真在检索,不需要任何代码,三个问题就够。
判断题 1:文档里根本没有的东西,它会不会老实说没有? 挑一个你的文件里确实没有、但看起来很会有的问题。比如给员工手册问“加班可以调休几天”,而手册里真没写这条。
- 回答“材料里没有相关条款”=检索在起作用,而且模型被约束在给定材料内。
- 回答得斩钉截铁、条目清晰=两种可能:要么根本没检索(它在背网上的公版知识),要么检索回来的是不相干段落还硬写。这是坏知识库最常见的样子。
判断题 2:同一个问题,换个说法还找得到吗? 先用文档里的原话问一次(“发票抬头”),再用你的口语说法问一次(“报销单上的名字写错了怎么办”)。
- 两次都对=有语义检索这一层。
- 第一次对、第二次说没有=基本可以判定它只做关键词匹配。这就是上面那三个结构性缺口的现场版。
判断题 3:需要跨两段拼的答案,它给得全吗? 挑一个答案天然分在两处的问题,比如“这个功能谁负责、什么时候上线”——负责人写在会议纪要里,时间写在计划表里。
- 只答出一半=切块把上下文切断了,或者一次取回的块数太少。
- 完整答出=它取回了多块并且做了合并。
这三道题的套路,和怎么读一份大模型发布稿:六个数分三组看,三个地方最容易讲错 是同一个方法:先定下“什么算数”的口径,再去找证据,只是对象从发布会变成了你手上正在用的那个产品。
三道题之外,还有两个动作值得马上做。
别把长表格、长截图当“文档”直接扔进去。 表格被切块之后,列名和数值会被分进不同的块里——“3 月”那一行配上“总计”那一列,坐标完全错乱。扫描件和图片同理:多数知识库的默认链路根本不读图(这是产品链路的现实,不是模型不行)。有表格就转成文字版,或者单独给它一整块。
自己建的时候,先别急着接模型。 只做一件事:索引建完,问一句“这份文档的标题是什么”这种答案就在第一块里的问题。这一步能确认“文件真的被读进索引”这一环通了。很多人第一次搭知识库卡住,卡在的不是模型答得差,是文件压根没进去。
现在能做的三件事
一、给你手上正在用的那个知识库做一次判断题。 上面三道,五分钟。如果发现它只会关键词匹配,你为它花的钱有一半是白花。
二、把“怎么写笔记”往“好检索”的方向调一点。 这是普通人唯一能直接影响检索质量的地方,三条就够:
- 一段只说一件事。 前面那张表已经说明,大而杂的一段,坐标是模糊的。你的笔记一屏塞四个话题,就是在给自己制造“全书 34 块”那种情况。
- 给每段一个自包含的开头。 写“关于年假:入职满一年后 5 天……”,而不是“补充一下:满一年后 5 天”。指代不清是切块的头号副作用。
- 少用图片存信息。 图上写的字,检索层看不见。
三、真想动手,站内有现成的链路。 从零建一个能用的私有知识库,看基于 Qdrant 向量数据库构建私有知识库 RAG MCP Server;想先搞懂“AI 怎么把外部东西接到你的编辑器里”这个前置概念,看MCP 到底是什么?从 AI 工具调用到 Agent 工作流,一文看懂 MCP。站内也有可以直接接的现成组件,比如Qdrant 向量库只读 MCP 和RAG 知识库 MCP,详情页里有可以直接复制的配置命令。想接到自己的笔记上,看使用 Notion 与 Obsidian MCP 打造 AI 驱动的个人第二大脑知识管理;要给代码库做,看借助 Meilisearch MCP 打造毫秒级代码库全文本与语义搜索工具;想更进一步搞清“AI 的记忆分几层”,看智能体记忆体系架构:工作记忆、短期会话缓冲与长期知识图谱的融合。
一句话版本
AI 翻到你那一页,靠的不是读完,而是先把每段话换成一张“体检报告”,再把你的问题也换成同规格的一张,然后按形状像不像取回最近的一小把,最后才把这一小把和你的问题一起交给模型。 所以它答得准不准,一半取决于模型,另一半取决于你的文档有没有被切成合适大小的块——后一半,是你能改的。