轨迹微调

轨迹微调蓝图。

目的

为什么用智能体自身的最佳轨迹来训练它,会教会它编造本应等待工具返回的输出?

智能体轨迹交织着两类作者的内容。模型编写推理和工具调用,环境则编写所有返回内容,从文件内容到测试失败报告。在通过准入的轨迹上进行监督微调,是让模型提出更好动作的最直接方式,但训练所用的目标是流水线标记为训练目标的所有 token。如果将环境的 token 作为训练目标,模型就会学会自行编写观测,而不是交出回合控制权。如果只用顺利完成的运行来训练,模型就从未见过自身错误造成的状态,因此错误会随着每个回合不断累积。如果只用一套固定的工具模式来训练,模型就会记住参数名称,而不是读取眼前的模式。这些失败在离线评估中都看似进步,因为验证损失下降了,问题只有在智能体实际运行时才会显现。工程上必须严谨地决定哪些内容应当进入权重(操作流程,例如调用哪个工具、如何解读错误以及何时停止),哪些内容必须留在权重之外(上下文中的契约和运行时中的检查)。微调改变的是每项提议通过运行时关卡的可能性,而不会改变任何 H·S·A 暴露,因此,前面各部分所学会约束的执行跨度、状态和权限,都完全保持原样。

学习目标
  • 区分微调能够修复的失败与应当通过上下文、工具模式或运行时解决的失败。
  • 将包含工具调用的多轮轨迹序列化为模型服务时使用的同一消息模板,包括并行调用和推理处理。
  • 构建观测损失掩码,使训练涵盖推理、工具调用和回合结束 token,同时将提示和观测保留为上下文。
  • 解释序列打包、损失归一化和位置处理如何导致信息跨轨迹泄漏,或使策略偏向较长的运行。
  • 分析暴露偏差如何随执行跨度增长,并设计能将其限制在一定范围内的同策略数据采集方案。
  • 针对给定的智能体角色和回滚要求,在上下文蒸馏、教师蒸馏和适配器之间做出选择。
  • 根据经验证的任务成功率、函数调用准确率、留出的工具族以及能力保留情况来评估微调后的智能体,而不是依据验证损失。

微调能够改变什么

H·S·A 定位图,所有轴均未点亮,原点以紫色高亮显示。

微调重塑每次模型调用,但将所有暴露都留给运行时处理。

一个编程智能体已经通过了 能力差距诊断 的分诊。它的上下文完整,工具模式明确无歧义,沙箱运行正常,但它仍会以一种可辨识的方式在某类任务上失败。一次测试失败后,它会将同一条命令重新运行三次,然后编辑一个从未读取过的文件。模型之下各层的所有修复都未能消除这一失败,因此,经验证轨迹后训练原则(16)允许采用最后一级修复。轨迹整理 的筛选流水线已经准入了一批针对这些任务的经验证轨迹,其中包括从测试失败中恢复的运行。本章要探讨的问题是:在这批语料上训练能够改变什么,又必须保留什么。

监督微调(SFT)调整模型的权重,使模型在给定相同上下文时,为已准入轨迹中包含的词元赋予更高的概率。模型在一次调用中所做的一切,都是两个输入的函数:权重,以及为该次调用组装的上下文(调用契约)。微调只能改变前者。这一事实将智能体知识划分为三个归属位置,概括见 表 1。规程是跨任务成立且变化缓慢的知识,例如在编辑前阅读堆栈跟踪、在修补文件前检查文件,或在封闭测试通过后停止。规程是权重能够学习的内容。契约是随部署或调用而变化的事实,例如当前的工具模式、任务规范、工作区布局,以及为这条轨迹授予的权限。契约保留在上下文中,因为记住了上个月模式的模型会输出上个月的参数。强制执行涵盖即使模型出错也必须成立的一切,例如模式验证、授权、沙箱隔离和核验。强制执行保留在运行时中,这正是不变量闭包原则(不变闭包原则)为其确定的位置。

表 1: 智能体知识的归属位置:智能体所需知识的三个归属位置,以及监督训练能够和不能够在这些位置之间迁移的内容。
归属位置 应存放的内容 归属于此的原因 微调对其的作用
权重 规程:选择哪个工具、如何解读错误、何时停止 跨任务成立,因此学习一次即可在每次调用中获益 直接改变它
上下文 契约:工具模式、任务规范、工作区事实、授予的权限范围 随部署或调用而变化,因此记忆这些内容会过时 必须教会模型持续读取它,而非替代它
运行时 强制执行:验证、授权、隔离、核验 即使模型出错也必须成立,因此不能依赖模型 不改变它;运行时检查微调后的模型提出的每个方案

这一划分澄清了一种看似诱人却错误的说法,即微调是将提示编译到权重中。提示中的一部分属于规程(少样本恢复示例、风格规则、步骤检查清单),将其迁移到权重中可以在每一轮节省词元,节 1.7 将这一做法发展为一种技术。提示的其余部分属于契约,移除它会让模型只能猜测当前任务的事实。微调迁移的只有规程。对通用助手进行监督微调的观察也指向同一结论。一个规模小、经过精心筛选的指令集,对模型格式和交互风格的改变远大于对其底层知识的改变 (Zhou 等 2023年);而对于智能体而言,格式和交互协议构成了规程的很大一部分。

Zhou, Chunting, Pengfei Liu, Puxin Xu, Srini Iyer, Jiao Sun, Yuning Mao, Xuezhe Ma, 等. 2023年. 《LIMA: Less Is More for Alignment》. Advances in Neural Information Processing Systems (NeurIPS 2023) 36.

由于只有权重发生变化,微调后的模型提出的每个方案仍须经过第二部分至第四部分中的预算、日志、边界约束和关卡,而微调改变的是方案通过这些约束的比率。本章其余内容将按照数据流动的顺序,介绍产生这一变化的流水线。首先,必须将轨迹记录为词元序列(节 1.2);损失必须针对模型将要写出的词元(节 1.3);多条轨迹必须能够共享一个批次,而不相互污染(节 1.4)。随后,基于准入数据的训练会遇到其结构性局限,即暴露偏差(节 1.5),以及最常见的隐蔽失效,即模式记忆(节 1.6)。蒸馏(节 1.7)和适配器(节 1.8)决定训练数据从何而来,以及训练结果如何部署;评估(节 1.9)则决定是否发布。

轨迹序列化

轨迹日志 实现持久化的轨迹日志是一组带时间戳的事件:任务到达,模型输出推理和两个工具调用,智能体运行框架分派这两个调用,结果乱序返回,然后下一次模型调用开始。模型从未见过这份日志。它看到的是通过聊天模板逐轮呈现的消息序列,在提供服务时也将看到相同的模板。序列化将日志还原为完全相同的序列,本节描述的每一种训练缺陷,都源于训练所呈现的内容与服务时所呈现的内容不一致。

使用服务时的模板进行训练

智能体模型通过包含四种角色的函数调用消息格式提供服务(调用契约)。系统消息承载任务契约和工具模式。用户消息承载任务。助手消息承载推理以及一个或多个工具调用,每个调用都有一个调用标识符。工具消息承载结果,每条消息都标注其所响应调用的标识符。一个调试轮次的训练示例,其示意形式如下:

<|system|> task contract; schemas for read_file(path), run_tests(target) <|end|>
<|user|> Fix the failing test in auth/session.py <|end|>
<|assistant|> <|reasoning|> Read the module, then reproduce. <|end_reasoning|>
  <|call id=c1|> {"name": "read_file", "arguments": {"path": "auth/session.py"}} <|end_call|>
  <|call id=c2|> {"name": "run_tests", "arguments": {"target": "tests/test_session.py"}} <|end_call|>
<|end_turn|>
<|tool id=c1|> ...file contents... <|end|>
<|tool id=c2|> FAILED test_refresh: KeyError: 'exp' <|end|>
<|assistant|> ...

这个模板有三个细节决定了模型学到什么。首先,角色边界和调用边界使用分词器词表中的保留词元,而绝不是诸如 Observation: 这样的文本字符串。由普通词元构成的边界可能被模型在推理过程中意外生成,导致模型提前结束自己的回合,或开启一条伪造的工具消息。保留词元使运行时解析器无需猜测就能识别边界。但它无法阻止指令与数据共享同一词元流,因此,模型底层的约束机制(原则 10)仍然支配着每一项操作。

其次是并行调用。当助手在一个回合中发出多个调用时,运行框架可能并发调度这些调用,并以任意顺序接收结果。序列化样本必须按照服务运行框架放置工具结果的顺序排列结果,并以调用标识符关联,因为在按调用顺序排列结果的样本上训练的模型,会错误地归属按完成顺序到达的结果。同一回合内的调用在语义上没有先后顺序,因此,流水线可以在不同训练样本中打乱这些调用的顺序,防止模型学到虚假的序列关系。

第三是跨回合推理。不同服务模板在组装下一次调用时,对是否将先前回合的推理保留在上下文中的处理方式不同。有些会保留;许多则会将其丢弃,以节省上下文空间(编排下一次调用)。训练必须与此保持一致。如果服务时丢弃先前的推理,而训练样本却保留它,那么样本中每个后续回合都会以部署后的模型永远看不到的文本为条件,模型也就会学着依赖这些文本。当服务时丢弃推理内容时,忠实的序列化方式是为每个助手回合生成一个样本,每个样本的前缀都与实际服务时完全一致。这种选择会带来以词元数衡量的成本。一条包含 \(H\) 个回合的轨迹会变成 \(H\) 个前缀相互重叠的样本,因此训练词元数大致按 \(H^2/2\) 增长,而非 \(H\)。如果每个回合增加的词元数相近,那么这 \(H\) 个样本合计包含的词元数约为单条轨迹的 \((H+1)/2\) 倍;对于一条三十回合的轨迹,这一倍数为 \((30+1)/2 = 15.5\),因此,长时程语料可能使训练计算量增加一个数量级。

因果性与证据

因果单调性:对于每个决策步骤 \(k\),若其开始于时刻 \(T_k\),则序列化前缀 \(\mathbf{x}_{<k}\) 只能包含 \(T_k\) 之前已存在于模型上下文中的状态。

序列化轨迹还必须遵守时间顺序。如果流水线在事后改进样本,例如将最终补丁添加到系统提示词中、列出智能体在后期才发现的工具,或插入根据失败分析得出的提示,就会让早期决策获得当时尚不存在的信息。注意力机制会发现这条捷径,验证损失随之下降,而部署后的策略却会失败,因为它的上下文中没有未来信息。页边栏中陈述的因果单调性正是防止这种情况的规则,而且可以依据日志中的时间戳以机械方式检查。

