声明式 vs 命令式:两种开发范式
MASFactory 支持两种开发范式:
- 声明式(Declarative):在创建
RootGraph/Graph/Loop时一次性声明拓扑结构;在build()阶段框架会根据这些声明装配出节点与边并完成一致性检查。 - 命令式(Imperative):先创建
Graph/RootGraph/Loop对象,然后逐条调用create_node()/create_edge()把节点和边添加到图上;这种写法很像给 Graph 下达一系列构建命令,因此称为“命令式”。
选择建议
- 如果你要搭建的工作流是静态的,使用声明式更加直观便捷。
- 如果你要搭建的工作流会依据超参数运行时决定部分结构,使用命令式功能更加强大。
1) 同一个工作流的两种写法
让我们回到 第一行代码 中的例子,我们使用两种开发方式实现它:
以下两段代码在运行时行为上等价,差别主要体现在“构图阶段”的组织方式与表达形式。
entry -> analyze -> answer -> exit
声明式
python
from masfactory import RootGraph, Agent, OpenAIModel, NodeTemplate
# 1) 创建模型配置(建议在真实项目中从环境变量/配置文件读取)
model = OpenAIModel(
api_key="YOUR_API_KEY",
base_url="YOUR_API_URL",
model_name="gpt-4o-mini",
)
# 2) 声明一个可复用的节点模板(用于批量创建同构 Agent 节点)
BaseAgent = NodeTemplate(Agent, model=model)
# 3) 声明式构图:在初始化阶段一次性声明 nodes / edges;build() 时由框架装配结构并做一致性校验
g = RootGraph(
name="qa_two_stage_decl",
nodes=[
# 复用模板:仅覆盖 instructions / prompt_template 等少量差异参数
("analyze", BaseAgent(instructions="你是问题分析专家。", prompt_template="用户问题:{query}")),
# 单节点内联模板:适用于一次性节点(不需要单独抽出 BaseAgent)
(
"answer",
NodeTemplate(
Agent,
model=model,
instructions="你是解决方案专家,基于分析给出最终回答。",
prompt_template="问题:{query}\n分析:{analysis}",
),
),
],
edges=[
("entry", "analyze", {"query": "用户问题"}),
("analyze", "answer", {"query": "原始问题", "analysis": "分析结果"}),
("answer", "exit", {"answer": "最终回答"}),
],
)
g.build()
out, _attrs = g.invoke({"query": "我想学习 Python,但不知道从哪里开始"})
print(out["answer"])命令式
python
from masfactory import RootGraph, Agent, OpenAIModel, NodeTemplate
# 1) 创建模型配置
model = OpenAIModel(
api_key="YOUR_API_KEY",
base_url="YOUR_BASE_URL", # OpenAI 官方可填 "https://api.openai.com/v1"
model_name="gpt-4o-mini",
)
# 2) 命令式构图:先创建图对象,再逐条创建节点与边
g = RootGraph(name="qa_two_stage_imp")
BaseAgent = NodeTemplate(Agent, model=model) # 命令式里也可以用 NodeTemplate 复用配置
# 逐条创建节点(create_node)
analyze = g.create_node(BaseAgent, name="analyze", instructions="你是问题分析专家。", prompt_template="用户问题:{query}")
answer = g.create_node(
Agent, # 不使用 NodeTemplate 的写法
name="answer",
instructions="你是解决方案专家,基于分析给出最终回答。",
model=model,
prompt_template="问题:{query}\n分析:{analysis}",
)
# 逐条创建边(edge_from_entry / create_edge / edge_to_exit)
g.edge_from_entry(analyze, {"query": "用户问题"})
g.create_edge(analyze, answer, {"query": "原始问题", "analysis": "分析结果"})
g.edge_to_exit(answer, {"answer": "最终回答"})
g.build()
out, _attrs = g.invoke({"query": "我想学习 Python,但不知道从哪里开始"})
print(out["answer"])2) 进阶:什么时候选哪种?怎么写更稳?
本页仅提供入门级对照示例。更系统的取舍原则、最佳实践与常见问题请参见: