4. 向量化嵌入模型选择
任务目标
在中文RAG场景中,不同嵌入模型对检索质量影响显著。本案例将使用同一中文问答数据集,分别通过 text-embedding-3-small、Cohere embed-multilingual-v3.0以及HuggingFace的BAAI/bge-small-zh-v1.5生成向量,基于余弦相似度进行Top-K检索,以Recall@K和命中率(Hit Rate)为指标评估三者性能差异。
环境与依赖
pip install cohere sentence-transformers numpy pandas
需要提前设置环境变量_与COHERE_。HuggingFace模型首次运行会自动下载权重(约100MB)。
数据集准备
使用公开中文问答数据集clue/clue(取自CLUE benchmark的AFQMC子集),取前200条作为语料库,另取20条不重复的问题作为查询集。每条数据包含sentence1(查询)与sentence2(相关文档)。
完整实现代码
import os
import numpy as np
import pandas as pd
from datasets import load_dataset
from import
import cohere
from sentence_transformers import SentenceTransformer
# ---------- 1. 加载数据 ----------
ds = load_dataset("clue", "afqmc", split="train")
df = ds.to_pandas().sample(frac=1, random_state=42).reset_index(drop=True)
corpus = df["sentence2"].head(200).tolist() # 语料库
queries = df["sentence1"].iloc[200:220].tolist() # 20条查询
true_docs = df["sentence2"].iloc[200:220].tolist() # 每条查询对应的相关文档
# ---------- 2. 定义嵌入函数 ----------
_client = (=os.environ["_"])
cohere_client = cohere.Client(os.environ["COHERE_"])
hf_model = SentenceTransformer("BAAI/bge-small-zh-v1.5")
def get_embeddings(texts, provider):
"""统一接口:输入文本列表,返回归一化向量矩阵"""
if provider == "":
resp = _client.embeddings.create(
model="text-embedding-3-small", input=texts)
vecs = [d.embedding for d in resp.data]
elif provider == "cohere":
resp = cohere_client.embed(texts=texts,
model="embed-multilingual-v3.0",
input_type="search_document")
vecs = resp.embeddings
elif provider == "hf":
vecs = hf_model.encode(texts, normalize_embeddings=True)
return np.array(vecs)
# ---------- 3. 检索评估 ----------
def evaluate(provider):
# 生成向量(/Cohere返回后需手动归一化)
doc_vecs = get_embeddings(corpus, provider)
query_vecs = get_embeddings(queries, provider)
if provider != "hf":
doc_vecs = doc_vecs / np.linalg.norm(doc_vecs, axis=1, keepdims=True)
query_vecs = query_vecs / np.linalg.norm(query_vecs, axis=1, keepdims=True)
# 余弦相似度矩阵
sim_matrix = query_vecs @ doc_vecs.T
hit_at_1, hit_at_5, recall_at_5 = 0, 0, 0
for i in range(len(queries)):
top_indices = np.argsort(sim_matrix[i])[::-1][:5]
top_docs = [corpus[idx] for idx in top_indices]
if true_docs[i] in top_docs[:1]:
hit_at_1 += 1
if true_docs[i] in top_docs:
hit_at_5 += 1
recall_at_5 += 1 # 每个查询仅1个相关文档,Recall@5=命中率
n = len(queries)
return {
"Hit@1": hit_at_1 / n,
"Hit@5": hit_at_5 / n,
"Recall@5": recall_at_5 / n
}
# ---------- 4. 运行对比 ----------
if __name__ == "__main__":
results = {}
for provider in ["", "cohere", "hf"]:
print(f"正在评估 {provider} ...")
results[provider] = evaluate(provider)
# 输出结果表
df_result = pd.DataFrame(results).T
df_result.columns = ["Hit@1", "Hit@5", "Recall@5"]
print("\n===== 中文检索性能对比 =====")
print(df_result.round(4))
运行方式
export _="sk-..."
export COHERE_="..."
python evaluate_embeddings.py
验证方法与判定标准
程序运行后会在终端打印三行结果,每行包含Hit@1、Hit@5和Recall@5三个指标。由于三个模型使用完全相同的查询与语料,可直接横向比较数值:
- 判定通过条件:三个模型均成功输出0~1之间的浮点数,且
Hit@5值明显高于随机基线(随机检索期望Hit@5≈5/200=0.025),说明检索有效。 - 预期观察:通常
BAAI/bge-small-zh-v1.5在中文数据上Recall@5接近或超过与Cohere(该模型针对中文优化),但具体数值取决于数据子集采样,以实际输出为准。
常见问题
- /Cohere限流:若请求过多报429错误,可在
get_embeddings中增加time.sleep(0.5)或减小数据集规模。 - HuggingFace下载慢:首次运行需下载模型,可设置
HF_ENDPOINT=https://hf-mirror.com加速。 - 结果差异:若某模型所有指标为0,检查是否因无效或网络问题导致嵌入返回空值。