Ascend-SACT/bge-m3_mistei
模型介绍文件和版本Pull Requests讨论分析
下载使用量0

BGE-M3模型服务化部署与精度评测实践

1. 背景

本文档介绍 BGE-M3 模型的完整服务化部署与精度评测实践,涵盖以下两个核心环节:

  1. 服务化部署:基于昇腾(Ascend)NPU 与 TEI(Text Embeddings Inference)框架,通过 Docker 容器将 BGE-M3 模型封装为兼容 OpenAI /v1/embeddings 格式的在线推理服务。
  2. 精度评测:使用 FlagEmbedding 框架,在 MKQA(Multilingual Knowledge Questions & Answers)多语言问答数据集上对部署后的模型服务进行跨语言检索能力评测,验证服务化后的模型精度是否满足预期。

MKQA 是一个多语言问答数据集,涵盖 26 种语言,所有语言共享同一英文语料库(BeIR/nq,约 268 万篇文档)。评测目标是验证模型在不同语言 query 下的跨语言检索能力。


2. 服务化部署

2.1 拉取镜像

docker pull swr.cn-south-1.myhuaweicloud.com/ascendhub/mis-tei:26.0.0-800I-A2-aarch64

2.2 下载权重

TORCH_DEVICE_BACKEND_AUTOLOAD=0 modelscope download --model BAAI/bge-m3

2.3 创建在线推理容器

export IMAGE=swr.cn-south-1.myhuaweicloud.com/ascendhub/mis-tei:26.0.0-800I-A2-aarch64
export NAME=bge-m3

docker run -u root -e ENABLE_BOOST=True -itd --privileged \
  --name $NAME \
  --net=host \
  --shm-size=40g \
  --device /dev/davinci_manager \
  --device /dev/devmm_svm \
  --device /dev/hisi_hdc \
  -w /workspace \
  -v /usr/local/Ascend/driver:/usr/local/Ascend/driver:ro \
  -v /usr/local/sbin:/usr/local/sbin:ro \
  -v /opt/data/models:/home/HwHiAiUser/model/ \
  $IMAGE BAAI/bge-m3 0.0.0.0 8003

2.4 测试服务

curl 127.0.0.1:8003/v1/embeddings \
  -X POST \
  -d '{
    "input": ["The capital of China is Beijing."]
  }' \
  -H 'Content-Type: application/json'

3. 精度评测

3.1 数据集介绍

3.1.1 MKQA 数据集结构

属性说明
全称Multilingual Knowledge Questions & Answers
语言数26 种
共享语料BeIR/nq(英文维基百科,2,681,468 篇文档)
Query 数约 10,000(每种语言)
答案形式短文本答案(非多项选择)
评测指标QA Recall@k

3.1.2 支持的语言代码

MKQA 数据集涵盖 26 种语言,各语言代码如下表所示:

序号语言代码序号语言代码
1阿拉伯语ar14日语ja
2丹麦语da15高棉语km
3德语de16韩语ko
4英语en17马来语ms
5西班牙语es18荷兰语nl
6芬兰语fi19挪威语no
7法语fr20波兰语pl
8希伯来语he21葡萄牙语pt
9匈牙利语hu22俄语ru
10意大利语it23瑞典语sv
11简体中文zh_cn24泰语th
12繁体中文(香港)zh_hk25土耳其语tr
13繁体中文(台湾)zh_tw26越南语vi

3.1.3 QA Recall@k 指标说明

与传统 IR Recall 不同,MKQA 的 QA Recall 检查的是:检索到的 top-k 文档中是否包含答案文本。

# 核心逻辑:答案字符串是否出现在文档中
def has_answer(answers, text) -> bool:
    for answer in answers:
        if answer.lower() in text.lower():
            return True
    return False

3.2 环境准备

3.2.1 依赖安装

# 克隆 FlagEmbedding 仓库
git clone https://github.com/FlagOpen/FlagEmbedding.git
cd FlagEmbedding

