Chapter 2: 程序员智能体 (Programmer Agent)
欢迎回来!在 第 1 章:多智能体协作框架 (Multi-Agent Collaboration Framework) 中,我们了解了 AutoSafeCoder 的“项目经理”——多智能体协作框架,它负责协调各个“专家”智能体来完成任务。现在,我们要深入认识这个团队中的第一位核心成员:**程序员智能体 (Programmer Agent)**。
程序员智能体是做什么的?
想象一下,你有一个很棒的想法,想要开发一个软件功能,比如一个简单的网页计算器。你首先需要有人能把你的想法(需求)变成实际的代码。在软件开发团队中,这个角色就是程序员。
在 AutoSafeCoder 里,程序员智能体 (Programmer Agent) 就扮演着这个程序员的角色。它的主要工作有两个:
- 编写初始代码: 根据我们给出的初始需求(一个“提示”或“Prompt”),它会尝试生成相应的 Python 代码来实现这个功能。就像你告诉程序员:“我需要一个能做加法的计算器”,程序员会写出第一版代码。
- 根据反馈修改代码: 光写出来还不够,代码可能存在问题。比如,代码可能不够安全(容易被攻击),或者在某些特殊情况下会出错(比如输入了非数字字符)。当其他智能体(比如静态安全分析器或模糊测试智能体们)发现了这些问题并给出反馈报告时,程序员智能体需要理解这些报告,并尝试修改代码来修复这些缺陷。这就像程序员收到测试人员提交的 Bug 报告,然后去调试和修复代码一样。
所以,程序员智能体不仅仅是一个“代码生成器”,它更像一个能够学习和迭代的开发者,不断改进自己的代码,使其更健壮、更安全。
程序员智能体如何工作?
这个智能体的核心能力来自于强大的**大语言模型 (Large Language Model, LLM)**,比如我们熟悉的 GPT 系列模型。你可以把它想象成一个拥有海量编程知识和经验的“虚拟大脑”。
工作流程大致如下:
- 接收任务: 多智能体协作框架会给程序员智能体分配任务。
- 如果是初始编写,任务就是一段描述需求的文字(Prompt)。
- 如果是修改代码,任务会包含当前的代码以及具体的反馈信息(比如静态分析报告或模糊测试发现的错误)。
- 与 LLM 交互: 程序员智能体会将任务信息(需求描述或代码+反馈)包装成一个适合 LLM 理解的请求(这部分通常由 大语言模型交互接口 辅助完成)。
- 生成/修改代码: LLM 根据收到的请求,利用其强大的语言理解和生成能力,产出相应的 Python 代码(新代码或修改后的代码)。
- 返回结果: 程序员智能体将 LLM 生成的代码返回给多智能体协作框架,以便进行下一步的检查或测试。
如何使用程序员智能体?
在 AutoSafeCoder 项目中,我们通常不会直接单独使用程序员智能体。它是由多智能体协作框架(在 main.py
中的 MultiAgentSystem
类)来创建和调用的。
让我们回顾一下 main.py
中框架是如何使用它的:
1. 创建程序员智能体实例
在 MultiAgentSystem
的初始化方法 __init__
中,会创建一个 ProgrammerAgent
的实例。
# main.py (片段)
from programmer_agent import ProgrammerAgent
# ... 其他导入 ...
class MultiAgentSystem:
def __init__(self, entry):
# 'entry' 包含了任务信息,比如 ID 和 Prompt
# 创建 ProgrammerAgent 实例,把任务信息传给它
self.programmer_agent = ProgrammerAgent(entry)
# ... 初始化其他智能体 ...
self.code = None # 用来存放代码
代码解释:
- 我们从
programmer_agent.py
文件导入ProgrammerAgent
类。 - 在
MultiAgentSystem
初始化时,使用ProgrammerAgent(entry)
创建了一个实例,并将其保存在self.programmer_agent
中。entry
是一个字典,包含了任务的具体信息,比如:entry = {'ID': 'Task001', 'Prompt': '编写一个函数,接收两个整数,返回它们的和。'}
2. 调用 write_code
方法生成初始代码
框架在 run
方法的一开始,会调用 programmer_agent
的 write_code
方法来生成第一版代码。
# main.py (run 方法片段)
class MultiAgentSystem:
# ... (init 方法) ...
def run(self, iterations=120):
# === 第 1 步: 程序员编写初始代码 ===
# 调用 programmer_agent 的 write_code 方法
self.code = self.programmer_agent.write_code()
print(f"程序员智能体生成了初始代码:\n{self.code}")
# ... 后续步骤 ...
代码解释:
self.programmer_agent.write_code()
这行代码会触发程序员智能体与 LLM 的交互,让 LLM 根据entry
中的 ‘Prompt’ 生成代码。- 返回的代码字符串会被存储在
self.code
变量中,供后续的静态分析或模糊测试使用。
示例输入 (Prompt):
编写一个函数,接收两个整数,返回它们的和。
可能的输出 (self.code):
def add_numbers(a, b):
"""
计算两个整数的和。
Args:
a: 第一个整数。
b: 第二个整数。
Returns:
两个整数的和。
"""
return a + b
3. 调用反馈方法修改代码
当其他智能体发现问题后,框架会调用程序员智能体的反馈方法,比如 write_code_feedback_static
(用于静态分析反馈) 或 write_code_feedback_fuzz
(用于模糊测试反馈)。
# main.py (静态分析反馈循环片段)
class MultiAgentSystem:
# ... (前面的代码) ...
# 如果静态分析发现问题 (result 不等于 SAFE)
if result.name != FResult.SAFE.name:
for i in range(4): # 最多尝试修复 4 次
print(f"发现静态分析问题: {error_description}")
# 调用 feedback 方法让程序员修改代码
self.code = self.programmer_agent.write_code_feedback_static(
self.code, # 当前有问题的代码
error_description, # 错误描述
"" # (这里可以传 CWE 编号,示例中为空)
)
# 再次进行静态分析... (省略)
# 如果修复成功,跳出循环 (省略)
# ... (后面的代码) ...
代码解释:
- 当静态安全分析器 (
executor_static
) 发现问题并返回error_description
后,框架会调用programmer_agent.write_code_feedback_static
。 - 这个方法需要传入当前的代码 (
self.code
) 和**错误描述 (error_description
)**。 - 程序员智能体接收到这些信息后,会再次请求 LLM,要求它基于反馈来修改代码。
- 返回的修改后的代码会更新
self.code
。 - 同样地,如果模糊测试发现了使代码崩溃的输入,框架会调用
programmer_agent.write_code_feedback_fuzz
,传入当前代码和导致失败的输入信息,让程序员智能体尝试修复。
示例输入 (静态分析反馈):
self.code
: (假设是上面那个add_numbers
函数)error_description
: “CWE-190: 潜在的整数溢出风险。如果输入的 a 和 b 都非常大,它们的和可能超过 Python 整数能表示的最大范围。”
可能的输出 (修改后的 self.code
):
import sys
def add_numbers(a, b):
"""
计算两个整数的和,并检查潜在的溢出。
Args:
a: 第一个整数。
b: 第二个整数。
Returns:
两个整数的和。
Raises:
OverflowError: 如果结果超出整数范围。
"""
# 检查输入是否为整数 (防御性编程)
if not isinstance(a, int) or not isinstance(b, int):
raise TypeError("输入必须是整数")
result = a + b
# 简单的溢出检查 (注意: Python 的整数理论上无限大,但这里模拟修复)
# 更实际的检查可能依赖于上下文或特定库的最大值
if a > 0 and b > 0 and result < 0: # 正数相加变负数,可能溢出
raise OverflowError("计算结果溢出")
if a < 0 and b < 0 and result > 0: # 负数相加变正数,可能溢出
raise OverflowError("计算结果溢出")
return result
正如你所见,程序员智能体通过这几个核心方法,实现了代码的“创造”与“改进”。
内部实现揭秘
我们已经了解了程序员智能体的职责和如何使用它,现在稍微深入一点,看看它是如何在内部与大语言模型 (LLM) 互动的。这主要涉及到 programmer_agent.py
文件和辅助函数所在的 utils.py
文件。
非代码流程图解:
当框架调用程序员智能体的方法时,内部大致发生了什么?
sequenceDiagram
participant MAS as 多智能体协作框架 (MultiAgentSystem)
participant PA as 程序员智能体 (ProgrammerAgent)
participant Utils as 工具函数 (utils.py)
participant LLM as 大语言模型 (例如 GPT)
MAS->>PA: 调用 write_code()
PA->>Utils: 调用 call_chatgpt_programmer(prompt)
Utils->>LLM: 发送格式化后的请求 (包含 Prompt)
LLM-->>Utils: 返回生成的代码文本
Utils-->>PA: 返回处理后的代码字符串
PA-->>MAS: 返回初始代码
MAS->>PA: 调用 write_code_feedback_static(代码, 反馈)
PA->>Utils: 调用 call_chatgpt_programmer_feedback_static(代码, 反馈)
Utils->>LLM: 发送格式化后的请求 (包含代码和反馈)
LLM-->>Utils: 返回修改后的代码文本
Utils-->>PA: 返回处理后的代码字符串
PA-->>MAS: 返回修改后的代码
图解说明:
- 框架 (MAS) 调用程序员智能体 (PA) 的方法(如
write_code
或write_code_feedback_static
)。 - 程序员智能体 (PA) 并不直接与 LLM 对话,而是调用
utils.py
中相应的工具函数(如call_chatgpt_programmer
)。这些函数扮演了大语言模型交互接口的角色。 - 工具函数 (Utils) 负责将输入(Prompt 或 代码+反馈)包装成一个结构化的、包含详细指令的请求,然后发送给**大语言模型 (LLM)**。
utils.py
中通常会包含预设的“提示模板”(Prompt Templates),用来指导 LLM 更好地完成任务。 - LLM 处理请求并生成回应(代码文本)。
- 工具函数 (Utils) 接收 LLM 的回应,可能会做一些清理工作(比如移除 LLM 回答中多余的解释文字,只留下代码),然后将纯净的代码字符串返回给程序员智能体。
- 程序员智能体 (PA) 最后将收到的代码返回给框架。
代码层面的深入了解:
让我们看看 programmer_agent.py
中的关键代码。
1. 初始化 (__init__
)
# programmer_agent.py (片段)
class ProgrammerAgent:
def __init__(self, entry):
# 存储传入的任务信息 'entry'
self.entry = entry
代码解释:
- 非常简单,构造函数只接收任务信息
entry
并将其存储在实例变量self.entry
中,以便后续方法(如write_code
)可以使用任务的 Prompt。
2. 编写初始代码 (write_code
)
# programmer_agent.py (片段)
from utils import call_chatgpt_programmer # 导入与 LLM 交互的函数
class ProgrammerAgent:
# ... (__init__ 方法) ...
def write_code(self):
# 构造一个简单的提示,结合任务需求
prompt = f"创建一个 Python 函数,遵循以下代码要求: {self.entry['Prompt']}"
# 调用 utils.py 中的函数与 LLM 交互
code = call_chatgpt_programmer(prompt)
return code # 返回 LLM 生成的代码
代码解释:
- 它从
self.entry
中获取原始的编程需求Prompt
。 - 将需求包装进一个更具体的指令字符串
prompt
中。 - 关键在于调用
call_chatgpt_programmer(prompt)
,这个函数位于utils.py
,它负责处理所有与 OpenAI API(或其他 LLM API)通信的细节,包括构建更复杂的 Few-Shot Prompt(在utils.py
中可以看到construct_few_shot_prompt
的加载和使用)、发送请求、接收和解析响应。 - 最后返回从
utils.py
函数获得的纯代码字符串。
3. 根据静态分析反馈修改代码 (write_code_feedback_static
)
# programmer_agent.py (片段)
# 导入处理静态分析反馈的 LLM 调用函数
from utils import call_chatgpt_programmer_feedback_static
class ProgrammerAgent:
# ... (__init__, write_code 方法) ...
def write_code_feedback_static(self, completion, cwe_code, issue_text):
# 调用 utils.py 中的函数,传入当前代码和反馈信息
code = call_chatgpt_programmer_feedback_static(
completion, # 当前代码
self.entry, # 原始任务信息 (可能有用)
cwe_code, # CWE 编号 (如果有)
issue_text # 具体的错误/警告描述
)
return code # 返回 LLM 修改后的代码
代码解释:
- 这个方法接收当前的代码 (
completion
) 和静态分析反馈 (cwe_code
,issue_text
)。 - 它调用
utils.py
中的call_chatgpt_programmer_feedback_static
函数。这个函数会构造一个特定的 Prompt,告诉 LLM:“这是当前的代码,它有这些安全问题,请修复它们。” - 同样,所有与 LLM API 的交互细节都封装在
utils.py
的函数中。 - 方法返回 LLM 生成的、尝试修复了问题的代码。
write_code_feedback_fuzz
方法的工作方式类似,只是它调用的是utils.py
中处理模糊测试反馈的函数 (call_chatgpt_programmer_feedback_fuzzing
),并传入导致失败的输入信息。
通过这种方式,ProgrammerAgent
类本身保持相对简洁,专注于定义“做什么”(编写代码、根据反馈修改代码),而将“如何与 LLM 对话”的具体实现委托给了 utils.py
中的辅助函数(即大语言模型交互接口)。
总结
在本章中,我们认识了 AutoSafeCoder 团队中的“程序员”——**程序员智能体 (Programmer Agent)**。我们学习到:
- 它的核心职责是:根据初始需求生成 Python 代码,并根据后续发现的安全问题或运行时错误修改代码。
- 它像一个真实世界的程序员,能够接收任务、编写代码,并根据 Bug 报告进行迭代修复。
- 它的“大脑”是强大的**大语言模型 (LLM)**。
- 多智能体协作框架通过调用它的
write_code
、write_code_feedback_static
和write_code_feedback_fuzz
等方法来驱动代码的生成和修改。 - 其内部实现依赖于
utils.py
中的辅助函数(大语言模型交互接口)来格式化请求并与 LLM API 进行通信。
程序员智能体是 AutoSafeCoder 实现“自动编写和修复代码”目标的关键执行者。但是,光有程序员还不够,我们还需要有人来检查代码的安全性。
下一章预告: 第 3 章:静态安全分析器 (Static Security Analyzer) - 探索负责在不运行代码的情况下检查代码是否存在已知安全漏洞模式的智能体。
Generated by AI Codebase Knowledge Builder