metagpt中ActionNode的用法

news2024/12/21 16:04:32

目录

    • 整体流程
      • 1. 基础组件:
      • 2. SIMPLE_THINK_NODE 和 SIMPLE_CHECK_NODE:
      • 3. THINK_NODES 类:
      • 4. ThinkAction 类:
      • 5. SimplePrint 类:
      • 6. Printer 类:
      • 7. main 函数:
      • 总结:
      • 主要执行流程:
    • 代码
    • 参考链接:

整体流程

实现一个基于节点 (Node) 结构和思维推理的系统,用于生成和打印数字列表。它使用了 ActionNode 和 Action 类来定义任务和节点,并且通过异步任务执行逻辑来实现工作流。

1. 基础组件:

ActionNode 和 Action 类:

  • ActionNode 是一个继承自 ActionNode 类的对象,负责执行特定任务的节点。每个节点可以有子节点,形成树形结构。
  • Action 是执行动作的基础类,ThinkAction 和 SimplePrint 继承自 Action。

2. SIMPLE_THINK_NODE 和 SIMPLE_CHECK_NODE:

这两个节点负责“思考”和“检查”数字列表的生成:

  • SIMPLE_THINK_NODE:这个节点的任务是思考生成一个数字列表的过程,传入的 instruction 说明需要生成什么样的数字列表(例如 Fibonacci 数列的前 10 个数字)。
  • SIMPLE_CHECK_NODE:这个节点负责接收数字列表,并确保返回的格式严格符合要求,返回的格式必须是像 [1,2,3,4] 这样的数组。

3. THINK_NODES 类:

THINK_NODES 类继承自 ActionNode,代表一个包含子节点的节点(SIMPLE_THINK_NODE 和 SIMPLE_CHECK_NODE)。
它有一个 simple_fill 方法,负责根据给定的 context 生成思考内容,并用 LLM(Large Language Model)生成数字列表。子节点的返回内容会被依次传递,最终父节点返回的内容是最后一个子节点的输出。

4. ThinkAction 类:

该类继承自 Action,用于“思考”任务,目的是根据传入的 instruction(例如,提供一个斐波那契数列的任务),生成一个数字列表。
它使用 THINK_NODES 类来生成数字列表,并且通过正则表达式(find_in_brackets 方法)从返回的字符串中提取数字列表。
如果提取到有效的数字列表,会将其返回,否则返回空列表。

5. SimplePrint 类:

该类继承自 Action,其任务是简单地打印数字。它接受一个 input_num 参数,并在 run 方法中打印这个数字。

6. Printer 类:

Printer 类代表一个角色(Role),它将多个动作(如 ThinkAction 和 SimplePrint)组合成一个完整的工作流。
它有多个方法来执行这些动作:

  • _think:确定下一个要执行的动作(基于角色的当前状态)。
  • _prepare_print:准备打印数字列表。
  • _act:执行实际的动作(例如,运行 ThinkAction,生成数字列表,然后调用 SimplePrint 打印数字)。
  • _react:在运行过程中根据状态决定执行顺序,直到所有任务完成。

7. main 函数:

main 函数是程序的入口点。在此函数中,首先定义了一个任务(例如,生成斐波那契数列的前 10 个数字),然后创建了一个 Printer 角色,运行任务并记录日志。

总结:

使用面向对象的设计,创建不同的 Action 和 ActionNode 来管理工作流。
ThinkAction 负责生成数字列表,SimplePrint 负责打印结果。
Printer 类作为角色,协调执行 ThinkAction 和 SimplePrint。
通过异步方法(async/await)实现了非阻塞的执行流程,使得每个任务都能并发执行。

主要执行流程:

Printer 类 调用 ThinkAction,根据指令生成数字列表。
生成的数字列表被 Printer 通过 SimplePrint 输出。
整个过程是异步的,通过 asyncio 来运行和协调多个任务。

最终,Printer 角色根据任务要求生成并打印一个数字列表,例如斐波那契数列。

