【AI Agent系列】【MetaGPT多智能体学习】2. 重温单智能体开发 - 深入源码,理解单智能体运行框架

简介: 【AI Agent系列】【MetaGPT多智能体学习】2. 重温单智能体开发 - 深入源码,理解单智能体运行框架

本系列文章跟随《MetaGPT多智能体课程》(https://github.com/datawhalechina/hugging-multi-agent),深入理解并实践多智能体系统的开发。

本文参考该课程的第三章 - 单智能体开发。在第三章的基础上,顺带着看下相关源码,深入理解单智能体的运行框架。

0. 单智能体概念及运行框架

这部分为理论介绍和部分源码理解,想直接实战的同学可以直接跳过该部分。

0.1 概念 - Role

在MetaGPT中定义的agent运行周期如下:

  • 一个agent在启动后他会观察自己能获取到的信息,加入自己的记忆中
  • 下一步进行思考,决定下一步的行动,也就是从Action1,Action2,Action3中选择执行的Action
  • 决定行动后,紧接着就执行对应行动,得到这个环节的结果

如下图,

所谓的单智能体,在MetaGPT中,其实就是一个Role实例。一个 Role 能执行特定的 Action,拥有记忆、思考并采用各种策略行动。

0.2 单智能体运行周期

之前的文章中讨论过MetaGPT单智能体的运行周期,详细分析了Role类中run函数的运行方式和相关函数(如_observe、react函数)的作用,可以去看下:

  • _observe函数用来观察环境中的信息,获取关心的上下文
  • react函数用来思考_think + 动作_act
  • 然后最后将最终的结果再放到环境中 publish_message

这个流程中,Role有个关键参数:RoleContext,这个类型组织了Role与上下文的交互内容。

0.3 RoleContext - 与环境上下文交互

Role 在与环境上下文进行交互时,是通过内部的 RoleContext 对象来实现的。下面是RoleContext的源码(0.7版本)及一些变量的含义:

class RoleContext(BaseModel):
    """Role Runtime Context"""
    model_config = ConfigDict(arbitrary_types_allowed=True)
    # Environment 对象,当在 Environment 添加 Role 时会同时设置 Role 对 Environment 的引用。
    env: "Environment" = Field(default=None, exclude=True)  
    # 一个 MessageQueue 对象,该对象是对 asyncio 的 Queue 进行简单封装,主要是提供了非阻塞的 pop / push 方法。Role 通过该对象与环境中的其他 Role 进行信息交互。
    msg_buffer: MessageQueue = Field(
        default_factory=MessageQueue, exclude=True
    )  
    # 记忆对象。当 Role 执行 _act 时,会将执行得到的响应转换为 Message 对象放入 memory 中。另外当 Role 执行 _observe 时,会把 msg_buffer 的所有消息转移到 memory 中。
    memory: Memory = Field(default_factory=Memory)
    # long_term_memory: LongTermMemory = Field(default_factory=LongTermMemory)
    working_memory: Memory = Field(default_factory=Memory)
    # 记录 Role 的执行状态。初始状态值为 -1,当全部 Action 执行完成之后也会被重置为 -1。
    state: int = Field(default=-1)  
    # 下一个待执行的 Action。当 state >= 0 时会指向最后一个 Action。
    todo: Action = Field(default=None, exclude=True)
    # 用 str 表示的当前 Role 观察的 Action 列表,目前用在 _observe 获取 news 时进行消息过滤。
    watch: set[str] = Field(default_factory=set)
    # 存储那些在本次执行  _observe 时读取到的与当前 Role 上下游相关的消息。
    news: list[Type[Message]] = Field(default=[], exclude=True)  # TODO not used
    # ReAct 循环的模式,目前支持 REACT、BY_ORDER、PLAN_AND_ACT 3种模式,默认使用 REACT 模式。
    react_mode: RoleReactMode = (
        RoleReactMode.REACT
    ) 
    # 在 react_mode 为 REACT 模式时生效,用于设置最大的思考-循环次数,超过后会停止 _react 执行。
    max_react_loop: int = 1
    @property
    def important_memory(self) -> list[Message]:
        """Retrieve information corresponding to the attention action."""
        return self.memory.get_by_actions(self.watch)
    @property
    def history(self) -> list[Message]:
        return self.memory.get()

从上面代码中,可以看到几个重要的变量:

  • 环境,定义智能体所处的环境信息,此智能体的结果和其它属于此环境的智能体的结果会放到里面
  • memory:记忆
  • todo: Action:该智能体能执行的动作列表
  • watch:关心的动作列表

下面,我们来看下赋予智能体行动能力的Action类。

0.4 单智能体的动作定义 - Action

Action定义Role对象可以进行的动作。看下它的源码参数:

class Action(SerializationMixin, ContextMixin, BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)
    name: str = ""
    i_context: Union[
        dict, CodingContext, CodeSummarizeContext, TestingContext, RunCodeContext, CodePlanAndChangeContext, str, None
    ] = ""
    prefix: str = ""  # aask*时会加上prefix,作为system_message
    desc: str = ""  # for skill manager
    node: ActionNode = Field(default=None, exclude=True)

其中,prefix参数会在调用大模型时作为Prompt的一部分带入。

1. 实现一个单智能体

1.1 实现步骤

要实现一个Agent,其实就是定义一个Role。该Role应该包含自己的Action。

(1)定义Actions,重写run函数,这里面决定了我们对传入的内容到底要做什么样的处理,例如调用大模型得到结果

(2)定义Role,在Role的初始化中初始化Actions

(3)Role重写_act函数或_react函数,Role run的时候会调用该函数。_react函数重写,一般是先思考_think下一步用哪个action,然后再_act

1.2 完整代码

直接上教程中的完整代码(有细微修改,因为升级0.7版本之后有坑):

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)
asyncio.run(main())

