一个 LLM 同时扮演程序员和测试员,不如两个分开
问题:一个 LLM 同时做太多事
让 LLM 生成代码时,通常会在同一个 prompt 里要求它:理解问题、考虑边界情况、写出正确代码、还要自己验证。这几件事的认知要求不同,放在一起往往互相干扰。
AgentCoder(Huang et al., 2023)的出发点是:把这些任务拆给不同的角色,每个角色专注一件事。
三个角色
程序员(Programmer Agent)
只负责写代码。给它问题描述,它输出实现:
# Programmer Agent 的输出
def find_missing_number(nums: list[int]) -> int:
n = len(nums)
expected_sum = n * (n + 1) // 2
return expected_sum - sum(nums)
程序员 Agent 的 prompt 里没有测试生成的指令,也没有执行结果的处理逻辑,只做一件事。
测试设计师(Test Designer Agent)
只负责生成测试用例。它看的是问题描述,而不是程序员写的代码——这是一个关键设计决策:如果测试设计师看到了代码,它生成的测试往往会迁就代码的实现,而不是真正检验问题的要求。
# Test Designer Agent 的输出
test_cases = [
([3, 0, 1], 2), # 基本情况
([0, 1], 2), # 短数组
([9, 6, 4, 2, 3, 5, 7, 0, 1], 8), # 长数组
([0], 1), # 单元素
]
测试执行器(Test Executor)
不是 LLM,是实际的代码执行环境。它运行程序员写的代码,用测试设计师给出的测试用例验证,把结果(通过/失败/报错信息)返回给程序员 Agent。
工作流程
问题描述
│
├──→ 程序员 Agent → 生成代码 ──────────────────┐
│ │
└──→ 测试设计师 Agent → 生成测试用例 │
│ │
↓ ↓
测试执行器(运行代码 + 测试)
│
┌───────────┴───────────┐
通过 失败
│ │
返回代码 报错信息 → 程序员 Agent 修正
→ 循环
循环在代码通过所有测试时终止,或者达到最大迭代次数时停止。
测试设计师不看代码的原因
这个设计细节值得多说一点。
如果测试设计师能看到程序员写的代码,它会自然地顺着代码的逻辑来生成测试——比如看到代码处理了 nums = [] 的情况,就给 [] 写个测试,看到没处理 None,就不写 None 的测试。这样生成的测试是对代码的描述,而不是对问题要求的独立验证。
独立性才是测试的价值所在。测试设计师只看问题描述,生成的测试才真正反映了"这个问题应该满足什么条件",而不是"这个代码实际上做了什么"。
实验结果
论文在 HumanEval、MBPP 和 CodeContests 上进行了对比:
| 方法 | HumanEval | MBPP |
|---|---|---|
| GPT-3.5 直接生成 | 72.6% | 65.9% |
| Self-Debugging | 76.8% | 69.4% |
| AgentCoder(GPT-3.5) | 79.9% | 73.9% |
| GPT-4 直接生成 | 82.0% | 75.1% |
| AgentCoder(GPT-4) | 91.5% | 83.2% |
用 GPT-3.5 的 AgentCoder 在 HumanEval 上接近了 GPT-4 直接生成的水平,说明多角色分工可以在一定程度上用结构设计弥补模型能力的差距。
和单 Agent 方法的比较
| 维度 | 单 Agent(Self-Debugging) | AgentCoder |
|---|---|---|
| 角色 | 一个 LLM 做所有事 | 三个角色分工 |
| 测试来源 | 执行报错 | 独立 Agent 生成 |
| 测试质量 | 依赖代码质量 | 独立于代码 |
| LLM 调用次数 | 较少 | 较多 |
| 可解释性 | 一般 | 较好(每步职责清晰) |
角色分离的适用范围
AgentCoder 的角色分离在有明确输入输出规范的任务上效果好。对于需求本身就模糊的任务,测试设计师也无法生成有效的测试,这个架构的优势就消失了。
实际应用中,测试设计师生成的测试也可能有错(预期输出不对),这和 AlphaCodium 面临的问题一样。AgentCoder 没有专门的机制来验证测试本身的正确性,这是这个方案的局限之一。
对多 Agent 架构的参考价值
AgentCoder 是较早系统性研究"角色分离对代码生成的影响"的工作之一。它的核心发现——独立的测试生成比让同一个 LLM 又写代码又想测试效果更好——对更广泛的多 Agent 系统设计有参考意义:
当一个任务包含几个认知上不同的子任务时,拆分给不同的 Agent 分别处理,通常比让一个 Agent 全部承担更稳定。这不是因为多个 LLM 加在一起更聪明,而是因为每个调用更专注,减少了任务之间的干扰。
版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。
(采用 CC BY-NC-SA 4.0 许可协议进行授权)
本文标题:11. AgentCoder:拆分角色,让代码生成和测试设计分开
本文链接:https://www.sshipanoo.com/blog/ai/code-agent-harness/11-AgentCoder/
本文最后一次更新为 天前,文章中的某些内容可能已过时!