模型声称自己已完成任务,并不具有任何证据效力(闭合证据等级)。进展的证据来自执行留下的痕迹,例如退出码、编译器诊断信息和测试结果,因此序列化必须保留这些证据。如果流水线删除非零退出码、剥离堆栈跟踪,或用措辞温和的摘要替换错误,就恰好移除了模型学习故障恢复所需的词元。流水线应当移除的是不携带有效信号的噪声,例如终端转义码、进程标识符和实际时钟时间;对于过长的输出,应予以折叠,使命令行和最终错误信息都得以保留。统摄这些要求的规则是:按照运行时在服务过程中呈现给模型的形式序列化每条观测,也就是经过清理和截断的 终端输出净化 和 观测流截断,而不是工具写出的原始字节。图 1 展示了从事件日志到训练序列的完整路径。

图 1: 轨迹序列化流水线:轨迹日志经过四轮处理,成为由角色分隔符划分的 token 序列。该流水线将事件按因果顺序排序并拒绝事后追加的内容,按照运行时在提供服务时采用的方式清理并折叠观测,插入保留的角色分隔符,并将推理与工具调用分离,以便损失掩码分别作用于二者。

当序列化出错时,得到的策略会以 Fail-Plausible 故障模型 所描述的方式发生看似合理的失败。它会输出流畅、自信的 token,而不是停止。只需一个偏移一位的错误,将工具消息的起始分隔符归入助手片段,就足以让模型学会自行开启工具消息;下一节将说明,这是智能体微调中破坏性最强的故障。序列化决定存在哪些 token,以及它们由谁写入;损失掩码决定训练模型生成其中的哪些 token。

观测损失掩码

一个团队使用聊天数据的默认方案,在几千条获准纳入训练的调试轨迹上进行微调,对系统提示之后的每个 token 计算交叉熵损失。验证损失持续下降。在智能体运行框架中,微调后的模型输出一条测试命令,随后不停顿地写出一份看似合理的 pytest 报告,读取自己的报告,并修复一个并不存在的缺陷。运行框架收到的是一个冗长的助手回合,直到上下文耗尽,也没有收到可供派发的工具调用。数据本身没有任何问题。损失作用于错误的 token。

带掩码的目标函数

一条序列化轨迹 \(X = (x_1, \dots, x_T)\) 包含来自四种来源的 token。提示 token(\(\mathcal{T}_{\text{prompt}}\))是系统消息和用户消息。观测 token(\(\mathcal{T}_{\text{observation}}\))是环境返回的全部内容。推理 token(\(\mathcal{T}_{\text{rationale}}\))和动作 token(\(\mathcal{T}_{\text{action}}\))是模型写入的内容,其中动作包括工具调用,以及将控制权交还运行时的回合结束 token。训练损失是带掩码的交叉熵:

\[\mathcal{L}_{\text{SFT}}(\theta) = -\frac{1}{N_{\text{active}}} \sum_{t=1}^T m_t \cdot \log P_\theta(x_t \mid x_{<t}), \qquad N_{\text{active}} = \sum_{t=1}^T m_t\]

其中,掩码 \(m_t \in \{0, 1\}\) 标记哪些位置是训练目标:

\[m_t = \begin{cases} 1 & \text{if } x_t \in \mathcal{T}_{\text{rationale}} \cup \mathcal{T}_{\text{action}}, \\ 0 & \text{if } x_t \in \mathcal{T}_{\text{prompt}} \cup \mathcal{T}_{\text{observation}}. \end{cases}\]

该损失相对于 logits \(z_t\)(位于位置 \(t\))的梯度为

\[\frac{\partial \mathcal{L}_{\text{SFT}}}{\partial z_{t, v}} = \frac{m_t}{N_{\text{active}}} \left( P_\theta(x_t = v \mid x_{<t}) - \mathbf{1}\{x_t = v\} \right),\]

因此,被掩码屏蔽的位置本身不贡献误差信号。但它并未从训练中消失。无论是否被掩码屏蔽,每个先前的 token 都通过注意力保留在上下文中,后续动作产生的梯度会沿注意力路径反向传播,进入模型所读取的观测的表示。掩码不会对模型隐藏环境。它改变了模型获得奖励的依据:从预测环境转向根据环境采取行动。图 2 展示了一条轨迹上的掩码,以及它消除的两种风险。

图 2: 观测损失掩码:一条轨迹的六个 token 片段上的掩码 \(m\)。推理、工具调用和补救调用的掩码值为 \(m_t = 1\),并向权重传递梯度。系统提示、用户指令和环境观测的掩码值为 \(m_t = 0\),仅作为上下文。右侧面板列出了掩码消除的两种无掩码训练风险:模拟环境输出,以及调用参数上的梯度被稀释。
Definition 1.1: 观测损失掩码

观测损失掩码 是作用于序列化轨迹的逐词元训练掩码 \(m_t \in \{0, 1\}\),仅对策略写出的词元(其推理、工具调用及回合结束词元)计算损失,并将提示和环境观测保留为上下文,同时采用 \(m_t = 0\)。

  1. 意义:使每一次梯度更新都针对动作提议,并消除预测工具输出的激励,否则这种激励会教会模型自行编写观测,而不是交出回合控制权。
  2. 区别:标准语言模型训练会对每个词元计算损失,而掩码目标将环境的词元视为条件输入,而非需要复现的文本。
  3. 常见陷阱:将回合结束词元与其后的观测一并掩蔽,导致策略无法获得有关何时停止的训练信号,并在部署时产生失控生成。

形式化损失目标与梯度动力学

形式上,对于长度为 \(T\) 的智能体轨迹,其监督微调目标由掩码交叉熵定义: \[ \mathcal{L}_{\text{SFT}}(\theta) = -\frac{1}{\sum_{t=1}^T m_t} \sum_{t=1}^T m_t \log p_\theta(x_t \mid x_{<t}) \] 其中,\(m_t \in \{0, 1\}\) 是一个二值词元掩码,用于标记词元 \(x_t\) 是否受梯度反向传播约束: \[ m_t = \begin{cases} 1 & \text{if } x_t \in \tau_{\text{thought}} \cup \tau_{\text{action}} \\ 0 & \text{if } x_t \in \tau_{\text{prompt}} \cup \tau_{\text{schema}} \cup \tau_{\text{observation}} \end{cases} \]

如果未对观测进行掩码处理,则梯度可分解为: \[ \nabla_\theta \mathcal{L}_{\text{unmasked}} = \nabla_\theta \mathcal{L}_{\text{action}} + \nabla_\theta \mathcal{L}_{\text{obs}} \] 由于观测包含随机的环境输出(例如非确定性的文件时间戳、临时进程 ID 和动态网络载荷),\(\nabla_\theta \mathcal{L}_{\text{obs}}\) 会引入高方差噪声,使模型因未能记住环境中的随机熵而受到惩罚,而非优化决策策略 \(\pi_\theta(a \mid s)\)。不同掩码层次之间的权衡详见 轨迹适配与损失掩码的权衡。

轨迹适配与损失掩码的权衡:不同掩码策略下的有效词元比例、优化目标和运行时隔离。
适配策略 目标词元(\(N_{\text{active}} / T\)) 主要优化目标 动作语法保真度 审慎规划的鲁棒性 运行时沙箱隔离
不加掩码的完整轨迹 \(100\%\) 环境模拟与文本困惑度 差(高熵日志稀释梯度) 低(容易臆造环境返回结果) 受损(存在输出模拟 stdout 的风险)
动作与推理依据掩码 \(15\% - 30\%\) 审慎规划与结构化工具调用合成 高(梯度集中于策略决策) 高(学习结构化的中间步骤分解) 鲁棒(在工具调用边界清晰地交还控制权)
仅动作掩码 \(5\% - 15\%\) API 模式合规性与参数准确性 最高(完全聚焦于语法和参数键) 中等(将推理文本视为被动上下文) 鲁棒(严格强化工具调用边界)
仅观测掩码 \(70\% - 85\%\) 世界状态转移动力学 \(P(s_{t+1} \mid s_t, a_t)\) 下降(学习模仿外部系统) 可忽略(充当环境模拟器) 不适用(充当模拟器而非策略)

为什么必须对观测施加掩码

观测损失掩码(原则 17)之所以存在,是因为智能体轨迹并非出自同一作者的文本。不加掩码的训练要求同一组权重同时学习两种不同的事物。一种是策略 \(P(a_t \mid s_t)\),它将智能体已看到的内容映射为下一步应采取的动作。另一种是环境模型 \(P(s_{t+1} \mid s_t, a_t)\),它预测 shell、编译器或 API 将返回什么。在基于模型的强化学习中,学习后者正是目的所在。对于使用真实工具的智能体而言,这却是浪费。编译器在每一轮都可用,并会准确返回其输出;预测临时路径、进程标识符或语法错误所在的列,对模型毫无益处。

这种浪费很大,因为观测占据了智能体轨迹的绝大部分。文件内容、测试日志和目录列表等工具结果,通常远长于产生这些结果的调用。下方笔记本 1.1 中的具体分析对一条代表性轨迹进行了成本核算,其中超过四分之三的词元是观测。在不加掩码的训练中,大部分损失和梯度都耗费在模型永远不必生成的文本上。这种耗费会造成两类失败。第一类是稀释。观测文本充斥着无法通过任何规则预测的高熵字符串,因此这些字符串上的损失居高不下,其梯度淹没了参数名称和值上较小却更重要的信号。第二类是角色混淆。接受训练以预测工具调用之后内容的模型,会学到工具调用之后紧接着工具输出。在部署时,模型结束调用后,会为继续生成臆造结果而非回合结束词元分配非零概率,从而绕过运行时对该回合的调控(六阶段执行生命周期),就像开篇示例中那样。掩码从源头消除了这种激励,按词元片段划分的损失掩码 则记录了由此得到的各类词元的掩码分配。

按词元片段划分的损失掩码:序列化智能体轨迹中各类词元的掩码分配及作用。
词元片段 内容 掩码(\(m_t\)) 训练中的作用 原因
提示 系统契约、工具模式、用户任务 \(0\) 仅作为上下文 模型会读取这些内容;记住它们会导致知识过时
推理 调用前的审慎思考 \(0\) 或 \(1\)(可选择) 保留推理时作为目标 在模仿推理与冗长程度之间权衡
工具调用 工具名称、JSON 参数、回合结束词元 \(1\) 主要目标 这是运行时将要验证的提议
观测 工具结果、错误、测试输出 \(0\) 仅作为上下文 由环境生成,而环境在每一轮都可用

粗略估算 1.1: 一条轨迹中的损失分配
问题:一条六轮调试轨迹填满了一个包含 16,384 个词元的训练序列。不加掩码的训练将多大比例的损失用于工具输出?施加掩码后,还有多少词元保留为目标?

