LLMNotes

第 09 章:Embedding

zjc 于 2026-01-09 发布

这是《LLM 应用开发 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 Embedding 模型把文本映射为向量,让语义相近的内容在向量空间中接近。它是向量检索的核心,但不是 RAG 的全部。

9.1 基本概念

"如何申请退款" -> [0.12, -0.34, ..., 0.08]
"退货流程是什么" -> [0.10, -0.31, ..., 0.06]
"今天天气很好" -> [0.75, 0.22, ..., -0.11]

常用相似度:

方法 说明
cosine 比较方向,常用于文本
dot product 向量未归一化时受长度影响
euclidean 距离越小越相似

多数文本检索会归一化向量,此时点积与 cosine 排序等价。

9.2 输入设计

不要只向量化正文:

标题路径:员工手册 / 考勤 / 远程办公
正文:远程办公需要提前一天审批...
关键问答:如何申请远程办公?

可检索文本示例:

def build_embedding_text(chunk):
    title = " / ".join(chunk.get("title_path", []))
    return f"{title}\n{chunk['content']}" if title else chunk["content"]

注意:

  1. 不要把权限、内部状态等不适合参与语义的内容拼入正文;
  2. 元数据应放在过滤字段;
  3. 不同语言选择匹配的模型;
  4. 任务前缀要遵循模型文档;
  5. 查询和文档是否需要不同前缀,以官方说明为准。

9.3 调用示例

import os
from openai import OpenAI

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

def embed(texts: list[str]) -> list[list[float]]:
    response = client.embeddings.create(
        model="text-embedding-3-small",
        input=texts,
    )
    return [item.embedding for item in response.data]

批处理建议:

  1. 控制单批输入条数和 token;
  2. 处理限流和重试;
  3. 保存模型名和维度;
  4. 批量任务支持断点续跑;
  5. 记录失败文本;
  6. 输出向量做归一化前先确认模型输出约定。

9.4 维度与存储

向量数量 = chunk 数量
存储量 ~= 向量数量 * 维度 * 4 bytes  # float32

示例:

100 万条 * 1536 维 * 4 bytes ~= 6 GB

常见优化:

  1. 只向量化有价值的文档;
  2. 去重;
  3. 降维;
  4. 量化;
  5. 冷热分层;
  6. 按租户或业务分索引;
  7. 结合关键词索引减少候选集。

9.5 模型切换

向量不可跨模型混用。

embedding-model v1
  -> index-v1

embedding-model v2
  -> index-v2

切换流程:

  1. 建立评测集;
  2. 双索引构建;
  3. 比较 Recall@K;
  4. 小流量切换;
  5. 观察回答质量;
  6. 保留旧索引一段时间;
  7. 全量切换;
  8. 归档旧向量。

9.6 查询改写

用户查询往往短且带上下文依赖。

用户:那这个要多久?
历史:我在问退款。

改写:退款审核需要多久?

常见方法:

方法 场景
指代补全 多轮对话
同义改写 口语化提问
拆分子查询 复合问题
HyDE 生成假设答案再检索
关键词抽取 编号、型号、错误码

改写要保留原文,避免把用户没说的条件补进去。

9.7 多语言

挑战:

  1. 中英混合;
  2. 专业术语翻译不一致;
  3. 中文分词不等于语义切分;
  4. 小语种召回差异;
  5. 文档语言与查询语言不同。

策略:

  1. 优先选择多语言模型;
  2. 建立术语表;
  3. 保留原文关键词;
  4. 混合检索编号和错误码;
  5. 按语言评测而非只看总体指标;
  6. 输出语言与检索语言解耦。

9.8 评估 Embedding

构造标注对:

query positive negative
如何申请退款 退款流程文档 优惠政策
账号锁定 登录失败处理 数据库锁定

指标:

指标 说明
Recall@K 相关文档召回率
MRR 首个相关的排名倒数
NDCG 排序质量
Mean Cosine Gap 正负例间隔
Latency 向量化延迟
Cost token 成本

9.9 常见问题

现象 原因 处理
编号查不到 向量对精确词弱 混合检索
长文档召回差 语义稀释 改切块
多主题 chunk 不准 块太杂 拆块
换模型后效果骤降 新旧向量混用 重建索引
相似度分数无法比较 模型或空间不同 只在同空间比较
多轮查询指代错 未改写 查询补全

本章小结

Embedding 负责语义召回,效果依赖输入构造、切块质量、模型选择和索引方式。向量空间与模型绑定,切换模型必须重建索引并做对比评测。对编号、术语和精确条件,应结合关键词或数据库过滤。

思考题

  1. 为什么不同模型的向量不能直接比较?
  2. 标题路径加入 embedding 文本有什么作用?
  3. 查询改写如何服务多轮对话?
  4. 如何评估 Embedding 模型替换收益?
  5. 什么场景必须使用混合检索?