工具调用与 Function Calling 提示工程
工具调用(Tool Use,也常被称为 Function Calling)是大语言模型从「只会聊天」走向「能办事」的关键能力。它让模型在生成自然语言之外,还能输出结构化的函数调用请求,由你的应用执行真实逻辑,再把结果回填给模型,最终合成回答。本文聚焦提示工程视角:如何在协议层面描述工具、如何通过提示引导模型正确决策,以及如何在实战中跑通一次完整的 JSON 往返。
为什么大模型需要工具调用
即便是最强的大模型,也存在三类内生短板,单靠提示词本身无法克服,必须借助外部工具:
- 知识时效短板。模型的参数化知识停留在训练截止时间,无法获知实时新闻、最新股价、当日天气。通过工具把「查询」动作交给外部系统,模型就能基于当前数据作答。
- 计算能力短板。大模型擅长语言推理,却不擅长精确算术、统计聚合、符号求解。把计算交给代码解释器或业务函数,可避免幻觉式算错。
- 外部系统访问短板。模型本身无法直接读写数据库、调用支付接口、操作日历或发消息。工具调用是模型与真实世界系统之间的唯一桥梁。
换言之,工具调用把模型定位为「决策者与编排者」:它决定何时需要外部能力、以什么参数调用,而把「执行」交给可信的系统代码。这正是后续所有 Agent 范式的基础。
Function Calling 与 Tool Use 的基本协议
无论 OpenAI、Anthropic 还是其他厂商,工具调用的核心协议高度一致,可以抽象为一个四步循环:
- 用 JSON Schema 描述函数。你向模型声明一组可用工具,每个工具包含名称、用途描述,以及参数的 JSON Schema。Schema 定义了参数的类型、必填项、枚举值与嵌套结构。
- 模型返回调用请求。模型不直接执行函数,而是输出一段结构化请求,例如函数名与参数字典(JSON 字符串)。此时控制权交还应用。
- 应用执行并回填结果。你的代码真正运行该函数(查天气、读数据库、算指标),把结果作为一条新消息回传给模型,并带上调用标识以便模型对齐上下文。
- 模型合成最终回答。模型读取工具结果,继续推理并产出面向用户的自然语言答案;若信息仍不足,可再次发起调用,形成多轮循环。
理解这一协议的关键点在于:模型产出的是「意图」,而非「副作用」。真正的执行永远在你的应用侧,因此工具调用天然安全可控,也便于做权限、审计与错误处理。
官方文档要点:OpenAI 与 Anthropic
两家主流平台的官方文档对协议细节有清晰定义,以下要点均来自其当前文档。
OpenAI:Function Calling / Tools
OpenAI 把函数视为一类「工具」,在请求中通过 tools 数组声明。每个函数定义包含 type、name、description 与 parameters(JSON Schema 对象),并可开启 strict 严格模式以保证调用必然符合 schema。
模型一次可返回零个、一个或多个调用;每个调用带有 call_id、name 与 arguments(JSON 编码的参数串)。应用侧通过 function_call_output 消息、以 call_id 引用原调用,把执行结果回填。
关于并行与流式,官方文档明确:
- 并行调用:较新模型可在单轮内并行调用多个函数,可用
parallel_tool_calls: false限制为最多一次调用。 - 流式:设置
stream: true后,会持续推送response.output_item.added、response.function_call_arguments.delta、response.function_call_arguments.done、response.output_item.done等事件;应用需自行拼接delta片段得到完整arguments。
Anthropic:Tool Use
Anthropic 的 Messages API 用 tools 数组声明工具,字段为 name、description 与 input_schema(JSON Schema)。模型在需要时返回 tool_use 内容块,并令 stop_reason 为 "tool_use";你的代码执行后,通过 tool_result 内容块、以 tool_use_id 回传结果。
官方文档区分两类工具:
- 客户端工具(含你自定义的函数):在你的应用中执行,模型给出
tool_use块,你运行后回传tool_result。 - 服务端工具(如 web_search、web_fetch、code_execution):在 Anthropic 基础设施上执行,你直接拿到结果,无需编写执行逻辑。
值得注意的提示与协议控制项:
tool_choice默认{"type": "auto"},由模型自行决定是否调用;也可强制调用指定工具。disable_parallel_tool_use: true可限制每轮最多一次调用。- 自定义工具可加
strict: true,保证调用严格符合 schema。 - 在系统提示中加入「Use the tools to investigate before responding.」之类指令,可显著提升工具的触发概率。
两家差异主要在命名与块结构(OpenAI 用 function_call / function_call_output 与 call_id;Anthropic 用 tool_use / tool_result 与 tool_use_id),但协议本质相同,提示设计原则也通用。
提示设计技巧
工具调用能否稳定工作,很大程度取决于你如何「写工具的说明书」。以下技巧可直接提升命中率与健壮性。
写清晰的函数描述
模型的调用决策几乎完全依赖 description。描述要说明「这个工具能做什么」以及「什么时候该用它」,避免含糊。例如「获取指定城市的当前天气」比「天气查询」更可操作。参数级 description 同样重要,能帮助模型正确填充字段。
设计严格且最小化的 Schema
- 用
enum收敛取值范围,减少自由文本带来的歧义。 - 能用
required固化的字段尽量固化,并配合严格模式(strict: true要求additionalProperties: false且所有属性标required)。 - 避免把本可枚举的语义塞进长字符串,必要时用嵌套对象表达结构。
显式设计错误处理
工具执行可能失败。约定好错误回传格式:成功时返回结构化数据,失败时返回明确错误码与可读信息。把错误结果回填给模型,让它有机会重试、换参数或改用其他工具,而不是在应用层直接中断。
让模型决定何时调用
优先使用 auto / tool_choice 默认行为,让模型基于用户意图自行判断。仅在确有必要(如必须强制走某流程)时才强制调用。过度强制会削弱模型的灵活性,也容易在低相关场景产生无谓调用。
善用并行与批处理
当多个独立查询互不依赖时,让模型并行调用可显著降低总时延。若业务要求顺序或隔离,则显式关闭并行。提示中可点明「这些查询相互独立,可一并发起」。
与 ReAct 等 Agent 范式的关系
ReAct(Reason + Act)是一种经典的 Agent 推理范式:模型交替进行「思考(推理)」与「行动(调用工具)」,把工具返回作为下一步观察,循环直至得出答案。
工具调用正是 ReAct 的底层执行机制。ReAct 中的「行动」在协议层就体现为一次 Function Calling / Tool Use 请求;「观察」对应应用回填的 tool_result / function_call_output。区别在于:
- 早期 ReAct 常把「思考—行动—观察」以自然语言拼进提示,依赖模型解析文本;
- 现代工具调用把这些结构显式化为 JSON 块,更可靠、更易解析,也更省 token。
因此,掌握工具调用的提示工程,就掌握了构建 Agent 的核心环(agentic loop):感知需求 -> 选工具 -> 填参数 -> 收结果 -> 再决策。多工具、多步规划、记忆与反思,都是在这一环之上叠加的能力。
实战:天气查询的完整 JSON 往返
下面以 OpenAI 风格(Responses API)展示一个天气查询从请求到最终回答的完整 JSON 往返。假设用户问:「北京今天天气怎么样?」
第一步,应用声明工具并发起请求:
{
"model": "gpt-5",
"input": "北京今天天气怎么样?",
"tools": [
{
"type": "function",
"name": "get_weather",
"description": "获取指定城市的当前天气信息",
"parameters": {
"type": "object",
"properties": {
"location": { "type": "string", "description": "城市名称,例如:北京" },
"unit": { "type": "string", "enum": ["celsius", "fahrenheit"] }
},
"required": ["location"],
"additionalProperties": false
},
"strict": true
}
]
}
第二步,模型不直接回答,而是返回结构化调用请求:
{
"output": [
{
"type": "function_call",
"call_id": "call_01",
"name": "get_weather",
"arguments": "{\"location\":\"北京\",\"unit\":\"celsius\"}"
}
]
}
第三步,应用执行 get_weather 函数,并把结果以 function_call_output 回填,注意用 call_id 对齐原调用:
{
"input": [
{
"type": "function_call_output",
"call_id": "call_01",
"output": "{\"location\":\"北京\",\"temp_c\":26,\"condition\":\"晴\",\"humidity\":40}"
}
]
}
第四步,模型读取结果,合成最终自然语言回答:
{
"output": [
{
"type": "message",
"content": "北京今天天气晴,气温 26 摄氏度,湿度 40%。"
}
]
}
整个过程中,模型始终只产出「调用意图」与「最终答案」,真正的天气数据由你的应用提供。若 get_weather 因城市拼写错误失败,只需把错误结果回填,模型便会修正参数重试,无需改动提示逻辑。
小结
工具调用让大模型突破知识时效、计算与外部系统访问的三重限制,其本质是「模型决策、应用执行、结果回填」的结构化循环。提示工程的关键在于:用清晰的描述和严格的 JSON Schema 把工具讲明白,把错误处理与重试交给协议循环,并尊重模型「何时调用」的自主判断。理解了这一协议,也就掌握了 ReAct 乃至各类 Agent 的核心执行环。
参考与延伸阅读
- OpenAI 官方 Function Calling 指南(WebFetch 已核实可访问):https://platform.openai.com/docs/guides/function-calling
- Anthropic 官方 Tool Use 文档(WebFetch 已核实可访问;原地址会重定向至 https://platform.claude.com/docs/en/agents-and-tools/tool-use ):https://docs.anthropic.com/en/docs/build-with-claude/tool-use
- JSON Schema 官方网站(WebFetch 已核实可访问,用于定义工具参数 schema):https://json-schema.org/