函数调用与工具使用 入门教程
所属主题:Claude 提示词工程完全指南
引言:为何需要函数调用与工具使用
许多 AI 模型(如 Claude、GPT 系列)最初仅能生成文本回复,无法直接与外部系统交互或执行实际操作。函数调用(Function Calling)与工具使用正是突破这一限制的关键技术,它让 AI 能够根据你的指令,主动调用预定义的 API 或函数,从而实现数据库查询、计算执行、消息发送以及与其他系统的整合。
本教程将系统地讲解函数调用的核心原理、实施步骤与常见陷阱,帮助你安全、高效地引导 AI 完成更复杂的真实世界任务。
快速理解:从自然语言到结构化指令
函数调用与工具使用的本质,是让 AI 模型将自然语言请求转化为结构化的函数调用指令,而非直接生成最终答案。例如,当你说“帮我查一下上海今天的天气”时,模型不会凭空编造一个气温,而是生成类似 get_weather(city="上海") 的函数调用。开发者接收到这个调用后,执行真实的 API 请求,再将结果返回给模型,最后由模型组织成流畅的自然语言输出。
这种模式的核心价值在于:让 AI 能够访问实时、私有或经过验证的信息源,并执行需要计算或权限的操作。重要的是要理解,AI 本身并不“完成”操作,而是通过“请求”来引导外部系统工作。
准备工作:确保必要的前提条件
在编写首个函数调用之前,请确认你具备以下条件:
- 支持函数调用的模型 API 密钥:确保你的 API 密钥(来自 OpenAI、Anthropic、Google 或开源模型的同类功能)具备调用权限。不同提供商的接口定义方式存在差异,需提前查阅对应文档。
- 基础的 API 调用能力:熟悉如何通过 HTTP 请求或 SDK(如
openaiPython 库)发送 Prompt 并处理返回的 JSON 数据。 - 后端 API 或函数(可选但推荐):你需要实际执行操作的服务端点。若为本地测试,可先定义一个模拟函数(如返回字典的 Python 函数)来观察调用流程。
重要提醒:许多新手在此犯的第一个错误是跳过这些前提条件,直接复制网上的代码段运行。请务必确认你的 API 密钥所属的模型版本明确支持函数调用功能,因为早期某些模型版本并不具备此能力。
函数调用的五个操作步骤
下面以天气查询场景为例,演示完整工作流程。
第一步:定义函数/工具
你需要使用 JSON Schema 格式向模型描述你的函数,包括名称、描述及每个参数的定义。
functions = [
{
"name": "get_weather",
"description": "获取指定城市的当前天气信息。",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,例如 '北京' 或 '上海'"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位"
}
},
"required": ["city"]
}
},
# 可定义多个函数,如 'send_email', 'calculate_route'
]
关键细节:description 字段至关重要。模型依赖它来决定何时及如何调用该函数。描述需清晰、具体,包括参数的可能格式或边界值。例如,若 unit 参数不使用 enum 而仅写 "description": "温度单位",模型可能传入 "摄氏度" 而导致后端解析失败。
第二步:发送带函数定义的初始请求
将用户消息与函数定义一起发送给模型。
import openai
messages = [{"role": "user", "content": "上海今天天气怎么样?"}]
response = openai.ChatCompletion.create(
model="gpt-4o", # 使用支持调用的模型
messages=messages,
functions=functions,
function_call="auto" # 让模型自行决定是否调用
)
返回的 response 对象包含 choices[0].message。若模型决定调用函数,该 message 会包含 function_call 字段,而 content 字段通常为 None。
第三步:解析函数调用请求
检查模型返回,提取函数名称和参数。
message = response["choices"][0]["message"]
if message.get("function_call"):
function_name = message["function_call"]["name"]
arguments = json.loads(message["function_call"]["arguments"])
# 输出:{'city': '上海', 'unit': 'celsius'}
print(function_name, arguments)
新手常见错误:直接对 arguments 字符串调用 json.loads(),若参数内容不规范(如缺少引号)会抛出异常。建议在解析前进行字符串清理,或使用容错性更强的解析库。这是处理模型输出时最常见的陷阱之一。
第四步:执行你的函数
用解析出的参数调用真实的业务逻辑。
def get_weather(city, unit="celsius"):
# 模拟 API 调用,实际场景应为对真实气象服务的 HTTP 请求
weather_data = {
"city": city,
"temperature": 22 if unit == "celsius" else 71,
"condition": "晴"
}
return weather_data
if function_name == "get_weather":
function_response = get_weather(**arguments)
第五步:将结果反馈给模型
将函数执行结果以 function 角色消息追加到对话历史,再次调用模型,让它用自然语言总结。
# 追加包含 function_call 的 assistant 消息
messages.append(message)
messages.append({
"role": "function",
"name": function_name,
"content": json.dumps(function_response) # 结果必须是字符串
})
# 再次请求模型进行总结
second_response = openai.ChatCompletion.create(
model="gpt-4o",
messages=messages
)
print(second_response["choices"][0]["message"]["content"])
# 输出:上海的当前天气为晴天,温度 22 摄氏度。
这就完成了从自然语言到工具调用,再到自然语言输出的完整循环。
结果检查清单
确认流程正确运行后,需检查以下关键点:
- 函数是否被正确调用:日志中应看到模型返回了包含正确函数名和参数的 JSON,而非直接输出文字。
- 参数值是否符合预期:特别关注枚举值(如
celsiusvs摄氏度)和大数字格式。模型有时会生成边界值。 - 多轮调用的连续性:当用户说“再查查北京的”时,模型能否复用对话上下文并生成新的调用?
- 错误处理是否完备:若后端 API 返回错误(如
{'error': 'City not found'}),模型能否理解并给出用户友好提示?
重要警告:务必先手动对比模型传入的参数与你后端 API 能接受的参数格式。许多集成失败源于后端要求 city_code 而模型只传 city_name,这应在函数定义阶段就解决。
常见问题的排查与解决
遇到问题时,优先检查以下三个方面:
1. 模型未调用函数,而是直接回答
- 检查
function_call参数是否设置为"auto"。若设为"none",模型永远不会调用函数。 - 审查函数定义中的
description是否准确描述了工具用途。模糊或错误的描述会导致模型判断失误。
2. 解析函数参数时出错
- 建立中间处理层,在
json.loads()前预处理模型返回的参数 JSON 字符串,如移除多余空格或转义不规范引号。 - 考虑使用更健壮的
json5或demjson3库解析,它们能容忍尾部逗号或单引号等情况。
3. 处理多个函数调用的场景
- 当模型认为需要一次调用多个函数(如先查航班再查酒店房间)时,需循环处理
function_call,直到message中不再包含该字段。切勿漏掉任何一个调用或搞错顺序。
回滚与验证技巧:最简单的验证方法是使用模拟、无副作用的函数(如 echo(data) 直接返回输入)进行测试。如果过程正确,再切换回真实 API。这能快速隔离问题:是模型参数解析的问题,还是真实 API 本身的问题。
常见问题(FAQ)
问:函数调用与工具使用 入门教程 是什么?
答:这是一份面向开发者的操作指南,主要讲解如何定义和调用 AI 模型中的函数(工具)功能。核心流程为:编写 JSON Schema 描述函数 → 发送给模型 → 解析模型返回的结构化调用请求 → 在你的代码中执行并反馈结果。本教程适合已有基础 API 调用经验,但刚开始引入外部工具能力的用户。
问:函数调用与工具使用 入门教程 怎么操作?
答:标准流程分为五步:定义函数(用 JSON Schema) → 发送包含函数定义的初始请求 → 解析模型返回的 function_call → 执行你的函数 → 将结果反馈给模型并获取最终回复。