一天内微调专属领域向量嵌入模型
如果你在构建 RAG 系统,很可能遇到过这个瓶颈:一切看起来都正常……直到它失灵。通用向量嵌入模型(Embedding Model)的训练目标是理解互联网,而不是你的合同、制造日志、专有化学配方或内部分类体系。它们能捕捉广泛的语义相似性,但无法理解你所在领域的细微差别。当现成模型无法有效捕捉领域特定细节时,微调向量嵌入模型可以显著提升检索流程的性能。尽管嵌入对 RAG 性能至关重要,但微调过程仍然相当零散,所需技能专业,时间投入也令人望而却步。
现在,只需一块 GPU 和不到一天的训练时间,你就能将一个通用向量嵌入模型转变为真正理解你领域的专家,且无需人工标注。为了让你快速上手,我们还发布了一个开箱即用的合成训练数据集,该数据集正是使用此流程从 NVIDIA 公开文档生成的。使用该数据和配方,我们看到 Recall@10 和 NDCG@10 均提升了 10% 以上。Atlassian 将此配方应用于其 JIRA 数据集的微调,将 Recall@60 从 0.751 提升至 0.951,提升了 26%——仅用一块 GPU。
🔗 快速链接
🧑💻 集成的开源项目
本配方集成了以下开源项目:
- NeMo Data Designer 用于合成数据生成
- NeMo Automodel 用于向量嵌入模型训练
- BEIR 用于信息检索评估
- NeMo Export-Deploy 用于 ONNX/TensorRT 转换
- NVIDIA NIM 用于生产环境推理服务
📋 前提条件
- 一个包含领域文档的目录(文本文件,如 .txt, .md 等)
- 有效的 NVIDIA API 密钥(可在 build.nvidia.com 免费获取)
- 至少 80GB 显存的 NVIDIA Ampere 架构或更新 GPU(计算能力 >= 8.0)
- 本教程已在 1xA100 (80GB) 和 1xH100 (80GB) 上测试通过
读完本文,你将学会如何: 📄 从领域文档生成训练数据,无需标注数据 🎯 使用困难负样本挖掘进行有效的对比训练 🔗 通过多跳问题提升嵌入质量 ⚙️ 微调一个双编码器向量嵌入模型 📊 评估微调是否改善了检索效果 🚀 将微调后的模型部署到你的流程中
⚙️ 环境设置
在本教程中,我们将微调基础模型 Llama-Nemotron-Embed-1B-v2——一个在质量和推理成本间取得平衡的 10 亿参数向量嵌入模型。要开始操作,请遵循此设置指南。
📚 第一步:从文档生成训练数据
微调向量嵌入模型需要成千上万的(查询,相关文档)对。大多数用例并没有现成的数据。手动创建既昂贵又缓慢,而且常常会受到标注者对“相关性”个人理解的偏见影响。
与其手动标注数据,不如使用大语言模型来读取你的文档,自动生成高质量的合成问答对。
nemotron embed sdg -c default corpus_dir=./data/my_domain_docs
工作原理
这条命令背后,运行的是一个由 NeMo Data Designer 驱动的四阶段合成数据生成(SDG)流程。
输出示例
源文档片段:
H100 GPU 的热设计功耗在 SXM 形态下为 700W。冷却方案必须在持续工作负载下将结温维持在 83°C 以下。对于每个节点超过 4 块 GPU 的高密度部署,推荐使用液冷,因为风冷无法在标准的 2U 机箱配置中散发足够的热量。
生成的问答对:
{
"question": "What cooling approach is recommended when deploying more than 4 H100 GPUs per server node?",
"answer": "Liquid cooling is recommended for dense deployments exceeding 4 GPUs per node, as air cooling cannot dissipate sufficient heat in standard 2U chassis configurations.",
"query_type": "contextual",
"reasoning_type": "factual",
"question_complexity": 3,
"segment_ids": [1],
"quality_score": 8.5
}
{
"question": "How does the 700W TDP of the H100 SXM constrain the choice between air and liquid cooling in multi-GPU configurations?",
"answer": "The 700W TDP generates substantial heat that must be dissipated to keep junction temperatures below 83°C. In dense configurations exceeding 4 GPUs per node, air cooling in standard 2U chassis cannot handle this thermal load, making liquid cooling necessary.",
"query_type": "multi_hop",
"reasoning_type": "causal",
"question_complexity": 4,
"segment_ids": [1, 2],
"hop_count": 2,
"quality_score": 9.0
}
注意区别:第一个问题是简单的事实查找。第二个则需要多跳因果推理。该流程会生成两种类型的问题,并具有可配置的复杂度级别和跳数。每个问答对随后会经过质量评估,获得相关性、准确性、上下文支持和清晰度等子分数以及一个总分。只有达到阈值的问答对才会被纳入训练。
⛏️ 第二步:挖掘困难负样本(及其重要性)
如果你只用正样本对训练向量嵌入模型,它只能学会区分明显不同的文档,但在困难案例上会失败——那些看起来相关但并非正确答案的段落。在实际的检索系统中,正是这些“擦边球”文档导致了错误的答案。困难负样本挖掘就是为了找出这些容易混淆的段落,让模型学会区分它们。
nemotron embed prep -c default
上述命令会自动运行三个子步骤:
2a. 训练/验证/测试集划分
生成的问答对被划分为训练集和测试集。测试集会格式化为 BEIR 兼容的基准,用于第五步的标准化评估。
2b. 困难负样本挖掘
使用基础向量嵌入模型,该流程会:
- 嵌入每个查询和语料库中的每个段落。
- 计算每个查询与所有段落之间的相似度。
- 屏蔽掉每个查询已标注的正样本文档。
- 应用边界过滤器:任何得分高于正样本最低分 95% 的非正样本文档都会被排除。这个排除区域是为了防止误将未标注但实际相关的段落当作负样本。
- 从剩余的候选文档中,选择得分最高的前 k 个文档作为困难负样本。
结果就是:困难负样本是那些与查询最相似、但得分又安全地低于正样本得分上限的非正样本段落。它们是当前模型认为高度相关但并非标注答案的段落。
为什么有效:用简单的负样本训练模型学不到新东西。用困难负样本训练,则迫使模型学习你领域中那些重要的细微差别。
2c. 多跳问题展开
多跳问题会引用多个正样本文档。展开操作会为每个(查询,正样本文档)对创建一个训练示例,这样对比损失就能独立地看到每个正样本。
最终的输出是一个可用于训练的 JSON 文件。
🔍 第三步:理解多跳问题及其如何提升检索
标准的向量嵌入微调会为每个段落生成一个问题,并训练模型进行匹配。这对于简单的事实查找有效,但真实用户会提出跨越多个文档或章节的复杂问题。如果模型只见过单跳训练数据,它很难为这些复杂查询检索到所有相关段落。
SDG 流程默认生成 1 到 3 跳的问题。每一跳都有其上下文摘要和段落 ID,因此训练数据保留了完整的推理链。经过展开后,每个(问题,相关段落)对都成为一个独立的训练信号,教会模型所有这些段落都与多跳查询相关。
微调后的模型学会检索上下文相关的文档,而不仅仅是词汇相似的文档。
🧠 第四步:微调向量嵌入模型
nemotron embed finetune -c default
对比学习如何工作
训练使用双编码器架构和对比损失。温度参数 0.02 是刻意设置的激进值,它会产生非常尖锐的概率分布。这之所以有效,是因为第二步挖掘出的困难负样本质量很高:它们是模型确实需要强梯度才能学会区分的、真正容易混淆的段落。
关键超参数
| 参数 | 默认值 | 说明 |
|---|---|---|
| Epochs | 3 | 对于大型数据集,可降至 2 或 1 |
| Learning rate | 1e-5 | 调参:可尝试默认值的两倍或一半 |
| Learning rate warmup steps | 5 | 设为微调总步数的 5-10% 以获得更好的早期训练稳定性 |
| Global batch size | 128 | 对于小数据集会自动缩小 |
| Passages per query | 5 | 1 个正样本 + 4 个困难负样本 |
小数据集自动适配
如果你的训练样本少于 2000 条,流程会自动调整:
- 降低批次大小(到 16–64),确保梯度计算有意义。
- 调整检查点频率,保证每次运行至少生成三个检查点。
- 按比例缩放验证频率。
这意味着你可以先用少量文档(50–100 份)快速验证概念,后续再扩展规模。
📈 第五步:评估效果提升
微调真的有用吗?运行一个标准化评估,在预留的测试集上对比基础模型和微调后的检查点,答案就出来了:
nemotron embed eval -c default
评估使用 BEIR 框架,计算 k = 1、5、10、100 时的四个标准信息检索指标:
- nDCG@k:排序质量——最好的文档是否排在最前面?
- Recall@k:覆盖率——有多少相关文档出现在前 k 个结果里?
- Precision@k:准确率——前 k 个结果中,实际相关的比例是多少?
- MAP@k:所有查询的平均精度
一次成功的微调,通常能在一天内让 nDCG@10 和 Recall@10 提升 10% 左右。
使用 Retrieval Synthetic NVDocs 数据集的结果:
📊 对比结果(基础模型 -> 微调模型)
============================================================
NDCG:
NDCG@1: 0.55178 → 0.60796 (+0.05618, +10.2%)
NDCG@5: 0.51894 → 0.57689 (+0.05795, +11.2%)
NDCG@10: 0.55506 → 0.61559 (+0.06053, +10.9%)
NDCG@100: 0.60617 → 0.66567 (+0.05950, +9.8%)
Recall:
Recall@1: 0.28478 → 0.31547 (+0.03069, +10.8%)
Recall@5: 0.54486 → 0.60288 (+0.05802, +10.6%)
Recall@10: 0.62979 → 0.69296 (+0.06317, +10.0%)
Recall@100: 0.81421 → 0.87020 (+0.05599, +6.9%)
如果指标没提升怎么办?
这个流程很容易迭代调试:
- SDG 阶段分数低? 检查文档质量——干净、格式良好的文本能生成更好的合成数据。试试更大、更强的 LLM。
- 训练数据不够? 往语料库里加更多文档,重新运行第 0 阶段。
- 过拟合了? 减少训练轮数,或者提高质量阈值,只保留最好的训练样本。
- 学习率不对? 大数据集试试 5e-6,非常小的数据集试试 2e-5。
🏆 真实案例:Atlassian
这个方案已经在 Atlassian 的真实企业数据上得到了验证。他们用这个流程,基于一个 公开的 Jira 数据集,在单张 NVIDIA A100 80GB GPU 上微调了 Llama-Nemotron-Embed-1B-v2 模型,步骤和上面描述的一样。
Recall@60 从 0.751 跃升至 0.951,提升了 26.7%。
微调后的模型,对于 95.1% 的查询,都能在前 60 个结果中检索到正确文档,而基础模型只有 75.1%。对于支撑 Jira 搜索的检索系统来说,这直接意味着为数百万用户提供了更相关的结果。更多细节可以看他们的博客文章 Advancing semantic search for millions of Rovo users。
🚀 第六步:导出与部署
PyTorch 检查点适合评估,但生产环境太慢。最后两个阶段负责转换模型,并通过 API 提供服务。
导出为 ONNX / TensorRT
nemotron embed export -c default
这条命令会把微调好的检查点导出为 ONNX 格式(opset 17)。可选地,它还能编译一个 TensorRT 引擎,以获得最大推理吞吐量,并支持为批次大小(1–64)和序列长度(3–256)配置优化方案:
# 仅 ONNX(随处可运行)
nemotron embed export -c default export_to_trt=false
# FP8 量化以进一步提速
nemotron embed export -c default quant_cfg=fp8
用 NVIDIA NIM 部署
导出的模型会被部署在 NVIDIA NIM 容器里——这是一个生产就绪的推理微服务,暴露一个 OpenAI 兼容的 /v1/embeddings 端点:
nemotron embed deploy -c default
运行起来后,任何客户端都可以调用它:
curl -X POST http://localhost:8000/v1/embeddings \
-H "Content-Type: application/json" \
-d '{"input": ["What cooling is needed for 8 H100 GPUs in a 2U chassis?"],
"model": "custom",
"input_type": "query"}'
因为 NIM 提供的是 OpenAI 兼容的 API,你可以直接把它塞进任何现有的、使用 embeddings API 格式的 RAG 流程里——完全不用改代码。
验证部署精度
流程里包含一个 NIM 精度验证步骤,会对部署好的端点运行同样的 BEIR 评估:
nemotron embed eval -c default eval_nim=true eval_base=false
这能捕捉到 ONNX/TensorRT 转换过程中可能出现的精度损失。指标在容差范围内(@1 为 0.03,@5+ 为 0.01)的会打上勾;超出转换噪声的偏差会被标记出来。
完整流程概览
整个嵌入模型微调流程可以用六条命令跑完,从原始文档到部署好的模型。
# 1. 从你的文档生成合成训练数据
nemotron embed sdg -c default corpus_dir=./data/my_docs
# 2. 准备训练数据(分割数据、挖掘困难负样本、展开)
nemotron embed prep -c default
# 3. 微调嵌入模型
nemotron embed finetune -c default
# 4. 评估基础模型与微调模型
nemotron embed eval -c default
# 5. 导出优化后的模型
nemotron embed export -c default
# 6. 部署模型
nemotron embed deploy -c default
预计耗时与资源
| 阶段 | 需要 GPU? | 预计时间 | 备注 |
|---|---|---|---|
| SDG | 否(使用 API) | ~1 小时 | 取决于语料大小和 API 速率限制 |
| 数据准备 | 是(40 GB 显存) | ~5 分钟 | 在 GPU 上挖掘困难负样本 |
| 微调 | 是(80 GB 显存) | ~1 小时 | 取决于数据集大小和训练轮数 |
| 评估 | 是(40 GB 显存) | ~5 分钟 | |
| 导出 | 是(40 GB 显存) | ~5 分钟 | TensorRT 需要 NGC 容器 |
| 部署 | 是(40 GB 显存) | ~5 分钟 | NIM 容器启动 |
总计:一天之内,大部分时间是无需干预的训练。 对于小语料库(约 500 份文档),整个流程大约 2–3 小时就能完成。
流程可以端到端运行,但每个阶段也可以根据你的起点独立执行。例如,如果你有原始文档,可以从合成数据生成(SDG)开始;而已经包含困难负样本的数据集,可以跳过早期步骤,直接开始微调。由于每个阶段都使用 JSON、BEIR、ONNX 等标准格式,很容易集成自定义组件,或者在其他工作流中复用中间输出。这个方案在运行方式上也很灵活,支持在本地机器、Docker 容器内或基于 Slurm 的集群上执行。
自己动手试试
如果你有领域文档,并且手头有点时间,今天就可以生成第一批合成训练数据!整个流程——从文档到部署好的、适应特定领域的嵌入模型——在单张 GPU 上一天之内就能跑完。你可以直接用我们现成的 nvidia/Retrieval-Synthetic-NVDocs-v1 数据集来立刻体验这个流程。期待看到你用它构建出什么。
如果觉得有用,别忘了给 Nemotron、NeMo Data Designer 和 NeMo Automodel 的仓库点个星。
觉得有用?分享给更多人

