【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 单独只能生成文本,但使用工具就能执行动作。

工具使用的核心流程并不复杂:

  1. 开发者定义一些函数(如 get_current_time、send_email)。
  2. 将这些函数的名称、参数、描述告诉 LLM。
  3. LLM 根据用户问题,决定是否需要调用某个函数,并以特定格式输出“我想调用函数 X,参数为 Y”。
  4. 开发者解析该格式,实际执行函数,获取结果。
  5. 将结果返回给 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 代码,然后运行它,获得结果。

工作流:

  1. 用户问:“2 的平方根是多少?”
  2. LLM 生成代码:import math; print(math.sqrt(2))
  3. 开发者执行这段代码(在安全沙箱中),得到 1.4142135623730951
  4. 将结果返回 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 生成的代码

最佳实践

  1. 使用 Docker 容器隔离执行。
  2. 使用 E2B、CodeBox 等轻量级云沙箱。
  3. 限制可用的 Python 内置函数(如禁止 os、subprocess、eval、import)。
  4. 设置资源限制(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 一个天气查询函数,然后问“明天北京会下雨吗?” 你会惊讶于它如何自主决定调用工具并给出答案。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