Embeddings

私有文档问答要先把文本变成向量,再进向量库做相似度检索。各云厂商 Embedding API 的请求格式、维度、批大小限制不同。Embeddings 抽象把「一段或多段文本 → list[float] 向量」统一成两个入口:embed_query(单条检索)与 embed_documents(批量建库)。

段末注释Embeddings = 文本嵌入(text embedding)模型的 LangChain 封装,输出固定维度的浮点向量。


1. 一句话定位

维度 内容
角色 能力层向量化:为 RAG 索引与 query 编码
输入 → 输出 strlist[str]list[float]list[list[float]]
典型调用入口 embeddings.embed_query(...)embeddings.embed_documents(...)
与 LangGraph 通常作为索引离线步骤或 RAG 节点内一步;图编排见 LangGraph 目录

2. 实现逻辑

建库 + 检索的典型流程:

1
2
3
4
5
1. 文档切分 → list[str] chunks
2. embed_documents(chunks) → list[list[float]],维度 = d
3. 落盘 {model, docs, vectors}(JSON / npy)或交给 VectorStore
4. 启动加载向量;用户问题 q → embed_query(q) → 向量 v_q(长度 d)
5. 与落盘向量算相似度 → Top-K 原文(不再对已入库文档跑 embed_documents)

字段级变形

1
2
"LangChain 是什么?"  → embed_query  → [0.12, -0.03, ..., 0.08]  # len=1536 等
["chunk1", "chunk2"] → embed_documents → [[...], [...]]

3. 原理说明

3.1 Embeddings 基类

langchain_core.embeddings.Embeddings 定义 embed_documentsembed_query。检索时 query 与 document 应使用同一模型、同一维度,否则相似度无意义。

Embeddings(抽象类)
功能:str / list[str] → 定长浮点向量。子类如 HuggingFaceEmbeddingsOpenAIEmbeddings
默认值:model / model_name 视集成(HF 类默认常为 sentence-transformers/all-mpnet-base-v2)。
最小维度:文本至少 1 段非空 str;输出向量 dim 由模型固定(本系列示例多语言 MiniLM 为 384)。

embed_query(text: str)(方法)
功能:编码单条检索问句。无额外默认参数。
最小维度:text 长度 ≥1 字符;返回 list[float]len == d

1
v = embeddings.embed_query("什么是 RAG?")  # len(v) == 384

embed_documents(texts: list[str])(方法)
功能:批量编码入库文本,内部按 batch 切分。
最小维度:texts len≥1(空列表返回 []);每条建议非空;返回 list[list[float]],形状 (n, d)

1
vecs = embeddings.embed_documents(["chunk A", "chunk B"])  # n=2, d=模型维

3.2 query 与 document 是否区分

部分模型(如 BGE)对 query/document 用不同前缀;OpenAI text-embedding-3-* 通常同一接口。

HuggingFaceEmbeddings(数据类 / 实现)
功能:本地 Sentence Transformers 推理,无需 API Key。

字段 类型 默认值 最小维度
model_name str all-mpnet-base-v2 非空模型 ID
model_kwargs dict {} 可空;device 常用 "cpu"
encode_kwargs dict {} 可空;检索建议 normalize_embeddings=True
cache_folder str / None None 走 HF 默认缓存
1
2
3
4
HuggingFaceEmbeddings(
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
encode_kwargs={"normalize_embeddings": True},
)

3.3 批处理与 rate limit

embed_documents 内部常按 batch 切分;云 API 大批量应控并发,避免 429。维度写入 VectorStore 前须与 collection schema 一致。

OpenAIEmbeddings(实现类)
功能:调用云 Embedding API。默认 model="text-embedding-3-small"(dim 1536,可 dimensions 截断)。
最小维度:同基类;api_key 从环境变量读取,构造器可省略。

3.4 与 VectorStore 的关系

多数 VectorStore 构造时传入 embedding=embeddingsadd_documents 时自动调 embed_documents;也可手动算向量再 add_embeddings

add_embeddings(VectorStore 方法,视实现)
功能:已有向量直接入库,跳过再编码。
最小维度:texts / embeddings 等长,len≥1;每条向量 len == d

3.5 向量落盘

embed_documents 只返回内存 list[list[float]]。小库写 JSON {model, docs, vectors};规模上来用 FAISS save_local 或 Chroma persist_directory。加载后只对用户问题调 embed_query

落盘 JSON 最小结构(数据约定,非官方类)

字段 类型 默认值 最小维度
model str 必填 非空,加载时须与当前模型一致
dim int 必填 ≥1,且等于 len(vectors[0])
docs list[str] 必填 len≥1
vectors list[list[float]] 必填 形状 (len(docs), dim)
1
2
payload = {"model": MODEL, "dim": len(vectors[0]), "docs": docs, "vectors": vectors}
Path("kb.json").write_text(json.dumps(payload, ensure_ascii=False), encoding="utf-8")

4. 最小可运行示例

