很多人以为 Agent 就是让模型自己调工具,但这只是冰山一角。

Agent 的核心不是"自动化",而是决策边界的管理。一个真正意义上的 Agent,必须回答三个问题:何时决策、如何决策、何时停止。如果这三个问题的答案完全由人工预设,那不是 Agent,是自动化脚本;如果完全交给模型,那不是 Agent,是赌博。

Agent 的本质

Agent 是一个具备环境感知、自主决策、行动执行、反馈迭代能力的系统。它区别于传统软件的根本特征在于:行为路径在运行时确定,而非编码时固定。

从工程角度看,Agent 的本质是决策闭环

观测 → 推理 → 行动 → 反馈 → 观测 → ...

这个闭环有三个关键参数:

  1. 决策粒度:每次行动前是否需要重新规划,还是沿用既定策略
  2. 反馈深度:环境反馈是否改变内部状态,还是仅作为下一个观测输入
  3. 终止条件:谁来定义"任务完成",是外部信号还是内部判断

很多人把 Agent 理解为"LLM + 工具调用",这忽略了最关键的状态管理和策略演化。一个成熟的 Agent 系统,其复杂度不在工具层,而在决策层:如何让模型在不确定的环境中,做出可预期的行为。

五种主流 Agent 设计模式

ReAct(Reasoning + Acting)

ReAct 是最接近人类思维模式的 Agent 架构。其核心机制是思维-行动交替

Thought: 我需要查询北京今天的天气
Action: search("北京天气 2026年8月1日")
Observation: 北京今天晴,气温28-35°C
Thought: 用户问的是否适合户外活动,我需要判断温度范围
Answer: 适合,但需注意防暑

适用场景

  • 任务可分解为明确步骤
  • 环境反馈相对确定性(如 API 调用)
  • 不需要长程规划,单步决策即可推进

局限

  • 无全局规划,容易陷入局部最优
  • 依赖高质量 Observation,环境噪声会放大决策失误
  • Token 消耗随步数线性增长,长任务成本高

ReAct 的优势在于简单可控,劣势在于无前瞻性。它适合"走一步看一步"的场景,不适合需要全局协调的复杂任务。

Plan-and-Execute

Plan-and-Execute 将决策拆分为两个阶段:先规划,再执行

Plan:
1. 收集用户需求文档
2. 分析技术栈选型
3. 生成架构设计方案
4. 输出详细技术文档

Execute:
Step 1: 调用文件读取工具,获取需求文档
Step 2: 调用知识库,检索相关技术方案
...

适用场景

  • 任务有明确起点和终点
  • 步骤间依赖关系清晰
  • 执行环境相对稳定,无需频繁调整计划

局限

  • 计划阶段的质量决定上限,一次规划失误会导致全盘失败
  • 执行阶段缺乏灵活调整能力,环境变化时需要重新规划
  • 过度依赖初始信息,新信息难以动态融入

Plan-and-Execute 的本质是用确定性对抗不确定性。它假设环境足够稳定,规划足够准确,这在很多场景下是强假设。

Multi-Agent(多智能体协作)

Multi-Agent 将复杂任务拆解到多个 Agent,每个 Agent 承担特定角色:

[ProductManager] 接收用户需求,生成产品文档
[TechLead] 审查文档,生成技术方案
[Developer] 实现方案,输出代码
[Tester] 执行测试,反馈问题

适用场景

  • 任务复杂度超出单 Agent 决策能力
  • 需要跨领域知识协作
  • 有明确的角色分工和协作流程

局限

  • 协调成本高,Agent 间通信开销大
  • 角色边界模糊时会产生推诿或重复劳动
  • 整体稳定性取决于最弱环节

Multi-Agent 的核心挑战不是"如何分工",而是"如何对齐"。多个 Agent 之间的认知偏差会逐级放大,最终导致协作失败。成功的 Multi-Agent 系统,必然有严格的接口契约结果验收机制

Self-Reflection(自我反思)

Self-Reflection 让 Agent 在执行后自我评估,形成迭代改进:

Action: generate_code(prompt)
Output: def foo(): return 1
Reflection: 代码缺少类型注解,不符合最佳实践
Revision: def foo() -> int: return 1

适用场景

  • 任务有明确的成功标准
  • 反馈机制可自动化(如单元测试、代码检查)
  • 迭代收益大于成本

局限

  • 自我评估的准确性受模型能力限制,模型无法发现自己不知道的问题
  • 迭代次数难以预测,可能无限循环
  • 对简单任务过度设计,性价比低

Self-Reflection 的前提是Agent 知道什么是"好结果"。这个标准不能完全交给模型定义,必须由工程系统提供客观反馈。

Tool Use(工具调用)

