☰
公开测试通过,代码 Agent 就正确了吗?用 Python 拆解执行反馈闭环
2026/10/16 6:41:24 网站建设 项目流程

写一个“生成代码 → 运行测试 → 失败后重试”的循环不难,难的是不把三个判断混在一起:还能否继续修复、当前响应拿多少奖励、最终结果如何给前面的尝试分配信用。

我最近在维护 TensorDrill 的 AI 编程练习时,把 RLEF 的执行反馈部分拆成了几个小函数。这里不调用模型、不训练 PPO,先用可运行的 Python 例子理解边界。

1. 先区分反馈和最终评测

公开测试给代码 Agent 提供可观察的反馈,帮助它修改代码。它们通过了,不意味着所有输入都处理正确。

下面的最小反例只说明测试覆盖不足,不代表任何实际基准:

defwrong_square(x):returnxassertall(wrong_square(x)==x*xforxin[0,1])assertwrong_square(-2)!=(-2)*(-2)

因此,“修复结束”和“正确性确认”应该是不同状态。RLEF 的迭代流程在公开测试通过或达到轮数预算后停止,再评估最后候选。

可以先把控制器约定为:继续尝试返回retry,进入最终评测返回private_eval。这两个字符串和下面的历史校验是本文的教学接口,并不是论文代码 API。

defepisode_action(public_passes,max_turns):iflen(public_passes)>max_turnsorany(public_passes[:-1]):raiseValueError("attempt after termination")iflen(public_passes)==max_turnsor(public_passesandpublic_passes[-1]):return"private_eval"return"retry"assertepisode_action([],3)=="retry"assertepisode_action([False],3)=="retry"assertepisode_action([False,True],3)=="private_eval"assertepisode_action([False,False],2)=="private_eval"try:episode_action([True,False],3)exceptValueError:passelse:raiseAssertionError("成功终止后不应继续修复")

预算耗尽和公开通过都进入评测,但两个情况都没有在这里返回“最终正确”。这能避免把停止条件误用为正确性标签。

2. 奖励先确定分支,再处理参考策略项

这几个分支容易写错:

当前情况基础奖励
终止,所有评测测试通过+1
终止,仍有评测测试失败−1
非终止,无效代码−0.2
非终止,有效代码0

终止分支优先。最终失败且代码无效,不应机械叠加成 −1.2。

参考策略项还带来一个独立的细节:本文按 RLEF 的响应概率约定使用 token 对数概率的平均,而不是总和。固定的参考模型也不等于 PPO 随迭代变化的旧策略。

importmathdefturn_reward(valid,terminal,all_pass,policy_logps,ref_logps,beta):base=(1.0ifall_passelse-1.0)ifterminalelse(0.0ifvalidelse-0.2)mean_log_ratio=math.fsum(p-rforp,rinzip(policy_logps,ref_logps))/len(policy_logps)returnbase-beta*mean_log_ratioassertturn_reward(False,True,False,[-1],[-1],0)==-1assertturn_reward(False,False,False,[-1],[-1],0)==-.2assertturn_reward(True,False,False,[-1,-3],[-2,-4],.5)==-.5assertturn_reward(True,False,False,[-4],[-2],.5)==1

约定输入为等长非空、有限的自然对数概率列表;all_pass仅对合法终止响应可能为 True。函数接收评测结论,不执行待测代码。

最后一个结果不是 bug:单个采样响应的对数概率比可以为负。不要把它当成已经对整个分布求和、必然非负的精确 KL 散度,再擅自截断成零。

3. 成功发生在最后,前面的尝试也需要信用分配

如果三个响应的修正奖励为[-0.2, -0.1, 1.0],只拿每一步即时奖励当作优势,会遗漏后续结果。

在这里采用无折扣的剩余奖励和,再减去该响应生成前的价值基线:

defturn_advantages(rewards,values):output=[0.0]*len(rewards)remaining=0.0fortinrange(len(rewards)-1,-1,-1):remaining+=rewards[t]output[t]=remaining-values[t]returnoutput actual=turn_advantages([-.2,-.1,1.0],[0.0,0.0,0.0])assertlen(actual)==3assertall(abs(a-b)<1e-12fora,binzip(actual,[.7,.9,1.0]))assertturn_advantages([1,2],[10,20])==[-7,-18]assertturn_advantages([],[])==[]

第二个断言刻意使用不同基线,防止把下一轮价值减到当前轮上。负优势也是合法结果,不该为了“看着像奖励”而截断。

4. 哪些东西仍然没有实现

这些函数适合检查控制逻辑和计算约定,但还缺少模型生成、代码执行隔离、反馈构建、价值模型与优化过程。它们不能据此证明复现了 RLEF 的训练效果。

论文里的公开与私有测试划分,也不能直接套到浏览器练习的判题能力上。本文对应练习的断言全部可查看,属于学习工具。

想按“修复控制 → 奖励 → 优势值”动手练习,可以使用我维护的 TensorDrill RLEF 学习单元。每题包含函数约定、浏览器测试和完整 Python 题解。

参考资料

  • RLEF 原论文 §2.1–2.2:迭代代码合成与执行反馈强化学习。本文示例、接口和断言为教学编写,不是论文代码复制。
  • 控制 RLEF 公开测试修复回合:可以参考并且练习的网站。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询