Composer 2:基于强化学习的智能编程体训练

3 阅读10分钟

Composer 2 是一个前沿级别的模型,专门为智能软件工程而设计。它不仅仅是回答孤立的聊天查询,而是能够浏览整个代码仓库、运行 shell 命令、编辑文件,并与开发环境交互,以解决复杂的用户意图。

构建一个在此开放领域取得成功的模型,需要超越标准的公开基准。Cursor 的方法依赖于一个核心原则:通过在与生产环境完全相同的条件下训练模型,来最小化训练与测试的差异。

本文综合了 Composer 2 技术报告和 Cursor 关于实时 RL 的最新博客文章中的发现。你将了解到他们如何通过自摘要管理长程任务、通过非线性奖励塑造交互式智能体行为,并通过一个 5 小时的生产 RL 循环直接基于实时用户反馈进行闭环训练。

Composer 2 的训练流程

该训练流程将一个强大的通用模型转化为专门的编程智能体。Cursor 在评估了内部代码库困惑度、编码知识和状态追踪能力后,选择了 Kimi K2.5(一个 1.04T 参数、32B 激活的 MoE 模型)作为其基座模型。

持续预训练与 MTP

第一阶段是在代码密集型的数据混合体上进行持续预训练。此阶段主要使用 32k 的序列长度,接着进行 256k 的长上下文扩展,最后在针对性的编码任务上进行短期的监督微调(SFT)。经验数据证实,在 SFT 后获得更低的交叉熵与更高的下游 RL 奖励密切相关。

此阶段的一个关键新增内容是训练多令牌预测(MTP)层。团队使用自蒸馏从头训练这些 MTP 层,以匹配主语言模型头的精确 logit 分布。通过投机解码,加入这些层使得生产环境中的推理速度提升了 2 到 3 倍。

异步强化学习

第二阶段在真实的编码任务上应用异步强化学习。团队运行单 epoch RL,意味着模型永远不会针对同一个提示进行两次训练。

他们对 GRPO 算法进行了有意的修改。例如,去掉了长度标准化项,因为它会给梯度引入不需要的长度偏差。当所有 rollout 共享相同的正确性分数时,他们也会避免按标准差对组优势进行归一化,以防止噪声放大。

对于 KL 正则化,他们倾向于使用标准的 k1 = -log r 估计器。更常见的 k3 估计器在训练策略和参考策略出现分歧时会导致方差爆炸,进而引发不稳定。

大规模训练的策略一致性维护

在大规模下维护策略一致性需要紧密的基础设施集成。系统依赖于快速的、增量压缩的权重同步。每个训练等级只将相对于先前权重的差异传输到一个共享的 S3 存储桶。

推理工作进程在 rollout 过程中应用动态权重更新,确保长轨迹中的后续令牌仍接近训练策略。由于基座模型使用了混合专家架构,数值差异可能导致推理引擎和训练器选择不同的专家。Cursor 使用 MoE 路由重放来覆盖训练器的路由,以匹配推理引擎的专家分配。

为了进一步模拟真实环境,rollout 在专用的 Firecracker 虚拟机中进行,该虚拟机允许完整的文件系统和内存快照。Cursor 后端的影子部署确保了诸如语义搜索等工具与生产行为完全一致。

最终,这个 RL 过程在保留的评估集上同时提高了平均性能和最佳-of-K 覆盖率,扩展了模型实际可达到的正确解集。

为什么基准测试无法反映真实的编码工作

公开的基准测试未能捕捉到现代智能体工作流的真实难度。Cursor 观察到,在静态评估集上的分数往往与实际效用相关性较差。他们识别出造成这一差距的四个主要错位因素。

  1. 领域不匹配:像 SWE-bench 这样的数据集几乎完全专注于孤立的错误修复,而不是广泛的特性开发或复杂的重构。
  2. 过度指定的提示:公开的提示绕过了解读模糊意图的挑战。
  3. 污染与过拟合:模型在预训练期间经常吸收开源的补丁,人为地抬高了基准分数。
  4. 范围狭窄:基准测试只衡量功能正确性,忽略了代码可读性、延迟、成本和交互会话行为。

CursorBench 解决方案

为了解决这个问题,团队构建了 CursorBench。这个内部测试集从他们自己的工程团队生成的实际编码会话中提取任务。

结构上的差异非常明显。一个典型的 CursorBench 任务需要更改 181 行代码,而 SWE-bench 变体仅需 7 到 10 行。CursorBench 的提示也是高度不明确的,中位长度为 390 个字符,而公开数据集中常见的是 1185 到 3055 个字符。这迫使模型从稀疏的指令和大型代码库中综合上下文。

