AI Agent的规划系统:让Agent更智能地完成任务

在前面的文章中,我们已经讨论了 AI Agent 的记忆系统和工具调用体系。今天,我想分享一下如何实现规划系统,让 AI Agent 能够更智能地完成复杂任务。

从一个真实需求说起

还记得前段时间,我在开发一个代码重构助手时遇到的场景:

plaintext 复制代码
用户:帮我重构这个项目的日志系统,统一使用结构化日志,添加链路追踪。

助手:好的,我来帮你重构。首先修改 logger.py...
(开始修改代码)

用户:等等,你这样直接改可能会影响到其他模块,能不能先分析一下影响范围?

助手:抱歉,你说得对。让我重新规划一下...

这个场景让我意识到:AI Agent 需要像人类工程师一样,在执行任务前先做好规划。不能一上来就写代码,而是要:

  1. 分析需求和影响范围
  2. 制定详细的执行计划
  3. 按步骤有序地执行
  4. 及时处理意外情况

规划系统的设计

经过几轮迭代,我设计了一个相对完善的规划系统:

python 复制代码
from typing import List, Dict, Any
from enum import Enum
from datetime import datetime
from pydantic import BaseModel

class TaskStatus(Enum):
    PENDING = "pending"
    IN_PROGRESS = "in_progress"
    COMPLETED = "completed"
    FAILED = "failed"
    BLOCKED = "blocked"

class TaskStep(BaseModel):
    id: str
    description: str
    status: TaskStatus
    dependencies: List[str]
    estimated_time: float
    actual_time: float = 0
    result: Any = None
    error: str = None
    
class Task(BaseModel):
    id: str
    name: str
    description: str
    steps: List[TaskStep]
    context: Dict[str, Any]
    created_at: datetime
    updated_at: datetime
    status: TaskStatus

class PlanningSystem:
    def __init__(
        self,
        llm,
        tool_registry,
        memory_system
    ):
        self.llm = llm
        self.tool_registry = tool_registry
        self.memory_system = memory_system
        self.tasks: Dict[str, Task] = {}
        
    async def plan_task(
        self,
        description: str,
        context: Dict[str, Any] = None
    ) -> Task:
        # 1. 分析任务,生成步骤
        steps = await self._generate_steps(
            description,
            context
        )
        
        # 2. 创建任务
        task = Task(
            id=self._generate_id(),
            name=self._extract_name(description),
            description=description,
            steps=steps,
            context=context or {},
            created_at=datetime.now(),
            updated_at=datetime.now(),
            status=TaskStatus.PENDING
        )
        
        # 3. 存储任务
        self.tasks[task.id] = task
        
        return task
    
    async def execute_task(
        self,
        task_id: str
    ) -> Task:
        task = self.tasks[task_id]
        task.status = TaskStatus.IN_PROGRESS
        
        try:
            # 1. 获取可执行的步骤
            steps = self._get_executable_steps(task)
            
            # 2. 并行执行步骤
            results = await asyncio.gather(*[
                self._execute_step(task, step)
                for step in steps
            ])
            
            # 3. 更新任务状态
            task.updated_at = datetime.now()
            if all(r.status == TaskStatus.COMPLETED for r in results):
                task.status = TaskStatus.COMPLETED
            elif any(r.status == TaskStatus.FAILED for r in results):
                task.status = TaskStatus.FAILED
            
            return task
            
        except Exception as e:
            task.status = TaskStatus.FAILED
            raise
            
    async def _generate_steps(
        self,
        description: str,
        context: Dict[str, Any]
    ) -> List[TaskStep]:
        # 使用 LLM 分析任务,生成步骤
        response = await self.llm.plan(
            task=description,
            context=context,
            available_tools=self.tool_registry.list_tools()
        )
        
        # 解析响应,创建步骤
        steps = []
        for step in response.steps:
            steps.append(TaskStep(
                id=self._generate_id(),
                description=step.description,
                status=TaskStatus.PENDING,
                dependencies=step.dependencies,
                estimated_time=step.estimated_time
            ))
            
        return steps
    
    def _get_executable_steps(
        self,
        task: Task
    ) -> List[TaskStep]:
        # 找出所有依赖已完成的步骤
        executable = []
        for step in task.steps:
            if step.status != TaskStatus.PENDING:
                continue
                
            if all(
                self._get_step_by_id(task, dep).status == TaskStatus.COMPLETED
                for dep in step.dependencies
            ):
                executable.append(step)
                
        return executable
    
    async def _execute_step(
        self,
        task: Task,
        step: TaskStep
    ) -> TaskStep:
        start_time = datetime.now()
        
        try:
            # 1. 准备执行上下文
            context = self._prepare_context(task, step)
            
            # 2. 使用 LLM 决定使用哪些工具
            tools = await self.llm.select_tools(
                step=step,
                context=context,
                available_tools=self.tool_registry.list_tools()
            )
            
            # 3. 执行工具调用
            results = []
            for tool in tools:
                result = await self.tool_registry.get_tool(
                    tool.name
                ).execute(**tool.parameters)
                results.append(result)
                
            # 4. 更新步骤状态
            step.status = TaskStatus.COMPLETED
            step.result = results
            
        except Exception as e:
            step.status = TaskStatus.FAILED
            step.error = str(e)
            
        finally:
            step.actual_time = (
                datetime.now() - start_time
            ).total_seconds()
            
        return step
    
    def _prepare_context(
        self,
        task: Task,
        step: TaskStep
    ) -> Dict[str, Any]:
        # 合并任务上下文和前置步骤的结果
        context = task.context.copy()
        
        # 添加依赖步骤的结果
        for dep_id in step.dependencies:
            dep_step = self._get_step_by_id(task, dep_id)
            if dep_step.result:
                context[f"step_{dep_id}_result"] = dep_step.result
                
        return context