运行结果:

1.3 升级0.7版本后,教程中原代码的坑

1.3.1 non-attribute was detected

解决办法:下面代码 PROMPT_TEMPLATE = 换成 PROMPT_TEMPLATE: str =

1.3.2 ‘SimpleCoder’ object has no attribute ‘_init_actions’

解决办法:将’_init_actions’改为’set_actions’

1.4 再加一个Action

定义另一个action:

class SimpleRunCode(Action):
    name: str = "SimpleRunCode"
    async def run(self, code_text: str):
        # 在Windows环境下,result可能无法正确返回生成结果,在windows中在终端中输入python3可能会导致打开微软商店
        result = subprocess.run(["python3", "-c", code_text], capture_output=True, text=True)
        # 采用下面的可选代码来替换上面的代码
        # result = subprocess.run(["python", "-c", code_text], capture_output=True, text=True)
        # import sys
        # result = subprocess.run([sys.executable, "-c", code_text], capture_output=True, text=True)
        code_result = result.stdout
        logger.info(f"{code_result=}")
        return code_result

修改Role的初始化,将这个Action也加进去:

class SimpleCoder(Role):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.set_actions([SimpleWriteCode, SimpleRunCode])
        self._set_react_mode(react_mode="by_order") # 多个Action之后,要指定一下动作的执行顺序,by_order表示按照顺序执行,by_name表示按照名称执行

运行遇到的坑:NameError: name ‘subprocess’ is not defined

解决办法:import subprocess

1.5 多Action之后增加的知识点总结

(1)self.set_actions([SimpleWriteCode, SimpleRunCode]) 之后要设置动作执行顺序,self._set_react_mode(react_mode="by_order")

(2)注意Role的_act函数里面的这几行代码:

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))

从环境中获取了最近的记忆,在本例中也就是上一个Action执行完的结果(生成的代码)。

执行完后,将该Action的返回结果封装成Message对象,放到环境中。

至此,单智能体的基本搭建过程就完成了。

2. 技术文档助手实践 / OSS订阅智能体实践

教程中后面还有两个复杂的单智能体实战案例,看了下,与之前MetaGPT入门课程中的教程基本没变化,这里就不再重复了。

这两部分的笔记可见:

2.1 技术文档助手相关

2.2 OSS订阅智能体相关

2.3 智能体开发作业相关

3. 参考资料

