本文目录
一句话:Function Calling 是「让只会输出文字的模型,变得能驱动真实世界」的关键一跃。Agent 岗高频考点,也是后面手写 Agent 的地基。
核心误区先纠正:模型并不执行工具
很多人以为「Function Calling = 模型自己去调用了函数」。不是。 模型只做一件事:根据你给的工具说明,决定要不要调、调哪个、传什么参数,然后吐出一个结构化的调用请求。真正执行的,永远是你的代码。
这个分工很重要,面试常考:模型负责「决策」,你负责「执行」,再把结果喂回去让它「继续决策」。
三步走
① 把函数描述成「工具 schema」
模型根据工具 schema 与当前上下文提出调用请求。description 会影响工具选择,但还需要验证参数约束、任务覆盖和模型能力。下面延续第 2 篇已经准备好的 client 与 MODEL;订单查询使用固定演示数据,不访问真实订单。
# 真正干活的函数(模型只"说要调",执行是你的代码)
def search_order(order_id: str) -> str:
return f"订单 {order_id}:已发货,预计明天送达" # 真实场景换成查数据库 / 调 API
tools = [{
"type": "function",
"function": {
"name": "search_order",
"description": "根据订单号查询订单的物流状态", # 模型靠这句决定何时调
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "订单号,如 SO20240601"}
},
"required": ["order_id"],
},
},
}]② 模型返回「要调用的请求」
把 tools 一起发给模型,如果它决定调用,返回的 message.tool_calls 里就有函数名和参数(JSON 字符串):
messages = [{"role": "user", "content": "我的订单 SO20240601 到哪了?"}]
resp = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
msg = resp.choices[0].message
calls = msg.tool_calls or []
if not calls:
print(msg.content) # 模型也可能直接回答;不能假定一定返回工具调用
else:
for call in calls:
print(call.function.name)
print(call.function.arguments)③ 你执行,再把结果回灌
import json
if calls:
messages.append(msg.model_dump(exclude_none=True))
for call in calls:
if call.function.name != "search_order":
raise ValueError("未注册的工具")
args = json.loads(call.function.arguments)
if not isinstance(args, dict) or set(args) != {"order_id"} or not isinstance(args["order_id"], str):
raise ValueError("order_id必须是字符串,且不能有额外参数")
result = search_order(**args)
messages.append({"role": "tool", "tool_call_id": call.id, "content": result})
final = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
print(final.choices[0].message.content)「调用 → 执行 → 回灌 → 再调用」这个循环重复起来,就是 Agent(见第 7 篇)。
训练数据怎么造(面试加分点)
面试官常追问「Function Calling 的数据怎么来」。标准做法:
- 准备工具集和真实/构造的用户问题;
- 标注「该问题应触发哪个工具、什么参数」的正样本;
- 配难负例:语义相近但不该调工具的问题(避免模型见啥都调),以及该调却调错工具/错参数的对比样本;
- 覆盖「需要多步调用」「参数要从上下文里抽」等复杂情形。
常见坑
- description 太含糊:模型不知道何时该调 → 漏调或乱调。把触发条件写进描述。
- 不处理「模型不调工具」的情况:它可能直接回答,
tool_calls为空,要判空。 - 参数没校验就执行:模型给的参数可能不合法,执行前做 schema 校验 + 兜底。
- 多工具时不按名字分发:
tools里多个函数时,要按call.function.name路由到对应实现。
关联面试题
- 「Function Calling 在 Agent 里是怎么落地的?数据怎么构造?」
- 「怎么避免模型该调工具时不调、不该调时乱调?」
👉 去 题库 搜 Function Calling / 工具调用 / Agent。
训练营延伸
训练营会把 Function Calling 延伸为「业务 → 数据 → 训练 → 评估」练习。只有亲自完成、能说明评测方法并留有证据的部分,才适合写进个人简历。
工具请求不等于授权。接入真实订单时,还要校验请求者身份、订单归属和访问权限。
参考:官方工具调用流程。