智能体面试准备(十八):Function Calling 全链路------Agent 真正"动手"的最后一公里
前面讲了单 Agent(ReAct)、多 Agent(B15)、安全(B16)、规划(B17)。但所有这些要"落地",都绕不开一个最基础也最关键的能力:Function Calling(函数调用)------让 LLM 决定"调哪个工具、传什么参数"。这一篇把全链路从定义到生产跑通:工具 schema 设计 → 模型决策 → 参数解析 → 执行 → 结果回填 → 并行调用与错误处理。每节给:原理 → 代码 → 面试速答 + 高频追问。配合 B14(MCP)看,刚好从"单进程工具"走到"跨进程协议"。
一、Function Calling 在 Agent 链路里的位置
它是 LLM 与外部世界之间的"接口层":
用户意图
│
▼
┌─────────┐ ① 选工具+填参 ③ 回填结果
│ LLM │◀────────────────┐
└────┬────┘ │
│ ② tool_call(JSON) │
▼ │
┌─────────┐ │
│ 执行器 │──▶ 真实工具/API │
└─────────┘ │
│ ④ observation │
└─────────────────────┘
没它,LLM 只能"说";有它,LLM 才能"做"。
二、工具 Schema:怎么告诉模型有哪些工具
用 JSON Schema 描述每个工具的元信息,喂给模型:
{
"name": "get_weather",
"description": "查询指定城市当前天气",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名,如 '北京'"},
"unit": {"type": "string", "enum": ["celsius","fahrenheit"], "default": "celsius"}
},
"required": ["city"]
}
}
关键原则:description 写清楚"什么时候用、参数怎么填",模型靠它选工具。描述含糊会导致选错工具或漏填参数。
三、模型决策与参数解析
主流模型(GPT-4o、Qwen、GLM 等)原生支持 function calling,返回结构化的 tool_calls:
import openai, json
tools = [get_weather_schema, search_schema] # 上面的 JSON Schema 列表
resp = openai.chat.completions.create(
model="gpt-4o",
messages=[{"role":"user","content":"北京今天天气咋样?"}],
tools=tools,
tool_choice="auto", # auto=模型自选;也可强制指定
)
msg = resp.choices[0].message
if msg.tool_calls:
for call in msg.tool_calls:
name = call.function.name
args = json.loads(call.function.arguments) # 模型填的参数
print(name, args) # get_weather {'city':'北京'}
面试速答:tool_choice="auto" 和强制指定有什么区别?auto 让模型自己判断是否调用、调哪个;强制(如 {"type":"function","function":{"name":"x"}})则模型必须调用指定工具,常用于固定流程。
四、执行器:调用真实工具并回填
把模型给的调用转成真实执行,再把结果作为新消息回传给模型:
def dispatch(name, args):
if name == "get_weather": return real_weather_api(args["city"])
if name == "search": return real_search(args["query"])
raise ValueError(f"unknown tool {name}")
# 把 assistant 的 tool_call 和 tool 结果都加入上下文
messages = [{"role":"user","content":"北京今天天气咋样?"}]
resp = openai.chat.completions.create(model="gpt-4o", messages=messages, tools=tools)
msg = resp.choices[0].message
messages.append(msg) # 必须保留带 tool_calls 的 assistant 消息
for call in msg.tool_calls:
result = dispatch(call.function.name, json.loads(call.function.arguments))
messages.append({"role":"tool", "tool_call_id": call.id, "content": str(result)})
final = openai.chat.completions.create(model="gpt-4o", messages=messages, tools=tools)
print(final.choices[0].message.content) # 自然语言回答
注意:tool 消息必须带 tool_call_id 且对应 assistant 的 call,否则 API 报错。
五、并行调用与错误处理(生产必备)
5.1 并行调用
模型可以在一次回复里返回多个 tool_call(如"查北京和上海天气"):
calls = msg.tool_calls or []
results = [dispatch(c.function.name, json.loads(c.function.arguments)) for c in calls]
# 用线程池并发执行真实工具,缩短延迟
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor() as ex:
results = list(ex.map(lambda c: dispatch(c.function.name,
json.loads(c.function.arguments)), calls))
5.2 错误处理与兜底
def safe_dispatch(call):
try:
return dispatch(call.function.name, json.loads(call.function.arguments))
except Exception as e:
# 把错误作为 observation 回传,让模型自我修正(如换参数/换工具)
return f"ERROR: {type(e).__name__}: {e}。请修正参数或换工具重试。"
把错误回传而非中断,模型往往能纠错(例如把城市名拼写改对)。
六、常见坑与最佳实践
| 坑 | 现象 | 对策 |
|---|---|---|
| 参数 JSON 不合法 | arguments 不是合法 JSON | 用 json.loads 容错 + 让模型重生成 |
| 工具描述含糊 | 选错工具/漏必填 | 写清 description + required |
| 上下文丢 tool_call_id | API 报不一致 | 严格保留 assistant+tool 消息对 |
| 工具执行慢/超时 | 整轮卡住 | 超时熔断 + 并行 + 降级 |
| 工具返回过大 | 撑爆上下文 | 截断/摘要后再回填 |
面试速答:为什么要把工具结果"回填"给模型而不是只执行?因为 LLM 是无状态的,它需要根据工具真实返回继续推理(例如"天气是雨,建议带伞"),不回填模型就不知道结果、无法生成最终回答。
七、面试速答 + 高频追问清单(汇总)
速答 TOP 8:
-
Function Calling 是 LLM 调外部工具的接口层,含 schema→决策→解析→执行→回填。
-
工具用 JSON Schema 描述,description 决定模型会不会选对。
-
模型返回 tool_calls(name + arguments JSON)。
-
执行后必须以 role=tool 且带 tool_call_id 回填上下文。
-
并行调用:一次返回多个 call,用线程池并发。
-
错误应回传 observation 让模型自我修正,而非直接中断。
-
tool_choice=auto 让模型自选,也可强制指定。
-
坑:JSON 不合法、描述含糊、丢 id、返回过大。
追问清单:
-
模型有时不按 schema 填参、编造字段,怎么约束?
-
几十上百个工具时,全塞进 context 会爆,怎么裁剪(tool retrieval)?
-
Function Calling 与 MCP(B14)的关系?MCP 解决了什么?
-
流式(streaming)场景下 tool_call 怎么逐步拼装?
-
如何防止模型陷入"反复调用同一工具"的死循环?
八、下一篇预告
Function Calling 讲完"动手的最后一公里",Agent 基础能力(感知-规划-行动-工具-安全)基本闭环。后续可进入 B19 RAG 评估 或 B20 可观测性( tracing/logging/评测),把 Agent 从"能跑"推向"可运维"。评论区告诉我优先级。