变量:

  • 系统提示与工具模式:1,200 个词元。
  • 任务描述:184 个词元。
  • 六轮中的推理:1,400 个词元。
  • 工具调用,包括回合结束词元:960 个词元。
  • 观测:12,640 个词元。

计算:

\[\text{Observation share} = \frac{12{,}640}{16{,}384} \approx 77.1\%\]

\[N_{\text{active}} = 1{,}400 + 960 = 2{,}360, \qquad \frac{2{,}360}{16{,}384} \approx 14.4\%\]

结果:不加掩码的训练将约 77% 的逐词元损失用于环境生成的文本。施加掩码后的目标在 2,360 个词元上进行训练,约占序列的 14%,这些词元全部由策略生成。

系统洞见:掩码将目标集合缩小至原来的约七分之一,同时不缩减上下文。前向传播仍然处理全部 16,384 个词元,因此掩码改变的是模型学习的内容,而非单个训练步骤的成本。

推理作为目标还是上下文

提示、观测和调用的掩码设置已经确定。推理的处理则是一项设计选择。对推理进行训练(将 \(m_t = 1\) 应用于 \(\mathcal{T}_{\text{rationale}}\))会教会模型示范者如何分解问题,这对规划至关重要的长任务有所帮助。它也会让模型学到示范者的冗长表达方式,而每个额外的推理词元都是输出词元,属于成本较高的那一类(加速器服务延迟),在模型服务时每一轮都要为此付出成本。仅对动作进行训练,会将示范中的推理保留为上下文,并将全部梯度用于提高调用准确性。这适用于必须以低成本输出正确调用的小型快速策略,但会削弱策略通过审慎思考摆脱陌生失败情形的能力。正如该原则所述,这一选择取决于部署需求。当部署的策略必须推理时,就对推理进行训练;当它无需推理时,就将推理保留为上下文。

回合结束词元与截断回合

在实践中,回合边界处的两种边缘情况导致了大多数掩码错误。第一种是回合结束词元。它属于模型的回合,因为模型必须输出该词元才能交还控制权。如果数据加载器将其归入随后的工具消息,就会对它施加掩码,模型因而得不到停止生成的信号,并在部署时于调用闭合后继续生成。看门狗会在模型不配合的情况下终止该回合(原则 12),但每个被终止的回合都白白浪费了。回合结束词元是动作词元,应保留 \(m_t = 1\)。

第二种是截断。在上下文长度限制处截断的轨迹,可能结束于助手回合的中途,此时 JSON 参数只写了一半。按通常方式为该回合设置掩码,会让模型学到未闭合的调用也是完整调用。隔离不变量(原则 隔离不变量)既适用于训练数据,也适用于模型服务时。缺少闭合定界符的回合应全部施加掩码,或者将轨迹回退截断至最后一个完整观测。两种训练方式之间的差异,在第一次真实调用时便清晰可见:

  TASK: Run the test suite and inspect failures.
  MODEL TURN (live):
  {"name": "bash", "arguments": {"cmd": "pytest tests/core_test.py"}}
- Running tests...
- tests/core_test.py::test_scheduler PASSED
- tests/core_test.py::test_memory FAILED
- [runtime: assistant turn contained simulated tool output; turn rejected]
+ <|end_turn|>
+ [runtime: dispatching call to sandbox]
+ [tool]: tests/core_test.py::test_memory FAILED

删除行中的未掩码模型自行编写测试报告,而运行时拒绝了该轮交互。新增行中的掩码模型结束调用并等待,随后读取的报告来自沙箱。

Checkpoint 1.1: 观测损失掩码

这些问题用于检验掩码后的目标函数,此时批处理尚未使问题复杂化。

掩码是针对单条轨迹定义的。训练则在包含多条轨迹的批次上进行,而轨迹共享批次的方式可能破坏掩码的设计意图:既可能使某些轨迹的权重远高于其他轨迹,也可能让一条轨迹读取另一条轨迹。

无泄漏打包

智能体语料库既包含仅有几百个词元的两轮查询,也包含接近上下文长度上限的四十轮调试会话。将每个样本都填充到最长样本的长度,会使每个批次的大部分空间浪费在填充上,因此训练流水线会将多条轨迹打包到一个序列中。打包是一种标准的效率优化手段,但它也带来了两种智能体特有的风险:损失函数在不易察觉的情况下偏重长轨迹,以及注意力从一条轨迹跨越到下一条轨迹。

损失归一化偏重长轨迹

在一个包含 \(B\) 条轨迹的批次中,轨迹 \(b\) 有 \(N_b\) 个有效目标词元,各词元的损失为 \(\ell_t^{(b)}\)。常用的损失平均方式有两种:

\[\mathcal{L}_{\text{token}} = \frac{\sum_{b=1}^B \sum_{t} m_t^{(b)} \ell_t^{(b)}}{\sum_{b=1}^B N_b} \tag{1}\]

\[\mathcal{L}_{\text{example}} = \frac{1}{B} \sum_{b=1}^B \left( \frac{1}{N_b} \sum_{t} m_t^{(b)} \ell_t^{(b)} \right) \tag{2}\]

按词元归一化(公式 1)为每个目标词元赋予相同权重,因此每条轨迹对更新的影响与其生成的词元数量成正比。一条迂回冗长的 4,000 词元运行轨迹,其权重是一条简洁的 40 词元解决方案的一百倍。按样本归一化(公式 2)则为每条轨迹赋予相同权重,与长度无关。对于智能体,这种差异会影响行为,因为语料库中的长轨迹往往效率较低,在取得成功的过程中包含冗余的列表输出和重复的命令。按词元归一化会教会模型模仿这种迂回行为,并以同样的方式消耗交互轮次和输出词元。按样本归一化则将一次果断的两轮修复视为同等重要的学习样本。表 2 总结了这一权衡。

表 2: 轨迹批次的损失归一化:按词元和按样本求平均如何为不同长度的轨迹赋予权重。
属性 按词元(\(\mathcal{L}_{\text{token}}\)) 按样本(\(\mathcal{L}_{\text{example}}\))
除数 批次中的目标词元总数 先将每条轨迹的损失除以各自的 \(N_b\),再除以轨迹数
每个词元的权重 每个词元均为 \(1/\sum_k N_k\) \(1/(B \cdot N_b)\),在长轨迹中更小
哪些运行轨迹占主导 长、多轮、冗长的运行轨迹 无;每个任务只计一次
对行为的影响 奖励对冗长、重复轨迹的模仿 为简洁和冗长的解决方案赋予相同权重
批次间稳定性 随每个批次的长度构成而变化 在不同长度构成下保持稳定

不同长度轨迹的损失归一化动态

将轨迹打包到训练批次中时,损失归一化方式的选择会显著影响梯度方差。在词元级归一化下: \[ \mathcal{L}_{\text{token}} = \frac{\sum_{i=1}^B \sum_{t=1}^{T_i} m_{i,t} \ell_{i,t}}{\sum_{i=1}^B \sum_{t=1}^{T_i} m_{i,t}} \] 其中 \(\ell_{i,t} = -\log p_\theta(x_{i,t} \mid x_{i,<t})\)。在序列级归一化下: \[ \mathcal{L}_{\text{seq}} = \frac{1}{B} \sum_{i=1}^B \frac{1}{\sum_{t=1}^{T_i} m_{i,t}} \sum_{t=1}^{T_i} m_{i,t} \ell_{i,t} \] 在词元级归一化中,一条包含 16,384 个词元的 100 轮轨迹所贡献的梯度总量,是一条包含 512 个词元的 2 轮轨迹的 32 倍,导致更新过度侧重多轮失败恢复,而牺牲了简洁的单轮工具调用。序列级归一化使各任务的策略梯度权重恢复相等。

块对角注意力隔离机制

将多条轨迹打包到同一个序列缓冲区中,可以消除零填充造成的浪费,但需要严格的注意力隔离。现代内核实现(如 FlashAttention-2 和 FlashAttention-3)并不在整个打包缓冲区上计算完整的 \(O(L^2)\) 注意力,而是接收一个累积序列长度向量 \(\mathtt{cu\_seqlens} = [0, T_1, T_1 + T_2, \dots, \sum T_i]\)。块对角注意力掩码强制满足以下约束: \[ A_{i,j} = \begin{cases} \frac{Q_i K_j^T}{\sqrt{d}} & \text{if } \text{traj}(i) = \text{traj}(j) \land j \le i \\ -\infty & \text{otherwise} \end{cases} \] 这保证了查询 token \(i\) 只能关注其自身轨迹内的先前 token,从而防止跨轨迹的状态污染。

打包与跨轨迹注意力

Definition 1.2: 序列打包

序列打包 是将多个相互独立、长度可变的训练样本拼接成一个固定长度的序列,并对注意力和位置索引进行分区,使每个样本都如同单独存在时一样被处理。

  1. 意义:消除填充,使几乎每个被处理的 token 都属于某个样本;这对于长度跨度达两个数量级的智能体语料尤为重要。
  2. 区别:填充通过为每个样本分配独立的一行来隔离样本,而打包在同一行内部隔离样本,因此需要显式划分注意力区域。
  3. 常见陷阱:在普通因果掩码下进行打包,这会让后面的轨迹关注前面的轨迹,并使模型学到服务时根本不存在的依赖关系。

一个打包序列包含轨迹 \(\tau^{(1)}, \dots, \tau^{(K)}\),其边界偏移量为 \(\mathbf{c} = [c_0, \dots, c_K]\)。在普通因果掩码下,\(\tau^{(2)}\) 的每个 token 都可以关注 \(\tau^{(1)}\) 的全部内容,包括其任务、工具模式和文件内容。在服务时,模型只能看到自身的轨迹。使用跨轨迹注意力训练的策略会学着利用届时并不存在的上下文,还可能将文件路径、标识符或模式字段从一个任务带入另一个任务。解决方法是使用块对角因果掩码,将注意力限制在当前轨迹内,如 图 3 所示:

\[M_{ij} = \begin{cases} 0 & \text{if } j \le i \text{ and } c_k \le j \le i < c_{k+1} \text{ for some } k, \\ -\infty & \text{otherwise.} \end{cases}\]

图 3: 打包轨迹的块对角注意力:两条轨迹被打包到一个序列中。在普通因果掩码下(a),\(\tau_2\) 中的查询关注 \(\tau_1\) 中的键,策略因而学到无关任务之间的依赖关系。块对角掩码(b)仅利用边界偏移量,将跨轨迹的分数设为 \(-\infty\),从而把因果注意力限制在每条轨迹自身的块内。