Tool Use 是 Agent 的基础能力,但作为设计模式时,强调的是工具的选择与组合策略

User: 分析这个 CSV 文件中的销售数据
Agent:
  - 工具选择: pandas_reader (数据加载)
  - 工具选择: data_visualizer (可视化)
  - 工具组合: 串联执行,传递中间结果

适用场景

  • 工具边界清晰,功能正交
  • 工具数量可控(<50个)
  • 任务可映射到现有工具集

局限

  • 工具描述质量决定选择准确性,描述不当会导致误用
  • 工具组合依赖模型推理能力,复杂组合易出错
  • 工具失败时的降级策略难以设计

Tool Use 的本质是能力扩展,但它没有解决"何时使用"的问题。纯粹的 Tool Use 模式需要外部决策系统驱动。

代码实战:一个完整的 ReAct Agent

以下实现一个最小可运行的 ReAct Agent,包含工具定义、推理循环和终止判断:

import json
import re
from typing import Callable, Dict, List, Optional

class Tool:
    """工具基类"""
    def __init__(self, name: str, description: str, func: Callable):
        self.name = name
        self.description = description
        self.func = func
    
    def run(self, args: str) -> str:
        try:
            return self.func(args)
        except Exception as e:
            return f"Error: {str(e)}"

class ReActAgent:
    """ReAct Agent 实现"""
    
    PROMPT_TEMPLATE = """You are a ReAct agent. Follow this format:

Question: the input question
Thought: your reasoning step
Action: tool_name[args]
Observation: tool result
... (repeat Thought/Action/Observation)
Thought: I now know the final answer
Answer: the final answer

Available tools:
{tools_desc}

Question: {question}
{history}"""

    def __init__(self, llm_call: Callable[[str], str], tools: List[Tool], max_steps: int = 10):
        self.llm_call = llm_call
        self.tools = {t.name: t for t in tools}
        self.max_steps = max_steps
    
    def _parse_action(self, text: str) -> Optional[tuple]:
        """解析 Action 和参数"""
        pattern = r"Action:\s*(\w+)\[(.*?)\]"
        match = re.search(pattern, text, re.DOTALL)
        if match:
            return match.group(1), match.group(2).strip()
        return None
    
    def _parse_final_answer(self, text: str) -> Optional[str]:
        """解析最终答案"""
        pattern = r"Answer:\s*(.+?)(?:\n|$)"
        match = re.search(pattern, text, re.DOTALL)
        return match.group(1).strip() if match else None
    
    def _build_tools_desc(self) -> str:
        """构建工具描述"""
        lines = [f"- {name}: {tool.description}" for name, tool in self.tools.items()]
        return "\n".join(lines)
    
    def run(self, question: str) -> str:
        """执行推理循环"""
        history = ""
        
        for step in range(self.max_steps):
            prompt = self.PROMPT_TEMPLATE.format(
                tools_desc=self._build_tools_desc(),
                question=question,
                history=history
            )
            
            response = self.llm_call(prompt)
            history += response + "\n"
            
            # 检查是否得出最终答案
            answer = self._parse_final_answer(response)
            if answer:
                return answer
            
            # 解析并执行工具调用
            action = self._parse_action(response)
            if not action:
                history += "Observation: Invalid action format\n"
                continue
            
            tool_name, args = action
            if tool_name not in self.tools:
                history += f"Observation: Unknown tool '{tool_name}'\n"
                continue
            
            result = self.tools[tool_name].run(args)
            history += f"Observation: {result}\n"
        
        return f"Max steps ({self.max_steps}) reached. Last response:\n{response}"

# 示例工具
def calculator(expression: str) -> str:
    """安全计算数学表达式"""
    try:
        # 仅允许基本数学运算
        allowed = set("0123456789+-*/().e ")
        if not all(c in allowed for c in expression):
            return "Error: Invalid characters in expression"
        return str(eval(expression))
    except Exception as e:
        return f"Error: {str(e)}"

def search_mock(query: str) -> str:
    """模拟搜索工具"""
    mock_db = {
        "python": "Python 3.12 released in 2023, with performance improvements",
        "agent": "AI Agent is a system with perception, reasoning, and action",
        "react": "ReAct pattern: Reasoning + Acting interleaving"
    }
    for key in mock_db:
        if key in query.lower():
            return mock_db[key]
    return "No relevant information found"

