Function Calling
Function Calling(工具调用)让模型根据工具定义,生成结构化的调用请求。请求里包含要调用的工具和参数,自定义工具则由应用执行。执行后,应用把结果交回模型,模型才能据此继续回答。
本文从一次调用的消息往返入手,解释工具定义、调用请求和执行结果怎样衔接。随后介绍工具契约、参数校验与错误处理,最后说明工具很多时怎样缩小选择范围。
1. 面试核心
先记住这几条,再读正文- 调用链路。 模型根据工具定义生成调用请求,应用校验并执行,再按调用 ID 回传结果供模型继续生成。卡 · 调用链路
- 工具契约。 工具契约用名称和描述说明用途,用 Schema 约束参数,并定义结果、错误及副作用。卡 · 工具契约设计
- 参数结构与执行条件。 严格 Schema 约束参数结构,程序仍需校验业务规则和权限,流式参数完整后才能执行。卡 · 严格模式与流式参数
- 可靠性控制。 应用通过参数校验、权限检查、有限重试、幂等处理和重复调用检测,控制工具调用失败与重复执行。卡 · 可靠性保障
- 工具发现。 工具很多时,应用先按任务路由或检索候选,再把少量工具的完整定义交给模型选择。卡 · 大量工具的选择
2. 调用链路
工具调用需要模型和应用交替完成。模型决定请求什么,应用负责校验和执行,双方通过调用 ID 对应请求与结果。
一次调用包含五个步骤:
- 应用在请求中提供工具名称、描述和参数 Schema。Schema 是规定字段类型、必填项等要求的结构规则。
- 模型根据工具描述和对话,判断是否需要调用。它可以直接回答,也可以返回一个或多个请求,每个请求带调用 ID、工具名和 JSON 参数。
- 应用检查工具是否存在,校验参数与权限,再执行对应函数。
- 应用把执行结果包装成工具结果,引用原调用 ID,并加入下一次模型请求。
- 模型读取结果后,继续请求工具或生成最终回答。
比如,get_order 可以描述为“按订单号查询订单状态和物流信息,用户询问订单进度时使用”。它的参数 order_id 是必填字符串,并要求订单号以 SO 开头。模型读到这些定义后,才有依据选择工具、填写参数。
以下片段展示 Anthropic Messages 的结果包装。execute_checked 负责校验和执行,返回结果字符串及错误标记。片段保留模型的原响应,再收集所有工具结果。完整实现还需处理停止原因及调用预算。
调用时可以给模型设置输出预算,例如 1024 Token。它限制该轮生成长度,工具执行超时和整个任务预算则由应用分别控制。
messages.append({"role": "assistant", "content": response.content})
results = []
for block in response.content:
if block.type == "tool_use":
content, failed = execute_checked(block.name, block.input)
results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": content,
"is_error": failed,
})
if results:
messages.append({"role": "user", "content": results})
Messages 用 tool_use_id 把结果关联到原来的 tool_use。结果放在紧随其后的用户消息中,以 tool_result 块标识。这里虽然使用 user 角色,块类型仍明确说明内容来自工具。并行调用的结果一起回传,assistant 原响应也要完整保留。
OpenAI Responses 使用 function_call_output 和 call_id。Chat Completions 使用 role: "tool" 与 tool_call_id。接入时按具体 API 转换,避免混用字段。
2.1 工具结果与调用关联
单独标识工具结果,是为了让模型和应用知道“谁返回了什么”。它解决三个问题:
- 请求对应:一次回复可以包含多个调用。调用 ID 把每个结果和原请求对应起来,即使结果完成顺序不同也能识别。
- 来源区分:工具结果类型说明这是执行反馈。外部网页或接口返回的文本仍按不可信数据处理,避免其中的指令改变任务。
- 协议完整性:应用要按接口要求为调用补齐结果。比如,Messages 中缺少对应的
tool_result会报错,所以失败调用也要返回错误结果。
3. 工具契约设计
工具契约是调用双方对用途、输入和输出的约定。模型会把名称、描述和参数说明作为选择依据,所以这些定义也是提示词的一部分。
| 部分 | 内容 |
|---|---|
| 名称 | 明确动作和对象,如 cancel_order |
| 描述 | 用途、适用条件与相似工具的区别 |
| 参数 | 类型、必填项、枚举、单位和来源 |
| 结果 | 状态、必要字段、分页或产物引用 |
| 错误 | 错误码、原因和可采取的下一步 |
| 副作用 | 写入范围、幂等条件与授权要求 |
设计工具时,要让模型容易选对、填对,并能读懂结果。可以从以下四个方面检查:
- 按任务封装:查询、计算和写入等能力适合交给程序执行。比如,
schedule_meeting内部查询日历并创建会议,能减少模型组合底层接口的步骤。封装后仍要清楚区分读取和写入的授权要求。 - 区分相似工具:名称用动作加对象,例如
search_orders和cancel_order。描述写清适用条件与差异,流程重复、难以区分的工具可以合并。 - 减少参数歧义:固定选项用枚举,也就是列出允许的值。参数标明格式、必填项、单位和来源,优先使用业务 ID,减少模型换算单位或猜数据库自增 ID 的需要。用户身份与凭据由程序注入。
- 返回可理解的结果:用名称、状态等业务字段代替内部编码。大结果可以分页或落盘并返回引用;截断时说明“已截断,共 3200 行,可用 page 参数读取”。模型知道结果不全后,才能决定是否继续读取。
错误也要帮助模型理解下一步。例如,INVALID_ORDER_ID: 订单号应以 SO 开头 指出了参数问题,比单独返回 500 更容易修正。错误码还应区分可重试的瞬时故障,以及需要修改参数或获得授权的问题。
订单号格式正确,只说明它符合结构规则。如果工具要求 ID 来自 search_orders 的结果,应在描述中写明这一要求。程序再核对 ID 是否来自前序查询,并检查订单是否存在、属于谁、当前是什么状态。
4. 可靠性保障
模型生成了合法请求之后,应用仍需判断这个操作是否有效、是否允许执行。可靠性检查要覆盖从生成到结果回传的完整过程。
| 阶段 | 检查与处理 |
|---|---|
| 生成 | 用 Schema 和枚举表达可选值 |
| 执行前 | 校验类型、业务条件、身份与访问范围 |
| 执行中 | 超时、并发限制与有界重试 |
| 执行后 | 结构化错误、结果裁剪与日志脱敏 |
| 循环中 | 检测重复失败,执行总预算 |
执行前,Schema 校验负责检查类型、必填项和枚举值。业务校验再检查 ID 是否存在、金额是否超限、时间是否在允许范围内。授权检查则根据当前用户和操作风险,判断能否访问对应数据或执行写入。
错误发生后,需要区分三类处理方式:
- 参数错误时,返回缺失字段或非法值及修正建议,让模型调整后再调用。
- 权限不足时,保留拒绝状态。需要额外确认的操作,应等待相应授权后再执行。
- 限流或瞬时故障时,可以退避重试,也就是等待一段时间后再尝试。重试同时受次数和总截止时间约束,避免任务一直卡住。
写入工具还要处理重复执行。幂等键用来识别同一次业务操作,让重复请求复用已有结果。写入超时则需要先确认操作是否已完成,再决定是否重试。
具体恢复方法见Agent 状态与持久化执行。授权与敏感信息传递见工具授权与执行沙箱。
应用还应记录工具名、参数和执行结果,并对日志中的敏感信息脱敏。相同调用反复出现、连续失败达到阈值时,应停止循环并报告部分结果或转人工处理。持续故障还可触发熔断,暂时停止向该工具发起请求。
“工具幻觉”指模型请求不存在的工具,或编造参数值。只提供当前任务需要的工具,能缩小选择范围。执行前再检查工具名是否在可用列表中、ID 是否来自前序查询,才能阻止这些错误进入实际操作。
4.1 严格模式与流式参数
严格模式用于减少参数格式错误。在 OpenAI 接口中,strict: true 让生成的参数遵守其支持的 Schema。
配置时,每个对象要设置 additionalProperties: false,表示拒绝额外字段。所有属性都列入 required;需要表达可选值时,让该字段接受 null。严格模式只保证结构约束,订单是否存在、额度是否足够和用户是否有权限,仍由程序检查。接口拒绝或输出未完成时,也要按对应状态处理。
流式返回还会带来参数不完整的问题。应用按调用 ID 或事件索引累积片段,收到参数结束事件后,再解析完整 JSON 并校验。片段中的目标或数值还会随着后续内容补齐,因此只能用于展示进度,执行要等完整请求就绪。
4.2 并行调用与依赖
同一轮生成多个调用,可以减少模型往返次数,但执行顺序仍取决于工具之间的依赖。互不依赖的只读查询可并行;后一步需要前一步返回的 ID 时,就要分阶段执行。
OpenAI 的 parallel_tool_calls=false 将同轮函数调用限制为零或一次,使用前需确认模型支持。这只限制每轮的调用数量,业务校验和整个循环的预算仍由应用控制。
5. 大量工具的选择
工具少、描述容易区分时,可以把完整定义一起交给模型。比如,十个左右的工具可以从这种方式开始评测。数量增多后,定义会占用更多上下文,相似工具也会增加选错的机会。
因此,工具达到几十个以上时,可以评估缩小候选范围的做法:
- 分层路由:先根据用户意图确定业务领域,再只加载该领域的工具。
- 工具检索:为描述建立关键词或向量索引,也可以组合两种检索方式。按请求取相关性最高的 Top-K 个候选,再加载它们的完整定义。Top-K 表示只取排名最靠前的 K 项。
- 按需发现:提供一个“搜索工具”的接口,让模型需要某项能力时再查找并加载。
- 合并固定流程:把经常一起调用的固定步骤封装成高层工具,减少候选数量。需要模型按规则判断的流程,则可用 Agent Skills 组织。
验证效果时,建立“请求—正确工具”的评测集。候选召回率检查正确工具是否进入候选,最终选择准确率则检查模型是否选中了它。需要选择单个工具时,可以统计 Top-1 命中率,也就是首选是否正确。新增工具或修改描述后,用相近意图和不适用请求一起回归。
选对工具后,也要控制返回结果的大小。冗余数据占满上下文窗口,会影响模型继续判断和生成回答。
6 · 面试题卡片
本页题目与参考回答
6.1 Function Calling 的完整调用链路是什么?为什么工具结果需要单独的 Tool Message?
考察重点
- 解释模型提出调用、应用校验和执行的分工。
- 说明调用 ID 如何对应结果,以及工具结果类型为何要区分来源。
参考回答
完整链路是应用提供工具定义,模型提出调用,应用校验并执行,再按调用 ID 回传结果供模型继续生成。
工具定义包含名称、描述和参数 JSON Schema。模型根据任务选择工具,并给出工具名和参数。应用检查参数、业务条件和权限后执行,把结果加入下一次请求,模型再决定继续调用还是回答。
独立的工具结果类型解决三个问题:
- 一次有多个调用时,ID 将结果与请求逐一对应。
- 类型说明内容来自工具,外部内容仍按不可信数据处理。
- 接口要求补齐结果时,失败调用也要返回错误,避免下一次请求因消息缺失而报错。
Anthropic Messages 用 tool_result 和 tool_use_id 回传。OpenAI Responses 则用 function_call_output 和 call_id。两者的封装不同,接入时要遵循所用 API。
6.2 如何保障工具调用的可靠性?模型传入错误或危险参数怎么办?
考察重点
- 解释 Schema 校验、业务校验和权限检查各自拦截什么问题。
- 说明错误回传、重试、幂等和重复调用检测怎样配合。
参考回答
工具可靠性由应用的参数校验、权限检查和执行控制共同保障,校验失败的请求应返回错误并停止执行。
执行前需要完成三层校验:
- Schema 检查类型、必填项和枚举值。
- 业务校验检查 ID、金额和时间范围。
- 授权检查判断当前用户能否操作。
要求 ID 来自前序查询时,程序还要核对来源,减少模型编造参数带来的错误。
参数错误返回原因和修正建议,让模型调整。权限不足保留拒绝状态,需要确认的操作等授权后执行。限流和瞬时故障可以有限退避重试,持续故障则通过熔断暂时停止调用。写入使用幂等键防重复,超时后先核对操作结果。
应用记录工具名、参数和结果,检查相同调用是否重复、失败是否连续出现。达到阈值或总预算后,停止循环并返回部分结果或转人工处理。
6.3 Tool 的设计原则是什么?如何设计参数 Schema 和错误码?
考察重点
- 说明怎样按任务封装工具,并设计名称、参数和返回字段。
- 能写出帮助模型修正的错误信息,并解释副作用声明与实际授权的关系。
相关内容:工具契约设计。
参考回答
Tool 应按用户任务封装查询、计算或写入能力,用清晰的契约说明用途、参数、结果和错误。
名称用动作加对象,描述写清适用条件和相似工具的差别。参数 Schema 标注类型、必填项、枚举和格式,字段说明给出单位与来源。优先用业务 ID,并由程序提供用户身份和凭据,减少模型猜值的需要。
结果只保留必要的业务字段,大结果分页或提供文件引用,截断时明确说明。错误码配上原因和修正建议,例如 INVALID_ORDER_ID: 订单号应以 SO 开头。瞬时故障可重试,参数错误需要修正,权限不足则需要相应授权。
固定步骤可组合进一个工具,例如在安排会议时完成日历查询和创建。工具还要声明写入范围、幂等条件及确认要求,实际权限由程序在执行时检查。
6.4 工具扩展到几百上千个时,如何保证模型选中正确的工具?
考察重点
- 解释工具定义增加后,上下文开销与误选机会为何增长。
- 能区分候选召回率与最终选择准确率,并用评测检查路由和检索。
相关内容:大量工具的选择。
参考回答
工具很多时,先按领域路由或检索候选,再加载少量完整定义,并用评测检查是否选对。
工具只有十个左右时,可以先尝试全部放入上下文。数量增多后,用意图分类缩小领域,或对工具描述做关键词与向量检索,取 Top-K 个候选。也可以让模型通过工具搜索接口按需发现能力。固定的多步调用封装成高层工具,需按规则判断的流程用 Skill 组织。
评测集记录每个请求应该使用的工具。候选召回率检查正确工具是否被找回,最终选择准确率检查模型是否选中它。单个工具选择可统计 Top-1 命中率。新增工具或修改描述后,回归相近意图和不适用请求,并限制返回数据大小。
6.5 strict 模式能保证工具调用安全吗,流式参数何时可以执行?
考察重点:解释严格模式能约束什么,以及流式参数为何必须完整后再校验执行。
相关内容:严格模式与流式参数。
参考回答
strict 模式只约束参数结构,工具安全仍靠业务校验和授权;流式参数要等完整请求到齐并通过校验后执行。
strict: true 让参数遵守接口支持的 Schema,但订单存在性、额度和用户权限由程序检查。收到拒绝或未完成状态时,也要分别处理。
流式参数按调用 ID 或事件索引累积,结束后再解析完整 JSON。分片尚未到齐时,目标或数值还会被后续内容补齐,所以提前执行会把未完成的参数当成最终请求。