使用示例:

python 复制代码
# 初始化规划系统
planner = PlanningSystem(
    llm=ChatGPT(),
    tool_registry=tool_registry,
    memory_system=memory_system
)

# 创建任务计划
task = await planner.plan_task(
    description="""
    重构项目的日志系统:
    1. 统一使用结构化日志
    2. 添加链路追踪
    3. 确保向后兼容
    """,
    context={
        "project_root": "./src",
        "current_logger": "logging",
        "target_logger": "structlog"
    }
)

# 查看生成的步骤
for step in task.steps:
    print(f"步骤:{step.description}")
    print(f"依赖:{step.dependencies}")
    print(f"预计耗时:{step.estimated_time}分钟")
    print("---")

# 输出:
# 步骤:分析当前日志系统的使用情况
# 依赖:[]
# 预计耗时:15分钟
# ---
# 步骤:设计新的日志接口
# 依赖:['step_1']
# 预计耗时:30分钟
# ---
# 步骤:实现日志适配器
# 依赖:['step_2']
# 预计耗时:45分钟
# ---
# 步骤:修改日志配置
# 依赖:['step_3']
# 预计耗时:20分钟
# ---
# 步骤:更新依赖项
# 依赖:['step_4']
# 预计耗时:10分钟
# ---
# 步骤:添加单元测试
# 依赖:['step_3', 'step_4']
# 预计耗时:40分钟
# ---
# 步骤:进行集成测试
# 依赖:['step_5', 'step_6']
# 预计耗时:60分钟

# 执行任务
result = await planner.execute_task(task.id)

关键设计决策

在实现这个规划系统时,我做了几个重要的设计决策:

1. 任务分解

