大模型 Agent 架构设计深度解析:从 ReAct 到多智能体协作的进化之路

引言:从“对话框”到“数字员工”的跨越

如果说大语言模型(LLM)是一本包罗万象的百科全书,那么 Agent(智能体)就是能够翻阅这本百科全书并动手干活的知识工作者。

过去一年,大模型的发展经历了从“拼智商”(模型参数量、推理能力)到“拼行动力”的范式转移。单纯的对话式 AI 已经无法满足复杂的真实业务需求。我们不再满足于让模型告诉我们“如何写一段代码来查询数据库”,而是期望模型能“直接连上数据库,执行查询,并将结果生成报表发到我的邮箱”。

这种从“被动回答”到“主动执行”的跨越,核心就在于 Agent 架构设计

本文将深入剖析大模型 Agent 的架构演进,从最底层的 ReAct 推理框架,到连接现实世界的 Tool Use(工具使用)机制,再到面向复杂任务的 Multi-Agent(多智能体)协作模式。我们不谈空泛的概念,将结合实际的代码片段和架构设计模式,带你一次性搞懂 Agent 技术的底层逻辑与工程实践。


一、 Agent 的灵魂:ReAct 推理框架

在设计 Agent 时,我们面临的最核心挑战是:如何让大模型在面临复杂问题时,不仅能“想清楚”,还能“做对事”?

早期的尝试走向了两个极端:

  1. 纯推理:模型在内部进行长长的思维链推导,但不与外界交互。由于缺乏外部知识补充,容易产生“幻觉”。
  2. 纯行动:模型直接调用工具,没有规划,一旦工具返回意外结果,模型就会陷入混乱。

2022 年,Yao 等人提出的 ReAct (Reason + Act) 框架完美地解决了这个问题。ReAct 的核心思想是:将推理和行动交织在一起,形成一个闭环。

1. ReAct 的工作机制

在 ReAct 模式下,模型的工作流被拆解为一个不断循环的三元组:Thought -> Action -> Observation

  • Thought(思考):模型面对当前任务,分析已有的信息,思考下一步应该做什么。
  • Action(行动):基于思考的结果,模型选择调用某个工具(如搜索引擎、数据库查询、API 调用)。
  • Observation(观察):系统执行工具后,将结果返回给模型,作为下一次思考的输入。

这个过程会一直循环,直到模型认为已经收集到足够的信息,可以给出最终答案(Finish)。

2. 代码示例:原生 ReAct Prompt 的构造

理解 ReAct 最好的方式是看其 Prompt 是如何设计的。下面是一个极简的 ReAct 系统提示词模板及交互逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
REACT_PROMPT_TEMPLATE = """
你是一个任务解决专家。你可以通过思考、行动来获取信息并最终回答问题。

你可以使用以下工具:
{tool_descriptions}

请严格按照以下格式输出:

Question: 你必须回答的输入问题
Thought: 你应该总是思考下一步要做什么
Action: 你要使用的工具,必须是 [{tool_names}] 中的一个
Action Input: 工具的输入参数
Observation: 工具执行的结果(这部分由系统提供,你不要生成)
... (Thought/Action/Action Input/Observation 可以重复多次)
Thought: 我现在知道最终答案了
Final Answer: 对原始问题的最终答案

开始!

Question: {input}
{agent_scratchpad}
"""

在代码中,agent_scratchpad 会动态填入历史的多轮 Thought/Action/Observation。当解析到模型输出 Action 时,程序拦截输出,调用对应工具,将结果作为 Observation 拼接到 Prompt 尾部,再次送入模型,直到模型输出 Final Answer

3. ReAct 的工程痛点与进化

虽然 ReAct 逻辑优美,但在工程落地中存在明显痛点:

  • 解析脆弱:依赖正则表达式去提取 ActionAction Input,一旦模型输出格式稍微偏离(比如多了一个换行符),整个流程就会崩溃。
  • token 浪费:模型每次推理都需要将冗长的历史 Scratchpad 重新读取,耗费大量上下文窗口和计算成本。

为了解决这些问题,工业界推出了更稳健的机制——Function Calling,它成为了现代 Agent 的标配。


二、 Agent 的四肢:Tool Use 与 Function Calling

如果说 ReAct 给了 Agent 思考的灵魂,那么 Tool Use 就给了 Agent 行动的四肢。而 Function Calling 则是当前连接 LLM 大脑与外部工具最标准化的神经接口。

1. 从 Prompt 解析到 Function Calling 的降维打击

传统的 ReAct 依赖模型输出文本,再由代码解析文本。Function Calling 则是在模型层面进行了原生支持:开发者在 API 请求中传入工具的 JSON Schema 描述,模型在判断需要调用工具时,直接在响应中生成结构化的 JSON 对象,而不是自然语言文本。

以 OpenAI 的 API 为例,这彻底告别了正则解析的脆弱性。

2. 代码实战:构建一个健壮的 Tool Use Agent

下面是一个基于 OpenAI API (兼容各类开源模型 vLLM 部署) 的 Function Calling 实战代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import json
from openai import OpenAI

