语义搜索的底层原理
为什么需要 Embedding
传统搜索是关键词匹配:你搜"苹果"只能找到包含"苹果"两个字的文档。但语义上相近的"iPhone""果公司""Apple Inc."都搜不到。
Embedding 的目标:让计算机理解"相似的意思",不只是"相同的字"。
核心概念:向量就是一个数组
// 一个 Embedding 向量,长度通常是 512~3072
const vector: number[] = [0.123, -0.456, 0.789, ...]
每个词/句子都被映射成一个这样的高维数组。神奇的地方是:
embed("狗") ≈ [0.1, 0.8, 0.3, ...]
embed("犬") ≈ [0.11, 0.79, 0.31, ...] // 很接近
embed("汽车") ≈ [-0.5, 0.2, -0.9, ...] // 差很远
语义相近的文本,向量距离也近。这就是 Embedding 的全部魔法。
调用 Embedding API
import OpenAI from 'openai'
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
})
const res = await client.embeddings.create({
model: 'text-embedding-3-small', // 1536 维,便宜
input: '前端开发者学习 AI',
})
console.log(res.data[0].embedding)
// [0.0123, -0.0456, 0.0789, ..., 总共 1536 个数]
开源替代:BGE(北智源,中文效果好)、m3e。可以本地部署,完全免费。
计算相似度:余弦相似度
两个向量的相似度,最常用的算法是余弦相似度(Cosine Similarity):
function cosineSim(a: number[], b: number[]): number {
let dot = 0, na = 0, nb = 0
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i]
na += a[i] * a[i]
nb += b[i] * b[i]
}
return dot / (Math.sqrt(na) * Math.sqrt(nb))
}
结果范围 [-1, 1]:
1:完全相同方向(几乎同义)0:无关-1:完全相反(实际很少见)
实践中,> 0.7 通常算强相关,具体阈值要根据你的数据校准。
一个完整的小例子
import OpenAI from 'openai'
const client = new OpenAI()
async function embed(text: string) {
const res = await client.embeddings.create({
model: 'text-embedding-3-small',
input: text,
})
return res.data[0].embedding
}
const documents = [
'如何使用 React Hooks',
'Vue 3 Composition API 详解',
'烤蛋糕的家常做法',
'TypeScript 泛型深入',
'和女朋友去哪里度假好',
]
// 预计算所有文档的向量
const docVecs = await Promise.all(documents.map(embed))
// 用户提问
const query = 'React useEffect 怎么用'
const queryVec = await embed(query)
// 排序
const ranked = documents
.map((doc, i) => ({ doc, score: cosineSim(queryVec, docVecs[i]) }))
.sort((a, b) => b.score - a.score)
console.log(ranked)
// 1. React Hooks 0.84
// 2. TypeScript 0.61
// 3. Vue 3 0.58
// ...
看,就算文档里没有 "useEffect" 这几个字,也能找到最相关的那条。
向量数据库:Embedding 的家
文档少的时候数组里一把梭就够了。几万条以上,你需要向量数据库:
| 数据库 | 特点 |
|---|---|
| pgvector | PostgreSQL 扩展,既有 SQL 又有向量 |
| Pinecone | 托管服务,免运维 |
| Chroma | 轻量本地库,适合原型 |
| Qdrant | Rust 写的,高性能 |
| Milvus | 分布式,大规模生产用 |
| Weaviate | 带混合搜索 |
对前端/全栈开发者的推荐路线:pgvector(你已有 Postgres 就零成本)或Chroma(零配置本地跑)。
-- pgvector 示例
CREATE EXTENSION vector;
CREATE TABLE docs (
id serial PRIMARY KEY,
content text,
embedding vector(1536)
);
-- 查找最相似的 5 条
SELECT content
FROM docs
ORDER BY embedding <=> $1::vector -- <=> 是余弦距离操作符
LIMIT 5;向量检索的底层:ANN
当数据量到百万级,逐个算余弦距离就慢了。向量数据库内部用**近似最近邻(ANN)**算法:
-HNSW(图结构):最流行,精度速度兼顾 -IVF(倒排索引) -LSH(局部敏感哈希)
作为前端开发者,知道有这回事即可,向量库会替你搞定。
Embedding 的实际应用场景
不只是 RAG,Embedding 能做的事很多:
1.语义搜索:站内搜索、文档搜索 2.推荐系统:相似商品/文章推荐 3.去重:发现重复/相似的内容 4.分类:把文本映射到预定义标签(零样本分类) 5.聚类:自动发现内容主题 6.异常检测:找和整体风格不一样的文本
成本参考
text-embedding-3-small 每百万 Token $0.02(2026 年价格)。
把整个项目代码(几十万 Token)全 embed 一遍不到 1 毛钱。
动手作业
给你自己的博客/笔记做一个语义搜索:
- 读取所有 markdown 文件
- 按标题+正文 embed 每篇文章
- 写一个命令行工具:输入查询关键字,返回最相关的 5 篇
- 对比关键词搜索(
grep)和语义搜索的差异
参考资料
- OpenAI Embeddings 文档
- pgvector GitHub — 官方仓库,文档齐全
- MTEB 排行榜 — 中/英文 Embedding 模型榜单
- Chroma 官网 — 最简单的本地向量库
- HNSW 算法动画演示 — 看 ANN 怎么工作
版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。
(采用 CC BY-NC-SA 4.0 许可协议进行授权)
本文标题:Embedding 与向量:把文字变成数字
本文链接:https://www.sshipanoo.com/blog/ai/ai-for-frontend/04-Embedding与向量/
本文最后一次更新为 天前,文章中的某些内容可能已过时!