大模型工具调用从入门到实战(1)

让 AI 学会动手

摘要:Tool Calling(工具调用/函数调用)是 LLM 应用开发中最关键的进阶能力之一。它让大模型不再只会「动嘴」,而是能真正「动手」------查数据库、调 API、发邮件、执行本地命令。本文从零讲解工具调用的工作机制,分别使用 OpenAI SDK 和 Anthropic SDK 提供完整可运行的 Python 代码示例,帮你迈出 AI Agent 开发的第一步。

一、引言

大语言模型非常强大,但它们有一个本质局限:模型的知识是静态的。GPT-4 的训练数据截止于 2023 年底,它不知道今天的天气、查不到你的数据库记录、也发不了邮件。

如果想让 AI 帮你处理实际工作,它必须能够与外部世界交互。这就是 Tool Calling 要解决的问题。

读完这篇文章,你将收获:

  1. 理解 Tool Calling 的完整工作流程
  2. 能用 OpenAI SDK 实现一个带工具调用的 AI 助手
  3. 能用 Anthropic SDK 实现同样的功能
  4. 掌握并行工具调用、结果传回等进阶技巧
  5. 理解何时使用、何时不使用工具调用

谁该读:有 Python 基础,了解 LLM API 基本用法,想开发 AI Agent 应用的开发者。

二、什么是 Tool Calling

2.1 一个直观的例子

假设你问一个普通的大模型:「北京今天天气怎么样?」

它只能回答:「我无法获取实时天气数据,建议你查看天气 App。」

但如果给模型配置了一个 get_weather 工具,整个对话会变成这样:

复制代码
用户: "北京今天天气怎么样?"
  ↓
模型: [不会直接回答,而是返回一个 tool_call]
      { "name": "get_weather", "arguments": { "city": "北京" } }
  ↓
你的代码: 调用真实的天气 API,得到结果 28°C
  ↓
模型: "北京今天晴天,气温 28°C,适合出行。"

这就是 Tool Calling 的核心------模型不执行工具,它只是「提议」调用哪个工具,真正执行的是你的代码。

2.2 完整工作流程

复制代码
用户消息 → 模型分析 → 模型返回 tool_call
                              ↓
                    你的代码执行工具
                              ↓
                    结果发回给模型
                              ↓
           模型基于结果生成最终回复 → 返回用户

Tool Calling 循环的时序图:
外部工具/API 你的代码 LLM 模型 用户 外部工具/API 你的代码 LLM 模型 用户 "北京今天天气怎么样?" 返回 tool_call: get_weather(city="北京") 调用天气 API {"temp": 28, "condition": "晴天"} 传回 tool_result(天气数据) "北京今天晴天,气温 28°C"

关键点:

  • 模型不会自动调用工具,它只输出一个结构化的调用请求
  • 你的代码负责执行,并将结果传回模型
  • 这个过程可以循环多次(一次对话中调用多个工具)

2.3 与普通 API 调用的区别

特性 普通聊天 Tool Calling
模型输出 纯文本 文本 或 结构化工具调用
交互次数 一次请求 → 一次回复 可能多轮:请求→调用→执行→结果→回复
外部能力 查数据库、调 API、操作文件等
代码复杂度 中等,需要工具调度循环

三、核心概念:Tool Definition

无论使用哪个 SDK,定义一个工具都需要三个要素:

3.1 工具的三要素

python 复制代码
# 一个典型的工具定义(伪代码概念版)
tool = {
    "name": "get_weather",           # ① 工具名:唯一标识
    "description": "获取指定城市的天气",  # ② 描述:告诉模型这工具是干嘛的
    "parameters": {                   # ③ 参数定义:JSON Schema 格式
        "type": "object",
        "properties": {
            "city": {
                "type": "string",
                "description": "城市名称,如'北京'、'tokyo'"
            }
        },
        "required": ["city"]
    }
}

description 是整个工具定义中最重要的字段。模型就是靠读这段描述来决定「该不该用这个工具」。描述写得不好,模型要么不调用,要么乱传参数。

3.2 什么是好的描述

好的描述应该:

  • 说清楚功能:「获取指定城市今天的实时天气信息,包括温度、湿度、天气状况」
  • 说清楚使用时机:「当用户询问某地当前天气时使用此工具」
  • 说清楚限制:「仅支持城市级别查询,不支持区县级」

差的描述:「查询天气」------模型根本不知道什么时候该用。

四、实战:OpenAI SDK 实现

4.1 环境准备

bash 复制代码
$ pip install openai

确保你有 OpenAI API Key,建议使用环境变量:

bash 复制代码
$ export OPENAI_API_KEY="sk-xxx"

4.2 定义工具

python 复制代码
# 模拟的天气查询函数
def get_weather(city: str) -> dict:
    """实际项目中替换为真实 API 调用"""
    # 这是模拟数据
    weather_data = {
        "北京": {"temperature": 28, "condition": "晴天", "humidity": "45%"},
        "上海": {"temperature": 32, "condition": "多云", "humidity": "70%"},
        "tokyo": {"temperature": 25, "condition": "小雨", "humidity": "80%"},
    }
    return weather_data.get(city, {"error": f"未找到 {city} 的天气数据"})