# 切换到 patch 对应的 commit
git checkout 7ed43d6

# 安装 FlagEmbedding
pip install -e .

# 安装评测依赖
pip install faiss-cpu datasets pytrec_eval

3.4 代码适配

3.4.1 获取 Patch

从当前仓库中获取Patch 文件,其中包含所有代码修改和新增文件:

# 将 patch 复制到仓库根目录后应用
git apply mkqa_api_eval.patch

3.4.2 确认应用成功

git status

应看到以下变更:

文件状态说明
api_embedder.py新增API Embedder 实现
run_mkqa_api.py新增评测主入口
quick_verify.py新增快速验证脚本
FlagEmbedding/evaluation/mkqa/utils/compute_metrics.py修改添加 tqdm 进度条

3.4.3 整体架构

FlagEmbedding 默认流程:

本地加载 HuggingFace 模型 → Corpus Encoding → FAISS Index → Query Encoding → Search → Evaluate

适配后流程:

调用远程 Embedding API → Corpus Encoding → FAISS Index → Query Encoding → Search → Evaluate

各阶段详细说明:

阶段说明输入/输出
Corpus Encoding通过 Embedding API 对 268 万篇英文语料进行向量编码,生成 doc.npy(约 10.3 GB)输入:BeIR/nq 语料文本;输出:(2681468, 1024) 维 float32 数组
FAISS Index基于余弦相似度构建平面内积索引(IndexFlatIP),支持 top-k 最近邻检索输入:Corpus embeddings;输出:可查询的 FAISS 索引对象
Query Encoding对评测语言的 query 文本进行向量编码(每种语言约 6,600 条 query)输入:MKQA query 文本;输出:(n_queries, 1024) 维向量
Search在 FAISS 索引中检索与 query 最相似的 top-k 文档输入:Query embeddings + FAISS 索引;输出:(n_queries, top_k) 文档 ID 及相似度分数
Evaluate使用 has_answer 判断检索结果中是否包含答案文本,计算 QA Recall@k输入:Search 结果 + 标准答案;输出:qa_recall@{1,3,5,10,100,1000}

3.4.4 API Embedder 实现(api_embedder.py)

核心逻辑:继承 AbsEmbedder,将 encode_single_device 重载为 HTTP API 调用。

class APIEmbedder(AbsEmbedder):
    def __init__(self, ..., max_workers=8, **kwargs):
        kwargs["devices"] = ["cpu"]
        super().__init__(...)
        self.max_workers = max_workers

    def encode_single_device(self, sentences, batch_size=256, ...):
        # 使用 ThreadPoolExecutor 并发调用 API
        with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
            # 提交所有 batch 任务
            future_to_idx = {
                executor.submit(self._call_api, batch): batch_idx
                ...
            }
            # 收集结果
            for future in tqdm(as_completed(future_to_idx), ...):
                ...

3.4.5 主入口脚本(run_mkqa_api.py)

适配后的评测入口,支持命令行参数:

def parse_args():
    parser.add_argument("--dataset_names", nargs="+", default=None)  # 语言代码
    parser.add_argument("--api_url", default="http://127.0.0.1:8003/v1/embeddings")
    parser.add_argument("--api_model", default="bge-m3")
    parser.add_argument("--api_batch_size", type=int, default=64)
    parser.add_argument("--search_top_k", type=int, default=1000)
    parser.add_argument("--corpus_embd_save_dir", default=None)  # Corpus 缓存目录
    parser.add_argument("--overwrite", action="store_true")      # 覆盖已有结果
    ...

3.4.6 快速验证脚本(quick_verify.py)

用于端到端 pipeline 验证,使用小规模数据(默认 1000 文档 + 100 query),数分钟内完成。所有参数均通过命令行传入:

def parse_args():
    # data
    parser.add_argument("--cache_path", default="/tmp/hf_cache")          # HF 数据集缓存目录
    parser.add_argument("--dataset_name", default="en")                   # MKQA 语言代码
    parser.add_argument("--max_docs", type=int, default=1000)             # 采样的语料文档数
    parser.add_argument("--max_queries", type=int, default=100)           # 采样的 query 数
    ...

