【AI】AI学习笔记:OpenAI Tools完全指南:从原理到实战入门

OpenAI Tools完全指南:从原理到实战入门

一、核心概念:为什么需要Tools?

想象一下,大语言模型(LLM)像一个学识渊博但"与世隔绝"的学者------它知道很多知识,但无法直接获取实时股价、查询数据库或发送邮件。Tools参数正是为LLM开启的"行动接口",让它能通过你定义的函数与外部世界交互。

关键技术演进

  • 旧方式(已弃用)functions + function_call 参数
  • 新方式(当前标准)tools + tool_choice 参数

二、核心原理:Tools如何工作?

1. 基础工作流程

当模型使用Tools时,对话不再是简单的"一问一答",而是变成一个决策-执行-回复的循环:
外部工具 OpenAI API 你的程序 用户 外部工具 OpenAI API 你的程序 用户 提问(自然语言) 发送请求(含tools定义) 返回工具调用指令(而非答案) 执行对应工具/函数 返回执行结果 发送结果给模型 生成最终自然语言回复 显示最终答案

2. 模型的两个决策点

在流程中,模型实际上做了两次关键判断:

  1. 是否需要调用工具? (通过tool_choice控制)
  2. 如果需要,调用哪个工具并传入什么参数? (通过tools定义控制)

三、详细参数解析

1. tools参数结构

python 复制代码
# 这是tools参数的标准结构
tools = [
    {
        "type": "function",  # 目前唯一支持的类型
        "function": {
            "name": "函数名",  # 如 get_weather
            "description": "清晰描述函数用途",  # 这是模型理解何时调用的关键!
            "parameters": {  # 使用JSON Schema格式定义
                "type": "object",
                "properties": {
                    "参数名": {
                        "type": "string/number/boolean等",
                        "description": "参数说明"
                    }
                },
                "required": ["必须的参数"],
                "additionalProperties": False  # 推荐设为False,限制模型只使用定义的参数
            },
            "strict": True  # 强烈建议开启,强制模型严格遵守Schema
        }
    }
    # 可以定义多个工具...
]

2. tool_choice参数详解

这个参数控制模型的"主动性":

行为 适用场景
"auto"(默认) 模型自主决定是否/如何调用工具 大多数通用场景
"none" 模型不调用任何工具,只生成文本回复 明确不需要工具交互时
{"type": "function", "function": {"name": "xxx"}} 强制模型调用指定工具 需要引导对话流程时

3. 新增配置:parallel_tool_calls

这是实现一次调用多个工具的关键:

python 复制代码
# 默认已开启,如需关闭可显式设置False
response = client.chat.completions.create(
    model="gpt-4",
    messages=messages,
    tools=tools,
    parallel_tool_calls=True  # 允许模型一次返回多个工具调用请求
)

四、完整实战示例

场景:同时查询多家公司股价

这个例子完整展示了从定义工具到获取最终答案的全过程:

python 复制代码
import json
from openai import OpenAI

# 初始化客户端
client = OpenAI(api_key="your-api-key")

# ========== 1. 定义工具 ==========
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_stock_price",
            "description": "获取指定公司的实时股票价格",
            "parameters": {
                "type": "object",
                "properties": {
                    "company_name": {
                        "type": "string",
                        "description": "公司的中文或英文名称,如:'苹果'、'Apple'、'小米'"
                    }
                },
                "required": ["company_name"],
                "additionalProperties": False
            },
            "strict": True  # 确保模型输出完全符合定义的格式
        }
    }
]

# ========== 2. 模拟的股票查询函数 ==========
def get_stock_price(company_name):
    """实际环境中,这里会调用真实的股票API"""
    mock_data = {
        "苹果": {"price": 189.85, "currency": "USD", "change": "+1.2%"},
        "小米": {"price": 18.72, "currency": "HKD", "change": "-0.5%"},
        "腾讯": {"price": 365.4, "currency": "HKD", "change": "+0.8%"}
    }
    return mock_data.get(company_name, {"error": "公司未找到"})

# ========== 3. 用户提问触发并行调用 ==========
user_question = "苹果公司和小米公司今天的股价分别是多少?走势如何?"

print("=== 第一步:用户提问 ===")
print(f"用户:{user_question}\n")

# ========== 4. 首次API调用:模型决定调用工具 ==========
print("=== 第二步:模型分析,决定调用工具 ===")
first_response = client.chat.completions.create(
    model="gpt-4-turbo",
    messages=[{"role": "user", "content": user_question}],
    tools=tools,
    tool_choice="auto",  # 让模型自主决定
)

assistant_msg = first_response.choices[0].message

# 检查模型是否要求调用工具
if assistant_msg.tool_calls:
    print(f"模型决定调用 {len(assistant_msg.tool_calls)} 个工具")
    
    # 存储所有工具执行结果
    tool_results_messages = []
    
    # ========== 5. 执行每个工具调用 ==========
    for i, tool_call in enumerate(assistant_msg.tool_calls):
        func_name = tool_call.function.name
        arguments = json.loads(tool_call.function.arguments)
        
        print(f"\n工具调用 #{i+1}:")
        print(f"  函数名:{func_name}")
        print(f"  参数:{arguments}")
        
        # 执行对应的函数
        if func_name == "get_stock_price":
            result = get_stock_price(arguments["company_name"])
            print(f"  执行结果:{result}")
            
            # 将结果格式化为API需要的消息格式
            tool_results_messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,  # 关键:ID必须匹配!
                "content": json.dumps(result)
            })
    
    # ========== 6. 第二次API调用:生成最终回复 ==========
    print("\n=== 第三步:将工具结果传回模型,生成最终回复 ===")
    
    # 构建完整的对话历史
    full_conversation = [
        {"role": "user", "content": user_question},
        assistant_msg,  # 包含工具调用的消息
        *tool_results_messages  # 所有工具执行结果
    ]
    
    second_response = client.chat.completions.create(
        model="gpt-4-turbo",
        messages=full_conversation,
        # 注意:这里可以不带tools参数,但带上更安全
        tools=tools,
    )
    
    final_answer = second_response.choices[0].message.content
    print(f"\n最终答案:{final_answer}")
    
