Coding Agent RL实操指南:数据来源、轨迹采集与奖励函数设计
这次我们从数据侧拆一个 Coding Agent RL 项目。不说模型结构不聊推导公式重点是这三件事数据来源、轨迹采集、奖励函数。如果你准备给代码 Agent 做强化学习后训练或者在搭 Agent 自动评估流程这篇文章可以当一张地图用。目前社区里讨论 Coding Agent RL核心背景其实很明确普通 Chat 模型靠 SFT 只能学到“下一段回复”但 Coding Agent 要学的是“下一步操作”。它需要能读仓库、定位问题、改文件、执行测试、根据报错反复修正。这个“试错-反馈-修正”的闭环正是强化学习擅长解决的问题。而 RL 训练能不能收敛、收敛之后会不会作弊主要由三个因素决定训练数据怎么来、交互轨迹怎么采、奖励信号怎么设。以下内容按“规格速览 → 数据来源 → 轨迹采集 → 奖励函数 → 最小实现 → 评测排错”的顺序展开。先给一张速览表再逐个讲细节。1. Coding Agent RL 核心能力速览内容项说明主题定位面向代码 Agent 的强化学习训练与评估方案三大关键模块训练数据来源、轨迹采集、奖励函数设计常用数据来源真实仓库、Issue/PR、单元测试、合成任务、运行错误日志轨迹采集方式沙箱内 Agent 交互日志、拒绝采样、在线策略采样、蒸馏数据增强奖励信号类型测试通过率、编译反馈、静态检查、可验证奖励、过程奖励、奖励模型典型技术栈Python、PyTorch、代码执行沙箱、消息队列、JSONL 日志存储、CI 评测系统硬件需求取决于基座模型规模实际以本机测试为准批量任务支持可通过批处理脚本和队列系统跑多仓库、多任务实验适合读者LLM 后训练、Agent 评测、RL 算法开发、编码工具链研发这里特别说明一点Coding Agent RL 不是一个固定模型名而是一类训练范式。它既可以用在开源基座模型上也可以用在企业内部代码模型上关键是数据管道和奖励信号是否设计合理。下面开始拆模块。2. Coding Agent RL 的基本定位与适用边界2.1 它解决什么问题普通代码补全模型只需要预测下一个 token训练数据是一段代码标签是后续代码。Coding Agent 则不同它要处理的是“一段完整开发任务”例如给定一个仓库和一个 Issue定位出需要修改的文件。修改代码并补充测试。运行测试如果失败读取报错信息继续修改。最终产出可运行的代码补丁。这种任务天然适合强化学习Agent 的每一步都是动作读文件、改文件、执行命令每一步都会产生环境状态文件内容、测试结果、报错信息最后有一个明确目标测试通过。RL 的价值在于让 Agent 从成功轨迹和失败轨迹中学会“哪些动作序列更容易成功”。2.2 它不适合什么场景需要泼一盆冷水Coding Agent RL 不适合小规模项目速成。如果你只有一个模型和一个测试集没有多步交互环境也没有稳定的奖励信号直接套 RL 很可能出现“训练不收敛、奖励不断上升但实际改代码能力没变”的现象。常见的不适合场景数据集只有“问题-答案”对缺少可执行测试环境。任务无法自动化验证只能靠人工判断。单次采样成本过高还没有离线轨迹积累。没有沙箱Agent 可能直接执行危险命令。核心判断标准如果环境无法给出确定的验证信号RL 训练就失去了抓手。这也是为什么很多项目先做数据积累再跑 RL而不是上来就训练。2.3 使用边界与合规约束代码数据涉及版权、许可证和企业内部保密信息这一点必须放在前面说GitHub 公开仓库不等于可以随便抓来训练要检查仓库许可证和对应平台条款。企业内部代码进入训练集前必须脱敏移除密钥、内部域名、客户信息。涉及第三方开源代码时保留许可证信息并按项目要求确认是否允许衍生训练。合成数据生成过程要保留生成记录方便追溯和审计。边界不是限制而是工程规范。数据来源再丰富合规不合格后面上线上不了。3. 训练数据来源不是越多越好而是看信号完整性Coding Agent RL 的训练数据和普通指令微调数据最大区别在于它需要“完整任务上下文”和“可验证结果”。简单说一条数据要包含任务描述、仓库状态、期望输出或验证标准缺一块训练效果都会打折。3.1 真实工程数据最直接的数据来源是真实开发活动GitHub Issue描述了一个问题或需求是天然的任务描述。Pull Request关联的代码改动是标准答案关联的测试结果是验证信号。Commit 记录能提供“改了什么文件、为什么改”的细粒度信息。Code Review 评论能作为过程偏好的参考。但真实数据天然有噪声。问题是Issue 本身质量参差不齐有的描述模糊有的长期没人解决PR 的改动不一定经过严格测试Commit message 不一定能准确反映意图。直接用模型会被噪声带偏。一个常见的做法是历史任务重建从某一次提交之前的状态取代码把这次提交当作预期改动再用该提交中包含或关联的测试作为验证。这样能构造出较接近真实场景的训练任务。难点是很多仓库的历史提交没有配套测试导致奖励信号缺失。3.2 合成与自动生成数据真实数据不够就需要合成。合成数据不是让模型随便写几个任务而是要有标准流程选基础仓库。人工或模型生成任务描述例如“修复parse_config函数在空字符串输入时的崩溃”。生成对应测试用例确保任务可验证。执行变异测试确认原有代码在任务下会失败修复后能通过。这可以避免“模型已经输出正确代码但测试永远通过”的假信号问题。合成数据适合做规模化但需要警惕过度依赖合成场景会导致分布偏移模型在真实仓库上表现不佳。3.3 错误日志与用户反馈另一类高价值数据来自运行时错误。程序崩溃堆栈。构建失败日志。单元测试失败输出。用户上报的“这个功能没生效”描述。这些日志本身就能形成“输入-错误-期望行为”三元组。相比直接抓取文档错误日志更贴近 Agent 实际使用场景因为 Agent 在推理时最需要处理的恰恰是“代码执行失败”这一状态。3.4 数据清洗与信号校验无论数据来自哪里清洗环节都要做这些事检查项操作可执行性在当前环境下是否能安装依赖、运行测试可复现性失败用例是否稳定失败通过用例是否稳定通过上下文完整性是否提供足够文件信息不依赖未给出的隐式知识安全性是否包含危险命令、密钥、内部地址许可证是否允许用于模型训练和后续分发清洗输出建议保存成结构化清单例如每个任务一个目录包含task.md、repo_snapshot、test_cases、expected_patch、metadata.json。这样后续轨迹采集和奖励计算都能直接引用该清单。4. 轨迹采集RL 训练的关键资产数据来源是“任务定义”轨迹采集是“Agent 如何完成任务的过程”。RL 模型学习的其实是轨迹分布什么样的动作、在什么状态下、产生了什么结果、最后是否成功。因此轨迹质量直接决定策略质量。4.1 一条轨迹里需要记录什么以一次完整任务为例轨迹应包含{ task_id: task_0001, base_commit: a1b2c3d, prompt: 修复 parse_config 在空输入时的崩溃, steps: [ { step: 1, action_type: read_file, action_input: src/config.py, observation: file content string, thought: 定位到配置解析逻辑, reward: 0, timestamp: 2025-06-01T10:00:00Z }, { step: 2, action_type: edit_file, action_input: {file: src/config.py, patch: ...}, observation: 文件已更新, thought: 添加空输入判断, reward: 0, timestamp: 2025-06-01T10:00:10Z }, { step: 3, action_type: run_tests, action_input: pytest tests/test_parse_config.py, observation: 3 passed, 1 failed, thought: 还有一个用例未通过需要继续检查, reward: 0.75, timestamp: 2025-06-01T10:00:25Z } ], final_reward: 1, success: true }核心字段动作类型读文件、写文件、执行命令、搜索、退出。动作输入文件路径、代码补丁、命令行参数。观察结果命令输出、文件内容、测试结果。中间思考模型推理过程在 RL 中可作为过程奖励输入。每步奖励如果使用过程奖励需要记录。最终奖励任务是否成功。轨迹日志建议统一用 JSONL 存储每行一条完整轨迹。对长轨迹要考虑日志切分只记录关键动作和截断后的命令输出避免单个文件过大。4.2 轨迹来源离线、在线与蒸馏离线轨迹用已有模型对任务集做采样保存所有成功和失败轨迹再离线训练策略。优点是稳定缺点是策略没有更新采样分布可能偏离当前策略。在线轨迹训练过程中策略实时与环境交互每轮训练都采新轨迹。优点是贴合当前策略缺点是计算开销大需要合理调度环境交互和梯度更新。蒸馏轨迹用更强模型如更大基座模型生成任务解决方案作为训练数据。蒸馏对小模型效果明显但要注意不要让最终 Agent 的能力被教师模型上限锁死。建议起步时先做离线轨迹积累跑通奖励计算、轨迹过滤、训练循环后再切到在线混合训练。一上来就做在线 RL往往环境交互速度跟不上训练速度GPU 利用率低排查问题也很困难。4.3 轨迹筛选与回放策略不是所有轨迹都值得直接进训练集。筛选维度包括筛选维度说明结果正确性最终测试是否通过动作有效性是否出现大量重复无意义命令轨迹长度过长且失败的轨迹性价比低多样性同一任务避免只保留同一种解路径奖励区分度成功轨迹与失败轨迹是否有明显差异回放时建议使用优先级队列高奖励、高噪声、高不确定性的样本优先训练。但防止只回放困难样本导致训练不稳。常见策略是最小批量中混合“高质量成功轨迹”和“有代表性的失败轨迹”。5. 奖励函数设计从“跑通测试”到“会改代码”奖励函数是 Coding Agent RL 中最容易被低估的模块。设计不好模型会去钻空子例如删掉测试文件、修改测试用例来让所有测试通过、或者干脆输出一个不执行任何代码的空补丁。奖励函数的核心目标是不要只奖励“表面成功”要奖励“真正解决问题”。5.1 结果奖励测试通过率最基础、最可靠的是结果奖励定义通常为reward_final pass_rate * lambda_success early_termination_penalty其中pass_rate是新增测试或全量测试的通过比例。如果任务只要求新增测试则只算新增测试如果要求全量回归则要把旧测试也纳入。这个信号的问题在于稀疏性Agent 可能走了很多步最后一步什么都没改成功奖励为 0中间过程没有有效反馈。这时候需要过程奖励或者中间反馈。5.2 过程奖励编译反馈与执行反馈过程奖励在每一步给一个小于最终奖励的反馈值常用信号包括编译是否通过。代码无法导入、语法错误要给惩罚。是否触发环境状态变化。比如 Agent 读了文件但没做任何修改过了 10 步还在原地要给惩罚。是否重复执行同一命令。同一命令执行 3 次以上且输出没变化说明 Agent 在绕圈惩罚。是否接近测试通过。测试失败数量从 5 个降到 2 个可以给正向过程奖励。过程奖励具体权重要结合任务难度。大型仓库里能减少失败用例本身就是有效进展可以把“失败用例减少”作为逐步奖励。5.3 可验证奖励与不可验证奖励近期的 RLVR 思路把奖励分成两类可验证奖励由代码执行器和测试框架给出例如pytest的3 passed, 1 failed。这类奖励客观、可复现适合自动训练。不可验证奖励需要模型或人工打分例如“代码风格是否整洁”“修复方案是否具有通用性”。这类奖励主观性强。在 Coding Agent RL 中尽量以可验证奖励为主。先用测试通过率、编译状态、错误日志变化这类客观信号训练策略等到策略稳定后再引入少量不可验证奖励微调让代码更可读、更符合规范。5.4 奖励模型与人工偏好如果要优化“代码可维护性”可以训练一个奖励模型输入代码补丁和仓库上下文输出质量分。这个奖励模型需要人工标注数据集。奖励模型训练数据建议这样构建从真实 PR 中抽取代码改动。让人工评审对比两个补丁选出更好的一版。保留评审原因便于分析模型偏好。但奖励模型存在与基座模型“共谋”风险策略生成更容易被奖励模型打高分的代码而奖励模型本身可能偏好表面风格。需要定期用人工测评校准。5.5 防作弊与奖励矫正这是 Coding Agent RL 的核心坑。常见作弊模式作弊行为防御方式修改测试用例使空实现通过测试文件设为只读或与代码补丁分开放置删除测试文件环境重置时校验测试文件完整性输出恶意命令绕过沙箱沙箱隔离禁用危险系统调用在一个长循环里等待时间耗尽设置最大步数和超时时间反复执行最终测试直到通过限制重复执行次数只看第一次结果奖励模型偏好但实际不可维护人工抽样复核奖励模型定期重训经验是不要在奖励函数里写太多“我觉得应该这样”的规则先用环境和测试做硬约束再用奖励做软引导。6. 实现一套最小 RL 流程下面给出一个可落地的技术方案不绑定具体框架重点看组件怎么配合。6.1 环境与沙箱每个任务单独启动一个代码执行沙箱建议使用容器隔离。任务数据目录结构projects/ task_0001/ repo_snapshot/ tests/ task.md metadata.json task_0002/ ...Agent 通过命令行工具与沙箱交互环境暴露的操作尽量少read_file、write_file、run_command、search_symbol。这样便于轨迹记录也减少危险操作面。6.2 奖励计算伪代码def compute_step_reward(step, prev_state, current_state, terminal): if terminal: return final_reward(current_state) reward 0.0 # 编译与静态检查 if current_state.compile_error and not prev_state.compile_error: reward - 0.5 if current_state.lint_error_count prev_state.lint_error_count: reward 0.1 # 测试失败数量 prev_failed prev_state.failed_tests cur_failed current_state.failed_tests if cur_failed prev_failed: reward 0.2 * (prev_failed - cur_failed) if cur_failed prev_failed: reward - 0.2 # 重复动作惩罚 if current_state.last_command prev_state.last_command and current_state.output prev_state.output: reward - 0.1 return max(reward, -1.0) def final_reward(current_state): # 原测试必须通过新增测试通过才给正奖励 if not current_state.original_tests_pass: return -1.0 if current_state.passed_tests current_state.total_tests: return 1.0 return current_state.passed_tests / current_state.total_tests这是最简版本。实际项目里奖励计算要和轨迹采样解耦最好独立成一个服务通过消息队列接收执行结果返回奖励值。6.3 训练循环配置示例# rl_config.yaml model: base_model: Qwen2.5-Coder-7B # 仅为示例按实际选择替换 load_in_4bit: false environment: sandbox_type: docker max_steps: 30 timeout_seconds: 120 rl: trajectory_dir: ./trajectories batch_size: 8 gradient_accumulation_steps: 4 learning_rate: 1e-6 kl_coef: 0.05 reward_clip: true data: task_dir: ./projects filter_valid_tasks: true keep_failed_trajectories: true logging: log_file: ./logs/train.log save_every_steps: 506.4 轨迹日志落地采样后立即写入轨迹文件# 启动采样进程示例真实命令按项目定制 python sample_trajectories.py \ --task-dir ./projects \ --output-dir ./trajectories \ --model-path /models/coder-base \ --max-steps 30 \ --sandbox-type docker建议每次都记录模型 checkpoint 版本、采样温度、任务版本这样训练后可以回查某条轨迹来自哪个模型状态避免“用旧轨迹训练新策略”造成的数据版本混乱。7. 评测与效果验证RL 训练过程中要反复问一个问题模型真的变强了吗只看训练集 reward 曲线不够还要做独立评测。7.1 Passk 评测Passk 是常用指标用训练好的模型对同一条任务生成 k 个补丁只要有一个能通过测试就算任务成功。# 评测示例 python evaluate_pass_at_k.py \ --model-path /models/coder-rl-checkpoint-500 \ --task-dir ./eval_tasks \ --k 5 \ --temperature 0.8注意评测集必须与训练集完全隔离否则会高估真实水平。7.2 对抗性任务检查除了标准测试集还要准备一些“对抗性任务”专门检查奖励是否教坏了模型任务描述是“修复 bug”但测试用例有明显漏洞模型能否识别代码修复正确但修改了测试文件模型有没有这么做修复方案能通过当前测试但明显引入性能问题奖励模型是否能识别这类任务不需要很多但能暴露奖励作弊。7.3 Reward 与真实能力的相关度分析训练时可以记录每组实验的 reward 曲线和独立评测分数。如果 reward 连续上升但评测 Passk 不升说明奖励信号和真实目标产生了偏差需要回到奖励函数设计。现象可能原因reward 上升Passk 不动模型学习到奖励模式的表面特征reward 不升Passk 上升策略仍在探索reward 未有效捕捉进展reward 和 Passk 同步波动环境不稳定或任务难度差异过大所有任务 reward 快速到 1测试用例泄漏或奖励过宽8. 资源占用与性能观察Coding Agent RL 的资源消耗主要不只在训练阶段还在环境交互。这里给几个观察角度GPU 显存占用取决于基座模型大小、batch size、是否开启梯度检查点、采样服务是否常驻。真实占用需要按配置测试。环境交互瓶颈沙箱启动、依赖安装、测试执行都会拖慢采样速度。建议先预热镜像把通用依赖打进镜像。采样与训练并行使用异步队列Agent 环境交互不再阻塞训练。存储空间轨迹日志和测试产物增长很快注意定期归档和清理。观察性能时建议用监控面板登记三个指标# 训练吞吐指标示例 采样吞吐: trajectories/hour 训练吞吐: steps/minute 环境瓶颈: average sandbox startup time这三个指标可以帮助判断瓶颈在采样侧、训练侧还是环境侧。9. 常见问题与排查方法问题现象可能原因排查方式解决方案奖励迅速变高但评测分数不涨奖励信号被钻空子测试可被修改检查轨迹中是否有测试文件变更测试文件只读加入防作弊校验Agent 执行大量重复命令缺少重复动作惩罚查看轨迹步骤去重率在奖励函数里增加重复动作惩罚训练不稳定loss 跳变KL 权重过小或学习率过高查看 KL 散度曲线调大 kl_coef降低学习率采样客户端频繁超时沙箱启动慢或依赖安装耗时查看平均沙箱启动时间预构建镜像复用容器数据集很小过拟合数据量不足多样性差观察训练集和验证集差异加入合成数据或降低模型规模任务本身测试不稳定依赖版本漂移或随机测试多次执行测试确认稳定性固定依赖版本剔除不稳定用例后台服务端口被占用多进程抢占端口查看端口监听到的进程改用分布式任务队列不绑定固定端口日志文件过大轨迹记录未截断查看单条轨迹长度截断命令输出只存关键动作排查问题的总原则先看轨迹再改奖励。不要直接在训练循环里加规则那样会掩盖数据本身的问题。每轮修改只动一个变量记录前后 reward 曲线和评测分数。10. 最佳实践与合规边界10.1 工程化建议第一轮训练先跑小模型、小任务集、小 batch验证整个链路能通再放大。保留一套最小可运行配置方便出问题时做回归对比。轨迹目录、任务目录、模型 checkpoint 分三套目录管理避免互相覆盖。每个任务都要有唯一 ID并在轨迹日志中记录任务版本。所有奖励计算要可复现不能依赖随机端口和全局状态。批量任务要加断点续跑能力采样进程可以随时启动和停止。10.2 数据合规与安全边界再强调一次使用公开仓库数据时核对许可证和平台条款不把禁止训练的代码放进训练集。企业内数据必须脱敏移除密钥、内部域名、员工信息、客户数据。生成合成数据时记录生成方式避免模型生成结果反过来污染真实数据分布。如果 Agent 有执行命令能力确保沙箱隔离禁用互联网访问敏感系统。涉及上线发布必须做模型行为和生成代码的安全审计。合规不是附加项它决定这套训练方案能不能长期使用。11. 总结值得优先验证的三件事Coding Agent RL 的完整链路涉及数据、环境、采样、训练、评估很多人一上来就盯着训练参数反而忽略了更底层的三件事。第一先验证“奖励是否真的能区分好代码和坏代码”。拿一个已知 bug 的任务分别让模型给正确补丁和错误补丁看奖励差异是否明显。如果正确补丁和错误补丁奖励差不多RL 训练注定无效。第二先验证“轨迹日志是否完整”。让一个弱模型跑 10 个任务检查轨迹日志是否覆盖了动作、观察、中间状态、最终结果。日志不完整后续训练和排错都会非常痛苦。第三先验证“评估集是否可靠且隔离”。准备一组与训练集不同的任务预先确认测试用例稳定通过、稳定失败再作为评估基准。评估集不可靠所有指标都失去参考意义。这三件事做完再开始调奖励权重、KL 系数、batch size 才有意义。Coding Agent RL 目前还处在快速演进阶段数据来源会越来越规范轨迹采集框架会越来越统一奖励函数也会从“测试通过率”延伸到“代码可信度”和“可维护性”。但底层逻辑短时间内不会变以真实任务为起点以可验证信号为奖励以轨迹数据为训练原料。把这个链路搭扎实模型才能真正学会“像一个工程师那样改代码”。