位置索引也需要采用相同的分区。如果位置编号在整个打包序列中连续递增,\(\tau^{(2)}\) 的第一个系统 token 就会位于数千的位置,而服务中的模型从不会看到系统提示从这样的位置开始。在每个边界处重置位置,

\[\text{pos}[t] = t - c_k \quad \text{for } t \in [c_k, c_{k+1}),\]

就能使每条打包轨迹在位置上与同一轨迹单独用于服务时完全一致。高效的注意力实现直接接收边界偏移量,并跳过被掩蔽的块,而不是显式构造完整掩码,因此隔离几乎没有额外开销。这些内核的实现机制属于《大规模机器学习系统》等训练系统教材的范畴;这里重要的是必须满足的约定:每条打包轨迹都必须与同一轨迹单独用于服务时不可区分。

当序列化、掩码和打包都正确时,训练步骤就能忠实地模仿获准纳入训练的轨迹。但忠实模仿仍有结构性局限,一旦训练后的模型独立运行,这种局限就会显现。

暴露偏差与同策略数据

分布偏移:训练从示范者的分布 \(d_{\pi^*}\) 中采样状态。部署时则访问来自策略自身分布 \(d_{\pi_\theta}\) 的状态。两者只在策略首次出错之前保持一致。

一个在干净、成功的运行轨迹上微调的策略,在生产环境中遇到了合并冲突:

$ git merge origin/staging
CONFLICT (content): Merge conflict in src/auth/session.py
$ python -m pytest tests/test_session.py
    <<<<<<< HEAD
    ^
SyntaxError: invalid syntax
$ git commit -m "resolve conflicts" --all
fatal: cannot do a partial commit during a merge.
$ git commit --force-resolve
error: unknown option `force-resolve'

第一行之后的每个观测都超出了训练语料所涵盖的范围。策略从未见过冲突标记后接正确编辑的情形,因此它先尝试提交,随后又编造了一个标志参数,而智能体运行框架则不断消耗轮次,直到预算耗尽或看门狗终止运行。问题并非出在某一条糟糕的示范上。教师强制在每一步都以示范者自身的前缀进行训练,因此模型学到的是如何在示范者访问过的状态中行动。一旦模型自己犯错,它就进入了一个没有示范者访问过的状态,而训练从未告诉它如何返回。以参考前缀训练、却以模型自身输出运行,两者之间的这种不匹配在序列预测中称为暴露偏差 (Bengio 等 2015年)。在文本生成中,它会导致措辞逐渐偏离;而在智能体中,每一次错误调用都会改变环境,使下一个观测比上一个观测进一步偏离训练分布。

Bengio, Samy, Oriol Vinyals, Navdeep Jaitly, 和 Noam Shazeer. 2015年. 《Scheduled Sampling for Sequence Prediction with Recurrent Neural Networks》. Advances in Neural Information Processing Systems (NeurIPS 2015) 28.

错误如何随时域累积

设某项智能体任务运行 \(H\) 轮,即时域为 H·S·A 暴露面。设 \(\pi^*\) 为示范者,\(\pi_\theta\) 为微调后的策略,并假设监督训练使策略在示范者状态上的单步错误率达到 \(\epsilon\):

\[\mathbb{E}_{s \sim d_{\pi^*}^t} \left[ \mathbb{I}\left( \pi_\theta(s) \neq \pi^*(s) \right) \right] \le \epsilon.\]

设每一步的代价为 \(C(s, a) \in [0, 1]\),示范者动作的代价为零。在第 \(t\) 步,根据联合界,策略此前已经至少犯过一次错误的概率至多为 \((t-1)\epsilon\)。根据是否已经发生过错误,将第 \(t\) 步的期望代价分解为:

\[\mathbb{E}_{s \sim d_{\pi_\theta}^t} [C] = P(\neg \mathcal{E}_{<t}) \cdot \mathbb{E}[C \mid \neg \mathcal{E}_{<t}] + P(\mathcal{E}_{<t}) \cdot \mathbb{E}[C \mid \mathcal{E}_{<t}] \tag{3}\]

如果此前未发生错误,策略仍处于示范路径上,犯错概率至多为 \(\epsilon\)。发生错误后,训练未向它提供任何信号,因此在最坏情况下,每一步都会产生最大代价。代入 公式 3 可得单步代价的上界为 \(\epsilon + (t-1)\epsilon = t\epsilon\),再对整个时域求和,得到

\[J(\pi_\theta) - J(\pi^*) \le \sum_{t=1}^{H} t\epsilon = \epsilon \frac{H(H+1)}{2} = O(\epsilon H^2). \tag{4}\]

公式 4 中的二次项,是对合并冲突轨迹的形式化表述。现在假设策略改为在从其自身轨迹采样中抽取的状态上训练,使其单步错误率 \(\epsilon\) 在它实际访问的状态分布上成立。此时,每一步的期望代价至多为 \(\epsilon\),且

\[J(\pi_\theta) - J(\pi^*) \le \sum_{t=1}^{H} \epsilon = O(\epsilon H). \tag{5}\]

Ross 等 (2011年) 对这一降低进行了形式化,并给出了实现它的算法。从 公式 4 到 公式 5 的变化,从定量上解释了为什么经验证的轨迹后训练(原则 16)要在语料中保留恢复轨迹。

粗略估算 1.2: 三十轮任务中的累积错误
问题:某个微调后的策略在示范路径上有 2% 的步骤会犯错。对于一项三十轮的任务,在最坏情况下,行为克隆和同策略训练分别可能使多少轮偏离示范路径?

变量:

  • 训练状态上的单步错误率:\(\epsilon = 0.02\)。
  • 时域:\(H = 30\) 轮。
  • 每轮处理的上下文(示例):8,000 个词元。

计算:

\[P(\text{no mistake in 30 turns}) = (1 - 0.02)^{30} \approx 0.545\]

\[\text{Behavior cloning bound: } \epsilon \frac{H(H+1)}{2} = 0.02 \times 465 = 9.3 \text{ turns}\]

\[\text{On-policy bound: } \epsilon H = 0.02 \times 30 = 0.6 \text{ turns}\]

\[9.3 \times 8{,}000 \approx 74{,}000 \text{ tokens} \quad \text{vs.} \quad 0.6 \times 8{,}000 = 4{,}800 \text{ tokens}\]

结果:即使单步准确率达到 98%,无错误运行的比例仍不足 55%。行为克隆的界允许三十轮中有 9.3 轮偏离示范路径;同策略训练的界则允许 0.6 轮,两者相差约十五倍。

系统启示:在示范数据上测得的单步准确率会高估任务可靠性,而且高估程度随时域的平方增长。对于长任务,在无法恢复的状态中消耗的词元会计入每项验收通过任务的成本,而不只是失败运行的成本。

行为克隆中累积遗憾的推导

在采用教师强制的标准行为克隆(BC)中,训练假设策略观测到的是从专家分布 \(d_{\pi^*}\) 中抽取的示范状态。如果策略的期望单步错误概率以 \(\epsilon\) 为上界: \[ \mathbb{E}_{s \sim d_{\pi^*}}[\mathbb{I}(\pi_\theta(s) \neq \pi^*(s))] \le \epsilon \] 在时域长度为 \(T\) 的自回归轨迹采样中,第一次错误会使策略偏离至未建模的状态 \(s \notin \text{supp}(d_{\pi^*})\)。由于策略从未在其自身产生的错误状态上接受训练,后续预测的错误概率趋近于 1。整条轨迹的预期总遗憾呈二次增长: \[ \mathbb{E}[\text{Regret}_{\text{BC}}(T)] \le \sum_{t=1}^T t \cdot \epsilon = \epsilon \cdot \frac{T(T+1)}{2} = \mathcal{O}(\epsilon T^2) \]

在交互式数据集聚合(DAgger)中,按照当前策略,从智能体所诱导的状态分布中进行轨迹采样 \(d_{\pi_\theta}\),并由专家标注纠正动作。期望遗憾的上界随轨迹时域长度线性增长: \[ \mathbb{E}[\text{Regret}_{\text{DAgger}}(T)] \le \mathcal{O}(\epsilon T) \]

代码 1 展示了未加缓解的暴露偏差在现实场景中导致的失效模式:一个经过微调的编码智能体陷入了无限的错误重试循环。

列表 1: Failure Trace: Unmitigated Exposure Bias in Autonomous Trajectories: An agent fine-tuned solely on pristine demonstrations encounters an unfamiliar Git CLI syntax error, entering an unrecoverable infinite loop because its training distribution contained zero recovery paths.
# Policy loops on unmodeled state: git commit --force-resolve (Exit Code 128)
[Step 14] ACTION: git commit -m "fix bug" --force-resolve
[Step 14] OBS:    error: unknown option `force-resolve' (exit code 128)
[Step 15] THOUGHT: Retrying command to resolve conflicts...
[Step 15] ACTION: git commit -m "fix bug" --force-resolve
[Step 15] OBS:    error: unknown option `force-resolve' (exit code 128)
[Step 16] THOUGHT: Retrying command to resolve conflicts...
[Step 16] ACTION: git commit -m "fix bug" --force-resolve
[Step 16] OBS:    error: unknown option `force-resolve' (exit code 128)

同策略数据收集

数据集聚合(DAgger)将线性界转化为一条数据流水线 (Ross 等 2011年)。每轮运行当前策略,找出它实际到达的状态,获取这些状态下的正确动作,并将其加入训练集。暴露偏差与同策略恢复对比了这两种形态。

Ross, Stéphane, Geoffrey Gordon, 和 J. Andrew Bagnell. 2011年. 《A Reduction of Imitation Learning and Structured Prediction to No-Regret Online Learning》. Proceedings of the Fourteenth International Conference on Artificial Intelligence and Statistics (AISTATS) 15: 627~35.
图 4: 暴露偏差与同策略恢复:行为克隆(a)仅沿示范路径训练;一次错误就会使策略进入语料库从未覆盖的状态,代价按 \(O(\epsilon H^2)\) 增长。结合故障注入的同策略聚合(b)收集策略到达的偏离路径状态,为其标注纠正动作,并将恢复过程中的状态转移加入语料库,因此代价按 \(O(\epsilon H)\) 增长。示例计算采用 \(\epsilon = 0.02\) 和 \(H = 30\)。

在智能体流水线中,每轮包含四个步骤,每个步骤都复用前面章节介绍的机制。首先,当前策略在沙箱中运行训练任务,沙箱池与重置中的池化与重置机制使大规模运行的成本可控。其次,运行时记录策略偏离正确路线的状态,这些状态通过验证器检查失败、调用被拒绝或循环检测来识别。第三,标注者为每个这样的状态提供正确的下一步动作。标注者通常采用更强的模型或更大的测试时计算预算(测试时计算),因为能够在策略到达的每个状态下指出正确动作的专家,正是 DAgger 所假设的条件,也是获取成本高昂的资源。第四,将新的状态—动作对加入语料库,并使用相同的观测掩码重新训练策略。

