第4章:Function Calling——让大模型从「聊天者」变成「执行者」
系列导读:从本章开始,我们进入 LLM 的「行动能力」阶段。如果你还没看第1章,建议先了解 LLM 的本质,再去理解为什么它能「调用工具」是真正的事半功倍。
一、Function Calling 到底是什么?
LLM 本身是一个文本生成器,它生成了天气查询请求,但它不能自己去调用 API。
Function Calling(工具调用)就是解决这个问题的机制:让 LLM 输出结构化的工具调用指令(通常是 JSON 格式),你的代码负责解析并执行真实的调用。
核心原则:模型只判断「该做什么」,代码负责「真正把它做了」。
二、Function Calling 的两轮对话流程
| |
这是最基础的流程,实际可能有多次工具调用循环。
具体例子
Round 1 - 用户输入:
“北京今天的天气怎么样?”
Round 1 - LLM 响应(不是答案,是工具调用指令):
| |
代码层 - 解析并执行:
| |
Round 2 - 把结果塞回对话:
| |
三、Schema 定义:关键工程细节
Function Calling 的核心是 schema 的定义。schema 告诉模型每个工具:
- name:工具名称,越具体越好
- description:工具的详细用途,模型靠这个决定要不要调它
- parameters:参数结构,包含每个参数名、类型、描述、是否必填
- required:必填参数列表
Schema 示例:
| |
description 是最关键的字段。模型完全靠 description 来判断该不该调这个工具。写 description 的技巧:
- 明确边界:不是什么都调,只在什么场景下调
- 给出例子:比如 “当用户问 xx 时调用”
- 避免触发词陷阱:description里别用模型的名字(如 “ChatGPT”),否则模型可能误触发
四、Function Calling 和「土办法」的区别
在没有 Function Calling 之前,开发者只能靠解析自然语言文本来判断模型要不要调工具:
| |
Function Calling 以后:
| |
关键区别:结构化输出 vs 自然语言解析。结构化输出准确率接近100%,自然语言解析经常抽风。
五、高级特性
1. 并行工具调用
模型可能在一次响应中输出多个 tool_calls,比如用户问"北京和上海的天气":
| |
你的代码可以并行执行两个调用,然后再把结果一起塞回去。
2. 强制使用工具
有些场景要求模型必须调工具,不提供直接回答:
| |
3. 多轮工具调用链
复杂任务可能需要多次调用:查天气 → 根据温度推荐衣服 → 查找推荐店铺的地址 → 查询交通路线。
每一轮把结果塞回 history,LLM 自动判断下一步该做什么。这就是 Agent 的基础。
六、常见坑
| 坑 | 解决方案 |
|---|---|
| 模型选错工具 | description 写清楚边界 + 用 tool_choice 限制 |
| 参数类型错误 | schema 中严格定义 enum/number/string |
| 函数结果太长塞爆 context | 摘要压缩后返回 |
| 工具调用死循环 | max_iterations 限制 + 超时熔断 |
| 结果格式不一致 | 在 function result 中也标准化输出格式 |
七、本章小结
- Function Calling = 模型决策 + 代码执行,两者严格分离
- Schema description 是核心,决定了模型是否选对工具、传对参数
- 并行调用、强制调用、多轮链式调用是高级用法
- 它是通往 Agent 的必经之路
思考题
- 为什么 Function Calling 要求模型输出的是 JSON schema 而不是自由文本?这背后的设计哲学是什么?
- 如果模型的 tool_calls 返回的参数含危险操作(如删除文件),你的拦截策略应该放在哪一层?