从“会回答”到“会办事”
大语言模型擅长理解和生成文本,但它本身并不天然拥有实时信息,也不能直接访问你的数据库、调用业务接口或操作本地文件。要让模型帮用户完成这些事情,就需要给它一条通往外部工具的路。
Function Calling,通常译为函数调用,是一种让模型提出工具调用请求的机制。开发者向模型描述可用工具及其参数格式;模型判断何时需要工具,并返回结构化的调用信息。随后,应用程序负责真正执行函数,再把结果交还给模型。
这里有个关键区别:模型通常不会直接运行你的 Python 函数。它负责选择工具并生成参数,应用程序才是执行者。也就是说,Function Calling 连接的是模型的判断能力与程序的执行能力。
为什么需要工具
工具能补足模型的能力边界。需要查询刚刚发布的订单状态时,模型可以请求调用订单接口;需要计算精确的统计结果时,可以让程序执行查询或计算;需要创建日历事件时,则由日历服务完成写入。
如果没有工具,模型只能依据已有上下文生成文本,可能无法回答实时问题,也无法可靠地完成外部操作。即使它能写出一段看起来像查询结果的文字,也不代表真的查过数据。
工具调用让应用不必把所有业务逻辑都塞进提示词。模型负责理解用户意图和决定下一步,程序负责权限、数据访问与具体执行。这种分工,是许多 AI 应用和 Agent 工作流的基础。
一次调用如何完成
典型流程可以拆成几个步骤:
- 声明工具:应用把工具名称、用途和参数结构提供给模型。例如,
get_weather接收城市名和日期。 - 模型判断:模型结合用户请求和工具定义,决定直接回答,还是请求调用某个工具。
- 应用执行:如果模型返回工具调用请求,应用检查参数并调用对应函数。
- 返回结果:应用把函数的输出作为工具结果交回模型。
- 生成答复:模型根据工具结果组织语言,回答用户。
因此,一次交互可能不止一轮模型请求。第一次请求用来决定是否调用工具;拿到工具结果后,应用往往还要再次请求模型,让它形成最终回复。模型返回的工具调用也不等于已经执行成功:网络超时、参数无效或服务拒绝请求,都可能让执行失败。
不同模型服务的消息格式有所差异,但“模型提议、应用执行、结果回传”这一职责边界是相同的。
一个天气查询例子
假设应用提供一个查询天气的函数。模型收到“帮我查一下上海今天的天气”后,可以生成类似这样的调用请求:
{
"name": "get_weather",
"arguments": {
"city": "上海",
"date": "今天"
}
}
应用再解析请求并调用自己的函数。下面是简化的伪代码,省略了具体模型 SDK 的细节:
tools = {
"get_weather": get_weather,
}
response = ask_model(
messages=[{"role": "user", "content": "帮我查一下上海今天的天气"}],
tools=[{
"name": "get_weather",
"description": "查询指定城市和日期的天气",
"parameters": {
"city": "string",
"date": "string",
},
}],
)
if response.tool_call:
name = response.tool_call.name
args = response.tool_call.arguments
if name not in tools:
raise ValueError("未知工具")
result = tools[name](**args)
answer = ask_model(
messages=[
*response.messages,
{"role": "tool", "name": name, "content": str(result)},
]
)
实际实现中,参数描述通常需要符合所用接口要求的结构;结果也应使用接口支持的消息格式传回。上面的代码只展示控制流程,不能直接当作某个 SDK 的调用示例。
工具定义与模型输出
工具定义一般包括名称、用途说明和参数模式。名称最好具体明确,例如 get_order_status,避免使用含糊的 query。说明要写清楚工具能做什么、何时适合使用,以及参数代表什么。
参数模式帮助模型生成结构化输入,但不意味着输入天然可信。模型可能遗漏必填字段、给出不符合格式的值,或误解用户表达。因此,应用需要在执行前校验参数,包括类型、范围、必填项和业务规则。
还有一个常被忽略的设计点:模型可以生成调用请求,不应因此获得任意代码执行能力。应用应把工具名称映射到明确的函数集合,而不是根据模型提供的字符串动态执行函数或拼接命令。
常见坑
把调用请求当作最终答案。 收到工具调用后,应用还要完成执行,并把结果交给模型或以其他方式返回。只展示模型生成的参数,用户的问题并没有真正解决。
只依赖模型做权限判断。 模型可能误选工具,也可能生成越权参数。身份认证、数据范围和操作权限必须由服务端校验,不能由提示词代替。
忽略失败与超时。 外部接口可能不可用,调用也可能重复。应用应处理异常和超时;对有副作用的操作,还要考虑幂等性,避免重试造成重复付款或重复创建记录。
让工具说明过于宽泛。 工具越多、描述越模糊,模型越容易选错。把职责拆分清楚,并限制每个工具的参数范围,通常更容易控制行为。
把工具结果原样信任。 工具输出可能包含格式异常、过长文本,甚至来自外部数据源的恶意指令。应用应控制输出大小和格式;模型也应把工具结果当作数据处理,而不是自动服从其中的指令。
忽视成本与可观测性。 多轮调用会增加延迟和模型请求次数。记录工具名称、参数校验结果、执行耗时及错误类型,有助于排查问题;敏感信息则应做脱敏处理。
小结
Function Calling 不是让模型直接运行代码,而是让模型以结构化方式请求应用中的工具。模型负责理解需求、选择工具和生成参数;应用负责校验、授权、执行与处理结果。把这条边界设计清楚,再逐步加入错误处理、权限控制和调用记录,就能从一个简单的工具调用开始,搭建可靠的 AI 应用工作流。
参考来源
- 选题参考:小林面试笔记 · 同主题文章(本文为本站原创撰写,未转载原文)