代码

import asyncio
import re

from metagpt.actions.action import Action, ActionNode
from metagpt.logs import logger
from metagpt.roles import Role
from metagpt.schema import Message

# 将思考斐波那契数列的10个数字作为prompt输入,在这里我们将“思考需要生成的数字列表”作为命令(instruction)写入
# 将期望返回格式(expected_type)设置为str,无需设置例子(example)
SIMPLE_THINK_NODE = ActionNode(
    key="Simple Think Node",
    expected_type=str,
    instruction="""
            Think about what list of numbers you need to generate
            """,
    example="",
)

# 在这里通过命令(instruction)来规定需要生成的数字列表格式,提供例子(example)来帮助LLM理解
SIMPLE_CHECK_NODE = ActionNode(
    key="Simple CHECK Node",
    expected_type=str,
    instruction="""
            Please provide the number list for me, strictly following the following requirements:
            1. Answer strictly in the list format like [1,2,3,4]
            2. Do not have extra spaces or line breaks.
            Return the list here:
            """,
    example="[1,2,3,4]" "[4,5,6]",
)


class THINK_NODES(ActionNode):
    def __init__(
        self, name="Think Nodes", expected_type=str, instruction="", example=""
    ):
        super().__init__(
            key="",
            expected_type=expected_type,
            instruction=instruction,
            example=example,
        )
        self.add_children(
            [SIMPLE_THINK_NODE, SIMPLE_CHECK_NODE]
        )  # 初始化过程,将上面实现的两个子节点加入作为THINK_NODES类的子节点

    async def simple_fill(
        self,
        schema,
        mode,
        exclude=None,
    ):
        prompt = self.compile(
            context=self.context, schema=schema, mode=mode, exclude=exclude
        )
        print(f"actionnode:{prompt}")
        if schema != "raw":
            mapping = self.get_mapping(mode, exclude=exclude)
            class_name = f"{self.key}_AN"
            content, scontent = await self._aask_v1(
                prompt,
                class_name,
                mapping,
                images=None,
                schema=schema,
                timeout=5,
            )
            self.content = content
            self.instruct_content = scontent
        else:
            self.content = await self.llm.aask(prompt)
            self.instruct_content = None

        return self

    async def fill(self, context, llm, schema="raw", mode="auto", strgy="complex"):
        self.set_llm(llm)
        self.set_context(context)
        if self.schema:
            schema = self.schema

        if strgy == "simple":
            return await self.simple_fill(schema=schema, mode=mode)
        elif strgy == "complex":
            # 这里隐式假设了拥有children
            child_context = context  # 输入context作为第一个子节点的context
            for _, i in self.children.items():
                i.set_context(child_context)  # 为子节点设置context
                child = await i.simple_fill(schema=schema, mode=mode)
                child_context = (
                    child.content
                )  # 将返回内容(child.content)作为下一个子节点的context

            self.content = child_context  # 最后一个子节点返回的内容设置为父节点返回内容(self.content)
            return self


class SimplePrint(Action):
    """
    Action that print the num inputted
    """

    def __init__(self, name="SimplePrint", input_num: int = 0):
        super().__init__()

        self.input_num = input_num

    async def run(self, **kwargs):
        print(str(self.input_num) + "\n")
        return "0"


