从面试中学习:什么是向量检索?

背景

最近面试了一位候选人,聊到了向量检索在组件库文档搜索中的实践。听起来很高级,但本质上是个很实用的技术。这篇文章用最通俗的话解释一下。

先说结论

向量检索:把文字转换成”数字”,然后在这个数字空间里找”意思相近”的内容。

简单说:让机器理解你的意图,而不是死板地匹配文字


什么是向量检索?

一个生活化的比喻

想象你在图书馆找书。

传统搜索

店员问:”你要什么书?”
你说:”《挪威的森林》。”
店员精确找到这本书。

向量检索

店员问:”你想看什么类型的书?”
你说:”我想看关于一个人经历了很多困难,最后成长起来的故事。”
店员不仅找到了《挪威的森林》,还推荐了《少年维特的烦恼》《平凡的世界》… 因为它们”讲的是类似的事情”。


为什么需要它?

你有没有遇到过这种情况:

场景搜索结果
搜”手机”只找到含”手机”两个字的内容
搜”苹果”不知道你要水果还是公司
搜”怎么把手机变成热点”搜不到”如何开启手机热点”
打错字什么都搜不到

传统搜索就是”字面对字面”,你说什么我就找什么,一字不差。

向量检索能解决什么?

传统搜索向量检索
搜”快乐”找不到”开心”语义相近都能找到
搜”苹果”可能混淆理解上下文(水果or公司)
搜法不同就搜不到同一意思不同说法都能搜到

它是怎么工作的?

整个过程可以拆成三步:

第一步:转成数字(Embedding)

把一段文字变成一串数字,这串数字就是”向量”。

1
2
"如何实现按钮点击" → [0.12, -0.34, 0.56, 0.89, ...] (1536个数字)
"按钮的点击事件怎么做" → [0.11, -0.32, 0.58, 0.88, ...] (1536个数字)

关键是:**意思相近的文字,生成的数字也会”长得像”**。

第二步:找相似的

在所有已转换的文字中,找到数字”距离近”的。

1
2
3
"如何实现按钮点击"  → [0.12, -0.34, 0.56, ...]
"按钮的点击事件怎么做" → [0.11, -0.32, 0.58, ...]
↓ 距离很近(相似度 95%)

什么是”距离近”?

想象在一个巨大的空间里,每个向量都是一个点:

1
2
3
4
5
6
7
8
          开心

/
/
快乐 ---★--- 悲伤
/ \
/ ★
高兴 难过

相近的词在这个空间中的位置也近。计算”距离”有几种方法:

方法适用场景了解更多
余弦相似度语义搜索(方向相近)余弦相似度 - 维基百科
欧氏距离绝对距离敏感欧几里得距离
点积计算效率优先点积 - Khan Academy

第三步:返回结果

把最相似的几个结果返回给你。


底层原理:文字是怎么变成数字的?

1. 最早的做法:独热编码

最早的词向量很简单,但没什么用。

1
2
3
4
假设我们有 10000 个词:

"苹果" → [1, 0, 0, 0, ..., 0] (第1位是1,其他都是0)
"香蕉" → [0, 1, 0, 0, ..., 0] (第2位是1,其他都是0)

问题:每个词都是”孤立的”,苹果和香蕉的距离 = 苹果和手机的距离,完全无法表达语义。

2. 从上下文学习

后来研究发现:一个词的意义,由它的上下文决定。

📚 参考:Word2Vec 论文 - Google (2013)

如果两个词经常出现在相似的上下文里,它们意思就相近。

1
2
3
4
5
6
7
"我吃了一个苹果"    → "苹果"是水果
"我吃了一个香蕉" → "香蕉"是水果
"我买了一部苹果手机" → "苹果"是公司

模型学习后发现:
- "苹果"和"香蕉"经常出现在相似的上下文 → 位置相近
- "苹果"和"手机"有时也在一起 → 有一定关系

3. 现代做法:Transformer

现在的 Embedding 模型用的是 Transformer 架构,更加强大。

📚 参考:Attention Is All You Need - Transformer 原始论文

📖 通俗解读:Transformer 模型详解 - Jay Alammar

**核心是”注意力机制”**,让模型理解上下文:

1
2
3
4
5
6
7
8
句子:"苹果的营养价值很高"

传统方法:每个词独立看
- "苹果" → 固定向量

Transformer:结合上下文
- "苹果" 在这句话里 → [0.12, -0.34, ...] (理解为水果)
- "苹果" 在另一句话里 → [0.11, -0.31, ...] (可能理解为公司)

Attention 的比喻

读一句话时,你会”关注”不同的词。

读”苹果手机很好用”:

  • 你关注”手机” → 理解这里”苹果”是公司

读”苹果很甜很好吃”:

  • 你关注”甜” → 理解这里”苹果”是水果

Transformer 就是模拟这个过程。

4. 一句话总结

阶段方法特点
早期独热编码每个词独立,无法表示语义
后来上下文学习语义相近则向量相近
现在Transformer结合上下文,理解深层语义

能做什么?

身边的产品例子

你可能已经用过向量检索了,只是没意识到:

1. Google 搜索

当你搜索”手机死机怎么办”时:

  • 早期 Google:精确匹配”手机死机怎么办”这几个字
  • 现在的 Google:理解你的意图,返回”手机卡顿解决方法””手机开不了机怎么解决”等相关文章

📖 参考:Google AI 搜索技术介绍

Google 从多年前开始大量使用语义搜索技术(BERT、Muennighoff 等)。

2. AI 搜索产品

现在的 AI 搜索(比如 Perplexity、秘塔搜索、知乎直达):

🔗 体验:Perplexity | 秘塔搜索 | 知乎直达

1
2
3
4
5
6
7
8
9
你问:"为什么早起对身体好?"

