Skip to content
清晨的一缕阳光
返回

Agent 架构设计模式详解

Agent 架构设计模式详解

AI Agent 是大模型应用的核心形态。如何设计高效的 Agent 架构?如何选择合适的设计模式?本文将深入解析 Agent 的主流架构设计模式及实战应用。

一、Agent 架构演进

1.1 架构演进历程

Agent 架构演进:

V1.0 - 简单对话 (2022)
└── 单轮对话,无状态

V2.0 - 工具调用 (2023)
└── Function Calling, Tool Use

V3.0 - 规划执行 (2023)
└── ReAct, Plan-and-Solve

V4.0 - 反思优化 (2024)
└── Self-Reflection, Critique

V5.0 - 多 Agent 协作 (2024)
└── Multi-Agent, Collaboration

1.2 核心架构模式

主流 Agent 架构模式:

┌─────────────────────────────────────────┐
│ 模式            │ 复杂度 │ 能力   │ 场景 │
├─────────────────────────────────────────┤
│ ReAct         │ 中     │ 强    │ 通用  │
│ Plan-and-Solve│ 中     │ 强    │ 推理  │
│ Reflection    │ 高     │ 最强  │ 复杂  │
│ Tool Use      │ 低     │ 中    │ 简单  │
│ Multi-Agent   │ 最高   │ 最强  │ 协作  │
└─────────────────────────────────────────┘

二、ReAct 架构模式

2.1 ReAct 原理

graph LR
    A[问题] --> B[思考]
    B --> C{需要工具?}
    C -->|是 | D[行动]
    C -->|否 | E[回答]
    D --> F[观察]
    F --> B
    E --> G[结果]

ReAct 核心思想

2.2 ReAct 实现

# react_agent.py
from typing import List, Dict, Optional
from dataclasses import dataclass
from enum import Enum

class StepType(Enum):
    """步骤类型"""
    THOUGHT = "thought"
    ACTION = "action"
    OBSERVATION = "observation"
    ANSWER = "answer"

@dataclass
class ReActStep:
    """ReAct 步骤"""
    type: StepType
    content: str