第三步存在一个智能体特有的陷阱。标注者给出的动作本身也是一项提议,错误的标注会训练策略朝错误的方向恢复。因此,每个纠正动作在进入语料库之前,都要重新经过@sec-vol3-flywheel-verification中的准入级联流程;在实践中,这意味着在沙箱中从纠正动作继续执行轨迹,只有任务验证器接受最终结果时才保留它。策略一旦变化,同策略数据也会随即过时,因为重新训练后的策略会访问不同的状态。一种常见的调度方式是在早期轮次中混合标注者与策略的动作,以概率 \(\beta_k\) 执行标注者的动作,并将 \(\beta_k\) 逐步衰减至零,使收集到的状态逐渐趋向策略自身的分布。将这一过程重复多轮的更广泛自我改进循环及其风险,将在@sec-vol3-trajectory-curation-self-improvement中讨论。

通过故障注入构建离线恢复数据

实时收集同策略数据成本高昂,因此流水线也会直接构造偏离路径的状态。数据整理流水线已经在这样做。其测试夹具在工具边界注入@tbl-vol3-fault-injection-taxonomy中的故障类别,并准入成功恢复的轨迹采样(恢复示范筛选),上文的合并冲突就是其中一类。对于训练,关键在于如何为这样的轨迹设置掩码。注入的错误属于观测,因此带有 \(m_t = 0\);诊断与纠正调用带有 \(m_t = 1\),从而使梯度恰好作用于行为克隆从未见过的偏离路径动作。故障注入覆盖流水线能够预见的失败,同策略收集则覆盖只有策略自身行为才会暴露的失败。两者都留下了一个未经检验的假设:模型会读取提供给它的上下文。下一节将展示,微调如何在智能体最重要的上下文——工具模式——上悄然破坏这一假设。

Checkpoint 1.2: 打包与暴露偏差

以下问题用于检验对批处理和同策略数据的理解,随后再讨论工具模式。

模式鲁棒性

一个经过微调的智能体上线一个月后,工具团队将某个参数从 file_path 重命名为 target_uri。每次调用的系统提示中都包含新的模式。经过微调的模型却持续输出 file_path,导致每次调用都无法通过验证:

# Runtime schema validation (fine-tuned policy, renamed argument)
ValidationError: "Missing required property: 'target_uri'"
received: {"name": "read_file", "arguments": {"file_path": "/etc/hosts"}}
schema:
  read_file:
    properties: {target_uri: {type: string}}
    required: [target_uri]
    additionalProperties: false

从未接受过该工具训练的基础模型能够读取新模式,并正确调用该工具。微调却使模型在契约所依赖的关键能力上表现更差。类型化动作契约会依据运行时当前持有的模式验证每次调用(原则 8),因此运行时能够捕获每一次错误调用,但智能体无法取得任何进展。数据集划分卫生验证 所要求的严格数据划分规范将未见过的工具族留作评估,正是出于这一原因。

为什么微调会记忆模式

在训练语料中,系统提示里的工具模式在数千个示例中完全相同。当数据中的每一次文件读取都使用 read_file,且其参数名为 path 时,仅凭用户请求就能预测调用的词元。对优化器而言,降低损失的成本最低的方式,就是将调用的表面形式存入权重;而从调用回溯到提示中模式的注意力路径则会减弱,因为这些路径已不再有帮助。模型将本应属于上下文的契约转化成了权重中的过程,而 表 1 指出,权重并不是它应当存放的位置。图 5 通过示意性的注意力权重展示了这一对比。

图 5: 模式记忆与上下文条件化调用:示意图展示了生成调用的词元对提示中工具模式的注意力,并给出了示例权重。在固定模式上训练后(a),调用词元对模式的注意力较弱,模型输出记忆中的参数,运行时因此拒绝该调用。在采用模式扰动进行训练后(b),调用词元会关注模式,并绑定当前的参数名。

在训练期间扰动模式

补救办法是让记忆不再带来收益。如果模式在不同训练示例之间变化,而目标调用始终与该示例的模式匹配,那么预测调用的唯一方法就是读取模式。在序列化期间应用的四种扰动可以实现这一点;表 3 对它们进行了汇总。排列扰动会打乱所声明模式和目标调用中的参数顺序,使模型无法依赖固定顺序。重命名会用同义名称或合成名称替换工具和参数标识符,例如 read_file(path) 在一个示例中变为 fetch_document(target_uri),在另一个示例中变为 load_buffer(locator),同时对目标调用进行相应重命名。干扰项注入会在每个提示中加入若干未使用的工具声明,使模型必须在多个工具之间进行选择,而不是调用唯一出现的工具;这更接近具有大型工具集的真实部署环境(可互操作的工具发现)。模式丢弃会从部分声明中移除可选参数,并从目标调用中一并移除,使模型学会不应发送模式中不存在的参数。

表 3: 轨迹训练中的模式扰动:序列化期间应用的变换、各自防止的失效及其成本。
扰动 变换 防止的失效 训练成本
排列扰动 打乱模式和目标调用中的参数顺序 依赖固定的参数顺序 无(文本重排)
重命名 用同义名称或合成名称替换标识符 记忆参数名 无(替换)
干扰项注入 在提示中加入未使用的工具声明 随意调用所声明的工具 提示更长,因此每步需要更多词元
模式丢弃 从模式和目标调用中移除可选参数 发送模式中已不存在的参数 无(删除)

扰动能够降低过时调用的概率,但无法将其彻底消除。保证仍然来自运行时的验证器,它会拒绝每一次不符合当前模式的调用。扰动带来的收益是:被拒绝的调用足够少,使智能体在接口发生变化后仍能持续取得进展。其效果要在训练集中从未出现过的工具族上衡量,而 节 1.9 将这一点规定为评估的必需组成部分。

蒸馏

前面的各节假定已有一个由获准纳入的轨迹组成的语料库,并探讨了如何使用它进行训练。但首先需要回答两个实际问题:当生产日志数量太少或质量太低时,优质轨迹从何而来?如何让模型不再在每一轮都为本可一次学会的指令付出成本?这两个问题的答案相同:让模型的一种成本更高的配置生成行为,再训练一种成本更低的配置来复现这些行为。

上下文蒸馏

智能体的系统提示词通常包含数千个 token 的操作流程:调试检查清单、十几个从常见错误中恢复的少样本示例,以及何时请求批准的规则。每条轨迹的每一轮都会重新处理这些文本。前缀缓存可以避免重复计算(KV 缓存管理),但在整条轨迹的执行过程中,前缀仍然占用上下文和缓存内存,并与任务状态争夺上下文预算。

上下文蒸馏将操作流程从提示词中移除,同时保留其效果。该流水线先让模型使用长提示词执行一组任务,通过常规的级联筛选流程接纳生成的轨迹,然后使用以短提示词序列化的这些轨迹训练模型。训练目标是长提示词产生的行为;训练输入则是模型在服务时将使用的提示词。训练完成后,短提示词产生的行为接近长提示词产生的行为,而两者之间的提示词 token 数量差额则成为每一轮节省的开销。

智能体知识的归属位置规定了哪些内容可以被蒸馏。操作流程可以迁移;契约不能。工具模式、任务规范以及授予当前轨迹的权限范围必须保留在短提示词中,因为它们会随部署而变化,而上一节已经展示了模型将它们学成常量时会发生什么。如果一次蒸馏在移除检查清单的同时也移除了工具模式,那么得到的模型在首次接口变更之前会表现良好。这一区分也告诉团队何时需要重新蒸馏。操作流程的变更,例如新增一条恢复规则,需要进行新一轮训练;这一过程耗时较长,而且必须通过发布门禁。如果一条规则每周都变化,那么它在实践中就是契约,应当保留在提示词中。

教师蒸馏

知识蒸馏通过训练小型学生模型,使其匹配大型教师模型 (Hinton 等 2015年)。对于智能体而言,教师不仅可以是更大的模型,也可以是任何能够生成更优轨迹、成本更高的配置,例如前沿模型、结合搜索和验证器的更大测试时计算预算(测试时计算),或集成模型。该流水线在训练任务上从教师模型采样轨迹,仅接纳验证器认可的轨迹,并使用与其他语料库相同的序列化方式和掩码,在获准纳入的轨迹集上训练学生模型。当只能通过 API 访问教师模型时,可获得的只有它采样生成的 token,而非完整的输出分布,因此学生模型模仿的是序列,而非概率。

Hinton, Geoffrey, Oriol Vinyals, 和 Jeff Dean. 2015年. 《Distilling the Knowledge in a Neural Network》. arXiv preprint.
Chen, Baian, Chang Shu, Ehsan Shareghi, Nigel Collier, Karthik Narasimhan, 和 Shunyu Yao. 2023年. 《FireAct: Toward Language Agent Fine-tuning》. arXiv preprint arXiv:2310.05915, 网络首发. https://doi.org/10.48550/arXiv.2310.05915.
Zelikman, Eric, Yuhuai Wu, Jesse Mu, 和 Noah D. Goodman. 2022年. 《STaR: Bootstrapping reasoning with reasoning》. Advances in Neural Information Processing Systems (NeurIPS) 35: 15476~88.

这类智能体轨迹蒸馏是构建较小智能体策略的常用方法。使用更强模型生成的轨迹对较小模型进行微调,已使其在智能体任务上的表现优于仅使用提示词的方法 (Chen 等 2023年; Zeng 等 2023年)。另一种相关的轨迹来源无需单独的教师模型。模型为每个任务采样多次尝试,验证器保留成功的尝试,模型再使用自身获准纳入的成功轨迹进行训练 (Zelikman 等 2022年)。由于这一循环反复使用模型自身的输出训练模型,因此它也具有自我改进循环中的模型坍塌和陈旧性风险(自我改进循环)。

蒸馏继承了教师模型的能力上限。通过模仿训练的学生模型无法超越教师模型所展示的行为;凡是验证器未能发现的系统性错误,学生模型也会继承。这一能力上限是 可验证奖励强化学习 的切入点。在此之前,必须先部署经过蒸馏或微调的策略;对于智能体而言,部署产物的形式与其准确性同样重要。

智能体适配器

一个平台运行着一个负责问题分诊的智能体、另一个负责编辑代码的智能体,以及第三个负责编写数据库迁移的智能体。每个智能体都能从各自的微调中受益,而且当更新导致性能退化时,每个智能体都必须能够独立回滚。全量微调会产生三份完整的模型权重副本,每份都是需要单独存储、加载和提供服务的产物。参数高效微调则在一个共享基础模型之上,为每种角色生成一个小型产物,这种形式符合智能体系统的运维方式。