# 工具定义 ------ JSON Schema 格式
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "获取指定城市今天的实时天气信息,包括温度、天气状况和湿度。当用户询问某地天气时使用此工具。",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "城市名称,中文或英文。例如:'北京'、'上海'、'tokyo'",
                    }
                },
                "required": ["city"],
            },
        },
    }
]

4.3 工具调用循环

python 复制代码
import json
from openai import OpenAI

client = OpenAI()

def run_conversation(user_message: str):
    messages = [{"role": "user", "content": user_message}]

    # 第一轮:发送用户消息 + 工具定义
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        tools=tools,
    )

    response_message = response.choices[0].message

    # 检查模型是否想调用工具
    if response_message.tool_calls:
        # 将模型的回复加入对话历史
        messages.append(response_message)

        for tool_call in response_message.tool_calls:
            function_name = tool_call.function.name
            function_args = json.loads(tool_call.function.arguments)

            # 执行对应的函数
            if function_name == "get_weather":
                result = get_weather(function_args["city"])
            else:
                result = {"error": f"未知工具: {function_name}"}

            # 将执行结果加入对话
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": json.dumps(result, ensure_ascii=False),
            })

        # 第二轮:把结果发回模型,生成最终回复
        final_response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
        )
        return final_response.choices[0].message.content

    # 模型不需要工具,直接返回文本
    return response_message.content


# 测试
print(run_conversation("北京今天天气怎么样?"))
# 输出: 北京今天晴天,气温 28°C,湿度 45%,适合出行。

4.4 OpenAI 并行工具调用

OpenAI 支持在一次响应中返回多个 tool_calls,当用户说「查一下北京和上海的天气」时,模型会同时提议调用两次 get_weather

python 复制代码
# 并行工具调用示例
def run_with_parallel_tools(user_message: str):
    messages = [{"role": "user", "content": user_message}]

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        tools=tools,
    )

    response_message = response.choices[0].message

    if response_message.tool_calls:
        messages.append(response_message)

        # 并行执行所有工具调用
        for tool_call in response_message.tool_calls:
            function_name = tool_call.function.name
            function_args = json.loads(tool_call.function.arguments)

            if function_name == "get_weather":
                result = get_weather(function_args["city"])
            else:
                result = {"error": f"未知工具: {function_name}"}

            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": json.dumps(result, ensure_ascii=False),
            })

        final_response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
        )
        return final_response.choices[0].message.content

    return response_message.content


print(run_with_parallel_tools("北京和上海的天气分别怎么样?"))
# 模型会并行调用 get_weather("北京") 和 get_weather("上海")
# 输出: 北京今天晴天,28°C;上海今天多云,32°C。

五、实战:Anthropic SDK 实现

Anthropic(Claude)的工具调用在设计哲学上与 OpenAI 不同。OpenAI 强调并行执行,Anthropic 强调工具使用的深度集成到对话流中。

5.1 环境准备

bash 复制代码
$ pip install anthropic
bash 复制代码
$ export ANTHROPIC_API_KEY="sk-ant-xxx"

5.2 定义工具

python 复制代码
import anthropic

client = anthropic.Anthropic()

# Anthropic 的工具定义格式
tools = [
    {
        "name": "get_weather",
        "description": "获取指定城市今天的实时天气信息,包括温度、天气状况和湿度。当用户询问某地天气时使用此工具。",
        "input_schema": {  # 注意:Anthropic 用 input_schema,OpenAI 用 parameters
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "城市名称,中文或英文。例如:'北京'、'上海'、'tokyo'",
                }
            },
            "required": ["city"],
        },
    }
]

Agent 循环流程(Anthropic SDK 版本):


用户消息 + 工具定义
调用 messages.create()
响应中有 tool_use 块?
返回文本回复给用户
提取所有 tool_use blocks
执行对应的工具函数
构造 tool_result 并加入对话

5.3 工具调用循环

python 复制代码
import json

def run_conversation_anthropic(user_message: str):
    messages = [{"role": "user", "content": user_message}]

    while True:
        response = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=1024,
            messages=messages,
            tools=tools,
        )

        # 检查响应中是否包含 tool_use 块
        tool_use_blocks = [
            block for block in response.content if block.type == "tool_use"
        ]

        if not tool_use_blocks:
            # 模型直接返回了文本,没有工具调用
            return response.content[0].text

        # 将模型回复加入对话
        messages.append({"role": "assistant", "content": response.content})

        # 执行每个工具调用
        tool_results = []
        for tool_block in tool_use_blocks:
            function_name = tool_block.name
            function_args = tool_block.input  # Anthropic 直接返回 dict,无需 json.loads

            if function_name == "get_weather":
                result = get_weather(function_args["city"])
            else:
                result = {"error": f"未知工具: {function_name}"}

            tool_results.append({
                "type": "tool_result",
                "tool_use_id": tool_block.id,
                "content": json.dumps(result, ensure_ascii=False),
            })

        messages.append({"role": "user", "content": tool_results})
        # 循环继续,直到模型不再返回 tool_use