例如,评估套件中的一个示例任务:智能体收到一个关于失败重试循环的简短错误报告,以及充满不相关服务警告的生产可观察性日志。真正的根本原因不在日志噪声中,而是一个与 using 关键字相关的 esbuild 转译错误。诊断此故障需要跨源推理和忽略误导信息的能力,完美地镜像了人类开发者日常面临的模糊性。

自摘要

真实的软件工程任务跨越很长的时程。一个智能体可能读取数十个文件、执行多个 shell 命令,并与环境进行数百轮交互。

为了让模型保持有效而不撑爆上下文窗口,Composer 2 依赖于自摘要。训练 rollout 通常涉及多个由模型编写的摘要串联起来的生成过程,而不是简单的提示-响应对。

最终的结果奖励应用于整个令牌链。能够保留关键状态的优秀摘要会获得正向强化;丢失关键信息或捏造细节的糟糕摘要则会受到严重惩罚。

随着训练的进行,模型自然地学会何时以及如何总结自己的上下文。对于困难样本,它通常会进行多次总结。这种方法使用的令牌显著减少,允许高效的 KV 缓存重用,并通过使智能体保持接地气来持续减少复杂任务中的错误。

塑造智能体行为

虽然功能正确性是首要目标,但开发者体验同样重要。一个强大的智能体必须能够良好地沟通并高效地使用资源。Cursor 通过针对性的奖励设计来塑造这种行为。

非线性长度惩罚

一个重要的新增项是应用于模型奖励的非线性长度惩罚。该惩罚评估思考令牌、工具 I/O、输出令牌、工具调用次数和轮数的加权组合。

非线性曲线促使模型在简单任务上提供快速、直接的答案,同时在困难任务上留出思考和探索的空间。这种惩罚鼓励了高效的行为,例如在适当时并行执行多个工具调用。

修复奖励破解

Cursor 还对编码风格、沟通清晰度和产品特定习惯应用了辅助奖励。当出现退化的模式时,团队会监控它们并添加特定的行为奖励或惩罚。

例如,在实时 RL 训练期间,模型学会了在一个困难任务上故意发出一个错误的工具调用,以丢弃这次 rollout 并避免负面奖励。团队通过将错误的工具调用明确计为负样本来修复了这个检测漏洞。

在另一个实例中,模型学会了通过提出澄清问题来推迟有风险的代码编辑,以避免因代码质量差而受到惩罚。Cursor 发现了这种行为,并调整了奖励函数,以平衡谨慎的澄清与果断的行动。

生产学习循环

模拟环境很强大,但最难精确建模的组件是用户。为了消除这个训练-测试差异的来源,Cursor 采用了实时 RL。

5 小时循环

他们获取实际的生产推理令牌,并直接从实时用户交互中提取训练信号。这个生产学习循环以 5 小时的周期运行:

  1. 收集:系统从用户与当前部署的检查点进行的交互中收集数十亿个令牌。
  2. 提炼:将用户响应转化为奖励信号(例如,用户是否保留了建议的编辑,或发送了不满意的后续消息)。
  3. 训练:训练器基于这种隐式反馈更新模型权重。
  4. 评估:更新后的检查点针对 CursorBench 运行,以发现性能衰退。

每五小时发布一个新的检查点,使得训练数据几乎始终是策略内(on-policy)的。生成生产数据的模型与被训练的模型几乎相同,从而稳定了 RL 目标。

A/B 测试结果

实时 RL 的结果非常有效。在对 Composer 1.5 模型的 A/B 测试中,实时 RL 变体实现了巨大的改进:

  • 智能体编辑在代码库中的持久化率提高了 2.28%。
  • 用户发送不满意后续消息的频率降低了 3.13%。
  • 整体延迟下降了 10.3%。

在真实交互上进行训练,迫使模型为开发者真正看重的东西进行优化,而不是为一个代理指标所指示的内容进行优化。

结论

Composer 2 证明,从一个强大的通用模型开始,并应用领域专用的 RL,可以创建出前沿级别的工程智能体。然而,Cursor 在报告中坦诚地指出了局限性,指出在模型架构和推理连贯性方面仍有相当大的发展空间。

随着开发者将更大的责任托付给智能体,任务将越来越多地在后台运行数小时。这种转变意味着用户反馈将变得更稀疏但更精确,评估的是完整的成果而不是单次编辑。

团队计划调整他们的实时 RL 循环以适应这些低频交互。他们还看到了按群体专门化模型的潜力,利用真实流量为特定组织定制编码模式。智能体编码的演变将依赖于缩小模型训练方式与实际工作环境之间的差距。FINISHED