模型智能体开发之metagpt-单智能体实践

需求分析

  1. 根据诉求完成函数代码的编写,并实现测试case,输出代码

代码实现

定义写代码的action

  1. action是动作的逻辑抽象,通过将预设的prompt传入llm,来获取输出,并对输出进行格式化

  2. 具体的实现如下

    1. 定义prompt模版

      1. prompt是传给llm的入参,所以llm对prompt的需求解析越准确,那么llm的输出就会越符合我们的诉求
      2. 如何抽象出最合适的prompt模版
      python 复制代码
      PROMPT_TEMPLATE = """
          Write a python function that can {instruction} and provide two runnnable test cases.
          Return ```python your_code_here ```with NO other texts,
          your code:
          """
    2. 调用llm生成代码

      1. 通过传入的instruction参数来格式化llm入参,之后通过aask调用llm进行输出。因为llm的输出是并不一定会符合我们的诉求,所以需要按照需求对output进行格式化
      python 复制代码
      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  
    3. 对llm output进行格式化

      1. 正则表达式提取其中的code部分,llm在返回给我们代码时通常带有一些格式化标识,而这些格式化标识往往是我们所不需要的
      2. 格式方法:
      bash 复制代码
       @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
  3. 完整代码

    python 复制代码
    import asyncio
    import re
    import subprocess
    
    import fire
    
    from metagpt.actions import Action
    from metagpt.logs import logger
    from metagpt.roles.role import Role, RoleReactMode
    from metagpt.schema import Message
    
    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

创建一个role

  1. 初始化上下文

    python 复制代码
    class SimpleCoder(Role):
        name: str = "Alice"
        profile: str = "SimpleCoder"
    
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            self.set_actions([SimpleWriteCode])
    1. 可以看到创建了一个名为SimpleCoder的类,继承了Role,标明当前类是一个role的定位
    2. 其中name指定了当前role的名称
    3. 其中name指定了当前role的类型
    4. 然后我们重写了__init__方法,
    5. 绑定要执行的action是SimpleWriteCode,这个Action 能根据我们的需求生成我们期望的代码,定义的行动SimpleWriteCode会被加入到代办self._rc.todo中,
  2. 定义执行规则

    python 复制代码
    async def _act(self) -> Message:
     logger.info(f"{self._setting}: to do {self.rc.todo}({self.rc.todo.name})")
     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 
    1. 重写_act,编写智能体具体的行动逻辑
    2. self.rc.todo:待办事项
    3. self.get_memories(k=1)[0]:获取最新的一条memory,即本次case里面的用户下达的指令
      1. 在本次的case里面,当用户输出instruction的时候,role需要把instruction传递给action,这里就涉及到了user如何传递消息给agent的部分,是通过memory来传递的
      2. memory作为agent的记忆合集,当role在进行初始化的时候,role就会初始化一个memory对象来作为self._rc.memory属性,在之后的_observe中存储每一个message,以便后续的检索,所以也可以理解role的memory就是一个含有message的list
      3. 当需要获取memory(llm的对话context)的时候,就可以使用get_memories(self, k=0) -> list[Message] 方法
    4. todo.run(msg.content):使用待办事项来处理最新一条memory
    5. Message:作为metagpt里面统一的消息处理格式
  3. 完整代码

    python 复制代码
        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  # 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
        ```
        
  4. 测试demo

    1. 代码

      python 复制代码
      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)
      
      asyncio.run(main())
    2. 运行

      1. 如下图,role alice 关联到了action,并且action调用了llm,获取到的llm输出是一条代码。注意,代码格式有python格式化标识,所以在代码实现层面我们通过parse_code方法去掉了python的格式化标识。
      2. llm输出分为两部分,一部分是方法,另外一部分是测试case

demo如果想正常运行的话,需要调用llm的key,环境配置可以参照 metagpt环境配置参考

相关推荐
hsling松子24 分钟前
使用PaddleHub智能生成,献上浓情国庆福
人工智能·算法·机器学习·语言模型·paddlepaddle
belldeep27 分钟前
python:reportlab 将多个图片合并成一个PDF文件
python·pdf·reportlab
FreakStudio3 小时前
全网最适合入门的面向对象编程教程:56 Python字符串与序列化-正则表达式和re模块应用
python·单片机·嵌入式·面向对象·电子diy
丶21363 小时前
【CUDA】【PyTorch】安装 PyTorch 与 CUDA 11.7 的详细步骤
人工智能·pytorch·python
zmjia1114 小时前
AI大语言模型进阶应用及模型优化、本地化部署、从0-1搭建、智能体构建技术
人工智能·语言模型·自然语言处理
_.Switch4 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一个闪现必杀技4 小时前
Python入门--函数
开发语言·python·青少年编程·pycharm
sp_fyf_20244 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-02
人工智能·神经网络·算法·计算机视觉·语言模型·自然语言处理·数据挖掘
新缸中之脑4 小时前
Ollama 运行视觉语言模型LLaVA
人工智能·语言模型·自然语言处理
小鹿( ﹡ˆoˆ﹡ )5 小时前
探索IP协议的神秘面纱:Python中的网络通信
python·tcp/ip·php