智能体工具调用的实现方式(Function Calling和MCP)
前言
智能体(AI Agent)本身运行在云端或受控的沙箱环境中,出于安全考虑,它不能直接访问或执行你本地电脑上的程序(如打开计算器、读取本地文件、运行 Python 脚本等)。
要实现“调用本地程序”,必须通过一个中间桥梁。
这个桥梁通常是一个运行在你本地电脑上的客户端程序或服务。
核心机制是:Function Calling (函数调用) + 本地服务器/代理。
智能体(AI Agent)本身运行在云端或受控的沙箱环境中,出于安全考虑,它不能直接访问或执行你本地电脑上的程序(如打开计算器、读取本地文件、运行 Python 脚本等)。
要实现“调用本地程序”,必须通过一个中间桥梁。这个桥梁通常是一个运行在你本地电脑上的客户端程序或服务。
核心机制是:Function Calling (函数调用) + 本地服务器/代理。
以下是具体的实现流程和三种主流方案:
核心流程
它是如何工作的?
- 定义工具 (Define Tools):
开发者在代码中定义一个“工具”(Tool/Function),告诉大模型:“我有一个叫run_local_script的功能,你可以调用它,需要传入参数script_name。”
注意:此时大模型只知道有这个功能,但还不知道怎么执行。 - 模型决策 (Decision):
当你问智能体:“帮我运行本地的backup.py脚本”,大模型分析后决定:“我需要调用run_local_script工具”,并生成一个结构化的调用请求(通常是 JSON 格式),包含函数名和参数。 - 拦截与转发 (Intercept & Forward):
你的应用程序(宿主代码)接收到这个大模型的调用请求。它不会让大模型直接执行,而是由本地代码去执行真正的逻辑。 - 本地执行 (Local Execution):
本地代码(运行在你的电脑上)收到指令,使用系统命令(如 Python 的subprocess、Node.js 的child_process)真正地去启动那个本地程序。 - 返回结果 (Return Result):
本地程序运行完毕,将输出结果(stdout)或错误信息返回给宿主代码,宿主代码再将其格式化后发给大模型。大模型根据结果回答你:“脚本运行成功,备份已完成。”
三种主流实现方案
使用 Function Calling
这是最基础也是最灵活的方式,适用于你自己开发的应用。
原理:你在本地写一个后端服务(Python/Node.js等),将本地程序封装成 API 或函数,并通过 SDK 注册给大模型。
流程:
- 注册:在代码中定义
tools列表,描述函数签名。 - 循环:
- 发送用户问题 + tools 定义给 LLM。
- LLM 返回
{"name": "open_app", "arguments": {"app": "notepad"}}。 - 你的代码检测到这个请求,执行
subprocess.run(["notepad.exe"])。 - 将执行结果返回给 LLM。
- 注册:在代码中定义
适用场景:构建专属的桌面助手、自动化运维脚本。
代码逻辑示例 (Python):
1 | # 伪代码逻辑 |
使用 MCP
MCP (Model Context Protocol) 是最近兴起的一个开放标准,专门用于解决 AI 模型连接本地数据和工具的问题。
- 原理:MCP 定义了一套标准协议。你只需要在本地运行一个 MCP Server(它可以是任何语言写的),这个 Server 负责暴露本地资源(文件系统、数据库、本地命令行工具)。支持 MCP 的 AI 客户端(如 Cursor, Claude Desktop, 或自研 Agent)会自动连接这个本地 Server。
- 优势:解耦。你不需要为每个 AI 应用重写连接代码,只要写好 MCP Server,任何支持 MCP 的客户端都能调用你的本地程序。
- 如何调用本地程序:
- 编写一个 MCP Server(例如用 TypeScript 或 Python)。
- 在 Server 中定义一个 Tool,内部逻辑调用
child_process执行本地命令。 - 在 AI 客户端配置中指向这个 Server。
- AI 自动发现该工具并调用。
本地代理模式 (Local Proxy / Sidecar)
很多现成的桌面端 AI 软件(如某些本地运行的 LLM 启动器)采用这种模式。
- 原理:软件在安装时会在本地启动一个微型 HTTP 服务器(Sidecar)。
- 流程:
- AI 模型(云端或本地)认为它在调用一个远程 API。
- 实际上,这个 API 的地址是
http://localhost:8080/execute。 - 请求发送到本地端口,本地服务接收后执行系统命令。
- 适用场景:开源项目(如 Open Interpreter, Dify 本地版),它们通常自带这种机制来执行代码。
Function Calling原理
在使用 vLLM 启用工具调用(Tool Calling)功能时,“能调用哪些工具”并不是由 vLLM 本身决定的,而是由你在发起 API 请求时动态传入的 tools 列表定义的。
vLLM 的作用是:解析模型输出,并按照你指定的格式(如 OpenAI 协议)返回结构化的工具调用信息。
请求示例
POST http://localhost:8000/v1/chat/completions
1 | { |
注意
每次请求都要把要使用的工具放在请求中。
核心属性是
"tool_choice": "auto"和tools工具的选择是模型依赖
description属性进行推断。
返回的数据是怎样使用的呢?
我们在模型启动的时候会添加类似这样的参数
1 | --enable-auto-tool-choice --tool-call-parser qwen3_coder |
并且在 API 请求中传入了 tools 和 tool_choice=”auto”,那么当模型判断需要调用工具时,其返回的数据结构将遵循 OpenAI Chat Completions API 的 Tool Calling 格式。
--tool-call-parser的作用就是大模型把返回的数据转为OpenAI Chat Completions API 的 Tool Calling 对应的JSON格式。
1 | { |
这样处理逻辑就能调用了
1 | # 提取工具调用 |
MCP的原理
MCP(Model Context Protocol,模型上下文协议)服务被大模型“发现”的过程,并不是由大模型主动扫描网络或注册中心,而是通过客户端(AI Agent 或 MCP 客户端)在运行时动态获取工具列表,并将这些能力以结构化提示词(Prompt)的形式注入给大模型,从而让大模型“知道”有哪些外部工具可用。整个过程是客户端驱动、协议标准化、提示工程引导的协同机制。
下面从三个核心阶段详细说明 MCP 服务如何被大模型“发现”:
核心阶段
阶段一:获取工具清单
客户端连接 MCP 服务器,获取工具清单(Tool Discovery)
这是“发现”的起点,但发现者是客户端,不是大模型本身。
用户或系统配置好一个或多个 MCP 服务器地址(如 https://mcp.amap.com)。
客户端(如 Cursor、Claude Desktop、Azure AI Agent 等)在会话开始前或需要时,向 MCP 服务器发送 /tools/list 请求(通常为 HTTP GET 或 SSE 连接)。
1 | GET https://mcp.amap.com/tools/list |
MCP 服务器返回一个 JSON 格式的工具清单,包含每个工具的:
name(唯一标识)description(功能描述)inputSchema或parameters(参数结构,符合 JSON Schema)
示例响应:
1 | { |
✅ 此时,客户端拥有了“服务菜单”,但大模型对此仍一无所知。
阶段二:合成提示词
客户端将工具信息注入 Prompt,引导大模型决策
这是“发现”对大模型生效的关键环节——通过提示词工程(Prompt Engineering)实现能力透传。
客户端将上一步获取的工具列表,格式化后嵌入到系统提示词(System Prompt)中,与用户问题一起发送给大模型 。
例如,构造如下 Prompt:
1 | 你是一个智能助手,可以使用以下工具帮助用户: |
或者使用 OpenAI 兼容的 tools 字段(在支持的平台如阿里云百炼中):
1 | { |
注意
大模型本身不具备主动发现能力,它只是在看到这个“菜单”后,基于语义理解判断是否需要调用某个工具 。
阶段三:客户端执行
大模型输出结构化指令,客户端执行调用
大模型分析用户问题(如“北京天气怎么样?”),匹配工具描述,决定调用
get_weather。它不直接执行操作,而是输出一个严格格式化的调用指令(XML 或 JSON)。
例如:
1
2
3
4<use_mcp_tool>
<tool_name>get_weather</tool_name>
<arguments>{"city": "北京"}</arguments>
</use_mcp_tool>客户端解析该指令,提取
tool_name和arguments,向对应的 MCP 服务器发起/tools/call请求 。MCP 服务器执行实际逻辑(如调用高德天气 API),返回结构化结果。
客户端将结果再次送回大模型,生成最终自然语言回复。
请求的格式
/tools/call 是 MCP(Model Context Protocol) 协议中用于客户端调用 MCP 服务端工具的标准接口。
其请求参数格式是严格定义的 JSON 结构,旨在确保跨平台、跨语言的互操作性。
标准请求格式(HTTP POST)
1 | POST /tools/call |
请求体(Request Body):
1 | { |
字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
tool_name |
string | ✅ 是 | 工具的唯一名称,必须与 MCP Server 通过 /tools/list 返回的 name 完全一致 |
arguments |
object | ✅ 是 | 调用该工具所需的参数对象,结构必须符合该工具在 /tools/list 中声明的 inputSchema 或 parameters |
⚠️ 注意:
arguments不是字符串,而是原生 JSON 对象(与 OpenAI Function Calling 的arguments字符串不同)。- 参数名和类型必须严格匹配工具定义,否则 MCP Server 应返回错误。
完整示例
- 假设 MCP Server 的
/tools/list返回:
1 | { |
- 客户端调用
/tools/call:
1 | { |
- MCP Server 成功响应(200 OK):
1 | { |
- 若参数错误(如缺少
query),应返回 400 错误:
1 | { |
与 OpenAI Function Calling 的关键区别
| 特性 | OpenAI Function Calling | MCP /tools/call |
|---|---|---|
arguments 格式 |
字符串(JSON-encoded) | 原生 JSON 对象 |
| 调用发起方 | 大模型生成 → 客户端解析执行 | 客户端直接构造调用 |
| 协议层级 | 模型 API 层 | 独立服务协议层 |
| 调用方式 | LLM 输出调用指令 | 客户端直接调用 |
注意:
在 MCP 架构中,大模型只负责决策是否调用及生成参数语义,而参数构造和网络调用由客户端完成,因此
arguments是结构化对象而非字符串。
安全与扩展字段(可选)
部分 MCP 实现可能支持额外字段,如:
1 | { |
但这些属于非标准扩展,使用前需确认 MCP Server 是否支持。
总结
MCP /tools/call 的标准参数格式为:
1 | { |
它强调结构化、类型安全、与模型解耦,是构建可靠 AI Agent 工具链的核心接口 。
MCP 服务的注册与集中发现机制
虽然单次调用依赖客户端传入,但生态层面已有集中式注册表,便于开发者查找和集成 MCP 服务:
- GitHub MCP Registry
GitHub 官方推出的 MCP 服务器目录,自动聚合托管在 GitHub 上的 MCP 项目,按 Star 数、活跃度排序,支持一键安装 。 - AIbase MCP 服务库
提供超过 12 万个 MCP 服务的排行榜,支持按流行度、更新时间、功能类型筛选,降低选型成本 。 - Azure API 中心
企业可在 API 清单中注册远程 MCP 服务器,并通过 Foundry 工具目录供 AI Agent 发现 。
这些平台解决的是“人类开发者如何找到 MCP 服务”的问题,而非大模型自动发现。
总结
MCP 服务被“发现”的本质
| 角色 | 职责 |
|---|---|
| MCP 服务器 | 托管工具,提供 /tools/list 和 /tools/call 接口 |
| 客户端(Agent) | 主动连接 MCP 服务,获取工具列表,注入 Prompt,解析并执行调用 |
| 大模型(LLM) | 被动接收工具信息,在 Prompt 引导下决策是否调用,输出结构化指令 |
大模型并不“主动发现”MCP 服务,而是通过客户端提供的上下文“被告知”有哪些工具可用。
这种设计实现了解耦、安全、灵活的工具扩展机制,是 MCP 协议的核心优势之一 。
因此,MCP 的“发现”本质上是 客户端驱动的动态工具注入 + 大模型的条件性调用,而非传统意义上的服务注册与自动发现。