Embedding 与向量检索:语义搜索的原理与动手实现
Words: 1161Read Time: 3 minLast edited: 2026-8-4
关键词搜索的短板
博客里攒了几十篇笔记后,搜索变得越来越难用。比如我记得写过一篇"给笔记本加内存"的文章,搜"硬件升级"——搜不到,因为全文没有这四个字。关键词匹配的死板就在于此:它只认字面,不认意思。
前阵子我系统学了下 embedding(嵌入),动手把笔记搜索改造成了语义搜索。这篇记录原理和实现,核心代码不到 40 行。
Embedding:把文字变成一串数字
Embedding 的原理一句话说清:模型把任意文本映射成一个高维向量(一串浮点数),并且保证意思相近的文本,向量在空间里的距离也近。
"给笔记本加内存条"和"电脑硬件升级",字面没有一个词重合,但向量会靠得很近;而"SQL Server 分页"和它们离得很远。语义搜索的全部魔法就建立在这个性质上。
OpenAI 的 embedding API 用起来很简单,text-embedding-3-small 模型默认返回 1536 维的向量:
价格几乎可以忽略:一百万 token 才 0.02 美元,我全部笔记跑一遍连一分钱都花不到。
余弦相似度:给"像不像"打个分
有了向量,怎么衡量两段文本像不像?常用余弦相似度:两个向量夹角的余弦值。方向越一致,值越接近 1,语义越接近;垂直是 0,相反是 -1。公式就是点积除以两个模长的乘积,numpy 一行搞定:
动手:几十条笔记的语义搜索
完整 demo:把所有笔记标题向量化(只需跑一次),查询时把搜索词也向量化,算它和每条笔记的余弦相似度,取分数最高的前几条:
实际效果对比很直观:
- 搜"硬件升级":关键词搜索 0 结果;语义搜索返回"怎么给笔记本加内存条"(0.62)和"给笔记本电脑清灰换硅脂"(0.51)。
- 搜"数据库性能":语义搜索命中"SQL Server 分页查询的三种写法",虽然标题里根本没有"性能"二字。
- 搜"内存":两种搜索都能找到。字面重合的场景,关键词搜索并不差。
所以结论是:语义搜索不是替代关键词搜索,而是互补。精确匹配(错误码、函数名)用关键词;模糊描述需求("电脑变卡怎么办")用语义。效果最好的是两者结合,各取所长。
注意点
踩过的坑和提醒:
- 换模型要重算所有向量。不同模型、甚至同模型的不同版本,向量空间都不一样,混着算相似度就失真了。存向量时一定标注用的是哪个模型。
- 文档向量算一次就缓存下来,查询时只需算查询词的向量,一次 API 调用。
- 几十条数据用 numpy 暴力遍历完全够(毫秒级);上到几万条后全量算相似度就慢了,得用专门的向量索引,那是另一个话题。
- 查询和文档必须用同一个 embedding 模型,别文档用 3-small、查询用 ada-002,算出来的分数没有意义。
Loading...