3.5 测试命令

3.5.1 快速验证

# 预创建缓存子目录(避免 wget 因目录缺失失败)
mkdir -p /tmp/hf_cache/mkqa

# 测试 1000 文档 + 100 query,验证 pipeline 完整性
HF_ENDPOINT=https://hf-mirror.com python quick_verify.py \
    --cache_path /tmp/hf_cache \
    --dataset_name en \
    --max_docs 1000 \
    --max_queries 100 \
    --api_url "http://127.0.0.1:8003/v1/embeddings" \
    --api_model "bge-m3" \
    --api_batch_size 32 \
    --top_k 100

3.5.2 单语言评测(英文)

mkdir -p /tmp/hf_cache/mkqa

nohup env HF_ENDPOINT=https://hf-mirror.com python run_mkqa_api.py \
    --dataset_names en \
    --cache_path /tmp/hf_cache \
    --api_url "http://127.0.0.1:8003/v1/embeddings" \
    --api_model "bge-m3" \
    --api_batch_size 32 \
    --search_top_k 1000 \
    --output_dir ./search_results_api \
    --corpus_embd_save_dir ./corpus_embd_api \
    --eval_output_path ./eval_results_api.md \
    --log_level INFO \
    > run_en_eval.log 2>&1 &

3.5.3 单语言评测(中文)

mkdir -p /tmp/hf_cache/mkqa

nohup env HF_ENDPOINT=https://hf-mirror.com python run_mkqa_api.py \
    --dataset_names zh_cn \
    --cache_path /tmp/hf_cache \
    --api_url "http://127.0.0.1:8003/v1/embeddings" \
    --api_model "bge-m3" \
    --api_batch_size 32 \
    --search_top_k 1000 \
    --output_dir ./search_results_api \
    --corpus_embd_save_dir ./corpus_embd_api \
    --eval_output_path ./eval_results_api.md \
    --log_level INFO \
    > run_zh_eval.log 2>&1 &

3.5.4 全量 26 语言评测

mkdir -p /tmp/hf_cache/mkqa

nohup env HF_ENDPOINT=https://hf-mirror.com python run_mkqa_api.py \
    --cache_path /tmp/hf_cache \
    --api_url "http://127.0.0.1:8003/v1/embeddings" \
    --api_model "bge-m3" \
    --api_batch_size 32 \
    --search_top_k 1000 \
    --output_dir ./search_results_api \
    --corpus_embd_save_dir ./corpus_embd_api \
    --eval_output_path ./eval_results_api.md \
    --log_level INFO \
    > run_all_eval.log 2>&1 &

3.5.5 参数说明

quick_verify.py(快速验证脚本)与 run_mkqa_api.py(完整评测脚本)支持的命令行参数分为三类:通用参数、quick_verify.py 独有参数、run_mkqa_api.py 独有参数。

通用参数(两个脚本都支持):

参数说明quick_verify 默认值run_mkqa_api 默认值
--cache_pathHuggingFace 数据集缓存目录/tmp/hf_cacheNone(需手动指定)
--api_urlEmbedding API 地址http://127.0.0.1:8003/v1/embeddingshttp://127.0.0.1:8005/v1/embeddings
--api_modelAPI 请求体中的 model 字段bge-m3bge-m3
--api_batch_size每次 API 请求批量大小3264
--log_level日志级别(DEBUG/INFO/WARNING/ERROR)INFOINFO

快速验证参数(仅quick_verify.py):

参数默认值说明
--dataset_nameen验证使用的 MKQA 语言代码(单语言,如 en、zh_cn)
--max_docs1000从 BeIR/nq 语料中采样的文档数量(小规模快速验证)
--max_queries100从 MKQA 中采样的 query 数量
--top_k100每个 query 检索的 top-k 文档数(实际值不超过语料规模)

完整评测参数(仅run_mkqa_api.py ):