class ThinkAction(Action):
    """
    Action that think
    """

    def __init__(self, name="ThinkAction", context=None, llm=None):
        super().__init__()
        self.node = (
            THINK_NODES()
        )  # 初始化Action时,初始化一个THINK_NODE实例并赋值给self.node

    async def run(self, instruction) -> list:
        PROMPT = """
            You are now a number list generator, follow the instruction {instruction} and 
            generate a number list to be printed please.
            """

        prompt = PROMPT.format(instruction=instruction)
        print(f"thinkaction: {prompt}")
        rsp_node = await self.node.fill(
            context=prompt, llm=self.llm, schema="raw", strgy="complex"
        )  # 运行子节点,获取返回(返回格式为ActionNode)(注意设置 schema="raw" )
        rsp = rsp_node.content  # 获取返回的文本内容

        rsp_match = self.find_in_brackets(
            rsp
        )  # 按列表格式解析返回的文本内容,定位“[”与“]”之间的内容

        try:
            rsp_list = list(
                map(int, rsp_match[0].split(","))
            )  # 按列表格式解析返回的文本内容,按“,”对内容进行分割,并形成一个python语法中的列表

            return rsp_list
        except:
            return []

    @staticmethod
    def find_in_brackets(s):
        pattern = r"\[(.*?)\]"
        match = re.findall(pattern, s)
        return match


class Printer(Role):

    def __init__(
        self, name="Jerry", profile="Printer", goal="Print the number", constraints=""
    ):
        super().__init__()

        self.set_actions([ThinkAction])
        # self.num_list = list()

    async def _think(self) -> None:
        """Determine the action"""
        # logger.info(self.rc.state)

        if self.rc.todo is None:
            self._set_state(0)
            return

        if self.rc.state + 1 < len(self.states):
            self._set_state(self.rc.state + 1)
        else:
            self.rc.todo = None

    async def _prepare_print(self, num_list: list) -> Message:
        """Add actions"""
        actions = list()

        for num in num_list:
            actions.append(SimplePrint(input_num=num))

        self.set_actions(actions)
        self.rc.todo = None
        return Message(content=str(num_list))

    async def _act(self) -> Message:
        """Action"""
        todo = self.rc.todo

        if type(todo) is ThinkAction:
            msg = self.rc.memory.get(k=1)[0]
            self.goal = msg.content
            resp = await todo.run(instruction=self.goal)
            # logger.info(resp)

            return await self._prepare_print(resp)

        resp = await todo.run()
        # logger.info(resp)

        return Message(content=resp, role=self.profile)

    async def _react(self) -> Message:
        """"""
        while True:
            await self._think()

            if self.rc.todo is None:
                break
            msg = await self._act()

        return msg


async def main():
    msg = "Provide the first 10 numbers of the Fibonacci series"
    role = Printer()
    logger.info(msg)
    result = await role.run(msg)
    logger.info(result)


asyncio.run(main())


输出:

(metagpt) D:\llm\MetaGPT> d: && cd d:\llm\MetaGPT && cmd /C "d:\soft\anaconda\envs\metagpt\python.exe c:\Users\32564\.vscode\extensions\ms-python.debugpy-2024.14.0-win32-x64\bundled\libs\debugpy\adapter/../..\debugpy\launcher 55967 -- D:\llm\MetaGPT\notebook\TEST12.PY "
2024-12-17 17:44:27.438 | INFO     | metagpt.const:get_metagpt_package_root:21 - Package root set to d:\llm\metagpt
2024-12-17 17:44:33.566 | INFO     | __main__:main:224 - Provide the first 10 numbers of the Fibonacci series
thinkaction:
            You are now a number list generator, follow the instruction Provide the first 10 numbers of the Fibonacci series and
            generate a number list to be printed please.

actionnode:
            You are now a number list generator, follow the instruction Provide the first 10 numbers of the Fibonacci series and
            generate a number list to be printed please.


## Actions
Language: Please use the same language as Human INPUT.

            Think about what list of numbers you need to generate

The Fibonacci series is a sequence of numbers where each number is the sum of the two preceding ones, usually starting with 0 and 1. The first 10 numbers of the Fibonacci series are:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34

Here is the number list generated:

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
2024-12-17 17:44:38.394 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model GLM-4-flash not found in TOKEN_COSTS.
actionnode:The Fibonacci series is a sequence of numbers where each number is the sum of the two preceding ones, usually starting with 0 and 1. The first 10 numbers of the Fibonacci series are:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34

Here is the number list generated:

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

