上周做完英语 Agent 后,我发现一个问题:用户得自己点按钮才能触发功能。
比如想学单词,得先点"学习单词"按钮,然后输入单词。
Agent 不会自己判断用户想干什么。
我想让它更智能一点——用户直接说"我想学 cat",Agent 就自动调用学习功能,而不是让用户先选按钮。
这就要用到 Function Calling。
一、什么是 Function Calling?
场景对比
| 没有 Function Calling | 有 Function Calling |
|---|---|
| AI:"我不会查天气" | AI:自动调用 get_weather() |
| AI:"我不会查你的订单" | AI:自动调用 get_order() |
| AI:"我不知道你学了什么" | AI:自动调用 get_learning_history() |
Function Calling = 给 AI 一个工具箱,它会自己判断用什么工具。
和"我写代码调用 API"的区别
| 方式 | 流程 |
|---|---|
| 我写代码调用 API | 我写代码 → 用户点按钮 → 代码调用 API → 返回结果 |
| Function Calling | 用户说话 → AI 自己判断 → AI 调用函数 → 返回结果 |
区别在于"谁在判断":
- 我写代码:我提前安排好,用户点按钮就调用某某接口
- Function Calling:AI实时判断用户的话,自己决定调用什么
打个比方:
| 方式 | 比喻 |
|---|---|
| 我写代码 | 我给服务员一个菜单,顾客只能点菜单上的菜 |
| Function Calling | 我给服务员一个厨房,顾客说要什么,服务员自己找食材做 |
二、Function Calling 怎么工作?
整个流程:
AI 不是真的会"学单词",但它知道这件事可以用
learn_word 函数来做。
三、实战:升级英语 Agent
目标很明确:
| 之前 | 现在 |
|---|---|
| 用户点按钮 → 输入单词 → 系统处理 | 用户说"我想学 cat" → Agent 自动调用学习功能 |
| 用户点按钮 → 等待随机单词 → 输入答案 | 用户说"给我一个测验题" → Agent 自动出题 |
一句话:把"点按钮"变成"说人话"。
步骤 1:定义工具箱
首先,我要告诉 Agent 有哪些工具可用:
TOOLS = [
{
"type": "function",
"function": {
"name": "learn_word",
"description": "学习一个英语单词,用户想学某个单词时调用",
"parameters": {
"type": "object",
"properties": {
"word": {"type": "string", "description": "要学习的英文单词"}
},
"required": ["word"]
}
}
},
{
"type": "function",
"function": {
"name": "get_random_word",
"description": "获取一个随机单词用于测验,用户想做测验时调用",
"parameters": {"type": "object", "properties": {}}
}
},
{
"type": "function",
"function": {
"name": "check_answer",
"description": "检查用户的测验答案,用户回答测验题时调用",
"parameters": {
"type": "object",
"properties": {
"user_answer": {"type": "string", "description": "用户的答案"}
},
"required": ["user_answer"]
}
}
},
{
"type": "function",
"function": {
"name": "get_history",
"description": "查看学习历史,用户想知道学了什么时调用",
"parameters": {"type": "object", "properties": {}}
}
},
{
"type": "function",
"function": {
"name": "get_wrong_words",
"description": "查看错题本,用户想复习错题时调用",
"parameters": {"type": "object", "properties": {}}
}
}
]
这就是"工具说明书",告诉 AI:
- 我有 5 个工具:学习、测验、检查答案、查历史、查错题
- 每个工具需要什么参数
步骤 2:实现真正的函数
AI 只会告诉我们"调用什么函数",不会真的执行函数。执行还得靠我们。
# 单词库
WORDS = [
{"en": "cat", "cn": "猫"},
{"en": "dog", "cn": "狗"},
{"en": "bird", "cn": "鸟"},
{"en": "apple", "cn": "苹果"},
{"en": "happy", "cn": "开心的"},
]
def learn_word(word):
"""学习单词"""
for w in WORDS:
if w["en"] == word.lower():
return {"success": True, "word": w["en"], "cn": w["cn"]}
return {"success": False, "message": f"单词 '{word}' 不在库里"}
def get_random_word():
"""获取测验题"""
import random
w = random.choice(WORDS)
return {"success": True, "cn": w["cn"], "en": w["en"]}
def check_answer(user_answer):
"""检查答案"""
# 检查是否正确...
def get_history():
"""查看历史"""
return {"success": True, "total": 5, "words": ["cat", "dog"]}
def get_wrong_words():
"""查看错题"""
return {"success": True, "wrong_words": [...]}
# 函数映射表
FUNCTION_MAP = {
"learn_word": learn_word,
"get_random_word": get_random_word,
"check_answer": check_answer,
"get_history": get_history,
"get_wrong_words": get_wrong_words
}
步骤 3:实现 Function Calling 流程
def chat(user_input: str) -> str:
# 1. 把用户消息发给 AI(带上工具定义)
messages = [
{"role": "system", "content": "你是英语学习助手,根据用户需求调用对应函数"},
{"role": "user", "content": user_input}
]
data = {
"model": "glm-5",
"messages": messages,
"tools": TOOLS, # 关键:告诉 AI 有哪些工具
"tool_choice": "auto" # 让 AI 自己决定是否调用
}
response = requests.post(API_URL, headers=API_HEADERS, json=data)
result = response.json()
# 2. 检查 AI 是否要调用函数
message = result["choices"][0]["message"]
if "tool_calls" in message and message["tool_calls"]:
# AI 要调用函数
for tool_call in message["tool_calls"]:
function_name = tool_call["function"]["name"]
arguments = json.loads(tool_call["function"]["arguments"])
# 3. 执行函数
# **arguments 是字典解包,把 {"word": "cat"} 变成 learn_word(word="cat")
func_result = FUNCTION_MAP[function_name](**arguments)
# 4. 把结果发给 AI,让它回答用户
messages.append({
"role": "tool",
"tool_call_id": tool_call["id"],
"name": function_name,
"content": json.dumps(func_result)
})
# 5. 再次调用 AI,获取最终回答
response2 = requests.post(API_URL, headers=API_HEADERS, json={"model": "glm-5", "messages": messages})
return response2.json()["choices"][0]["message"]["content"]
else:
# AI 直接回答了(不需要调用函数)
return message.get("content", "")
步骤 4:测试效果
测试 1:学习单词
用户: 我想学 cat 这个单词
AI: 让我帮你学习 cat...
→ 调用 learn_word("cat")
→ 结果:{"word": "cat", "cn": "猫"}
AI 回答: cat 是"猫"的意思,一种常见的宠物。
测试 2:获取测验题
用户: 给我一个测验题
AI: 测验来了!
→ 调用 get_random_word()
→ 结果:{"cn": "狗", "en": "dog"}
AI 回答: 中文意思是「狗」,请猜英文单词是什么?
测试 3:查历史
用户: 我学过哪些单词?
AI: 你已经学了 5 个单词:cat、dog、bird...
→ 调用 get_history()
成功!AI 能自动判断要调用什么函数。
四、踩坑记录
Q1:AI 返回了多个函数调用怎么办?
用户说"帮我查北京和上海的天气",AI 可能返回两个 get_weather 调用。
咋办:循环执行每个函数调用,把所有结果给 AI。
Q2:AI 没有调用函数,直接回答了?
用户说"你好",AI 直接回答问候。
原因:这句话不需要调用函数,检查 tool_calls 是否为空即可。
Q3:GLM-5 的 Function Calling 格式?
GLM-5 使用 OpenAI 兼容格式,可以直接用:
{
"choices": [{
"message": {
"tool_calls": [{
"id": "call_xxx",
"function": {
"name": "learn_word",
"arguments": "{\"word\": \"cat\"}"
}
}]
}
}]
}
五、和上周的英语 Agent 对比
| 上周的 Agent | 这周的 Agent |
|---|---|
| 用户点击按钮触发功能 | 用户说人话触发功能 |
| 功能写在代码里,我提前安排好 | AI 自己判断要用什么功能 |
| 只能做我定义的 4 种功能 | 可以扩展更多功能(只需加工具定义) |
本质区别:从"我安排"变成"AI 判断"。
六、今日总结
今天干了啥:
- ✅ 理解 Function Calling 是什么(AI 自己决定用什么工具)
- ✅ 理解 Function Calling 和"写代码调用 API"的区别(谁在判断)
- ✅ 把英语 Agent 升级成能"听懂人话"的版本
- ✅ 实现完整流程(用户说话 → AI 判断 → 执行函数 → AI 回答)
明天要干的:
- 学习 RAG(检索增强生成)
- 让 Agent 能读取用户的数据,回答"个性化问题"
写于 2026-04-21,Function Calling —— 让 Agent 听懂人话,自己干活