@GottliebEli: 写了一些关于如何设计好的RL任务的想法!

X AI KOLs Timeline 新闻

摘要

Eli Gottlieb 分享了关于设计高效RL训练任务的见解,将任务构建描述为一个涉及四个组件——提示词、世界、验证器和意图——的约束满足问题,并阐述了如提示词-验证器、验证器-意图等对齐维度,以避免奖励作弊(reward hacking)。

写了一些关于如何设计好的RL任务的想法!https://t.co/6UDvpIEX08
查看原文
查看缓存全文

缓存时间: 2026/10/13 23:49

如何制作一个好的 RL 任务

最近我一直在做大量的任务。其中不少是糟糕的,有一些还行,而现在终于做出了几个好的。通过这些工作,我对任务生成过程有了一些我认为很有价值的见解,想在这里分享。

我会把内容分为四个部分:

  • 我如何定义一个任务

  • 任务的内部运作机制

  • 我对制作好任务的看法

  • 构建任务工厂

什么是任务?

我喜欢把任务看作四个相互关联的组成部分:

Prompt(提示)

即请求本身。对于编码任务,它可能是“去实现功能 X“或“我遇到了 bug Y,帮我修复“。金融任务的提示可能是“这里有一些文档、一些电子表格,帮我构建一个财务模型“。

World(世界)

决定模型所处环境的数据和动态。对于编码任务,世界可能是一个代码仓库;对于金融任务,世界可能是一组凌乱的文件系统、Excel 和一个 Slack 克隆版。世界可以是真实世界,但也不必是。

(为了与世界交互,模型会使用工具;为了简化,我们假设这组工具以及它们暴露给模型的协议是充分且固定的。)

Verifier(验证器)

我们如何定义“好“是什么样子。这可以是一个确定性机制(例如一个评分脚本,确保某段软件通过所有测试),也可以由模型驱动(由单个 LLM/Jev 调用来将生成的答案与参考答案进行比较,甚至启动一个全新的 agent 会话来评分)。

Intent(意图)

你希望模型在哪个方面变得更好,明确指出来。无论是修复某类软件 bug、执行某个定制化工作流,还是按照特定的准则行事,你的任务都应该立足于某个明确的改进目标或你想要解决的具体失败模式。

好了,现在我们有了 prompt、world、verifier 和任务意图。那它们之间是如何连接的呢?

任务的内部运作机制

我把任务生成过程看作一个约束满足问题:作为任务作者的你,正在一组相互关联的组件——你的 prompt、world 和 verifier——之间进行调整,同时必须受制于某个总体意图。对某个组件调整太多,你会发现自己超出了目标分布;调整太少,你可能在强化错误的东西。这一切都很模糊,可能也没太说清楚,让我来定义几个重要的对齐轴:

Prompt <-> Verifier

你的 prompt 和 verifier 应该是一致的。如果你认为 verifier 是固定的,那你的 prompt 应该包含足够的信号,引导一个足够智能的模型去满足那个 verifier。假设你的任务是为某个 Python 版的 Pacman 添加多人游戏支持,verifier 是一套健壮的测试套件,用来确保生成的代码正确实现了多人功能。如果任务提示是“让这个游戏更好玩“,那就不公平了——你没有给模型足够的机会去获得奖励。

Verifier <-> Intent

你的 verifier 应该与任务意图对齐。Verifier 是唯一的优化压力来源;任何能够满足它的行为都会被强化,包括你不想要的行为。你可能听说过这种 verifier 与意图之间的错位——“奖励黑客”:模型能够在不真正做你想让它做的事情的情况下获得奖励。比如编写不完整、有 bug 但仍能通过评分脚本中所有测试的代码是一个例子;逃出你的沙箱并黑入 Hugging Face 来找到问题答案是另一个例子。

Prompt <-> Intent

你的 prompt 必须与任务意图对齐。假设你想训练一个能够使用自定义 DSL 直觉地浏览内部文档来回答问题的聊天机器人。在生成训练任务时,提示应该在分布上与聊天机器人在生产环境中将面临的提问类型对齐。如果我们能预期聊天机器人的用户倾向于某种提问风格(比如信息不够充分的查询),你也应该在训练中遵循同样的提问风格。模型不擅长像我们一样说话(有一些很酷的研究在解决这个问题)——如果任务提示与你的生产 agent 将面临的场景偏差太大,你就有风险在打磨某些在生产中不会被用到的技能。

Worlds(世界)

Worlds 高度依赖于任务,可能值得单独写一篇帖子——它们形状大小各异,存在于从“真实“到“模拟“的光谱上:在一个未被修改的代码仓库上做编码任务,我认为这是一个相当“真实“的世界;一个金融任务让模型基于一批真实的内部文档加上有依据的合成辅助数据来生成报告,仍然是一个相当“真实“的世界,只是带了一点“合成“的味道;一个计算机使用任务请求在四个完全克隆的旅游网站上预订一个为期两周的整个假期,那就非常“合成“了。

