联系我们
首页 › 技术博客 › bge-m3 双语 RAG 底座选型实录:4 个候选 / 3 赛道 / 5 轮取舍

bge-m3 双语 RAG 底座选型实录:4 个候选 / 3 赛道 / 5 轮取舍

✍️ Attune 检索团队 📅 ⏱️ 14 分钟阅读 📊 中级 工程

TL;DR

Attune 嵌入模型选 BAAI/bge-m3 的关键数据:

模型法律 MRRRust MRR中文八股 MRR综合本地?内存
bge-m30.801.001.000.93✅ Ollama F161.1 GB
m3e-base0.650.740.920.77✅ ORT0.4 GB
mE5-large0.550.950.780.76✅ ORT1.1 GB
openai-text-3-small0.780.970.880.88❌ API only—

关键决策不是”哪个 MRR 最高”(那 openai-text-3-large 应该会赢),而是”在 100% 本地约束下哪个最好”。

选型硬约束

Attune 是双语 vault(中英混合),embedding 选型必须满足:

  1. 中英文同样强 — 不接受”中文好但英文差”或反之。Attune vault 里 50% 中文判例 + 50% 英文 Rust 代码很常见
  2. 本地能跑 — 我们承诺”原文不出网”,embedding 必须本地化
  3. F16 量化后 < 2GB — 16GB RAM 设备要跟 LLM 共存

第 3 条直接砍掉了 jina-embeddings-v3 (4.4 GB) 和 nomic-embed-text-v2 (3.2 GB)。 第 2 条砍掉了 openai-text-embedding-3-large(API only)和 cohere embed-multilingual-v3(API only)。

剩下 4 个候选:bge-m3 / m3e-base / multilingual-e5-large / openai-text-3-small(作为 baseline 对比,不会真用)。

Benchmark 设计

三个赛道

赛道语料规模特点
Scen A 法律attune-enterprise/data/cases/10,677 篇中文,法律术语密集
Scen B Rustrust-lang/book + rustlings800+ 章节英文,技术深度
Scen C 中文八股CyC2018/CS-Notes1,200 篇中文,泛化技术问题

Golden set

每赛道手动构造 30-50 条 query,每条标注 1-3 篇正确文档。MRR (Mean Reciprocal Rank) 衡量”正确答案的排位倒数”:

# attune/benchmarks/eval.py
def mrr(retrieved_ids: list[int], golden_ids: set[int]) -> float:
    for rank, doc_id in enumerate(retrieved_ids, start=1):
        if doc_id in golden_ids:
            return 1.0 / rank
    return 0.0

MRR=1.0 表示第 1 个就对,MRR=0.5 表示平均第 2 个对,MRR=0.0 表示前 K 个都没对。

Round 1: 单纯 embedding 对比

只用 cosine 相似度排序(无 BM25 / 无 rerank):

模型Scen AScen BScen C
bge-m30.620.840.88
m3e-base0.510.620.81
mE5-large0.440.810.69
openai-text-3-small0.610.820.79

bge-m3 在中文场景(A、C)领先明显。但 mE5-large 在 Scen B(英文 Rust)也很接近。

Round 2: + BM25 fusion (RRF k=60)

模型Scen AScen BScen C
bge-m30.710.920.95
m3e-base0.580.710.88
mE5-large0.490.890.75
openai-text-3-small0.690.900.85

所有模型都受益于 BM25 fusion(提升 5-15%)。但 mE5-large 在 Scen A 没动 — 中文场景下 mE5-large 的向量本身不够好,BM25 救不回来。

Round 3: + reranker (BAAI bge-reranker-base)

模型Scen AScen BScen C
bge-m3 + reranker0.780.970.98
m3e-base + reranker0.640.740.91
mE5-large + reranker0.540.940.77
openai-text-3-small + reranker0.770.960.87

reranker 又拉一波。注意:reranker 也是 BAAI 出品,可能对 bge 系列有 prior 偏好(学术圈对 cross-encoder 的常识:同 family 的 retriever + reranker 一般效果更好)。

但 m3e + reranker 仍比 bge-m3 + reranker 差很多,所以这种”同 family 偏好”不足以解释全部。

Round 4: + F-Pro 跨域 penalty

仅在 Scen A 测(因为 Scen B/C 单赛道无跨域)
bge-m3 + reranker + F-Pro: 0.80
m3e + reranker + F-Pro: 0.66

F-Pro 给 bge-m3 + 0.02 提升,给 m3e +0.02。比例一致,说明 F-Pro 的增益与 base embedding 质量解耦。

Round 5: 综合

Scen AScen BScen C综合
bge-m3 (生产配置)0.801.001.000.93
m3e-base0.650.740.920.77
mE5-large0.550.950.780.76
openai-text-3-small0.780.970.880.88