class ReActAgent:
    """ReAct Agent"""
    
    def __init__(
        self,
        llm,
        tools: List[dict],
        max_iterations: int = 10
    ):
        """
        初始化
        
        Args:
            llm: LLM 模型
            tools: 工具列表
            max_iterations: 最大迭代次数
        """
        self.llm = llm
        self.tools = {tool['name']: tool for tool in tools}
        self.max_iterations = max_iterations
    
    def run(self, question: str) -> Dict:
        """
        运行 Agent
        
        Args:
            question: 用户问题
        
        Returns:
            执行结果
        """
        steps: List[ReActStep] = []
        
        for i in range(self.max_iterations):
            # 生成下一步
            step = self._generate_step(question, steps)
            steps.append(step)
            
            # 如果是思考步骤,继续
            if step.type == StepType.THUGHT:
                continue
            
            # 如果是行动步骤,执行工具
            if step.type == StepType.ACTION:
                action = self._parse_action(step.content)
                if action:
                    observation = self._execute_action(action)
                    steps.append(ReActStep(
                        type=StepType.OBSERVATION,
                        content=observation
                    ))
                else:
                    steps.append(ReActStep(
                        type=StepType.THUGHT,
                        content="Invalid action format"
                    ))
                continue
            
            # 如果是回答,结束
            if step.type == StepType.ANSWER:
                return {
                    'answer': step.content,
                    'steps': steps,
                    'iterations': i + 1
                }
        
        # 达到最大迭代次数
        return {
            'answer': 'Failed to find answer within max iterations',
            'steps': steps,
            'iterations': self.max_iterations
        }
    
    def _generate_step(
        self, 
        question: str, 
        steps: List[ReActStep]
    ) -> ReActStep:
        """生成下一步"""
        # 构建 Prompt
        prompt = self._build_prompt(question, steps)
        
        # 调用 LLM
        response = self.llm.generate(prompt)
        
        # 解析响应
        return self._parse_response(response)
    
    def _build_prompt(
        self, 
        question: str, 
        steps: List[ReActStep]
    ) -> str:
        """构建 Prompt"""
        prompt_parts = [
            "你是一个智能助手,使用 ReAct 模式回答问题。",
            "",
            "你可以使用以下工具:",
        ]
        
        # 添加工具描述
        for tool in self.tools.values():
            prompt_parts.append(
                f"- {tool['name']}: {tool['description']}"
            )
        
        prompt_parts.extend([
            "",
            "请使用以下格式:",
            "Thought: 你的思考",
            "Action: 工具名",
            "Action Input: 工具参数",
            "Observation: 工具返回结果",
            "... (重复 Thought/Action/Observation)",
            "Thought: 我现在知道答案了",
            "Answer: 最终答案",
            "",
            "开始!",
            "",
            f"Question: {question}",
        ])
        
        # 添加历史步骤
        for step in steps:
            if step.type == StepType.THUGHT:
                prompt_parts.append(f"Thought: {step.content}")
            elif step.type == StepType.ACTION:
                prompt_parts.append(f"Action: {step.content}")
            elif step.type == StepType.OBSERVATION:
                prompt_parts.append(f"Observation: {step.content}")
        
        return '\n'.join(prompt_parts)
    
    def _parse_action(self, content: str) -> Optional[Dict]:
        """解析行动"""
        import json
        import re
        
        # 解析 Action Input
        match = re.search(r'Action Input:\s*(.+)', content, re.DOTALL)
        if not match:
            return None
        
        try:
            action_input = json.loads(match.group(1).strip())
            
            # 解析 Action
            action_match = re.search(r'Action:\s*(\w+)', content)
            if action_match:
                return {
                    'action': action_match.group(1),
                    'input': action_input
                }
        except:
            pass
        
        return None
    
    def _execute_action(self, action: Dict) -> str:
        """执行行动"""
        tool_name = action['action']
        tool_input = action['input']
        
        if tool_name not in self.tools:
            return f"Error: Unknown tool '{tool_name}'"
        
        tool = self.tools[tool_name]
        
        try:
            result = tool['function'](**tool_input)
            return str(result)
        except Exception as e:
            return f"Error: {str(e)}"
    
    def _parse_response(self, response: str) -> ReActStep:
        """解析响应"""
        response = response.strip()
        
        # 判断类型
        if response.startswith('Answer:'):
            return ReActStep(
                type=StepType.ANSWER,
                content=response.replace('Answer:', '').strip()
            )
        elif response.startswith('Action:'):
            return ReActStep(
                type=StepType.ACTION,
                content=response
            )
        else:
            return ReActStep(
                type=StepType.THUGHT,
                content=response.replace('Thought:', '').strip()
            )

2.3 ReAct 工具定义

# react_tools.py
from typing import Callable, Dict

def create_tools() -> Dict:
    """创建工具集"""
    
    def search(query: str) -> str:
        """搜索工具"""
        import requests
        
        response = requests.get(
            'https://api.example.com/search',
            params={'q': query}
        )
        
        results = response.json().get('results', [])
        return '\n'.join([r['title'] for r in results[:5]])
    
    def calculate(expression: str) -> str:
        """计算器工具"""
        try:
            result = eval(expression)
            return str(result)
        except Exception as e:
            return f"Error: {str(e)}"
    
    def get_current_time() -> str:
        """获取当前时间"""
        from datetime import datetime
        return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    
    return {
        'search': {
            'name': 'search',
            'description': '搜索互联网信息',
            'function': search,
            'parameters': {
                'query': {'type': 'string', 'description': '搜索关键词'}
            }
        },
        'calculate': {
            'name': 'calculate',
            'description': '执行数学计算',
            'function': calculate,
            'parameters': {
                'expression': {'type': 'string', 'description': '数学表达式'}
            }
        },
        'get_current_time': {
            'name': 'get_current_time',
            'description': '获取当前时间',
            'function': get_current_time,
            'parameters': {}
        }
    }

三、Plan-and-Solve 架构

3.1 架构原理

Plan-and-Solve 流程:

