「从零到 AI 应用工程师」专栏 · 第 11 篇
切片有了,下一步是让计算机「觉得两段话像不像」。
Embedding(嵌入)把文本变成定长浮点向量;向量库负责存和近邻搜索。
一、Embedding 一句话
语义相近的文本,向量空间里距离更近;无关的更远。
例子(设备运维场景):
- 「单体过压告警怎么处理」≈「电芯电压过高排查步骤」→ 应能互相召回
- 「逆变器日常巡检」→ 和上面无关,不该排第一
检索时:问题也做成向量,在库里找距离最近的 TopN 切片。
二、模型从哪来
常见做法:用开源句向量模型(如 sentence-transformers 生态),本地下载后离线推理。
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("BAAI/bge-small-zh-v1.5") # 中文场景常用
# 或轻量英文演示:all-MiniLM-L6-v2
vectors = model.encode(
["切片文本1", "切片文本2"],
normalize_embeddings=True, # 便于用内积近似余弦
)
要点:
- 入库和查询必须同一模型(含同一版本),否则空间不互通;
- 中文工业术语优先中文优化模型;英文 MiniLM 对中文故障词往往偏弱;
- 小模型 CPU 也能跑批量入库;首次下载后缓存本地,生产可断网。
也可用云端 Embedding API:效果/速度往往更好,但按量计费、依赖外网——大批量灌库要想清楚成本。
三、批量与截断(工程必做)
上千切片一次 encode → 容易 OOM / 超时
→ 按 batch(如 16)循环,失败可重试单批
→ 超长文本按字符/token 上限截断,避免模型报错
每条入库记录建议绑定:id(可用 doc_id+文本指纹)+ text + meta + vector。重复导入用 upsert,避免切片数翻倍。
四、向量库:FAISS 与 pgvector
| FAISS | pgvector(PostgreSQL 扩展) | |
|---|---|---|
| 定位 | 专用近似近邻库,本地文件即可 | 向量进数据库,和业务库一体 |
| 适合 | 单机演示、原型快 | 已有 Postgres、要 SQL/备份一体 |
| 注意 | 维数、索引类型要约定好 | vector(N) 维数必须与模型一致 |
相似度常用余弦距离/内积(向量先 L2 归一化后,内积与余弦一致)。约定写进配置:距离越小越相似,还是分数越大越好——前后端别混。
切换模型维度(如 384→512)要重建索引/改表,不是只改个环境变量名。
五、检索接口长什么样
GET /rag/retrieve?query=过压怎么处理&top_n=5
→ 返回若干 { text, meta, cosine_distance }
此接口只检索、不调大模型,适合调试「找没找对」。
完整问答走下一篇的 POST /rag/query。
六、常见坑
- 入库 MiniLM、查询换 bge → 结果乱飞。
EMBEDDING_DIM与表结构不一致 → 写入/检索直接报错。- 只存向量不存原文 → 召回了也无法给模型看。
- Docker 无模型回退到 TF-IDF → 语义弱,别当最终效果验收。
- 阈值过严 → 全拒答;过松 → 噪声进 Prompt。
七、带走这三条
- Embedding 把语义变成可比较的向量;同一模型贯穿入库与查询。
- 批量、截断、meta 绑定是工程标配。
- FAISS 快原型,pgvector 贴业务库;维度变更要重建。
下一篇:把解析、分块、检索、Prompt、大模型串成 POST /rag/query,真正「能答专业问题」。
这是专栏第 11 篇。两到三天一更,全链路见。