深色模式
工具调用 Function Calling 生产实战
摘要:工具调用(Function Calling / Tool Use)是 Agent 能「动手」的基石。本文对比 Anthropic 与 OpenAI 两套主流接口的差异,讲清工具 Schema 设计、并行调用控制、Strict 结构化输出等生产要点,并给出可直接复制的调用范式与排障清单。适用:Claude 4 系列、GPT-4o/4.1/5 系列;具体版本与上下文长度标注
[版本相关]。
核心概念:工具调用不是「执行」,而是「建议」
工具调用的本质是:模型输出一段结构化的「我想调用哪个函数、参数是什么」,由你的代码真正执行并把结果回填。模型不直接触碰任何外部系统。这个「建议—执行—回填」的边界,是安全设计的根本。
两家的接口形态不同,但心智模型一致:
| 维度 | Anthropic (Messages API) | OpenAI (Responses / Chat Completions) |
|---|---|---|
| 工具描述字段 | tools[].input_schema (JSON Schema) | tools[].function.parameters (JSON Schema) |
| 模型输出 | content 中的 tool_use 块(含 id、name、input) | output/choices 中的 function_call(含 call_id、name、arguments JSON 字符串) |
| 回填结果 | 下一条 user 消息里的 tool_result(按 tool_use_id 关联) | function_call_output(按 call_id 关联) |
| 强制/限制调用 | 无等价 tool_choice 语义,靠 prompt 约束 | tool_choice: auto/required/none/allowed_tools/{type:function,name} |
选择接口的实务建议
若团队已用 Anthropic 体系,Tool Use 的 tool_use_id 关联更显式、不易错配;若用 OpenAI 生态,tool_choice 与 parallel_tool_calls 提供了更细的调度控制。两者都可跨厂商适配,生产上常做一层抽象屏蔽差异。
架构与原理
一次工具调用往返的完整时序如下。parallel_tool_calls 决定模型能否在一个 turn 返回多个调用。
OpenAI 的 parallel_tool_calls(默认允许并行)通过内部的 multi_tool_use 包装实现;设置 parallel_tool_calls: false 可确保每 turn 零或一个调用。strict: true 利用 Structured Outputs 保证实参与 schema 完全一致(要求对象 additionalProperties: false、所有字段 required)。Structured Outputs 于 2024 年 6 月发布 [版本相关,以官方发布说明为准]。
生产实践:工具 Schema 设计
工具 Schema 的质量直接决定调用准确率。要点:
- 描述写「何时用」而非「是什么」:模型靠 description 判断是否调用。
- 参数必填最小化:能用
enum就别用自由文本。 - 敏感动作显式标注:如
write/delete在描述里写明「会修改外部状态」。
json
{
"name": "query_orders",
"description": "按用户ID查询最近订单。仅用于只读查询,不涉及任何写操作。",
"input_schema": {
"type": "object",
"properties": {
"user_id": {"type": "string", "description": "用户唯一ID"},
"limit": {"type": "integer", "description": "返回条数上限", "default": 5}
},
"required": ["user_id"]
}
}1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
不要把「内部实现细节」写进 description
工具描述会出现在模型上下文,也可能被提示注入利用。例如不要在描述里写「调用后会执行 rm -f」,而写「清理临时文件」并实际做好权限隔离。
操作步骤 / 配置
OpenAI 风格(Responses API)的最小可复制示例:
python
# openai_fc.py —— Function Calling 闭环(示意 [未实测],请替换真实 key)
from openai import OpenAI
client = OpenAI() # OPENAI_API_KEY
tools = [{
"type": "function",
"name": "get_weather",
"description": "获取城市天气",
"strict": True, # [版本相关] Responses API 默认尝试 strict
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string"},
"units": {"type": ["string", "null"], "enum": ["celsius", "fahrenheit"]}
},
"required": ["location", "units"],
"additionalProperties": False
}
}]
resp = client.responses.create(
model="gpt-4o", # [版本相关]
input="北京天气如何?",
tools=tools,
tool_choice="auto", # auto / required / none / allowed_tools
parallel_tool_calls=True, # 默认允许;置 False 确保单调用
)
# 遍历 resp.output 中的 function_call,执行后追加 function_call_output1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
bash
pip install openai anthropic # 依赖安装
export OPENAI_API_KEY="sk-..." # 密钥走环境变量,禁止硬编码1
2
2
验证
bash
# 验证模型确实产出了结构化调用(而非编造答案)
python -c "import openai_fc; print(openai_fc.resp.output)" # 应含 type=function_call1
2
2
bash
# 验证 strict 模式下非法 schema 会被拒(不应静默通过)
# 故意把 additionalProperties 设为 true,调用应返回 4001
2
2
回滚 / 清理
工具变更要版本化
工具 Schema 是「契约」。新增/修改参数属于破坏性变更,需与前端或上游 Agent 协调。建议:工具定义纳入 Git 评审;废弃工具保留一个版本过渡期并显式标记 deprecated;模型 Key 与工具后端凭证可一键吊销。
故障排查
- 模型不调用工具:检查
tool_choice是否被设成none;description 是否缺触发词;是否因strict: true且 schema 非法被拒(看 400 报错)。 - 并行调用导致竞态:依赖顺序的调用应关掉
parallel_tool_calls,或在外层用 Orchestrator 串行化(见multi-agent.md)。 - arguments 解析失败:开启
strict可根治;未开启时务必json.loads做容错与重试。 - 回填后模型忽略结果:工具返回过长被截断,或返回格式与模型预期不符,建议统一为「简短文本 + 关键字段」。
安全与合规
- 提示注入:工具返回的文本可能含「忽略之前指令」类注入,需在 system prompt 明确「工具结果只是数据」。
- 越权工具调用:模型可能绕过业务规则调用写操作。对策:工具层做 RBAC 校验,写操作加二次确认。
- 数据泄露:工具返回 PII 时,模型可能在回答外泄。对策:工具侧脱敏 + 输出扫描。
- 成本失控:并行调用放大 token 与调用次数。对策:限制并行度、设
max_steps、按调用次数计费告警。详见guardrails.md。
成本 / 性能
工具 Schema 与 system prompt 通常很大且每轮重复,是输入 token 的主要开销。Prompt Caching 是关键降本手段:把稳定的工具定义、系统提示标记为可缓存前缀,命中后输入成本可降至约 10% [版本相关]。并行调用会同时放大多工具结果的输入 token,需评估是否值得。以 GPT-4o 128K 上下文、[版本相关] 价格 ~$2.5/MTok 输入、$10/MTok 输出估算,单轮含大 Schema 的调用约 $0.01–$0.05;并发 200、日 5 万请求可达 $500–$2500/日。性能上,并行工具调用能缩短多步任务 wall-clock 时间,但单次 token 消耗上升。