引言

在前面的文章中,我们分别探讨了AI Agent的响应生成(第33篇)、对话管理(第34篇)、工具调用(第35篇)和记忆系统(第36篇)。如果说记忆系统解决了AI Agent"记什么"的问题,工具调用解决了"怎么做"的问题,对话管理解决了"怎么说"的问题,响应生成解决了"说什么"的问题,那么还有一个更核心的问题需要回答:在行动之前,Agent在想什么?

规划系统(Planning System)是AI Agent的"大脑皮层",它负责将用户的模糊意图转化为可执行的行动计划,处理复杂任务的分解与编排,并在执行过程中动态调整策略。本文将深入解析AI Agent规划系统的完整工程实践。

一、规划系统的定位与核心价值

规划系统是AI Agent四大核心子系统(感知、推理、执行、记忆)中推理层的具体实现。它的核心使命是:

  • 意图转译:将用户模糊的自然语言请求分解为可操作的步骤序列
  • 策略选择:在面对多种可能的执行路径时,选择最优方案
  • 资源编排:合理安排工具调用顺序,处理并行与串行的依赖关系
  • 异常恢复:当某一步失败时,动态重规划并选择替代方案

在现代基于LLM的AI Agent中,规划不再依赖预先定义的规则库,而是利用大语言的推理能力进行实时、灵活、上下文感知的决策。

二、规划系统的理论基础

AI Agent的规划系统虽以LLM为引擎,但其设计思想深受经典AI规划理论的影响:

规划范式核心思想在LLM Agent中的映射
STRIPS将行动表示为前提条件和效果的状态转移LLM理解工具的前置条件和输出
HTN层次化任务分解,将复杂任务递归拆解为原子操作Plan-and-Execute中的子任务拆分
PDDL用形式化语言描述规划问题结构化Prompt中的任务描述格式
MDP马尔可夫决策过程,状态-动作-奖励的序列优化ReAct中的行动-观察-奖励循环

经典规划算法强调精确的形式化建模和可证明的正确性;而基于LLM的规划则更强调灵活性、泛化能力和对开放域问题的适应能力。两者在工程实践中正走向融合。

三、基于LLM的规划范式:三大主流架构

3.1 CoT(Chain-of-Thought)规划

最基础的规划范式,通过在Prompt中引导模型"一步一步思考",让LLM自动生成推理链条。其形式如下:

用户请求:帮我订一张明天去上海的机票,价格不超过2000元
思考过程:
1. 首先需要确定出发城市、到达城市、出行日期
2. 然后调用航班搜索工具,传入参数
3. 查看搜索结果,筛选符合条件的航班
4. 询问用户确认选择
5. 调用订票工具完成预订
行动:询问用户出发城市

CoT规划实现简单,适合推理步骤少(不超过5步)、逻辑清晰的场景。其局限在于缺乏外部验证机制,推理链条一旦偏离方向难以自我纠正。

3.2 ReAct(Reasoning + Acting)规划

ReAct框架将推理与行动交替执行,每个思考步骤后紧跟一个行动,行动的观察结果反馈到下一步思考中:

Thought 1: 用户想知道北京的天气,我需要查询天气预报工具
Action: call_weather("北京")
Observation: 北京今日晴,最高温度28°C,最低温度15°C
Thought 2: 已获取到天气信息,其中温度信息完整但缺少空气质量
Action: call_air_quality("北京")
Observation: 北京空气质量指数AQI为85,良
Thought 3: 已有完整信息,可以回答用户了
Final Answer: 北京今天晴,温度15-28°C,空气质量良

ReAct的核心优势是观察闭环——每一步行动的真实结果都会修正后续推理,避免了"空想"。这使它成为构建可靠生产级Agent的首选范式。

3.3 Plan-and-Execute(规划后执行)

对于复杂任务(需要10+步骤),Plan-and-Execute采用两阶段策略:先制定完整计划,再逐步执行:

=== 规划阶段 ===
完整计划:
1. [调研] 搜索目标公司近3年的财务报告
2. [调研] 搜索同行业竞争对手数据
3. [分析] 对比营收增长率、利润率、市场份额
4. [分析] 评估技术护城河与团队背景
5. [生成] 输出结构化投资分析报告

=== 执行阶段 ===
Step 1 执行: 搜索目标公司财务报告
  --> 完成,获取3份年报数据
Step 2 执行: 搜索竞争对手数据
  --> 完成,获取5家竞对公司数据
Step 3 执行: 对比分析
  --> 完成,生成对比表格
Step 4 执行: 评估护城河(发现需要补充数据)
  --> 触发更新计划
Step 5 执行: 输出报告
  --> 完成

Plan-and-Execute的优势在于全局视野——Agent在行动前就对整体任务有清晰认识,执行过程中也可以根据实际情况动态调整计划。

四、分层规划架构设计

成熟的AI Agent通常采用三层规划架构,从宏观到微观逐层细化:

+-------------------------------------------------+
|              战略目标层(Strategic Level)         |
|  为用户完成年度税务申报准备                        |
|  输出:Goal Objectives(目标列表)                  |
+-------------------------------------------------+
|              战术计划层(Tactical Level)          |
|  收集收入凭证、整理抵扣项目、填写申报表、提交       |
|  输出:Task Graph(任务依赖图)                     |
+-------------------------------------------------+
|              原子执行层(Atomic Level)            |
|  打开PDF、提取字段、调用计算工具、写入表格         |
|  输出:Tool Calls(工具调用序列)                   |
+-------------------------------------------------+

这种分层架构的价值在于:

  • 关注点分离:每层只关心本层的决策逻辑,降低复杂度
  • 可中断恢复:在任意层暂停和恢复,系统状态清晰可管理
  • 渐进式执行:无需一次性生成所有步骤,降低Token消耗和认知负荷

五、动态重规划与异常处理

在实际执行中,规划不可能一成不变。动态重规划机制使Agent能够应对以下异常场景:

5.1 工具调用失败

场景:搜索API返回500错误
原始计划:搜索数据、分析、输出
重规划策略:重试 --> 降级到备用工具 --> 告知用户并提供替代方案

5.2 中间结果不满足预期

场景:搜索结果返回空数据
重规划策略:换关键词重搜索 --> 扩大搜索范围 --> 查询本地记忆缓存

5.3 用户需求变更

执行过程中用户修改了原始需求,Agent应暂停当前执行,评估变更影响,增量调整计划(而非从头开始),然后继续执行。

5.4 重规划的原则

  • 最小改动原则:尽量保持已完成步骤的成果,只调整受影响的后继步骤
  • 时效约束:重规划本身不能无限循环(设置最大重规划次数为3次)
  • 降级优雅:当完美方案不可达时,提供局部最优解而非直接放弃

六、任务依赖图与执行状态机

复杂任务中各步骤间存在依赖关系,需要以有向无环图(DAG)建模:

TaskGraph:
  A(收集需求) --> B(创建项目) --> C(分配资源)
                                       |
  D(开发模块) --> E(集成测试) --> F(部署上线)
       ^                   |
  G(代码审查) <------------+
  (E完成后G依赖于测试结果)

基于DAG可以自动识别可并行执行的任务,提升执行效率。执行状态机为每个任务维护状态:PENDING(未开始)、READY(依赖已满足可执行)、RUNNING(执行中)、COMPLETED(成功)、FAILED(失败触发重规划)、SKIPPED(条件不符跳过)。

七、规划质量评估与安全性

7.1 可行性评估

在计划执行前,对每项操作进行评估:工具是否可用?参数是否满足前置条件?权限是否充分?预估耗时和Token消耗是否在预算内?

7.2 复杂度评估

根据任务图的节点数、深度、分支因子估算整体复杂度。超出预设阈值的任务需要拆分为多个子任务分批执行,避免上下文窗口溢出。

7.3 安全性审查

规划系统必须内置安全检查层:是否涉及不可逆操作(删除/转账/发邮件)?是否在用户授权范围内?是否可能产生副作用?这些检查确保Agent不会执行危险或超出权限的操作。

八、与记忆系统的协同

规划系统与记忆系统深度耦合:

  • 历史规划复用:相似任务过往的执行方案可作为当前规划的参考起点
  • 用户偏好的应用:从记忆中提取用户偏好(如用户偏好简洁输出),指导规划风格选择
  • 执行经验积累:本次规划的成功/失败经验写入记忆,优化未来的规划策略
  • 上下文保持:在多轮对话中,规划进度和中间结果通过记忆实现无缝衔接

这种协同使得记忆不再是被动的信息存储,而是主动驱动规划质量持续提升的核心资源。第36篇中建立的记忆系统为本文的规划能力提供了坚实的数据基础。

九、完整代码实现:Planner核心类

import uuid
from enum import Enum
from typing import List, Dict, Any, Optional
from dataclasses import dataclass, field

class TaskStatus(Enum):
    PENDING = "pending"
    READY = "ready"
    RUNNING = "running"
    COMPLETED = "completed"
    FAILED = "failed"
    SKIPPED = "skipped"

class PlanningMode(Enum):
    COT = "cot"
    REACT = "react"
    PLAN_EXECUTE = "plan_execute"

@dataclass
class Task:
    id: str = field(default_factory=lambda: str(uuid.uuid4())[:8])
    name: str = ""
    description: str = ""
    tool: Optional[str] = None
    params: Dict[str, Any] = field(default_factory=dict)
    dependencies: List[str] = field(default_factory=list)
    status: TaskStatus = TaskStatus.PENDING
    result: Any = None
    retry_count: int = 0
    max_retries: int = 3