低秩适配(LoRA)冻结基础权重 \(W_0\),并学习一个低秩更新 (Hu 等 2021年):

Hu, Edward J., Yelong Shen, Phillip Wallis, Zeyuan Allen-Zhu, Yuanzhi Li, Shean Wang, Lu Wang, 和 Weizhu Chen. 2021年. 《LoRA: Low-Rank Adaptation of Large Language Models》. arXiv preprint arXiv:2106.09685.

\[W = W_0 + \frac{\alpha}{r} B A, \qquad B \in \mathbb{R}^{d \times r}, \; A \in \mathbb{R}^{r \times k}, \; r \ll \min(d, k).\]

将 \(B\) 初始化为零,可使适配后的模型在训练开始时与基础模型完全一致。对于一个方形 \(d \times d\) 投影,适配器增加 \(2 r d\) 个参数,相对于其修改的 \(d^2\) 个参数,占比为 \(2r/d\)。当秩为 \(r = 16\)、宽度为 \(d = 4{,}096\) 时,这一比例为 \(32/4{,}096\),低于每个适配矩阵参数量的 1%。由于只训练适配器,优化器状态也按相同的比例缩减。

适配器的三个特性使其成为智能体角色的默认交付产物。首先是隔离性。每个角色的适配器都独立训练、评估和发布,因此迁移智能体的性能退化不会迫使分诊智能体重新训练。其次是回滚。回退某个角色只需回退一个小文件,相比重新部署完整模型,这更契合 分阶段金丝雀部署 中的分阶段发布和自动回滚。第三是共享服务。服务系统可以保留一份基础模型和多个适配器,并在同一批次中为每个请求应用相应的适配器 (Sheng 等 2024年; Chen 等 2024年),因此增加一个角色只会增加少量内存占用。LoRA 梯度的附录推导见 LoRA 矩阵分解。

Sheng, Ying, Shiyi Cao, Dacheng Li, Coleman Hooper, Shuo Chen, Daxin Jiang, Christopher Rodriguez, 等. 2024年. 《S-LoRA: Serving Thousands of Concurrent LoRA Adapters》. Proceedings of the 7th Conference on Machine Learning and Systems (MLSys).
Chen, Liyuan, Zihao Ye, Yonghao Wu, Danyang Zhuo, Luis Ceze, 和 Arvind Krishnamurthy. 2024年. 《Punica: Multi-Tenant LoRA Serving》. Proceedings of the 7th Conference on Machine Learning and Systems (MLSys).
Dettmers, Tim, Artidoro Pagnoni, Ari Holtzman, 和 Luke Zettlemoyer. 2023年. 《QLoRA: Efficient Finetuning of Quantized LLMs》. Advances in Neural Information Processing Systems (NeurIPS) 36: 10088~115.

有一项预算核算可以使预期保持合理。适配器减少了需训练的参数及其优化器状态,对冻结的基础权重进行量化则可进一步减少内存占用 (Dettmers 等 2023年)。这两种方法都无法减少反向传播必须保留的激活值,而这些激活值会随序列长度增加而增多。因此,即使使用适配器,每条长达数万 token 的智能体轨迹在训练时仍然受内存限制;常见的补救方法是在反向传播过程中重新计算激活值,以额外计算换取内存节省。详细的核算属于 《大规模机器学习系统》 的内容;在规划时,应遵循的原则是:在智能体数据上训练所需的内存由轨迹长度决定,而非适配器大小。

适配器还缩小了训练可能扰动的范围,但并不能完全防止这种扰动。仅使用工具调用轨迹训练的适配器,仍可能削弱基础模型原有的通用指令遵循能力、推理能力或知识,这正是序贯训练中典型的灾难性遗忘 (Kirkpatrick 等 2017年)。有效的解决办法在于数据,而非参数化方式。将通用指令数据混入智能体语料,可以在增加智能体技能的同时保留通用能力 (Zeng 等 2023年);混合比例是一个由评估确定的调优参数。这一评估是整个流程的最后一步,也是决定性的一步。

Kirkpatrick, J., R. Pascanu, N. Rabinowitz, J. Veness, G. Desjardins, A. A. Rusu, K. Milan, 等. 2017年. 《Overcoming catastrophic forgetting in neural networks》. Proceedings of the National Academy of Sciences 114 (13): 3521~26. https://doi.org/10.1073/pnas.1611835114.
Zeng, Aohan, Mingdao Liu, Rui Lu, Bowen Wang, Xiao Liu, Yuxiao Dong, 和 Jie Tang. 2023年. 《AgentTuning: Enabling Generalized Agent Capabilities for LLMs》. arXiv preprint arXiv:2310.12823, 网络首发. https://doi.org/10.48550/arXiv.2310.12823.

长时程轨迹中的激活内存墙

在较长的多轮轨迹(\(L = 32{,}768\) 至 \(128{,}000\) 个 token)上微调智能体模型,会遇到激活内存墙。模型权重保持固定,而反向传播期间的激活内存占用随序列长度 \(L\) 和批大小 \(B\) 线性增长。对于隐藏维度为 \(d_{\text{model}}\)、注意力头数为 \(a\) 且采用选择性激活检查点的 Transformer 层,其层激活内存占用满足: \[ M_{\text{act}} = B \cdot L \cdot d_{\text{model}} \cdot \left(34 + 5 \cdot \frac{a \cdot L}{d_{\text{model}}}\right) \text{ bytes per layer} \] 如 不同 70B SFT 配置下的加速器内存占用 和 智能体适配的加速器内存占用明细 中的量化结果所示,激活内存很快就会远超静态适配器参数权重所占内存,因此必须采用序列并行、激活重计算以及 FlashAttention 内核优化。

不同 70B SFT 配置下的加速器内存占用:模型权重、优化器状态和动态激活的硬件内存分布(\(T=64\text{k}\) 个词元,微批次大小为 \(B=1\))。
SFT 适配形态 基础权重与梯度 优化器状态 动态激活(\(T=64\text{k}\)) HBM 总占用量 最低硬件要求
全参数 SFT(16 位) 280 GB(权重 + 梯度) 840 GB(AdamW fp32) 约 160 GB(不使用检查点) 约 1,280 GB HBM 多节点集群(\(16\times 80\text{ GB}\) H100)
QLoRA(NF4,不使用检查点) 35 GB(NF4 基础权重 + LoRA 梯度) 3 GB(分页 AdamW) 约 160 GB(不使用检查点) 约 198 GB HBM \(4\times 80\text{ GB}\) 或 \(2\times 141\text{ GB}\) H200
QLoRA(NF4 + 激活检查点) 35 GB(NF4 基础权重 + LoRA 梯度) 3 GB(分页 AdamW) 18 GB(选择性重计算) 约 56 GB HBM 单块 \(1\times 80\text{ GB}\) H100 GPU
智能体适配的加速器内存占用明细:在全参数 SFT、LoRA 和 QLoRA 配置下,采用选择性激活检查点时,不同模型规模和上下文长度对应的加速器内存占用完整明细。各数值均假设微批次大小为 \(B=1\),并集成 FlashAttention-2。
模型架构 适配方法 静态内存(GB) 动态激活(\(T=4\text{k}\)) 动态激活(\(T=16\text{k}\)) 动态激活(\(T=64\text{k}\)) 总内存(\(T=64\text{k}\)) 硬件配置
8B 稠密模型 全参数 SFT(AdamW) \(128.0\) \(8.4\text{ GB}\) \(33.6\text{ GB}\) \(134.4\text{ GB}\) \(262.4\text{ GB}\) \(4\times \text{H}100\text{ (80GB)}\)
(\(L=32, d=4096\)) LoRA(\(r=16\)) \(17.2\) \(8.4\text{ GB}\) \(33.6\text{ GB}\) \(134.4\text{ GB}\) \(151.6\text{ GB}\) \(2\times \text{H}100\text{ (80GB)}\)
LoRA + 选择性检查点 \(17.2\) \(1.8\text{ GB}\) \(7.2\text{ GB}\) \(28.8\text{ GB}\) \(46.0\text{ GB}\) \(1\times \text{H}100\text{ (80GB)}\)
QLoRA(4 位)+ 选择性检查点 \(5.8\) \(1.8\text{ GB}\) \(7.2\text{ GB}\) \(28.8\text{ GB}\) \(34.6\text{ GB}\) \(1\times \text{A}100\text{ (40GB)}\)
32B 稠密模型 全参数 SFT(AdamW) \(512.0\) \(18.2\text{ GB}\) \(72.8\text{ GB}\) \(291.2\text{ GB}\) \(803.2\text{ GB}\) \(16\times \text{H}100\text{ (80GB)}\)
(\(L=64, d=5120\)) LoRA(\(r=16\)) \(66.4\) \(18.2\text{ GB}\) \(72.8\text{ GB}\) \(291.2\text{ GB}\) \(357.6\text{ GB}\) \(8\times \text{H}100\text{ (80GB)}\)
LoRA + 选择性检查点 \(66.4\) \(3.2\text{ GB}\) \(12.8\text{ GB}\) \(51.2\text{ GB}\) \(117.6\text{ GB}\) \(2\times \text{H}100\text{ (80GB)}\)
QLoRA(4 位)+ 选择性检查点 \(19.8\) \(3.2\text{ GB}\) \(12.8\text{ GB}\) \(51.2\text{ GB}\) \(71.0\text{ GB}\) \(1\times \text{H}100\text{ (80GB)}\)
70B 稠密模型 全参数 SFT(AdamW) \(1{,}120.0\) \(31.5\text{ GB}\) \(126.0\text{ GB}\) \(504.0\text{ GB}\) \(1{,}624.0\text{ GB}\) \(32\times \text{H}100\text{ (80GB)}\)
(\(L=80, d=8192\)) LoRA(\(r=16\)) \(144.2\) \(31.5\text{ GB}\) \(126.0\text{ GB}\) \(504.0\text{ GB}\) \(648.2\text{ GB}\) \(16\times \text{H}100\text{ (80GB)}\)
LoRA + 选择性检查点 \(144.2\) \(5.4\text{ GB}\) \(21.6\text{ GB}\) \(86.4\text{ GB}\) \(230.6\text{ GB}\) \(4\times \text{H}100\text{ (80GB)}\)
QLoRA(4 位)+ 选择性检查点 \(41.8\) \(5.4\text{ GB}\) \(21.6\text{ GB}\) \(86.4\text{ GB}\) \(128.2\text{ GB}\) \(2\times \text{H}100\text{ (80GB)}\)