每个阵营都有各自的好处和缺点——详细展开我怕会跑题——但重要的是要理解,对于存在于这些半合成或完全合成世界中的任务,世界本身是另一个可调整的优化面,必须与其对应的 prompt、verifier 和意图对齐(你的任务世界越接近真实世界,你需要对它做的调整就越少,因为真实世界就是 ground truth 目标)。

对于半合成到完全合成的世界,有一个很有用的框架:一个世界是充分的,当且仅当它能够可靠地引出任务的目标失败模式。举个快速的例子:上面提到的合成“帮我预订两周假期“任务测试的是模型在 web 领域的长程推理、规划和周密性。任何失败的尝试都应该展现出这些方面的某项不足;成功的尝试应该展现出对这些技能的全面掌握。模型在某个合成网站上因为一个 bug 而卡住,这不是一个合理的失败;模型跳过了研究过程中本应是必要的步骤却得出了正确答案,这可能意味着世界不够丰富,无法有效地支撑这个任务。这当然假设 verifier 是可靠的、prompt 是校准良好的,这也凸显了这些组件之间相互作用的微妙性。

你可能会问,为什么这一切很重要?为什么我们必须在这个艰苦的事业中坚持最高标准?强化学习不区分预期行为和非预期行为;它只是强化任何获得奖励的东西。上述任何一个轴上的错位都会让你冒着强化错误东西的风险。虽然这看起来微不足道,但它可能带来灾难性的后果——最近 OpenAI Hugging Face 攻击事件就说明了这一点(可以推测),某个模型是在那些可以通过不正当手段获取奖励的任务上训练的,导致了错位且极度危险的行为被强化。

现在我们理解了这些组件是如何连接的,让我们进入有趣的部分:如何实际制作一个任务。还有最后一点我之前可能没说清楚:当然我们希望编码 agent 尽可能多地承担这项工作!

我对制作好任务的看法

制作好任务归根结底是识别并实现修正循环(revision loops),以正确地校准任务的优化面——它的 prompt、verifier 和 world——使其与一个合理的任务意图或失败模式对齐。

我已经说过,我把任务生成过程看作一个约束满足问题,任务作者在任务相互关联的组件之间精心编排一场微妙的舞蹈,以揭示模型真实的失败模式。这种微妙的舞蹈可以通过 agent 流水线来编码。

一个简单的任务生成流水线可能如下:

  • 编写任务

  • 评测任务

  • 审查轨迹(traces)

  • 要么回到第一步(1)进行修改,要么保存任务,要么丢弃任务

一个稍复杂的 SWE 流水线可能如下:

  • 编写任务 prompt(还没有 verifier)

  • 并行地,将任务 prompt 给到一些 agent(“求解 agent”),让它们求解任务;同时启动另一个 agent(“verifier agent”),给它任务 prompt,让它为任务创建一个评分脚本

  • 当“求解 agent“完成、“verifier agent“产出评分器后,对求解 agent 的工作进行评分;同时再启动一组 agent(“黑客 agent”),给它们任务 prompt + 评分脚本 + 任务意图,让它们寻找一种仍能通过测试但不可取的解法

  • 将所有这些信息(评分脚本、求解 agent 的工作 + 它们的得分、黑客 agent 的发现)传递给一个审核 agent,由它决定是保存任务、丢弃任务,还是回到最初的编写 agent(1)或 verifier agent(2)进行修改

这些流水线不过是 agent 执行工作的自然语言程序。关键所在(alpha)在于配方:那些编排、顺序、专业化和循环,能够将任务及其相互关联的组件塑造成型。

在我几乎所有工作中都遇到的一个修正循环是校准 verifier。无论它是确定性的还是基于 LLM 的,你都需要确信你的 verifier 能够奖励好的、惩罚坏的。你很少能第一次就做对;一个恰当的修正循环必须在宣称 verifier 可靠且忠实之前,梳理出边缘情况并针对 ground truth 标签进行回归测试。

类似地,将现有任务变得“更难“也可能是一个危险的游戏:简单来说,以增加任务难度为目标的修正循环可能会瞄准人为的或刻意的维度,而这些维度与任务意图不对齐(比如以不现实的方式在任务提示中添加大量琐碎要求)。一个让任务变难的修正循环必须在校准好之后,沿着有意义的维度来提升难度。

好了,酷。那我们如何大规模地做到这一点呢?

可验证性光谱

稍作回顾——在我讨论“合理的任务失败“、“有意义的难度维度“和“任务意图“时,我忽略了其中一个重要部分:任务可验证性。我认为这是一个光谱——一端是高度可验证的数学任务,只有唯一正确答案;另一端是创意写作任务,对“正确“或“好“没有明确的定义。

