Embedding 模型选型与微调 · 运维手册
适用场景:为 RAG 知识库、语义搜索、相似度匹配场景选择合适的 Embedding 模型。
1. Embedding 模型概览
1.1 什么是 Embedding
Embedding 是将文本转化为固定长度的向量(数组),语义相近的文本向量距离也近。
"Kubernetes 部署失败" → [0.12, -0.45, 0.78, ...] # 1024 维
"Docker 容器启动错误" → [0.15, -0.42, 0.75, ...] # 相似度高
1.2 核心指标
| 指标 | 说明 | 典型值 |
|---|---|---|
| 维度 | 向量长度 | 384-1024 |
| 最大 token | 单次输入长度 | 512-8192 |
| MTEB 分数 | 基准测试质量 | 60-85 |
| 推理速度 | 每秒处理 token 数 | 1000-10000 |
| 显存占用 | 模型加载所需显存 | 1-3 GB |
2. 主流模型对比
2.1 国内主流模型
| 模型 | 厂商 | 维度 | 最大 token | 中文支持 | 部署方式 |
|---|---|---|---|---|---|
| bge-m3 | 阿里 | 1024 | 8192 | ⭐⭐⭐ | 本地/API |
| text2vec-large | 上海 AI Lab | 1024 | 512 | ⭐⭐⭐ | 本地 |
| mxbai-embed-large | Mixedbread | 1024 | 512 | ⭐⭐ | 本地 |
| GTE-Qwen2 | 阿里 | 1536 | 8192 | ⭐⭐⭐ | 本地 |
2.2 国际主流模型
| 模型 | 厂商 | 维度 | 最大 token | 中文支持 | 成本 |
|---|---|---|---|---|---|
| text-embedding-3-small | OpenAI | 1536/512/256 | 8191 | ⭐⭐⭐ | 付费 |
| text-embedding-3-large | OpenAI | 3072 | 8191 | ⭐⭐⭐ | 付费 |
| embed-english-v3 | Voyage AI | 1024 | 4000 | ⭐⭐ | 付费 |
| nomic-embed-text | Nomic | 768 | 8192 | ⭐⭐ | 免费 |
2.3 选型决策树
需要私有化部署?
├─ 是 → 用 bge-m3(综合最强)
└─ 否 → 需要高并发?
├─ 是 → text-embedding-3-small(快速便宜)
└─ 否 → 追求精度?
├─ 是 → text-embedding-3-large
└─ 否 → bge-m3(免费且好用)
3. 本地部署
3.1 Ollama 部署 bge-m3
# 拉取模型
ollama pull bge-m3
# 测试生成
curl http://localhost:11434/api/embeddings -d '{
"model": "bge-m3",
"prompt": "Kubernetes Pod 处于 Pending 状态"
}'
3.2 Python 调用
from langchain_community.embeddings import OllamaEmbeddings
embeddings = OllamaEmbeddings(
model="bge-m3",
base_url="http://localhost:11434"
)
# 生成向量
vec = embeddings.embed_query("Nginx 502 错误")
print(f"向量维度: {len(vec)}")
print(f"向量前 5 维: {vec[:5]}")
3.3 批量生成优化
from concurrent.futures import ThreadPoolExecutor
def batch_embed(texts: list[str], batch_size: int = 32) -> list[list[float]]:
"""批量生成 Embedding"""
results = []
for i in range(0, len(texts), batch_size):
batch = texts[i:i+batch_size]
vecs = embeddings.embed_documents(batch)
results.extend(vecs)
return results
4. 检索优化
4.1 向量相似度计算
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
def similarity_score(v1: list[float], v2: list[float]) -> float:
"""余弦相似度"""
a = np.array([v1])
b = np.array([v2])
return cosine_similarity(a, b)[0][0]
# 阈值判断
THRESHOLD = 0.75
if similarity_score(query_vec, doc_vec) > THRESHOLD:
print("语义高度相关")
4.2 混合检索策略
from langchain.retrievers import EnsembleRetriever
from langchain.vectorstores import Chroma
from langchain.retrievers import BM25Retriever
# 向量检索
vector_retriever = Chroma(...).as_retriever()
# 关键词检索
bm25_retriever = BM25Retriever.from_documents(documents)
# 混合检索
ensemble = EnsembleRetriever(
retrievers=[vector_retriever, bm25_retriever],
weights=[0.7, 0.3] # 向量 70% + 关键词 30%
)
5. 模型微调
5.1 何时需要微调
| 场景 | 是否需要微调 | 理由 |
|---|---|---|
| 通用知识库 | ❌ 不需要 | 预训练模型已足够 |
| 垂直领域(医疗/法律) | ✅ 建议微调 | 领域术语和表达特殊 |
| 多语言混合 | ✅ 建议微调 | 提升低资源语言表现 |
| 极高精度要求 | ✅ 需要微调 | 特定场景优化 |
5.2 微调流程
from sentence_transformers import SentenceTransformer, InputExample, losses
from torch.utils.data import DataLoader
# 加载预训练模型
model = SentenceTransformer('BAAI/bge-m3')
# 准备训练数据
train_examples = [
InputExample(texts=["查询文本", "相关文档"]),
InputExample(texts=["查询文本", "不相关文档"]),
]
# 训练
train_dataloader = DataLoader(train_examples, shuffle=True, batch_size=16)
train_loss = losses.CosineSimilarityLoss(model)
model.fit(
train_objectives=[(train_dataloader, train_loss)],
epochs=3,
warmup_steps=100
)
# 保存
model.save("my-embedding-model")
5.3 微调效果评估
# 测试集评估
from sentence_transformers.evaluation import SemanticSearchEvaluator
eval_dataset = [...] # 测试数据
evaluator = SemanticSearchEvaluator(
queries=test_queries,
corpus=test_corpus,
relevant_docs=test_relevant
)
score = evaluator(model)
print(f"MRR: {score['mrr']}") # 平均倒数排名
print(f"HitRate: {score['hit_rate']}") # 命中率
6. 性能调优
6.1 向量库索引优化
# ChromaDB HNSW 索引
collection = client.get_or_create_collection(
name="ops-knowledge",
metadata={
"hnsw:space": "cosine",
"hnsw:M": 16, # 连接度
"hnsw:ef_construction": 200 # 构建效率
}
)
6.2 量化加速
# FP16 量化(显存减半,精度损失小)
model = SentenceTransformer(
'BAAI/bge-m3',
model_kwargs={"torch_dtype": torch.float16}
)
# INT8 量化(显存减 4 倍)
from optimum.quanto import quantize
quantize(model, bits=8)
7. 常见问题排查
问题 1:检索结果不相关
原因:Embedding 质量差或 chunk 切分不当
解决: - 换更好的模型(bge-m3 → text-embedding-3-large) - 优化 chunk_size(512 → 1024) - 调整相似度阈值(0.75 → 0.6)
问题 2:检索速度慢
解决: - 启用 HNSW 索引 - 减小向量维度(1024 → 768) - 使用 GPU 加速推理
问题 3:长文本截断
解决: - 用支持长文本的模型(bge-m3 支持 8192 token) - 提前切分长文档 - 用 sliding window 滑动切片