else:
    # 如果模型没有调用工具,直接输出内容
    print(f"模型直接回复:{assistant_msg.content}")

关键输出说明:

当模型决定调用工具时,响应中的关键字段如下:

json 复制代码
{
  "id": "chatcmpl-xxx",
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": null,  // 注意:这里不是最终答案!
      "tool_calls": [{  // 核心:工具调用请求数组
        "id": "call_abc123",
        "type": "function",
        "function": {
          "name": "get_stock_price",
          "arguments": "{\"company_name\":\"苹果\"}"  // JSON字符串格式!
        }
      }, {
        "id": "call_def456",
        "type": "function", 
        "function": {
          "name": "get_stock_price",
          "arguments": "{\"company_name\":\"小米\"}"
        }
      }]
    },
    "finish_reason": "tool_calls"  // 停止原因是触发了工具调用
  }]
}

五、核心要点与最佳实践

1. 工具描述决定一切

模型完全依赖function.description来判断何时调用工具。描述要:

  • 明确说明工具的功能
  • 包含可能触发调用的关键词
  • 避免歧义

2. 严格模式是你的朋友

设置"strict": true"additionalProperties": false能:

  • 减少模型输出错误格式的几率
  • 提高参数提取的准确性
  • 避免意外参数导致的程序错误

3. 完整对话历史管理

成功的工具调用需要维护完整的对话上下文:

python 复制代码
messages = [
    {"role": "user", "content": "苹果股价多少?"},
    {"role": "assistant", "content": null, "tool_calls": [...]},  # 模型要求调用
    {"role": "tool", "tool_call_id": "call_abc123", "content": "189.85"},  # 工具结果
    # 可以继续对话...
]

4. 错误处理与限制

  • 数量限制:最多128个工具/请求
  • 参数解析:始终验证和清理模型返回的JSON
  • 超时处理:为工具执行设置超时,避免阻塞
  • 成本注意:工具调用通常需要2次API请求,成本翻倍

5. 高级技巧:链式调用

通过持续对话,可以实现复杂的链式调用:

python 复制代码
# 示例:先查天气,再根据天气推荐活动
# 1. 用户:今天北京天气如何?
# 2. 模型:调用get_weather(北京)
# 3. 程序:返回天气结果
# 4. 模型:根据天气,再调用recommend_activity(天气数据)
# 5. 最终:生成包含天气和活动建议的完整回复

六、常见问题解答

Q1:模型能直接输出${get_stock_price(苹果)}这样的代码吗?

不能。模型只会输出结构化的工具调用请求(JSON格式),不会输出编程语言风格的函数调用代码。

Q2:一次能调用多少个不同的工具?

理论上没有硬性限制,但受限于模型的上下文窗口。实践中,一次响应中通常不会超过5-10个工具调用。

Q3:工具执行失败怎么办?

应该将错误信息返回给模型,让它决定如何回应:

python 复制代码
result = {"error": "API暂时不可用", "details": "网络超时"}
# 模型收到后可能会说:"抱歉,暂时无法获取股价信息,请稍后再试。"

Q4:如何让输出格式更符合要求?

通过系统提示词(system message) 控制:

python 复制代码
messages = [
    {"role": "system", "content": "你是一个财经助手。请用清晰的Markdown列表格式回复,包含公司名称、股价和涨跌幅。"},
    {"role": "user", "content": "苹果和小米的股价"}
]

总结

OpenAI的Tools参数是一个强大的桥梁,让大语言模型从"知识库"变成了"智能执行者"。关键记住:

  1. 定义清晰:好的工具描述是成功的一半
  2. 流程完整:遵循"请求→调用→执行→回复"的完整循环
  3. 格式严格:使用strict模式和完整JSON Schema
  4. 历史完整:妥善管理包含tool消息的对话历史

通过合理使用Tools,你可以创建出真正能与现实世界交互的智能应用,从简单的数据查询到复杂的多步骤工作流,都能轻松实现。

相关推荐
我的golang之路果然有问题18 小时前
积累的 java 找工作资源
java·笔记
EchoL、18 小时前
指定GPU设备
pytorch·笔记
狮子座明仔18 小时前
MiMo-V2-Flash 深度解读:小米 309B 开源 MoE 模型如何用 15B 激活参数吊打 671B 巨头?
人工智能·语言模型·自然语言处理
九成宫18 小时前
计算机网络期末复习——第2章:应用层 Part Two
笔记·计算机网络·软件工程
gravity_w18 小时前
Conda常用命令总结
经验分享·笔记·conda
紧固件研究社18 小时前
从标准件到复杂异形件,紧固件设备如何赋能制造升级
人工智能·制造·紧固件
木头左18 小时前
贝叶斯深度学习在指数期权风险价值VaR估计中的实现与应用
人工智能·深度学习
反向跟单策略18 小时前
期货反向跟单—高频换人能够提高跟单效率?
大数据·人工智能·学习·数据分析·区块链
哎吆我呸18 小时前
Android studio 安装Claude Code GUI 插件报错无法找到Node.js解决方案
人工智能