MetaGPT中的单智能体Action
单智能体 单Action
定义一个名为SimpleCoder的角色,这个角色可以执行一个名为SimpleWriteCode的动作。这个动作的目的是生成一个Python函数的代码,该函数能够完成给定的任务,并提供两个可运行的测试用例。代码使用了metagpt库中的Action和Role类,以及日志记录功能。
下面是代码的逐行解释:
**1.导入所需的模块:**re用于正则表达式,asyncio用于异步编程,以及metagpt库中的Action、Role、Message和logger。
2.定义一个名为SimpleWriteCode的类: 继承自Action。这个类的作用是生成Python函数代码。
- PROMPT_TEMPLATE是一个字符串模板,用于生成提示用户编写代码的字符串。 name是这个动作的名称。
- run方法是一个异步方法,它接受一个指令字符串,生成一个提示,然后调用_aask方法(这个方法在代码中没有定义,可能是metagpt库的一部分)来获取用户输入的代码。
- parse_code是一个静态方法,用于从用户输入中提取Python代码。它使用正则表达式来查找被python包围的代码块。
3.定义一个名为SimpleCoder的类: 继承自Role。这个类的作用是使用SimpleWriteCode动作。
- 在__init__方法中,它设置了可以执行的动作列表,这里只有一个SimpleWriteCode。
- _act方法是一个异步方法,它获取最近的消息,使用SimpleWriteCode动作生成代码,然后创建一个新的Message对象并返回。
4.定义一个名为main的异步函数: 创建了一个SimpleCoder实例,设置了一个任务(在这个例子中是“write a function that calculates the sum of a list”),然后运行这个角色并记录结果。
import re
import asyncio
from metagpt.actions import Action
from metagpt.roles import Role
from metagpt.schema import Message
from metagpt.logs import logger
class SimpleWriteCode(Action):
PROMPT_TEMPLATE:str = """
Write a python function that can {instruction} and provide two runnable test cases.
Return ```python your_code_here ```with NO other texts,
your code:
"""
name: str = "SimpleWriteCode"
async def run(self, instruction: str):
prompt = self.PROMPT_TEMPLATE.format(instruction=instruction)
rsp = await self._aask(prompt)
code_text = SimpleWriteCode.parse_code(rsp)
return code_text
@staticmethod
def parse_code(rsp):
pattern = r'```python(.*)```'
match = re.search(pattern, rsp, re.DOTALL)
code_text = match.group(1) if match else rsp
return code_text
class SimpleCoder(Role):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.set_actions([SimpleWriteCode])
async def _act(self) -> Message:
logger.info(f"{self._setting}: ready to {self.rc.todo}")
todo = self.rc.todo # todo will be SimpleWriteCode()
msg = self.get_memories(k=1)[0] # find the most recent messages
code_text = await todo.run(msg.content)
msg = Message(content=code_text, role=self.profile,
cause_by=type(todo))
return msg
async def main():
msg = "write a function that calculates the sum of a list"
role = SimpleCoder()
logger.info(msg)
result = await role.run(msg)
logger.info(result)
await main()
输出:
2024-12-11 16:21:31.726 | INFO | __main__:main:51 - write a function that calculates the sum of a list
2024-12-11 16:21:31.728 | INFO | __main__:_act:37 - <property object at 0x000001DAC56A5260>(): ready to SimpleWriteCode
```python
def generate_sum_function():
def sum_of_list(lst):
return sum(lst)
return sum_of_list
# Test cases
sum_function = generate_sum_function()
# Test case 1
assert sum_function([1, 2, 3, 4, 5]) == 15
print("Test case 1 passed.")
# Test case 2
assert sum_function([-1, 0, 1, 2, -3]) == -1
print("Test case 2 passed
2024-12-11 16:21:36.636 | WARNING | metagpt.utils.cost_manager:update_cost:49 - Model GLM-4 not found in TOKEN_COSTS.
2024-12-11 16:21:36.637 | INFO | __main__:main:53 - :
def generate_sum_function():
def sum_of_list(lst):
return sum(lst)
return sum_of_list
# Test cases
sum_function = generate_sum_function()
# Test case 1
assert sum_function([1, 2, 3, 4, 5]) == 15
print("Test case 1 passed.")
# Test case 2
assert sum_function([-1, 0, 1, 2, -3]) == -1
print("Test case 2 passed.")
.")
```
另一个问题测试
async def main():
msg = "solve th problem: 3x+11*2/3 =6"
role = SimpleCoder()
logger.info(msg)
result = await role.run(msg)
logger.info(result)
await main()
输出
2024-12-11 16:28:46.157 | INFO | __main__:main:4 - solve th problem: 3x+11*2/3 =6
2024-12-11 16:28:46.158 | INFO | __main__:_act:37 - <property object at 0x000001DAC56A5260>(): ready to SimpleWriteCode
```python
def solve_linear_equation():
# Constants in the equation: 3x + 11 * 2/3 = 6
a = 3
b = 22/3
c = -6
# Calculate x using the formula: x = (c - b) / a
x = (c - b) / a
return x
# Test cases
test_case_1 = solve_linear_equation()
test_case_2 = solve_linear_equation()
# The following line is just to prevent syntax error, remove it when pasting into a Python environment
# python your_code_here
```
Please note that when pasting this into a Python environment, you should remove the last line starting with `# python`. The test cases are simply calling the function twice to show that it can be run multiple times. The actual result should be the same each time the function is called.
2024-12-11 16:28:57.476 | WARNING | metagpt.utils.cost_manager:update_cost:49 - Model GLM-4 not found in TOKEN_COSTS.
2024-12-11 16:28:57.477 | INFO | __main__:main:6 - :
def solve_linear_equation():
# Constants in the equation: 3x + 11 * 2/3 = 6
a = 3
b = 22/3
c = -6
# Calculate x using the formula: x = (c - b) / a
x = (c - b) / a
return x
# Test cases
test_case_1 = solve_linear_equation()
test_case_2 = solve_linear_equation()
# The following line is just to prevent syntax error, remove it when pasting into a Python environment
# python your_code_here
单智能体 多Action
定义一个名为Programmer的角色,它能够执行三个动作:优化需求(RequirementsOpt)、编写代码(CodeWrite)和运行代码(CodeRun)。这个角色的目的是自动化地处理编程任务,从理解需求到编写和测试代码。下面是对代码的详细解释:
导入模块
- re:正则表达式模块,用于文本匹配。
- asyncio:异步编程模块,用于定义和运行异步任务。
- subprocess:用于执行外部命令和程序。
- metagpt库中的Action、Role、Message和logger。
CodeWrite 类
- 这是一个Action类,用于根据给定的需求编写Python函数。
- PROMPT_TEMPLATE:一个字符串模板,用于生成提示用户编写代码的字符串。
- run方法:接受需求字符串,生成提示,调用_aask方法获取代码,然后解析代码。
- parse_code静态方法:从响应中提取Python代码。
RequirementsOpt 类
- 另一个Action类,用于优化和明确需求。
- PROMPT_TEMPLATE:一个字符串模板,用于生成需求优化的提示。
- run方法:接受原始需求,生成优化需求的提示,调用_aask方法获取优化后的需求。
CodeRun 类
- 用于运行Python代码。
- run方法:使用subprocess模块执行Python代码,并返回输出结果或错误信息。
Programmer 类
- 定义了一个名为Programmer的角色,继承自Role。
- 初始化时,设置了三个动作:RequirementsOpt、CodeWrite和CodeRun,并设置为顺序执行模式。
- _act方法:定义了角色的行动逻辑,包括获取用户输入、执行动作、构造消息对象并返回结果。
main 函数
- 定义了一个异步函数main,用于运行Programmer角色。
- 实例化Programmer角色,设置一个具体的需求,记录日志信息,运行角色并记录结果。
- 代码执行 使用await main()启动异步任务。
代码逻辑
- 需求优化:首先,Programmer角色会优化用户提供的需求,使其更加明确和全面。
- 代码编写:然后,根据优化后的需求,编写相应的Python代码。
- 代码运行:最后,运行编写的代码,并返回结果。
import re
import asyncio
import subprocess
from metagpt.actions import Action
from metagpt.roles import Role
from metagpt.schema import Message
from metagpt.logs import logger
# 代码撰写Action
class CodeWrite(Action):
PROMPT_TEMPLATE: str = """
根据以下需求,编写一个能够实现{requirements}的Python函数。
返回的格式为:```python\n你的代码\n```,请不要包含其他的文本。
```python
# your code here
```
"""
name: str = "CodeWriter"
async def run(self, requirements: str):
prompt = self.PROMPT_TEMPLATE.format(requirements=requirements)
rsp = await self._aask(prompt)
code_text = CodeWrite.parse_code(rsp)
return code_text
@staticmethod
def parse_code(rsp): # 从模型生成中字符串匹配提取生成的代码
pattern = r"```python(.*?)```" # 使用非贪婪匹配
match = re.search(pattern, rsp, re.DOTALL)
code_text = match.group(1) if match else rsp
return code_text
# 需求优化Action
class RequirementsOpt(Action):
PROMPT_TEMPLATE: str = """
你要遵守的规范有:
1.简要说明 (Brief Description)
简要介绍该用例的作用和目的。
2.事件流 (Flow of Event)
包括基本流和备选流,事件流应该表示出所有的场景。
3.用例场景 (Use-Case Scenario)
包括成功场景和失败场景,场景主要是由基本流和备选流组合而成的。
4.特殊需求 (Special Requirement)
描述与该用例相关的非功能性需求(包括性能、可靠性、可用性和可扩展性等)和设计约束(所使用的操作系统、开发工具等)。
5.前置条件 (Pre-Condition)
执行用例之前系统必须所处的状态。
6.后置条件 (Post-Condition)
用例执行完毕后系统可能处于的一组状态。
无需测试用例,所有的代码在一个```python```中
请优化以下需求,使其更加明确和全面:
{requirements}
"""
name: str = "RequirementsOpt"
async def run(self, requirements: str):
prompt = self.PROMPT_TEMPLATE.format(requirements=requirements)
rsp = await self._aask(prompt)
return rsp.strip() # 返回优化后的需求
# 代码运行Action
class CodeRun(Action):
name: str = "CodeRun"
async def run(self, code_text: str):
try:
result = subprocess.run(
["python", "-c", code_text], text=True, capture_output=True, check=True
)
return result.stdout
except subprocess.CalledProcessError as e:
return e.stderr
# 设计Programmer Agent人设
class Programmer(Role):
"""
Programmer 角色类,继承自 Role 基类
"""
name: str = "cheems"
profile: str = "Programmer"
def __init__(self, **kwargs):
"""
初始化 Programmer 角色
"""
super().__init__(**kwargs) # 调用基类构造函数
self.set_actions([RequirementsOpt, CodeWrite, CodeRun]) # 为角色配备三个动作
self._set_react_mode(react_mode="by_order") # 顺序执行
async def _act(self) -> Message:
"""
定义角色行动逻辑
"""
logger.info(f"{self._setting}: 准备 {self.rc.todo}") # 记录日志
todo = self.rc.todo # 按照排列顺序获取待执行的动作
msg = self.get_memories(k=1)[0] # 获取最相似的一条记忆 (用户输入)
# 优化需求》编写代码》运行代码
result = await todo.run(msg.content)
# 构造 Message 对象
msg = Message(content=result, role=self.profile, cause_by=type(todo))
self.rc.memory.add(msg) # 将运行结果添加到记忆
return msg # 返回最终的 Message
# 运行我们的Agent
async def main():
msg = "如何用python设计一个ToDoList,使用Tkinter库,尽量不要安装额外包,安装包的代码要直接在python代码中运行,而非手动输入cmd;"
role = Programmer() # 实例化 Programmer
logger.info(msg) # 记录日志信息
result = await role.run(msg) # 得到运行结果
logger.info(result) # 记录运行结果
await main() # 异步运行 main 函数
2024-12-11 16:57:47.304 | INFO | __main__:main:119 - 如何用python设计一个ToDoList,使用Tkinter库,尽量不要安装额外包,安装包的代码要直接在python代码中运行,而非手动输入cmd;
2024-12-11 16:57:47.305 | INFO | __main__:_act:100 - cheems(Programmer): 准备 RequirementsOpt
为了使ToDoList应用程序的需求更加明确和全面,我们可以按照您提供的模板来细化需求。以下是针对该应用程序的优化需求说明:
### 简要说明
开发一个基于Python和Tkinter库的图形用户界面(GUI)待办事项列表(ToDoList)应用程序。该应用程序允许用户创建、查看、编辑和删除待办事项,无需安装任何额外的包。
### 事件流
1. **基本流**
- 启动应用程序时,显示一个窗口,其中包含添加新待办事项的输入框和按钮。
- 用户输入待办事项并点击添加按钮,待办事项被添加到列表中。
- 用户可以点击列表中的待办事项来编辑或删除它。
- 用户可以清除所有待办事项。
2. **备选流**
- 如果用户尝试添加空白的待办事项,应用程序应阻止并提示用户输入内容。
- 如果用户尝试编辑待办事项,但未做任何更改,应用程序应允许取消编辑。
- 如果用户尝试删除待办事项,应用程序应请求确认。
### 用例场景
1. **成功场景**
- 用户成功添加一个待办事项。
- 用户编辑并保存待办事项。
- 用户删除一个待办事项。
- 用户清除所有待办事项。
2. **失败场景**
- 用户尝试添加空白的待办事项,应用程序显示错误消息。
- 用户尝试编辑待办事项但取消操作,待办事项保持不变。
### 特殊需求
- 应用程序应具有直观的用户界面。
- 应用程序应在所有主流操作系统上运行。
- 应用程序应避免使用额外的包,所有必需的代码应在脚本内提供。
### 前置条件
- Python环境已安装。
- Tkinter库随Python一同安装,无需额外步骤。
### 后置条件
- 应用程序启动后,用户界面应正确显示。
- 待办事项列表中的数据应正确反映用户的添加、编辑和删除操作。
以下是一个简化版的Python代码示例,它实现了上述需求,并直接在代码中包含了Tkinter库的使用:
```python
import tkinter as tk
from tkinter import messagebox
class ToDoListApp:
def __init__(self, root):
self.root = root
self.root.title("To Do List")
self.listbox = tk.Listbox(root)
self.listbox.pack(fill="both", expand=True)
self.entry = tk.Entry(root)
self.entry.pack(side="bottom", fill="x")
self.entry.bind('<Return>', self.add_item)
tk.Button(root, text="Add", command=self.add_item).pack(side="bottom")
def add_item(self, event=None):
item = self.entry.get()
if item:
self.listbox.insert(tk.END, item)
self.entry.delete(0, tk.END)
else:
messagebox.showwarning("Warning", "Please enter a to-do item.")
def run(self):
self.root.mainloop()
if __name__ == "__main__":
root = tk.Tk()
app = ToDoListApp(root)
app.run()
```
请注意,上述代码仅提供了添加待办事项的基本功能,为了完整实现需求,还需要添加编辑、删除和清除所有待办事项的功能。由于代码较长,这里仅提供了核心框架。
2024-12-11 16:58:16.614 | WARNING | metagpt.utils.cost_manager:update_cost:49 - Model GLM-4 not found in TOKEN_COSTS.
2024-12-11 16:58:16.634 | INFO | __main__:_act:100 - cheems(Programmer): 准备 CodeWrite
Certainly! Below is an extended version of the Python code using Tkinter that includes the functionality to edit, delete, and clear all the to-do items in the list.
```python
import tkinter as tk
from tkinter import messagebox
class ToDoListApp:
def __init__(self, root):
self.root = root
self.root.title("To Do List")
self.listbox = tk.Listbox(root)
self.listbox.pack(fill="both", expand=True)
self.listbox.bind('<Double-Button-1>', self.edit_item)
self.entry = tk.Entry(root)
self.entry.pack(side="bottom", fill="x")
self.entry.bind('<Return>', self.add_item)
tk.Button(root, text="Add", command=self.add_item).pack(side="left", anchor="sw")
tk.Button(root, text="Delete", command=self.delete_item).pack(side="left", anchor="sw")
tk.Button(root, text="Clear All", command=self.clear_all).pack(side="left", anchor="sw")
def add_item(self, event=None):
item = self.entry.get()
if item:
self.listbox.insert(tk.END, item)
self.entry.delete(0, tk.END)
else:
messagebox.showwarning("Warning", "Please enter a to-do item.")
def edit_item(self, event=None):
try:
index = self.listbox.curselection()[0]
item = self.listbox.get(index)
self.listbox.delete(index)
self.entry.delete(0, tk.END)
self.entry.insert(tk.END, item)
self.entry.select_range(0, tk.END)
except IndexError:
messagebox.showwarning("Warning", "No item selected for editing.")
def delete_item(self):
try:
index = self.listbox.curselection()[0]
confirm = messagebox.askokcancel("Confirm", "Are you sure you want to delete this item?")
if confirm:
self.listbox.delete(index)
except IndexError:
messagebox.showwarning("Warning", "No item selected for deletion.")
def clear_all(self):
confirm = messagebox.askokcancel("Confirm", "Are you sure you want to clear all items?")
if confirm:
self.listbox.delete(0, tk.END)
def run(self):
self.root.mainloop()
if __name__ == "__main__":
root = tk.Tk()
app = ToDoListApp(root)
app.run()
```
This code provides the following functionalities:
- Double-clicking an item in the listbox will allow you to edit it.
- A "Delete" button to remove the currently selected item from the listbox.
- A "Clear All" button to remove all items from the listbox
2024-12-11 16:58:39.547 | WARNING | metagpt.utils.cost_manager:update_cost:49 - Model GLM-4 not found in TOKEN_COSTS.
2024-12-11 16:58:39.549 | INFO | __main__:_act:100 - cheems(Programmer): 准备 CodeRun
参考链接
https://github.com/qianyouliang/MetaGPT-Learn
如果有任何问题,欢迎在评论区提问。
原文地址:https://blog.csdn.net/qq_41472205/article/details/144405471
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!