Function Calling与工具编排#
一句话答案#
Function Calling 是 LLM 调用外部工具的核心机制,通过输出结构化 JSON 指定工具名和参数,配合多步依赖管理和参数校验实现复杂任务编排。
核心要点
1. Function Calling 工作流程#
用户提问 → LLM 推理
├── 直接回答 → 返回用户
└── 需要工具 → 输出 tool_call JSON(工具名+参数)
→ Runtime 校验参数 → 执行函数 → 结果回传 LLM
→ LLM 继续推理(可能再次调用工具)plaintext2. Tool Schema 设计原则#
| 原则 | 说明 | 反例 |
|---|---|---|
| 描述精确 | 说清用途、何时用/不用、参数含义 | ”处理数据”(太模糊) |
| 参数约束 | enum/required/类型严格限定 | 无约束的 string |
| 最小权限 | 只暴露必要参数 | 暴露 SQL 直接执行 |
| 幂等设计 | 相同参数多次调用结果一致 | 每次调用都创建新记录 |
3. 多步工具依赖管理#
- 顺序依赖:查用户→查订单→查物流(前者输出是后者输入)
- 并行调用:独立工具并行执行(查天气 + 查日历)
- 拓扑排序:复杂依赖图用 DAG 拓扑排序确定执行顺序
4. 工具幻觉与防御#
LLM 可能调用不存在的工具或编造参数。
防御手段:
- Schema 白名单校验:工具名必须在已注册列表中
- 参数类型检查:严格按 JSON Schema 校验
- 枚举值约束:限定参数取值范围
5. 错误处理链路#
工具调用
├── 参数校验失败 → 提示 LLM 修正参数重试
├── 执行超时(>5s)→ 重试1次(指数退避)
├── 执行异常 → 降级到备选工具
└── 无可用工具 → LLM 直接回答或提示用户plaintext6. 各家 API 的关键参数(以官方文档为准)#
| 能力 | OpenAI(推荐 Responses API) | Anthropic Claude(Messages API) | Google Gemini |
|---|---|---|---|
| 工具定义 | tools 中的 function(name/description/parameters) | tools 中的 name/description/input_schema,可选 input_examples | function_declarations |
| Schema 严格遵循 | strict: true:每个对象 additionalProperties: false、所有字段列入 required,可选字段用 null 类型表示;Responses API 会尽量把 schema 规范成 strict,不兼容时退回 best-effort | 工具定义上设 strict: true(strict tool use) | 有 VALIDATED 模式约束调用符合 schema |
| 选择策略 | tool_choice:auto(默认)/ required / none / 指定函数 / allowed_tools(限定子集) | tool_choice:auto(有工具时默认)/ any / tool(指定工具)/ none;部分模型不支持强制调用(any/tool 返回 400),此时用 auto + strict | 模式 AUTO(默认)/ ANY / NONE / VALIDATED,可限定允许调用的函数名 |
| 并行调用 | parallel_tool_calls: false 可保证每轮最多调一个工具 | tool_choice 里的 disable_parallel_tool_use | 支持并行调用和串联(compositional)调用 |
| 结果回传 | function_call_output,按 call_id 对应 | tool_result 内容块,按 tool_use_id 对应 | functionResponse |
要点:强制调用(required/any)时模型不会先输出解释文字;需要”保证调用 + 保证入参合法”时,常见组合是强制调用 + strict schema,模型不支持强制调用时用 auto + strict 或改用结构化输出。
7. 工具选择不一定交给 LLM#
工具少、选择条件能写成几个布尔信号(是否模糊、是否要时效、是否要记忆等)时,一种取舍是用规则引擎做路由:延迟从一次模型调用降到微秒级,结果确定、能写单元测试断言、每次决策带 reason 写进 trace;代价是新增工具或意图时要改规则,覆盖不到的长尾要回退给 LLM。另一种常见结构是同一个工具实现走两个入口:内部 Agent 用 Function Calling 直接调,外部客户端通过 MCP Server 暴露,Schema 只定义一次。
面试回答(2分钟版)
Function Calling是LLM调用外部工具的核心机制。工作流程是这样的:用户提问后LLM推理判断是否需要工具,如果需要就输出一段结构化的JSON,包含工具名和参数,由Runtime执行后把结果回传给LLM继续推理。这个过程可能循环多次直到生成最终答案。工具Schema设计是关键,要遵循几个原则:描述要精确不能模糊,参数要有类型和枚举约束防止LLM编造值,遵循最小权限原则只暴露必要参数,关键操作要设计为幂等的。多步工具编排分两种:有依赖关系的串行执行比如先查用户再查订单,独立的工具可以并行调用提高效率。工具幻觉是常见问题,LLM可能调用不存在的工具或编造参数,需要通过Schema白名单和参数校验来防御。错误处理要有降级链路:参数错误提示LLM修正重试,执行超时用指数退避重试一次,执行失败降级到备选工具,实在不行让LLM直接回答。高风险工具比如删除数据或发邮件要加人工审批环节。各家API都提供了控制参数:strict让参数严格符合Schema,tool_choice控制自动、强制或禁止调用,并行调用也能关掉。结合项目时可以讲:工具选择交给LLM还是规则、在哪一层做参数校验、用什么数据验证效果。
追问与易错
追问方向:
- Schema 设计太粗太细怎么权衡?工具描述多长合适? → 描述要说清做什么、什么时候用/不用、每个参数的含义和限制,参数用 enum/required 强约束。过粗导致工具幻觉(LLM 编造参数)。Anthropic 官方建议每个工具描述至少 3–4 句,复杂工具更多,复杂入参可加
input_examples;控制 token 的办法是合并相近工具、按需加载工具,而不是把描述砍到一句 - 多步工具依赖怎么避免死循环?最大深度怎么设? → 检测连续相同工具+相同参数的调用立即终止,设 max_steps(5-15)。用 DAG 拓扑排序管理依赖,有环则报错
- 高风险工具(删数据、发邮件)怎么加人工审批环节? → 工具分三级权限:read-only 自动执行、write 需用户确认、admin 需管理员审批。LangGraph 的 Human-in-the-loop 断点天然支持
- 并行工具调用的结果怎么合并回 Context? → 每个工具结果带调用 ID(OpenAI 的
call_id、Claude 的tool_use_id)对应回原调用,独立工具并行执行后统一追加,有依赖的串行等待 - 怎么保证模型一定调工具、且参数合法? → 强制调用(OpenAI
tool_choice: "required"或指定函数;Claudeany/tool)+strict: true;模型不支持强制调用时用auto+ strict,或改用结构化输出 - 工具选择一定要交给 LLM 吗? → 不一定。条件能写成少量布尔信号时用规则引擎更快、可测、可追溯,代价是扩展要改规则,长尾仍回退 LLM
易错点:
- ❌ “让 LLM 自己决定所有参数” → 必须做强类型校验,LLM 会编造不存在的枚举值;开了 strict 也只保证格式,业务合法性(权限、归属)仍要服务端校验
- ❌ “工具描述越短越省越好” → 描述是影响工具选择准确率的首要因素;要省 token 应合并相近工具、按需加载,而不是写得含糊
- ❌ “工具调用失败就报错” → 应该有降级链路:重试→备选工具→纯 LLM 回答
- ❌ “业务上下文(租户、用户)让 LLM 填参数” → 这类值应由服务端注入(如 Spring AI 的
ToolContext),不经过模型,防止越权