
RAG 系统上线后最常被吐槽的是检索不准。明明知识库里有答案用户换一种口语化问法向量检索却召回一堆无关段落大模型只能基于错误上下文硬答于是“答非所问”“回答不专业”就都来了。问题往往出在 Embedding 模型的能力边界而不是生成模型本身不聪明。面向 2026 年RAG 优化已经不只是调切块长度或换个大模型。越来越多团队开始走同一条路线借助 Qwen3 构造高质量训练数据对 Embedding 模型做领域微调让向量检索更贴近真实业务语言最终让大模型回答更专业。这篇博客会把这条链路拆开讲清楚RAG 为什么检索不准、Embedding 微调的基本原理、Qwen3 在数据生成和难负样本构造里的角色、训练代码怎么写、接入 Milvus 和 LlamaIndex 时要注意什么、上线后效果怎么评估以及生产落地上最容易踩的坑。1. 先理解 RAG 检索不准的根因再决定要不要微调 Embedding1.1 检索不准往往不是“模型笨”而是“召回偏了”RAG 的完整链路通常分三块知识库切块、文本向量化、向量检索与排序。大多数团队投入精力最少、出错却最多的是中间那块 Embedding。Embedding 模型做的事情是把一段文本压缩成一个向量让语义相近的文本在向量空间里距离更近。例如“怎么申请工伤认定”和“工伤认定申请流程”应该是近邻而“工伤鉴定标准”虽然包含“工伤”两个字却不应在用户问流程时排在前面。问题在于通用 Embedding 模型是在互联网开放语料上训练的它擅长处理“通用语言”但面对一个行业的简称、系统名称、产品术语、客服话术、中英混排、业务单据编号时向量空间的分布可能完全不对。观察下面这种典型 badcase用户 Query检索结果是期望结果我们公司发票冲红后税号会变吗发票管理办法关于红字发票的规定本项目发票冲红的具体操作指南XX 系统登录报 5001 错误怎么办系统使用手册目录XX 系统 5001 错误码说明如果把这两组 Query 和文档片段丢给通用 Embedding 模型会发现相似度分数往往没有明显区分度。问题不是切块没切好而是模型根本不知道“5001 错误码”在这个系统里等价于“登录鉴权失败”。1.2 通用 Embedding 模型的“领域盲区”长什么样行业内比较常见的开源 Embedding 模型包括 BGE 系列、BGE-M3、GTE 系列、M3E 等。它们在中英文通用检索任务上表现很好但一进垂直领域就会暴露几个问题。第一专业术语语义稀疏。比如“货描不符”“质保单”“T0 回款”这些词在训练语料里出现频次不高模型很容易把它们当成普通词语处理向量表征不够稳定。第二口语化和反问句式泛化弱。RAG 系统的真实用户不会按照文档目录说话他们经常输入“这个单子咋走流程”“为什么不能提现”和正式文档的语言风格差异很大。第三同义词和缩写关联弱。“结算单”和“Settlement Note”“结算凭证”在业务里可能指向同一类文件但通用模型不一定能建立这种等价关系。用户搜索“qwen3 embedding 微调”时看到的很多教程本质上都是在解决这类“领域盲区”。如果只是换一个更大的通用模型通常只能缓解问题不能根治。要让检索真正贴近业务就要让 Embedding 模型见过业务数据并针对业务 Query 和文档做过对比学习。1.3 什么时候该微调什么时候先不要动 Embedding微调 Embedding 不是 RAG 优化的第一步甚至不是第二步。在投入 GPU 训练之前可以按下面顺序排查。排查项检查方式如果存在问题切块粒度查看召回文档是否在中间截断调整 chunk_size / overlap或按标题、段落结构切块元数据过滤是否能用业务字段排除明显无关文档增加创建时间、部门、文档类型等过滤条件Query 改写用户原问是否太口语化、太短用大模型把 Query 改写成标准检索词再走向量检索Rerank 模型召回 top50 后是否仍然把错误文档排在前面加入专门的 Rerank 模型做精排Embedding 领域适配上述手段都做过后 badcase 仍重复出现再考虑微调 Embedding 模型换句话说微调 Embedding 适合在“检索链路已经比较完整、但深层语义匹配能力不足”的阶段启动。它的前置条件有三个一是有一个可重复复现的 badcase 集合二是有办法评估召回效果不靠肉眼感觉三是有能力构造一批覆盖业务场景的训练数据。如果知识库总共只有几百个文档检索效果差主要因为切块太粗或者没有元数据过滤那么先优化这些环节性价比更高。2. 微调 Embedding 的原理对比学习、难负样本和 Qwen3 的定位2.1 Embedding 模型训练的本质是“拉近正例推开负例”Embedding 模型本身不是被“教”出所有业务知识的它是在一个表示学习任务上被优化的。微调时我们不再训练模型回复一句话而是训练它把 Query 和对应的文档片段映射到同一个向量空间中的相近位置。最常用的训练目标是对比学习损失例如 InfoNCE。核心思想是给一个 Query让模型优化相似度使得它和正确文档的距离更近同时和一批错误文档的距离更远。假设一个 batch 里有 N 个 Query对应的正文档是同一个 batch 里的 N 个文档那么可以构造 N×N 的相似度矩阵对角线是正样本其余位置是负样本。MultipleNegativesRankingLoss 就是这么工作的。一个简单理解score(query_i, positive_i) - 尽量高 score(query_i, negative_j) - 尽量低2.2 难负样本比正样本更影响微调效果很多人第一次构造 Embedding 训练集会在每个 Query 后面配一个正确文档、一个随机文档然后开始训练。等训练完上线发现效果几乎没变。原因很简单随机文档和 Query 大多完全不相关模型很容易把它们分开训练信号很弱。真正需要训练的是“看起来相关、实际不对”的难负样本。举个例子Query发票冲红后购买方还能抵扣吗正样本发票冲红操作指南里关于购买方抵扣的相关段落难负样本发票开具流程里关于“红字发票信息表”的段落难负样本包含“发票”“冲红”“抵扣”等多个关键词向量上离 Query 很近但语义和用户问的不是一回事。只有把这种样本作为负例压下去模型才学会区分“操作流程”和“概念解释”。这是为什么微调 Embedding 必须有一个质量较高的负样本构造环节而不能只在文件系统里随机抽几个文件当负样本。2.3 Qwen3 在这条链路里的真实角色标题里写“通过 Qwen3 对 Embedding 进行训练微调”容易让人误以为直接把 Qwen3 结构拿来当向量模型训练。这里必须澄清一下技术定位。Qwen3 是生成式大模型它的输出是文本不是文本向量。当前更稳妥、也更常见的做法是用 Qwen3 生成领域 Query把“文档段落”转成“用户可能会问的问题”用 Qwen3 把这些 Query 和候选文档做相关性打分找出“分数高但实际不相关”的难负样本用 Qwen3 改写 Query制造更多表达方式不同、语义相同的正样本用 Qwen3 检查训练数据质量去掉噪声样本。也就是说Qwen3 是在“数据生产”和“数据清洗”环节起作用真正被微调的对象是专用 Embedding 模型比如 BGE-M3、bge-large-zh、GTE 等。如果团队非要用 Qwen 系列模型做 Embedding也不是不行需要自己接 pooling 层和相似度目标对比训练成本和难度都会明显上升。对于大多数 RAG 项目更理性的选择是用 Qwen3 生成数据 微调轻量专用 Embedding 模型这样训练成本低、上线快、维护也容易。3. 用 Qwen3 构造高质量 Embedding 微调数据集3.1 先设计统一数据格式微调 Embedding 的数据集一般使用 JSONL 格式每行一个训练样本。常见结构是带一个正样本和多个负样本{ query: 发票冲红后购买方还能抵扣吗, positive: 购买方取得红字发票信息表后可在增值税发票综合服务平台上进行相应抵扣处理具体以当地税务机关要求为准。, negatives: [ 发票开具流程中销售方需在开票系统内填开红字发票信息表并上传。, 普通发票丢失后如何处理纳税人应当向税务机关报告。 ] }推荐把训练数据写成这种格式而不是只用 query-positive 二元组。因为一条 Query 配多个负样本训练效率更高模型也能更快学会区分“业务概念”和“业务操作”。3.2 用 Qwen3 从文档段落生成用户 Query数据构造的第一步是把知识库文档的每个段落变成一个或多个用户 Query。可以调用 Qwen3 的 OpenAI 兼容接口也可以在本机用 vLLM 部署 Qwen3 后按相同接口调用。下面是一个用于生成 Query 的 Prompt 示例你是知识库检索训练数据的构造助手。 我会给你一段文档内容请你模拟真实用户生成 5 个不同角度的检索 Query。 要求 1. Query 必须是用户会直接输入的真实问法避免照抄原文措辞。 2. 至少包含 2 个口语化或短问法。 3. 不要生成与这段内容语义偏差过大的问题。 4. 输出格式为 JSON 数组每个元素是一个字符串。 文档内容 {chunk_text}对应的 Python 调用示例import json import openai client openai.OpenAI( base_urlhttp://your-qwen3-server:8000/v1, api_keyEMPTY ) def generate_queries(chunk_text: str) - list[str]: prompt f你是知识库检索训练数据的构造助手。 我会给你一段文档内容请你模拟真实用户生成 5 个不同角度的检索 Query。 要求 1. Query 必须是用户会直接输入的真实问法避免照抄原文措辞。 2. 至少包含 2 个口语化或短问法。 3. 不要生成与这段内容语义偏差过大的问题。 4. 输出格式为 JSON 数组每个元素是一个字符串。 文档内容 {chunk_text} resp client.chat.completions.create( modelqwen3, messages[{role: user, content: prompt}], temperature0.7, max_tokens512, ) content resp.choices[0].message.content content content.replace(json, ).replace(, ).strip() return json.loads(content)调用时需要注意真实用户 Query 和文档原文的措辞差异越大对 Embedding 微调的收益越高。如果 Qwen3 生成的问题基本都是照抄文档里的句子那训练数据对检索没有增量价值。3.3 构造难负样本从批量召回结果里筛选构造难负样本最实用的方法是“用当前 Embedding 模型先跑一遍检索然后让 Qwen3 判断相关性”。具体流程对每一条 Query用当前线上 Embedding 模型从知识库召回 top 20 个文档片段。把这 20 个片段中相似度分数较高、但在业务上不代表正确答案的片段挑出来。让 Qwen3 逐条判断“这个片段是否确实回答了 Query”给出 0 或 1 标签。标签为 0、但向量相似度靠前的片段作为难负样本加入训练集。这个流程比随机负样本有效因为模型“错得最厉害”的地方正是它需要被纠正的地方。Prompt 示例请判断下面的文档片段能否回答用户问题。只能回答 0 或 1。 用户问题 {query} 文档片段 {chunk_text} 能否回答批量处理时要注意并发限制和请求失败重试。比如本地部署 Qwen3 时如果接口偶尔超时可以加上重试逻辑并把结果记录到单独的日志文件里方便后续排查数据质量问题。3.4 数据清洗和人工抽验不要拿到 Qwen3 生成结果就直接训练。常见问题包括Query 和 positive 完全不匹配模型学不到有效信号negative 实际上也回答了 Query造成标签噪声多条 Query 完全重复导致模型过拟合到某一种表达文档片段过长或过短超过模型 max_len 限制训练时被截断。建议先做一轮自动化清洗脚本def filter_sample(sample, min_len10, max_len512): q_len len(sample[query]) p_len len(sample[positive]) if q_len min_len or p_len min_len: return False if p_len max_len * 3: return False if sample[query] in sample[positive]: return False return True然后抽出 5% 到 10% 的样本人工判断标签是否合理。如果人工抽验的准确率低于 90%建议重新调整 Qwen3 的 Prompt而不是直接扩大数据量。数据规模上Embedding 微调的最小有效集通常在几千条左右。先保证 2000 到 5000 条高质量样本比一次生成 5 万条低质量样本更有效。4. 选择开源 Embedding 模型和训练环境4.1 可微调的 Embedding 模型选型不是所有 Embedding 模型都适合微调。使用云厂商 API 的 Embedding 模型通常不开放权重只能通过官方接口调用无法针对业务数据做训练。要微调必须选择开源权重模型。常见可选模型如下模型特点适合场景注意点BGE-M3支持多语言、长文本、多粒度检索中英文混合知识库、长文档 RAG参数较多训练显存相对高bge-large-zh中文效果稳定社区资料多中文业务知识库需注意 query 指令前缀bge-base-zh参数少训练快数据量不大、端侧场景效果上限低于 largeGTE 系列部分模型支持中英和多任务需要统一向量模型的场景需确认授权和版本M3E中文效果不错部署简单中文知识库快速验证遇到复杂语义边界时可能要换模型推荐第一次做 Embedding 微调时选择 BGE 系列或 BGE-M3。它们有两个优势一是社区案例多排错资料容易找二是官方模型通常配套了推荐的指令格式训练和推理时不容易踩配置坑。另外要确认模型版本。不同版本的 Embedding 模型输出维度不同如果后续要迁移已经建好的向量库需要特别注意维度是否能对上。4.2 训练框架和依赖准备Embedding 微调可以用三种方式实现sentence-transformers 库适合快速跑通最小实验FlagEmbedding 库BGE 官方微调工具适合深度定制和难负样本训练直接用 transformers 自定义 loss适合彻底控制训练流程。为了快速跑通推荐先用 sentence-transformers。安装命令pip install -U sentence-transformers pip install torch --index-url https://download.pytorch.org/whl/cu121如果要用 FlagEmbedding还需要额外安装依赖。实际项目里要注意 PyTorch、CUDA、transformers 之间的版本兼容不要照抄教程里的版本号先在当前环境验证一次。4.3 训练超参数和显存控制Embedding 模型的参数量比 Qwen3 这类生成模型小很多训练门槛相对低。但“全参训练”和“LoRA 微调”的显存差别仍然明显。参数含义常见取值范围设置建议learning_rate学习率2e-5 到 5e-5数据量小就偏低避免灾难性遗忘batch_size每个 batch 的 Query 数量16 到 64显存不足时优先减小 batch_sizemax_len文本最大长度256 到 1024根据知识库 chunk 长度设置num_epochs训练轮数1 到 5优先 2 轮过拟合很容易warmup_ratio预热比例0.05 到 0.1稳定训练初期 loss全参微调对 Embedding 模型来说通常可行但如果你只有一个 24G 显存的 GPU又想训练 BGE-M3 这类大模型建议用 LoRA。sentence-transformers 已经支持通过 PEFT 给 Embedding 模型加 LoRA 适配器训练时先冻结主干参数只训练低秩矩阵显存占用会明显下降。5. 微调训练实战用对比学习跑通最小案例5.1 用 sentence-transformers 训练 MultipleNegativesRankingLoss这里以一个最小可运行脚本为例。假设训练数据文件是train.jsonl每条数据包含query、positive、negatives三个字段。import json from sentence_transformers import SentenceTransformer, models, losses, InputExample from torch.utils.data import DataLoader from sentence_transformers.datasets import SentenceLabelDataset base_model BAAI/bge-base-zh-v1.5 word_embedding_model models.Transformer(base_model, max_seq_length512) pooling_model models.Pooling( word_embedding_model.get_word_embedding_dimension(), pooling_mode_cls_tokenTrue, pooling_mode_mean_tokensFalse, pooling_mode_max_tokensFalse, ) model SentenceTransformer(modules[word_embedding_model, pooling_model]) examples [] with open(train.jsonl, encodingutf-8) as f: for line in f: item json.loads(line) texts [item[query], item[positive]] item.get(negatives, []) examples.append(InputExample(textstexts)) train_dataloader DataLoader(examples, shuffleTrue, batch_size32) train_loss losses.MultipleNegativesRankingLoss(model) model.fit( train_objectives[(train_dataloader, train_loss)], epochs2, warmup_steps100, output_path./embedding_model_finetuned, save_best_modelTrue, )这段代码的核心是MultipleNegativesRankingLoss。每个 InputExample 的第一条文本会被当成 Query第二条是正样本后面的所有文本是负样本。损失函数会尽量提高 Query 和正样本的相似度同时降低它和负样本的相似度。需要注意这里没有给 Query 加指令前缀。如果模型是 BGE 系列官方推荐的推理方式是给 Query 加指令但训练时是否加指令取决于数据构造方式。推荐做法是保持训练和推理一致在训练脚本里统一处理。5.2 使用 FlagEmbedding 训练 BGE-M3 的另一种方式如果选择 BGE-M3FlagEmbedding 提供了更直接的训练接口。示例代码from FlagEmbedding import FlagModel model FlagModel( BAAI/bge-m3, query_instruction_for_retrieval为这个句子生成表示以用于检索相关文章, use_fp16True )FlagEmbedding 完整训练脚本一般包含数据加载、损失计算、评估三个模块。由于版本差异较大建议直接参考官方仓库的examples/finetune/embedder目录里面提供了带难负样本的训练入口。这里不推荐把别人的训练命令原样复制到生产环境。必须先确认自己的模型名、数据格式、指令前缀和输出维度再运行训练。5.3 训练日志怎么判断是否正常训练时主要观察两个信号。第一loss 是否在下降。MultipleNegativesRankingLoss最开始时通常会在 4 到 6 这个区间训练一段时间后降到 1 以下。如果 loss 一直不降或者出现 NaN优先检查数据里是否有超长文本、空文本以及学习率是否设置过高。第二离线检索效果是否提升。loss 下降不代表检索效果一定变好。建议在训练脚本里加入一个小型 eval 集每次 checkpoint 后计算 Recall10。如果 loss 下降但 Recall 不涨可能负样本太简单或数据噪声太多。训练输出的目录里会保存模型权重和 tokenizer。加载微调后模型时要用同一个目录不能混用原版模型和微调权重。from sentence_transformers import SentenceTransformer model SentenceTransformer(./embedding_model_finetuned) emb model.encode(发票冲红后还能抵扣吗, normalize_embeddingsTrue)6. 把微调后的 Embedding 接回 RAG 检索链路6.1 全量重建向量库这一步不能省微调后的模型和旧 Embedding 模型生成的向量分布不一致两者不能在同一个向量索引里混用。上线前必须全量重建知识库向量不能用“只对新增文档生成向量”的方式做增量替换否则新旧向量之间距离比较没有意义。重建流程从知识库导出所有 chunk。用微调后的 Embedding 模型批量生成向量。将向量写入新的 Collection 或新的向量索引。线上检索流量切到新索引。保留旧索引至少一个版本便于回滚。批量生成向量时可以控制 batch size避免 GPU 显存溢出from sentence_transformers import SentenceTransformer model SentenceTransformer(./embedding_model_finetuned) chunks [...] # 所有知识库 chunk batch [] embeddings [] for chunk in chunks: batch.append(chunk) if len(batch) 64: vecs model.encode(batch, normalize_embeddingsTrue) embeddings.extend(vecs) batch [] if batch: vecs model.encode(batch, normalize_embeddingsTrue) embeddings.extend(vecs)6.2 写入 Milvus 或本地 Faiss 索引以 Milvus 为例需要先创建 Collection并指定向量维度。BGE-M3 的维度是 1024bge-base-zh 是 768具体以模型输出为准。from pymilvus import ( connections, CollectionSchema, FieldSchema, DataType, Collection ) connections.connect(host127.0.0.1, port19530) fields [ FieldSchema(nameid, dtypeDataType.INT64, is_primaryTrue), FieldSchema(nametext, dtypeDataType.VARCHAR, max_length8192), FieldSchema(namevector, dtypeDataType.FLOAT_VECTOR, dim1024), ] schema CollectionSchema(fields) collection Collection(qa_knowledge_new, schema) data [ list(range(len(chunks))), chunks, embeddings, ] collection.insert(data) collection.create_index(vector, {index_type: IVF_FLAT, metric_type: IP, params: {nlist: 1024}})检索时要用同一种向量计算方式query_vec model.encode([query], normalize_embeddingsTrue)[0] result collection.search( data[query_vec.tolist()], anns_fieldvector, param{metric_type: IP, params: {nprobe: 16}}, limit20, output_fields[text], )6.3 在 LlamaIndex 中接入自定义 Embedding 模型如果用 LlamaIndex 搭 RAG接入自定义模型非常简单from llama_index.core import Settings from llama_index.embeddings.huggingface import HuggingFaceEmbedding Settings.embed_model HuggingFaceEmbedding( model_name./embedding_model_finetuned, embed_batch_size64, )设置好后文档索引和 Query 检索都会使用同一个embed_model。这一步最容易踩的坑是索引文档时用了微调后模型但 Query 检索时误用了默认模型导致查询向量和文档向量不在同一空间。6.4 不要丢掉 Rerank 环节微调 Embedding 能提高“正确文档是否能进 top 20”的概率但不保证正确文档一定排在第一位。生产级 RAG 仍然应该在向量召回后加一个 Rerank 模型对召回结果做精排序。推荐链路是Query - 向量召回 top50 - Rerank 精排 top5 - LLM 生成Embedding 微调和 Rerank 不是二选一。前者负责提高召回上限后者负责提高排序精度。两者结合效果通常比只做其中一项更稳定。7. 效果评估与常见问题排查7.1 构造最小离线评估集评估集不需要很大但需要覆盖真实用户 Query。建议准备 200 到 500 条真实或近似真实的 Query并为每条 Query 标注 1 到 3 个正确文档。常用指标指标说明计算方式RecallK正确文档是否出现在前 K 条结果里命中数 / 总 Query 数MRR第一个正确结果所在排名的倒数按排名取倒数后求平均Hit Rate1第一条结果是否就是正确答案命中数 / 总 Query 数评估的时候要把微调前和微调后的模型分别跑同一批评估集保留结果。不要只凭“感觉变准了”就上线。7.2 微调后常见的失败模式问题现象可能原因排查方式处理建议loss 下降但 Recall 不涨难负样本太少或太简单检查训练数据中每条 Query 的负样本数量增加难负样本构造逻辑上线后效果反而变差向量库未全量重建确认新旧向量是否混用全量重建并校验向量维度训练时显存不足batch_size 或 max_len 过大查看 GPU 显存占用降低 batch_size改用 LoRA检索时 Query 结果不对推理时和训练时指令前缀不一致对比训练和推理代码统一指令前缀和预处理逻辑负样本实际也是正确答案Qwen3 相关判断不准人工抽验负样本标签调整 Qwen3 打分 Prompt 或加入人工复核微调后通用能力下降训练数据过于单一观察泛化指标混入一定比例通用检索数据7.3 上线前回归清单上线前建议按下面清单逐项检查[ ] 训练数据和评估集是否分开评估集里没有出现训练数据[ ] Qwen3 生成的 Query 是否覆盖了真实用户高频问法[ ] 负样本是否包含至少一部分“向量相似但语义无关”的难负样本[ ] 训练脚本中 query 指令和推理脚本中 query 指令是否一致[ ] 微调后模型输出维度是否和原始模型一致[ ] 向量库是否全量重建旧索引是否可回滚[ ] 离线评估指标是否记录并对比过基线[ ] 是否保留了原 Embedding 模型和原向量索引方便快速回滚。8. 生产环境落地建议微调不是唯一的优化手段8.1 建议的优化顺序在团队资源有限的情况下RAG 优化顺序可以按下面排列先治理知识库切块和元数据加入 Query 改写解决用户口语化和指代不清引入 Rerank 模型把 top50 变 top5收集真实 badcase分析检索失败原因再用 Qwen3 构造数据微调 Embedding 模型。这套顺序的核心是先用成本低、见效快的手段把明显问题解决掉再通过微调处理更深层的语义匹配问题。如果一开始就启动 Embedding 微调很容易把切块错误、元数据缺失的问题也归因到模型上导致训练数据很脏最终效果也不稳定。8.2 建立数据回流和定期重训机制Embedding 微调不是一次性的。业务新名词不断出现用户提问方式也在变化训练数据需要持续更新。生产环境可以设计一个小闭环从线上日志采集“低分但用户点击/反馈有用的 Query”把用户反馈和 badcase 汇总到标注队列每两周或每月用 Qwen3 补充新 Query 和新难负样本重新训练 Embedding 模型并跑离线评估评估通过后全量重建向量库并灰度上线。这里的难点是“自动判断用户是否满意”。如果没有显式反馈可以用业务指标兜底例如搜索无结果率、同一会话的再提问次数等。8.3 成本控制和 LoRA 选择Embedding 模型训练成本通常远低于生成模型。但如果知识库很大向量重建的推理成本会比训练成本更高。因此训练前要预估 GPU 总时长训练后做一次“向量重建成本”评估。LoRA 微调在 Embedding 模型上的收益没有大语言模型那么夸张因为 Embedding 模型的参数量本来就小。但对于 BGE-M3 这类 5 亿参数以上的模型LoRA 仍然是显存不足时的首选。选择 LoRA 时要关注训练后是否能导出合并权重避免推理时额外依赖适配器加载逻辑。8.4 再往前走Rerank、Agentic RAG 和图谱增强Embedding 微调只是 RAG 优化的一个环节。当检索召回率已经稳定可以考虑下一步用领域数据微调一个小的 Rerank 模型替代通用 Rerank引入 Agentic RAG让模型根据用户意图主动选择多路检索在知识库中补充实体关系图谱处理“实体关系型问题”对多轮对话场景增加 Query 改写和历史上下文压缩。这些方向都需要先有“稳定可评估的检索链路”作为基座。Embedding 微调的真正价值是让基座更贴近业务而不是替代其他优化模块。最后给新手的练习建议不要一上来就微调一个大模型先用一个小型中文知识库构造 2000 条数据微调 bge-base-zh并在 Milvus 里对比微调前后 Recall10。这个闭环跑通后再逐步加深对难负样本、LoRA、Rerank 和数据回流的理解会比直接堆模块更有效。