MetaGPT 智能体 101:打造你的第一个 AI 智能体

本教程将带你从零开始,一步步打造你的第一个 MetaGPT 智能体。通过本教程,你将学会:

  • 使用现成的智能体
  • 开发一个可以执行一个或多个动作的智能体

使用现成的智能体

MetaGPT 提供了许多现成的智能体,你可以直接导入并使用。例如,以下代码展示了如何使用 ProductManager 智能体来编写一个产品需求文档 (PRD):

import asyncio

from metagpt.context import Context
from metagpt.roles.product_manager import ProductManager
from metagpt.logs import logger

async def main():
    msg = "Write a PRD for a snake game"
    context = Context()  # 创建会话上下文对象
    role = ProductManager(context=context)  # 初始化智能体
    while msg:
        msg = await role.run(msg)  # 运行智能体
        logger.info(str(msg))

if __name__ == '__main__':
    asyncio.run(main())

这段代码首先导入必要的模块,然后定义一个 main 函数。在 main 函数中,我们创建了一个会话上下文对象 context,并使用 ProductManager 类初始化一个智能体 role。最后,我们使用 role.run() 方法运行智能体,并打印输出结果。

开发你的第一个智能体

从实际应用的角度来看,一个有用的智能体需要能够执行某些动作。MetaGPT 提供了高度灵活的方式来定义自己的动作和智能体。

1. 定义动作

在 MetaGPT 中,Action 类是动作的抽象表示。你可以使用 LLM 来增强 Action,只需调用 self._aask 函数即可。

例如,我们想创建一个名为 SimpleWriteCode 的动作,用于根据自然语言描述编写 Python 代码:

import re
from metagpt.actions import Action

class SimpleWriteCode(Action):
    PROMPT_TEMPLATE: str = """
    Write a python function that can {instruction} and provide two runnnable 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

这段代码定义了一个名为 SimpleWriteCode 的类,它继承自 Action 类。该类包含一个 PROMPT_TEMPLATE 属性,用于定义提示词模板。run 方法接受一个自然语言描述 instruction,并使用提示词模板生成一个提示词,然后调用 _aask 函数向 LLM 发送请求,并返回代码文本。

2. 定义角色

在 MetaGPT 中,Role 类是智能体的抽象表示。一个角色可以执行某些动作,拥有记忆,并根据不同的策略进行思考和行动。

例如,我们想创建一个名为 SimpleCoder 的角色,它可以使用 SimpleWriteCode 动作来编写代码:

from metagpt.roles import Role

class SimpleCoder(Role):
    name: str = "Alice"
    profile: str = "SimpleCoder"

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.set_actions([SimpleWriteCode])

    async def _act(self) -> Message:
        logger.info(f"{self._setting}: to do {self.rc.todo}({self.rc.todo.name})")
        todo = self.rc.todo  # 获取当前动作

        msg = self.get_memories(k=1)[0]  # 获取最近一条消息
        code_text = await todo.run(msg.content)  # 执行动作
        msg = Message(content=code_text, role=self.profile, cause_by=type(todo))

        return msg

这段代码定义了一个名为 SimpleCoder 的类,它继承自 Role 类。该类包含一个 name 属性和一个 profile 属性,用于定义角色的名称和描述。__init__ 方法用于初始化角色,并使用 set_actions 方法添加 SimpleWriteCode 动作。_act 方法定义了角色的行动逻辑,它会获取最近一条消息,并使用当前动作执行代码编写任务。

3. 运行你的角色

现在,你可以初始化你的角色并运行它:

import asyncio

from metagpt.context import Context

async def main():
    msg = "write a function that calculates the product of a list"
    context = Context()
    role = SimpleCoder(context=context)
    logger.info(msg)
    result = await role.run(msg)
    logger.info(result)

asyncio.run(main())

这段代码首先定义一个 main 函数,并创建一个会话上下文对象 context。然后,我们使用 SimpleCoder 类初始化一个角色 role。最后,我们使用 role.run() 方法运行角色,并打印输出结果。

智能体拥有多个动作

一个智能体可以拥有多个动作,并根据不同的策略来选择执行哪个动作。例如,我们想创建一个名为 RunnableCoder 的角色,它可以编写代码并立即执行:

1. 定义动作

除了 SimpleWriteCode 动作,我们还需要定义一个名为 SimpleRunCode 的动作,用于执行代码:

class SimpleRunCode(Action):
    name: str = "SimpleRunCode"

    async def run(self, code_text: str):
        result = subprocess.run(["python3", "-c", code_text], capture_output=True, text=True)
        code_result = result.stdout
        logger.info(f"{code_result=}")
        return code_result

2. 定义角色

我们修改 RunnableCoder 角色,使其拥有 SimpleWriteCodeSimpleRunCode 两个动作:

class RunnableCoder(Role):
    name: str = "Alice"
    profile: str = "RunnableCoder"

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.set_actions([SimpleWriteCode, SimpleRunCode])
        self._set_react_mode(react_mode="by_order")

    async def _act(self) -> Message:
        logger.info(f"{self._setting}: to do {self.rc.todo}({self.rc.todo.name})")
        todo = self.rc.todo  # 获取当前动作

        msg = self.get_memories(k=1)[0]  # 获取最近一条消息
        result = await todo.run(msg.content)  # 执行动作

        msg = Message(content=result, role=self.profile, cause_by=type(todo))
        self.rc.memory.add(msg)
        return msg

这段代码中,我们使用 set_actions 方法添加了两个动作,并使用 _set_react_mode 方法设置了动作执行策略为 by_order,表示按照动作定义的顺序执行。

3. 运行你的角色

现在,你可以初始化 RunnableCoder 角色并运行它:

import asyncio

from metagpt.context import Context

async def main():
    msg = "write a function that calculates the product of a list"
    context = Context()
    role = RunnableCoder(context=context)
    logger.info(msg)
    result = await role.run(msg)
    logger.info(result)

asyncio.run(main)

这段代码与之前类似,只是使用了 RunnableCoder 角色。

总结

本教程展示了如何使用 MetaGPT 创建一个简单的智能体,并演示了如何定义动作和角色,以及如何运行智能体。你可以在此基础上进一步扩展你的智能体,使其能够执行更复杂的任务。

更多学习资源

发表评论