多租户适配器调度与 SRAM 换入换出

在生产环境的智能体平台中,多个专用适配器(例如编码专家适配器、模式转换适配器和数据库查询编写适配器)共享同一个冻结的基础模型。运行时采用低秩适配(LoRA),将权重更新分解为低秩矩阵,从而无需为每个微调变体分配专用 GPU 内存: \[ W = W_0 + \frac{\alpha}{r} B A, \quad B \in \mathbb{R}^{d \times r}, A \in \mathbb{R}^{r \times k}, \quad r \ll \min(d, k) \]

运行时按请求动态地将适配器矩阵热切换至 GPU SRAM 和高带宽内存(HBM),如 图 6 所示。

图 6: 智能体服务中的多租户低秩适配器切换:架构示意图展示了秩为 \(r\) 的参数分解(\(W = W_0 + \frac{\alpha}{r} B A\)),以及采用分段批量 GEMM 的多租户服务引擎(S-LoRA/Punica)。在面板 (a) 中,前向传播同时计算基础投影 \(h_{\text{base}} = x W_0\) 与低秩适配器投影 \(x A^T B^T\),而内在参数流形的几何结构将更新限制在 \(r(d_{\text{in}} + d_{\text{out}})\) 维子空间 \(\mathcal{M}_r \subset \mathbb{R}^D\) 内。在面板 (b) 中,片上适配器页表将批量序列请求路由至高带宽内存(HBM)中的专用适配器权重,执行分段批量 GEMM,且无需重新加载基础模型。

不同适配器服务层级在延迟、内存带宽和容量之间的权衡详见 表 4。

表 4: 多租户 LoRA 适配器分派架构:比较面向不同智能体领域的独立完整模型实例与融合式动态适配器路由。
分派架构 基础权重表示 每个领域的内存开销 并发与扩展 硬件服务效率
独立完整实例 独立的 70B 参数副本(每个领域 \(140\text{ GB}\))。 每项并发能力 \(140\text{ GB}\)。 低;每个领域均需独立的 GPU 集群。 差;硬件成本为 \(3\times\),容量严重闲置。
融合式动态 LoRA 分派 GPU HBM 中单个共享且冻结的 70B 基础模型(\(35 - 140\text{ GB}\))。 每个专用适配器 \(10 - 50\text{ MB}\)(\(A_k, B_k\))。 高;在 Bash、SQL 和 Python 适配器之间动态路由批次。 最优;在单台服务器上复用数十项能力。

评估微调后的智能体

一次微调运行结束后,会得到一组训练后的权重和一个验证损失值。两者都无法说明智能体是否有所改进。智能体评估 中的评估机制用于衡量智能体;本节则确定应当对微调后的智能体衡量哪些指标,以及每项指标防范什么问题。

验证损失为何具有误导性

验证损失衡量模型在给定示范者前缀的条件下预测示范词元的准确程度。它对所有目标词元取平均,因此,对 JSON 标点和模板化推理的近乎确定的预测,与对正确文件路径的预测一样,都能降低验证损失,尽管只有路径决定调用能否成功。验证损失还通过在留出示范上采用教师强制计算得出,而这些示范大多是顺利执行的运行,因此,它无法反映 节 1.5 中导致智能体失败的偏离正常路径的状态。

Example 1.1: 损失更低,智能体却更差
场景:两个候选模型使用同一批获准纳入的轨迹进行训练。模型 A 对系统提示之后的所有词元计算损失。模型 B 使用观测损失掩码,并纳入通过故障注入获得的恢复轨迹。在留出示范上,A 的验证损失更低,因为它还学会了预测观测,而观测占据了很大比例的词元。

诊断:在沙箱化的智能体运行框架中运行时,A 经常在发出工具调用后继续生成,并自行编写结果,因此,它的许多轨迹以轮次被拒绝或预算耗尽而告终。B 则在每次调用后交出控制权,读取真实结果,并在测试失败后恢复。尽管 B 的验证损失更高,但它解决的任务更多,且每个获验收任务的成本更低。

系统启示:对策略并不生成的词元计算损失,会奖励错误的技能。候选模型应按闭环验证成功率排序,绝不能按验证损失排序。

评估记分卡

微调后的模型需要在五项指标上与其将要替代的策略进行比较,后者通常是采用更长提示的同一个基础模型。每项指标都用于防范本章已指出的一种失败情形。

首要指标是经验证的任务成功率,即在 封闭隔离评估训练场 的评估训练场中,由封闭验证器判定智能体完成留出任务的比例;所有候选模型均采用相同的轮次、词元和时间预算。由于微调后的策略可能提高一致性却未提高能力上限,也可能恰好相反,因此,对于重复运行,成功率同时以 \(\text{pass}@k\) 和 \(\text{pass}^k\) 报告(潜在能力解耦);一个候选模型若在五次尝试中能成功一次,却很少能五次全部成功,就不能说它已经变得可靠。

经验证的成功只说明智能体是否完成任务,并不说明它为何失败,因此第二项指标是函数调用准确率。每个发出的调用都会接受检查,以确认工具选择正确、参数格式规范,且参数值符合模式要求,这与函数调用基准对 API 调用的评分方式一致 (Patil 等 2023年)。函数调用失败类别 将失败划分为不同类别,因为每个类别都指向不同的修复方法。序列化格式错误指向训练数据问题,虚构工具指向模式记忆问题,而调用截断则指向被截断轮次的掩码处理问题。

Patil, Shishir G., Tianjun Zhang, Xin Wang, 和 Joseph E. Gonzalez. 2023年. 《Gorilla: Large Language Model Connected with Massive APIs》. arXiv preprint arXiv:2305.15334, 网络首发. https://doi.org/10.48550/arXiv.2305.15334.
函数调用失败类别:调用失败在运行时的表现,以及各类失败通常指示的训练缺陷。
失败类别 运行时观察到的现象 可能的训练原因
调用格式错误 大括号未闭合、JSON 无效、控制字符未转义 语料中的序列化缺陷
违反模式 缺少必需参数、未知键、类型错误 模式记忆、缺少随机丢弃
未知工具 调用了当前提示中未声明的工具 训练中使用固定工具集、没有干扰项
调用截断 调用在闭合定界符之前被截断 训练中未对被截断的轮次进行掩码处理

第三项指标直接针对模式记忆问题。节 1.6 的模式鲁棒性在训练语料从未包含的工具和模式上进行测量,其中包括对熟悉工具的参数进行重命名,这与工具使用基准针对未见过的 API 所采用的做法一致 (Qin 等 2024年)。这一指标用两个比率概括。模式遵循准确率是指调用中指定了已声明工具,且键和类型与该工具当前模式相匹配的比例:

Qin, Yujia, Shihao Liang, Yining Ye, Kunlun Zhu, Lan Yan, Yaxi Lu, Yankai Lin, 等. 2024年. 《ToolLLM: Facilitating Large Language Models to Master 16000+ Real-World APIs》. Proceedings of the 12th International Conference on Learning Representations (ICLR).

\[\text{SFA} = \frac{1}{N} \sum_{i=1}^N \mathbf{1}\left( \text{Tool}(a_i) \in \mathcal{S}_i \;\land\; \text{Keys}(a_i) \subseteq \text{Params}(\mathcal{S}_i) \;\land\; \text{Types}(a_i) \models \text{Spec}(\mathcal{S}_i) \right)\]

参数化记忆错误率是指调用中使用了训练集中的参数名称、但当前模式并不包含该名称的比例:

\[\text{PRE} = \frac{1}{N} \sum_{i=1}^N \mathbf{1}\left( \exists k \in \text{Keys}(a_i) : k \in \mathcal{K}_{\text{train}} \land k \notin \text{Params}(\mathcal{S}_i) \right)\]

PRE 上升是记忆现象的标志,而且即使分布内成功率提高,PRE 也可能上升。

第四项指标是每个验收通过任务的成本。微调会改变智能体消耗的轮次数和输出 token 数,有时会降低消耗,有时则会增加消耗,尤其是在模仿了推理过程或较长示范时。每个验收通过任务的轮次数和输出 token 数应按 加速器服务延迟 中的方式计价,并纳入评分表,因为一个候选策略即使成功率略有提高,若 token 消耗翻倍,也未必算得上改进。

第五项指标是能力保留。还应在基座模型能够处理的留出通用任务上对候选策略评分,例如指令遵循、编程,以及智能体领域之外的推理任务。分数下降意味着遗忘,补救方法是采用 节 1.8 中的数据混合方法,然后重新评估。

比较协议

只有在比较条件受控时,评分表才有意义。候选策略应在相同的任务测试配置上运行,使用相同的工具版本、沙箱配置、预算和重复运行次数,并结合 统计评估的严谨性 中的置信区间报告差异。基线始终应包含问题分诊时考虑过的成本更低的替代方案,例如改进提示或模式后的基座模型,因为微调的目的在于超越那些无需改变权重的修复方案。评估任务与训练语料在代码仓库和任务族层面不得重叠,数据集划分卫生验证 中的数据划分规范会在训练开始之前确保这一点。通过评估的候选策略将进入 分阶段金丝雀部署 中的分阶段发布流程;该流程要求候选策略在替换当前运行的策略之前,必须具备因果证据和统计证据(原则 15)。

困惑度背离与多维评估

使用语言建模困惑度或 token 级验证损失来评估微调后的智能体策略,是一种公认不可靠的做法。策略可能在验证损失降低的同时,出现灾难性的运行崩溃,例如输出无效的工具调用 JSON,或在收到意外的命令行错误后陷入无限重试循环。可靠的评估需要一份实证评估评分表,用于衡量任务完成率、语法有效性、步骤效率和灾难性遗忘,如 图 7 所示。

图 7: SFT 检查点的多指标评估雷达图:通过多指标雷达图比较和定量评分表,从任务完成率、工具调用语法有效性、轨迹执行效率和灾难性遗忘审计四个运行维度,将候选策略检查点与未经适配的基础模型及最低生产验收阈值进行评估比较。尽管检查点 A 的语法有效性很高(\(99.2%\)),但其轨迹效率严重下降(\(28%\)),且基础推理能力受损(\(58%\))。检查点 B 在全部四个维度上均显著超过生产阈值包络,确保了部署的鲁棒性。

四个运行评估维度在 表 5 中得到了系统评估。

