AI Agent 系统设计:从单轮推理到多工具协同的架构演进
AI Agent 系统设计:从单轮推理到多工具协同的架构演进

一、从 Chatbot 到 Agent:大模型能力的边界与突破
大语言模型在单轮问答场景中表现优异,但面对需要多步推理、外部工具调用和状态管理的复杂任务时,纯文本生成模式暴露出根本性缺陷:模型无法获取实时信息(如当前天气、股票行情),无法执行确定性操作(如数据库查询、API 调用),且在长链推理中容易产生幻觉累积。
以一个"分析竞品定价策略并生成报告"的任务为例,Agent 需要依次完成:搜索竞品信息、调用数据库获取历史定价、用计算工具分析趋势、将结果写入文档。这要求模型从"生成文本"进化为"规划并执行动作序列",即从 Chatbot 演进为 Agent。
Agent 的核心架构由三个组件构成:规划器(Planner)负责任务分解与步骤编排,执行器(Executor)负责调用工具并处理返回结果,记忆模块(Memory)负责维护上下文状态和对话历史。三者协同的效率决定了 Agent 的任务完成率。
二、Agent 核心架构的底层机制
2.1 ReAct 框架:推理与行动的交织
ReAct(Reasoning + Acting)是目前最主流的 Agent 框架。其核心思想是将推理(Thought)和行动(Action)交替执行,每一步推理都基于前一步的观察结果(Observation),形成 Thought-Action-Observation 的循环。
sequenceDiagram
participant U as 用户
participant P as Planner (LLM)
participant E as Executor
participant T as 工具集
U->>P: 提交任务
P->>P: Thought 1: 需要先获取竞品信息
P->>E: Action 1: search("竞品A 最新定价")
E->>T: 调用搜索工具
T-->>E: Observation 1: 竞品A 定价 ¥299/月
E-->>P: 返回结果
P->>P: Thought 2: 需要对比历史数据
P->>E: Action 2: query_db("竞品A 价格历史")
E->>T: 调用数据库工具
T-->>E: Observation 2: 近6个月价格从¥399降至¥299
E-->>P: 返回结果
P->>P: Thought 3: 信息已充分,生成分析报告
P->>E: Action 3: write_report(分析结果)
E->>T: 调用文档工具
T-->>E: Observation 3: 报告已生成
E-->>P: 返回结果
P-->>U: 任务完成,返回报告
ReAct 的优势在于推理过程可解释:每一步 Thought 都记录了模型的决策依据,便于调试和优化。但其劣势也很明显——每一步都需要调用 LLM 生成 Thought,延迟和成本随步骤数线性增长。
2.2 工具调用的函数签名机制
现代 Agent 通过 Function Calling 实现工具调用。模型接收工具的函数签名描述,在需要时输出结构化的调用请求,而非自由文本。
from pydantic import BaseModel, Field
from typing import Literal
import json
class ToolDefinition(BaseModel):
"""工具定义:描述工具的名称、参数和用途"""
name: str = Field(description="工具名称,全局唯一标识")
description: str = Field(description="工具功能描述,供 LLM 理解用途")
parameters: dict = Field(description="JSON Schema 格式的参数定义")
# 定义工具集
TOOLS = [
ToolDefinition(
name="search_web",
description="搜索互联网获取实时信息,适用于查询新闻、价格、天气等动态数据",
parameters={
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索关键词"
},
"num_results": {
"type": "integer",
"description": "返回结果数量,默认5",
"default": 5
}
},
"required": ["query"]
}
),
ToolDefinition(
name="execute_sql",
description="执行 SQL 查询并返回结果,仅支持 SELECT 语句",
parameters={
"type": "object",
"properties": {
"sql": {
"type": "string",
"description": "SQL 查询语句"
},
"database": {
"type": "string",
"enum": ["analytics", "pricing", "users"],
"description": "目标数据库名称"
}
},
"required": ["sql", "database"]
}
),
]
def build_tool_prompt(tools: list[ToolDefinition]) -> str:
"""将工具定义转换为 LLM 可理解的系统提示"""
tool_schemas = [t.model_dump() for t in tools]
return f"""你可以使用以下工具来完成任务:
{json.dumps(tool_schemas, ensure_ascii=False, indent=2)}
当你需要调用工具时,请输出如下格式:
```json
{{"tool_call": {{"name": "工具名", "arguments": {{参数}}}}}}
如果你已经收集到足够信息,直接输出最终答案,无需调用工具。"""
## 三、生产级 Agent 框架实现
### 3.1 带状态管理与错误恢复的 Agent 循环
```python
import openai
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class AgentState:
"""Agent 运行状态:维护对话历史与工具调用记录"""
messages: list[dict] = field(default_factory=list)
tool_calls_log: list[dict] = field(default_factory=list)
max_iterations: int = 10
current_iteration: int = 0
class ProductionAgent:
"""生产级 Agent:支持工具调用、错误恢复与迭代限制"""
def __init__(self, model: str = "gpt-4o", tools: list[dict] = None):
self.model = model
self.tools = tools or []
self.tool_implementations = {
"search_web": self._search_web,
"execute_sql": self._execute_sql,
}
async def run(self, task: str) -> str:
"""执行 Agent 任务,返回最终结果"""
state = AgentState()
system_prompt = build_tool_prompt(self.tools)
state.messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": task},
]
while state.current_iteration < state.max_iterations:
state.current_iteration += 1
try:
response = await openai.ChatCompletion.acreate(
model=self.model,
messages=state.messages,
temperature=0.1, # 低温度保证推理稳定性
)
except openai.error.RateLimitError:
# 限流时指数退避重试
import asyncio
await asyncio.sleep(2 ** state.current_iteration)
continue
except openai.error.APIError as e:
return f"API 调用失败: {e}"
assistant_msg = response.choices[0].message
state.messages.append(assistant_msg.to_dict())
# 检查是否包含工具调用
tool_call = self._parse_tool_call(assistant_msg.content)
if tool_call is None:
# 无工具调用,任务完成
return assistant_msg.content
# 执行工具调用
tool_name = tool_call["name"]
tool_args = tool_call["arguments"]
if tool_name not in self.tool_implementations:
observation = f"错误:未知工具 '{tool_name}'"
else:
try:
observation = await self.tool_implementations[tool_name](**tool_args)
except Exception as e:
observation = f"工具执行失败: {type(e).__name__}: {e}"
# 记录工具调用日志
state.tool_calls_log.append({
"iteration": state.current_iteration,
"tool": tool_name,
"args": tool_args,
"result_preview": str(observation)[:200],
})
# 将观察结果反馈给 LLM
state.messages.append({
"role": "user",
"content": f"工具返回结果:{observation}"
})
return "任务未完成:已达到最大迭代次数限制"
@staticmethod
def _parse_tool_call(content: str) -> Optional[dict]:
"""从 LLM 输出中解析工具调用请求"""
import re
pattern = r'```json\s*(\{.*?\})\s*```'
match = re.search(pattern, content, re.DOTALL)
if match:
try:
parsed = json.loads(match.group(1))
if "tool_call" in parsed:
return parsed["tool_call"]
except json.JSONDecodeError:
pass
return None
@staticmethod
async def _search_web(query: str, num_results: int = 5) -> str:
"""搜索工具实现(示例)"""
# 实际场景接入搜索 API
return f"搜索结果:找到 {num_results} 条关于 '{query}' 的信息"
@staticmethod
async def _execute_sql(sql: str, database: str) -> str:
"""数据库查询工具实现(示例)"""
# 安全校验:仅允许 SELECT 语句
if not sql.strip().upper().startswith("SELECT"):
return "错误:仅允许执行 SELECT 查询"
return f"查询结果:从 {database} 执行 {sql[:50]}..."
3.2 多 Agent 协作架构
class MultiAgentOrchestrator:
"""多 Agent 编排器:将复杂任务分配给专业 Agent"""
def __init__(self):
self.agents = {
"researcher": ProductionAgent(
model="gpt-4o",
tools=[t for t in TOOLS if t.name in ["search_web"]]
),
"analyst": ProductionAgent(
model="gpt-4o",
tools=[t for t in TOOLS if t.name in ["execute_sql"]]
),
"writer": ProductionAgent(
model="gpt-4o",
tools=[] # 写作 Agent 无需工具
),
}
async def execute(self, task: str) -> str:
"""三阶段流水线:调研 → 分析 → 写作"""
# 阶段1:调研 Agent 收集信息
research_result = await self.agents["researcher"].run(task)
# 阶段2:分析 Agent 处理数据
analysis_prompt = f"基于以下调研结果进行数据分析:\n{research_result}"
analysis_result = await self.agents["analyst"].run(analysis_prompt)
# 阶段3:写作 Agent 生成报告
writing_prompt = (
f"基于以下调研和分析结果,撰写专业报告:\n"
f"调研:{research_result}\n"
f"分析:{analysis_result}"
)
final_report = await self.agents["writer"].run(writing_prompt)
return final_report
四、Agent 架构的边界分析与权衡
4.1 ReAct 框架的延迟问题
ReAct 的每一步都需要 LLM 推理,10 步任务的端到端延迟可能超过 30 秒。对于实时性要求高的场景(如客服对话),这一延迟不可接受。替代方案是 Plan-and-Execute:先由 LLM 一次性生成完整计划,再逐步执行,减少 LLM 调用次数。但 Plan-and-Execute 的代价是缺乏灵活性——如果某一步的观察结果与预期不符,需要重新规划。
4.2 工具调用的可靠性瓶颈
LLM 生成的工具调用参数可能不符合 Schema 约束(如类型错误、缺少必填参数)。实测中,GPT-4o 的工具调用格式正确率约为 95%,仍有 5% 的失败率需要重试或兜底处理。对于关键操作(如数据库写入),必须在工具实现层增加校验和确认机制。
4.3 上下文窗口的约束
Agent 的对话历史随迭代次数增长,可能超出模型的上下文窗口。以 GPT-4o 的 128K Token 限制为例,10 轮工具调用可能消耗 20K-50K Token。解决方案包括:滑动窗口截断早期历史、对历史进行摘要压缩、或使用向量数据库存储长期记忆。
4.4 适用边界总结
| Agent 类型 | 适用场景 | 不适用场景 |
|---|---|---|
| 单 Agent + ReAct | 3-5 步简单任务 | 10+ 步复杂任务 |
| 多 Agent 流水线 | 可分解的串行任务 | 需要动态协作的任务 |
| Plan-and-Execute | 任务步骤可预判 | 环境高度不确定 |
五、总结
AI Agent 的核心价值在于将 LLM 从文本生成器升级为任务执行器。ReAct 框架通过 Thought-Action-Observation 循环实现了推理与行动的交织,Function Calling 机制使工具调用从自由文本变为结构化请求。生产环境中,必须关注迭代限制、错误恢复、工具校验和上下文管理,才能构建可靠的 Agent 系统。
落地路线建议:从单 Agent + ReAct 起步,使用 2-3 个核心工具验证任务完成率;当任务复杂度增加时,引入 Plan-and-Execute 减少延迟;最终根据业务领域拆分为多 Agent 协作架构。始终监控每步工具调用的成功率和平均延迟,以此作为 Agent 迭代优化的核心指标。
更多推荐
所有评论(0)