我们这个领域中绝大多数有趣的工作都处于这个光谱的中间某处:做研究、法律工作、金融工作或几乎所有其他白领行业的工作,都没有单一的“正确方法“。即使是像编码这样看似可验证的领域,也有重要的、不可验证的维度,比如品味、风格和可读性。对于你想优化的这些不可验证特征,必须有某种信号来源,某种“做得好“的定义。在我看来,对于绝大多数领域来说,这个信号来源仍然是人类。

那位理解财务模型应该如何构建的细微之处的投资银行家。那位想要将良好的工程品味灌注到模型中的软件工程师。这些人类专家才是终极的验证器。

作为一个思维实验,考虑这样一个世界:你可以完美地数字化一位人类专家,让他们检查这个流水线中的每个组件。你会如何给他们提示?你会让他们产出什么?你可能会让他们审查任务提示、分析工具调用来理解世界的动态,以及审计验证器以确保对“好“的定义得到了恰当的近似。

这个世界显然是虚构的,但它为梳理任务流水线应该如何组织提供了一个有价值的子问题来解决。

任务工厂

任务工厂是一个外部优化循环,它将人类判断逐步提炼到任务生成流水线本身中,持续提升其以越来越低的成本产出与人类意图对齐的高质量任务的能力。

我们现在有两个优化循环:

内部循环:即上述的配方。一个在任务的优化面(prompt、world、verifier)上运行的 agent 流水线。这个配方受制于某个总体意图——例如,产出能够测试 agent 是否能独立识别相关源文件、调和矛盾数据并构建出可靠的财务模型的金融任务。

外部循环:一种随着我们对“好任务“的理解不断深化而更新配方的机制。

例子:在审查一批初始金融任务时,投资银行家发现任务提示不切实际地引导模型去读特定的文件——在现实世界中不会有这样的提示。这个外部循环将这个权威信号转化为对配方的更新,使未来的任务更忠实地服务于最初的目标。

我把配方定义为 agent 执行工作的自然语言程序:“编写任务,然后评测,然后审查,如有问题则回到编写者,如果可靠则保存任务,如果无可救药则丢弃。”

这个配方实际上如何编码,以及施加多少结构化约束,我认为尚存争议。光谱的一端,你的配方可以是在某个 agent SDK 中编写的僵化脚本;另一端它可以是一个单独的 skill 文件,交给像 Prime Agent 这样能够编排任意复杂子 agent 群体的系统。我认为,鉴于当前模型的能力和成本,最优的中间地带在于某个位置:一个在更高层次的编排结构中利用通用 agent 能力的状态机。

无论你选择如何构建配方,这个选择将决定这个外部循环所作用的优化面。如果结构化程度很低,也许就是一个持续更新的单一 skill 文件;在我倾向于的这个中间地带,优化面包括 agent 运行的顺序、职责的模块化、每个 agent 如何被条件化、信息在系统中流动的方式等。

以下是我发现的一些有助于构建外部循环的策略:

将人类判断分解为明确的标准

对于每个任务族,指出重要的特征。这些可能包括:

  • 任务提示与生产流量对齐

  • 失败的尝试展现出你希望任务针对的有意义的不足

  • 成功的尝试展现出你想要强化的行为

  • 世界包含足够的信息和复杂度来有意义地锻炼目标技能

这些就是你的受保护的任务质量轴。对于每个轴,在流水线中实现一个守卫(guard),检查生成的任务是否满足它。例子:在金融任务编写 agent 之后,可以跟一个专门识别提示中不现实线索的审核 agent——比如提到了特定的文件、工作表或数字,而真实分析师不会收到这样的信息。如果发现了任何此类问题,任务就会被路由回编写者进行修正。

将人类判断编译为成本逐渐降低的配方组件

你的配方中的每个组件都有其作用——你可能有一个任务编写组件、一个评分组件、一个审查组件,诸如此类。一条任务流水线应该在最小化每个任务的花费的同时最大化质量产出,因此随着时间的推移,当来自可信赖来源的决策、解释和标注以信号的形式不断积累时,应该存在一种编译算法,能够开发出更廉价的替代品,充分保留更昂贵组件的判断力/能力。

拿上面的金融例子来说。最初,投资银行家可能直接充当配方中的一个关卡,丢弃糟糕的任务,确认好的任务,并标注需要改进的任务。最终,在积累了足够的样本后,这个组件可以被替换为……

相似文章

@tanayj: https://x.com/tanayj/status/2072766211256119475

X AI KOLs Timeline

本文探讨了将强化学习应用于缺乏明确可验证性任务的挑战,引用了Dario Amodei关于实现“数据中心中的天才之国”的预测,并讨论了RLVR、RLHF、Constitutional AI以及Scale AI的基于规则的奖励等技术。