client = OpenAI(base_url="YOUR_BASE_URL", api_key="YOUR_API_KEY")

# 1. 定义工具的 JSON Schema
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的当前天气信息",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,例如:北京"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位"
}
},
"required": ["city"]
}
}
}
]

# 2. 模拟本地工具执行函数
def get_weather(city: str, unit: str = "celsius") -> str:
# 实际业务中,这里应该调用真实的天气 API
mock_data = {"北京": "25°C 晴", "上海": "28°C 多云"}
return json.dumps({"city": city, "weather": mock_data.get(city, "未知"), "unit": unit})

# 3. Agent 执行循环
def run_agent(user_query: str):
messages = [{"role": "user", "content": user_query}]

while True:
# 调用大模型
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
tool_choice="auto" # auto 表示由模型决定是否调用工具
)

message = response.choices[0].message
messages.append(message) # 记录模型的响应(包含思考或工具调用意图)

# 检查模型是否决定调用工具
if message.tool_calls:
# 支持并行调用多个工具
for tool_call in message.tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)

print(f"[Agent 执行动作] 调用工具: {function_name}, 参数: {function_args}")

# 路由到本地函数
if function_name == "get_weather":
result = get_weather(**function_args)
else:
result = json.dumps({"error": "Unknown tool"})

# 将工具执行结果追加到 messages 中
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
# 继续循环,让模型根据工具结果继续思考
else:
# 模型没有调用工具,说明已经得出最终答案
print(f"[Agent 最终回复] {message.content}")
break

run_agent("今天北京和上海的天气怎么样?")

3. Tool Use 的架构设计原则

在构建企业级 Agent 时,Tool Use 的设计绝不仅仅是写几个函数,需要注意以下几点:

  • 工具描述即是 Prompt:模型完全依赖 description 来决定何时调用工具。描述不清、边界模糊,就会导致模型误触发或漏触发。例如,“查询数据库”不如“查询用户近30天的订单流水数据”明确。
  • 容错与重试机制:工具调用可能失败(如网络超时、API限流)。在 Agent 架构中,必须将错误信息通过 tool role 原封不动地返给模型,优秀的模型会尝试更换参数或换用备用工具重试。
  • 权限与安全隔离:Agent 有了手脚就可能造成破坏。工具层面必须做沙箱隔离和权限管控(例如只读数据库账号、API 限流),防止模型被“提示词注入”攻击后执行危险操作(如 rm -rf /)。

三、 Agent 的社会:Multi-Agent 协作架构

当单一 Agent 变得越来越强大,问题也随之而来:Prompt 过长导致注意力涣散、角色混乱(既要懂业务又要懂代码还要懂数据)、单点失败率高。

人类社会解决复杂问题的方式是分工协作,于是 Multi-Agent System (MAS) 应运而生。通过将复杂任务拆解,赋予不同 Agent 不同的角色、工具和记忆,让它们在特定的协作框架下共同完成任务。

1. 经典的 Multi-Agent 架构模式

目前工业界主流的 Multi-Agent 架构主要有以下三种:

A. 中心化路由架构

类似经典的 AutoGPT 模式。有一个“主控 Agent”负责理解任务、规划和分发,其他 Agent 作为具体的执行者。

  • 流程:用户输入 -> 主控 Agent -> 拆解为子任务 -> 分发给代码 Agent / 检索 Agent -> 汇总结果 -> 返回用户。
  • 优点:控制力强,流程清晰。
  • 缺点:主控 Agent 容易成为瓶颈,单点故障风险高。

B. 扁平化群聊架构

类似微软的 ChatDevCrewAI 的 Round-robin 模式。所有 Agent 处于同一个聊天室中,按照一定规则轮流发言。

  • 流程:CEO 提出需求 -> CTO 设计架构 -> 程序员编写代码 -> 测试员测试 -> 程序员修改…
  • 优点:鲁棒性好,一个 Agent 掉线不影响全局。
  • 缺点:容易偏离主题,陷入死循环(两个 Agent 互相道歉或无休止争论),需要引入“打断机制”或“总结 Agent”。

C. 层级化流水线架构

类似 MetaGPT 强调的 SOP(标准作业程序)。模仿真实公司的组织架构,强调上下游的契约精神。

  • 流程:产品经理输出 PRD(标准化文档) -> 架构师根据 PRD 输出系统设计 -> 工程师根据设计输出代码。上游必须交付合格的结构化产物,下游才开始工作。
  • 优点:最不容易产生幻觉,结果确定性强。
  • 缺点:架构重,灵活性差,不适合开放性创意任务。

2. 实战演练:用代码构建一个群聊式 Multi-Agent

我们使用轻量级的代码演示一个“程序员-测试员”协作闭环。这种模式比中心化架构更具自组织性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import json

# 简化的 LLM 调用函数
def call_llm(system_prompt: str, chat_history: list) -> str:
# 实际中这里调用 GPT/Claude 等接口
pass

class Agent:
def __init__(self, name: str, role: str, system_prompt: str):
self.name = name
self.role = role
self.system_prompt = system_prompt