社区方案:langchain-huggingface + Sentence Transformers 本地推理(官方集成,无需 API Key)。

  • 场景:离线建库、内网/隐私文本、无云额度原型。
  • 做法embed_documents 批量编码 → JSON 落盘(原文 + 向量 + 模型名)→ 下次启动只 embed_query 检索。
  • 风险:首次下载权重(本例约 120MB);换模型必须重建文件;JSON 只适合小库;normalize_embeddings 必须与检索度量一致(归一化后点积 = 余弦相似度)。

段末注释L2 归一化 = 把向量长度缩到 1;开启后点积与余弦相似度数值相同。

1
pip install -U langchain-huggingface sentence-transformers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import json
from pathlib import Path

import numpy as np
from langchain_huggingface import HuggingFaceEmbeddings

MODEL = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
KB_PATH = Path("./data/kb_embeddings.json")

# 中文检索也可换 BAAI/bge-small-zh-v1.5(query 建议加官方指令前缀)
embeddings = HuggingFaceEmbeddings(
model_name=MODEL,
model_kwargs={"device": "cpu"},
encode_kwargs={"normalize_embeddings": True},
)

docs = [
"LangChain 把各厂商 LLM API 收成统一的 ChatModel 与 LCEL 管道。",
"RAG 先检索相关文档,再把片段交给模型生成答案。",
"Embeddings 把文本映射成固定维度向量,供相似度检索使用。",
"LangGraph 负责带环、检查点与人工审批的图编排。",
]

# 1) 建库:embed_documents → 本地 JSON(已有文件则跳过,避免重复编码)
if not KB_PATH.exists():
KB_PATH.parent.mkdir(parents=True, exist_ok=True)
vectors = embeddings.embed_documents(docs)
KB_PATH.write_text(
json.dumps(
{"model": MODEL, "dim": len(vectors[0]), "docs": docs, "vectors": vectors},
ensure_ascii=False,
),
encoding="utf-8",
)
print(f"已写入 {KB_PATH}{len(vectors)} 条 × {len(vectors[0])} 维")

# 2) 加载:读回向量,不再对文档调 embed_documents
kb = json.loads(KB_PATH.read_text(encoding="utf-8"))
assert kb["model"] == MODEL, "换模型必须重建索引"
mat = np.array(kb["vectors"], dtype=np.float32) # shape = (n, d)

# 3) 检索:只对 query 调 embed_query;已归一化,点积即余弦
query = "私有文档问答为什么要先检索再生成?"
q = np.array(embeddings.embed_query(query), dtype=np.float32)
scores = mat @ q
idx = int(scores.argmax())
print(kb["docs"][idx], round(float(scores[idx]), 3))
# 预期命中 RAG 那条(真实语义,不是随机向量)

接 OpenAI(需 OPENAI_API_KEY)时只换构造器,落盘与检索逻辑不变:

1
2
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")

重要配置参数

参数(API 名) 类型 / 默认值 功能说明 作用与影响 参考起点 配置指导
model / model_name str,构造器 选定嵌入模型,决定语义空间与输出维 d 换模型必须重建索引,否则召回崩溃 多语言 MiniLM / text-embedding-3-small 建库与查询必须同一模型
encode_kwargs.normalize_embeddings bool,默认 False 编码后是否 L2 归一化(点积=余弦) True 才能用点积检索;与落盘向量必须一致 True(点积检索) 中途改此值须重算全部向量
model_kwargs.device str 指定本地推理设备 cuda 加速、cpu 更稳 cpu 无 GPU 勿填 cuda
cache_folder str,可选 本地权重缓存目录 不设则走 HF 默认缓存 Hugging Face 默认 内网预先下载到此目录
dimensions int,部分云模型可选 截断输出向量维数 越小越省存储、召回可能变差 1536 / 256 必须与已落盘 dim 一致
chunk_size int,云集成常见 一次 API 最多送多少条文本 过大易 413/429;过小吞吐低 100~1000 批量建库按厂商限额拧
max_retries int 云 API 失败自动重试次数 提高建库成功率、拉长尾延迟 2~6 批量索引建议保留
api_key str 云 Embedding 鉴权 本地 HF 不需要 环境变量 勿进仓库

5. 易踩坑

  1. 索引与查询用了不同 Embeddings 模型:召回率骤降,且不易从日志直接看出;落盘文件须写入并校验 model
  2. 把 embed_documents 结果当 embed_query 混用维度:自定义 pipeline 时须校验 len(v) 与落盘 dim 一致。
  3. 每次启动都对全量文档再跑 embed_documents:应加载已落盘向量,只对 query 编码。
  4. 未归一化却用点积当余弦normalize_embeddings 与检索公式必须同一套。

小结

  • Embeddings 提供 embed_query / embed_documents 双入口,是 RAG 向量化的标准接口。
  • 建库与检索须 同一模型、同一维度
  • embed_documents 结果须自行落盘(或交给 VectorStore);查询阶段只 embed_query
  • 本地真实语义用 HuggingFaceEmbeddings + Sentence Transformers,无需 API Key。

参考链接

-------------本文结束感谢您的阅读-------------