┌─────────────────────────────────────┐
│ 1. 理解问题                          │
│    - 分析问题需求                   │
│    - 识别关键信息                   │
├─────────────────────────────────────┤
│ 2. 制定计划                          │
│    - 分解为子任务                   │
│    - 确定执行顺序                   │
├─────────────────────────────────────┤
│ 3. 执行计划                          │
│    - 按顺序执行子任务               │
│    - 收集中间结果                   │
├─────────────────────────────────────┤
│ 4. 整合答案                          │
│    - 汇总所有结果                   │
│    - 生成最终答案                   │
└─────────────────────────────────────┘

3.2 Plan-and-Solve 实现

# plan_and_solve_agent.py
from typing import List, Dict, Optional
from dataclasses import dataclass

@dataclass
class SubTask:
    """子任务"""
    id: int
    description: str
    status: str = 'pending'  # pending, completed, failed
    result: Optional[str] = None

class PlanAndSolveAgent:
    """Plan-and-Solve Agent"""
    
    def __init__(self, llm):
        self.llm = llm
    
    def run(self, question: str) -> Dict:
        """运行 Agent"""
        # 1. 理解问题
        understanding = self._understand_problem(question)
        
        # 2. 制定计划
        plan = self._create_plan(question, understanding)
        
        # 3. 执行计划
        results = self._execute_plan(plan)
        
        # 4. 整合答案
        answer = self._synthesize_answer(
            question, 
            understanding, 
            plan, 
            results
        )
        
        return {
            'answer': answer,
            'understanding': understanding,
            'plan': plan,
            'results': results
        }
    
    def _understand_problem(self, question: str) -> str:
        """理解问题"""
        prompt = f"""
请分析以下问题:

问题:{question}

请分析:
1. 问题的核心需求是什么?
2. 需要哪些关键信息?
3. 可能的难点是什么?
"""
        return self.llm.generate(prompt)
    
    def _create_plan(
        self, 
        question: str, 
        understanding: str
    ) -> List[SubTask]:
        """创建计划"""
        prompt = f"""
基于以下问题和分析,制定解决计划:

问题:{question}

分析:
{understanding}

请制定详细的解决计划,将问题分解为多个可执行的子任务。
每个子任务应该:
1. 有明确的目标
2. 可以独立执行
3. 有清晰的输出

请按以下格式输出:
1. [子任务 1 描述]
2. [子任务 2 描述]
...
"""
        plan_text = self.llm.generate(prompt)
        
        # 解析计划
        tasks = []
        for i, line in enumerate(plan_text.split('\n'), 1):
            if line.strip() and line[0].isdigit():
                task = SubTask(
                    id=i,
                    description=line.split('.', 1)[-1].strip()
                )
                tasks.append(task)
        
        return tasks
    
    def _execute_plan(
        self, 
        plan: List[SubTask]
    ) -> List[Dict]:
        """执行计划"""
        results = []
        
        for task in plan:
            # 执行子任务
            result = self._execute_subtask(task)
            task.result = result['output']
            task.status = result['status']
            
            results.append({
                'task_id': task.id,
                'description': task.description,
                'status': task.status,
                'output': task.result
            })
        
        return results
    
    def _execute_subtask(self, task: SubTask) -> Dict:
        """执行子任务"""
        prompt = f"""
请执行以下子任务:

任务:{task.description}

请详细执行该任务,并提供完整的输出。
"""
        try:
            output = self.llm.generate(prompt)
            return {
                'status': 'completed',
                'output': output
            }
        except Exception as e:
            return {
                'status': 'failed',
                'output': str(e)
            }
    
    def _synthesize_answer(
        self,
        question: str,
        understanding: str,
        plan: List[SubTask],
        results: List[Dict]
    ) -> str:
        """整合答案"""
        # 构建结果摘要
        results_summary = '\n'.join([
            f"任务 {r['task_id']}: {r['description']}\n"
            f"状态:{r['status']}\n"
            f"结果:{r['output']}\n"
            for r in results
        ])
        
        prompt = f"""
基于以下信息,整合最终答案:

问题:{question}

理解:
{understanding}

执行结果:
{results_summary}

请综合以上信息,给出完整、准确的最终答案。
"""
        return self.llm.generate(prompt)

