
很多团队尝试用 AI 做代码评审,第一反应是:把代码丢给大模型,让它挑毛病。
这个方式能用,但效果有限。
一个 Agent 同时扮演写代码和审代码两个角色,就像让一个人自己写完论文再自己审。它很难跳出自己的思路去发现真正的盲点。模型会倾向于认为自己写的代码是合理的,即使有隐患也会轻描淡写地放过。
多 Agent 协作的价值就在这里。
当你把"写代码"和"审代码"拆成两个独立 Agent,给它们不同的角色设定、不同的 Prompt、不同的约束,它们之间就会产生真正的张力。初级 Agent 负责实现功能,资深 Agent 负责找问题、提建议、打回重做。
AutoGen 是目前做多 Agent 协作比较成熟的框架之一。它支持 Agent 之间自动对话、轮流发言、条件终止,非常适合模拟这种"开发-评审"的协作模式。
一句话:
单 Agent 做代码评审,本质是自我审查;多 Agent 做代码评审,才是真正的对抗性检查。
单 Agent 做代码评审,通常是这样:
User: 请帮我 review 这段代码
Agent: 好的,我来看看...(输出一段评审意见)这种方式有几个根本性问题。
第一,Agent 没有"写代码"的上下文。
它只看到最终代码,不知道开发者为什么这样写、考虑了哪些方案、放弃了哪些选择。评审意见容易浮于表面,比如"建议加注释""命名不够清晰",但发现不了架构层面的问题。
第二,Agent 倾向于给出温和的评审。
大模型在训练过程中被优化为"有帮助的助手",它不太愿意说"这段代码写得不好"。即使代码有明显问题,它也倾向于用"可以考虑""建议优化"这种委婉表达,而不是直接指出风险。
第三,没有迭代过程。
真实代码评审不是一次性的。Reviewer 提出问题,Developer 修改,Reviewer 再看,可能还要再改。单 Agent 模式缺少这种来回对抗。
第四,评审标准不统一。
单 Agent 每次评审的侧重点可能不同。这次关注性能,下次关注安全,再下次关注命名。没有稳定的评审框架,评审质量波动很大。
多 Agent 协作可以解决这些问题。
把"写代码"交给一个 Agent,把"审代码"交给另一个 Agent。写代码的 Agent 有明确的实现目标和约束,审代码的 Agent 有明确的评审标准和打回规则。两者之间通过对话迭代,直到代码达到质量标准。
这不是让一个 AI 做两件事,而是让两个 AI 各做一件事,然后互相校验。
AutoGen 是微软开源的多 Agent 对话框架。它的核心抽象是 Agent 和 Conversation。
每个 Agent 有自己的角色设定、系统 Prompt、工具能力和终止条件。Agent 之间通过消息传递协作,由 Conversation Manager 控制对话流程。
AutoGen 的关键能力包括:
对于代码评审场景,最常用的是两个 Agent 的对话模式:
两者之间自动对话,Reviewer 不满意就打回,Developer 修改后再提交,直到 Reviewer 通过或达到最大轮次。
这个模式非常接近真实团队里的 Code Review 流程。
很多人搭多 Agent 代码评审,给两个 Agent 用同一个模型,只是 Prompt 不同。
这是对的。
多 Agent 协作的核心不是让不同 Agent 有不同能力,而是给它们不同的约束和目标。
Junior Agent 的目标是:根据需求描述,写出能运行的代码。
它的约束包括:
Junior Agent 不需要考虑太多架构问题,它的重点是"把功能做出来"。
它的系统 Prompt 可能长这样:
你是一个初级开发工程师。你的任务是根据需求描述编写代码实现。
要求:
1. 代码必须能正确运行;
2. 必须包含基本的错误处理;
3. 必须编写单元测试;
4. 命名清晰,函数职责单一;
5. 不要过度设计,先实现功能。
如果 Reviewer 提出修改意见,请根据意见修改代码并重新提交。Senior Agent 的目标是:发现代码中的问题,确保代码质量。
它的约束包括:
Senior Agent 的系统 Prompt 可能长这样:
你是一个资深代码评审工程师。你的任务是评审初级开发提交的代码。
评审维度:
1. 功能正确性:代码是否正确实现了需求;
2. 边界条件:是否处理了空值、异常输入、并发情况;
3. 安全性:是否存在注入、越权、敏感信息泄露风险;
4. 性能:是否有明显的性能隐患;
5. 测试:单元测试是否覆盖了关键路径;
6. 可维护性:命名是否清晰,结构是否合理。
输出格式:
- 问题列表(每个问题必须包含:位置、问题描述、修改建议);
- 总体评价(通过 / 需要修改);
- 如果"需要修改",Junior 会根据你的意见修改后重新提交。
注意:
- 不要给出模糊建议,比如"建议优化",必须具体说明怎么改;
- 如果代码没有严重问题,应该通过,不要为了挑毛病而挑毛病;
- 关注真实风险,不要纠结于代码风格偏好。两个 Agent 的差异不在模型能力,而在角色约束。
Junior 聚焦实现,Senior 聚焦质量。两者之间的张力产生真正的评审效果。
下面是一个基于 AutoGen 的代码评审实现。
import autogen
# 配置 LLM
llm_config = {
"config_list": [
{
"model": "gpt-4",
"api_key": "your-api-key"
}
],
"temperature": 0.2
}
# Junior Developer Agent
junior = autogen.AssistantAgent(
name="Junior_Developer",
system_message="""你是一个初级开发工程师。你的任务是根据需求描述编写代码实现。
要求:
1. 代码必须能正确运行;
2. 必须包含基本的错误处理;
3. 必须编写单元测试;
4. 命名清晰,函数职责单一。
如果 Reviewer 提出修改意见,请根据意见修改代码并重新提交。
每次修改后,输出完整的修改后代码。""",
llm_config=llm_config
)
# Senior Reviewer Agent
senior = autogen.AssistantAgent(
name="Senior_Reviewer",
system_message="""你是一个资深代码评审工程师。你的任务是评审 Junior 提交的代码。
评审维度:
1. 功能正确性;
2. 边界条件和异常处理;
3. 安全性;
4. 性能隐患;
5. 测试覆盖率;
6. 可维护性。
输出格式:
## 问题列表
(每个问题包含:位置、问题描述、修改建议)
## 总体评价
APPROVED(通过)或 CHANGES_REQUESTED(需要修改)
注意:
- 给出具体修改建议,不要模糊表述;
- 如果没有严重问题,应该通过;
- 最多评审 3 轮,第 3 轮必须给出最终结论。""",
llm_config=llm_config
)
# 启动对话
task = """
需求:实现一个用户注册接口。
功能要求:
1. 接收用户名、邮箱、密码;
2. 校验邮箱格式;
3. 密码长度至少 8 位,必须包含字母和数字;
4. 用户名不能重复(假设已有用户列表);
5. 密码必须加密存储,不能明文保存。
请用 Python 实现,并编写单元测试。
"""
junior.initiate_chat(
recipient=senior,
message=f"请评审我实现的代码。\n\n需求:{task}\n\n我的实现:\n\n(Junior 会在这里生成代码)"
)这个基础版本能跑通,但有几个问题。
第一,Junior 第一次不会自动生成代码,因为它只是发起了对话,没有先写代码。
第二,对话终止条件不清晰。需要明确什么时候结束。
第三,没有代码执行验证。Reviewer 只能看代码,不能确认代码能不能跑。
import autogen
# 带代码执行能力的 Junior
junior = autogen.AssistantAgent(
name="Junior_Developer",
system_message="""你是一个初级开发工程师。
工作流程:
1. 根据需求编写代码;
2. 编写单元测试;
3. 运行测试确认通过;
4. 提交给 Reviewer 评审;
5. 如果 Reviewer 要求修改,修改后重新运行测试并提交。
每次提交时必须包含:
- 完整代码(不要只输出修改部分);
- 测试运行结果。""",
llm_config=llm_config,
is_termination_msg=lambda x: x.get("content", "").rstrip().endswith("APPROVED")
)
# 带代码执行能力的 Senior
senior = autogen.AssistantAgent(
name="Senior_Reviewer",
system_message="""你是一个资深代码评审工程师。
评审流程:
1. 检查代码是否实现了需求;
2. 检查边界条件和异常处理;
3. 检查安全性;
4. 检查测试覆盖;
5. 给出评审意见。
如果代码质量达标,输出 APPROVED。
如果需要修改,输出 CHANGES_REQUESTED 和具体修改建议。
最多评审 3 轮。第 3 轮必须给出最终结论。""",
llm_config=llm_config
)
# 使用 UserProxy 执行代码
code_executor = autogen.UserProxyAgent(
name="Code_Executor",
human_input_mode="NEVER",
code_execution_config={
"work_dir": "code_review_workspace",
"use_docker": True
},
system_message="执行代码并返回结果。"
)加入代码执行后,Junior 写的代码会被实际运行,测试也会真正执行。Reviewer 看到的不仅是代码,还有运行结果。
这比纯文本评审可靠得多。
两个 Agent 的代码评审已经比单 Agent 好很多,但真实 Code Review 往往不止一个人参与。
AutoGen 支持 Group Chat,可以加入更多角色。
比如:
import autogen
# 定义多个 Agent
junior = autogen.AssistantAgent(
name="Junior_Developer",
system_message="你是初级开发,负责根据需求实现代码。根据评审意见修改代码。",
llm_config=llm_config
)
reviewer = autogen.AssistantAgent(
name="Senior_Reviewer",
system_message="你是资深 Reviewer,负责评审代码质量、架构设计和可维护性。",
llm_config=llm_config
)
security = autogen.AssistantAgent(
name="Security_Specialist",
system_message="""你是安全专家,负责审查代码中的安全风险。
重点关注:
1. 注入攻击(SQL 注入、XSS、命令注入);
2. 认证和授权漏洞;
3. 敏感信息泄露;
4. 不安全的依赖;
5. 加密和哈希是否正确使用。""",
llm_config=llm_config
)
test_eng = autogen.AssistantAgent(
name="Test_Engineer",
system_message="""你是测试工程师,负责评审测试用例。
重点关注:
1. 测试是否覆盖了关键路径;
2. 边界条件是否测试;
3. 异常场景是否覆盖;
4. 测试是否可重复运行;
5. 是否有假阳性或假阴性。""",
llm_config=llm_config
)
tech_lead = autogen.AssistantAgent(
name="Tech_Lead",
system_message="""你是技术负责人,负责最终决策。
汇总所有评审意见后,判断代码是否可以合并。
如果有任何高风险问题未解决,必须打回。
如果所有评审角色都通过,输出 APPROVED。""",
llm_config=llm_config
)
# 创建 Group Chat
groupchat = autogen.GroupChat(
agents=[junior, reviewer, security, test_eng, tech_lead],
messages=[],
max_round=15,
speaker_selection_method="auto"
)
# 创建 Group Chat Manager
manager = autogen.GroupChatManager(
groupchat=groupchat,
llm_config=llm_config
)
# 启动评审
task = """
需求:实现一个文件上传接口。
功能要求:
1. 支持上传图片和 PDF;
2. 文件大小限制 10MB;
3. 必须校验文件类型,不能只依赖扩展名;
4. 上传后存储到指定目录;
5. 返回文件访问 URL。
请用 Python + FastAPI 实现,并编写单元测试。
"""
code_executor.initiate_chat(
manager,
message=task
)Group Chat 模式下,每个 Agent 从自己的专业角度评审代码,最后由 Tech Lead 汇总决策。
这种模式更接近真实团队的多角色 Code Review。
但注意,Agent 数量越多,对话轮次越多,Token 消耗越大,延迟也越高。生产环境里建议控制在 3-5 个 Agent,不要为了"看起来全面"而加太多角色。
多 Agent 代码评审最容易犯的错误是:让 Reviewer Agent 自由评审。
自由评审的结果不可预测。这次关注性能,下次关注命名,再下次关注注释。评审标准不稳定,评审质量就不可控。
正确的做法是把评审标准工程化。
给 Reviewer Agent 一个明确的评审清单,而不是让它自己决定看什么。
review_checklist = """
评审清单(必须逐项检查):
## 功能正确性
- [ ] 代码是否实现了需求中的所有功能点
- [ ] 返回值是否符合预期
- [ ] 状态变更是否正确
## 边界条件
- [ ] 空值输入是否处理
- [ ] 超长输入是否处理
- [ ] 并发场景是否考虑
- [ ] 异常输入(特殊字符、非法格式)是否处理
## 安全性
- [ ] 用户输入是否校验和转义
- [ ] 是否存在 SQL 注入风险
- [ ] 是否存在权限越界风险
- [ ] 敏感信息是否加密或脱敏
## 性能
- [ ] 是否有 N+1 查询
- [ ] 是否有不必要的循环或递归
- [ ] 大数据量场景是否考虑分页或流式处理
## 测试
- [ ] 正常路径是否有测试
- [ ] 异常路径是否有测试
- [ ] 边界条件是否有测试
- [ ] 测试是否可以独立运行
## 可维护性
- [ ] 函数职责是否单一
- [ ] 命名是否清晰
- [ ] 是否有重复代码可以提取
"""把清单写进 Reviewer 的系统 Prompt,要求它逐项检查并输出结果。
这样评审标准就稳定了,每次评审都覆盖相同维度。
要求 Reviewer 按固定格式输出评审结果。
## 评审结果
### 功能正确性
- 状态:PASS / FAIL
- 说明:...
### 边界条件
- 状态:PASS / FAIL
- 问题:...
- 建议:...
### 安全性
- 状态:PASS / FAIL
- 问题:...
- 建议:...
### 性能
- 状态:PASS / FAIL
- 说明:...
### 测试
- 状态:PASS / FAIL
- 缺失场景:...
### 总体结论
APPROVED / CHANGES_REQUESTED
### 修改建议(如果 CHANGES_REQUESTED)
1. ...
2. ...
3. ...标准化输出有两个好处。
第一,Junior Agent 更容易理解评审意见并修改代码。
第二,系统可以自动解析评审结果,判断是否通过、哪些维度有问题、需要修改什么。
不是所有代码都需要同样严格的评审。
可以按风险等级分级:
分级评审可以节省 Token 消耗,也避免低风险代码被过度评审。
多 Agent 代码评审听起来很美,但落地时有几个坑必须提前知道。
Junior 修改代码,Reviewer 不满意打回,Junior 再改,Reviewer 还是不满意。来回几轮后,Token 消耗爆炸,但代码没有实质进展。
解决方法是设置明确的终止条件:
junior = autogen.AssistantAgent(
name="Junior_Developer",
is_termination_msg=lambda x: "APPROVED" in x.get("content", ""),
max_consecutive_auto_reply=3
)多 Agent 对话的 Token 消耗是单 Agent 的数倍。每个 Agent 每轮发言都会消耗 Token,而且对话历史会累积。
5 个 Agent 对话 10 轮,Token 消耗可能是单 Agent 的 20-50 倍。
降低成本的方法:
如果让 Agent 执行代码,必须在隔离环境里运行。
不要在生产机器上直接执行 Agent 生成的代码。用 Docker 容器或沙箱环境,限制文件系统和网络访问。
code_executor = autogen.UserProxyAgent(
name="Code_Executor",
code_execution_config={
"work_dir": "/tmp/code_review",
"use_docker": True,
"docker_image": "python:3.11-slim"
}
)Reviewer Agent 的行为取决于 Prompt。
如果 Prompt 里写"找出所有问题",它可能会纠结于无关紧要的细节,比如变量命名偏好。
如果 Prompt 里写"如果没有严重问题就通过",它可能会放过真正的风险。
需要反复调试 Reviewer 的 Prompt,找到平衡点。
一个经验是:在 Prompt 里明确告诉 Reviewer 什么级别的问题是必须打回的,什么级别的问题可以忽略。
必须打回的问题:
- 功能未实现或实现错误;
- 安全漏洞(注入、越权、明文密码);
- 数据丢失风险;
- 测试完全缺失。
可以忽略的问题:
- 变量命名偏好(只要清晰即可);
- 代码风格差异(只要一致即可);
- 非关键的优化建议(可以作为备注提出,但不阻塞通过)。多 Agent 评审不能替代人工评审。
它可以在人工评审之前做一轮预筛选,过滤掉明显问题,减少人工评审负担。但最终是否合并,应该由人决定。
尤其是高风险代码,多 Agent 评审只是辅助工具,不是决策者。
多 Agent 评审如果只靠 Prompt,评审标准是静态的。
更好的做法是让 Reviewer Agent 能访问知识库和历史评审记录。
把团队的编码规范、架构原则、安全要求整理成文档,让 Reviewer Agent 在评审时参考。
from autogen import AssistantAgent
reviewer = AssistantAgent(
name="Senior_Reviewer",
system_message="""你是资深 Reviewer。评审时必须参考以下团队规范:
{coding_standards}
如果代码违反团队规范,必须指出并引用具体规范条目。""",
llm_config=llm_config
)这样评审就不是泛泛而谈,而是基于团队真实标准。
把过去人工评审中发现的典型问题整理成案例库,让 Reviewer Agent 学习。
reviewer = AssistantAgent(
name="Senior_Reviewer",
system_message="""你是资深 Reviewer。以下是过去评审中发现的典型问题,请重点关注类似情况:
{historical_issues}
如果当前代码存在类似问题,必须指出。""",
llm_config=llm_config
)历史案例让 Reviewer 的评审更贴近团队真实经验,而不是通用的最佳实践。
每次多 Agent 评审的结果应该保存下来,形成评审记录。
记录内容包括:
这些记录可以用来:
评审不只是检查代码,还是积累工程经验的过程。
多 Agent 代码评审不是唯一方案。下面和其他几种常见方式做个对比。
单 Agent 评审成本低、速度快,但缺乏对抗性,容易自我审查。
适合简单代码、低风险场景。
多 Agent 评审有真正的对抗和迭代,评审质量更高,但成本和延迟也更高。
适合中等复杂度代码、需要质量保障的场景。
SonarQube、ESLint、Pylint 这类工具速度快、成本低,但只能检查已知模式,无法理解业务逻辑。
适合做基础检查,不能替代语义级评审。
人工评审质量最高,但成本高、速度慢,而且依赖 Reviewer 的经验和状态。
适合高风险代码、架构决策。
最佳实践是把这几种方式组合起来:
每一层解决不同问题,成本和质量互补。
如果你的团队想用 AutoGen 搭多 Agent 代码评审,建议按这个路径推进。
第一步,先跑通两个 Agent 的基础对话。
一个 Junior,一个 Senior,用最简单的 Prompt,验证 AutoGen 的对话机制能跑通。
第二步,完善评审标准。
给 Reviewer 加上评审清单和输出格式,让评审结果可预测、可解析。
第三步,加入代码执行。
让 Junior 写的代码真正运行,测试真正执行,Reviewer 看到运行结果。
第四步,调试 Prompt。
用 10-20 个真实代码案例测试评审效果,看 Reviewer 是否过于严苛或过于宽松,调整 Prompt 直到效果稳定。
第五步,接入团队规范。
把团队编码规范、安全要求、历史评审案例接入 Reviewer,让评审更贴近团队实际。
第六步,控制成本。
用便宜模型做 Junior,强模型做 Reviewer。限制对话轮次。评估每次评审的 Token 消耗,确保成本可控。
第七步,接入 CI/CD。
把多 Agent 评审接入代码提交流程。开发者提交 PR 后,自动触发多 Agent 评审,评审结果作为评论附加到 PR 上。人工 Reviewer 看到预评审结果后,再做最终确认。
这件事的价值不在于替代人工评审,而在于把大量低级问题在人工评审之前就过滤掉,让人工 Reviewer 把精力集中在真正重要的架构和业务判断上。
很多团队听到"多 Agent",第一反应是"自动化"。
但多 Agent 代码评审的真正价值不是自动化,而是对抗性。
单 Agent 做评审,是自己和自己对话,很难发现盲点。多 Agent 做评审,是两个独立视角互相校验,一个负责实现,一个负责质疑。
这种对抗性让评审结果更接近真实团队的 Code Review。
AutoGen 提供了实现这种对抗的基础设施。但基础设施不等于效果。效果取决于你怎么设计角色、怎么定义评审标准、怎么控制对话流程、怎么接入团队知识。
多 Agent 代码评审不是银弹。它不能替代人工评审,不能保证发现所有问题,也不能消除技术债。
但它能在人工评审之前做一轮高质量的预筛选,把明显问题过滤掉,把评审意见结构化,把评审过程可追溯。
对于代码量大、评审人力不足的团队,这种预筛选的价值非常大。
不要追求让 Agent 完全替代人工评审。
追求让 Agent 把 80% 的低级问题过滤掉,让人工 Reviewer把精力集中在 20% 的关键判断上。
这才是多 Agent 代码评审的正确定位。
一个 Junior 写代码,一个 Senior 审代码,两者之间来回迭代,最后由人做最终决策。
这个模式不性感,但很实用。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。