大模型Function Calling实战:从原理到AI Agent开发全解析
1. 从“聊天”到“干活”:Function Calling 的本质跃迁
如果你在过去一年里深度使用过 ChatGPT、Claude 或者国内的大模型,一定有过这样的体验:你跟它聊得天花乱坠,它也能对答如流,但一旦你想让它帮你做点“实事”,比如查一下明天的天气、给你的购物车算个总价、或者把一段对话内容整理成表格发到你的邮箱,它多半会礼貌地告诉你:“作为一个AI模型,我无法直接执行这个操作。” 这种感觉就像你雇了一个知识渊博的顾问,他什么都懂,但就是不会动手,所有事情都得你听完他的建议后,自己再去操作一遍。
Function Calling 的出现,彻底改变了这个局面。它不是一个具体的函数,而是一种标准化的“协议”或“能力”。简单来说,它让大模型从一个“健谈的顾问”变成了一个“能听懂指令并指挥工具干活的管家”。模型本身依然不直接操作外部世界(比如它不能真的去访问天气网站),但它学会了识别你的自然语言指令中隐含的“意图”,并将这个意图精准地“翻译”成对某个具体工具(我们称之为“函数”或“API”)的调用请求。然后,由你的程序去执行这个工具,并把结果返回给模型,模型再组织成自然语言回复你。这一来一回,就完成了从“说”到“做”的闭环。
为什么这件事如此重要?因为它解决了大模型落地应用的核心瓶颈—— 连接现实世界 。没有 Function Calling,大模型是信息孤岛,它的价值仅限于文本生成。有了 Function Calling,大模型就成了一个万能的中枢大脑,可以调度无数的外部工具和服务(数据库、计算引擎、邮件系统、硬件设备等),真正融入业务流程和用户体验中。我们常说的 AI Agent(智能体) ,其核心能力之一就是通过 Function Calling 来使用工具。所以,掌握 Function Calling,是构建实用化 AI 应用、迈向 AI Agent 开发的必经之路。
2. 核心原理拆解:大模型如何学会“发号施令”
要理解 Function Calling,我们需要暂时跳出代码,看看它背后大模型与开发者之间是如何“默契配合”的。这个过程并非魔法,而是一套设计精巧的交互协议。
2.1 交互流程的三步舞曲
一次完整的 Function Calling 交互,通常包含三个核心步骤,我把它比作一场精心编排的“三步舞曲”:
第一步:开发者“亮出工具箱”(定义函数) 在向大模型发送用户问题之前,我们(开发者)需要先告诉模型:“嗨,我这里有这些工具你可以用。” 这个“告诉”的方式,就是以 JSON Schema 的形式,描述一个或多个函数的名称、功能说明、以及所需的参数及其类型。例如,我们定义一个 get_current_weather 的函数,描述是“获取指定城市的当前天气”,它有一个参数叫 location ,类型是字符串。这一步的关键在于描述要清晰、准确,因为模型完全依赖这个描述来理解工具的用途。
第二步:大模型“理解并开单”(解析意图并返回调用请求) 当用户提出一个问题,比如“北京天气怎么样?”时,我们将用户问题和我们定义好的函数列表一起发送给大模型。大模型会进行如下思考:
- 用户的问题是否需要调用我已知的工具来解决?(意图识别)
- 如果需要,哪个工具最匹配?(函数选择)
- 调用这个工具,需要哪些具体信息?(参数提取)
如果模型判断需要调用函数,它 不会直接执行函数 ,而是会返回一个结构化的 JSON 对象。这个对象里包含了它“想”调用的函数名称,以及它从用户问题中提取并填充好的参数。例如: {"name": "get_current_weather", "arguments": {"location": "北京"}} 。注意,此时函数并没有被真正执行,模型只是返回了一个“调用指令单”。
第三步:程序“执行并反馈”(执行函数并返回结果) 我们的应用程序收到这个 JSON 指令后,就会在本地(或远程)找到对应的 get_current_weather 函数,传入参数“北京”,真正执行它。执行后,我们会得到一个结构化的结果,比如 {"temperature": 22, "unit": "celsius", "description": "晴朗"} 。然后,我们将这个结果作为新的信息,再次发送给大模型,并请它根据这个结果来生成面向用户的最终回答。模型此时会说:“北京目前天气晴朗,气温22摄氏度。”
2.2 关键设计:结构化输出与“零样本”学习
Function Calling 的实现,依赖于大模型两项核心能力的结合:
-
强大的结构化信息抽取能力 :大模型,特别是 GPT-4 这个级别的模型,在理解自然语言并从中精准提取结构化信息(如时间、地点、人名、事件)方面表现卓越。Function Calling 本质上就是将这种能力标准化、定向化。我们通过函数描述,引导模型去关注和提取我们关心的那几类参数。
-
基于描述的“零样本”函数理解 :我们不需要给模型提供成千上万个调用示例来训练它。我们只需要用自然语言清晰地描述函数是干什么的、需要什么参数,模型就能在“零样本”(即没有见过该函数具体调用例子)的情况下,正确理解并使用它。这得益于大模型在预训练阶段获得的、对世界知识的通用理解能力。
注意 :这里有一个非常重要的认知纠正。Function Calling 并不是在模型内部“运行”了你的代码。模型对函数一无所知,它只是根据你的描述,做了一个“模式匹配”和“信息填充”的工作。真正的执行权始终牢牢掌握在你的应用程序手中。这既是出于安全考虑(防止模型执行恶意代码),也使得架构更加清晰(业务逻辑与模型逻辑分离)。
3. 主流平台实战:OpenAI、Anthropic 与国产模型的实现
理论讲清楚了,我们来看看具体怎么干。不同的大模型平台对 Function Calling 的实现细节略有不同,但核心思想一致。我将以最主流的 OpenAI(GPT)和快速崛起的 Anthropic(Claude)为例,并简要对比国产主流模型的现状。
3.1 OpenAI / Azure OpenAI API 实现详解
OpenAI 是 Function Calling 的提出者和标准定义者,其 API 最为成熟。在最新的 Chat Completions API 中,通过 tools 参数来定义函数。
第一步:定义工具(函数)列表 你需要准备一个 tools 数组,其中每个元素描述一个函数。 type 固定为 "function" ,核心在 function 对象内的描述。
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "获取指定城市的当前天气信息",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市名称,例如:北京、San Francisco"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位,默认为摄氏度(celsius)"
}
},
"required": ["location"]
}
}
}
]
第二步:发起对话并处理模型响应 将用户消息和 tools 一起发送给 API。关键是要设置 tool_choice 参数。如果设为 "auto" ,模型将自行决定是否调用函数;如果设为 {"type": "function", "function": {"name": "xxx"}} ,则可以强制要求模型调用特定函数。
import openai
from openai import OpenAI
client = OpenAI(api_key="your-api-key")
response = client.chat.completions.create(
model="gpt-3.5-turbo", # 或 gpt-4-turbo
messages=[{"role": "user", "content": "上海今天热吗?"}],
tools=tools,
tool_choice="auto", # 让模型自主决定
)
message = response.choices[0].message
第三步:判断并执行函数调用 检查响应中是否包含 tool_calls 。如果有,则遍历每个调用请求,执行对应的本地函数,并将结果收集起来。
if message.tool_calls:
# 准备一个列表来存放所有工具调用的结果
tool_messages = []
for tool_call in message.tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
# 根据 function_name 找到并执行对应的本地函数
if function_name == "get_current_weather":
location = function_args.get("location")
unit = function_args.get("unit", "celsius")
# 调用你的真实天气API或函数
weather_result = get_real_weather(location, unit)
# 将结果格式化为模型期望的格式
tool_messages.append({
"role": "tool",
"content": json.dumps(weather_result), # 结果必须是字符串
"tool_call_id": tool_call.id # 必须关联对应的调用ID
})
# 第四步:将工具执行结果送回给模型,让它生成最终回答
second_response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "上海今天热吗?"},
message, # 包含原始 tool_calls 的助理消息
*tool_messages # 展开所有工具执行结果
]
)
final_answer = second_response.choices[0].message.content
print(final_answer) # 输出:“上海今天天气多云,气温28摄氏度,体感较热。”
else:
# 如果模型没有调用工具,直接输出其回复
print(message.content)
实操心得:
- 描述(description)是灵魂 :函数的
description和参数的description至关重要。要用清晰、无歧义的自然语言撰写。例如,“获取天气”就不如“获取指定城市的实时温度、天气状况和湿度”来得精确。 - 处理多个工具调用 :模型在一次回复中可能同时调用多个工具(
parallel function calling)。你的代码需要能处理一个message中包含多个tool_call的情况,并确保将每个结果通过正确的tool_call_id关联回去。 - 温度(temperature)参数 :对于需要稳定输出结构化数据的 Function Calling 场景,建议将
temperature设置为 0 或接近 0 的值,以减少输出的随机性,确保参数提取的准确性。
3.2 Anthropic Claude Messages API 实现
Anthropic 的 Claude 3 系列模型也支持类似功能,但术语和 API 格式有所不同。它称之为 Tool Use 。整体流程相似,但细节有差异。
第一步:定义工具(Tools) 在 Claude API 中,工具定义在 tools 参数下,结构略有不同。
tools = [{
"name": "get_current_weather",
"description": "获取指定城市的当前天气信息",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市名称"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"default": "celsius"
}
},
"required": ["location"]
}
}]
第二步:发起对话并处理 Block 响应 Claude 的响应消息 ( Message ) 包含一个 content 数组,其中可能包含 TextBlock 和 ToolUseBlock 。
import anthropic
client = anthropic.Anthropic(api_key="your-api-key")
response = client.messages.create(
model="claude-3-sonnet-20240229",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "对比一下北京和杭州的天气。"}]
)
# 检查响应内容
for block in response.content:
if block.type == ‘text‘:
print(f“Text: {block.text}“)
elif block.type == ‘tool_use‘:
print(f“Tool to use: {block.name}“)
print(f“Tool input: {block.input}“)
# 这里 block.id 相当于 OpenAI 的 tool_call_id
第三步:执行工具并提交结果 你需要收集所有 ToolUseBlock ,执行对应函数,然后将结果以 ToolResultBlock 的形式,作为新的用户消息提交给 Claude 进行后续处理。
tool_results = []
for block in response.content:
if block.type == ‘tool_use‘:
if block.name == “get_current_weather“:
weather = get_real_weather(block.input[“location“])
tool_results.append({
“type“: “tool_result“,
“tool_use_id“: block.id, # 关联 ID
“content“: json.dumps(weather)
})
# 将工具结果作为后续对话输入
if tool_results:
follow_up_response = client.messages.create(
model=“claude-3-sonnet-20240229“,
max_tokens=1024,
messages=[
{“role“: “user“, “content“: “对比一下北京和杭州的天气。“},
response, # 包含 ToolUseBlock 的助理消息
{“role“: “user“, “content“: tool_results} # 提交工具结果
]
)
print(follow_up_response.content[0].text)
与 OpenAI 的主要差异点:
- 术语 :OpenAI 叫
tools/function calling, Claude 叫tools/tool use。 - 响应结构 :OpenAI 的调用信息在
message.tool_calls里;Claude 的则在content数组中以ToolUseBlock形式出现。 - 结果提交 :OpenAI 要求将结果以
role: tool的消息格式插入历史;Claude 要求将结果作为新的user消息中的ToolResultBlock提交。 - 并行调用 :两者都支持,但处理代码的编写方式因上述结构差异而不同。
3.3 国产大模型的适配与现状
目前,国内主流大模型平台(如百度文心、阿里通义、智谱GLM、月之暗面Kimi等)也都在快速跟进 Function Calling 能力。通常有以下几种实现方式:
- 兼容 OpenAI 格式 :这是最友好的方式。许多国产模型 API 在设计上力求与 OpenAI API 兼容,这意味着你为 GPT 编写的
tools定义和调用代码,只需更换 API Endpoint 和 API Key,就能在一定程度上直接运行。例如,部分平台提供的“Chat Completions 兼容接口”。 - 自有格式 :部分平台提供了自己定义的函数调用格式,通常也会提供详细的 SDK 和文档。其核心流程(定义、调用、执行、回调)万变不离其宗,学习成本在于熟悉其特定的 JSON 结构字段名。
- 插件/工具平台 :一些平台通过更高层次的“插件市场”或“工具平台”来提供类似能力,开发者以配置化方式上传工具,模型通过平台调度。这种方式对开发者更简单,但灵活性可能不如直接调用 API。
给开发者的建议 :在开始一个涉及 Function Calling 的项目前,先调研目标模型平台的官方文档,查看其“工具调用”或“函数调用”相关章节。优先选择提供 OpenAI 兼容接口的平台,可以最大程度复用代码和降低迁移成本。同时,要关注不同模型在意图理解准确率、复杂参数提取能力上的差异,必要时需要调整函数描述或加入少量示例(few-shot)进行引导。
4. 高级模式与架构设计:构建健壮的 AI 应用
掌握了基础调用,我们就可以探讨更复杂的应用模式了。单个函数调用解决单一问题,而现实世界的任务往往是多步骤、有条件分支的。这就需要更高级的设计模式。
4.1 多轮对话与状态管理
Function Calling 天然支持多轮对话。例如,用户问:“帮我订一张明天从北京飞上海的机票。”模型可能先调用 search_flights 函数,返回一堆航班选项。用户接着说:“要下午出发的。”这时,你需要将整个对话历史(包括之前的函数调用和结果)连同新的用户指令一起发送给模型。模型会理解上下文,它可能不会再次调用搜索,而是从之前的搜索结果中筛选,或者调用一个新的 filter_flights 函数。
关键点:状态管理。 你的应用程序需要维护完整的对话历史记录。一个典型的对话状态( ConversationState )应该包括:
- 用户和助理的文本消息列表。
- 历史上所有发生过的工具调用(
tool_calls)及其结果(tool_messages)。 - 任何自定义的会话上下文(如用户ID、会话偏好等)。
每次与模型交互时,都将这个完整的状态作为 messages 发送过去。模型会根据整个上下文来决定下一步是直接回复,还是调用新工具。
4.2 并行与串行调用策略
- 并行调用 :当用户的一个请求涉及多个独立任务时,模型可以一次性返回多个
tool_calls。例如,“查一下北京天气和上海股市大盘”。你的后端应该并行执行get_weather和get_stock_index这两个函数,以降低总延迟。所有结果返回后,再一次性提交给模型进行总结。 - 串行调用 :很多任务具有依赖性,必须串行。例如,“查一下特斯拉的股价,如果超过200美元就发邮件提醒我”。这需要先调用
get_stock_price(“TSLA”),得到结果后,在下一轮对话中,模型根据结果判断条件成立,再调用send_email函数。这需要你的程序能驱动多轮交互循环。
架构设计模式:控制流引擎 对于复杂的串行或带条件分支的任务,一个常见的架构是引入一个轻量级的“控制流引擎”或“工作流引擎”。这个引擎负责:
- 维护与模型的对话循环。
- 解析模型的响应,判断是文本回复还是工具调用。
- 执行工具调用,管理其输入输出。
- 根据工具执行结果和预定义的业务逻辑(或让模型决策),决定下一步是继续询问模型还是执行其他操作。
- 这种模式是构建复杂 AI Agent 的雏形。
4.3 错误处理与用户反馈
工具执行可能失败(网络超时、API限流、参数错误等)。健全的 Function Calling 应用必须有完善的错误处理机制。
- 工具执行失败 :当本地函数执行抛出异常时,不要崩溃。应该将错误信息(例如“天气服务暂时不可用”)作为该工具调用的“结果”返回给模型。模型有能力理解错误,并可能生成对用户友好的解释,如“抱歉,天气查询服务出了点问题,请您稍后再试。”
- 模型“幻觉”调用 :有时模型可能会错误地调用一个不存在的函数,或为参数生成完全不合逻辑的值(如
location: 12345)。你的代码需要在执行前进行验证:- 检查
function_name是否在已注册的工具列表中。 - 使用 JSON Schema 验证器(如
jsonschema库)检查arguments是否符合预定义的模式。 - 对于关键参数,进行业务逻辑验证(如城市名是否在支持列表中)。 如果验证失败,可以将验证错误信息作为结果返回给模型,让它有机会纠正。
- 检查
- 用户澄清 :如果模型提取的参数模糊不清(例如
location: “南方”),你的工具函数可能无法处理。一种策略是让工具返回一个特定的错误码或消息,模型收到后,会主动向用户提问以澄清:“您具体想查询南方哪个城市的天气呢?”
5. 实战:从零构建一个智能旅行助手 Agent
让我们综合运用以上知识,构建一个简单的“智能旅行助手”AI Agent。它能理解用户关于旅行的复杂请求,并通过调用多个外部工具来完成。
5.1 定义工具集
我们为助手装备三个核心工具:
search_flights:查询航班。search_hotels:查询酒店。get_city_info:获取城市基本信息(如天气、景点,这里简化为一个函数)。
tools = [
{
“type“: “function“,
“function“: {
“name“: “search_flights“,
“description“: “根据出发地、目的地、日期搜索航班信息。日期格式为 YYYY-MM-DD。“,
“parameters“: {
“type“: “object“,
“properties“: {
“departure_city“: {“type“: “string“, “description“: “出发城市“},
“arrival_city“: {“type“: “string“, “description“: “到达城市“},
“date“: {“type“: “string“, “description“: “出发日期,YYYY-MM-DD“}
},
“required“: [“departure_city“, “arrival_city“, “date“]
}
}
},
{
“type“: “function“,
“function“: {
“name“: “search_hotels“,
“description“: “根据城市和入住/离店日期搜索酒店信息。日期格式为 YYYY-MM-DD。“,
“parameters“: {
“type“: “object“,
“properties“: {
“city“: {“type“: “string“, “description“: “城市名称“},
“check_in“: {“type“: “string“, “description“: “入住日期“},
“check_out“: {“type“: “string“, “description“: “离店日期“}
},
“required“: [“city“, “check_in“, “check_out“]
}
}
},
{
“type“: “function“,
“function“: {
“name“: “get_city_info“,
“description“: “获取城市的基本信息,如当前天气、主要景点等。“,
“parameters“: {
“type“: “object“,
“properties“: {
“city_name“: {“type“: “string“, “description“: “城市名称“}
},
“required“: [“city_name“]
}
}
}
]
5.2 实现主控循环与工具执行器
我们将创建一个 TravelAssistant 类来管理整个对话状态和流程。
import json
import openai
from typing import List, Dict, Any
class TravelAssistant:
def __init__(self, api_key: str, model: str = “gpt-3.5-turbo“):
self.client = openai.OpenAI(api_key=api_key)
self.model = model
self.conversation_history: List[Dict] = [] # 存储完整对话历史
def add_user_message(self, content: str):
“““添加用户消息到历史。“““
self.conversation_history.append({“role“: “user“, “content“: content})
def _execute_tool(self, tool_name: str, arguments: Dict) -> str:
“““模拟执行工具。在实际应用中,这里会调用真实的API。“““
if tool_name == “search_flights“:
# 模拟航班搜索
return json.dumps({
“flights“: [
{“airline“: “航司A“, “flight_no“: “CA1234“, “dep_time“: “08:00“, “price“: 1200},
{“airline“: “航司B“, “flight_no“: “MU5678“, “dep_time“: “14:00“, “price“: 900}
]
})
elif tool_name == “search_hotels“:
# 模拟酒店搜索
return json.dumps({
“hotels“: [
{“name“: “酒店X“, “star“: 4, “price_per_night“: 500},
{“name“: “酒店Y“, “star“: 5, “price_per_night“: 1200}
]
})
elif tool_name == “get_city_info“:
# 模拟城市信息
city = arguments.get(“city_name“)
return json.dumps({
“weather“: “晴朗,25℃“,
“attractions“: [“景点1“, “景点2“]
})
else:
return json.dumps({“error“: f“未知工具: {tool_name}“})
def process_query(self, user_query: str) -> str:
“““处理用户查询的核心循环。“““
# 1. 添加用户消息到历史
self.add_user_message(user_query)
# 2. 调用模型,传入完整历史和工具定义
response = self.client.chat.completions.create(
model=self.model,
messages=self.conversation_history,
tools=tools,
tool_choice=“auto“,
temperature=0
)
assistant_message = response.choices[0].message
# 3. 将助理的回复(可能包含文本或工具调用)加入历史
self.conversation_history.append(assistant_message.to_dict())
final_answer = None
# 4. 检查是否需要调用工具
if assistant_message.tool_calls:
tool_messages = []
for tool_call in assistant_message.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
print(f“[Agent 正在执行] {func_name}({func_args})“)
# 执行工具
tool_result = self._execute_tool(func_name, func_args)
# 构造工具结果消息
tool_messages.append({
“role“: “tool“,
“content“: tool_result,
“tool_call_id“: tool_call.id
})
# 5. 将所有工具结果加入历史
self.conversation_history.extend(tool_messages)
# 6. 再次调用模型,让它基于工具结果生成最终回复
second_response = self.client.chat.completions.create(
model=self.model,
messages=self.conversation_history,
temperature=0
)
final_message = second_response.choices[0].message
self.conversation_history.append(final_message.to_dict())
final_answer = final_message.content
else:
# 没有工具调用,直接返回文本回复
final_answer = assistant_message.content
return final_answer
# 使用助手
assistant = TravelAssistant(api_key=“your-key“)
answer = assistant.process_query(“我想下周五从北京飞上海,住两晚,推荐一下航班和酒店,顺便说说上海现在天气怎么样。“)
print(“助手回复:“, answer)
5.3 运行示例与解析
当你运行上面的代码,输入复杂查询时,模型可能会进行以下操作:
- 首先,它识别出三个子任务:查航班、查酒店、查天气。
- 它可能一次性并行调用
search_flights(北京,上海,下周五) 和get_city_info(上海)。因为这两个任务没有依赖关系。 - 在得到航班和城市信息后,它发现查询酒店需要入住和离店日期。它可以从用户“住两晚”和航班日期中推断出日期,然后调用
search_hotels。 - 最后,它汇总所有工具返回的结构化数据,生成一段连贯、友好的自然语言回复给你:“为您找到以下航班... 上海的天气晴朗25℃,推荐景点有... 根据您的行程,推荐以下酒店...”
这个简单的 Agent 已经具备了处理多步骤、有条件任务的能力。通过扩展工具集(如租车、景点门票、餐厅预订),它可以变得更强大。
6. 避坑指南与性能优化
在实际生产环境中应用 Function Calling,会遇到许多在教程中不会提及的“坑”。以下是我从多个项目中总结出的关键经验。
6.1 描述(Description)撰写的艺术
函数的 description 是模型理解工具用途的唯一途径。写得不好,模型就会用错。
- 避免歧义 :“处理数据”是糟糕的描述。“根据用户ID从数据库查询其最近3个月的订单记录”是好的描述。
- 明确输入输出 :在函数描述中,可以简要说明输入是什么,输出大概是什么。例如:“输入城市名,返回该城市当前温度、天气状况和湿度百分比。”
- 参数描述要具体 :
location的描述如果是“地点”,模型可能填入“我家门口”。改成“城市或机场的IATA代码(如‘北京’或‘PEK’)”,效果会好得多。 - 利用枚举(enum)和默认值 :对于有限的选项,如单位
{“celsius“, “fahrenheit“},或分类{“economy“, “business“},使用enum可以极大提高准确率。对于可选参数,设置合理的default值。
6.2 处理模型的不确定性
即使描述再完美,模型也可能出错。
- 设置最大重试次数 :当模型返回的参数无法通过验证,或调用了错误的函数时,不要直接报错给用户。可以设计一个重试循环:将验证错误信息作为系统提示,重新向模型提问(例如:“上次调用失败,原因是参数XX格式错误。请根据以下正确格式重新生成调用。”),通常重试1-2次就能成功。
- 提供少量示例(Few-shot) :对于极其复杂或容易出错的函数,可以在
messages的系统提示或历史中,提供一两个正确调用该函数的示例对话。这能显著提升模型在复杂场景下的表现。 - 后处理与修正 :对于模型提取的参数,在执行前进行后处理。例如,将“明天”转换为具体的日期,将“北上广”拆分为三个城市等。
6.3 成本与延迟优化
Function Calling 会增加 API 调用次数(一次用户查询可能触发多轮模型调用),进而增加成本和延迟。
- 批量处理 :鼓励用户一次性提出完整需求,利用模型的并行调用能力,减少交互轮次。
- 缓存工具结果 :对于相同参数的工具调用(如短时间内多次查询同一城市天气),在客户端或服务端实现缓存,避免重复调用外部 API。
- 精简上下文 :虽然需要维护完整对话历史,但对于非常长的对话,可以考虑只保留最近N轮或总结之前的对话内容,以减少发送给模型的 token 数量,降低成本。
- 模型选型 :对于工具调用本身(即解析意图、生成调用参数),
gpt-3.5-turbo在大多数场景下已经足够准确且成本更低。对于需要高度推理或总结复杂工具结果的最终回复,可以酌情使用gpt-4。
6.4 安全与权限考量
让模型决定调用哪个函数,存在潜在风险。
- 最小权限原则 :只向模型暴露完成当前任务所必需的最少工具。例如,一个订餐助手不需要拥有“删除用户账户”的工具。
- 参数校验与净化 :在执行任何工具前,必须对模型提供的参数进行严格的校验和净化,防止 SQL 注入、命令注入等攻击。永远不要相信模型的直接输入。
- 用户确认 :对于具有重大影响或不可逆的操作(如发送邮件、支付、删除数据),即使在模型调用后,也应在真正执行前增加一层用户确认(例如,“我将为您发送这封邮件,确认吗?”)。
Function Calling 不仅仅是一个 API 特性,它代表了一种全新的、让 AI 融入现实工作流的范式。从简单的数据查询到复杂的多步骤自动化,它的边界只取决于你的工具库和想象力。现在,是时候为你的大模型装上“手和脚”,让它真正开始为你“干活”了。
更多推荐
所有评论(0)