相关文章
|
4天前
|
人工智能 运维 安全
AI大模型运维开发探索第四篇:智能体分阶段演进路线
本文探讨了智能体工程的演进历程,从最初的思维链(智能体1.0)到实例化智能体(智能体2.0),再到结构化智能体(智能体3.0),最终展望了自演进智能体(智能体4.0)。文章详细分析了各阶段遇到的问题及解决策略,如工具调用可靠性、推理能力提升等,并引入了大模型中间件的概念以优化业务平台与工具间的协调。此外,文中还提到了RunnableHub开源项目,为读者提供了实际落地的参考方案。通过不断迭代,智能体逐渐具备更强的适应性和解决问题的能力,展现了未来AI发展的潜力。
|
8天前
|
人工智能 API 语音技术
HarmonyOS Next~鸿蒙AI功能开发:Core Speech Kit与Core Vision Kit的技术解析与实践
本文深入解析鸿蒙操作系统(HarmonyOS)中的Core Speech Kit与Core Vision Kit,探讨其在AI功能开发中的核心能力与实践方法。Core Speech Kit聚焦语音交互,提供语音识别、合成等功能,支持多场景应用;Core Vision Kit专注视觉处理,涵盖人脸检测、OCR等技术。文章还分析了两者的协同应用及生态发展趋势,展望未来AI技术与鸿蒙系统结合带来的智能交互新阶段。
61 31
|
2天前
|
人工智能 自然语言处理 程序员
AI引爆全美失业潮?通义灵码助你开发路上不孤单!
达沃斯调查显示,超4成老板计划2025-2030年因AI自动化削减员工。首当其冲的是软件工程行业,Anthropic CEO称AI可能在12个月内接管几乎所有代码编写工作。面对这一变革,程序员应如何应对?通义灵码作为基于通义大模型的AI研发辅助工具,提供代码生成、智能问答等功能,助力开发者适应AI原生研发新范式。现可直接参与项目,完成未实现功能!
|
7天前
|
人工智能 小程序 前端开发
【一步步开发AI运动小程序】十八、如何识别用户上传图片中的人体、运动、动作、姿态?
【云智AI运动识别小程序插件】为小程序提供人体、运动及姿态检测的AI能力,本地引擎支持10余种运动,无需后台服务,具备快速、低成本等优势。本文介绍如何通过Canvas方案读取用户上传图片的像素数据,实现人体检测与姿态分析功能,代码简单高效,适合快速集成。更多内容欢迎交流!
|
5天前
|
人工智能 小程序 前端开发
【一步步开发AI运动小程序】十九、运动识别中如何解析RGBA帧图片?
本文介绍了如何将相机抽取的RGBA帧图像解析为`.jpg`或`.png`格式,适用于体测、赛事等场景。首先讲解了RGBA图像结构,其为一维数组,每四个元素表示一个像素的颜色与透明度值。接着通过`uni.createOffscreenCanvas()`创建离屏画布以减少绘制干扰,并提供代码实现,将RGBA数据逐像素绘制到画布上生成图片。最后说明了为何不直接使用拍照API及图像转换的调用频率建议,强调应先暂存帧数据,运动结束后再进行转换和上传,以优化性能。
|
1天前
|
人工智能 自然语言处理 前端开发
20分钟上手DeepSeek开发:SpringBoot + Vue2快速构建AI对话系统
本文介绍如何使用Spring Boot3与Vue2快速构建基于DeepSeek的AI对话系统。系统具备实时流式交互、Markdown内容渲染、前端安全防护等功能,采用响应式架构提升性能。后端以Spring Boot为核心,结合WebFlux和Lombok开发;前端使用Vue2配合WebSocket实现双向通信,并通过DOMPurify保障安全性。项目支持中文语义优化,API延迟低,成本可控,适合个人及企业应用。跟随教程,轻松开启AI应用开发之旅!
|
4天前
|
人工智能 编解码 小程序
【一步步开发AI运动小程序】二十、AI运动小程序如何适配相机全屏模式?
本文探讨了小程序`camera`组件在全屏模式下的适配问题及其解决方案。由于`camera`组件存在预览图像裁切特性,可能导致入镜检测与预览不一致、骨骼图与人体不重合等问题。通过分析其裁剪逻辑(长边按比缩放,短边居中裁切),我们提供了计算裁剪比例和留白的适配方法,并优化了插件特性以支持全屏应用。同时,文章还讨论了全屏模式可能带来的副作用,如人体可视区域变小、检测范围变化及抽帧帧率下降等,并给出了改进建议。该方案适用于云上赛事、健身锻炼、AI体测、AR互动等场景,助力提升用户体验和UI布局合理性。
|
2天前
|
人工智能 数据可视化 API
36.7K star!拖拽构建AI流程,这个开源LLM应用框架绝了!
`Flowise` 是一款革命性的低代码LLM应用构建工具,开发者通过可视化拖拽界面,就能快速搭建基于大语言模型的智能工作流。该项目在GitHub上线不到1年就斩获**36.7K星标**,被开发者誉为"AI时代的乐高积木"。
|
5天前
|
机器学习/深度学习 存储 人工智能
AI职场突围战:夸克应用+生成式人工智能认证,驱动“打工人”核心竞争力!
在AI浪潮推动下,生成式人工智能(GAI)成为职场必备工具。文中对比了夸克、豆包、DeepSeek和元宝四大AI应用,夸克以“超级入口”定位脱颖而出。同时,GAI认证为职场人士提供系统学习平台,与夸克结合助力职业发展。文章还探讨了职场人士如何通过加强学习、关注技术趋势及培养合规意识,在AI时代把握机遇。
|
4天前
|
机器学习/深度学习 人工智能 自然语言处理
多模态AI核心技术:CLIP与SigLIP技术原理与应用进展
近年来,多模态表示学习在人工智能领域取得显著进展,CLIP和SigLIP成为里程碑式模型。CLIP由OpenAI提出,通过对比学习对齐图像与文本嵌入空间,具备强大零样本学习能力;SigLIP由Google开发,采用sigmoid损失函数优化训练效率与可扩展性。两者推动了多模态大型语言模型(MLLMs)的发展,如LLaVA、BLIP-2和Flamingo等,实现了视觉问答、图像描述生成等复杂任务。这些模型不仅拓展了理论边界,还为医疗、教育等领域释放技术潜力,标志着多模态智能系统的重要进步。
46 13
多模态AI核心技术:CLIP与SigLIP技术原理与应用进展

热门文章

最新文章