参数默认值说明
--dataset_dirNone本地 MKQA 数据集目录(为空时仅使用缓存)
--dataset_namesNone(全部 26 种)评测语言代码列表(多语言,可空格分隔多个,如 en zh_cn)
--output_dir./search_results_api搜索结果保存目录
--corpus_embd_save_dirNoneCorpus embeddings 缓存目录(用于跨语言复用)
--overwriteFalse是否覆盖已有的搜索结果与 embeddings 缓存
--search_top_k1000每个 query 检索的 top-k 文档数
--eval_output_path./eval_results_api.md多语言汇总评测结果的 Markdown 输出路径

注意事项:

  • quick_verify.py 的 --top_k 与 run_mkqa_api.py 的 --search_top_k 作用一致,但参数名不同
  • quick_verify.py 的 --dataset_name(单数)只接受单语言,run_mkqa_api.py 的 --dataset_names(复数)接受多语言列表
  • 实际部署中 API 端口为 8003,使用 run_mkqa_api.py 时需通过 --api_url 显式覆盖默认值

3.6 测试与优化过程

3.6.1 各阶段耗时分析

阶段英文中文说明
Corpus Loading~3.5 min~4 min加载 268 万文档
Corpus API Encoding~58 min0(缓存复用)首次需编码,后续复用
FAISS Index 构建~1.5 min~1.5 min构建向量索引
Query API Encoding~8 sec~7 sec编码 query
FAISS Search~41 min~44 min检索
Evaluate~42 min~44 min计算 qa_recall@k
总计~2.5 小时~1.7 小时

3.7 结果说明

3.7.1 评测结果

{
    "en-test": {
        "qa_recall_at_1": 0.4687,
        "qa_recall_at_3": 0.6073,
        "qa_recall_at_5": 0.6542,
        "qa_recall_at_10": 0.6989,
        "qa_recall_at_100": 0.7840,
        "qa_recall_at_1000": 0.8234
    },
    "zh_cn-test": {
        "qa_recall_at_1": 0.3650,
        "qa_recall_at_3": 0.5170,
        "qa_recall_at_5": 0.5653,
        "qa_recall_at_10": 0.6256,
        "qa_recall_at_100": 0.7500,
        "qa_recall_at_1000": 0.8127
    }
}

3.7.2 结果对比

指标英文 (en)中文 (zh_cn)差距
qa_recall@146.87%36.50%-10.37
qa_recall@360.73%51.70%-9.03
qa_recall@565.42%56.53%-8.89
qa_recall@1069.89%62.56%-7.33
qa_recall@10078.40%75.00%-3.40
qa_recall@100082.34%81.27%-1.07

3.7.3 与官方结果对比

M3-Embedding 结果:

语言官方 Dense Recall@100本次服务化 qa_recall@100差异
中文 (zh_cn)74.6%75.00%+0.40

说明:

  • 服务化部署后通过 API 调用获得的评测结果与官方结果一致,验证了服务化部署的精度无损

3.7.4 结果分析

  1. 低 k 值差距明显:@1 / @3 / @5 差距 8-10 个百分点,说明中文 query 的 top 排名检索质量低于英文
  2. 高 k 值差距缩小:@100 / @1000 差距仅 1-3 个百分点,说明模型仍能召回大部分答案,只是排名靠后
  3. 非英语 query 检索英文语料,存在语言差异,精度下降属正常现象

4. 结论与建议

  1. API 化适配可行:通过 APIEmbedder 将 FlagEmbedding 框架适配为远程 API 调用,无需修改框架核心逻辑,完整保留了评测流程的准确性。

  2. Corpus embedding 可复用:26 种语言共享同一语料库,首次编码后缓存 doc.npy,后续语言无需重复编码,大幅节省时间和 API 调用成本。

  3. 中文检索能力:中文 qa_recall@1000 达 81.27%,与英文 82.34% 差距仅 1.07 个百分点,说明 BGE-M3 的跨语言检索能力较强。