导读
如果你曾经尝试过让大模型(LLM)帮你查天气、订机票或操作数据库,你多半已经接触过"Function Call"技术。但你是否真正理解它的底层逻辑?当听到 MCP 和 A2A 这些新概念时,你是否感到困惑?
本文将带你深入理解 AI Agent 工具调用的核心技术,从最基础的 Function Call 原理讲起,逐步演进到 LangChain 框架的封装,最后解析 MCP 和 A2A 这两项前沿协议。读完本文,你将不仅理解“如何调用”,更能看清“调用什么”和“谁来调用”的全貌。

一、Function Call: 最容易被误解的技术
1.1 一个常见的认知误区
很多人认为 Function Call 就是"大模型自己去调用工具"。这个说法只对了一半。
大模型本身并不执行任何代码,它只负责"决策"——输出一个结构化的指令。真正的"调用"动作,必须由你的应用程序 (宿主代码) 来完成。
这个认知偏差源于 OpenAI 等官方 SDK 封装得过于"丝滑",让开发者误以为一次 API 调用就完成了所有事情。实际上,在那些看似简单的 API 背后,隐藏着严格分离的职责边界。
1.2 Function Call 的完整四步流程
为了清晰理解,我们把一次完整的 Function Call 拆解为四个标准步骤:
第一步:注册工具
你将工具的名称、功能描述以及参数结构(JSON Schema)放入系统提示词或 API 的 tools 参数中。这相当于告诉大模型:“我有这些工具可用,它们各自做什么,需要什么参数。”
第二步:大模型决策
收到用户问题后,大模型不会直接回答。如果它判断需要借助工具,就会输出一个结构化的 JSON 对象,其中明确包含 tool_name(工具名) 和 parameters(参数值)。
第三步:宿主代码执行
这是最关键的一步。你的后端代码监听到大模型输出的 JSON 后,通过 if 判断或 switch 结构,由你的代码去真正执行对应的函数。大模型全程没有执行任何代码,它只是给出了指令。
第四步:结果回传与最终回复
你把执行获得的真实数据再次发给大模型,大模型基于这些数据生成最终的自然语言回复,呈现给用户。

