工具调用微调为什么一接完整轨迹就开始离线更稳却线上更僵:从 State Delta Tokenization 到 Step Dropout 的工程实战
轨迹更完整不等于 Agent 线上更会走很多团队把工具调用微调从单步监督升级成完整轨迹后先看到离线分更高、回放更顺。 于是容易相信计划、观测、重试和提交喂得越全Agent 就越会做事。但线上更常见的是状态稍一变化模型就抱着旧中间态往前推动作很熟结果更僵。图 1离线轨迹更像未必代表线上更会续跑这类问题不会先表现为“不会用工具”。⚠️ 工具名常常还能选对但分支条件一变、字段顺序一换模型就沿着旧轨迹补动作甚至把失效观察继续当事实。对 Agent 来说掉的是遇到新状态时重算下一步的弹性。 真正被过拟合的往往是中间状态而不是最终答案完整轨迹数据里混着计划语句、工具观测、错误重试和临时结论。✅ 如果这些 token 被同等当作“标准答案”模型更容易学到的不是决策逻辑而是把整段状态描述原样接下去。可到了生产环境只要接口多回一个字段、排序略变或上游已修复旧轨迹就会变成错误惯性。图 2模型背下的是旧过程不一定是当前决策 只看轨迹完全一致率、步骤命中率和 JSON 可解析率会奖励“像历史一样走”却不奖励“观测变了还能换路”。于是面板不断变绿线上却开始出现重复重试、拿旧观察做提交或该回退人工却继续执行。⚙️ 先压缩状态表示再故意打断部分步骤更稳的做法是把监督目标从“复写整段轨迹”改成“根据当前状态生成下一步”。 一种方案是做State Delta Tokenization不再把完整观察原样喂回只保留会影响决策的状态增量比如新增字段、冲突槽位和动作结果。这样模型学的是变化本身而不是历史正文。defbuild_step_target(step,drop_prob0.15):deltaextract_state_delta(step.observation,step.prev_state)ifstep.index0andrandom.random()drop_prob:returnNonereturn{state_delta:delta,tool_name:step.tool_name,tool_args:step.tool_args,next_action:step.next_action,}再往前走一步可以在训练阶段加入Step Dropout。 它会随机拿掉少量中间步骤让模型在上下文不完美时也得自己补推理而不是机械续写上一轮。这样改完后离线分数不一定最高但恢复能力通常会抬起来。图 3把状态压扁并适度丢步才能逼出真正的续跑能力 发布门槛别只看轨迹完全一致率如果发布门槛只盯trajectory exact match完整轨迹监督往往最讨喜。 可一旦把分支漂移恢复率、旧观察误提交率和人工接管前的回退成功率一起拉进面板排名经常会反过来。线上真正昂贵的不是少走一步而是在错误分支上把后续动作越做越满。方案轨迹完全一致率分支漂移恢复率旧观察误提交率常见结果完整轨迹等权监督93.4%61.8%7.2%回放很漂亮线上更僵State DeltaStep Dropout90.7%84.9%1.9%轨迹略短但续跑最稳只做State Delta89.8%77.1%3.4%比完整轨迹稳但仍怕长链依赖更可靠的发布方式是把“像不像历史轨迹”和“状态变了还能不能重算”拆成两条门槛。 只要后者开始掉就不该因为前者更好看而继续放行否则发到生产环境的只会是一个更会背流程的 Agent。 接下来拉开差距的不是谁堆了更多轨迹笔者认为接下来 3 到 6 个月工具调用训练真正的分水岭不会是“谁收集了更多完整轨迹”而是“谁先把轨迹监督改造成状态驱动监督”。 当模型被迫围绕state delta、关键参数和下一步动作学习它遇到新分支时才更像在做决策而不是复读昨天的路径。图 4上线前先看续跑能力再看回放是否漂亮如果当前微调链路还把整段tool trace当成黄金答案那离线稳定很可能只是把历史上下文背得更熟。✅ 真正值得追的不是更长轨迹而是更强的状态恢复力。你们的发布门槛里把续跑能力记账了吗