代码地址:https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/actions/action_node.py
提供ActionNode类实现树形节点结构,支持复杂指令的分解与执行。作为MetaGPT动作系统的核心组件,它提供了声明式的节点定义方式和灵活的内容生成能力,是实现多智能体协作流程的基础构建块。
add_child()
、add_prev()
、add_next()
等方法构建节点间的父子关系和依赖关系_get_children_mapping()
实现树形结构的深度优先遍历from_children()
和from_pydantic()
工厂方法,支持从节点列表或Pydantic模型快速构建节点树check_missing_fields_validator
验证器,确保必填字段不缺失# 从Pydantic模型创建ActionNode
task_model = TaskModel(title=str, priority=int, assignee=str)
root_node = ActionNode.from_pydantic(task_model)
核心方法fill()
支持三种填充策略:
code_fill()
:从LLM输出中提取代码块xml_fill()
:解析XML格式输出并转换为指定类型single_fill()
:直接填充简单文本内容auto_review()
调用LLM分析内容与要求的匹配度human_review()
提供交互式人工反馈界面auto_revise()
根据审核意见自动修正内容,支持多轮迭代优化内置三类核心模板:
compile()
方法注入动态内容# 1. 创建节点树
root = ActionNode(key="project", expected_type=str, instruction="项目规划")
root.add_child(ActionNode(key="name", expected_type=str, instruction="项目名称", example="MetaGPT-Plugin"))
root.add_child(ActionNode(key="tasks", expected_type=list, instruction="任务列表", example=["需求分析", "架构设计"]))
# 2. 配置LLM和上下文
root.set_llm(OpenAILLM())
root.set_context("创建一个Markdown编辑器插件项目规划")
# 3. 填充内容
await root.fill(mode="complex")
# 4. 审核与修订
review_comments = await root.review(review_mode=ReviewMode.AUTO)
if review_comments:
await root.revise(revise_mode=ReviseMode.AUTO)
# 5. 获取结果
print(root.instruct_content.model_dump_json(indent=2))
方法名 | 功能描述 | 关键参数 |
---|---|---|
fill() |
填充节点内容 | mode : 填充模式; strgy : 填充策略 |
review() |
审核内容 | review_mode : 审核模式; strgy : 审核策略 |
revise() |
修订内容 | revise_mode : 修订模式; strgy : 修订策略 |
create_class() |
生成Pydantic模型 | mode : 模型生成模式 |
compile() |
编译提示模板 | template : 模板类型; schema : 输出格式 |
update_instruct_content() |
更新节点内容 | incre_data : 增量数据字典 |
from_pydantic() |
从Pydantic模型创建节点树 | model : Pydantic模型类 |
在需求分析阶段,ActionNode可用于结构化分解用户需求,自动生成产品需求文档(PRD):
# 创建PRD节点树
prd_root = ActionNode(key="prd", expected_type=str, instruction="产品需求文档")
prd_root.add_child(ActionNode(key="title", expected_type=str, instruction="文档标题", example="智能客服系统PRD"))
prd_root.add_child(ActionNode(key="features", expected_type=list, instruction="核心功能列表", example=[]))
prd_root.add_child(ActionNode(key="user_stories", expected_type=list, instruction="用户故事", example=[]))
# 填充内容
await prd_root.fill(mode="complex", schema="markdown")
# 导出为Markdown文档
with open("prd.md", "w") as f:
f.write(prd_root.instruct_content.content)
结合ActionGraph实现完整的代码生成-审查-修订流程:
# 创建代码生成节点
code_node = ActionNode(key="code", expected_type=str, instruction="生成Python函数")
code_node.add_child(ActionNode(key="function", expected_type=str, instruction="函数实现", example=""))
code_node.add_child(ActionNode(key="tests", expected_type=str, instruction="单元测试", example=""))
# 创建代码审查节点
review_node = ActionNode(key="review", expected_type=str, instruction="代码审查")
# 构建工作流
workflow = ActionGraph()
workflow.add_edge(code_node, review_node)
# 执行工作流
await workflow.run()
# 获取最终结果
print(review_node.instruct_content.model_dump())
ActionNode作为ActionGraph的基础节点单元,可构建复杂的有向无环图(DAG)工作流:
prevs
和nexts
属性定义节点间依赖关系exp_pool
实现工作流执行状态的持久化在多智能体协作中,ActionNode可作为角色能力的封装单元:
ActionNode支持调用外部工具扩展能力:
# 集成Web搜索工具
search_node = ActionNode(key="research", expected_type=str, instruction="技术调研")
search_node.add_child(ActionNode(key="query", expected_type=str, instruction="搜索关键词", example="LLM最新进展"))
search_node.add_child(ActionNode(key="results", expected_type=list, instruction="搜索结果摘要", example=[]))
# 填充时调用搜索工具
await search_node.fill(strgy="complex", tool=WebBrowserTool())
通过继承ActionNode并重写compile()
方法实现自定义模板:
class MyActionNode(ActionNode):
def compile(self, context, schema="json", mode="children"):
custom_template = """
## 自定义模板
{context}
### 特殊要求
输出必须包含详细的实现步骤
{instruction}
"""
return super().compile(context, schema, mode, template=custom_template)
exclude
参数过滤不需要处理的节点exp_cache
装饰器缓存重复计算结果complex
策略时设置合理的批处理大小问题 | 解决方案 |
---|---|
LLM输出格式不符合预期 | 使用xml_fill 模式并增加格式约束提示 |
节点树嵌套过深导致性能下降 | 拆分节点树为多个子树并行处理 |
复杂类型解析失败 | 自定义Pydantic模型验证器 |
审核修订循环次数过多 | 设置最大修订次数阈值 |
ActionNode提供了完善的可测试性支持,推荐使用pytest进行单元测试:
import pytest
from metagpt.actions.action_node import ActionNode
from metagpt.llm import MockLLM
@pytest.mark.asyncio
async def test_action_node_fill():
# 创建测试节点
node = ActionNode(key="test", expected_type=str, instruction="返回'hello'")
node.set_llm(MockLLM(return_value="[CONTENT]hello[/CONTENT]"))
node.set_context("测试上下文")
# 执行填充
await node.fill(mode="simple")
# 验证结果
assert node.instruct_content.test == "hello"
logger.setLevel(logging.DEBUG)
查看详细执行日志node.content
查看LLM原始输出node.instruct_content.model_validate()
验证数据完整性print(node.to_dict())
打印节点结构对于包含大量子节点的场景,采用批量处理提升效率:
# 批量创建节点
nodes = [
ActionNode(key=f"item_{i}", expected_type=str, instruction=f"生成第{i}项")
for i in range(100)
]
root = ActionNode.from_children(key="batch", nodes=nodes)
# 批量填充(仅调用一次LLM)
await root.fill(mode="simple", batch_size=20)
利用exp_pool
模块缓存重复计算结果:
from metagpt.exp_pool import exp_cache
@exp_cache()
async def create_cached_node(context):
node = ActionNode(key="cached", expected_type=str, instruction="生成报告")
node.set_context(context)
await node.fill()
return node
节点数量 | simple策略 | complex策略 | 批量处理(simple+batch) |
---|---|---|---|
10个节点 | 0.8秒 | 3.2秒 | 0.9秒 |
50个节点 | 1.2秒 | 15.6秒 | 1.5秒 |
100个节点 | 1.8秒 | 31.2秒 | 2.1秒 |
属性名 | 类型 | 描述 |
---|---|---|
key |
str | 节点唯一标识 |
expected_type |
Type | 预期输出类型 |
instruction |
str | 节点生成指令 |
example |
Any | 示例值 |
children |
dict[str, ActionNode] | 子节点字典 |
prevs /nexts |
list[ActionNode] | 前置/后置节点 |
content |
str | LLM原始输出 |
instruct_content |
BaseModel | 解析后的结构化内容 |
ActionNode支持通过事件钩子扩展功能:
class HookedActionNode(ActionNode):
async def on_before_fill(self):
logger.info(f"开始填充节点: {self.key}")
self.start_time = time.time()
async def on_after_fill(self):
duration = time.time() - self.start_time
logger.info(f"节点填充完成: {self.key}, 耗时{duration:.2f}秒")