
大多数构建 RAG 的团队,其实没必要自己训练 Embedding 模型。
OpenAI 的 text-embedding-3-large、Cohere 的 embed-v4 这类现成模型价格不高、文档完善,也不需要自己维护推理基础设施。对于大多数通用语料,它们已经足够好用。
但有一个比较明确的分界线。
如果你在自己业务查询上的 Recall@10 已经低于大约 80%,也就是说 10 次真实查询里,有超过 2 次正确文档进不了前 10;与此同时,你手里已经积累了几千甚至几万条真实的“查询—文档”配对,那么继续换通用 Embedding API,往往解决不了根本问题。
这个时候,更值得尝试的是:用自己的业务数据微调一个小型开源 Embedding 模型。
一些已经公开相关实验结果的团队发现,经过领域数据微调之后,一个参数规模并不大的开源 Embedding 模型,在特定领域检索上的指标可以比通用 API 模型高出 10 个点甚至更多。
而且,这件事并没有听起来那么重。
你未必需要建设一套完整的 MLOps 平台。对于一个 1 亿级参数的 Embedding 模型,一张 GPU、几十分钟训练时间,再加一个支持 pgvector 的 PostgreSQL,就足以跑通从训练、评测到生产检索的完整流程。
本文会以一个支持工单 RAG 系统为例,看看什么时候值得定制 Embedding,以及如何用 DigitalOcean GPU Droplet + PostgreSQL托管数据库 + pgvector 搭建一套相对简单的生产架构。
为什么通用 Embedding 在垂直领域会失效
通用 Embedding 模型通常在规模非常大的公开文本上训练,因此很擅长理解一般意义上的语义关系。
比如,它知道 car 和 automobile 基本是在说同一件事。
但它未必知道:
在你的数据库支持系统里,ORA-01555 和 snapshot too old 指的是同一类故障;
或者在你的内部代码库里,reconcile_ledger 和“nightly balance job”其实指向的是同一套任务。
这类问题的本质,并不是模型“不够聪明”,而是它没有学过你所在行业和企业内部的表达方式。
用户搜索时使用的是一种语言,知识库写文档时使用的是另一种语言。
这就是所谓的词汇鸿沟。
而对比式微调恰好是在解决这个问题。
训练时,你给模型大量这样的配对:
用户会这样问 → 正确答案其实是这篇文档。
模型会把匹配的查询和文档在向量空间中拉得更近,同时把无关内容推远。
它不会因此成为更强的通用语言模型,而只是变得更擅长一件事:
把用户真实的提问方式,映射到你的知识库组织答案的方式上。
这正是检索型 Embedding 最重要的职责。
一个更具体的例子:支持工单 RAG
假设你正在构建一个面向企业客户的技术支持 RAG 系统。
用户提交工单的时候,可能会写:
db conn pool exhausted after upgrade
但知识库里的正式标题却可能是:
Connection limits in Managed Databases
对于人类工程师来说,两句话说的是一件事。
但从表面词汇来看,它们几乎没有重叠。
通用 Embedding 模型当然有可能把它们关联起来,但如果你的产品里充满内部术语、错误代码、产品缩写、历史命名和行业黑话,这种匹配就会越来越不稳定。
现在假设你已经积累了六个月的已解决工单。
每一张工单,都能对应到最终解决问题的知识库文章。
那么这些历史数据天然就是一批非常有价值的训练样本:
用户问题 → 最终解决它的文档
用这些数据微调 Embedding 后,模型学到的不只是英文语义,而是你自己的用户到底会怎样描述问题。
这往往比单纯换一个更大的通用模型有效得多。
几个术语,先用大白话解释
Embedding:一组数字,用来表示一段文本的语义。含义越接近的文本,对应的向量通常也越接近。
知识库:你希望搜索的文档、文章或文本块集合。本文的例子里,就是产品支持文章。
向量数据库:用来保存 Embedding,并快速搜索相似向量的数据库。pgvector 可以让 PostgreSQL 直接具备向量搜索能力。
Recall@10:所有测试查询里,正确文档能够进入前 10 个搜索结果的比例。越高越好。
MRR(平均倒数排名):不仅看正确答案有没有出现,还看它排得够不够靠前。正确答案排第 1,显然比排第 8 更有价值。
对比式微调:通过“这个查询应该匹配这篇文档”这样的训练对,让模型学会把相关内容的向量拉近。
微调之后,差距可能有多大?
下面假设一个相对典型的企业 RAG 场景:
知识库包含 10,000 个文本块;
有 1,000 条单独留出的测试查询,这些数据完全不会参与训练;
另外有 50,000 个训练对,每一个都是历史真实工单与最终解决文档之间的配对。
Recall 和 MRR 可以理解为类似项目中常见的结果区间;模型维度、向量大小以及 API 成本,则可以直接根据模型规格估算。
| 指标 | text-embedding-3-large API | bge-base-en-v1.5 原版 | bge-base-en-v1.5 微调后 |
|---|---|---|---|
| Recall@10,领域查询 | 0.71 | 0.66 | 0.83 |
| MRR@10,领域查询 | 0.58 | 0.52 | 0.71 |
| Recall@10,通用查询 | 0.89 | 0.84 | 0.82 |
| 向量维度 | 3,072 | 768 | 768 |
| 1000 万文本块向量规模 | 约 123 GB | 约 31 GB | 约 31 GB |
| Embedding 生成成本 | API 计费 | GPU 计算 | GPU 计算 |
| 查询路径 | 远程 API + 搜索 | 本地推理 + 搜索 | 本地推理 + 搜索 |
这张表里有三个重点。
第一,领域效果提升才是微调最重要的理由。
从 0.71 提高到 0.83,看起来只是十几个百分点,但对于生产 RAG 来说,这意味着大量原本根本检索不到正确文档的问题,现在有机会进入上下文。
如果检索阶段已经漏掉正确答案,后面的 LLM 再聪明也很难补救。
第二,微调通常会牺牲一点通用能力。
模型开始更懂你的业务,也就意味着它会稍微减少对“什么都懂一点”的追求。
如果你的查询绝大多数都是通用英文问题,微调可能反而没有意义。
第三,768 维和 3,072 维之间的差距不仅是技术参数,还会直接影响数据库。
向量维度缩小到四分之一,意味着向量本身占用的空间、索引体积以及内存压力都会明显下降。
到了上千万文本块的规模,这就不再只是几个 GB 的区别,而可能直接影响你需要购买什么规格的数据库。
真正值得算的,不只是训练费
很多人第一次考虑微调 Embedding 时,第一反应都是:
训练模型是不是很贵?
实际上,对于这种规模的小模型,GPU 很可能是整个项目里最便宜的部分。
bge-base-en-v1.5 大约只有 1.09 亿参数。
即使你有 50,000 组训练数据,使用单张 GPU 完成几轮对比式训练,通常也只是几十分钟到数小时级别的任务。
比如你可以临时创建一台 DigitalOcean GPU Droplet,SSH 登录后直接运行 Sentence Transformers、PyTorch 或 Hugging Face 训练代码。训练完成之后保存 checkpoint,不需要的时候就把 GPU 释放掉。
真正昂贵的是另外几件事:
收集高质量的查询—文档配对;
建立不会被训练数据污染的评测集;
持续观察 Recall 和 MRR;
以及未来每隔几个月重新训练一次模型。
换句话说,Embedding 微调首先是一个数据工程问题,其次才是 GPU 问题。
也正因为如此,这类场景不一定值得为了训练本身再采购一整套专门的模型平台。
这次训练到底涉及什么?
这一节主要是为了说明训练规模,并不是完整教程。
假设训练数据已经整理成 JSONL:
{"query": "db conn pool exhausted after upgrade", "positive": "Connection limits in Managed Databases: each plan tier has a maximum connection count..."}
{"query": "how do i rotate the ca cert", "positive": "Rotating certificates: Managed Databases uses a per-cluster CA that can be regenerated..."}
使用 sentence-transformers,训练代码并不复杂:
from datasets import load_dataset
from sentence_transformers import (
SentenceTransformer,
SentenceTransformerTrainer,
SentenceTransformerTrainingArguments,
)
from sentence_transformers.losses import MultipleNegativesRankingLoss
model = SentenceTransformer("BAAI/bge-base-en-v1.5")
dataset = load_dataset(
"json",
data_files="pairs.jsonl",
split="train"
)
dataset = dataset.rename_columns({
"query": "anchor",
"positive": "positive"
})
args = SentenceTransformerTrainingArguments(
output_dir="bge-base-support-ft",
num_train_epochs=2,
per_device_train_batch_size=64,
learning_rate=2e-5,
warmup_ratio=0.1,
bf16=True,
)
trainer = SentenceTransformerTrainer(
model=model,
args=args,
train_dataset=dataset,
loss=MultipleNegativesRankingLoss(model),
)
trainer.train()
model.save_pretrained("bge-base-support-ft/final")
这里使用的是 MultipleNegativesRankingLoss。
它有一个很实用的特点:
对于 batch 中的每个查询,它对应的正确文档是正样本,而同一个 batch 里的其他文档会自动成为负样本。
因此你不需要人工整理大量:
这篇文档是错误答案。
只需要尽可能收集高质量的:
这个查询最终对应这篇正确文档。
这也是为什么历史工单、站内搜索点击和客服解决记录特别适合作为训练数据。
训练完成以后,可以使用 InformationRetrievalEvaluator 在留出测试集上计算 Recall@K 和 MRR。
注意,一定要把测试集单独留出来。
如果模型训练过这些查询,那么最终数字基本没有参考意义。
数据库成本,可能比训练成本更值得关注
Embedding 模型一旦进入生产环境,真正持续产生的成本往往来自推理和存储。
模型选择会直接反映到 PostgreSQL 里。
768 维向量下,1000 万个文本块的向量和相关索引大约是几十 GB 级别;
到了 3,072 维,同样规模的知识库则可能增长到一百多 GB。
而这还没有计算正文、元数据以及其他业务表。
所以选择 Embedding 模型的时候,不应该只比较模型榜单,还应该同时考虑:
检索效果、Embedding 推理成本、向量维度和数据库规格。
如果你的应用本身就在使用 PostgreSQL,也不一定需要为了 RAG 再维护一套完全独立的向量数据库。
DigitalOcean PostgreSQL托管数据库支持 pgvector,因此可以继续在 PostgreSQL 体系里保存文档元数据和 Embedding,并通过 HNSW 等索引完成向量检索。
对于中等规模的 RAG 应用来说,这种方式的优势主要不是“功能更多”,而是少维护一套系统。
数据库还是 PostgreSQL,应用还是原来的应用,只是增加了一列向量和一个向量索引。
在 DigitalOcean 上,这套架构可以很简单
如果真的决定微调自己的 Embedding 模型,一个典型架构并不复杂:
业务数据 → GPU Droplet 微调模型 → Embedding 推理服务 → PostgreSQL托管数据库 + pgvector → RAG 应用 → LLM
里面真正新增的组件其实不多。
GPU Droplet:训练和运行 Embedding
首先创建一台 DigitalOcean GPU Droplet。
它本质上是一台带 GPU 的标准云服务器,而不是一个只能按照固定格式提交任务的微调 API。
你可以直接 SSH 登录,然后使用:
-
Sentence Transformers
-
PyTorch
-
Hugging Face
-
Transformers
-
自己编写的训练脚本
训练完成以后,checkpoint 也由你自己控制。
对于每季度或者每隔几个月跑一次的 Embedding 微调,这种方式往往已经足够。
如果只是临时训练,训练结束后还可以释放 GPU,避免机器长期空转。
PostgreSQL托管数据库 + pgvector:保存知识库向量
模型训练好以后,需要重新为知识库生成 Embedding。
这些向量可以继续存入 DigitalOcean PostgreSQL托管数据库。
这样,文档 ID、权限、版本、业务字段以及 Embedding 可以继续放在一套数据库体系中。
应用查询时,大致流程就是:
用户问题 → Embedding 模型 → 查询向量 → pgvector 相似度搜索 → Top-K 文档 → LLM
对于原本已经熟悉 PostgreSQL 的开发团队来说,这意味着不需要突然学习和维护完全不同的数据基础设施。
Droplet 或 Kubernetes:继续运行你的 RAG 应用
真正面向用户的 RAG 应用,可以继续运行在普通 Droplet、Kubernetes 或其他计算资源上。
因此最终形成的是一套比较传统的云架构:
应用服务器 + GPU 推理 + PostgreSQL
而不是为了一个 Embedding 模型,再引入几个相互独立的 SaaS 平台。
这其实是 DigitalOcean 在这个场景里比较重要的价值。
它并不是提供一个“点击按钮就帮你微调 Embedding”的产品,而是提供一套相对容易理解的基础设施:
GPU 负责训练和模型推理,PostgreSQL托管数据库 + pgvector 负责检索,应用继续使用常规云计算资源。
如果团队本身已经具备基本的 Linux、Python 和 PostgreSQL 运维经验,增加一个定制 Embedding 模型,并不会突然把 RAG 项目变成一个复杂的机器学习平台项目。
为什么这比单纯比较 GPU 价格更重要?
Embedding 项目最大的误区之一,是过度关注那几十分钟 GPU 花了多少钱。
但一次微调可能只运行几十分钟,而生产系统会运行几个月甚至几年。
真正应该计算的是整个生命周期:
训练成本
Embedding 推理成本
向量数据库成本
索引和内存成本
运维复杂度
数据在不同平台之间流动的成本
如果为了训练使用平台 A,为 Embedding 推理使用平台 B,向量存入平台 C,而应用又部署在平台 D,那么每一个组件单独看都可能很便宜,最终系统却不一定简单。
对于 Embedding 微调这种本身计算规模并不大的任务,把 GPU、PostgreSQL 和应用集中在同一套云基础设施里,有时比节省几毛钱 GPU 费用更有价值。
其他平台怎么选?
当然,DigitalOcean 并不是所有场景里的唯一答案。
不同平台解决的问题并不一样。
OpenAI 和 Cohere 更适合这样的团队:
通用模型效果已经足够好,不希望维护任何模型基础设施。
这种情况下继续调用 API,通常是最合理的选择。
Baseten 一类模型平台更强调模型训练、部署和推理服务的一体化。如果你希望平台帮助完成更多模型工程工作,而不是自己维护训练和 serving,它们值得评估。
Modal 的思路又不太一样。
它采用更偏无服务器计算的方式,GPU 可以按任务启动,尤其适合大量短时间、并行运行的实验和超参数搜索。
DigitalOcean 则更接近传统云基础设施:
创建 GPU → SSH 登录 → 运行代码 → 自己控制 checkpoint → 接入自己的数据库和应用。
所以关键并不是谁“绝对更好”,而是你的工作负载是什么。
如果需要同时运行几百组短暂的实验,无服务器 GPU 计算通常更加方便。
但如果你的场景是:
每隔几个月重新训练一次 Embedding,长期运行一个生产 RAG,并且已经有自己的应用和 PostgreSQL 数据库,
那么 GPU Droplet + PostgreSQL托管数据库 + pgvector 这种模式通常更容易理解,也更容易和现有技术栈结合。
什么时候其实根本不应该微调?
有三种情况,可以很放心地继续使用现成 Embedding。
查询量很小
训练 GPU 很便宜,但维护训练数据并不便宜。
总要有人维护:
配对数据;
评测集;
数据清洗;
指标;
模型版本;
再训练周期。
如果系统每天只有几百次查询,而且当前检索已经基本可用,那么工程维护成本可能永远收不回来。
领域词汇变化太快
如果你的产品名、错误代码和业务术语每个月都在变化,那么 Embedding 模型也会不断过时。
这个时候,频繁再训练可能变成一种负担。
相比之下,通用 Embedding 加 BM25、关键词检索或者混合搜索,有时候反而更加稳定。
根本没有真实训练对
Embedding 微调的效果,很大程度取决于:
用户实际上是怎样问问题的。
如果没有查询日志、工单、点击数据或者真实问答配对,只是从知识库文档里自动生成一批问题,那么提升通常不会像真实用户数据那么明显。
因为合成问题更多是在学习“文档自己是怎样描述自己的”,而不是用户真正会怎样描述问题。
而后者才是你真正需要解决的词汇鸿沟。
决策框架:满足三个条件,再考虑微调
做决定之前,最重要的一步不是租 GPU,而是建立一个真正可信的评测集。
从历史日志中取出 200 到 500 条有代表性的真实查询。
人工确认每一条查询应该命中哪篇文档。
然后使用当前 Embedding 模型建立索引,计算 Recall@10。
如果同时满足下面三个条件,微调就值得认真考虑:
第一,领域查询 Recall@10 低于大约 80%。
说明检索本身还有明显改进空间。
第二,你至少能收集几千条真实查询—文档配对。
没有高质量数据,再大的 GPU 也解决不了问题。
第三,团队有人可以维护再训练周期。
不一定需要每周训练。对于很多相对稳定的企业知识库,每季度重新评测和训练一次,可能已经足够。
反过来,如果你的查询主要是通用问题、领域词汇变化很快,或者根本没有真实训练数据,那么继续使用现成 Embedding API 通常更加合理。
还有一种中间方案也经常被忽略:
不微调,只自托管。
如果现在的问题主要是 API 延迟、向量维度过大或者调用成本,而检索准确率本身已经不错,那么完全可以直接部署一个原版开源 Embedding 模型。
先获得:
更低的网络延迟;
更小的向量;
更可控的推理成本。
等以后真正积累出足够多的查询—文档数据,再加入微调。
最后:先测,再决定要不要建
所以,“要不要定制 Embedding 模型”其实并不需要凭感觉判断。
先做一个真实评测集。
如果当前模型的 Recall@10 已经很好,那就继续调用 OpenAI、Cohere 或其他现成 API。
省下来的工程时间,很可能比模型成本更值钱。
但如果 Recall@10 明显低于预期,而且你已经积累了几千甚至几万条真实的“查询—文档”配对,那么自己微调一个开源 Embedding 模型,也没有想象中那么复杂。
你甚至不需要为了这件事建设一套庞大的 AI 基础设施。
一台 DigitalOcean GPU Droplet 可以负责模型训练和推理;Embedding 和文档数据继续放进支持 pgvector 的 DigitalOcean PostgreSQL托管数据库;RAG 应用则继续运行在现有的云服务器或 Kubernetes 环境中。
最终得到的仍然是一套很容易理解的架构:
GPU + PostgreSQL + 应用。
真正值得优化的,也并不只是一次训练省下来的几美元。
更高的领域检索准确率、更小的向量、更低的长期 Embedding 成本,以及一套由自己掌控、能够和现有业务基础设施结合的 RAG 架构,才是定制 Embedding 真正值得投入的地方。
相关产品与选型