@dataclass
class Plan:
    goal: str
    tasks: Dict[str, Task] = field(default_factory=dict)
    mode: PlanningMode = PlanningMode.REACT
    context: Dict[str, Any] = field(default_factory=dict)
    
    def add_task(self, task: Task) -> str:
        self.tasks[task.id] = task
        return task.id
    
    def get_ready_tasks(self) -> List[Task]:
        ready = []
        for task in self.tasks.values():
            if task.status != TaskStatus.PENDING:
                continue
            deps_met = all(
                self.tasks[dep_id].status == TaskStatus.COMPLETED
                for dep_id in task.dependencies
                if dep_id in self.tasks
            )
            if deps_met:
                task.status = TaskStatus.READY
                ready.append(task)
        return ready
    
    def is_complete(self) -> bool:
        return all(
            t.status in (TaskStatus.COMPLETED, TaskStatus.SKIPPED)
            for t in self.tasks.values()
        )

class Planner:
    """AI Agent规划系统核心"""
    
    def __init__(self, llm_client, tool_registry, memory_store=None):
        self.llm = llm_client
        self.tools = tool_registry
        self.memory = memory_store
        self.max_replan_attempts = 3
    
    async def create_plan(self, user_goal: str, mode: PlanningMode = PlanningMode.REACT) -> Plan:
        """根据用户目标生成任务计划"""
        plan = Plan(goal=user_goal, mode=mode)
        
        if mode == PlanningMode.COT:
            await self._plan_cot(plan)
        elif mode == PlanningMode.REACT:
            await self._plan_react(plan)
        else:
            await self._plan_and_execute(plan)
        
        return plan
    
    async def _plan_react(self, plan: Plan):
        """ReAct模式:交替进行推理和行动"""
        context = {"goal": plan.goal, "steps_completed": [], "observations": []}
        
        for turn in range(20):
            thought = await self.llm.think(goal=plan.goal, context=context)
            
            if thought.should_respond_to_user:
                break
            
            action = await self.llm.select_action(
                thought=thought,
                available_tools=self.tools.list()
            )
            
            task = Task(
                name=action.tool_name,
                description=thought.reasoning,
                tool=action.tool_name,
                params=action.parameters
            )
            plan.add_task(task)
            
            observation = await self._execute_task(task, plan)
            context["observations"].append(observation)
            
            if observation.get("status") == "failed":
                await self._replan(plan, context, task)
    
    async def _execute_task(self, task: Task, plan: Plan) -> Dict:
        """执行单个任务"""
        task.status = TaskStatus.RUNNING
        try:
            tool = self.tools.get(task.tool)
            result = await tool.execute(**task.params)
            task.result = result
            task.status = TaskStatus.COMPLETED
            return {"status": "success", "result": result}
        except Exception as e:
            task.status = TaskStatus.FAILED
            task.retry_count += 1
            return {"status": "failed", "error": str(e)}
    
    async def _replan(self, plan: Plan, context: Dict, failed_task: Task):
        """动态重规划"""
        if failed_task.retry_count >= failed_task.max_retries:
            alt_task = await self._find_alternative(plan, failed_task)
            if alt_task:
                plan.add_task(alt_task)
            else:
                failed_task.status = TaskStatus.SKIPPED
        else:
            failed_task.status = TaskStatus.PENDING
    
    async def execute_plan(self, plan: Plan) -> Dict[str, Any]:
        """执行完整计划"""
        results = {}
        while not plan.is_complete():
            ready_tasks = plan.get_ready_tasks()
            if not ready_tasks:
                await self._resolve_deadlock(plan)
                continue
            for task in ready_tasks:
                result = await self._execute_task(task, plan)
                results[task.id] = result
        return results

这段代码展示了一个完整的Planner实现,涵盖了三种规划模式、任务依赖管理、动态重规划和异常恢复机制,可以作为构建生产级AI Agent规划层的基础框架。

十、总结与方向展望

规划系统是AI Agent从"应答器"走向"执行者"的关键能力。本文完整覆盖了从理论基础到工程实现的全链路:

  • CoT、ReAct、Plan-and-Execute三大主流规划范式的原理与适用场景
  • 三层分层规划架构:战略目标、战术计划、原子执行
  • 动态重规划机制:工具失败、结果不符、需求变更的应对策略
  • 任务依赖图与执行状态机的工程建模
  • 规划质量评估与安全性审查
  • 规划系统与记忆系统的深度协同
  • 完整的Planner核心类代码实现

至此,我们完成了AI Agent核心子系统的完整闭环:响应生成(说)、对话管理(沟通)、记忆系统(记)、规划系统(想)、工具调用(做)。它们共同构成了现代AI Agent的完整认知链条。

在后续文章中,我们将探讨AI Agent的安全与治理体系、多Agent协作架构、以及RAG增强下的知识工程实践,进一步拓展智能体的能力边界。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部