# 使用示例
if __name__ == "__main__":
    # 模拟 LLM 调用(实际使用时替换为真实 API)
    def mock_llm(prompt: str) -> str:
        # 简化示例:实际应调用 GPT/Claude 等
        if "2+3" in prompt or "calculate" in prompt.lower():
            return "Thought: I need to use the calculator\nAction: calculator[2+3]"
        elif "agent" in prompt.lower():
            return "Thought: I should search for agent information\nAction: search[AI Agent]"
        return "Thought: I now know the final answer\nAnswer: Task completed"
    
    tools = [
        Tool("calculator", "Evaluate math expressions", calculator),
        Tool("search", "Search for information", search_mock)
    ]
    
    agent = ReActAgent(mock_llm, tools)
    result = agent.run("What is 2+3?")
    print(result)

这个实现包含以下关键设计:

  1. 严格的格式约束:通过正则解析 Action,避免模型输出不稳定导致的解析失败
  2. 步数限制max_steps 防止无限循环
  3. 错误隔离:工具执行异常不影响 Agent 主流程
  4. 历史管理:维护完整的 Thought-Action-Observation 链

实际生产中需要补充:LLM API 接入、更复杂的历史压缩、工具参数验证、并发调用等。

Agent 开发框架对比

LangChain

优势

  • 生态最完善,工具链丰富
  • 抽象层次清晰,从简单 Chain 到复杂 Agent
  • 文档和社区支持强

劣势

  • 抽象过度,源码阅读成本高
  • 版本迭代快,API 稳定性差
  • 复杂场景下性能调优困难

LangChain 适合快速原型验证标准场景落地。如果需求超出预设抽象,扩展成本会显著上升。

AutoGen

优势

  • Multi-Agent 原生支持,角色对话模式自然
  • 人机协作设计成熟,支持中断和干预
  • Microsoft 背书,长期维护有保障

劣势

  • 单 Agent 场景能力平庸
  • 配置复杂,学习曲线陡峭
  • 调试困难,多 Agent 状态追踪成本高

AutoGen 适合明确的多角色协作场景。如果不需要 Multi-Agent,它的价值难以体现。

CrewAI

优势

  • 角色定义直观,Task-Assignment 模式清晰
  • 轻量级,代码侵入性低
  • 快速搭建 Demo 体验好

劣势

  • 生产级特性不足(如容错、监控)
  • 社区规模小,问题解决依赖官方
  • 扩展能力受限,复杂定制困难

CrewAI 适合中小规模项目快速迭代阶段。大规模生产环境需要自行补齐工程能力。

踩坑点

无限循环

现象:Agent 在某个状态反复执行相同 Action,无法推进。

原因

  • 终止条件定义模糊,模型无法判断何时结束
  • 工具返回结果与预期不符,Agent 陷入"重试-失败"循环
  • 规划失败,Agent 反复尝试错误的路径

解决

  • 硬性步数限制(如 max_steps=15
  • 状态去重:记录已执行 Action,重复时强制终止
  • 显式终止信号:要求模型在满足条件时输出特定标记

Token 爆炸

现象:单次调用 token 数超限,或累计成本不可控。

原因

  • 历史记录无压缩,Observation 过长
  • Multi-Agent 通信开销累积
  • 工具返回结果未精简

解决

  • 历史压缩:只保留关键 Thought 和最终 Observation
  • 工具输出截断:限制返回内容长度
  • 分层规划:高层策略用小模型,低层执行用大模型

工具调用失败处理

现象:工具执行异常导致 Agent 中断或输出错误结果。

原因

  • 工具参数验证缺失,模型生成无效输入
  • 工具依赖环境不稳定(如网络、文件系统)
  • 错误信息不明确,Agent 无法理解失败原因

解决

  • 工具层防御:参数校验 + 异常捕获 + 明确错误消息
  • 降级策略:工具失败时提供替代方案或要求人工干预
  • 工具隔离:单个工具失败不影响其他工具和主流程

作者观点与选型建议

Agent 不是万能解,它是对确定性工程的补充,而非替代。

选型决策树

  1. 任务是否需要运行时决策?

    • 否 → 传统软件工程,不需要 Agent
    • 是 → 继续
  2. 决策路径是否可枚举?

    • 是 → ReAct,单步决策足够
    • 否 → 继续
  3. 任务是否可分解为独立子任务?

    • 是 → Plan-and-Execute 或 Multi-Agent
    • 否 → Self-Reflection + 人工监督
  4. 是否有明确的成功标准和自动化反馈?

    • 是 → Self-Reflection 可行
    • 否 → 降低自动化预期,引入人工验收环节

框架选择

  • 标准场景 + 快速落地 → LangChain
  • 多角色协作 → AutoGen
  • 中小规模 + 快速迭代 → CrewAI
  • 特殊需求 + 团队技术强 → 自研

Agent 的成熟度,不取决于模型能力,而取决于决策边界的设计工程兜底的能力。把不确定性交给模型,把确定性留给工程,这是 Agent 落地的核心原则。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