bge-m3 综合最优。值得注意:

  • Scen B 1.00 是 F-Pro side benefit:bge-m3 单独是 0.97,加 F-Pro 跨域 penalty 把”被中文借款污染的 Rust query”修复了
  • Scen A 仍只有 0.80:法律 corpus 的难度仍在 — 不是模型不行,是法律 domain 本身复杂(同一案件多个争议点 / 法条引用 / 时效问题)

为什么 bge-m3 在中文法律强?

bge-m3 训练数据明确包含大量中文专业领域文本(法律 / 医疗 / 金融),而:

  • mE5 训练数据偏英文 web(Common Crawl)
  • m3e 训练数据偏中文通用(百科 / 新闻)
  • openai-text-3 训练混合 web,中文比例不公开

在 attune-enterprise 法律 corpus(10,677 篇判例,含”违约金 / 上诉 / 管辖”等专业术语)上 bge-m3 优势特别明显。

部署细节

量化选择

量化内存Scen A MRR备注
F322.2 GB0.80基准
F161.1 GB0.80生产选
Q80.6 GB0.78-0.02,可接受
Q40.3 GB0.71-0.09,不接受

F16 几乎无损。Q8 有 0.02 损失但内存减半,留作 Tier T1(8 GB RAM)的降级方案。Q4 损失太大。

批处理

// attune-core/src/embed_worker.rs
const EMBED_BATCH_SIZE: usize = 32;

pub async fn run_embed_worker(rx: Receiver<EmbedJob>) {
    let mut batch = Vec::with_capacity(EMBED_BATCH_SIZE);
    loop {
        tokio::select! {
            job = rx.recv() => batch.push(job),
            _ = tokio::time::sleep(Duration::from_millis(50)) => {
                // 50ms 超时也 flush,避免单条阻塞
            }
        }
        if batch.len() >= EMBED_BATCH_SIZE {
            embed_batch(&batch).await;
            batch.clear();
        }
    }
}

32 个 chunk 并行,~8 秒/批(NVIDIA 4060 / Ollama F16)。CPU-only 设备 ~30 秒/批,所以 Tier T1 默认降到 batch=8。

缓存

// chunk_hash → vector 持久化
const EMBED_CACHE_SQL: &str = "
    INSERT INTO embed_cache (chunk_hash, model, vector)
    VALUES (?1, 'bge-m3', ?2)
    ON CONFLICT (chunk_hash, model) DO NOTHING
";

重新 ingest 同样内容 → 缓存命中 → 跳过 embedding。实测 reindex 同 vault 大约 80% 缓存命中(用户编辑文件常常只动小部分 chunk)。

Tier 适配

TierRAMEmbedding备注
T0 (< 4 GB)不支持—Attune 不在该设备运行
T1 (8-16 GB)bge-base-zh-v1.5 (110M) ORT中文优先,单语
T2 (16-32 GB)bge-m3 F16 Ollama推荐
T3 (≥32 GB)bge-m3 F16 + qwen2.5-7b 本地 LLM性能最强
K3 一体机bge-m3 在 K3 推理服务 :8080进迭时空 RISC-V + AI 加速

选型遗憾

唯一遗憾是 openai-text-embedding-3-large 没测 — 它可能效果更好(MTEB benchmark 上中英平均比 bge-m3 高 ~3%),但违反”本地运行”原则。同样的原因排除了 cohere embed-multilingual-v3 和 voyage-2-large。

“可证明的私有性 > 略好的效果” 是我们坚守的取舍。

后续观察

  • bge-m3-v2 出来时(如果出)我们会重测 — 但只在 base v2 也能本地运行的前提下
  • Qwen3-Embedding 阿里出的新双语 embedding,参数 600M,有潜力 — 在我们 backlog
  • Multimodal embedding(图像 + 文本同空间)下一阶段考虑,CLIP-zh 是候选

相关阅读

· 18 分钟

F-Pro 四阶段跨域污染防御:从 0.60 → 0.80 的完整复盘

法律赛道 MRR 0.60 → 0.80(+33%)。F-Pro 不是一个算法,是 4 个阶段叠加的防御:domain 字段 + chunk 前缀 + 跨域惩罚 + 关键词意图识别。零 LLM 调用,10ms 内出结果。本文复盘了 5 轮调参 sweep,包括为什么 penalty=0.4 而不是 0.2 或 0.6,以及一个意外发现:Rust 赛道 MRR 顺带从 0.87 → 1.00。

阅读全文 →
· 12 分钟

Attune 设计哲学:为什么我们不做又一个云端 AI SaaS

过去三年我们看过 20+ 款 "AI 知识库" 产品,全部走相同范式:上传文档到云端 → 服务端 chunk + embed → 云端 LLM。Attune 选择反向:本地 vault + AES-256-GCM 字段加密 + 显式出网 + 12 类 PII 自动脱敏。代价是工程复杂度 3 倍,回报是"原文不出网"成为可证明的事实而非空头承诺。

阅读全文 →