多数强化学习任务质量不佳,我总结出优质任务的四个关键组件
最近我设计了大量任务,其中多数质量不佳,部分尚可,最终有少数达到了优秀水平。通过这些实践,我总结出了一些对任务生成流程有价值的见解,在此分享。我会把内容分成四个部分:任务的定义、任务的内部运作逻辑、设计优质任务的思路、构建任务工厂。
什么是任务?
我认为一个任务由四个相互关联的部分组成:
- 提示词(Prompt):任务要求。对于编码任务,它可能是“去实现功能X”或“我遇到了Bug Y,请修复它”;对于金融任务,它可能是“这里有一些文档和表格,请帮我搭建这个财务模型”。
- 环境(World):模型运行所处环境的数据和动态规则。编码任务的环境可能是一个代码仓库;金融任务的环境可能是混乱的文件系统、Excel文档和类Slack工具的集合。环境可以是真实世界,也可以不是。(为了和环境交互,模型会使用工具;为简化讨论,我们认为工具集合和它们暴露给模型的协议是固定且足够的。)
- 验证器(Verifier):我们如何定义“好”的结果。它可以是确定性机制(比如确保软件测试通过的评分脚本),也可以由模型定义(单个大语言模型/Jev调用将生成答案和参考答案对比,甚至启动全新的智能体会话来评分)。
- 意图(Intent):你明确希望模型提升的能力方向,比如修复特定类型的软件Bug、执行定制工作流,或是按照特定规则行动。任务需要锚定在你希望模型提升的明确方向上,或是你希望解决的具体失败模式上。
现在我们已经有了提示词、环境、验证器和任务意图,这些部分是怎么连接起来的?
任务的内部运作逻辑
我把任务生成流程看作一个约束满足问题:作为任务设计者,你需要调整提示词、环境、验证器这组相互关联的组件,同时让它们符合总体意图。对一个组件调整过多,任务就可能偏离目标分布;调整过少,又可能强化错误的行为。下面是我认为最重要的几个对齐维度:
- 提示词 ↔ 验证器:提示词和验证器必须一致。如果验证器固定,提示词需要包含足够的信号,引导足够智能的模型满足验证器的要求。比如你的任务是给基础版Python吃豆人添加多人联机支持,验证器是一套确保多人实现正确的健壮测试集。如果你的提示词只写“让这个游戏更好”,那对模型并不公平——你没有给模型足够的机会获得奖励。
- 验证器 ↔ 意图:验证器必须和任务意图对齐。验证器是优化压力的唯一来源;任何能让验证器满足的行为都会被强化,其中包括不符合预期的不良行为。你可能听过这种不对齐的情况——“奖励黑客”:模型不需要完成你真正想要它做的事,也能拿到奖励。比如编写不完整、有缺陷但仍然能通过所有测试的代码,或是逃离沙盒、黑进Hugging Face找到问题答案,都是这类例子。
- 提示词 ↔ 意图:提示词必须和任务意图对齐。比如你想训练一个聊天机器人,让它能使用自定义领域特定语言(DSL)梳理内部文档来回答问题。在生成训练任务时,提示词的分布需要和聊天机器人上线后会遇到的问题类型对齐。如果用户实际使用时倾向于某种提问风格(比如不完整查询),训练时的提示词也需要遵循这种风格。模型不擅长像人一样自然地提问(有相关研究正在解决这个问题);如果任务提示和智能体上线后面临的情况偏差太大,你可能会训练出一些实际用不上的技能。
环境
环境高度依赖于具体任务,本身就值得单独写一篇文章讨论。环境形态多样,分布在从“真实”到“模拟”的区间内:未篡改仓库上的编码任务属于相当“真实”的环境;要求模型基于真实内部文档加少量合成辅助数据生成报告的金融任务,仍是偏真实的环境;要求模型在四个完全克隆的旅行网站上完成两周度假预订的计算机使用任务,就属于非常“合成”的环境。
不同类型的环境各有优缺点,这里就不展开讨论了,但需要明确:半合成或全合成环境本身也是可调整的优化面,必须和对应的提示词、验证器、意图对齐。任务的环境越接近真实世界,需要的调整就越少,因为真实世界本身就是目标真值。
对半合成或全合成环境,有一个实用的判断框架:只有当环境能够稳定引出任务目标的失败模式时,它才是足够的。举个例子:前面说的合成“帮我预订两周假期”任务,是用来测试模型在网络领域的长时程推理、规划和做事周全性。任何失败尝试都应该体现出这几个能力中某一个的缺陷,成功尝试则体现出对这些能力的掌握。如果模型只是因为合成网站本身的Bug卡住,那不是合理的失败;如果模型跳过了研究过程中必要的步骤还能得到正确答案,那说明环境的丰富度不足以支撑这个任务。当然,这一切都建立在验证器合理、提示词校准到位的基础上,也体现出这些组件之间相互作用的微妙性。
你可能会问,这一切为什么重要?为什么我们要在这项费力的工作中坚持高标准?强化学习不会区分预期行为和非预期行为;它只会强化能获得奖励的行为。上述任何维度不对齐,都可能让你强化错误的行为。这看起来可能不起眼,但会造成灾难性后果——近期OpenAI的Hugging Face攻击事件就是一例,据推测该事件中模型训练所用任务的奖励可以通过不当手段获取,最终导致错误且高度危险的行为被强化。
现在我们理解了这些组件的连接方式,接下来聊聊具体怎么设计一个任务。另外需要补充一点:我们当然希望编码智能体能完成尽可能多的工作!
设计优质任务的思路
设计一个好任务,核心就是识别并实现修正循环,针对合理的任务意图或失败模式,正确校准任务的各个优化面——提示词、验证器和环境。我之前提过,任务生成是一个约束满足问题,任务设计者需要协调各个相互关联的组件,以暴露模型合理的失败。这种协调可以通过智能体流水线来实现。
一个简单的任务生成流水线大概是这样:
1. 撰写任务
2. 评估任务
3. 审计轨迹
4. 要么返回第1步修改任务,要么直接保存任务,要么丢弃任务
一个更复杂的软件工程(SWE)流水线大概是这样:
1. 撰写任务提示词(暂时没有验证器)
2. 并行给多个“求解智能体”任务提示词让它们求解,同时启动另一个“验证器智能体”,让它根据提示词创建任务的评分脚本
3. 求解智能体完成后,验证器智能体也生成了评分器,接下来给求解结果评分;同时再启动一组“黑客智能体”,给它们提示词、评分脚本和任务意图,让它们寻找仍然能通过测试的不良解
4. 将所有信息(评分脚本、求解智能体的工作和得分、黑客智能体的发现)交给评审智能体,由它决定保存任务、丢弃任务,还是返回给原任务作者或验证器智能体修改
这些流水线本质上就是智能体工作的自然语言程序。核心在于编排方式:顺序、分工和循环,能把任务和它的各个关联组件梳理成型。
我在几乎所有工作中都遇到过校准验证器的修正循环。不管验证器是确定性的还是基于大语言模型的,你都需要确认它能奖励好结果、惩罚坏结果。很少有人第一次就能做对;合理的修正循环必须梳理出边缘情况,并针对真值标签做回归测试,才能确认验证器合理可靠。
同样,给现有任务增加难度也可能是一件危险的事:如果想当然地通过修正循环提升难度,会针对不符合任务意图的人为维度调整(比如不切实际地给提示词添加大量详尽要求)。提升任务难度的修正循环必须沿着有意义的维度校准难度。
可验证性区间
先退一步说:在我讨论“合理任务失败”“有意义的难度维度”和“任务意图”时,我漏掉了一个重要部分:任务可验证性。我认为可验证性是一个区间:一端是高度可验证的数学任务,只有一个正确答案;另一端是创意写作任务,没有清晰的“对”或“好”的定义。
世界上绝大多数有意思的工作都落在区间中间:研究、法律工作、金融工作,几乎所有白领工作都没有单一的“正确方法”。哪怕是看起来可验证性很强的编码领域,也有品味、风格、可读性这类不可验证的重要维度。对于你想要优化的这些不可验证特征,必须要有信号来源,也就是“做好工作”的定义。在我看来,对绝大多数领域来说,这个信号来源仍然是人类。
理解财务模型该如何构建的投资银行家、希望让模型养成良好工程品味的软件工程师,这些人类专家才是最终的验证者。做一个思维实验:假设你可以完美数字化一位人类专家,让他们检查流水线的每个组件。你会怎么给他们提示?你会让他们做什么?你大概率会让他们检查任务提示词、分析工具调用来理解环境的动态、审计验证器以确保“好”的定义被正确近似。这个世界显然是虚构的,但在规划任务流水线该如何组织时,它是一个很有价值的子问题。
任务工厂
任务工厂是一个外层优化循环,它会逐步把人类判断提炼到任务生成流水线中,不断提升流水线生成符合人类意图的高质量任务的能力,同时持续降低成本。
现在我们有两个优化循环:
- 内层:就是前面提到的方法。一组智能体流水线在任务的各个优化面(提示词、环境、验证器)上运作,这个方法绑定在某个总体意图上——比如生成金融任务,测试智能体能否独立识别相关源文档、调和冲突数据、构建合理的财务模型。
- 外层:随着我们对优质任务的理解不断加深,更新方法的机制。
举个例子:投资银行家在检查初始一批金融任务时,发现任务提示词不切实际地把模型引导到需要读取的特定文件上——在真实世界中不会有这种提示。外层循环就会采纳这个权威信号,更新方法,让后续生成的任务更符合原始目标。
我把方法定义为智能体工作的自然语言程序:“先撰写任务,然后评估,然后审计,有问题退回给作者,合格就保存,无法挽救就丢弃。”至于具体怎么编码这个方法,以及给它施加多少结构,目前还没有定论。区间一端是方法可以是在某个智能体SDK中编写的刚性脚本;另一端可以只是单个技能文件,交给Prime Agent这类能编排任意复杂子智能体集群的系统。我认为,结合当前模型的能力和成本,最优的结构在两者中间:一个状态机,在高层编排结构内利用通用智能体能力。
不管你选择怎么构建方法,这个选择会决定外层循环运作的优化面。如果结构很少,可能只是一个不断更新的单个技能文件;在我倾向的中间路线上,优化面包括智能体运行顺序、职责模块化、每个智能体的条件设置、信息在系统中的流动方式等等。
我总结了几个对构建外层循环有用的策略:
- 将人类判断拆解为明确标准:对每个任务族,列出重要特征,通常包括:任务提示与线上流量对齐;失败尝试能体现出你希望任务针对的有意义缺陷;成功尝试能体现你想要强化的行为;环境包含足够的信息和复杂度,能有效锻炼目标技能。这些就是你要维护的任务质量维度。对每个维度,在流水线中设置防护,检查生成的任务是否满足要求。比如,金融任务撰写智能体之后,会跟着一个专门负责识别提示词中不切实际提示的评审智能体——比如真实分析师不会得到的特定文件、表格或数据引用,如果发现了,任务就会退回给作者修改。
- 将人类判断编译为逐步成本更低的方法组件:方法的每个组件都有自己的作用:你可能会有任务撰写组件、评分组件、审计组件等等。任务流水线需要在最大化产出质量的同时最小化单个任务的成本,因此随着时间推移,来自可信来源的决策、解释、标注等信号不断积累,应该有一个编译算法,开发更便宜的替代品,同时足够保留昂贵组件的判断和能力。还是拿金融例子来说:一开始,投资银行家就是方法中的一道关卡,丢弃坏任务、确认好任务、标注需要改进的任务。最终,积累足够多示例之后,这个组件可以被一个能足够好代理人类专家的智能体会话替代。对某些组件(比如任务提示词关卡),只要能保证能力保留,这种编译甚至可以一直下放到Jev这类廉价分类器。
这样做能得到什么?
这就是应用在任务工厂上的持续学习:单个任务的反馈会被整合到方法中,因此工厂生成优质任务的能力会逐步提升,不需要重复花钱重新学习相同的经验。而且,如果设置得当,这些信号可以用来训练运行工厂本身的数据生成模型。
只要我们设计出正确的接口,提取人类判断并把这些专业知识整合到流水线中,这个方法没有道理不能跨领域泛化。它的妙处在于,随着前沿模型能力越来越强,它们提炼内化专家判断的能力也会越来越强,让它们能更好地驱动整个系统。
我们的目标是在半可验证领域有效提取信号,并把信号提炼成一个爬山机器,我认为我们已经很接近这个目标了。