print(run_conversation_anthropic("北京今天天气怎么样?"))

5.4 OpenAI vs Anthropic 关键差异速览

对比点 OpenAI Anthropic
参数定义字段 parameters input_schema
调用返回格式 tool_calls 数组 tool_use content block
参数解析 json.loads(tool_call.function.arguments) tool_block.input 直接是 dict
结果回传角色 role: "tool" role: "user"
并行调用 一次请求可返回多个 tool_call 一次返回多个 tool_use block
流式处理 支持 支持(逐 token 增量)
tool_choice "none"/"auto"/"required" tool_choice 参数,支持 "any"/"auto"/tool

六、进阶:多工具协作

一个真正的 AI Agent 通常需要多个工具协作。比如一个「智能客服助手」可能需要:

python 复制代码
tools = [
    {
        "type": "function",
        "function": {
            "name": "query_order",
            "description": "根据订单号查询订单状态和详情",
            "parameters": {
                "type": "object",
                "properties": {
                    "order_id": {
                        "type": "string",
                        "description": "订单号,格式如 ORD-20231201-001"
                    }
                },
                "required": ["order_id"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "send_email",
            "description": "发送邮件给指定收件人",
            "parameters": {
                "type": "object",
                "properties": {
                    "to": {"type": "string", "description": "收件人邮箱"},
                    "subject": {"type": "string", "description": "邮件主题"},
                    "body": {"type": "string", "description": "邮件正文"},
                },
                "required": ["to", "subject", "body"],
            },
        },
    },
]

模型会根据用户意图自动选择调用哪个工具。当用户说「帮我查一下订单 ORD-20231201-001」时调用 query_order,说「发邮件通知客户」时调用 send_email
查询订单
发送邮件
查询天气
用户输入
LLM 分析意图

(基于工具描述)
query_order
send_email
get_weather
执行工具 → 返回结果
模型整合结果

生成最终回复

多工具选择的三个技巧

  1. 描述差异化:如果两个工具功能相近,描述必须明确边界。比如一个查「国内天气」一个查「国际天气」。
  2. 避免重叠:不要让两个工具能做同样的事,模型会困惑。
  3. 数量克制:工具不是越多越好。超过 10 个工具时,模型选择准确率明显下降。

七、Tool Calling 的适用场景

适合用 Tool Calling

  • 需要实时数据(天气、股价、新闻)
  • 需要访问私有数据(公司数据库、CRM)
  • 需要执行操作(发邮件、创建工单、操作文件)
  • 需要精确计算(复杂数学、日期计算)

不适合用 Tool Calling

  • 纯文本生成任务(翻译、摘要、写作)
  • 模型自身知识可以覆盖的简单问答
  • 对延迟极度敏感的场景(多轮调用增加响应时间)

八、总结

这篇文章覆盖了 Tool Calling 的核心要点:

  1. Tool Calling 的本质:模型提议调用哪个工具,你的代码执行,结果传回模型生成回复
  2. 工具定义的三要素:name(标识)、description(最关键,决定模型会不会用)、parameters(JSON Schema)
  3. OpenAI SDKtools 参数传入定义,通过 response.choices[0].message.tool_calls 获取调用请求,结果通过 role: "tool" 传回
  4. Anthropic SDK :工具定义用 input_schema,调用请求在 content 中以 tool_use block 出现,结果通过 role: "user" 传回
  5. 生产实践:描述要精准、工具数量要克制、要考虑并行调用和错误处理
相关推荐
墨北小七1 小时前
从目标检测到行为识别:YOLO 模型微调实战
人工智能·深度学习·神经网络
Peter·Pan爱编程1 小时前
第三篇:10 分钟上手:用自然语言生成一个全栈应用
人工智能·ai编程
薛定猫AI2 小时前
【深度解析】从 Claude Jupiter 到 ARC-AGI 3:大模型发布信号、评测体系与多模型工程接入实践
人工智能·agi
刘一说2 小时前
AI 热点资讯日报-2026-05-01
人工智能
threelab2 小时前
Three.js 代码云效果 | 三维可视化 / AI 提示词
开发语言·javascript·人工智能
Java小生不才2 小时前
Spring AI文生音
java·人工智能·spring
jinanwuhuaguo2 小时前
(第二十八篇)OpenClaw成本与感知的奇点——从“Token封建制”到“全民养虾”的本体论地基
android·人工智能·kotlin·拓扑学·openclaw
byte轻骑兵2 小时前
【HID】规范精讲[8]: 蓝牙HID核心之L2CAP层——无线人机交互的通信桥梁设计解析
人工智能·人机交互·蓝牙·键盘·hid