智能体核心技术七大模块之(二)
任务规划与分解——将目标转化为可执行步骤
本文是七大模块的第二部分,深入探讨智能体的任务规划与分解模块。该模块负责将用户的高层目标(意图)拆解为一系列有序、可执行的子任务或步骤,为后续的推理和执行提供蓝图。我们将通过UML建模、详细设计和完整代码实现,增强智能体的规划能力,支持静态模板规划和基于LLM的动态规划。
1. 核心概念
1.1 什么是任务规划
任务规划是将一个复杂目标分解为一系列更小、更易管理的子目标或动作序列的过程。在智能体中,规划模块接收来自感知模块的目标(如ParsedInput),结合可用工具和当前状态,输出一个计划(Plan)。
1.2 规划的重要性
- 结构化执行:将无序的意图转化为有序步骤,避免盲目尝试。
- 资源优化:提前识别所需工具和依赖关系。
- 错误恢复:当某一步失败时,可基于计划调整后续步骤。
- 可解释性:计划本身可向用户展示智能体的思考路径。
1.3 规划的类型
- 静态规划:基于预定义模板,适用于固定流程的任务(如发送邮件)。
- 动态规划:利用LLM生成计划,适用于开放、多变的任务(如“帮我规划一次北京三日游”)。
- 混合规划:结合两者,先静态后动态,或反之。
2. 系统架构设计
2.1 新增核心类
在原有架构基础上,我们引入以下关键类:
- Plan:表示一个完整的计划,包含多个步骤。
- Step:表示计划中的一个原子步骤,可对应一个工具调用或子计划。
- Planner:规划器的抽象基类,定义create_plan接口。
- TemplatePlanner:基于模板的规划器实现。
- LLMPlanner:基于LLM的规划器实现。
2.2 类图
#mermaid-svg-agImkMzxquAD0ZSC{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-agImkMzxquAD0ZSC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-agImkMzxquAD0ZSC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-agImkMzxquAD0ZSC .error-icon{fill:#552222;}#mermaid-svg-agImkMzxquAD0ZSC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-agImkMzxquAD0ZSC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-agImkMzxquAD0ZSC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-agImkMzxquAD0ZSC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-agImkMzxquAD0ZSC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-agImkMzxquAD0ZSC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-agImkMzxquAD0ZSC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-agImkMzxquAD0ZSC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-agImkMzxquAD0ZSC .marker.cross{stroke:#333333;}#mermaid-svg-agImkMzxquAD0ZSC svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-agImkMzxquAD0ZSC p{margin:0;}#mermaid-svg-agImkMzxquAD0ZSC g.classGroup text{fill:#9370DB;stroke:none;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-agImkMzxquAD0ZSC g.classGroup text .title{font-weight:bolder;}#mermaid-svg-agImkMzxquAD0ZSC .nodeLabel,#mermaid-svg-agImkMzxquAD0ZSC .edgeLabel{color:#131300;}#mermaid-svg-agImkMzxquAD0ZSC .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-agImkMzxquAD0ZSC .label text{fill:#131300;}#mermaid-svg-agImkMzxquAD0ZSC .labelBkg{background:#ECECFF;}#mermaid-svg-agImkMzxquAD0ZSC .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-agImkMzxquAD0ZSC .classTitle{font-weight:bolder;}#mermaid-svg-agImkMzxquAD0ZSC .node rect,#mermaid-svg-agImkMzxquAD0ZSC .node circle,#mermaid-svg-agImkMzxquAD0ZSC .node ellipse,#mermaid-svg-agImkMzxquAD0ZSC .node polygon,#mermaid-svg-agImkMzxquAD0ZSC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-agImkMzxquAD0ZSC .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-agImkMzxquAD0ZSC g.clickable{cursor:pointer;}#mermaid-svg-agImkMzxquAD0ZSC g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-agImkMzxquAD0ZSC g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-agImkMzxquAD0ZSC .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-agImkMzxquAD0ZSC .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-agImkMzxquAD0ZSC .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-agImkMzxquAD0ZSC .dashed-line{stroke-dasharray:3;}#mermaid-svg-agImkMzxquAD0ZSC .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-agImkMzxquAD0ZSC #compositionStart,#mermaid-svg-agImkMzxquAD0ZSC .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-agImkMzxquAD0ZSC #compositionEnd,#mermaid-svg-agImkMzxquAD0ZSC .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-agImkMzxquAD0ZSC #dependencyStart,#mermaid-svg-agImkMzxquAD0ZSC .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-agImkMzxquAD0ZSC #dependencyStart,#mermaid-svg-agImkMzxquAD0ZSC .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-agImkMzxquAD0ZSC #extensionStart,#mermaid-svg-agImkMzxquAD0ZSC .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-agImkMzxquAD0ZSC #extensionEnd,#mermaid-svg-agImkMzxquAD0ZSC .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-agImkMzxquAD0ZSC #aggregationStart,#mermaid-svg-agImkMzxquAD0ZSC .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-agImkMzxquAD0ZSC #aggregationEnd,#mermaid-svg-agImkMzxquAD0ZSC .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-agImkMzxquAD0ZSC #lollipopStart,#mermaid-svg-agImkMzxquAD0ZSC .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-agImkMzxquAD0ZSC #lollipopEnd,#mermaid-svg-agImkMzxquAD0ZSC .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-agImkMzxquAD0ZSC .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-agImkMzxquAD0ZSC .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-agImkMzxquAD0ZSC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-agImkMzxquAD0ZSC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-agImkMzxquAD0ZSC :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
Agent
-perception: Perception
-planner: Planner
-reasoning: Reasoning
-executor: Executor
-state: State
-tools: dict
+register_tool(tool)
+run(user_input) : -> str
«abstract»
Planner
+create_plan(goal: ParsedInput, tools: dict, state: State) : -> Plan
TemplatePlanner
-templates: dict
+create_plan(goal, tools, state) : -> Plan
LLMPlanner
-llm: BaseLLM
+create_plan(goal, tools, state) : -> Plan
Plan
-steps: List[Step]
-metadata: dict
+add_step(step)
+get_next_incomplete() : -> Step
+is_complete() : -> bool
Step
-id: str
-type: str # 'tool_call' or 'subplan'
-tool_name: str # if tool_call
-status: str # 'pending', 'in_progress', 'completed', 'failed'
-result: any
-parameters: dict # expected parameters(can be unfilled)
+execute(executor, context) : -> result
State
-memory: Memory
-current_plan: Plan
-intermediate_results: dict
+update_after_step(step, result)
+get_context() : -> str
2.3 规划与执行时序图
以下是包含规划模块的完整任务处理流程:
渲染错误: Mermaid 渲染失败: Parse error on line 33:
… break else Action类型为思考
———————-^
Expecting 'SPACE', 'NEWLINE', 'create', 'box', 'end', 'autonumber', 'activate', 'deactivate', 'title', 'legacy_title', 'acc_title', 'acc_descr', 'acc_descr_multiline_value', 'loop', 'rect', 'opt', 'alt', 'par', 'par_over', 'critical', 'break', 'participant', 'participant_actor', 'destroy', 'note', 'links', 'link', 'properties', 'details', 'ACTOR', got 'else'
3. 详细设计
3.1 计划与步骤模型
Step 类设计:
- id: 唯一标识(如步骤索引)。
- type: 步骤类型,当前仅支持tool_call,未来可扩展为subplan(嵌套计划)。
- tool_name: 要调用的工具名称(如果type为tool_call)。
- parameters: 期望的参数,可能包含占位符(如${city}),在执行前需填充。
- status: pending, in_progress, completed, failed。
- result: 执行结果存储。
Plan 类设计:
- steps: 步骤列表。
- metadata: 额外信息(如创建时间、目标描述)。
- 方法:
- add_step(step)
- get_next_incomplete(): 返回第一个状态为pending的步骤。
- is_complete(): 检查所有步骤是否已完成。
- update_step_status(step_id, status, result)
3.2 规划器接口
class Planner(ABC):
@abstractmethod
def create_plan(self, goal: ParsedInput, tools: Dict[str, Tool], state: State) –> Plan:
"""根据目标生成计划"""
pass
- goal: 感知模块解析后的目标。
- tools: 当前注册的工具字典,规划器可以据此决定哪些步骤可行。
- state: 当前状态,可用于上下文(如用户偏好、历史任务)。
3.3 基于模板的规划器
TemplatePlanner 维护一个从意图到步骤模板的映射。模板可以是固定的步骤列表,也可以包含条件分支(简化起见,我们先实现固定列表)。
例如:
- 意图 send_email 对应的步骤模板:["get_email_by_name", "send_email"]
- 意图 query_weather 对应的步骤模板:["get_weather"]
- 意图 calculate 对应的步骤模板:["calculate"]
模板中的步骤名称需与工具名称对应。规划器会为每个步骤创建一个Step对象,初始状态为pending,并填充已知参数(从goal的slots中提取)。
3.4 基于LLM的规划器
LLMPlanner 利用大语言模型生成计划。它需要将目标、可用工具描述、可能的约束等信息构造成提示,并解析LLM返回的计划文本(通常为JSON格式)。
示例提示结构:
你是一个任务规划专家。请将用户的目标分解为一系列步骤。
可用工具:
– calculator: 计算数学表达式
– weather: 查询天气
– email: 发送邮件,需先获取收件人邮箱
用户目标:{goal描述}
请以JSON格式输出计划,格式如下:
{"steps": [{"tool": "工具名", "parameters": {"param1": "占位符或值"}}]}
只输出JSON。
LLM返回后,解析JSON并构建Plan。
3.5 状态模块的增强
State 类需要新增 current_plan 属性和相关方法:
- set_plan(plan: Plan)
- get_next_step() -> Optional[Step]
- update_step(step_id, status, result)
- get_plan_status() 用于生成上下文。
同时,get_context() 方法应包含计划进度信息,帮助推理模块做出决策。
4. 项目结构更新
在原有项目基础上,新增或修改以下文件:
agent_core/
├── agent/
│ ├── core/
│ │ ├── __init__.py
│ │ ├── agent.py # 修改:使用Planner,集成计划
│ │ ├── state.py # 修改:增加current_plan管理
│ │ ├── plan.py # 新增:Plan和Step类
│ │ ├── planner.py # 新增:Planner抽象基类
│ │ ├── models.py # 可能需更新(如ParsedInput保持不变)
│ │ └── … (其他不变)
│ ├── planners/ # 新增:规划器实现
│ │ ├── __init__.py
│ │ ├── template_planner.py
│ │ └── llm_planner.py
│ ├── nlu/… (不变)
│ ├── tools/… (不变)
│ ├── llm/… (不变)
│ └── utils/… (不变)
├── examples/
│ └── planner_demo.py # 新示例,展示规划模块
└── …
5. 源代码完整实现
下面提供增强后的核心模块代码,重点关注计划与规划模块的实现,并与之前的状态模块集成。
5.1 计划与步骤类 (agent/core/plan.py)
from typing import List, Dict, Any, Optional
from enum import Enum
class StepStatus(Enum):
PENDING = "pending"
IN_PROGRESS = "in_progress"
COMPLETED = "completed"
FAILED = "failed"
class Step:
"""计划中的一个步骤"""
def __init__(self, step_id: str, tool_name: str, parameters: Dict[str, Any] = None):
self.id = step_id
self.tool_name = tool_name
self.parameters = parameters or {}
self.status = StepStatus.PENDING
self.result: Optional[Any] = None
def to_dict(self) –> dict:
return {
"id": self.id,
"tool": self.tool_name,
"parameters": self.parameters,
"status": self.status.value,
"result": self.result
}
class Plan:
"""一个完整的计划,由多个步骤组成"""
def __init__(self, goal_description: str = ""):
self.goal_description = goal_description
self.steps: List[Step] = []
self.metadata: Dict[str, Any] = {}
def add_step(self, step: Step):
self.steps.append(step)
def get_next_incomplete_step(self) –> Optional[Step]:
"""返回第一个未完成的步骤(pending状态)"""
for step in self.steps:
if step.status == StepStatus.PENDING:
return step
return None
def is_complete(self) –> bool:
return all(step.status == StepStatus.COMPLETED for step in self.steps)
def update_step_status(self, step_id: str, status: StepStatus, result: Any = None):
for step in self.steps:
if step.id == step_id:
step.status = status
if result is not None:
step.result = result
break
def to_dict(self) –> dict:
return {
"goal": self.goal_description,
"steps": [s.to_dict() for s in self.steps],
"metadata": self.metadata
}
5.2 规划器抽象基类 (agent/core/planner.py)
from abc import ABC, abstractmethod
from typing import Dict
from agent.core.models import ParsedInput
from agent.core.tool import Tool
from agent.core.state import State
from agent.core.plan import Plan
class Planner(ABC):
@abstractmethod
def create_plan(self, goal: ParsedInput, tools: Dict[str, Tool], state: State) –> Plan:
"""根据目标生成计划"""
pass
5.3 基于模板的规划器 (agent/planners/template_planner.py)
from typing import Dict
from agent.core.planner import Planner
from agent.core.models import ParsedInput
from agent.core.tool import Tool
from agent.core.state import State
from agent.core.plan import Plan, Step
class TemplatePlanner(Planner):
"""基于意图-模板映射的规划器"""
def __init__(self):
# 定义意图到步骤模板的映射
self.templates = {
"send_email": [
{"tool": "email", "params": {"action": "get_email", "name": "${to}"}},
{"tool": "email", "params": {"action": "send", "to": "${email}", "content": "${content}"}}
],
"query_weather": [
{"tool": "weather", "params": {"city": "${city}"}}
],
"calculate": [
{"tool": "calculator", "params": {"expression": "${expression}"}}
],
"chat": [] # 聊天无需工具
}
def create_plan(self, goal: ParsedInput, tools: Dict[str, Tool], state: State) –> Plan:
intent = goal.intent
slots = goal.slots
template = self.templates.get(intent, [])
plan = Plan(goal_description=goal.raw_text)
for i, step_def in enumerate(template):
tool_name = step_def["tool"]
# 参数模板填充:将 ${key} 替换为 slots 中的值
raw_params = step_def["params"]
filled_params = self._fill_parameters(raw_params, slots, state)
step = Step(step_id=f"step_{i}", tool_name=tool_name, parameters=filled_params)
plan.add_step(step)
return plan
def _fill_parameters(self, raw_params: dict, slots: dict, state: State) –> dict:
"""将参数模板中的占位符替换为实际值"""
filled = {}
for key, value in raw_params.items():
if isinstance(value, str) and value.startswith("${") and value.endswith("}"):
placeholder = value[2:–1]
# 优先从slots获取,其次从state的intermediate_results获取
if placeholder in slots:
filled[key] = slots[placeholder]
elif placeholder in state.intermediate_results:
filled[key] = state.intermediate_results[placeholder]
else:
filled[key] = None # 未找到,暂留空
else:
filled[key] = value
return filled
5.4 基于LLM的规划器 (agent/planners/llm_planner.py)
import json
from typing import Dict
from agent.core.planner import Planner
from agent.core.models import ParsedInput
from agent.core.tool import Tool
from agent.core.state import State
from agent.core.plan import Plan, Step
from agent.llm.base import BaseLLM
class LLMPlanner(Planner):
"""使用大语言模型生成计划的规划器"""
def __init__(self, llm: BaseLLM):
self.llm = llm
def create_plan(self, goal: ParsedInput, tools: Dict[str, Tool], state: State) –> Plan:
# 构建工具描述
tools_desc = "\\n".join([f"- {t.name}: {t.description}" for t in tools.values()])
# 从状态获取历史上下文(可选)
context = state.get_context()[:200] # 截断避免过长
prompt = f"""你是一个智能任务规划器。请将用户的目标分解为一系列步骤,每个步骤调用一个可用工具。
可用工具:
{tools_desc}
当前上下文(可能包含历史信息):
{context}
用户目标:{goal.raw_text}
意图:{goal.intent}
参数:{goal.slots}
请以JSON格式输出计划,格式如下:
{{"steps": [{{"tool": "工具名", "parameters": {{"参数名": "参数值或占位符"}}}}]}}
要求:
– 步骤顺序应合理。
– 如果某参数需要从之前步骤的结果获取,用占位符表示,如 "${{step_result}}"。
– 只输出JSON,不要其他文字。
"""
response = self.llm.generate(prompt).strip()
try:
data = json.loads(response)
steps_data = data.get("steps", [])
except json.JSONDecodeError:
# 解析失败,返回空计划
steps_data = []
plan = Plan(goal_description=goal.raw_text)
for i, step_data in enumerate(steps_data):
tool_name = step_data.get("tool")
params = step_data.get("parameters", {})
if tool_name and tool_name in tools:
step = Step(step_id=f"step_{i}", tool_name=tool_name, parameters=params)
plan.add_step(step)
return plan
5.5 状态模块增强 (agent/core/state.py)
需要修改State类,添加对current_plan的支持。以下是完整的新版state.py:
from typing import List, Dict, Any, Optional
from .memory import Memory
from .models import Message
from .plan import Plan, Step, StepStatus
class State:
"""智能体内部状态"""
def __init__(self):
self.memory = Memory()
self.current_plan: Optional[Plan] = None
self.intermediate_results: Dict[str, Any] = {} # 步骤ID -> 结果
def add_user_message(self, content: str):
self.memory.add_message(Message(role="user", content=content))
def add_assistant_message(self, content: str):
self.memory.add_message(Message(role="assistant", content=content))
def add_system_message(self, content: str):
self.memory.add_message(Message(role="system", content=content))
def add_tool_message(self, tool_name: str, result: str):
self.memory.add_message(Message(role="tool", content=f"{tool_name}: {result}"))
def set_plan(self, plan: Plan):
self.current_plan = plan
# 重置中间结果(可选)
self.intermediate_results = {}
def get_next_step(self) –> Optional[Step]:
"""获取下一个待执行的步骤"""
if self.current_plan:
return self.current_plan.get_next_incomplete_step()
return None
def update_step(self, step_id: str, status: StepStatus, result: Any = None):
"""更新步骤状态,并记录结果"""
if self.current_plan:
self.current_plan.update_step_status(step_id, status, result)
if result is not None:
self.intermediate_results[step_id] = result
# 如果步骤完成,可能需要将结果注入后续步骤的参数占位符(可选)
def get_context(self) –> str:
"""生成供推理模块使用的上下文文本"""
recent_msgs = self.memory.get_context()[–5:]
history = "\\n".join([f"{m.role}: {m.content}" for m in recent_msgs])
plan_status = ""
if self.current_plan:
plan_status = f"当前计划: {[s.to_dict() for s in self.current_plan.steps]}\\n"
next_step = self.get_next_step()
plan_status += f"下一步: {next_step.to_dict() if next_step else '无'}"
intermediates = f"中间结果: {self.intermediate_results}"
return f"{history}\\n\\n{plan_status}\\n{intermediates}"
def get_short_term_memory(self) –> List[Message]:
return self.memory.short_term
5.6 主控制器 Agent 修改 (agent/core/agent.py)
需要集成规划器,并在run方法中生成计划。以下是修改后的agent.py:
from typing import Dict, Optional
from .perception import Perception
from .planner import Planner
from .reasoning import Reasoning
from .executor import Executor
from .state import State
from .reflector import Reflector
from .models import Action, Message
from .plan import StepStatus
from agent.core.tool import Tool
from agent.nlu.base import NLUEngine
class Agent:
def __init__(self, nlu_engine: NLUEngine, planner: Planner, llm):
self.perception = Perception(nlu_engine)
self.planner = planner
self.reasoning = Reasoning(llm)
self.executor = Executor()
self.state = State()
self.reflector = Reflector()
self.tools: Dict[str, Tool] = {}
self.max_iterations = 20
def register_tool(self, tool: Tool):
self.tools[tool.name] = tool
def run(self, user_input: str) –> str:
# 1. 感知
parsed = self.perception.parse(user_input)
self.state.add_user_message(user_input)
# 2. 规划:生成计划
plan = self.planner.create_plan(parsed, self.tools, self.state)
self.state.set_plan(plan)
if plan.steps:
self.state.add_system_message(f"生成计划: {[s.tool_name for s in plan.steps]}")
# 3. ReAct循环 + 计划执行
iteration = 0
final_answer = None
while iteration < self.max_iterations:
iteration += 1
# 获取下一个待办步骤(如果有)
current_step = self.state.get_next_step()
step_info = f"当前步骤: {current_step.to_dict() if current_step else '无'}"
context = self.state.get_context() + "\\n" + step_info
action = self.reasoning.decide(context, self.state.get_short_term_memory(), self.tools)
if action.type == 'final':
final_answer = action.content
self.state.add_assistant_message(final_answer)
break
elif action.type == 'tool':
# 执行工具
obs = self.executor.execute(action, self.tools)
# 更新状态:如果当前有步骤且工具名匹配,则标记该步骤完成
if current_step and current_step.tool_name == action.tool:
if not obs.error:
self.state.update_step(current_step.id, StepStatus.COMPLETED, obs.result)
else:
self.state.update_step(current_step.id, StepStatus.FAILED, obs.error)
else:
# 可能是推理模块自主调用的工具,未在计划中,我们仍记录结果
self.state.add_tool_message(action.tool, obs.result if not obs.error else obs.error)
# 也可以将结果存入intermediate_results
self.state.intermediate_results[f"unplanned_{action.tool}"] = obs.result
else:
if action.content:
self.state.add_assistant_message(f"思考: {action.content}")
# 检查计划是否完成
if self.state.current_plan and self.state.current_plan.is_complete():
# 计划完成,但可能还需生成最终答案
if not final_answer:
# 可以尝试让推理模块生成总结
continue
if not final_answer:
final_answer = "抱歉,无法完成您的请求。"
# 4. 反思(略)
return final_answer
注意:以上代码假设Reasoning.decide方法返回的Action中tool名称与计划中的步骤名称一致。在实际中可能需要更复杂的映射。
5.7 示例运行 (examples/planner_demo.py)
创建一个新示例,使用模板规划器和模拟LLM,展示规划与执行。
import sys
sys.path.append("..")
from agent.core.agent import Agent
from agent.nlu.rule_based import RuleBasedNLU
from agent.planners.template_planner import TemplatePlanner
from agent.llm.mock import MockLLM
from agent.tools.calculator import CalculatorTool
from agent.tools.weather import WeatherTool
from agent.tools.email import EmailTool
def main():
nlu = RuleBasedNLU()
planner = TemplatePlanner()
llm = MockLLM()
agent = Agent(nlu, planner, llm)
agent.register_tool(CalculatorTool())
agent.register_tool(WeatherTool())
agent.register_tool(EmailTool())
print("带有规划模块的智能体已启动")
while True:
user_input = input("\\n用户: ")
if user_input.lower() == 'quit':
break
response = agent.run(user_input)
print(f"助手: {response}")
if __name__ == "__main__":
main()
运行示例:
用户: 发送邮件给张三说下午开会
助手: 邮件已发送至 zhangsan@example.com,内容:下午开会
后台会打印计划生成和步骤执行信息(如果设置verbose)。
如果想尝试LLM规划器,只需将planner = TemplatePlanner()替换为planner = LLMPlanner(llm),但需要注意模拟LLM可能无法返回有效JSON,建议使用真实LLM(如OpenAI)。
6. 总结与扩展
通过本文,我们为智能体添加了强大的任务规划与分解能力:
- 设计了通用的Plan和Step模型,支持步骤状态跟踪。
- 实现了基于模板的规划器,适用于固定流程任务。
- 提供了基于LLM的规划器接口,可扩展用于复杂开放域任务。
- 与状态模块深度集成,使计划成为智能体内部模型的核心部分。
这些增强使得智能体能够将用户的高层目标转化为结构化的执行蓝图,从而更高效、更可靠地完成任务。后续模块(如推理、执行)可以充分利用计划信息进行决策。
下一步,你可以考虑:
- 实现动态重规划:当某一步失败时,调用规划器重新生成剩余步骤。
- 支持嵌套计划:步骤可以是一个子计划,实现层次化规划。
- 集成记忆模块,将用户常见任务的计划存入长期记忆,实现个性化规划。
现在,你的智能体已经具备了初步的“规划”能力,向着真正的“执行专家”又迈进了一大步!
附录:项目文件清单(更新后)
agent_core/
├── agent/
│ ├── __init__.py
│ ├── core/
│ │ ├── __init__.py
│ │ ├── agent.py # 更新:使用planner
│ │ ├── perception.py # 不变
│ │ ├── state.py # 更新:支持计划
│ │ ├── memory.py # 不变
│ │ ├── models.py # 不变
│ │ ├── planner.py # 新增:规划器基类
│ │ ├── plan.py # 新增:计划与步骤类
│ │ ├── reasoning.py # 不变
│ │ ├── executor.py # 不变
│ │ ├── reflector.py # 不变
│ │ └── tool.py # 不变
│ ├── planners/ # 新增:规划器实现
│ │ ├── __init__.py
│ │ ├── template_planner.py
│ │ └── llm_planner.py
│ ├── nlu/… (不变)
│ ├── tools/… (不变)
│ ├── llm/… (不变)
│ └── utils/… (不变)
├── examples/
│ └── planner_demo.py # 新示例
└── …
现在,你可以基于此框架继续构建更复杂的智能体应用。