表 5: 适配策略实证评分表:针对具有 70B 参数的策略,在 300 条留出的软件工程轨迹上进行评估,比较各适配策略的性能、训练效率和产物大小。
适配配置 序列打包(\(U_{\text{pack}}\)) 训练时间(8\(\times\) H100 节点) 工具语法错误率 SWE-bench 任务成功率 检查点产物大小
零样本基础模型(仅使用提示) 不适用 0.0 小时 14.8% 18.2% 141.2 GB(基础模型)
朴素 SFT(全量损失,零填充) 9.2% 34.2 小时 3.4% 22.4% 141.2 GB(全量)
无正则化 SFT(动作掩码,序列打包) 97.1% 3.5 小时 2.1% 26.8% 1.8 GB(LoRA)
综合 SFT 流水线(掩码,序列打包,模式正则化) 97.4% 3.6 小时 0.1% 38.6% 1.8 GB(LoRA)

受控评估协议与运行框架组件

对自主智能体进行基准测试需要使用封闭隔离的评估环境,以防止数据泄漏和非确定性的网络噪声。关键运行框架架构组件详见 表 6。

表 6: 封闭隔离评估运行框架的架构组件:基准测试各阶段的组件职责、隔离边界和确定性机制。
运行框架组件 子系统与边界 运行机制 确定性与封闭隔离性约定
候选检查点 模型服务运行时 冻结模型权重,采用贪心采样(\(T=0, \text{top\_p}=1.0\))。 消除重复试验中的随机生成噪声。
任务测试夹具 任务配置存储 固定初始状态 \(\mathbf{S}_0\),并封存验证测试套件。 与训练语料严格隔离;确保零数据污染。
封闭隔离容器 沙箱运行时 隔离的 OverlayFS 文件系统,以及仅允许环回通信的网络命名空间。 防止宿主机状态泄漏和外部网络依赖漂移。
固定工具模拟对象 沙箱 IPC 适配层 注入确定性的执行延迟和预设返回载荷。 使评估免受第三方服务延迟和中断的影响。
封存测试判定器 特权监督器 从宿主机只读挂载中执行权威单元测试。 断言不变量得到满足;不受智能体篡改工作区的影响。

训练留给运行时的职责

至此,流水线已完整构建,其中每个阶段都针对模仿学习可能出错的一种具体方式而设。序列化按照模型服务所用的模板,以因果顺序写入每条获准纳入的轨迹,并保留证据。观测掩码使模型仅针对其自身写出的内容进行训练。序列打包在注意力和位置上隔离各条轨迹,并按样本赋予权重。同策略数据和故障注入将语料扩展到策略实际到达的状态,每个新标签都通过与原始数据相同的级联流程获准纳入。模式扰动使模型持续从上下文中读取契约。蒸馏提供轨迹,并将操作流程从提示中移除;适配器按角色封装训练结果;闭环评估则决定是否发布。

最终得到的策略,其提议能更频繁地通过运行时的各项关卡:有效调用更多、无效轮次更少、测试失败后恢复成功的次数更多。这并不意味着运行时可以更加信任该策略。模型侧训练降低了错误提议出现的概率,却无法将其消除,因此不变量闭包原则(不变闭包原则)仍与之前完全一样成立。每次调用仍须通过运行时的模式验证器和授权检查,每条命令仍须在沙箱内运行,每项完成声明仍须由封存测试加以核验(不变闭包原则)。如果团队因为微调后的模型很少触发某项运行时检查而放宽该检查,就会将罕见的模型错误变成未经检查的错误。

自动化策略编译流水线

轨迹收集、验证过滤、模式正则化、参数高效微调和实证评分表评估的端到端生命周期,构成了一条自动化策略编译流水线,如 图 8 所示。

图 8: 端到端监督式策略编译流水线:监督式策略编译中六个封闭隔离阶段的架构有向无环图(DAG),涵盖轨迹数据准备、分布式参数优化和制品发布验证。原始多轮执行轨迹依次经过模式验证(阶段 1)、采用面向动作的损失掩码的确定性角色序列化(阶段 2),以及采用块对角注意力掩码的动态序列打包(阶段 3)。编译后的序列缓冲区送入分布式低秩参数优化阶段(阶段 4),生成不可变的已签名适配器清单(阶段 5);这些制品必须通过封闭回归沙箱的检验(阶段 6),才能晋级至生产环境的模型服务。

外部强制执行不变量

微调调整模型的先验,使其更倾向于有效的工具模式、简洁的推理词元和鲁棒的错误恢复轨迹。然而,无论进行多少参数优化,都无法将随机神经网络变成不可突破的安全屏障。正如不变量闭包原则(不变闭包原则)所形式化的那样,运行时能力、文件系统隔离、网络出站防火墙和凭据代理必须始终由模型底层的机制强制执行。

谬误与陷阱

微调错误很难察觉,因为标准的离线信号——下降的损失和看起来更规整的样本——恰恰会在智能体表现变差的情形下改善。以下误解在智能体微调中反复出现。

谬误: 对获准纳入训练的轨迹中的每个词元都进行训练,能让智能体学到更多。

在智能体轨迹中,大多数词元都是环境写入的观测。在笔记本 1.1 的分析实例中,观测约占序列的 77%。对这些词元进行训练,会将大部分损失用于预测工具输出,并让模型学到工具调用之后紧接着就是工具输出,因此部署后的模型会自行编写结果,而不是交出当前回合的控制权。观测损失掩码(节 1.3)仅对策略实际写入的词元进行训练,这些词元约占七分之一,其余词元则保留为上下文。

谬误: 一旦模型针对我们的工具完成微调,就可以从提示中移除模式,并放宽验证器的约束。

微调将操作流程移入权重,而非接口契约(表 1)。必须从权重中回忆模式的模型,会输出训练时学到的参数,而第一次接口变更就会使其失效(节 1.6)。放宽验证器的约束更糟,因为这会移除原本将这些过时调用转化为无害拒绝的检查。训练降低了错误提案的发生率;运行时检查仍然是唯一的保障。

陷阱: 仅用首次尝试就成功的轨迹构建语料库。

由顺利运行的轨迹组成的语料库,会教策略在一切顺利时该做什么,却完全不会教它如何应对自身错误造成的状态。根据 公式 4 中的界,这种缺口的代价随决策时域的平方增长;当每步准确率为 98%、执行三十轮时,最坏情况下可能有 9.3 轮偏离示范路径。通过同策略采集(节 1.5)和故障注入(恢复示范筛选)获得的恢复轨迹,才能将这一界降至线性。

陷阱: 在普通因果掩码下打包轨迹。

打包消除了填充,但普通因果掩码允许每条轨迹关注排在其前面的其他打包轨迹,而连续的位置索引会将后续轨迹置于模型在服务时从未用作起点的位置。策略会学到不相关任务之间的依赖关系,并可能将一个任务中的文件路径或标识符带入另一个任务。采用块对角掩码并为每条轨迹重置位置索引(节 1.4),可使每条打包轨迹与该轨迹单独用于模型服务时完全一致。

陷阱: 选择验证损失最低的训练后模型。

验证损失是在大多干净无误的示范上通过教师强制计算的,它会奖励对策略并不写入的词元的预测。未使用掩码的模型可以达到比使用掩码的模型更低的损失,却仍会在智能体运行框架中有更多任务失败(节 1.9.1)。候选模型依据经验证的成功表现、\(\text{pass}^k\)、在留出的工具家族上的函数调用准确率、每个验收通过任务的成本以及能力保持情况进行比较,并与问题分诊时考虑过的成本更低的修复方案对照。

总结

轨迹微调使用获准纳入训练的智能体轨迹来训练模型,使其提出更好的动作。其适用范围取决于智能体知识存放在何处。操作流程可以迁移到权重中,契约必须保留在上下文中,而强制执行仍由运行时负责。在这一范围内,流水线的任务是确保模仿忠实于示范。轨迹按照服务时使用的模板和因果顺序进行序列化,并完整保留环境提供的证据。损失仅针对策略写出的 token,包括回合结束 token。打包后的轨迹在注意力和位置上相互隔离,并按样本加权。忠实模仿在偏离示范路径后仍会失效,其代价随时域长度的平方增长,因此需要通过同策略数据采集和故障注入,将语料库扩展到策略实际到达的状态;每个新标签都必须通过与原始数据相同的验证器检验,才能获准纳入。模式扰动使模型持续读取其契约。上下文蒸馏和教师蒸馏提供所需行为,并将操作流程从提示中移除;适配器使每个角色都能独立发布和回滚;评估则依据闭环验证的成功率,而非验证损失,对候选模型进行排序。

要点回顾: 在策略自身到达的状态上,训练策略自身写出的 token
  • 微调迁移的是操作流程,而非契约:权重可以学会使用哪个工具以及如何恢复;模式、任务事实和获准的权限范围必须保留在上下文中,所有检查仍由运行时执行。
  • 将损失对准策略写出的内容:观测占据了轨迹中的大部分 token;对这些 token 进行训练,会教会模型自行编写工具结果。应屏蔽这些 token 的损失,同时保留回合结束 token 作为训练目标。
  • 干净示范的失效代价呈二次增长:行为克隆的最坏情况代价按 \(O(\epsilon H^2)\) 增长;带有获准纳入的标签和故障注入恢复轨迹的同策略数据,可将其降至 \(O(\epsilon H)\)。
  • 记住模式意味着契约失效:训练中的固定模式会使模型将参数名学成常量;应扰动模式,并在语料库从未包含的工具族上衡量成功率。
  • 依据验证成功率,而非损失,对训练后的模型排序:在验证成功率、\(\text{pass}^k\)、调用准确率、每个验收通过任务的成本以及能力保持情况上,与成本更低的提示或模式修正方案进行比较,然后通过与其他变更相同的准入关卡发布。

观测损失掩码(原则 17)被证明是一种存在边界情形的机制,而非一条简单规则。掩码移除观测对应的损失,但将观测保留在上下文中;它必须使回合结束 token 继续参与损失计算,并根据部署后的策略必须执行的行为,决定是否将推理纳入损失计算。经验证的轨迹后训练(原则 16)从二次界与线性界之间的差距中获得了定量依据,这也解释了为何恢复轨迹应纳入语料库。在整个过程中,训练并未改变不变量闭包原则(不变闭包原则)的地位,因为权重改变的是模型提出哪些动作,绝不会改变运行时允许哪些动作。

后续内容: 从模仿到针对验证器的优化
策略能学会哪些示范中从未展示过的行为?模仿受限于其示范。微调后的策略充其量只能复现教师的行为,而同策略数据仍然需要知道正确动作的标注者。对于许多智能体任务,环境提供了一种能力弱于标注者但成本更低的机制:验证器能够检验某个结果,即使它自身无法生成该结果。可验证奖励强化学习 以本章微调后的策略为起点,直接针对这类验证器进行优化,沿用观测掩码和适配器,并直面优化带来的新失效模式:策略学会了满足检查,而非完成任务。

回到顶部
← 三卷书架