传统搜索:返回一堆网页链接你自己点开看

AI 搜索:
1. 理解你的问题
2. 向量检索找到相关的健康知识
3. 让 AI 总结成答案直接给你
4. 还会标注信息来源

3. 电商搜索

在淘宝搜”显白的裙子”:

  • 传统搜索:找不到”显白”这个词
  • 向量检索:理解你要”显肤色白”,返回白色、浅色、粉色等裙子

4. 代码搜索

在 GitHub 搜”发送网络请求”:

  • 传统搜索:只找含”发送网络请求”的文件
  • 向量检索:找到 fetch、axios、XMLHttpRequest 相关的代码

🔗 GitHub 已经在使用语义代码搜索,可以试试 GitHub Code Search

实际应用场景

场景用法
智能客服用户问”怎么退货”,找到退货相关的FAQ
文档搜索搜”怎么做表格”,找到Excel教程
代码搜索搜”发送请求”,找到HTTP相关代码
内容推荐给你推荐”你可能感兴趣的文章”

一个具体例子

假设你在做一个组件库文档搜索:

用户搜索:”点击按钮没反应”

传统搜索:只找含”点击按钮没反应”这几个字的内容

向量检索:找到

  • “按钮点击事件无效”
  • “button点击没有响应”
  • “点击button没反应怎么办”

因为它们”说的是同一件事”。


如何搭建一个向量检索系统?

第一步:准备数据

把所有文档拆分成小块。比如一篇长文档,可以按章节、按段落拆分。

📖 参考:LangChain 文本分割器

1
2
3
4
5
6
7
8
9
10
11
原文档
├─ 1. 按钮组件介绍
├─ 2. 按钮的用法
├─ 3. 按钮的事件
└─ 4. 按钮的样式

拆分成:
├─ chunk-1: "按钮组件用于触发操作事件"
├─ chunk-2: "button组件支持onClick事件"
├─ chunk-3: "如何设置按钮的样式"
└─ chunk-4: ...

第二步:调用 Embedding API

把每块内容转换成向量。这步不需要自己写算法,调用现成的服务就行。

1
2
3
4
5
6
7
8
9
10
11
12
13
import OpenAI from "openai"

const client = new OpenAI()

// 把文字转成向量
const response = await client.embeddings.create({
model: "text-embedding-3-small",
input: "按钮组件用于触发操作事件"
})

// 拿到这1536个数字(1536维向量)
const vector = response.data[0].embedding
// [0.12, -0.34, 0.56, 0.89, ...]

1536维是什么意思?

想象一个坐标系,每个向量有1536个坐标。这1536个数字一起定义了它在”语义空间”中的位置。

第三步:存入向量数据库

把每块内容及其对应的向量存到数据库里。

1
2
3
4
5
6
7
8
// 存入向量数据库(以Pinecone为例)
await index.upsert({
vectors: [
{ id: "chunk-1", values: vector1, metadata: { content: "按钮组件用于触发操作事件" } },
{ id: "chunk-2", values: vector2, metadata: { content: "button组件支持onClick事件" } },
// ...更多内容
]
})

第四步:处理用户搜索

当用户搜索时,同样的逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 1. 把用户的搜索词转成向量
const queryVector = await client.embeddings.create({
model: "text-embedding-3-small",
input: "按钮点击怎么做"
})

// 2. 在向量空间里找相似的
const results = await index.query({
vector: queryVector.data[0].embedding,
topK: 5 // 返回最相似的5个结果
})

// 3. 返回结果
console.log(results.matches)
// [
// { id: "chunk-1", score: 0.95, metadata: { content: "按钮组件用于触发操作事件" } },
// { id: "chunk-2", score: 0.89, metadata: { content: "button组件支持onClick事件" } },
// ...
// ]

完整流程图

1
2
3
4
5
6
7
8
9
用户搜索"按钮点击怎么做"

转成向量 [0.15, -0.31, 0.52, ...]

在数据库中找距离近的

返回最相似的5条内容

用户得到答案

常用工具

用途工具参考链接
Embedding 生成OpenAIOpenAI Embeddings 文档
ClaudeAnthropic Embeddings
GoogleGoogle Embeddings API
开源模型Hugging Face Sentence Transformers
向量数据库PineconePinecone 官网
MilvusMilvus 官网
ChromaChroma 官网
QdrantQdrant 官网

术语表

术语解释
向量(Vector)一串数字,代表文字在语义空间中的位置
Embedding把文字转换成向量的过程或模型
向量检索在向量空间中找相似内容的技术
语义搜索理解意图的搜索,而不是关键词匹配
相似度(Similarity)两个向量”距离近”的程度
余弦相似度最常用的相似度计算方法
Transformer现在的Embedding模型用的架构
AttentionTransformer的核心,理解上下文
Chunk把大文档拆成的小块
TopK返回最相似的K个结果
Reranking对检索结果重新排序提升精度

总结

向量检索解决的核心问题是:让机器理解你的意图,而不是死板地匹配文字

它的工作流程:

  1. 转成数字 - 把文字变成向量
  2. 找相似的 - 在数字空间里找”距离近”的
  3. 返回结果 - 把最相关的返回

什么时候用它?当你需要语义搜索而不是关键词搜索的时候。


扩展阅读

想深入了解?这些资源可以帮助你:

入门系列

  • 向量搜索入门 - Pinecone
  • 语义搜索介绍 - Elasticsearch

视频教程

  • 3Blue1Brown - 神经网络系列
  • 李宏毅 - Transformer 课程

实践教程

  • OpenAI Embeddings 教程
  • LangChain 向量存储

论文

  • Word2Vec 原始论文
  • Attention Is All You Need
  • BERT 论文