ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Agentic合成训练数据:多智能体协作在SFT、mid-training与RL中的实操指南

Agentic合成训练数据:多智能体协作在SFT、mid-training与RL中的实操指南 1. 为什么“合成数据”这件事值得单独拎出来讲做模型训练的人都有一个共同的痛高质量标注数据永远不够用。你可能有几万条真实业务日志但真正能拿来喂给 SFT 的、格式规整、逻辑自洽、答案可靠的样本可能连十分之一都不到。更别提 mid-training 阶段需要的大规模领域语料以及 RL 阶段需要的偏好对比数据——这两类数据对“多样性”和“区分度”的要求比 SFT 还要苛刻。过去我们处理这个问题靠的是“人海战术 规则脚本”写一堆正则去清洗、雇标注团队去改写、用模板去扩充。这套打法在数据量小的时候还能撑住一旦到了十万、百万级别成本直接爆炸而且一致性极差——三个标注员能给你写出五种风格的答案。agentic 方式合成 / 清洗训练数据本质上是用“智能体编排”的思路把数据生产从“流水线”升级成“项目组”。你不是在跑一个固定的脚本而是在指挥一组有分工、有工具、有反馈回路的智能体有的负责生成种子样本有的负责批判和打分有的负责改写和修复有的负责去重和多样性控制。这套方法在 SFT、mid-training、RL 三个阶段都能用只是侧重点不同。这篇文章适合谁看如果你正在做以下任何一件事那接下来的内容应该能帮你省下不少试错时间手头有少量真实数据想合成大批量高质量 SFT 样本要做领域 mid-training但公开语料质量参差不齐需要清洗和重构在搞 RLHF / DPO偏好数据不够想用智能体合成对比样本已经试过用大模型直接“批量生成”但发现质量不稳定、重复率高、格式跑偏我踩过的坑包括但不限于生成的数据看着像那么回事一训练就发现模型学会了“正确的废话”清洗脚本把有价值的长尾样本全过滤掉了RL 偏好对里正负样本差异太小模型根本学不到区分度。下面把这些经验拆开讲。2. 整体设计思路把数据生产当成一个多智能体协作项目2.1 核心思路从“生成-过滤”到“生成-批判-修复-验证”闭环大多数人第一次尝试合成数据走的是最直觉的路线写一个 prompt让大模型批量生成然后用规则或另一个模型过滤一遍。这个路线的问题在于生成和过滤是割裂的。生成模型不知道过滤标准过滤模型没机会让生成模型改。agentic 方式的核心变化是引入角色分工和反馈回路。我常用的最小可行架构是四个角色角色职责典型实现生成者根据种子和指令产出候选样本强生成模型 多样化 prompt批判者按维度打分并给出修改意见评分模型或规则引擎修复者根据批判意见改写样本同一生成模型带反馈上下文验证者最终校验格式、事实性、去重规则 嵌入相似度这个闭环跑一轮相当于把“生成-过滤”重复了多次但每次修复都带着具体的批判意见而不是盲目重试。实测下来同样数量的种子闭环产出的可用样本率能从 30% 左右提到 70% 以上。2.2 三个阶段的数据需求差异SFT、mid-training、RL 对数据的要求完全不同不能用同一套 prompt 打天下。SFT 阶段要的是“指令-回答”配对重点是回答的正确性、格式规范、风格一致。这个阶段的数据量通常在几千到几万条质量比数量重要。合成时我会让批判者重点盯三个维度指令是否清晰、回答是否直接回应指令、有没有编造事实。mid-training 阶段要的是大规模领域语料重点是覆盖面、多样性、领域术语密度。这个阶段数据量可能到几十万到上百万条单条质量要求可以放宽但整体分布要均匀。合成策略偏向“从种子文档出发做改写、扩写、风格迁移”而不是从零生成。RL 阶段要的是偏好对或带奖励信号的样本重点是正负样本的区分度。这里最容易犯的错是负样本太“假”——一眼就能看出是错的模型学不到细粒度偏好。agentic 方式在这里的价值是让批判者生成“高质量负样本”看起来合理但有细微缺陷的回答比如逻辑跳跃、遗漏关键条件、语气不当。2.3 为什么不用单一模型端到端搞定有人会问现在模型这么强直接让它“生成并自我检查”不就行了我试过不行。原因是自我检查存在盲区。同一个模型生成的错误它自己往往看不出来因为它的偏好和生成时的分布是一致的。拆成多个角色后批判者可以用不同的 prompt、不同的模型、甚至不同的温度设置形成“视角差异”。这个差异是发现问题的关键。我通常会让生成者用较高温度保证多样性批判者用低温度保证评分稳定修复者用中等温度平衡创造性和忠实度。3. 核心细节解析每个角色的实操要点3.1 生成者种子设计比 prompt 技巧更重要生成者的输出质量八成取决于种子质量。我见过太多人花大量时间调 prompt却用一堆随便找的种子结果生成的数据千篇一律。种子的设计原则是**“少而精覆盖关键维度”**。以 SFT 为例如果你要做客服场景的指令数据种子应该覆盖不同问题类型咨询、投诉、退换、不同情绪平静、愤怒、焦急、不同复杂度单轮、多轮、需要追问。每个维度下放 3-5 个真实样本作为种子比放 100 个同质样本有用得多。生成时的 prompt 结构我一般这样组织你是一个数据合成助手。基于以下种子样本生成 {n} 条新的指令-回答对。 种子样本 {seed} 要求 1. 保持与种子相同的任务类型和回答风格 2. 在问题表述、具体细节、回答结构上做变化 3. 不要重复种子中的具体实体和数字 4. 输出格式为 JSON字段为 instruction 和 response 多样性提示{diversity_hint}这里的diversity_hint是动态的每一批生成时从预设的维度池里随机抽比如“这次侧重多轮追问”“这次侧重包含数字计算”“这次侧重口语化表达”。这个小技巧能显著降低批次内的重复率。注意生成者不要一次要太多。我实测单次生成 5-10 条时质量最稳超过 20 条后后半部分明显敷衍。宁可多跑几轮也不要一次贪多。3.2 批判者评分维度要可操作不能太抽象批判者最容易犯的错是评分标准太虚比如“回答质量高不高”“逻辑好不好”。这种标准模型没法稳定执行不同批次打分尺度会漂移。我的做法是把评分拆成可观察的具体维度每个维度 1-5 分并给出明确的扣分理由。SFT 场景我常用这四个维度指令遵循度回答是否直接回应了指令的核心诉求有没有答非所问事实一致性回答中的事实陈述是否与种子或常识一致有没有编造格式规范性是否符合要求的输出格式长度是否合理表达自然度是否像真人写的有没有明显的模板痕迹或重复用词批判者的输出不只是分数还要有具体的修改建议。比如“第三句话的事实与种子矛盾建议改为……”“回答开头太啰嗦建议直接给出结论”。这些建议会作为修复者的输入所以越具体越好。{ score: 3, dimensions: { instruction_following: 4, factual_consistency: 2, format: 5, naturalness: 3 }, issues: [ 回答中提到的退款时限与种子中的政策不一致, 第二段有重复表述 ], suggestions: [ 将退款时限改为种子中的 7 个工作日, 合并第二段的重复内容 ] }3.3 修复者带着反馈改而不是重新生成修复者的关键区别是它拿到的是原始样本 批判意见而不是从零开始。这样改出来的样本保留了原来的合理部分只针对问题点修改效率和质量都更高。修复者的 prompt 要强调“最小改动原则”以下是一条待修复的样本和批判意见。请根据意见做最小必要的修改保留原文中合理的部分。 原始样本 {original} 批判意见 {critique} 要求 1. 只修改被指出的问题不要重写整个回答 2. 保持原有的格式和风格 3. 输出修复后的完整样本实测下来修复者一轮能把 60% 左右的低分样本拉到可用水平。剩下的要么是种子本身有问题要么是问题太严重直接丢弃比修复更划算。3.4 验证者去重和多样性控制是最后一道关验证者做的是机械但必不可少的工作格式校验、长度过滤、嵌入去重、多样性统计。去重我用的是嵌入相似度 阈值的方式。把所有样本过一遍嵌入模型两两算余弦相似度超过 0.95 的视为重复保留分数高的那条。阈值设 0.95 而不是 0.9是因为太激进会误杀合理的相似样本——比如同一类问题的不同问法相似度高但都是有价值的。多样性统计我关注两个指标指令首词分布和回答长度分布。如果发现 80% 的指令都以“请”开头或者回答长度集中在某个区间说明生成时多样性控制没做好需要调整diversity_hint重新生成一批。4. 完整实操流程从种子到可用数据集4.1 环境准备与工具选型这套流程不依赖特定框架用 Python 脚本 任意模型 API 就能跑。我自己的技术栈是这样的编排层纯 Python用concurrent.futures做并发不引入重型框架模型调用统一封装一个call_model(prompt, temperature)函数方便切换模型存储中间结果存 JSONL每行一条方便断点续跑去重sentence-transformers做嵌入numpy算相似度矩阵进度监控tqdm看进度关键节点打日志为什么不直接用 LangChain 之类的框架因为这套流程的逻辑很直白引入框架反而增加调试成本。用纯 Python 写每个环节的数据流都看得见出问题好定位。4.2 分阶段参数设置不同阶段的核心参数差异很大我整理了一张对照表参数SFTmid-trainingRL单批生成数5-1020-505-10生成温度0.8-1.00.9-1.10.7-0.9批判阈值4 分以上保留3 分以上保留正负对区分度 1 分修复轮次最多 2 轮最多 1 轮最多 2 轮去重阈值0.950.900.95目标可用率70%85%60%mid-training 的去重阈值设得更低是因为这个阶段要的是覆盖面适度的相似样本可以接受。RL 阶段对区分度要求高所以批判时专门加了一个“正负样本差异度”维度。4.3 实操现场跑一轮 SFT 数据合成的完整记录我拿一个客服场景的实际项目举例。种子是 20 条真实客服对话目标是合成 2000 条可用 SFT 样本。第一步种子聚类。用嵌入把 20 条种子聚成 5 类每类选 2 条代表作为生成种子。这样做的目的是保证生成时每类都有覆盖不会偏向某一类。第二步批量生成。5 类种子每类跑 40 批每批生成 8 条理论产出 1600 条。实际因为并发限制和失败重试跑了大约 2 小时拿到 1520 条原始样本。第三步批判打分。1520 条过批判者耗时约 40 分钟。结果分布5 分 210 条4 分 580 条3 分 490 条2 分及以下 240 条。第四步修复。把 3 分及以下的 730 条送修复者一轮后 420 条升到 4 分以上剩余 310 条丢弃。第五步验证去重。可用样本合计 210 580 420 1210 条去重后剩 1080 条。最终可用率 1080 / 1520 ≈ 71%符合预期。整个流程跑下来人工介入只有两次一次是检查种子聚类是否合理一次是抽查最终样本质量。其余全自动。4.4 关键代码骨架生成环节的并发骨架大概长这样import json from concurrent.futures import ThreadPoolExecutor, as_completed def generate_batch(seed, diversity_hint, n8): prompt build_generation_prompt(seed, diversity_hint, n) raw call_model(prompt, temperature0.9) return parse_json_list(raw) def run_generation(seeds, hints, n_per_batch8, batches_per_seed40): tasks [] for seed in seeds: for i in range(batches_per_seed): hint hints[i % len(hints)] tasks.append((seed, hint)) results [] with ThreadPoolExecutor(max_workers8) as executor: futures {executor.submit(generate_batch, s, h, n_per_batch): (s, h) for s, h in tasks} for future in as_completed(futures): try: results.extend(future.result()) except Exception as e: log_error(futures[future], e) return results批判和修复的骨架类似只是 prompt 不同。验证环节的去重import numpy as np from sentence_transformers import SentenceTransformer def dedup(samples, threshold0.95): model SentenceTransformer(all-MiniLM-L6-v2) texts [s[instruction] s[response] for s in samples] embeddings model.encode(texts, normalize_embeddingsTrue) sim_matrix embeddings embeddings.T keep [] dropped set() for i in range(len(samples)): if i in dropped: continue keep.append(samples[i]) for j in range(i 1, len(samples)): if j not in dropped and sim_matrix[i][j] threshold: dropped.add(j) return keep注意去重时用“指令回答”的拼接嵌入而不是只用指令。因为同一指令可能有多个合理回答只用指令去重会误杀有价值的多样性样本。5. 常见问题与排查技巧实录5.1 生成的数据“看着对一训就废”这是最常见的问题。表现是人工抽查觉得样本没问题但模型训练后表现反而变差或者学会了奇怪的表达习惯。排查思路分三层。第一层看分布统计生成样本的指令长度、回答长度、词汇丰富度和真实数据对比。如果生成数据的词汇丰富度明显低于真实数据说明模型在“偷懒”反复用同样的表达。第二层看长尾把生成样本按指令类型聚类看有没有某些类型被过度生成某些类型几乎没覆盖。第三层看事实随机抽 50 条人工核对事实性错误率。如果错误率超过 5%说明批判者的事实校验不够严。我遇到过一次典型情况生成的客服回答里80% 都以“非常抱歉给您带来不便”开头。这就是典型的模板化模型学到了这个开头就以为万事大吉。解决办法是在批判维度里加一条“开头多样性”并在生成时把“避免使用常见套话”写进 prompt。5.2 批判者打分尺度漂移不同批次之间打分标准不一致导致有的批次整体偏高有的整体偏低。这个问题在批判者用大模型时特别明显。解决办法是给批判者提供锚点样本。在批判 prompt 里放 2-3 个已知分数的示例让模型参照打分。锚点样本要覆盖高分、中分、低分三档并且分数理由要写清楚。这样模型的打分尺度会被锚定在一个稳定区间。另一个技巧是分批校准。每跑 500 条抽 20 条人工核对分数如果发现偏差超过 0.5 分就调整锚点样本重新校准。5.3 RL 偏好对区分度不够RL 阶段最头疼的是正负样本太容易区分。比如正样本是完整正确的回答负样本是明显错误的回答模型一眼就能看出哪个好学不到细粒度偏好。agentic 方式在这里的解法是让批判者专门生成“困难负样本”。具体做法是先让生成者产出一个高质量回答作为正样本然后让修复者基于这个正样本做“最小破坏”——改一个关键条件、删一个必要步骤、换一个不恰当的语气词。这样产出的负样本和正样本差异很小但确实有优劣之分。我常用的“最小破坏”指令包括把回答中的具体数字改成一个相近但错误的数字删掉回答中的一个关键前提条件把正式语气改成过于随意的语气在正确回答后加一句无关的废话这些负样本的区分度明显更好实测 RL 训练时模型对这类样本的学习信号更强。5.4 常见问题速查表问题现象可能原因排查方法解决方向生成样本重复率高种子太单一 / 温度太低统计嵌入相似度分布增加种子多样性 / 提高温度批判分数整体偏高锚点样本缺失人工核对 20 条补充锚点样本重新校准修复后质量没提升批判意见太抽象检查批判输出要求批判给出具体修改建议去重后样本量骤降阈值太低看相似度直方图调高阈值到 0.95RL 负样本太假破坏程度太大人工对比正负样本改用最小破坏策略训练后模型表达单一生成时模板化统计开头词分布prompt 中加反套话要求5.5 几个我踩过的坑坑一批判者用太强的模型反而不好。我试过用最强的模型做批判结果它太“宽容”什么样本都给高分理由是“虽然有小问题但整体不错”。后来换成一个中等模型打分反而更严格、更稳定。强模型适合做生成批判用中等模型性价比更高。坑二修复轮次不是越多越好。我试过让修复者跑三轮结果发现第三轮开始出现“过度修改”把原本合理的部分也改动了引入了新问题。两轮是甜点超过两轮收益递减。坑三mid-training 数据不要过度清洗。一开始我用 SFT 的标准去清洗 mid-training 语料把大量“看起来不完美但包含领域知识”的样本过滤掉了。后来意识到 mid-training 要的是知识密度不是格式完美放宽标准后模型在领域任务上的表现反而更好。坑四RL 偏好对要控制长度差。如果正样本明显比负样本长模型可能会学到“长就是好”的偏见。我在验证环节加了一个长度差检查正负样本长度差超过 30% 的配对直接丢弃。6. 不同阶段的策略微调与扩展思路6.1 SFT 阶段质量优先闭环要短SFT 数据量需求相对小但对质量要求最高。我的策略是短闭环、严批判、多轮修复。生成一批 5-10 条立刻批判低分的立刻修复修复后立刻验证。整个链路短反馈快质量可控。这个阶段我还会做一件事人工抽检 反馈回灌。每跑完一批人工抽 10 条看把发现的问题总结成新的批判维度加到下一批的批判 prompt 里。这样批判标准会随着项目推进越来越精准。6.2 mid-training 阶段规模优先清洗要克制mid-training 的数据量可能是 SFT 的几十倍这时候逐条批判和修复的成本太高。我的策略是粗筛 抽样精修。粗筛用规则和轻量模型长度过滤、语言检测、重复段落检测、敏感词过滤。这些规则能过滤掉明显不合格的样本成本极低。剩下的样本按 5% 抽样做精修精修结果用来评估整体质量如果抽样合格率低于 80%就调整粗筛规则重新跑。这个阶段还有一个重点是领域术语的覆盖。我会统计生成语料中的领域术语分布和真实领域文档对比如果某些术语出现频率明显偏低就在生成 prompt 里加进去定向补充。6.3 RL 阶段区分度优先负样本要“像”RL 阶段的数据量介于 SFT 和 mid-training 之间但对样本的“信息量”要求最高。我的策略是正样本精挑、负样本巧造、配对严审。正样本从 SFT 的高分样本里选确保质量。负样本用前面说的“最小破坏”策略生成。配对时检查三个指标长度差不超过 30%、正样本分数比负样本高至少 1 分、两者在嵌入空间的距离在合理区间太近说明差异太小太远说明差异太大。这个阶段我还试过一个扩展思路用批判者的分数作为奖励信号。批判者给每个样本打的分可以直接作为 RL 的奖励省去单独训练奖励模型的成本。实测下来用批判分数做奖励模型收敛速度和用专门奖励模型差不多但省了一大笔训练开销。6.4 跨阶段的数据复用三个阶段的数据不是孤立的。SFT 阶段产出的高质量样本可以作为 mid-training 的种子mid-training 产出的领域语料可以从中抽取指令对用于 SFTRL 阶段的正样本可以回流到 SFT 数据集。我通常会在项目开始时建一个统一的数据池所有阶段产出的样本都带标签存进去标签包括来源阶段、质量分数、领域分类。这样后续任何阶段需要数据都可以从池子里按条件筛选避免重复劳动。7. 一些关于成本和效率的实测数据最后分享几组我实测的数据供你做预算和排期参考。SFT 合成2000 条目标样本种子 20 条总耗时约 4 小时含生成、批判、修复、验证模型调用成本约 15 美元。最终可用 1080 条单条可用成本约 0.014 美元。对比人工标注单条 1-2 美元的成本合成方式的成本优势是数量级的。mid-training 清洗10 万条原始语料粗筛耗时 20 分钟抽样精修 5000 条耗时 1 小时总成本约 8 美元。最终保留 8.2 万条保留率 82%。RL 偏好对合成5000 对目标正样本从 SFT 池抽取负样本生成 配对审核耗时约 3 小时成本约 12 美元。最终可用 3200 对可用率 64%。这些数字会随模型价格和任务复杂度波动但量级关系是稳定的合成数据的成本主要花在批判和修复环节生成本身反而便宜。所以优化成本的关键是提高批判的准确率减少无效修复。提示如果你的预算有限优先保证批判环节的质量生成环节可以用便宜模型。批判准了修复才有方向整体可用率才上得去。这套 agentic 数据合成的方法我从去年开始在自己的项目里反复迭代目前已经稳定用在三个不同领域的训练任务上。最大的体会是数据生产的瓶颈从来不是生成能力而是判断能力。知道什么是好数据、能稳定地识别出坏数据、能给出具体的修改方向这三件事做到了合成数据的质量就有保障。智能体编排的价值就是把这三种能力拆开、专业化、形成闭环。
返回列表