← 返回目录
ap4.3实操⏱ 约 11 分钟

嵌入与检索:相似度就是一行数学

手写一遍 20 行的检索引擎,再决定要不要上向量数据库

🔎 最后验证 2026-08📚 来源:本节手写检索管线为 ECS 实测(2026-08,纯标准库实现,脚本与原始输出见本节代码)🧰 Python、DeepSeek API
为什么学这个

"嵌入模型""向量数据库""余弦相似度"——这几个词吓退了很多人,以为要先学一学期线性代数。

这一节我们手写一遍:把文本变成向量、算相似度、排序取前三。全程不装任何库,核心代码不到 20 行。写完你会发现:检索的原理简单到令人失望——真正难的是后面的工程取舍。

💡 打个比方

把每段文字变成一串数字(向量),就像给每个人量三围。"找相似的文本" = "找三围最接近的人"——用的就是初中学过的距离公式。

嵌入模型只是一台更高级的量尺(量的是"语义"而不是"字面"),但比对方式完全一样。

三步,手写一个检索引擎

第 1 步:分词(把文本拆成"特征")

def tokenize(s):
    s = s.lower()
    toks = re.findall(r'[a-z]+|\d+\.?\d*', s)        # 英文和数字按词
    zh = re.sub(r'[^一-鿿]', '', s)
    toks += [zh[i:i+2] for i in range(len(zh)-1)]     # 中文按相邻两字
    return toks

第 2 步:向量化(TF-IDF:一个词在本块里越常见、在全库里越罕见,权重越高)

idf = {t: math.log((N+1)/(df[t]+1)) + 1 for t in df}      # 罕见词权重高
v = {t: (1+math.log(freq)) * idf[t] for t, freq in counts.items()}
norm = math.sqrt(sum(x*x for x in v.values()))
v = {t: x/norm for t, x in v.items()}                     # 归一化

第 3 步:算相似度(归一化之后,余弦相似度就是点积)

def cosine(a, b):
    return sum(x * b.get(t, 0.0) for t, x in a.items())    # 就这一行

检索 = 把问题也变成向量 → 和每个块算一次 cosine → 排序取前 k。完了。

手写版的能力边界(重要)

本节的 TF-IDF 版在实测里表现不错(按结构切时 10/10),但它有个根本局限:只能匹配字面,不懂意思

问题文档里的写法TF-IDF嵌入模型
"退货要几天""退换货时限 7 个自然日"⚠️ 靠"退"字勉强命中✅ 理解同义
"运费怎么算""配送费收取标准"❌ 字面无重合✅ 理解同义
"会员划算吗""年费 199 元享 95 折"❌ 完全不匹配✅ 理解意图

所以生产环境用嵌入模型:它把文本映射到"语义空间",意思相近的向量就相近——比对方式和你手写的完全一样(还是余弦),区别只在于向量是怎么来的

那要不要上向量数据库

你的规模建议
几百块以内内存里算就行(本节代码的做法),一次遍历几毫秒
几千到几万块内存 + 简单索引仍可行;或用轻量向量库
十万块以上 / 需要过滤+并发上专业向量数据库

别一上来就装向量数据库——很多真实知识库(公司制度、产品文档、FAQ)总共就几百到几千块,内存里暴力算完全够用,还省掉一整套运维。先跑通,再优化

选嵌入模型的三个考量

  1. 中文能力:优先选中文或多语言训练充分的(纯英文模型处理中文会明显掉分);
  2. 向量维度与成本:维度越高一般越准但存储和计算更贵;嵌入调用也要计费(通常远低于生成);
  3. 能否本地跑:敏感数据不能出内网时,选可本地部署的开源嵌入模型。

⚠️ 具体选哪个模型,以你实测为准——用 4.4 的检索评测跑一遍你自己的数据,比看任何榜单都靠谱。

🔧 动手做:手写一遍,再想升级(15 分钟)

  1. 跑本节代码 rag_pipeline.py,重点读 build_indexcosine 那 20 行——确认你能看懂每一步。
  2. 做个"字面 vs 语义"的对比实验:给你的评测集加 3 个"问题用词和文档完全不同"的问题(比如文档写"配送费",你问"运费"),看手写版能不能命中。
  3. 如果掉分了——恭喜,你亲手证明了为什么需要嵌入模型
  4. 可选升级:接一个嵌入 API(把 build_index 换成调嵌入模型、cosine 保持不变),重跑评测,看提升多少。
  5. 记下你的决策:我的场景用字面检索够吗?还是必须上嵌入?——依据是那 3 个同义问题的命中情况。

做到这里你应该有:对检索原理的"祛魅",以及一个用数据支撑的"要不要上嵌入模型"的判断。

为什么:很多人在 RAG 上花了大钱(向量数据库、昂贵嵌入模型),却从没验证过"我的场景真的需要吗"。手写一遍让你有能力判断:哪些是必需的,哪些是被卖给你的。

❓ 测验
手写的 TF-IDF 检索,在什么情况下会明显不如嵌入模型?
⚠️ 避坑嵌入模型换了,索引必须全部重建

一个容易踩的坑:你用模型 A 建好了 10 万块的索引,后来换成模型 B(或 A 的新版本)——旧向量和新查询向量不在同一个空间,比对结果是垃圾

规矩:① 索引里存好"用哪个模型、哪个版本建的";② 换模型 = 全量重建 + 重跑评测(别假设新模型一定更好);③ 重建期间的双写/灰度方案要提前想(4.7 的知识更新会讲)。

🤖 让 AI 帮你选检索方案
我的知识库:【文档类型和总量】,用户问法特点:【是否用词统一/口语化】,数据敏感度:【能否出内网】。请帮我判断:1) 字面检索(BM25/TF-IDF)是否够用,还是必须上嵌入模型;2) 如果上嵌入,选云端 API 还是本地部署,推荐哪类模型;3) 我这个规模要不要向量数据库;4) 怎么用评测集验证这个选择。
✅ 小结

检索祛魅三句话:原理就是"文本变向量 + 比余弦"(20 行手写)、TF-IDF 只懂字面、生产用嵌入模型但比对方式一样;几百块的知识库内存里算就够,别急着上向量数据库。

下一节回答 4.2 留下的问题:回答准确率会掩盖检索问题——所以必须把检索单独拎出来测。

下一节 → 检索质量评测:分开测检索和回答
🔎 来源与核验· 2 条,点开核对
本节每个关键论断都对应一个可追溯的来源 —— 这是本课程"靠谱、不过时"的底线。
「本节手写 TF-IDF 检索管线(分词/向量化/余弦)在实测知识库上,配合按结构切分达到检索命中 10/10、回答准确 10/10」
📚 ECS 实测 rag_pipeline.py(2026-08,纯标准库实现,top-3)✓ 已核验 2026-08
「TF-IDF 仅能匹配字面重合,嵌入模型可处理同义表述;两者比对方式相同(余弦相似度),区别在向量生成方式」
📚 本节实现与实测观察✓ 已核验 2026-08
智图软件的赞赏码
都看到这了,打个赏呗!
接下来 · ap4.4
检索质量评测:回答对了,不代表检索对了
继续读下一节 →