1.3 代码示例:原生调用
下面是一段使用 OpenAI SDK 的原生调用代码,请注意"决策"与"执行"的分界线:
import json
from openai import OpenAI
client = OpenAI(api_key="你的 API_KEY")
# 真实的工具函数 (由你的代码执行)
def get_weather(city: str) -> str:
weather_db = {"北京": "晴天 25°C", "上海": "小雨 22°C", "吉林市": "大雪 -20°C"}
return weather_db.get(city, "未知城市天气")
# 注册工具
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的实时天气状况",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名称"}
},
"required": ["city"]
}
}
}]
messages = [{"role": "user", "content": "吉林市现在天气怎么样?"}]
# 第一次调用:让大模型决策
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
tool_choice="auto"
)
response_message = response.choices[0].message
if response_message.tool_calls:
tool_call = response_message.tool_calls[0]
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
print(f"🤖 大模型决策:调用 '{function_name}',参数 {function_args}")
# ⭐️ 关键分界线:此处由宿主代码真正执行
real_result = get_weather(**function_args)
print(f"💻 宿主代码执行结果:{real_result}")
# 回传结果,生成最终回答
messages.append(response_message)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": real_result
})
final_response = client.chat.completions.create(
model="gpt-4o",
messages=messages
)
print("🗣️ 最终回答:", final_response.choices[0].message.content)
输出结果清晰地展示了决策与执行的分离:
🤖 大模型决策:调用 'get_weather',参数 {'city': '吉林市'}
💻 宿主代码执行结果:大雪 -20°C
🗣️ 最终回答:吉林市现在是大雪天气,气温低至零下 20°C,请注意保暖!
二、LangChain: 让事情变得更简单
2.1 封装了什么?
直接使用原生 API 时,你需要手动编写大量"胶水代码":解析 JSON、执行函数、判断是否再次调用、回传结果……这些重复劳动占据了大量开发时间。
LangChain 的 bind_tools() 和 invoke() 方法将这些步骤全部封装起来,你只需关注核心业务逻辑 (工具函数本身),框架自动处理了"决策 - 执行 - 回传"的完整循环。
2.2 代码对比
使用 LangChain 实现同样的功能,代码大幅精简:
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage
@tool
def get_weather(city: str) -> str:
"""查询指定城市的实时天气状况"""
weather_db = {"北京": "晴天 25°C", "上海": "小雨 22°C", "吉林市": "大雪 -20°C"}
return weather_db.get(city, "未知城市天气")
model = ChatOpenAI(model="gpt-4o").bind_tools([get_weather])
messages = [HumanMessage(content="吉林市现在天气怎么样?")]
response = model.invoke(messages)
print(response.content) # 直接获得最终回答
2.3 便捷与控制的权衡
LangChain 的简化带来的好处显而易见:
- 自动处理工具格式:
@tool装饰器和bind_tools()自动完成 JSON Schema 转换 - 自动执行循环: 无需手动编写 while 循环和 if 判断
- 代码量大幅减少: 聚焦业务逻辑而非框架代码
但也要注意权衡:
- 灵活性降低:精细控制每一步 (如自定义重试、超时、流式处理) 时较为受限
- 调试难度增加:错误可能被多层封装隐藏,定位不如原生调用直观
选择 LangChain,本质上是选择用"便捷性"交换"控制权"。
三、MCP: 让工具调用标准化
3.1 为什么需要 MCP?
在 MCP 出现之前,每个 AI 框架都有自己定义工具的方式。如果你想在 LangChain 中调用一个工具,需要按 LangChain 的格式写;换到别的框架,又得重新适配一遍。这导致了大量的重复劳动和生态割裂。
MCP(Model Context Protocol) 由 Anthropic 提出,旨在解决这个问题。它定义了一个标准化的工具接入协议,让 AI 应用可以像使用 USB 设备一样,即插即用地接入任何遵循 MCP 标准的工具服务器。
如果说 Function Call 解决的是"如何调用"的问题,那么 MCP 解决的就是"调用什么"的问题——它为工具提供了统一的接口规范。
3.2 在 LangChain 中使用 MCP
LangChain 官方提供了 langchain-mcp-adapters 库来支持 MCP:
import asyncio
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent
async def main():
client = MultiServerMCPClient({
"math": { # 数学计算 MCP 服务器
"transport": "stdio",
"command": "python",
"args": ["/path/to/math_server.py"],
},
"weather": { # 天气查询 MCP 服务器
"transport": "http",
"url": "http://localhost:8000/mcp",
},
})
tools = await client.get_tools() # 统一加载所有工具
agent = create_agent("claude-sonnet-4-6", tools)
response = await agent.ainvoke(
{"messages": [{"role": "user", "content": "计算 (3+5)x12"}]}
)
Agent 可以无缝调用来自不同 MCP 服务器的工具,完全不需要关心它们背后的实现差异。
3.3 MCP 的核心价值
- 生态互通: 同一个工具服务器可以被任何支持 MCP 的 AI 框架使用
- 标准化接入: 工具开发者只需实现一次 MCP 接口,即可被所有 AI 应用调用
- 去中心化: 任何人都可以发布 MCP 服务器,丰富 AI 工具生态
四、A2A: 让智能体相互协作
4.1 单 Agent 的局限与多 Agent 的挑战
单个 Agent 的能力终究有限。当任务复杂到一定程度 (如"规划一次跨国旅行并预订所有行程"),可能需要多个专业 Agent 分工协作:一个负责订机票,一个负责订酒店,一个负责制定行程路线。
但问题来了:不同框架开发的 Agent 如何相互通信?如何协调分工?
A2A(Agent-to-Agent Protocol) 由 Google 提出,正是为了解决这个问题。它定义了一套智能体之间标准化通信的协议,让不同来源、不同框架的 AI 代理能够像人类同事一样相互对话、协作完成任务。
4.2 LangChain 中的 A2A 支持
在 LangChain 生态中,A2A 的支持主要体现在LangSmith 的 Agent Server中。你可以将一个 LangGraph Agent 部署为 A2A 服务器,它就能通过标准化的 JSON-RPC 2.0 协议与其他 A2A 兼容的 Agent 对话。
一次典型的 A2A 调用请求如下:
curl --request POST \
--url https://api.example.com/a2a/{assistant_id} \
--header 'Content-Type: application/json' \
--data '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/send",
"params": {
"message": {
"role": "user",
"parts": [{"kind": "text", "text": "请帮我查询明天的航班"}],
"messageId": "msg-1"
}
}
}'
4.3 A2A 的核心价值
- 跨框架协作: 用 LangChain 开发的 Agent 可以与用其他框架开发的 Agent 协同工作
- 任务分解: 复杂任务可以被自动分解给多个专业 Agent
- 标准化生态: 为多智能体系统提供了统一的通信语言
五、完整图景:从调用到生态
回顾整个技术演进路径,我们可以清晰地看到一条主线:
| 层次 | 技术 | 解决的核心问题 |
|---|---|---|
| 调用层 | Function Call | 如何让大模型"调用"外部工具 |
| 封装层 | LangChain | 如何简化调用的工程复杂度 |
| 接入层 | MCP | 工具如何标准化接入 (调用什么) |
| 协作层 | A2A | 智能体之间如何协作 (谁来调用) |

Function Call 是技术地基,解决的是"如何调用"的工程问题。
LangChain 是工程封装,让开发者从重复劳动中解放出来。
MCP 是协议延伸,让工具接入走向标准化、生态化。
A2A 是架构升级,让多智能体协作成为可能。
这四个层次共同构建了当今 AI Agent 技术栈的完整图景。理解它们之间的关系,不仅能帮助你更好地选择技术方案,也能让你更清晰地看到这个领域未来的演进方向。
结语
从最基础的 Function Call 到 LangChain 的便捷封装,再到 MCP 和 A2A 这两项前沿协议,AI Agent 工具调用技术正在经历从"能用"到"好用"再到"互联互通"的快速演进。
作为开发者,理解 Function Call 的底层原理能让你在调试时更从容;善用 LangChain 能让你在开发时更高效;关注 MCP 和 A2A 能让你在架构设计时更有前瞻性。