引言:Agent 的核心引擎
现代 AI Agent(如 Claude Code、Cursor Agent、Aider)能够自主完成编程、数据分析等复杂任务,其背后依赖两个核心层:
- 工具执行层:通过 MCP 等协议与外部系统交互(文件读写、命令执行、API 调用)
- 推理决策层:Agent Host 与 LLM 之间的交互协议,决定 Agent"何时做、做什么、怎么做"
本文聚焦于推理决策层------Agent 与 LLM 之间的交互协议。你将理解:
- Agent Host 如何将工具能力"翻译"给 LLM
- LLM 如何输出结构化的决策(思考 + 行动)
- 为什么 ReAct 模式和 XML 格式成为行业标准
- 一次完整的 Agent 推理循环是如何运转的
第一章:Agent Host 的双重身份
1.1 Agent Host 在架构中的定位
在 MCP 架构中,Agent Host(如 Claude Code)处于中间层:
- 向下(工具层) :通过 MCP Client 与 Server 通信,发现并调用
read_file、run_command、get_weather等工具 - 向上(模型层) :将工具列表和对话历史组织成 Prompt,调用 LLM API,解析 LLM 的响应
LLM 不直接理解 MCP 协议 。它看到的不是 tools/list 或 JSON-RPC,而是经过 Host 转换后的、符合该模型 API 规范的工具定义。
1.2 为什么需要这层"翻译"?
不同 LLM 提供商的工具调用格式各不相同:
| 模型提供商 | 工具调用格式 | 关键字段 |
|---|---|---|
| OpenAI | Function Calling | tools, tool_calls |
| Anthropic | Tool Use | tools, tool_use content block |
| Google Gemini | Function Calling | tools, functionCall |
Agent Host 的核心职责之一,就是将 MCP 的标准化工具定义,转换为目标 LLM 所能理解的格式。这种"适配器模式"使得 Agent 可以灵活切换底层模型,而无需修改工具实现。
第二章:Agent ↔ LLM 交互全流程
2.1 整体流程图
用户输入
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Agent Host │
│ │
│ ① 发现工具 ② 格式转换 │
│ ┌─────────────────┐ ┌──────────────────────────────────┐ │
│ │ MCP Client │ │ 将 MCP Tool 定义转换为 │ │
│ │ tools/list ────►│───►│ 目标 LLM 的 tools 参数格式 │ │
│ │ ◄─── Tool 列表 │ └──────────────────────────────────┘ │
│ └─────────────────┘ │ │
│ ▼ │
│ ③ 发起 LLM 推理 ④ 解析模型响应 │
│ ┌──────────────────────────────────┐ ┌────────────────────┐ │
│ │ 调用 LLM API,传入: │ │ 检测响应中是否包含 │ │
│ │ - 系统提示(含 ReAct 指令) │──►│ <function_calls> │ │
│ │ - 用户消息 │ │ 或 <final_response>│ │
│ │ - 转换后的工具定义 │ └────────────────────┘ │
│ └──────────────────────────────────┘ │ │
│ ▼ │
│ ⑤ 执行工具 ⑥ 结果回传 │
│ ┌─────────────────┐ ┌──────────────────────────────────┐ │
│ │ 解析 <function_ │ │ 将工具结果作为 tool 角色消息 │ │
│ │ calls> 提取参数 │───►│ 追加到对话历史,再次调用 LLM │ │
│ │ 调用 MCP Client │ │ 直到 LLM 返回 <final_response> │ │
│ └─────────────────┘ └──────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
▼
最终回复用户
2.2 步骤详解
步骤①:发现工具
Host 启动时,通过 MCP Client 向每个 Server 发送 tools/list,获取工具列表。每个 Tool 包含 name、description、inputSchema(JSON Schema 定义参数)。
步骤②:格式转换
Host 将 MCP Tool 定义转换为目标 LLM 的 tools 参数。以 OpenAI 为例:
python
# MCP Tool 定义
{
"name": "get_weather",
"description": "获取指定城市的天气",
"inputSchema": {"type": "object", "properties": {"city": {"type": "string"}}}
}
# 转换为 OpenAI 格式
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}}
}
}
步骤③:发起 LLM 推理
Host 构建 Prompt,包含:
- 系统提示:明确要求模型按 ReAct 模式输出,使用 XML 标签(见第三章)
- 对话历史:用户消息、之前的工具调用记录
- 工具定义:转换后的 tools 参数
步骤④:解析模型响应
LLM 返回的响应通常有两种格式:
<function_calls>:要求调用工具<final_response>:直接回答用户
Host 解析 XML,提取工具名称和参数。
步骤⑤:执行工具
Host 根据解析结果,通过 MCP Client 调用 tools/call,将参数传递给对应的 MCP Server。
步骤⑥:结果回传与循环
Host 将工具执行结果以 role: tool 的消息追加到对话历史,再次调用 LLM。重复③~⑥,直到 LLM 输出 <final_response>。
第三章:ReAct 模式与 XML 交互格式
3.1 两条技术路线:原生 Function Call vs. XML Prompt
在开始深入之前,必须先澄清一个关键分歧。阅读 Agent 相关技术文章时,初学者最容易产生的困惑是:"为什么有的 Agent 用 JSON 返回工具调用,有的用 XML?"
这两种方式对应着两种不同的实现路线,且在实际的 API 调用中是互斥的:
| 路线 | 实现方式 | 典型代表 | 优缺点 |
|---|---|---|---|
| 原生 Function Call | 使用模型 API 内置的 tools 参数,模型在 tool_calls JSON 字段中返回结构化调用 |
OpenAI、Anthropic、Google 官方 API | ✅ 稳定可靠,无需解析 ❌ 流式控制受限,难以获取思维链 |
| XML Prompt 驱动 | 在 System Prompt 中内嵌工具定义,要求模型在纯文本中输出 XML 标签,Host 通过正则或流式解析器提取 | Claude Code、Cursor、AutoGPT(早期) | ✅ 流式可控,可获取 thinking,绕过模型限制 ❌ 依赖 Prompt 工程,解析容错成本高 |
虽然现代 LLM API 提供了原生的 Function Calling JSON 接口,但像 Claude Code、Cursor 等高级 Agent,为了获得更强的流式控制、思维链可见性、以及对长上下文的更好兼容性 ,往往选择绕过原生接口,在纯文本流中强制使用 XML 标签来输出决策。Host 接收到文本后,通过正则或流式 XML 解析器提取动作。
本文的其余部分聚焦于路线②(XML Prompt 驱动) ,这也是当前最先进 Agent 系统的共同选择。如果你使用原生 Function Calling,步骤④中你将从 response.tool_calls 读取结构化数据,而非解析 XML,但整体的"发现 → 决策 → 执行 → 观察"循环逻辑是相通的。
3.2 什么是 ReAct?
ReAct(Reasoning + Acting)是一种 Prompt 范式,要求 LLM 在每一步先输出推理过程,再输出行动决策。这种模式最早由 Google 在 2022 年提出,现已成为 Agent 系统的默认选择。
核心优势:
- 可解释性:开发者能追踪模型的决策路径,调试错误
- 错误恢复:当工具返回意外结果时,模型可在下一轮思考中调整策略
- 多步推理:复杂任务天然需要多轮思考-行动循环
3.3 XML 标签格式
在 XML Prompt 驱动路线下,LLM 的每次响应必须包含两个部分:
① 推理过程(<thinking>)
xml
<thinking>
用户询问北京天气。我看到工具列表中有 get_weather,正好可以完成这个任务。city 参数从问题中提取为"北京"。调用这个工具后,我就能获得准确信息。
</thinking>
② 行动决策(二选一)
- 调用工具:
xml
<function_calls>
<invoke name="get_weather">
<parameter name="city">北京</parameter>
</invoke>
</function_calls>
- 直接回复:
xml
<final_response>
北京今天晴,气温 18°C ~ 26°C。
</final_response>
3.4 为什么选择 XML?
| 维度 | XML 标签 | JSON |
|---|---|---|
| 流式解析 | 可增量解析(遇到开标签即可处理) | 需完整 JSON 才能解析 |
| 自然语言嵌入 | 与自然文本融合良好 | 需要转义,干扰阅读 |
| LLM 生成难度 | 更符合 LLM 的文本生成习惯 | 需要严格括号匹配,容易出错 |
| 可读性 | 清晰标记思考与行动 | 嵌套结构不易阅读 |
关键点:XML 标签是 Agent Host 与 LLM 之间的内部约定 ,不属于任何标准协议。不同 Agent 可能使用不同的标签名(如
<thought>、<action>),但本质都是"思考 + 行动"的二段式结构。
第四章:完整模拟交互------编程智能体查询天气
以下通过角色扮演,完整展示一个编程智能体(类似 Claude Code)与 LLM 的交互过程。
4.1 模拟设定
| 角色 | 职责 |
|---|---|
| 用户 | 提出查询请求 |
| Agent Host | 管理对话历史、解析 XML、执行工具、控制 ReAct 循环 |
| LLM(小白) | 输出 <thinking> + <function_calls> 或 <final_response> |
| MCP Server | 提供工具(本例中包含 get_weather) |
工具列表(通过 MCP 发现):
| 工具名 | 描述 | 参数 |
|---|---|---|
read_file |
读取文件 | path |
write_file |
写入文件 | path, content |
run_command |
执行命令 | command |
search_code |
搜索代码 | pattern, path |
get_weather |
获取天气(来自 MCP 天气 Server) | city |
4.2 LLM 的系统提示词(简化版)
text
你是一个编程智能体,遵循 ReAct 模式。可用工具如下:
- get_weather(city): 获取城市天气
你的输出格式:
1. <thinking> 你的推理过程 </thinking>
2. 要么 <function_calls><invoke name="工具名"><parameter name="参数名">值</parameter></invoke></function_calls>
要么 <final_response> 你的最终回答 </final_response>
只输出上述格式,不要添加其他文字。
4.3 交互日志
第 1 轮:用户提问,Host 发送给 LLM
用户: 北京今天天气怎么样?
Host → LLM(小白):
<message>
<conversation_history>[{"role":"user","content":"北京今天天气怎么样?"}]</conversation_history>
<tools>
<tool><name>get_weather</name><description>获取城市天气</description><parameters><parameter name="city" type="string"/></parameters></tool>
</tools>
<instruction>请按 ReAct 模式处理。</instruction>
</message>
LLM 响应:
xml
<thinking>
用户询问北京天气。我看到 get_weather 工具正好可用,city 参数为"北京"。调用它即可获得数据。
</thinking>
<function_calls>
<invoke name="get_weather">
<parameter name="city">北京</parameter>
</invoke>
</function_calls>
第 2 轮:Host 执行工具,回传结果
Host(模拟 MCP 执行): get_weather 返回"北京今天晴,18°C~26°C,空气质量良好"
Host → LLM(小白):
<message>
<conversation_history>
[
{"role":"user","content":"北京今天天气怎么样?"},
{"role":"assistant","content":"<thinking>...</thinking>"},
{"role":"tool","tool_call_id":"call_001","content":"北京今天晴,18°C~26°C,空气质量良好"}
]
</conversation_history>
<instruction>请根据工具结果生成最终回复。</instruction>
</message>
LLM 响应:
xml
<thinking>
工具返回了北京天气详情:晴,18-26°C,空气质量良好。信息完整,可直接组织成自然语言回复用户。
</thinking>
<final_response>
北京今天晴,气温 18°C ~ 26°C,空气质量良好,非常适合户外活动!
</final_response>
第 3 轮:Host 返回给用户
Host → 用户:
北京今天晴,气温 18°C ~ 26°C,空气质量良好,非常适合户外活动!
4.4 流程复盘
| 步骤 | 角色 | 动作 | 关键内容 |
|---|---|---|---|
| ① | 用户 | 提问 | 自然语言 |
| ② | Host | 打包请求 | 对话历史 + 工具定义 + ReAct 指令 |
| ③ | LLM | 思考 + 决策 | <thinking> + <function_calls> |
| ④ | Host | 执行工具 | 调用 MCP Server 的 get_weather |
| ⑤ | Host | 回传结果 | 将工具结果追加到历史 |
| ⑥ | LLM | 再思考 + 最终回复 | <thinking> + <final_response> |
| ⑦ | Host | 返回给用户 | 最终回答 |
关键认知:LLM 从未直接接触 MCP 协议,它只看到 XML 格式的对话历史和工具定义。Host 完成了所有协议翻译和工具调度工作。
第五章:总结与认知
5.1 核心要点
-
Agent Host 是唯一的协议翻译者:
- 向下(工具层):通过 MCP 发现和调用工具(JSON-RPC)
- 向上(模型层):根据所选的实现路线(原生 Function Call 或 XML Prompt),将工具定义转换为 LLM 能理解的格式
-
两条路线,按需选择:
- 原生 Function Call:快速原型、标准应用、追求稳定性
- XML Prompt 驱动:高级 Agent(Claude Code/Cursor)、追求流式控制和思维链可见性
-
ReAct 模式是 Agent 推理的骨架:
- 每一步都包含"思考"(
<thinking>)和"行动"(<function_calls>或<final_response>) - 这种设计让 Agent 具备多步推理和错误恢复能力
- 每一步都包含"思考"(
-
MCP 提供工具,ReAct 提供决策:
- MCP 解决了"如何调用工具"的问题(标准化接入层)
- ReAct + XML 解决了"何时调用工具、如何决策"的问题(推理决策层)
5.2 从 MCP 到 Agent 的完整链路
用户提问
│
▼
┌──────────────────────────────────────────────────────────────┐
│ Agent Host(如 Claude Code) │
│ │
│ ① MCP 发现工具 ② 构建 ReAct Prompt │
│ ┌────────────┐ ┌───────────────────────────────────┐ │
│ │ tools/list │ │ System: 工具列表 + XML 格式要求 │ │
│ │ ◄── Tool[] │ │ User: 用户问题 │ │
│ └────────────┘ └───────────────────────────────────┘ │
│ │
│ ③ 发送 Prompt 给 LLM(纯文本,是否使用原生 tools 参数可选)│
│ ④ LLM 返回文本(含 XML 标签 或 原生 tool_calls 字段) │
│ ⑤ Host 解析决策(提取 XML 或反序列化 JSON) │
│ ⑥ 执行工具(MCP Client → tools/call) │
│ ⑦ 将工具结果追加到历史,重复③~⑥,直到 LLM 输出 final │
└──────────────────────────────────────────────────────────────┘
│
▼
最终回答
5.3 Agent 与普通聊天的本质区别
| 维度 | 普通聊天 | ReAct Agent |
|---|---|---|
| 输出内容 | 直接回答 | 思考 + 行动(工具调用或回答) |
| 交互轮次 | 单轮 | 多轮(思考-行动-观察循环) |
| 能力边界 | 固定(模型训练时学到的知识) | 可扩展(通过 MCP 接入任意工具) |
| 可解释性 | 低(无法追踪决策路径) | 高(<thinking> 暴露推理过程) |
| 错误恢复 | 无 | 可基于工具错误信息重新决策 |
5.4 生产环境最佳实践
① 系统提示词设计
系统提示词应明确声明:
- 模型的角色和职责
- 可用的工具列表(名称、描述、参数)
- 输出格式要求(XML 标签结构或 JSON 格式)
- ReAct 模式的执行规则
② 工具描述优化
工具描述直接影响 LLM 调用的准确性,建议:
description应包含"何时调用"的明确指引- 参数描述应说明格式和取值范围
- 示例优于抽象描述
③ 错误处理
Agent Host 应处理:
- 工具调用超时:设置合理超时,超时后向 LLM 返回错误消息
- 解析失败:要求 LLM 重新输出或返回友好错误
- 工具返回错误:将错误信息追加到对话历史,让 LLM 决定重试或降级
④ 对话历史管理
- 长对话应截断或摘要,避免超出上下文窗口
- 保留最近 N 轮推理-行动记录即可
- 工具返回的大文件内容应考虑摘要后再追加
5.5 未来演进方向
根据最新的 MCP 规范演进方向,Agent-LLM 交互协议也在持续发展:
- Tasks 扩展:支持长时间运行的工具调用,Agent 可在工具执行期间发送进度通知
- 无状态核心:简化 Host 实现,降低维护成本
- MCP Apps:为 Agent 带来 UI 交互能力,用户可在工具调用过程中提供实时反馈
这些变化将进一步增强 Agent 的自主性和交互性,但 ReAct 作为推理决策的核心模式,以及结构化输出(无论是 XML 还是 JSON)作为与 LLM 交互的主流方式,依然会保持其重要地位。
附录:Server-Side Sampling(已弃用)
A.1 什么是 Server-Side Sampling?
Server-Side Sampling 允许 MCP Server 通过 Client 向 Host 请求 LLM 采样。例如,一个代码分析 Server 可能需要 LLM 生成代码注释。这是 MCP 中为数不多的"反向"交互。
A.2 协议交互
Server 向 Client 发送 sampling/createMessage 请求:
json
{
"jsonrpc": "2.0",
"id": 1,
"method": "sampling/createMessage",
"params": {
"messages": [{"role": "user", "content": "请总结这段代码的功能"}],
"maxTokens": 500
}
}
Client(Host)将请求转发给 LLM,并将结果返回给 Server。
A.3 弃用说明
重要更新 :根据最新的 MCP 规范更新,Sampling 功能已被标记为 Deprecated(弃用)。其核心原因在于:
- 安全风险------恶意 Server 可能通过精心构造的提示词进行注入攻击,Host 难以完全防御
- 架构演进------MCP 趋向于更薄的协议层,让 Server 更独立,Server 应直接调用 LLM API,而非依赖 Host 中转
新实现不应采用此功能,现有实现应迁移到 Server 直接集成 LLM 提供商 API。
结语
Agent 与 LLM 的交互协议,决定了 Agent 能否高效、准确地完成复杂任务。理解并掌握这套协议,是构建可靠 AI Agent 系统的基础。
对于开发者而言,掌握这套协议意味着:
- 你能选择正确的实现路线:原生 Function Call 适合快速原型,XML Prompt 驱动适合追求极致流式控制和可观测性的生产级 Agent
- 你能更好地调试 Agent :通过
thinking标签追踪模型的推理路径,定位错误决策的根源 - 你能优化工具设计:精准的工具描述能显著提高模型调用的准确性,减少"幻觉调用"
- 你能理解性能瓶颈:多次推理的延迟累积、上下文窗口的限制,都需要在系统设计时仔细考量
从 MCP 的标准化工具接入,到 ReAct 的结构化推理决策,再到 XML 或 JSON 的结构化输出控制------这三个层次共同构成了现代 AI Agent 的技术基座。无论技术如何演进,理解并掌握这套核心交互协议,都是深入 Agent 开发领域的必修课。
本文基于 MCP 规范及主流 Agent 实现(Claude Code、Cursor、Aider)的最佳实践总结而成。