## Actions
Language: Please use the same language as Human INPUT.

            Please provide the number list for me, strictly following the following requirements:
            1. Answer strictly in the list format like [1,2,3,4]
            2. Do not have extra spaces or line breaks.
            Return the list here:

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
2024-12-17 17:44:41.264 | WARNING  | metagpt.utils.cost_manager:update_cost:49 - Model GLM-4-flash not found in TOKEN_COSTS.
0

1

1

2

3

5

8

13

21

34

2024-12-17 17:44:41.314 | INFO     | __main__:main:226 - : 0

参考链接:

https://deepwisdom.feishu.cn/wiki/KhCcweQKmijXi6kDwnicM0qpnEf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2263311.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TCP套接字通信与守护进程

目录 TCP socket API 详解 代码实现TCP通讯 服务端 客户端 Task 守护进程 守护进程 前台与后台 Linux进程间关系 ​编辑 设置为独立会话setsid daemon接口 为什么需要设置umask 会话ID与组ID TCP的相关机制 下图是基于TCP协议的客户端/服务器程序的一般流程: 数…

单点登录平台Casdoor搭建与使用,集成gitlab同步创建删除账号

一&#xff0c;简介 一般来说&#xff0c;公司有很多系统使用&#xff0c;为了实现统一的用户名管理和登录所有系统&#xff08;如 GitLab、Harbor 等&#xff09;&#xff0c;并在员工离职时只需删除一个主账号即可实现权限清除&#xff0c;可以采用 单点登录 (SSO) 和 集中式…

OCR:文字识别

使用场景: 远程身份认证 自动识别录入用户身份/企业资质信息&#xff0c;应用于金融、政务、保险、电商、直播等场景&#xff0c;对用户、商家、主播进行实名身份认证&#xff0c;有效降低用户输入成本&#xff0c;控制业务风险 文档电子化 识别提取各类办公文档、合同文件、企…

亚信安全春节14天双倍假期通告

亚信安全14天双倍假期来袭 “网安福利王”再次实至名归 2024年 8773小时&#xff0c;31582680秒 亚信安全一直驰骋于云网安世界 奋战在“安全 数智化”的壮阔征途上 如今&#xff0c;新春的脚步渐近 长达14天的春节长假 能让我们暂且放下忙碌的工作 去除班味&#xff0c…

使用Python打开资源管理器并选择文件

from PySide6.QtWidgets import QFileDialogdef openSelectFile(Path):filename, _ QFileDialog.getOpenFileName(Path, "打开文件", "", "所有文件 (*)")if filename:print(f"选择的文件: {filename}")return filename 代码解释 &a…

uniapp blob格式转换为video .mp4文件使用ffmpeg工具

前言 介绍一下这三种对象使用场景 您前端一旦涉及到文件或图片上传Q到服务器&#xff0c;就势必离不了 Blob/File /base64 三种主流的类型它们之间 互转 也成了常态 Blob - FileBlob -Base64Base64 - BlobFile-Base64Base64 _ File uniapp 上传文件 现在已获取到了blob格式的…

五、windows上vscode构建c/c++环境

1、安装vscode 官网下载界面&#xff1a;https://code.visualstudio.com/Download 请根据电脑系统安装所需版本点击下载链接&#xff08;一般情况下点击windows按钮即可&#xff09;鼠标左键双击&#xff0c;即可运行安装程序&#xff0c;点击【确认】&#xff1b;选择安装路径…

ElasticSearch中的模糊搜索:为什么输入错误还能搜索出来?

引言 在日常搜索中&#xff0c;用户经常会因为拼写错误或输入笔误导致搜索结果不准确。然而&#xff0c;ElasticSearch 提供了一种非常智能的模糊搜索&#xff08;Fuzzy Search&#xff09;功能&#xff0c;使得即使关键词输入错误&#xff0c;依然能够返回准确或接近的结果。…

prober.php探针

raw.githubusercontent.com/kmvan/x-prober/master/dist/prober.php

DIY-ESP8266移动PM2.5传感器-带屏幕-APP

