AI Agent 入门实战:Function Calling 让大模型学会调用工具
用一段可运行的代码,讲清大模型"调用工具"的完整链路与工程落地要点。
一、为什么 Agent 需要工具
大模型很擅长理解和生成语言,但它有两个天生短板:
- 知识有截止时间:训练数据之外的信息,它不知道,只能"编"。
- 只能输出文字:无法查询数据库、调用接口、执行操作。
把大模型当成一个聪明但"手被绑住"的大脑,**工具调用(Function Calling / Tool Use)**就是给它接上的双手。它让模型能查天气、检索知识库、下单、发消息——这才是 Agent 与"聊天机器人"的分水岭。
二、Function Calling 到底做了什么
一个常见误解是"模型会执行函数"。并不会。
模型做的事只有一件:根据你声明的工具描述,判断"该不该调工具、调哪个、参数填什么",然后输出一段结构化的调用意图(函数名 + JSON 参数)。真正的执行由你的程序完成,再把结果回填给模型。
声明工具 → 用户提问 → 模型输出调用意图 → 你的程序执行 → 结果回填 → 模型生成回答
三、一次完整调用流程
以"北京现在天气怎么样"为例:
- 声明工具:用 JSON Schema 告诉模型有一个
get_weather工具,参数是city。 - 模型判断:识别到问题需要实时天气数据,返回
tool_calls:get_weather(city="北京")。 - 本地执行:你的代码调用真实天气 API,拿到
{"temp_c": 26, "condition": "晴"}。 - 回填结果:把结果以
role: tool的消息追加到上下文。 - 模型收尾:基于工具结果生成自然语言回答;若信息还不够,它会继续发起下一次调用。
关键在于第 2、4 步:模型负责"决策",程序负责"执行",两者职责清晰分离。
四、可运行示例
下面用兼容 OpenAI 风格的接口(主流模型平台大多提供兼容接口)演示,核心逻辑与具体厂商无关。
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.openai.com/v1", api_key="YOUR_API_KEY")
# 1. 声明工具:描述越精确,模型选得越准
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的当前天气",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名,例如:北京"}
},
"required": ["city"]
}
}
}]
# 2. 工具的真实实现(此处用假数据,替换为真实天气 API 即可)
def get_weather(city: str) -> dict:
return {"city": city, "temp_c": 26, "condition": "晴"}
# 3. 单轮对话主循环
def chat(user_input: str) -> str:
messages = [{"role": "user", "content": user_input}]
resp = client.chat.completions.create(
model="gpt-4o-mini", messages=messages, tools=tools
)
msg = resp.choices[0].message
# 模型没想调工具,直接回答
if not msg.tool_calls:
return msg.content
# 把模型的调用意图写回上下文
messages.append(msg)
# 4. 逐个执行工具并回填结果
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = get_weather(**args)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result, ensure_ascii=False)
})
# 5. 再问一次模型,让它基于工具结果作答
final = client.chat.completions.create(
model="gpt-4o-mini", messages=messages, tools=tools
)
return final.choices[0].message.content
print(chat("北京现在天气怎么样?"))
运行后,你会看到模型先"要"工具,程序执行后再给出自然语言答案。
五、工程落地的最佳实践
demo 能跑不等于能上线。下面这些点决定了 Agent 是否稳定。
1. 工具描述是"第一生产力"。
模型选哪个工具,几乎只依据 description。写清楚"这个工具做什么、什么时候用、参数含义",比调模型参数更有效。
2. 不信任模型给的参数。
模型可能编造字段、给出非法值。参数必须做类型校验、范围校验,必填项缺失就返回结构化错误,让模型重试。
3. 工具数量要克制。
工具越多,模型选错的概率越高。经验上,同一场景超过 10~15 个工具就应考虑拆分或做工具路由。
4. 超时、重试与幂等。
外部接口会超时。给每次调用设超时;对可重试的读操作自动重试;对写操作(下单、扣款)要保证幂等,避免模型重试导致重复执行。
5. 安全是底线。
- 最小权限:工具只暴露必要能力,绝不让模型直接持有数据库写权限。
- 危险操作二次确认:删除、支付、发信等,必须由用户或风控确认后再执行。
- 防提示注入:工具返回的内容可能被恶意构造,不能当作可信指令。
6. 控制对话轮数与上下文。
限制最大调用轮数,防止死循环;工具返回的大结果要截断或摘要,避免上下文爆炸。
7. 可观测。
记录每次工具调用的入参、出参、耗时。出问题时,这是唯一能复盘的东西。
六、几个高频踩坑
| 现象 | 根因 | 对策 |
|---|---|---|
| 模型编造不存在的参数 | 工具描述含糊 / 缺 Schema 约束 | 收紧 JSON Schema,补全必填与枚举 |
| 选错工具 | 工具过多、描述重叠 | 精简工具、区分描述、做路由 |
| 陷入反复调用 | 结果回填格式不对 / 无轮数上限 | 规范回填、设置最大轮数 |
| 回答里出现"函数名" | 没把最终结果再交模型总结 | 执行后务必再请求一次模型 |
| 上下文越来越长 | 原始工具结果过大 | 截断 / 摘要后再回填 |
七、小结
Function Calling 的本质是一次职责分工:模型做决策,程序做执行。掌握这条链路后,你就能把大模型接上任意系统,做出真正能做事的 Agent。
下一步可以继续深入的方向:
- 多工具编排:让 Agent 连续调用多个工具完成复杂任务。
- ReAct 范式:引入"思考—行动—观察"循环,提升复杂推理能力。
- RAG:先检索私有知识,再让模型基于检索结果回答,缓解幻觉。
工具调用是 Agent 的地基。先把这一层打扎实,后面的规划、记忆、多智能体协作才有稳定的落脚点。
- 点赞
- 收藏
- 关注作者
评论(0)