def speak(self, chat_history: list) -> str:
# 将群聊历史连同自己的系统提示词送入 LLM
messages = [{"role": "system", "content": self.system_prompt}] + chat_history
response = call_llm(self.system_prompt, messages)
return f"[{self.name}({self.role})]: {response}"

# 定义角色
product_manager = Agent(
name="Bob", role="PM",
system_prompt="你是产品经理,你提出需求,并判断最终代码是否满足需求。如果满足,回复'任务完成'。"
)

coder = Agent(
name="Alice", role="Coder",
system_prompt="你是程序员,你根据需求编写Python代码。只输出代码,不要解释。"
)

tester = Agent(
name="Charlie", role="Tester",
system_prompt="你是测试员,你审查代码。如果有Bug或不符合需求,指出问题;如果没有,回复'代码通过'。"
)

# 模拟 Multi-Agent 群聊循环
def run_multi_agent(task: str, max_rounds=10):
chat_history = [{"role": "user", "content": task}]

# 简单的轮询顺序
agents = [product_manager, coder, tester]

for i in range(max_rounds):
current_agent = agents[i % 3]
response = current_agent.speak(chat_history)
print(f"Round {i+1}: {response}\n")

# 将发言加入群聊历史
chat_history.append({"role": "assistant", "content": response})

# 检查终止条件
if "任务完成" in response:
print("==== 任务圆满结束 ====")
break

run_multi_agent("写一个函数,判断一个整数是否为素数。")

3. Multi-Agent 的工程深水区

搭建一个 Demo 级的 MAS 很容易,但在生产环境中落地却要蹚过很多深水区:

  • 共享记忆的冲突:全量共享聊天历史会导致上下文爆炸,各 Agent 吸收了大量无关信息。最佳实践是引入短时记忆长时记忆,Agent 之间传递的不是原始对话,而是提炼后的结构化消息
  • 死循环的破局:Agent A 和 Agent B 互相推诿是常态。必须在架构层面引入“裁判”或设置最大重试次数,并在 Prompt 中强行要求“如果尝试3次仍失败,请直接向用户求助”。
  • 通信协议标准化:Agent 之间应该用 API/JSON 交流,而不是自然语言。自然语言虽然灵活,但解析成本高、信息损耗大。未来的趋势是类似 AutoGen 中的 ConfigureGenerateReply 协议,实现基于 Schema 的 Agent 间通信。

四、 架构设计哲学:从 Demo 到生产环境

掌握 ReAct、Tool Use 和 Multi-Agent 只是起点。在真实的生产环境中,一个大模型 Agent 应用要想稳定运行,还需要在架构设计上补齐以下拼图:

1. 记忆架构

没有记忆的 Agent 就像患有失忆症的员工,每次交互都从零开始。

  • 短期记忆:依赖大模型的上下文窗口,采用滑动窗口或摘要算法解决溢出问题。
  • 长期记忆:基于向量数据库(如 Milvus、Pinecone)构建。Agent 在执行任务时,通过 RAG 机制检索历史经验。更前沿的做法是反射记忆,让 Agent 在每天下班前,将成功经验和失败教训总结存档,供未来参考。

2. 规划架构

面对宏大目标(如“帮我开发一个网站”),Agent 必须具备拆解能力。

  • 从单次 ReAct 进化到 Plan-and-Solve。先输出完整的 DAG(有向无环图)任务流,再逐步执行。
  • 当执行发现偏离时,具备重规划能力,动态调整后续任务流。

3. 可观测性与评估

Agent 的非确定性给调试带来了地狱级的难度。

  • 全链路追踪:必须记录每一次 LLM 的输入 Prompt、输出 Token、工具调用参数、返回结果及耗时。类似 LangSmith、LangFuse 这样的工具是 Agent 调试的显微镜。
  • 自动化评估:传统的 BLEU/ROUGE 无法评估 Agent 的行动力。现在业界更倾向于使用LLM-as-a-Judge 模式,或者评估任务最终状态是否达成(如:数据库里的数据是否真的被修改了)。

总结

大模型 Agent 的架构设计,本质上是一门将非确定性的语言智能与确定性的软件工程相融合的艺术。

ReAct 中,我们学会了让大模型“知行合一”,用行动的反馈来纠正推理的偏航;
通过 Tool Use / Function Calling,我们为模型接上了数字世界的神经末梢,让知识转化为生产力;
Multi-Agent 协作,则向我们展示了用分布式思想对抗复杂性,用分工与契约构建数字社会的可能。

目前,Agent 技术仍在快速迭代中。从以 Prompt 为主的软编码,到以工作流为主的硬编排,再到未来的自适应 SOP,Agent 的形态还在演进。但无论如何演变,“感知-推理-行动” 的核心闭环不会改变。

作为技术人,现在正是入场构建的最佳时机。不要只停留在 API 的调用上,深入到架构的骨架中去,去解决容错、记忆、协作的真实痛点。因为在这个时代,谁能率先打造出稳定可靠的“数字员工”,谁就掌握了下一轮生产力革命的入场券。