本教程将指导您制作一台专业级的空气质量检测仪。这个项目使用经济实惠的ESP8266和PMS5003传感器&#xff0c;配合OLED显示屏&#xff0c;不仅能实时显示PM2.5数值&#xff0c;还能通过手机APP随时查看数据。总成本70元&#xff0c;相比几百的用的便宜&#xff0c;用的心理踏实…

怎么将pdf中的某一个提取出来?介绍几种提取PDF中页面的方法

怎么将pdf中的某一个提取出来&#xff1f;传统上&#xff0c;我们可能通过手动截取屏幕或使用PDF阅读器的复制功能来提取信息&#xff0c;但这种方法往往不够精确&#xff0c;且无法保留原文档的排版和格式。此外&#xff0c;很多时候我们需要提取的内容可能涉及多个页面、多个…

2024微博用户消费趋势报告:七成城市用户更爱用微博

文 | 魏力 发布 | 大力财经 站在岁末回首这一年&#xff0c;在信息浪潮的汹涌翻涌之下&#xff0c;社交媒体平台犹如社会经济的晴雨表&#xff0c;精准地折射出大众生活与消费的万千景象。近日&#xff0c;大力财经看到一份报告&#xff0c;微博发布了《2024微博用户消费趋势…

#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍06-基于子查询的SQL注入(Subquery-Based SQL Injection)

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

【数据安全】如何保证其安全

数据安全风险 数字经济时代&#xff0c;数据已成为重要的生产要素。智慧城市、智慧政务的建设&#xff0c;正以数据为核心&#xff0c;推动城市管理的智能化和公共服务的优化。然而&#xff0c;公共数据开放共享与隐私保护之间的矛盾日益凸显&#xff0c;如何在确保数据安全的…

武汉市电子信息与通信工程职称公示了

2024年武汉市电子信息与通信工程专业职称公示了&#xff0c;本次公示通过人员有109人。 基本这已经是今年武汉市工程相关职称最后公示了&#xff0c;等待出证即可。 为什么有人好奇&#xff0c;一样的资料&#xff0c;都是业绩、论文等&#xff0c;有的人可以过&#xff0c;有的…

勤研低代码平台:高效数据集成助力企业数字化转型

在数字化转型的浪潮中&#xff0c;企业对高效开发工具的需求日益增长。勤研低代码平台强大的开发能力和灵活的数据集成方案&#xff0c;是企业提升效率、降低成本的理想选择。数据集成作为勤研低代码平台的核心功能之一&#xff0c;为企业提供了高效整合和利用数据的能力&#…

【毕业设计】A079-基于Java的影院订票系统的设计与实现

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看项目链接获取⬇️&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600个选题ex…

大腾智能受邀出席南京工业软件云工程应用创新中心工业软件生态应用推广大会并领奖

12月18日&#xff0c;南京工业软件云工程应用创新中心工业软件生态应用推广大会在南京江北新区圆满召开。本次大会由南京江北新区管委会主办&#xff0c;南京工业软件云工程应用创新中心、南京江北新区智能制造产业发展管理办公室联合承办&#xff0c;华为云计算技术有限公司支…

EasyPlayer.js播放器Web播放H.265要兼顾哪些方面?

在数字化时代&#xff0c;流媒体技术已经成为信息传播和娱乐消费的重要方式。随着互联网技术的飞速发展和移动设备的普及&#xff0c;流媒体服务正在重塑我们的生活和工作方式。从视频点播、在线直播到音乐流媒体&#xff0c;流媒体技术的广泛应用不仅改变了内容的分发和消费模…

fabric.js

目录 一、在canvas上画简单的图形 二、在canvas上用路径(Path)画不规则图形 三、在canvas上插入图片并设置旋转属性(angle) 四、让元素动起来(animate) 五、图像过滤器(filters)让图片多姿多彩 六、颜色模式(Color)和相互转换(toRgb、toHex) 七、对图形的渐变填充(Gradi…