四、反射架构

4.1 反射原理

反射架构流程:

┌─────────────────────────────────────┐
│ 初始执行                            │
│ ↓                                  │
│ 生成初步答案                        │
│ ↓                                  │
│ 自我反思                            │
│ - 检查答案质量                      │
│ - 识别潜在问题                      │
│ ↓                                  │
│ 批评改进                            │
│ - 提出改进建议                      │
│ - 修正答案                         │
│ ↓                                  │
│ 最终输出                            │
└─────────────────────────────────────┘

4.2 反射 Agent 实现

# reflection_agent.py
from typing import Dict, List

class ReflectionAgent:
    """反射 Agent"""
    
    def __init__(self, llm):
        self.llm = llm
    
    def run(self, question: str) -> Dict:
        """运行带反思的 Agent"""
        # 1. 初始执行
        initial_response = self._initial_execution(question)
        
        # 2. 自我反思
        reflection = self._self_reflect(
            question, 
            initial_response
        )
        
        # 3. 批评改进
        critique = self._critique(
            question,
            initial_response,
            reflection
        )
        
        # 4. 修正答案
        revised_response = self._revise_answer(
            question,
            initial_response,
            critique
        )
        
        # 5. 质量评估
        quality_score = self._evaluate_quality(
            question,
            revised_response
        )
        
        return {
            'initial_response': initial_response,
            'reflection': reflection,
            'critique': critique,
            'revised_response': revised_response,
            'quality_score': quality_score
        }
    
    def _initial_execution(self, question: str) -> str:
        """初始执行"""
        prompt = f"""
请回答以下问题:

问题:{question}

请给出你的答案。
"""
        return self.llm.generate(prompt)
    
    def _self_reflect(
        self, 
        question: str, 
        response: str
    ) -> str:
        """自我反思"""
        prompt = f"""
请反思以下答案的质量:

问题:{question}

答案:
{response}

请从以下角度反思:
1. 答案是否完整回答了问题?
2. 是否有事实错误?
3. 逻辑是否清晰?
4. 是否有遗漏的重要信息?
5. 表达是否准确?

请详细列出发现的问题。
"""
        return self.llm.generate(prompt)
    
    def _critique(
        self,
        question: str,
        response: str,
        reflection: str
    ) -> str:
        """批评改进"""
        prompt = f"""
基于以下反思,提出改进建议:

问题:{question}

原答案:
{response}

反思:
{reflection}

请针对反思中发现的问题,提出具体的改进建议。
"""
        return self.llm.generate(prompt)
    
    def _revise_answer(
        self,
        question: str,
        initial_response: str,
        critique: str
    ) -> str:
        """修正答案"""
        prompt = f"""
请根据批评建议改进答案:

问题:{question}

原答案:
{initial_response}

批评建议:
{critique}

请综合以上信息,给出改进后的完整答案。
"""
        return self.llm.generate(prompt)
    
    def _evaluate_quality(
        self,
        question: str,
        response: str
    ) -> float:
        """评估质量"""
        prompt = f"""
请评估以下答案的质量(0-10 分):

问题:{question}

答案:
{response}

评分标准:
- 完整性:是否完整回答问题
- 准确性:是否有事实错误
- 逻辑性:逻辑是否清晰
- 简洁性:是否简洁明了

请只输出分数(0-10 的数字)。
"""
        score_text = self.llm.generate(prompt)
        
        # 提取分数
        import re
        match = re.search(r'(\d+)', score_text)
        if match:
            return min(10, max(0, int(match.group(1))))
        return 5.0

五、架构模式对比

5.1 模式对比表

模式优点缺点适用场景
ReAct灵活、可解释迭代次数多需要工具调用
Plan-and-Solve结构化、系统规划成本高复杂推理任务
Reflection质量高、自优化延迟高高质量要求
Tool Use简单、快速能力有限简单任务
Multi-Agent能力强、分工复杂度高复杂协作

