LLM 工具使用指南:从函数调用到代码执行与 MCP 标准
【Agent智能体专栏】第3篇:工具使用
摘要
LLM 不仅擅长对话,还能通过“工具使用”(Tool Use)主动调用外部函数,获取实时信息、执行计算、操作数据库,甚至编写并运行代码。本文系统讲解工具使用的核心原理:从 LLM 如何“请求”调用函数,到现代框架(如 AI Suite)的简洁实现;从基础的日历查询到危险的代码执行沙箱;最后介绍最新标准 MCP(模型上下文协议),它如何将工具生态从“M×N”的重复劳动转变为“M+N”的高效协作。无论你是 AI 应用开发者还是技术决策者,掌握工具使用都是构建真正“能做事”的代理的关键一步。
适用人群 / 前置知识
适用人群:希望让 LLM 与外部系统交互的 AI 应用开发者;对代理工作流感兴趣的技术人员;正在评估 LLM 工具调用能力的架构师。
前置知识:了解 LLM 基本 API 调用(如 OpenAI 格式);熟悉 Python 函数定义;知道什么是 JSON(用于理解工具描述)。无需深度机器学习背景。
正文
一、引言:为什么 LLM 需要“工具”?
大语言模型本质上是“知识固化”的系统。它知道的截止于训练数据,无法获取实时信息(如当前时间、最新股价),也无法主动采取行动(如发送邮件、修改日历)。但如果我们给 LLM 一套“工具”(即函数),让它自己决定何时调用,就能突破这些限制。
类比:人类用手只能抓起物品,但使用锤子就能钉钉子。LLM 单独只能生成文本,但使用工具就能执行动作。
工具使用的核心流程并不复杂:
- 开发者定义一些函数(如 get_current_time、send_email)。
- 将这些函数的名称、参数、描述告诉 LLM。
- LLM 根据用户问题,决定是否需要调用某个函数,并以特定格式输出“我想调用函数 X,参数为 Y”。
- 开发者解析该格式,实际执行函数,获取结果。
- 将结果返回给 LLM,让它生成最终回答。
下面我们深入每一步。
二、核心概念:LLM 如何“请求”调用函数?
很多人误以为 LLM 能直接执行代码。实际上,LLM 只是一个文本生成器。它无法运行任何东西。工具调用的真实流程是:
用户提问 → LLM 生成特殊标记(如 FUNCTION: get_current_time) → 开发者代码检测到该标记 → 开发者调用对应函数 → 将函数返回值拼接到对话中 → LLM 生成最终回答
2.1 早期手工方式(理解原理)
在 LLM 未被专门微调前,开发者需要手写提示词约定格式。例如:
System: 你可以使用工具 getCurrentTime。当你需要获取当前时间时,请输出 “FUNCTION: getCurrentTime”。
User: 现在几点?
Assistant: FUNCTION: getCurrentTime
然后开发者写正则表达式提取 getCurrentTime,执行函数,将结果(如“14:30”)追加为一条新消息:
User: 现在几点?
Assistant: FUNCTION: getCurrentTime
Function result: 14:30
Assistant: 现在是下午2点30分。
这种方法的缺点:脆弱、格式不统一、难以传递参数。
2.2 现代方式:工具调用 API
如今,主流 LLM(GPT-4、Claude 3、Gemini 等)原生支持工具调用。开发者只需按照 API 规范提供工具列表,LLM 会直接返回结构化的函数调用请求(JSON 格式),无需手动解析特殊字符串。
以 OpenAI 为例:
tools = [{
"type": "function",
"function": {
"name": "get_current_time",
"description": "获取当前时间",
"parameters": {
"type": "object",
"properties": {
"timezone": {"type": "string", "description": "时区,如 Asia/Shanghai"}
},
"required": ["timezone"]
}
}
}]
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "上海现在几点?"}],
tools=tools
)
#response 中会包含 tool_calls 字段,格式为 JSON
三、实战:使用 AI Suite 简化工具调用
AI Suite 是一个开源库,封装了多提供商的工具调用逻辑。你只需定义 Python 函数并编写 docstring,库会自动生成 JSON schema。
示例:无参数的当前时间
import datetime
from aisuite import Client
def get_current_time():
"""获取当前的 UTC 时间。"""
return datetime.datetime.now().isoformat()
client = Client()
response = client.chat.completions.create(
model="openai:gpt-4o",
messages=[{"role": "user", "content": "现在几点?"}],
tools=[get_current_time], # 直接传函数对象
max_turns=5
)
print(response.choices[0].message.content)
示例:带时区参数的函数
import pytz
def get_current_time_in_timezone(timezone: str):
"""
获取指定时区的当前时间。
Args:
timezone: 时区名称,例如 "America/New_York", "Pacific/Auckland"
"""
tz = pytz.timezone(timezone)
return datetime.datetime.now(tz).isoformat()
AI Suite 会自动从函数的签名和 docstring 中提取参数名称、类型和描述,构建 JSON schema 传给 LLM。LLM 返回的 tool_calls 中包含 arguments(如 {“timezone”: “Pacific/Auckland”}),库会自动调用你的函数并将结果返回。
四、进阶:代码执行工具——最强大的瑞士军刀
与其为每种计算(加、减、乘、除、平方根、指数、三角函数……)都单独写一个工具,不如给 LLM 一个“代码执行”工具。让 LLM 自己编写 Python 代码,然后运行它,获得结果。
工作流:
- 用户问:“2 的平方根是多少?”
- LLM 生成代码:import math; print(math.sqrt(2))
- 开发者执行这段代码(在安全沙箱中),得到 1.4142135623730951
- 将结果返回 LLM,LLM 回答:“2 的平方根大约是 1.4142。”
示例提示词设计:
System: 你可以编写 Python 代码来解决用户的问题。请将你的代码放在
<execute_python> 和 </execute_python> 标签之间。代码的输出将会被执行并返回给你。
User: 计算 500 美元本金,年利率 5%,10 年后的复利终值。
LLM 可能生成:
<execute_python>
principal = 500
rate = 0.05
years = 10
amount = principal * (1 + rate) ** years
print(amount)
</execute_python>
执行后得到 814.447…,最终回答:“10 年后您将拥有约 814.45 美元。”
4.1 安全警告:永远沙箱执行
真实事故:某团队使用自主编码代理,该代理主动执行了 os.remove(“star.py”),删除了项目文件。虽然有备份未造成损失,但警示我们:绝不能直接 exec() LLM 生成的代码。
最佳实践:
- 使用 Docker 容器隔离执行。
- 使用 E2B、CodeBox 等轻量级云沙箱。
- 限制可用的 Python 内置函数(如禁止 os、subprocess、eval、import)。
- 设置资源限制(CPU 时间、内存、网络)。
示例使用 subprocess 调用安全脚本:
import subprocess
result = subprocess.run(["python", "-c", code], capture_output=True, timeout=5, text=True)
五、生态革命:MCP(模型上下文协议)
当你的应用需要集成多个外部系统(Slack、Google Drive、GitHub、数据库)时,为每个系统编写适配器的工作量巨大。MCP 应运而生。
核心思想:将“工具/数据源”与“应用”解耦。
- MCP 服务器:提供一组标准化的工具和资源(例如 GitHub MCP 服务器提供
list_pull_requests、get_file_content 等工具)。 - MCP 客户端:应用通过 MCP 协议与服务器通信,无需关心底层 API。
传统模式:M 个应用 × N 个数据源 = M×N 个适配器。
MCP 模式:M 个应用 + N 个服务器 = M+N 个连接。
示例:使用 MCP 客户端查询 GitHub 仓库的最新 PR。
用户输入:“列出 AI Suite 仓库的最新 pull requests。”
MCP 客户端自动调用 GitHub MCP 服务器的 list_pull_requests 工具,传入参数 repo=“aisuite”,获取 PR 列表,再交给 LLM 生成总结。
目前已有大量 MCP 服务器可用:文件系统、PostgreSQL、Slack、Google Drive、Brave 搜索等。你也可以编写自己的 MCP 服务器,将内部 API 暴露给任意 LLM 应用。
六、常见问题与注意事项
| 问题 | 解决方案 |
|---|---|
| LLM 调用错误的工具 | 提高工具描述质量;使用更强大的模型(如 GPT-4o 或 Claude 3.5 Sonnet) |
| 工具调用陷入循环 | 设置 max_turns(如 5)强制终止 |
| 代码执行安全风险 | 使用 Docker/E2B 沙箱;禁用危险模块;限制网络访问 |
| 时区/实时数据不准 | 让 LLM 通过工具获取,而不是依赖模型内部知识 |
| 工具参数缺失 | 在函数描述中明确参数是否必需;LLM 会要求用户补充信息 |
七、总结
工具使用是 LLM 从“聊天机器人”进化为“代理”的核心能力。通过赋予 LLM 一组精心设计的函数,它能够:
- 获取实时信息(时间、天气、股价)
- 操作外部系统(发送邮件、修改日历、查询数据库)
- 执行任意计算(通过编写代码)
现代 API 和开源库(如 AI Suite)极大地简化了实现。而 MCP 标准则正在重塑整个工具生态,让开发者能像“插拔”一样集成海量工具。
最后,永远记住:让 LLM 执行代码时,务必使用沙箱。安全是生产级应用的生命线。
下一步,你可以尝试在自己的项目中实现一个简单的工具调用——比如给 LLM 一个天气查询函数,然后问“明天北京会下雨吗?” 你会惊讶于它如何自主决定调用工具并给出答案。
更多推荐
所有评论(0)