FlagEmbedding 推理 Embedder API 全解析:BaseEmbedder、M3Embedder、BaseLLMEmbedder 与 ICLLLMEmbedder 的架构、参数与实战
【免费下载链接】FlagEmbeddingRetrieval and Retrieval-augmented LLMs项目地址: https://gitcode.com/GitHub_Trending/fl/FlagEmbedding
本篇技术指南聚焦 FlagEmbedding 的推理侧(inference)Embedder API,系统讲解仓库 API 文档(docs/source/API/inference/embedder/embedder.rst)所覆盖的四类嵌入模型封装类:面向编码器架构的BaseEmbedder、面向 BGE-M3 多模态检索的M3Embedder、面向解码器 LLM 的BaseLLMEmbedder,以及支持上下文学习(In-Context Learning)的ICLLLMEmbedder。读完本文,你将掌握每个类的构造参数含义与默认值、encode_queries/encode_corpus/encode等核心方法的调用约定、底层 pooling 与多设备推理的实现原理,并能直接照搬到自己的检索与 RAG 项目中。
一、文档结构与四类 Embedder 的总览
embedder.rst本身是一个 Sphinx toctree 索引页,它挂载了四个子 API 页面,分别对应四个推理类:
| 子文档 | 对应类 | 适用模型架构 | 代表模型 |
|---|---|---|---|
| encoder_only/BaseEmbedder.rst | FlagEmbedding.inference.embedder.encoder_only.base.BaseEmbedder | 编码器(Encoder-only,BERT 类) | BGE v1/v1.5 系列、e5、gte 等 |
| encoder_only/M3Embedder.rst | FlagEmbedding.inference.embedder.encoder_only.m3.M3Embedder | 编码器(多向量/稀疏/稠密混合) | BGE-M3 |
| decoder_only/BaseLLMEmbedder.rst | FlagEmbedding.inference.embedder.decoder_only.base.BaseLLMEmbedder | 解码器(Decoder-only,LLM) | bge-reasoner、Qwen3-Embedding、SFR-Embedding 等 |
| decoder_only/ICLLLMEmbedder.rst | FlagEmbedding.inference.embedder.decoder_only.icl.ICLLLMEmbedder | 解码器(上下文学习) | BGE-EN-ICL |
在代码层面,这四个类分别定义在 FlagEmbedding/inference/embedder/encoder_only/base.py、m3.py、decoder_only/base.py 与 decoder_only/icl.py,并统一从FlagEmbedding/inference/embedder/__init__.py导出为FlagModel、BGEM3FlagModel、FlagLLMModel、FlagICLModel等用户友好的别名。四者都继承自抽象基类AbsEmbedder(见 FlagEmbedding/abc/inference/AbsEmbedder.py),因此共享一套"查询/语料/通用编码"接口约定,差异集中在 pooling 方式与多模态输出上。
二、共同架构:抽象基类 AbsEmbedder 与统一编码流程
所有 Embedder 的骨架由AbsEmbedder定义(FlagEmbedding/abc/inference/AbsEmbedder.py),其 docstring 明确说明:扩展该类并实现encode_queries、encode_corpus、encode三个方法即可自定义 Embedder。
2.1 统一的三入口设计
encode_queries(queries, ...):编码查询。内部以self.query_max_length为默认长度上限,并自动拼接检索指令query_instruction_for_retrieval(见 AbsEmbedder.py 的encode_queries实现)。encode_corpus(corpus, ...):编码语料/文档。以self.passage_max_length为默认长度上限,并支持通过 kwargs 传入passage_instruction_for_retrieval/passage_instruction_format为语料附加独立的指令(默认"{}{}")。encode(sentences, ...):通用编码入口,最终依据设备数量决定走单设备路径encode_single_device还是多进程池路径encode_multi_process。
三者均支持输入单个字符串(str)或字符串列表(List[str]),返回值可以是numpy.ndarray或torch.Tensor,由convert_to_numpy控制(默认True,返回 numpy 数组)。
2.2 指令拼接机制
get_detailed_instruct(instruction_format, instruction, sentence)(AbsEmbedder.py 第 157-170 行)按模板把指令与句子组合:
def get_detailed_instruct(instruction_format: str, instruction: str, sentence: str): if "\\n" in instruction_format: instruction_format = instruction_format.replace("\\n", "\n") return instruction_format.format(instruction, sentence)例如query_instruction_format="Instruct: {}\nQuery: {}"会把"检索指令 + 查询文本"拼成Instruct: <指令>\nQuery: <查询>。注意源码会对字面量\n做一次显式替换,因此既支持在 Python 字符串中写真实换行,也支持写\n转义序列。
2.3 设备自动探测与多进程并行
get_target_devices(devices)(AbsEmbedder.py 第 110-154 行)是一套完整的设备解析逻辑:
devices=None时按优先级自动探测:CUDA(全部可用卡cuda:0...N)→ NPU(npu:0...N)→ MUSA(musa:0...N)→ MPS(Apple Silicon)→ 兜底cpu;- 传入
str如"cuda:0"、int如0、字符串列表或整数列表均可; - 当检测到多张卡且输入为批量列表时,
encode会通过start_multi_process_pool启动每卡一个进程的 worker 池,配合encode_multi_process分块分发、_concatenate_results_from_multi_process合并结果;对象析构时由__del__调用stop_self_pool清理进程与显存。
2.4 通用后处理钩子
_convert_to_numpy:在 bf16 推理且非 CPU 设备上,先将bfloat16张量升为float32再转 numpy(NumPy 不支持 bfloat16);_truncate_embeddings:配合 Matryoshka 表示学习模型,当truncate_dim不为None时截取前truncate_dim维,例如把 4096 维向量截到 1024 维使用。
三、BaseEmbedder:编码器模型的通用推理封装
3.1 构造参数速查
BaseEmbedder(encoder_only/base.py)用于加载任意 HuggingFace 编码器模型(AutoModel),核心参数与默认值如下:
| 参数 | 默认值 | 说明 |
|---|---|---|
model_name_or_path | 必填 | 本地模型路径,或 HuggingFace Hub 上的模型名 |
normalize_embeddings | True | 是否对输出向量做 L2 归一化 |
use_fp16 | True | 半精度推理加速(轻微精度损失) |
use_bf16 | False | 使用 bfloat16;优先于 fp16 |
query_instruction_for_retrieval | None | 检索任务查询指令文本 |
query_instruction_format | "{}{}" | 指令拼接模板 |
devices | None | 推理设备,见上文设备探测逻辑 |
pooling_method | "cls" | 池化方式:cls或mean |
trust_remote_code | False | 是否信任远端模型自定义代码 |
cache_dir | None | 模型缓存目录 |
batch_size | 256 | 推理批大小 |
query_max_length | 512 | 查询最大 token 长度 |
passage_max_length | 512 | 语料最大 token 长度 |
convert_to_numpy | True | 输出 numpy 数组而非张量 |
truncate_dim | None | Matryoshka 截断维度 |
构造时使用AutoTokenizer.from_pretrained与AutoModel.from_pretrained加载模型,并按get_model_torch_dtype(bf16 > fp16 > fp32)设置精度。
3.2 池化方法实现
pooling(last_hidden_state, attention_mask)(第 284-308 行)支持两种方法:
cls:直接取last_hidden_state[:, 0],即[CLS]token 的隐状态;mean:按 attention mask 对非 padding 位置的隐状态做加权平均:s / d,其中s是掩码加权和、d是有效 token 数;- 其他值抛出
NotImplementedError。
3.3 单设备编码流水线(encode_single_device)
encode_single_device(第 174-282 行)是理解整个库推理性能设计的关键,流程如下:
- 单条字符串输入会先包成列表并在返回时还原(
input_was_string标记); - 预分词:先不带 padding 分词,记录每条输入的真实长度;
- 按长度降序排序(
np.argsort),将长度相近的样本分到同一 batch,最大限度减少 padding 浪费; - batch size 自适应:用"试跑一个 batch"的方式探测显存,捕获
RuntimeError或torch.cuda.OutOfMemoryError时把batch_size乘以3/4缩小重试; - 正式推理:forward 取
last_hidden_state→pooling→_truncate_embeddings→ 按需 L2 归一化 → 按需转 numpy; - 按
length_sorted_idx的逆序还原样本顺序后返回。
这套"预排序 + 自适应 batch"的设计在长尾长度的真实语料上能显著提升吞吐,是仓库在大量推理场景中推荐的默认实现。
四、M3Embedder:BGE-M3 的稠密 + 稀疏 + 多向量混合检索
M3Embedder(encoder_only/m3.py)专为 BGE-M3 设计,在BaseEmbedder基础上新增了**稀疏词权重(lexical weights)与ColBERT 多向量(colbert vecs)**两种输出,覆盖稠密检索、稀疏检索、多向量重排三类能力。
4.1 独有构造参数
除BaseEmbedder的通用参数外,还包含:
| 参数 | 默认值 | 说明 |
|---|---|---|
colbert_dim | -1 | ColBERT 线性投影维度,-1表示使用模型 hidden_size |
return_dense | True | 是否返回稠密向量 |
return_sparse | False | 是否返回稀疏词权重字典 |
return_colbert_vecs | False | 是否返回 ColBERT 多向量 |
模型加载走专门的EncoderOnlyEmbedderM3ModelForInference包装类(来自FlagEmbedding.finetune.embedder.encoder_only.m3),内部负责把 tokenizer、池化与归一化装配在一起。
4.2 encode_* 方法的字典返回值
encode_queries/encode_corpus/encode的返回类型统一为字典:
Dict[Literal["dense_vecs", "lexical_weights", "colbert_vecs"], Union[np.ndarray, List[Dict[str, float]], List[np.ndarray]]]dense_vecs:归一化后的稠密向量(np.ndarray);lexical_weights:每个样本一个{token_id: weight}字典(token_id 为字符串形式),已剔除 cls/eos/pad/unk 等特殊 token,且同 token 取最大权重(见_process_token_weights);colbert_vecs:去掉 padding 与[CLS]后的逐 token 向量列表。
三个方法的默认长度/开关回退规则各不相同:encode_queries用query_max_length,encode_corpus与encode用passage_max_length;若调用时未显式传return_dense/sparse/colbert_vecs,则回退到构造时的对应开关。
4.3 词级与向量级辅助方法
convert_id_to_token(lexical_weights):把{token_id: weight}字典转换为{token: weight},方便直接阅读或对接 BM25 类检索器;compute_lexical_matching_score(lw1, lw2):按共享 token 的权重乘积求和计算稀疏匹配分数,支持"单对单返回 float、批量对返回np.ndarray"两种形态;colbert_score(q_reps, p_reps):用torch.einsum('in,jn->ij')计算查询-文档 token 相似度矩阵,取每行最大值(MaxSim)后求均值,得到 ColBERT 风格的交互分数。
4.4 混合打分:compute_score 系列
compute_score(sentence_pairs, batch_size, max_query_length, max_passage_length, weights_for_different_modes)(第 488-538 行)直接对(query, passage)对打分,返回五档分数:
Dict[Literal["colbert", "sparse", "dense", "sparse+dense", "colbert+sparse+dense"], List[float]]- 单卡时直接走
compute_score_single_device; - 多卡时启动
M3Embedder._compute_score_multi_process_worker进程池,用compute_score_multi_process分块并汇总; weights_for_different_modes是稠密、稀疏、ColBERT 三者的权重列表(长度必须为 3),默认[1.0, 1.0, 1.0],即等权融合;sparse+dense与colbert+sparse+dense分别按权重做加权平均。这在 hybrid 检索评测(如仓库research/C_MTEB、evaluation下的多个 benchmark)中是直接可复用的打分 API。
五、BaseLLMEmbedder:解码器 LLM 的嵌入封装
5.1 与编码器版本的关键差异
BaseLLMEmbedder(decoder_only/base.py)面向 LLM 类嵌入模型,与BaseEmbedder的差异集中在三点:
- 默认指令模板不同:
query_instruction_format默认值从"{}{}"变为"Instruct: {}\nQuery: {}",适配 E5、SFR、bge-reasoner 等指令式 LLM 嵌入模型; - 池化方式强制为 last_token:构造时校验
kwargs.get("pooling_method", "last_token"),一旦传入非last_token立即抛ValueError("Pooling method must be 'last_token' for LLM-based models."); - 池化函数不同:使用模块级函数
last_token_pool(第 12-29 行)——先判断是否为左 padding(attention_mask[:, -1].sum() == batch 行数),是则取最后一个位置last_hidden_states[:, -1],否则按每行有效 token 数定位最后一个真实 token 并取对应隐状态,从而兼容padding=True的 batch 推理。
5.2 编码流水线
encode_single_device与BaseEmbedder的结构一致(预分词 → 长度排序 → 自适应 batch → last_token 池化 → 归一化 → 输出),并在参数注释中提示:对于 bge-multilingual-gemma2 等模型可在 kwargs 中传pad_to_multiple_of=8。由于 LLM 序列较长,实际使用中建议配合batch_size与max_length的调优来控制显存占用。
六、ICLLLMEmbedder:带示例注入的上下文学习嵌入
ICLLLMEmbedder(decoder_only/icl.py)面向 BGE-EN-ICL 这类通过 few-shot 示例增强检索的模型:把"指令 + 示例 + 查询"组装成模型特有的模板再编码,使模型针对当前任务自适应。
6.1 独有参数
| 参数 | 默认值 | 说明 |
|---|---|---|
query_instruction_format | "<instruct>{}\n<query>{}" | 查询指令模板(构造时自动把\n字面量转为真实换行) |
suffix | '\n<response>' | 查询后追加的后缀 token 序列 |
examples_for_task | None | few-shot 示例列表,元素为含instruct/query/response键的字典 |
examples_instruction_format | "<instruct>{}\n<query>{}\n<response>{}" | 单个示例的组装模板 |
6.2 示例管理与前缀组装
set_examples(examples_for_task=None)(第 133-165 行):把示例按examples_instruction_format展开后以'\n\n'连接,末尾再补'\n\n'作为self.prefix;未提供任何示例时prefix为空串;get_detailed_example(instruction_format, instruction, query, response)(第 167-182 行):静态方法,负责单条示例的模板拼接;- 构造完成后立即调用
self.set_examples(),把构造参数中的examples_for_task固化为前缀。
6.3 带前缀的查询编码
encode_queries_single_device(第 322-457 行)是 ICL 模式的核心,处理链条为:
- 用
query_instruction_format拼接检索指令与查询文本; - 将
self.prefix与self.suffix分词后,重新计算有效最大长度:new_max_length = (len(prefix_ids) + len(suffix_ids) + max_length + 8) // 8 * 8 + 8(8 对齐,兼顾部分模型对序列长度的对齐要求); - 预分词阶段把每条文本重写为
prefix + 截断后的查询 + suffix; - 之后的长度排序、自适应 batch、last_token 池化、归一化与
BaseLLMEmbedder一致。
此外,ICL 类为查询单独维护了一个query_pool(与语料编码的pool分离),并在encode_corpus前调用stop_self_query_pool释放查询侧的多进程资源,避免两套进程池互相干扰。
七、从 API 到自动装配:模型映射与统一入口
尽管embedder.rst只列出四个类,但仓库在 FlagEmbedding/inference/embedder/model_mapping.py 中为它们建立了完整的模型名 → 类 + 池化方式 + 指令模板映射表:
EmbedderModelClass枚举了encoder-only-base、encoder-only-m3、decoder-only-base、decoder-only-icl、decoder-only-pseudo_moe五种类型;BGE_MAPPING把bge-m3→BGEM3FlagModel(cls)、bge-en-icl→FlagICLModel(last_token, "<instruct>{}\n<query>{}")、bge-large-en-v1.5等 →FlagModel(cls)、bge-reasoner-embed-qwen3-8b-0923→FlagLLMModel("Instruct: {}\nQuery: {}");- 此外还有
QWEN3_EMBEDDING_MAPPING、E5_MAPPING、GTE_MAPPING、SFR_MAPPING、LINQ_MAPPING、BCE_MAPPING,最终合并为AUTO_EMBEDDER_MAPPING,由support_model_list()列出全部支持模型名。
这意味着在实际项目中,多数情况下无需手动实例化上述四个类,直接使用统一入口FlagAutoModel(FlagEmbedding/inference/auto_embedder.py)即可按模型名自动匹配正确的类、池化方式与指令模板;需要精细控制时再回到这四个类手工配置。
八、典型使用示例与工程建议
以下示例演示如何直接使用四类 API(均为仓库真实支持的调用形态,仓库另附多份可运行的完整示例脚本,见 examples/inference/embedder/encoder_only 与 examples/inference/embedder/decoder_only):
from FlagEmbedding import FlagModel, BGEM3FlagModel, FlagLLMModel, FlagICLModel # 1) 编码器模型(BGE v1.5 系列等),cls 池化 model = FlagModel("bge-large-en-v1.5", query_instruction_for_retrieval="Represent this sentence for searching relevant passages:", use_fp16=True) q_emb = model.encode_queries(["how to use FlagEmbedding?"]) c_emb = model.encode_corpus(["FlagEmbedding is a library for retrieval.", "..."]) # 2) BGE-M3 混合输出:稠密 + 稀疏 + 多向量 m3 = BGEM3FlagModel("bge-m3", use_fp16=True, return_dense=True, return_sparse=True, return_colbert_vecs=True) out = m3.encode_queries(["query text"]) dense, lexical, colbert = out["dense_vecs"], out["lexical_weights"], out["colbert_vecs"] # 词 id 转回 token、并直接算稀疏匹配分 lexical_tokens = m3.convert_id_to_token(lexical) scores = m3.compute_lexical_matching_score(lexical, lexical) # 或直接对 (query, passage) 混合打分 hybrid = m3.compute_score([("q1", "p1")], weights_for_different_modes=[1., 1., 1.]) # 3) LLM 嵌入模型(last_token 池化,指令模板自动拼接) llm = FlagLLMModel("bge-reasoner-embed-qwen3-8b-0923", query_max_length=8192, batch_size=16) q_emb = llm.encode_queries(["query text"]) # 4) ICL 上下文学习:注入 few-shot 示例 icl = FlagICLModel("bge-en-icl", examples_for_task=[ {"instruct": "Given a web search query, retrieve relevant passages...", "query": "example query", "response": "example passage"} ]) q_emb = icl.encode_queries(["real query"])工程使用建议:
- 显存优先:LLM 类(
BaseLLMEmbedder/ICLLLMEmbedder)建议调小batch_size并配合use_bf16=True;超大语料可先encode_corpus批量建索引,再encode_queries在线检索; - 多卡扩展:传入
devices=["cuda:0", "cuda:1"]即可自动走多进程池并行,注意每卡一个进程是推荐配置; - 检索评估:
M3Embedder.compute_score可直接用于 hybrid 检索的分数融合验证,仓库的 evaluation 与 research/C_MTEB 目录提供了 MSMARCO、BEIR、MIRACL、MLDR 等基准的完整评测配套; - 回归验证:仓库测试目录中的 tests/test_infer_embedder_basic.py 覆盖了 Embedder 的基础推理路径,可作为自定义封装后的自检参考。
九、小结
FlagEmbedding 的推理 Embedder API 用"一个抽象基类 + 四个具体类"覆盖了当前主流的两代嵌入模型范式:BaseEmbedder与M3Embedder服务于编码器架构(单向量检索与稠密+稀疏+多向量混合检索),BaseLLMEmbedder与ICLLLMEmbedder服务于解码器 LLM 架构(指令式嵌入与上下文学习嵌入)。理解它们的参数默认值、三入口编码约定、池化差异与多设备调度机制,是高效使用 BGE 系列模型构建 RAG 与检索系统的基础,也是阅读仓库评测与微调代码(FlagEmbedding.abc.inference、FlagEmbedding.finetune.embedder)的切入点。
【免费下载链接】FlagEmbeddingRetrieval and Retrieval-augmented LLMs项目地址: https://gitcode.com/GitHub_Trending/fl/FlagEmbedding
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考