RAG实战-Embedding模型(BGE)

RAG实战-Embedding模型(BGE)

  • [为什么 RAG 需要 Embedding 模型?](#为什么 RAG 需要 Embedding 模型?)
  • 1 RAG两阶段检索:Embedding召回 + Rerank精排 #embeddingrerank
      • [1.1 Bi-Encoder(Embedding召回模型)](#1.1 Bi-Encoder(Embedding召回模型))
      • [1.2 Cross-Encoder(Rerank精排模型)](#1.2 Cross-Encoder(Rerank精排模型))
    • [2 对称任务 vs 非对称任务(BGE指令机制的根源)](#2 对称任务 vs 非对称任务(BGE指令机制的根源))
      • [2.1 对称任务 Symmetric Tasks](#2.1 对称任务 Symmetric Tasks)
      • [2.2 非对称任务 Asymmetric Tasks(检索任务属于此类)](#2.2 非对称任务 Asymmetric Tasks(检索任务属于此类))
    • [3 Embedding基础概念与分类](#3 Embedding基础概念与分类)
      • [3.1 什么是文本Embedding](#3.1 什么是文本Embedding)
      • [3.2 Embedding三种类型](#3.2 Embedding三种类型)
    • [4 Embedding评测体系 MTEB / C-MTEB](#4 Embedding评测体系 MTEB / C-MTEB)
      • [4.1 MTEB(Massive Text Embedding Benchmark)](#4.1 MTEB(Massive Text Embedding Benchmark))
      • [4.2 C-MTEB](#4.2 C-MTEB)
      • [4.3 Scifact数据集(MTEB检索任务示例)](#4.3 Scifact数据集(MTEB检索任务示例))
    • [5 BGE v1.5核心原理(重点面试)](#5 BGE v1.5核心原理(重点面试))
      • [5.1 BGE v1.5 官方指令(只给Query!文档绝对不加)](#5.1 BGE v1.5 官方指令(只给Query!文档绝对不加))
      • [5.2 BGE 核心本质](#5.2 BGE 核心本质)
      • [5.3 为什么 BGE 要区分「带指令 / 不带指令」](#5.3 为什么 BGE 要区分「带指令 / 不带指令」)
      • [5.4 向量空间三种情况对比](#5.4 向量空间三种情况对比)
      • [5.5 输入输出向量规则](#5.5 输入输出向量规则)
      • [5.6 工程标准函数封装(RAG 通用规范)](#5.6 工程标准函数封装(RAG 通用规范))
    • [6 BGE-M3三合一模型(BAAI)](#6 BGE-M3三合一模型(BAAI))
    • [7 完整工程链路:Embedding召回 → Top-K → Rerank精排](#7 完整工程链路:Embedding召回 → Top-K → Rerank精排)
    • [8 BGE-M3与Milvus向量库集成](#8 BGE-M3与Milvus向量库集成)
    • [9 总结](#9 总结)
    • 可直接运行代码片段汇总
      • [1. MTEB评测](#1. MTEB评测)
      • [2. BGE v1.5 编码封装](#2. BGE v1.5 编码封装)
      • [3. BGE-M3 编码](#3. BGE-M3 编码)
      • [4. Milvus 集成](#4. Milvus 集成)

为什么 RAG 需要 Embedding 模型?

想象这样一个场景:你是一家企业的知识库管理员,库里躺着几十万份技术文档、产品手册和售后记录。用户抛来一句口语化的问题------"上次那个接口超时的问题最后怎么解决的?"------你需要在几秒内从海量文档里捞出最相关的那几段,交给大模型组织成答案。

如果让大模型逐篇读完所有文档再回答,成本和时间都不可接受;如果只靠关键词匹配,又会被"超时""接口"这类同义表达卡住,漏掉真正有用的内容。这正是 RAG(检索增强生成)要解决的问题,而它的第一步,就是用 Embedding 模型把文本变成向量,让"语义相近"变成"向量距离近",从而在百万级文档中快速完成召回。

本文围绕 BGE 系列模型展开,从两阶段检索流水线讲起,逐步拆解 BGE v1.5 的指令机制、BGE-M3 的三合一能力,以及它们如何与 Milvus 等向量库集成,最终串成一条可直接落地的 RAG 工程链路。无论你是准备面试,还是正在搭建生产级检索系统,这份实战笔记都值得从头读一遍。

1 RAG两阶段检索:Embedding召回 + Rerank精排 #embeddingrerank

RAG系统不会直接把全部文档送入大模型,采用先粗召回,后精细排序两阶段流水线,平衡速度与精度。

阶段 模型类型 核心目标 特点
第一阶段:召回Retrieval Embedding(Bi-Encoder双塔) 从十万/百万级文档库快速筛选Top-K候选文档 优先速度,牺牲部分精度;文档向量可以离线预先计算存入向量数据库
第二阶段:精排Rerank Cross-Encoder重排器 对少量候选文档做细粒度相关性打分,重新调整顺序 优先精度 ,计算开销大;不能直接跑全量文档,仅用于召回输出的小候选集

1.1 Bi-Encoder(Embedding召回模型)

概念:双塔模型,逻辑上分为Query塔、Document塔。

⚠️重点:BGE v1.5底层并不是两套独立网络,是单套权重,靠输入指令区分两种输入;DPR才是真正双权重双塔。

  • Query塔:把用户问题文本映射向量 V q V_q Vq
  • Document塔:把知识库段落映射向量 V d V_d Vd
  • 工程流程:
    1)知识库全部文档提前离线编码,向量存入Milvus、FAISS等向量库;
    2)用户提问到来,只编码Query得到向量;
    3)向量库做ANN近似最近邻搜索,计算余弦/点积相似度,返回相似度最高的Top-K文档。
  • 优点:文档可预计算,在线服务推理开销极小,支持百万级文档库。

1.2 Cross-Encoder(Rerank精排模型)

只有一个编码器,输入是拼接后的Query+Document句子对 ,格式:[CLS] Query [SEP] Document [SEP]

  1. Query和文档的每一个token互相做Attention交互,模型看得见词与词之间细粒度匹配关系;
  2. 最后使用[CLS]位置输出得到一个标量,代表这一组query-doc的相关性;
  3. 每一个候选文档都需要独立跑一次前向传播。
  • ✅优点:理解细粒度语义、指代、转折,相关性判断精度远高于Bi-Encoder;
  • ❌缺点:速度慢。例如召回100条候选,就要跑100次模型推理;绝对不能直接对百万知识库全量跑Rerank。

2 对称任务 vs 非对称任务(BGE指令机制的根源)

2.1 对称任务 Symmetric Tasks

两个文本地位完全平等,可以互换,相似度(A,B) = 相似度(B,A)。

  • 典型场景:文本聚类、信息去重、同义问句判断;
  • 输入特点:两段文本长度、句式风格接近;
  • BGE使用规则:不需要加任何指令前缀。

2.2 非对称任务 Asymmetric Tasks(检索任务属于此类)

Query和Document本身文本分布差异巨大:

  • Query:简短问句、口语化、疑问句式、意图明确;
  • Document:长陈述句、书面知识段落、大段上下文。

向量域偏移 :如果不加任何指令,同一个模型直接编码两种不同风格文本,会把语义相关的query和doc映射到向量空间不同子区域;明明语义匹配,但计算余弦距离很大,发生漏召回。
BGE解决方案:不训练两套网络,在Query文本前面拼接固定指令前缀,触发模型切换编码行为,把Query编码到和文档对齐的向量子空间,实现单权重完成非对称检索任务。
对比DPR:DPR采用真正两套独立权重的双塔,参数、显存翻倍,训练成本高;BGE单权重+指令,部署成本更低。

3 Embedding基础概念与分类

3.1 什么是文本Embedding

将离散的文本(字符串)映射为连续的低维数值向量。

  • 核心性质1 语义保距:语义越接近的文本,向量在高维空间距离越近;语义无关距离更远。
  • 核心性质2 维度权衡 :
    • 高维度(1024):表征能力更强,占用显存、存储更大;
    • 低维度(384/512):速度快、省内存,复杂语义表达能力会下降。

3.2 Embedding三种类型

  1. 传统词嵌入(统计):基于词频TF-IDF、BM25;无上下文语义理解,只做关键词匹配。
  2. 静态词向量(Word2Vec/GloVe) :一个词固定唯一向量;无法处理一词多义,同一个词在不同句子输出向量完全一样。
  3. 动态上下文嵌入(Transformer,BGE属于此类):根据上下文动态生成向量;相同词语不同语境输出不同向量;RAG主流选择。

BGE系列:基于XLM-Roberta架构;BGE-M3最大支持8192 token输入长度,支持长文档处理。

4 Embedding评测体系 MTEB / C-MTEB

4.1 MTEB(Massive Text Embedding Benchmark)

业界通用大规模嵌入评测基准,覆盖8大类任务:Retrieval检索、STS语义相似度、分类、聚类、重排等;支持上百种语言;提供可复现代码、公开排行榜。

4.2 C-MTEB

MTEB中文专项子集;专门面向中文语料评测。

✅RAG选型优先级指标:

  1. Retrieval任务 nDCG@10(最重要):衡量检索召回质量;
  2. STS分数(辅助):衡量语义辨别能力。

4.3 Scifact数据集(MTEB检索任务示例)

scifact是科学事实检索数据集,用于验证模型从论文摘要库检索支持/反驳科学论断的证据文档。

MTEB所有检索数据集统一三件套格式:

  1. Corpus文档库 :_id、title、text;待检索全部文档;
  2. Queries查询集 :_id、text;代表用户查询/科学论断;
  3. Qrels相关性标注 :query-id、corpus-id、score;score=1代表这条文档对该查询是相关证据。

评测逻辑:输入query,模型召回文档列表,对比qrels人工标注,计算nDCG、Recall指标。

运行评测最简代码

python 复制代码
import mteb
task = mteb.get_tasks(["SciFact"])
evaluator = mteb.MTEB(task)
model = mteb.get_model("BAAI/bge-base-zh-v1.5")
evaluator.run(model)

5 BGE v1.5核心原理(重点面试)

5.1 BGE v1.5 官方指令(只给Query!文档绝对不加)

中文Query指令:

text 复制代码
为这个句子生成表示以用于检索相关文章:

英文Query指令:

text 复制代码
Represent this sentence for searching relevant passages:

关键规则:

  1. 检索任务:Query拼接指令,知识库Chunk直接裸文本输入;
  2. 聚类、STS相似度任务:全部文本不加指令;
  3. 不要自己改写指令字符串,模型只见过训练时固定前缀;
  4. v1.5可以不带指令跑通,但短问句场景召回指标显著下降。

5.2 BGE 核心本质

  1. BGE 是单编码器共享权重的检索嵌入模型(区别于 DPR 双塔双编码器)。
  2. 专门为非对称检索任务训练:短问句(Query)匹配长文档(Passage/Corpus)。
  3. 核心特性:同一个模型、同一套权重,通过输入指令前缀切换编码行为,无需两套网络。
  4. 适用场景:RAG 检索、文本相似度匹配;不适用场景无特殊限制,但非检索任务不需要指令。

5.3 为什么 BGE 要区分「带指令 / 不带指令」

根本原因:检索是不对称任务。

  • Query:短、问句、口语化、疑问句式
  • Passage:长、陈述句、书面化、知识片段

两者文本分布天然不同,直接编码会出现向量域偏移:语义相关但向量距离很远,导致漏召回。

指令的真实作用(极简大白话):

指令 = 向量空间坐标转换器

  • Query 加指令:告诉模型「当前是检索提问,请编码到 Query 向量子空间」
  • Passage 不加指令:模型默认编码到 Passage 向量子空间

最终让两个不同分布的文本,向量空间可精准匹配、计算相似度有效。

为什么不用「两个独立函数 / 双编码器」?

  • 双编码器(DPR 方案)效果好,但参数翻倍、显存翻倍、训练推理成本极高
  • BGE 采用单权重 + 指令触发,参数复用、轻量化、部署简单,是性价比最优方案
  • 注意:工程层可以封装两个函数,但模型底层仍是同一套权重,不是真双塔

5.4 向量空间三种情况对比

使用方式 结果 现象
✅正确:Query+指令,文档无指令 向量子空间对齐 相似度计算有效,召回最优
⚠️错误:全部文本不加指令 query-doc分布偏移 大量相关文档距离拉大,漏召回,Recall下降
❌致命错误:文档也拼接指令 两边同时偏移,匹配规则完全破坏 检索结果完全不可用,性能毁灭性下跌

5.5 输入输出向量规则

  1. 输入单字符串:输出一维数组 (768,),一个向量;
  2. 输入字符串list:输出二维数组 (N,768);每条文本独立向量,不会把多条文本融合合并为一个向量;批量只是并行加速;
  3. normalize_embeddings=True:开启L2归一化;归一化之后余弦相似度等价向量点积;向量库检索必须开启该参数。

注意:encode_queries()、encode_corpus() 不是库原生函数,属于工程封装,底层调用同一个model.encode,底层模型权重没有两套。

5.6 工程标准函数封装(RAG 通用规范)

python 复制代码
from sentence_transformers import SentenceTransformer

model = SentenceTransformer('BAAI/bge-base-zh-v1.5')
QUERY_INS = "为这个句子生成表示以用于检索相关文章:"

# 批量编码提问(加指令)
def encode_queries(queries: list[str]):
    return model.encode([QUERY_INS + q for q in queries], normalize_embeddings=True)

# 批量编码知识库文档(无指令)
def encode_corpus(corpus: list[str]):
    return model.encode(corpus, normalize_embeddings=True)

6 BGE-M3三合一模型(BAAI)

BGE-M3不再需要Query指令前缀!和v1.5重要区别。

三大能力集成到同一个权重:Dense密集检索 + Sparse稀疏词法检索 + ColBERT多向量细粒度检索。

三种检索模式

  1. Dense密集向量检索

    输出单个1024维稠密向量;依靠整体语义做匹配;擅长同义词、转述、深层语义;缺点:容易遗忘特殊关键词。

  2. Sparse稀疏检索(Lexical词法)

    输出token权重稀疏向量,类似BM25;重点捕捉关键词、专有名词、型号;解决dense"关键词遗忘";大部分维度为0。

  3. ColBERT多向量检索(Multi-vector)

    每一个token输出独立向量矩阵;查询token和文档所有token做late-interaction晚交互匹配;匹配粒度最细,效果最好,存储、计算开销最高。

工程常用Hybrid混合检索 :hybrid_score = w1*dense_score + w2*sparse_score;同时利用语义能力+关键词能力;Milvus、Vespa原生支持BGE-M3混合检索。
模型规格:维度1024,最大序列长度8192,支持100+语言;

依赖库:pip install -U FlagEmbedding。

BGE-M3编码示例

python 复制代码
from FlagEmbedding import BGEM3FlagModel

model = BGEM3FlagModel('BAAI/bge-m3', use_fp16=True)
sentences = ["什么是BGE-M3"]
out = model.encode(sentences, return_dense=True, return_sparse=True, return_colbert_vecs=False)
# out["dense_vecs"] 稠密向量
# out["lexical_weights"] 稀疏token权重

7 完整工程链路:Embedding召回 → Top-K → Rerank精排

完整RAG链路流程:

  1. 使用BGE-M3对Query、知识库文档编码,得到dense、sparse向量;
  2. 计算dense得分、sparse得分,加权得到hybrid混合得分,排序召回候选集;
  3. 截取召回结果Top-K(例如k=3~10,不能太大);
  4. 构造[query,doc]句子对送入FlagReranker;
  5. Reranker输出logits,sigmoid映射0-1相关性分数;
  6. 使用rerank分数重新排序,输出最终结果给LLM。

关键点:Reranker只做重排,不做召回。

8 BGE-M3与Milvus向量库集成

milvus_model封装好BGEM3EmbeddingFunction,可以直接输出dense/sparse向量,适配Milvus混合检索。

python 复制代码
from milvus_model.hybrid import BGEM3EmbeddingFunction

model_path = "./bge-m3"
embedding_func = BGEM3EmbeddingFunction(model_name=model_path, device="cpu", use_fp16=False)
texts = ["测试文本"]
emb = embedding_func.encode_documents(texts)
dense_vec = emb["dense"]
sparse_vec = emb["sparse"]

9 总结

  1. BGE-v1.5:单编码器共享权重 + Query指令前缀,解决非对称检索query-doc向量域偏移;指令只给查询,文档不加。
  2. BGE-M3一体化模型,支持Dense / Sparse / ColBERT三种检索,不再需要指令,适合混合检索RAG。
  3. RAG标准流水线:Embedding(Bi-Encoder)快速召回候选 → Rerank(Cross-Encoder)做少量候选精排,兼顾速度与精度。
  4. 评测看MTEB/C-MTEB,RAG优先看Retrieval任务nDCG@10指标。

一句话极简总结

BGE 依靠单模型权重共享 + Query 指令前缀触发向量空间切换,解决问答与文档的非对称匹配问题;工程上封装为 encode_queries、encode_corpus 区分场景,批量输入生成多条独立向量,是 RAG 检索的标准嵌入方案。


可直接运行代码片段汇总

1. MTEB评测

python 复制代码
import mteb
task = mteb.get_tasks(["SciFact"])
evaluator = mteb.MTEB(task)
model = mteb.get_model("BAAI/bge-base-zh-v1.5")
evaluator.run(model)

2. BGE v1.5 编码封装

python 复制代码
from sentence_transformers import SentenceTransformer

model = SentenceTransformer('BAAI/bge-base-zh-v1.5')
QUERY_INS = "为这个句子生成表示以用于检索相关文章:"

def encode_queries(queries: list[str]):
    return model.encode([QUERY_INS + q for q in queries], normalize_embeddings=True)

def encode_corpus(corpus: list[str]):
    return model.encode(corpus, normalize_embeddings=True)

3. BGE-M3 编码

python 复制代码
from FlagEmbedding import BGEM3FlagModel

model = BGEM3FlagModel('BAAI/bge-m3', use_fp16=True)
sentences = ["什么是BGE-M3"]
out = model.encode(sentences, return_dense=True, return_sparse=True, return_colbert_vecs=False)
# out["dense_vecs"] 稠密向量
# out["lexical_weights"] 稀疏token权重

4. Milvus 集成

python 复制代码
from milvus_model.hybrid import BGEM3EmbeddingFunction

model_path = "./bge-m3"
embedding_func = BGEM3EmbeddingFunction(model_name=model_path, device="cpu", use_fp16=False)
texts = ["测试文本"]
emb = embedding_func.encode_documents(texts)
dense_vec = emb["dense"]
sparse_vec = emb["sparse"]
相关推荐
李游Leo1 小时前
HarmonyOS 7 + ArkTS + Image Kit 学习笔记:图像超分处理链路与 PixelMap 数据流实践【鸿蒙心迹】
笔记·学习·harmonyos
驭渊的小故事1 小时前
牛客网算法刷题笔记:哈希表、贪心与动态规划实战
笔记·算法·散列表
田园诗人之园2 小时前
一文搞懂 Token化、Embedding 与位置编码
embedding·位置编码·深度学习token
李游Leo2 小时前
HarmonyOS 7 + ArkTS + NAPI 学习笔记:Native 模块桥接、CMake 构建与跨语言调用实践【鸿蒙心迹】
笔记·学习·harmonyos
像风一样自由20202 小时前
42.VueReactNextjs如何为AI应用设计前端交互
前端·人工智能·大模型·交互·rag·智能体
索端阳3 小时前
I.MX6ULL 裸机开发:LCD Framebuffer 与 RGB888 学习笔记
笔记·vscode·嵌入式硬件·学习
一个低调的青年3 小时前
电池健康状态估计(一)
经验分享·笔记·其他·算法·模型
影寂ldy3 小时前
C# TCP转串口Modbus网关终极完整版笔记(队列防抖+一问一答+帧解析+双客户端轮询)
笔记·tcp/ip·c#
像风一样自由202012 小时前
41.用FastAPI搭建一个RAG后端需要哪些接口
人工智能·大模型·fastapi·rag·智能体