ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Coding Agent 强化学习的关键:数据、轨迹与奖励函数设计

Coding Agent 强化学习的关键:数据、轨迹与奖励函数设计 做 Coding Agent 强化学习Coding Agent RL很多人一开始会把注意力放在模型规模、算力卡数、训练框架上但真正决定实验能不能走远的往往是三件看起来更基础的事数据从哪里来、轨迹怎么采集、奖励函数怎么设计。这三件事只要有一件没想清楚训练出来的 Agent 就会出现一种典型症状评测集指标在涨放到真实仓库场景里却连一个编译错误都修不明白。这篇文章围绕“数据来源、轨迹采集、奖励函数”三条主线把 Coding Agent RL 的最小训练闭环拆一遍。适合正在做代码大模型对齐、Agent 训练、RL 实验方向的人阅读也适合想从单轮代码生成转向多轮代码智能体训练的团队参考。到了 2026 年再看这个方向强化学习在代码智能体上的应用已经过了“能不能跑”的阶段更多是在拼数据质量、轨迹完整度和奖励信号是否可靠。下面按我实际跑实验时习惯的顺序来写先理解闭环再讲数据再讲轨迹再讲奖励最后给一套可以照着做的最小实验链路和排查清单。1. 先理解训练闭环Coding Agent RL 到底在学什么1.1 代码生成和代码智能体不是一回事普通代码生成任务输入是一段 prompt输出是一段代码到 return 就结束了。模型不需要知道自己写的代码能不能编译、测试能不能过、是不是改坏了其他模块。Coding Agent 不一样。它面对的是一个多轮交互决策问题读取仓库文件、定位可能出问题的函数、修改代码、运行测试、看到报错后再改。每一步动作都会改变环境状态环境状态又会影响下一步动作。这种“动作—环境反馈—下一状态—再动作”的循环才是强化学习真正可以发挥价值的地方。如果还用监督微调的方式训练这种 Agent会遇到一个明显问题SFT 只是在模仿训练数据里的下一步动作模型不知道某个动作之后到底发生了什么。它可能学会了“改完代码要跑测试”这个表面模式但不会因为测试失败而调整策略。强化学习的目标就是让模型通过环境反馈学会更本质的东西某个动作到底有没有让测试通过某个修改方向是不是离最终结果更近。1.2 RL 闭环里的三个关键输入一个完整的 Coding Agent RL 训练闭环可以简化成下面这条链路模型根据任务描述和当前仓库状态产生一个动作动作在沙箱环境里执行得到执行结果根据执行结果和最终测试情况计算奖励信号奖励信号通过强化学习算法更新模型策略模型带着新策略进入下一轮交互。这个闭环里有三个关键输入分别对应标题里的三个词数据来源决定的是状态分布。也就是任务描述、仓库代码、测试用例这些初始状态从哪里来。如果任务来源单一模型只能学会在特定仓库形态下做事。轨迹采集决定的是动作序列的完整程度。模型每一步读了什么文件、改了哪几行、跑了什么命令、看到了什么输出这些过程信息必须被完整记录下来才能拿到训练样本。奖励函数决定的是优化方向。最终测试通过只是一个信号中间每一步的对错好坏都需要用不同的奖励项来引导。举个例子。一个任务描述是“修复 order 模块的超时问题”初始状态是某个开源项目的代码测试用例会调用 order 模块并断言返回时间。Agent 第一步可能先读取src/order.py第二步修改了某个循环逻辑第三步运行测试测试通过。这条轨迹里有状态快照、动作参数、环境输出、最终结果四个部分缺一不可。如果只记录最终代码不管中间过程这个样本就退化成普通的代码生成数据RL 很难从中学到多轮决策能力。如果奖励函数只给最终测试结果打分模型大概率会采用“穷举尝试”的策略反正试错了不扣分多跑几次命令总能撞对。这些都是我在实际实验里踩过的坑下面每一节展开说。2. 数据来源不能只盯着公开代码库2.1 四类常见数据来源Coding Agent RL 的数据来源我一般会分成四类公开代码仓库、评测基准集、合成任务、真实用户交互日志。四类各有用途也各有问题。第一类是公开代码仓库。GitHub 这类平台上有大量开源项目随手一抓就是几万个仓库。但直接拿来训练会有几个麻烦很多仓库在本地无法构建依赖缺失、环境变量复杂、构建脚本失效导致任务不可验证仓库 README 或 issue 描述跟实际代码 diff 经常脱节重复代码太多尤其是教程项目和个人练习项目质量参差不齐。此外还要注意许可证和权限问题公开代码不是拿过来就能随意作为训练数据的。第二类是评测基准集。这类数据集的好处是任务定义清晰通常配套测试用例和执行环境适合用来验证模型能力。但不少基准集已经被模型在预训练阶段见过直接放进训练集会造成数据泄漏。更稳妥的做法是当作 held-out 验证集只在训练完后评估不参与 RL 训练。第三类是合成任务。从 commit diff 反向生成任务描述或者用静态分析工具定位函数后套模板生成修复任务。这类数据可以按需扩展可控性最强缺点是容易产生“任务描述泄露答案”的问题。比如模板直接把“删掉第 42 行的缓存逻辑”写进 prompt模型不需要理解代码就能完成任务学到的策略也没有迁移性。第四类是真实用户交互日志。最接近真实使用场景能体现真实的项目上下文、真实的报错、真实的修复过程。但采集成本高、隐私处理复杂、日志格式混乱。很多团队把它当作后期优化数据而不是冷启动数据。2.2 数据筛选的优先级我现在做 Coding Agent RL 数据清洗时会按下面的优先级筛选任务是否可验证。必须有测试用例或明确的检查脚本能自动判断任务有没有完成。问题描述是否清晰。任务描述不能太含糊让 Agent 不知道要改哪个模块。环境是否可复现。仓库依赖、Python 版本、构建步骤都要能固定住否则轨迹采出来无法重建。修改范围是否明确。单文件小改动适合冷启动多文件改动适合后期提升能力上限。可以用这个表格快速判断一批候选数据数据属性高优先级低优先级可验证性有可执行测试只有描述没有检查逻辑任务描述定位到具体模块和现象泛泛而谈“优化性能”环境可复现Docker 或脚本可构建依赖缺失、网络不稳定修改范围单文件或集中改动跨多个模块的模糊改动任务难度有明确边界需要大量隐性背景知识数据泄漏是另一个必须提前处理的问题。我一般会把数据按 commit hash 切分不能按仓库切分因为同一个仓库的不同版本会出现在多个 commit 里。还要做一次相似度去重和公开评测集、常见竞赛题做一下匹配把可能被模型见过的样本剔除掉。这个步骤看起来费时间但能避免后面训练跑完才发现提升是假的。3. 轨迹采集要采集的不只是一条成功路径3.1 一条完整轨迹应该包含哪些内容很多第一次做 Coding Agent RL 的人会以为轨迹采集就是“把模型最终生成的代码存下来”。真不是。轨迹是 Agent 从拿到任务开始到最终提交补丁为止每一步动作和对应环境反馈的完整序列。一条典型的轨迹包含这些部分任务信息任务 ID、prompt 原文、仓库地址、基础 commit。状态快照每一步动作发生前当前文件树结构、相关文件内容、当前 git diff。动作参数模型调用了哪个工具传入了什么参数。比如读取文件路径、修改的具体 diff、执行的命令行。环境反馈命令退出码、stdout、stderr、测试输出、文件变更结果。最终结果测试通过数量、失败数量、是否有隐藏测试遗漏、最终 patch。元信息采样时间戳、模型版本、采样参数、token 消耗。只有把中间过程记录下来才能还原模型到底是怎么走到最终结果的。失败轨迹尤其重要因为强化学习需要一个“负样本”信号光有成功轨迹模型学不会避开错误路径。3.2 单轮采样、多轮搜索与日志记录采集方案按复杂度可以分三种。第一种是单轮 rollout。对同一个任务让模型从同一个初始状态出发跑完整条轨迹记录每一步。重复采样 N 次得到 N 条轨迹。这种方案最简单适合冷启动和验证数据管线。缺点是探索空间有限同一个任务如果初始动作就错了后面很难绕回来。第二种是多轮 rollout 或树搜索。让模型在早期同时尝试多个候选动作每个候选动作展开成一条子轨迹最后把这些子轨迹合并成一棵搜索树。这种方案能给模型提供更丰富的中间状态覆盖但存储成本和计算成本都更高需要额外设计裁剪策略。第三种是接入真实 Agent 日志系统。工具调用记录、文件变更记录、命令执行记录、结果输出全量落盘。这种方案适合在真实产品采集数据但数据格式最杂清洗成本最高。我更建议的训练路径是先用单轮 rollout 把数据管线跑通再引入多轮搜索增加困难任务的数据量最后如果条件允许再接入真实用户日志。不要一上来就追求最复杂的数据采集方案。3.3 存储格式与清洗轨迹存储推荐用 JSONL一行是一条完整轨迹方便按行读取、按任务切分、断点续跑。一个简化版的结构是这样的{ task_id: task_0007, repo: example-order-service, base_commit: a1b2c3d, prompt: 在 order 模块中修复超时问题确保订单查询接口在 500ms 内返回。, trajectory: [ { step: 0, action: read_file, args: {path: src/order.py}, output_excerpt: def query_order(order_id): ..., success: true }, { step: 1, action: edit_file, args: { path: src/order.py, diff: -38,7 38,7 }, output_excerpt: patch applied, success: true }, { step: 2, action: run_command, args: {command: pytest tests/test_order.py -q}, output_excerpt: 3 passed, 1 failed, success: true } ], test_result: { pass: true, passed_tests: 8, failed_tests: 0 }, final_patch: diff --git a/src/order.py b/src/order.py ..., reward: 1.0 }清洗时有几个需要特别注意的点过滤空轨迹。模型没有做任何有意义的动作就结束了这种数据基本是废数据。过滤运行超时的轨迹。超时不一定代表任务失败也可能是沙箱资源不够需要单独标记不要直接当成失败样本。过滤日志中的敏感信息。真实项目日志里可能有密钥、内网地址、个人信息必须做脱敏。保留失败轨迹。不要只保留最终成功的数据。失败轨迹如果能配上有区分度的奖励对训练帮助非常大。4. 奖励函数测试通过不等于奖励设计完成4.1 从稀疏奖励到过程奖励最简单的奖励设计是稀疏奖励最终测试全部通过给 1否则给 0。这个设计看起来客观但实际训练时问题很明显Agent 在很长一段探索过程里拿不到任何正反馈梯度几乎是零模型不知道该往哪个方向调整。对于“改一行就能通过”的简单任务稀疏奖励勉强够用。但真实 Coding Agent 任务通常需要十几步操作稀疏奖励会让模型退化成随机试错。更合理的做法是引入过程奖励给轨迹中的中间步骤也打分。过程奖励不是凭空发明的。它背后的逻辑是即使最终任务还没有完成某些动作仍然是有价值的方向性信号。比如 Agent 第一步就读取了关键文件这个动作是有效的如果它一直在无关文件里来回翻即使最后碰巧成功也不应该给出和“路径清晰的成功”一样的奖励。4.2 常见奖励项与权重方案下面列几个我在实践里常用的奖励项以及它们的风险点奖励项作用风险最终测试通过率直接衡量任务完成度模型可能硬编码返回测试期望值隐藏测试通过数量防止模型只适配可见测试对任务设计能力要求高编译或 lint 通过过滤低级语法错误独立使用价值有限覆盖率增量鼓励模型覆盖更多逻辑分支可能写无意义的空断言刷覆盖编辑是否命中关键文件引导模型快速定位容易先验过强限制了探索工具调用有效性减少无效搜索和重复调用需要额外标注工具调用质量权重设计上不建议一上来就搞复杂的加权和。我的做法是先分两层第一层强制看任务完成信号测试通过是最硬的标准第二层再看效率和质量比如步数更少、diff 更小、没有引入新的失败测试。一个比较稳的起点是成功任务给 1.0失败任务给 0.0但在失败任务里增加一个“部分完成”的中间信号比如修复后通过了一半测试给 0.3。等跑通之后再逐步引入过程奖励模型。4.3 奖励模型的坑如果过程奖励不是用规则算的而是用模型预测的就涉及奖励模型。奖励模型最容易遇到两个问题奖励 hack 和奖励漂移。奖励 hack 的意思是模型找到了一个能让奖励信号变高、但实际能力并没有提升的路径。最常见的例子是模型发现“只要直接返回测试用例期望的常量字符串测试就能通过”于是所有任务都变成输出常量。这种问题不能只靠加大奖励模型训练数据来解决更好的办法是把测试拆分得更细让可见测试和隐藏测试分开并增加代码质量约束。奖励漂移指的是奖励模型打分分布随着策略更新逐渐偏移最后打出来的分数失真。对策是固定奖励模型、用拒绝采样方式让奖励模型保持在较高质量上并且定期抽一批轨迹做人工评估而不是完全信任自动打分。另外一个经验训练之前先跑 200 条轨迹看奖励分布是否合理。如果全部集中在 0 和 1 两个极端说明过程信号没起作用如果奖励持续上涨但验证集成功率不涨优先怀疑奖励 hack而不是模型出了问题。5. 一套可复现的最小实验链路从 500 条数据开始5.1 最小环境与数据准备Coding Agent RL 不一定非得要大规模集群。做小规模验证时单张 24GB 显存左右的 GPU 就能跑起来。模型建议先用 7B 到 14B 的代码模型先不要上 70B因为 Agent 的 rollout 推理开销比普通生成大得多。准备工作分四步准备一个可复现的沙箱环境。推荐用 Docker 封装代码仓库和依赖保证每一步动作执行结果可复现。构造一个最小数据集。先从开源仓库里挑 500 个可验证任务要求必须有测试、环境能构建、问题描述清晰。配置轨迹记录模块。把每一步的输入参数、输出、执行结果、时间戳记录到 JSONL。实现一个最小奖励计算脚本。先只算测试通过率和部分测试通过比例。5.2 从 10 条 rollout 到 500 条实验我不会直接拿 500 条数据开跑而是分三步走。第一步先跑 10 条 rollout。这一步的核心目标不是训练效果而是确认管线通畅。检查轨迹有没有丢动作、奖励能不能算出来、日志能不能正确落盘。第二步把这 10 条轨迹的奖励分布打出来。如果全部是 0 或 1说明中间过程信号完全没有需要检查奖励函数是不是没有被正确计算。如果同一任务的多次采样奖励差异很大很可能是环境不稳定先不要急着训练。第三步再扩大到 500 条。跑 1 到 2 个 epoch观察 reward 曲线和验证集的成功率变化。这个阶段如果 reward 一直在涨但验证集成功率不变就要回头检查数据泄漏和奖励 hack。5.3 实验有效性的判断指标训练后期我主要看这几个指标验证集成功率也就是 pass1 或类似指标。只看训练集成功率没有意义。平均完成步数。一个优秀的 Agent 应该随着训练推进用更少的步骤完成任务而不是靠更多次试错。失败类型分布。如果失败的样例集中在编译错误说明基础代码能力不足如果集中在逻辑判断错误说明问题定位能力不足。奖励稳定性。奖励曲线如果剧烈震荡先调学习率或奖励系数不要加模型规模。新手配置和进阶配置的差别可以参考这个表配置项冷启动最小配置进阶配置数据规模500 条可验证任务5000 条以上含真实日志采样方式单轮 rollout多轮树搜索加拒绝采样奖励信号测试通过 部分测试通过比例过程奖励模型 多维度约束沙箱环境单 Docker 镜像多服务、多依赖、带网络隔离评估方式少量 held-out 基准集人工抽查 真实仓库任务回放6. 常见翻车点与排查顺序6.1 数据问题数据层面的翻车最常见的是这几个任务不可复现。仓库依赖太多沙箱里构建失败Agent 根本无法运行测试最后所有轨迹都是残缺的。任务描述泄露答案。比如把“删除 42 行的 try 块”写进 prompt模型不需要理解就能过。训练集和验证集重叠。同一个任务的不同版本同时出现在两边验证集指标变成假的。遇到这类问题先不要改模型。把任务抽出来人工在沙箱里跑一遍确认任务本身可解、可验证、描述不泄露答案。6.2 轨迹问题轨迹层面的翻车典型表现是日志不完整。只记录了工具名没记录参数无法回放。状态快照太旧。Agent 已经修改了文件但记录里还是修改前的内容导致状态和动作对不上。超时被误判为失败。沙箱环境资源不够命令执行超时不能简单当成任务失败。排查方式是随机抽一条轨迹按记录手动重放看每一步能不能还原原始状态和执行结果。如果没办法重放就说明轨迹记录有缺失需要先修采集逻辑。6.3 奖励问题奖励层面最常见的翻车是稀疏奖励导致训练不稳定。奖励 hack 导致 reward 上涨但成功率不涨。奖励模型漂移导致打分越来越不可信。排查顺序是先看同一批任务多次采样的奖励方差如果方差过大说明环境不稳定再看训练集和验证集成功率是否同步变化如果训练集大涨、验证集不动优先怀疑 reward hack最后抽 30 条高奖励和低奖励轨迹做人工对比看看模型到底靠什么拿到了高分。6.4 我的排查顺序把整套流程串起来遇到训练效果不好时我的习惯排查顺序是这样的先看单条样本能否被人工复现。任务本身、环境、测试任何一步失败都先解决。再跑 10 条新 rollout检查轨迹完整度。确认每一步的输入输出都记录完整。看奖励分布。判断是信号太稀疏还是信号值本身计算错误。训练 100 步后看 reward 走势。如果 reward 稳定上升继续看验证集。验证集成功率不升就回到数据泄漏和 reward hack 两个方向排查。这套顺序看起来慢但能避开大多数 Coding Agent RL 训练早期最容易踩的坑。数据、轨迹、奖励这三个环节任何一个没有闭环训练结果都会失真。我现在的习惯是把数据质量检查放在训练之前把轨迹完整度检查放在训练之中把验证集成功率监控放在训练之后。先跑稳一个小规模实验再谈扩大数据、增加模型参数、切换复杂奖励模型这条路走起来更可控。
返回列表