5.2 选择指南

架构选择决策树:

1. 是否需要调用工具?
   ├── 是 → 2
   └── 否 → 3

2. 是否需要多轮推理?
   ├── 是 → ReAct
   └── 否 → Tool Use

3. 任务是否复杂?
   ├── 是 → 4
   └── 否 → 简单对话

4. 是否需要高质量?
   ├── 是 → Reflection
   └── 否 → 5

5. 是否可以分解?
   ├── 是 → Plan-and-Solve
   └── 否 → ReAct

六、实战案例

6.1 数据分析 Agent

# data_analysis_agent.py
from react_agent import ReActAgent

def create_data_analysis_agent(llm):
    """创建数据分析 Agent"""
    
    def load_data(file_path: str) -> str:
        """加载数据"""
        import pandas as pd
        df = pd.read_csv(file_path)
        return f"Shape: {df.shape}\nColumns: {list(df.columns)}"
    
    def describe_data() -> str:
        """描述数据"""
        return df.describe().to_string()
    
    def run_query(query: str) -> str:
        """运行查询"""
        return df.query(query).to_string()
    
    def calculate_statistic(
        column: str, 
        operation: str
    ) -> str:
        """计算统计"""
        if operation == 'mean':
            return str(df[column].mean())
        elif operation == 'sum':
            return str(df[column].sum())
        # ... 其他操作
    
    tools = {
        'load_data': {
            'name': 'load_data',
            'description': '加载 CSV 数据文件',
            'function': load_data,
            'parameters': {
                'file_path': {'type': 'string'}
            }
        },
        'describe_data': {
            'name': 'describe_data',
            'description': '获取数据统计描述',
            'function': describe_data,
            'parameters': {}
        },
        'run_query': {
            'name': 'run_query',
            'description': '执行数据查询',
            'function': run_query,
            'parameters': {
                'query': {'type': 'string'}
            }
        },
        'calculate_statistic': {
            'name': 'calculate_statistic',
            'description': '计算统计指标',
            'function': calculate_statistic,
            'parameters': {
                'column': {'type': 'string'},
                'operation': {'type': 'string'}
            }
        }
    }
    
    return ReActAgent(llm, tools)

6.2 代码生成 Agent

# code_generation_agent.py
from plan_and_solve_agent import PlanAndSolveAgent

def create_code_generation_agent(llm):
    """创建代码生成 Agent"""
    
    agent = PlanAndSolveAgent(llm)
    
    # 重写执行子任务方法
    original_execute = agent._execute_subtask
    
    def execute_with_validation(task):
        """执行并验证代码"""
        result = original_execute(task)
        
        if result['status'] == 'completed':
            # 验证生成的代码
            code = result['output']
            validation = _validate_code(code)
            result['validation'] = validation
        
        return result
    
    agent._execute_subtask = execute_with_validation
    
    return agent

def _validate_code(code: str) -> Dict:
    """验证代码"""
    import ast
    
    try:
        ast.parse(code)
        return {
            'valid': True,
            'message': 'Syntax valid'
        }
    except SyntaxError as e:
        return {
            'valid': False,
            'message': f'Syntax error: {str(e)}'
        }

七、总结

7.1 核心要点

  1. ReAct

    • 推理和行动交替
    • 适合工具调用场景
    • 可解释性强
  2. Plan-and-Solve

    • 先规划后执行
    • 适合复杂推理
    • 结构化好
  3. Reflection

    • 自我反思改进
    • 适合高质量要求
    • 自优化能力

7.2 最佳实践

  1. 根据场景选择架构

    • 简单任务:Tool Use
    • 中等复杂:ReAct
    • 高度复杂:Plan-and-Solve + Reflection
  2. 优化迭代次数

    • 设置合理的 max_iterations
    • 添加早期终止条件
    • 缓存中间结果
  3. 提升执行效率

    • 并行执行独立任务
    • 批量调用工具
    • 使用流式输出

参考资料


分享这篇文章到:

上一篇文章
RocketMQ 运维监控与告警指南
下一篇文章
Kafka Connector 插件开发实战