轻量 Embedding CPU实战:实现embedding和语义检索
本文基于 ModelScope 的ONNX 模型,实现了轻量、高效、多语言的文本 Embedding 与相似度检索,完全适配 RAG 系统的核心需求。相比闭源 API,本地 ONNX 推理无成本、无延迟、数据安全,且性能足以支撑中小规模 RAG 应用。后续可进一步集成向量数据库、优化文档切分策略,打造完整的企业级 RAG 检索系统。

在 RAG(检索增强生成)系统中,文本 Embedding 与向量相似度检索是核心环节 —— 把文本转为高维向量、再通过余弦相似度找到语义最相关内容,让大模型能精准召回知识。本文将基于 ModelScope 上的intfloat/multilingual-e5-small模型,下载 ONNX 格式后,用 Python 实现本地高效 Embedding 生成 + 余弦相似度计算,并适配 RAG 场景的向量检索需求。
一、模型与技术选型
1.1 为什么选 multilingual-e5-small?
multilingual-e5-small是 intfloat 开源的轻量多语言文本 Embedding 模型,适配 RAG / 语义检索场景,核心优势:
- 多语言覆盖
:支持 100 + 语言(含中文、英文、日文等),跨语言语义统一
- 轻量高效
:12 层 Transformer、384 维输出向量,体积小、推理快,适合本地部署
- ONNX 友好
:可导出 / 直接使用 ONNX 格式,搭配
onnxruntime实现 CPU 加速推理 - RAG 适配
:专为检索优化,Mean Pooling 输出句子向量,余弦相似度效果稳定
模型来源:ModelScope intfloat/multilingual-e5-small
1.2 技术栈
- 模型格式
:ONNX(本地推理、无依赖、跨平台)
- 推理引擎
:
onnxruntime(高效执行 ONNX 模型) - 分词工具
:
transformers(加载模型配套 Tokenizer) - 相似度计算
:
scikit-learn(余弦相似度) - 向量处理
:
numpy(张量运算、均值池化)
二、环境准备与模型下载
2.1 安装依赖
pip install onnxruntime transformers scikit-learn numpy
2.2 下载 ONNX 模型
-
打开 ModelScope 模型页:https://www.modelscope.cn/models/intfloat/multilingual-e5-small/
-
进入模型文件,找到并下载ONNX 格式模型包(含
model.onnx、tokenizer.json、vocab.txt等) -
解压到本地目录,例如:
E:\git_project\factory-qa\models\multilingual-e5-small-onnx
提示:也可通过
transformers.onnx工具将 PyTorch 版导出为 ONNX,社区已提供预导出版本,直接下载更高效。
三、代码重构与实现(模块化优化版)
基于原代码重构,拆分为模型加载、Embedding 生成、相似度计算、批量检索、结果打印五大函数,逻辑清晰、可复用、易扩展。
3.1 完整代码
import time
import numpy as np
import onnxruntime as ort
from sklearn.metrics.pairwise import cosine_similarity
from transformers import AutoTokenizer
# -------------------------- 配置常量(按需修改)--------------------------
# 本地ONNX模型目录
MODEL_DIR = r"E:\git_project\factory-qa\models\multilingual-e5-small-onnx"
# ONNX模型文件名
ONNX_MODEL_FILE = "model.onnx"
# 文本最大长度(截断/填充)
MAX_SEQ_LENGTH = 512
# ---------------------------------------------------------------------------
def load_onnx_embedding_model(model_dir: str):
"""
加载ONNX推理会话与Tokenizer
:param model_dir: 模型本地目录
:return: tokenizer, ort_session(分词器、ONNX会话)
"""
# 加载Tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_dir)
# 加载ONNX模型
onnx_path = f"{model_dir}/{ONNX_MODEL_FILE}"
ort_session = ort.InferenceSession(onnx_path)
print(f"✅ 模型加载完成:{onnx_path}")
return tokenizer, ort_session
def generate_text_embedding(ort_session, tokenizer, text: str) -> np.ndarray:
"""
单文本生成Embedding向量(ONNX推理+均值池化)
:param ort_session: ONNX推理会话
:param tokenizer: 分词器
:param text: 输入文本
:return: 384维句子Embedding向量
"""
# 文本分词预处理
inputs = tokenizer(
text,
return_tensors="pt",
padding=True,
truncation=True,
max_length=MAX_SEQ_LENGTH
)
# 构造ONNX输入(转为numpy,补全token_type_ids)
input_feed = {
"input_ids": inputs["input_ids"].numpy(),
"attention_mask": inputs["attention_mask"].numpy(),
"token_type_ids": np.zeros_like(inputs["input_ids"].numpy())
}
# ONNX推理
outputs = ort_session.run(None, input_feed)
token_embeddings = outputs[0] # (1, seq_len, 384)
# 均值池化:token级向量 → 句子级向量
sentence_embedding = np.mean(token_embeddings, axis=1)
return sentence_embedding
def compute_cosine_similarity(emb1: np.ndarray, emb2: np.ndarray) -> float:
"""
计算两个句子Embedding的余弦相似度
:param emb1: 向量1
:param emb2: 向量2
:return: 相似度(0~1,值越高越相似)
"""
return cosine_similarity(emb1, emb2)[0][0]
def batch_similarity_retrieval(
ort_session,
tokenizer,
query: str,
candidate_texts: list
) -> tuple:
"""
批量检索:查询 vs 候选文本,计算相似度+统计性能
:param ort_session: ONNX会话
:param tokenizer: 分词器
:param query: 查询文本
:param candidate_texts: 候选文本列表
:return: 相似度结果、总耗时、总Token数、推理速度
"""
# 仅生成1次查询向量(优化性能,避免重复计算)
start = time.time()
query_emb = generate_text_embedding(ort_session, tokenizer, query)
query_time = time.time() - start
results = []
total_time = 0.0
total_tokens = 0
# 遍历候选文本,计算相似度
for text in candidate_texts:
t_start = time.time()
text_emb = generate_text_embedding(ort_session, tokenizer, text)
# 统计耗时与Token数
cost = time.time() - t_start
total_time += cost
total_tokens += text_emb.shape[1]
# 计算相似度
sim = compute_cosine_similarity(query_emb, text_emb)
results.append((query, text, sim))
# 计算推理速度(Token/秒)
speed = total_tokens / total_time if total_time > 0 else 0
total_cost = query_time + total_time
return results, total_cost, total_tokens, speed
def print_retrieval_result(results: list, total_time: float, total_tokens: int, speed: float):
"""格式化打印检索结果与性能数据"""
print("\n" + "="*60)
print("📊 语义相似度检索结果")
print("="*60)
for q, t, s in results:
print(f"相似度:{s:.3f} | 查询:{q} | 候选:{t}")
print("="*60)
print(f"⏱️ 总耗时:{total_time:.4f}s | 总Token数:{total_tokens} | 推理速度:{speed:.2f} token/s")
def main():
"""主函数:执行完整流程"""
# 1. 加载模型
tokenizer, ort_session = load_onnx_embedding_model(MODEL_DIR)
# 2. 定义查询与候选文本(模拟RAG知识库)
query = "苹果手机多少钱"
candidates = [
"这个小米的手机什么价格",
"苹果什么价值",
"我想买一部分手机",
"iPhone 15售价多少",
"华为手机最新报价"
]
# 3. 批量相似度检索
results, total_time, total_tokens, speed = batch_similarity_retrieval(
ort_session, tokenizer, query, candidates
)
# 4. 打印结果
print_retrieval_result(results, total_time, total_tokens, speed)
if __name__ == "__main__":
main()
3.2 代码核心说明
- 模型加载
:
load_onnx_embedding_model统一加载 Tokenizer 与 ONNX 会话,解耦初始化逻辑。 - Embedding 生成
:
generate_text_embedding完成分词→ONNX 推理→均值池化,输出 384 维句子向量(适配 RAG 向量库)。 - 相似度计算
:
compute_cosine_similarity基于余弦相似度衡量语义相关性,值越接近 1 越相似。 - 批量检索
:
batch_similarity_retrieval优化查询向量仅生成 1 次,大幅提升批量处理速度,并统计推理性能。 - 结果打印
:
print_retrieval_result格式化输出相似度与性能指标,便于调试与评估。
四、运行结果与效果解析
============================================================
📊 语义相似度检索结果
============================================================
相似度:0.922 | 查询:苹果手机多少钱 | 候选:这个小米的手机什么价格
相似度:0.946 | 查询:苹果手机多少钱 | 候选:苹果什么价值
相似度:0.905 | 查询:苹果手机多少钱 | 候选:我想买一部分手机
相似度:0.936 | 查询:苹果手机多少钱 | 候选:iPhone 15售价多少
相似度:0.918 | 查询:苹果手机多少钱 | 候选:华为手机最新报价
============================================================
⏱️ 总耗时:0.0270s | 总Token数:1920
4.2 结果解读
- 语义匹配精准
:“苹果什么价值” 与查询相似度最高(0.946),“iPhone 15售价多少” 次之(0.936),符合语义逻辑。
- 推理效率高
:CPU 环境下速度快,满足 RAG 实时检索需求。
- 多语言兼容
:输入英文 / 日文文本同样可生成有效向量,适配跨境 RAG 场景。
五、在 RAG 系统中的应用
5.1 RAG 核心流程(Embedding + 检索)
- 知识库向量化
:将文档 / FAQ 切分→用本模型生成 Embedding→存入向量数据库(如 FAISS、Qdrant、Milvus)。
- 用户查询向量化
:用户提问→生成查询 Embedding。
- 向量检索
:在向量库中查找 Top-K 最相似的文本片段→返回给大模型生成答案。
5.2 扩展建议
- 向量归一化
:对 Embedding 做 L2 归一化,提升余弦相似度计算稳定性(
np.linalg.norm(emb, axis=1, keepdims=True))。 - 批量处理优化
:对候选文本批量分词 / 推理,进一步提升吞吐量。
- 向量数据库集成
:将生成的 Embedding 存入 FAISS/Qdrant,实现百万级数据毫秒级检索。
- 模型量化
:使用 ONNX Runtime INT8 量化,模型体积减少 60%、速度提升 45%。
六、总结
本文基于 ModelScope 的multilingual-e5-small ONNX 模型,实现了轻量、高效、多语言的文本 Embedding 与相似度检索,完全适配 RAG 系统的核心需求。相比闭源 API,本地 ONNX 推理无成本、无延迟、数据安全,且性能足以支撑中小规模 RAG 应用。
后续可进一步集成向量数据库、优化文档切分策略,打造完整的企业级 RAG 检索系统。
更多推荐
所有评论(0)