python 复制代码
class TaskAnalyzer:
    def __init__(self, llm):
        self.llm = llm
        
    async def analyze(
        self,
        description: str,
        context: Dict[str, Any]
    ) -> List[Dict]:
        # 使用 LLM 分析任务
        response = await self.llm.analyze(
            prompt=self._generate_prompt(
                description,
                context
            )
        )
        
        # 验证步骤的合理性
        steps = self._validate_steps(response.steps)
        
        # 检查依赖关系
        self._check_dependencies(steps)
        
        return steps
        
    def _generate_prompt(
        self,
        description: str,
        context: Dict[str, Any]
    ) -> str:
        return f"""
        请分析以下任务,将其分解为具体的执行步骤:
        
        任务描述:
        {description}
        
        上下文信息:
        {json.dumps(context, indent=2)}
        
        要求:
        1. 每个步骤要具体且可执行
        2. 明确步骤之间的依赖关系
        3. 估计每个步骤的执行时间
        4. 考虑可能的风险和回退方案
        
        请以 JSON 格式返回结果。
        """

2. 并行执行

python 复制代码
class StepExecutor:
    def __init__(
        self,
        tool_registry,
        max_concurrent: int = 5
    ):
        self.tool_registry = tool_registry
        self.semaphore = asyncio.Semaphore(max_concurrent)
        
    async def execute_steps(
        self,
        steps: List[TaskStep],
        context: Dict[str, Any]
    ) -> List[TaskStep]:
        # 创建执行任务
        tasks = [
            self._execute_with_semaphore(step, context)
            for step in steps
        ]
        
        # 并行执行
        return await asyncio.gather(*tasks)
        
    async def _execute_with_semaphore(
        self,
        step: TaskStep,
        context: Dict[str, Any]
    ) -> TaskStep:
        async with self.semaphore:
            return await self._execute_step(step, context)

3. 错误处理

python 复制代码
class ErrorHandler:
    def __init__(self, llm):
        self.llm = llm
        
    async def handle_error(
        self,
        step: TaskStep,
        error: Exception,
        context: Dict[str, Any]
    ) -> TaskStep:
        # 分析错误
        analysis = await self.llm.analyze_error(
            step=step,
            error=str(error),
            context=context
        )
        
        if analysis.can_retry:
            # 修改参数重试
            step.parameters = analysis.fixed_parameters
            return await self._retry_step(step)
        elif analysis.can_workaround:
            # 使用替代方案
            return await self._execute_workaround(
                step,
                analysis.workaround
            )
        else:
            # 标记失败
            step.status = TaskStatus.FAILED
            step.error = str(error)
            return step

实践心得

在实现和使用这个规划系统的过程中,我总结了几点经验:

  1. 任务分解要合理

    • 粒度要适中
    • 依赖要清晰
    • 考虑并行可能
  2. 执行要有弹性

    • 支持并行执行
    • 优雅处理错误
    • 允许动态调整
  3. 状态管理很重要

    • 及时更新状态
    • 保存执行历史
    • 支持断点恢复

写在最后

一个好的规划系统能让 AI Agent 的行为更加可控和高效。它就像是一个项目经理,懂得如何拆分任务、分配资源、控制风险。

在下一篇文章中,我会讲解如何实现 AI Agent 的多轮对话系统。如果你对规划系统的设计有什么想法,欢迎在评论区交流。

相关推荐
赛丽曼2 小时前
机器学习-K近邻算法
人工智能·机器学习·近邻算法
皮肤科大白6 小时前
如何在data.table中处理缺失值
学习·算法·机器学习
汤姆和佩琦6 小时前
2025-1-21-sklearn学习(43) 使用 scikit-learn 介绍机器学习 楼上阑干横斗柄,寒露人远鸡相应。
人工智能·python·学习·机器学习·scikit-learn·sklearn
HyperAI超神经6 小时前
【TVM教程】为 ARM CPU 自动调优卷积网络
arm开发·人工智能·python·深度学习·机器学习·tvm·编译器
Luzem03197 小时前
使用scikit-learn中的KNN包实现对鸢尾花数据集的预测
人工智能·深度学习·机器学习
缺的不是资料,是学习的心7 小时前
使用qwen作为基座训练分类大模型
python·机器学习·分类
Zda天天爱打卡8 小时前
【机器学习实战中阶】使用Python和OpenCV进行手语识别
人工智能·python·深度学习·opencv·机器学习
一叶_障目9 小时前
机器学习之决策树(DecisionTree——C4.5)
人工智能·决策树·机器学习