Day 2:Function Calling 到底是什么?跟着AI老师从笨办法开始写
本文是「AI Agent学习日记」系列第二篇。 一个"规划狂魔但想坚持"的程序员,用AI陪伴式学习AI。 老师:Hermes Agent(AI Agent)
前言
昨天发了第一篇笔记,一天时间270浏览。说实话有点意外,毕竟我就是个记录学习过程的小透明。
今天继续。
昨天学了Agent的四个核心概念(对话历史、工具调用、Function Calling、规划能力),今天的目标是:把这四个概念串起来,做一个真正能用的小工具。
工具叫「代码片段管理器」------用来保存和搜索常用代码片段,比如设计模式模板、工具方法等。
从"笨办法"开始
AI老师说:先别急着用Function Calling,咱们用最笨的方式写一版,你才能理解Function Calling到底解决了什么问题。
于是第一版代码长这样:
python
class SnippetTools:
def parse_intent(self, text):
"""字符串匹配判断用户想干什么"""
if "保存" in text or "存" in text:
return "save"
elif "搜索" in text or "找" in text or "查找" in text:
return "search"
elif "列表" in text or "看看" in text:
return "list"
elif "删除" in text:
return "delete"
else:
return "chat"
运行效果对比:
| 用户输入 | 识别结果 |
|---|---|
| "保存一下这段代码" | ✅ 识别为 save |
| "存一下这段代码" | ✅ 识别为 save |
| "帮我留着这段代码" | ❌ 识别失败,跑到chat去了 |
问题来了:你永远穷举不完用户的所有说法。
"留着"、"记一下"、"收起来"、"帮我存下"......每换一种说法,你就要加一个关键词。
这就是"笨办法"的致命缺陷。
Function Calling 是什么?
一句话:让AI自己决定调用哪个工具,不用你写if-else。

对比一下:
| 维度 | 笨办法(字符串匹配) | Function Calling |
|---|---|---|
| 识别方式 | 关键词匹配 | AI语义理解 |
| 灵活性 | 低,必须用固定说法 | 高,各种表达都行 |
| 维护成本 | 高,需要不断加关键词 | 低,AI自动理解 |
| 理解能力 | ❌ 换个说法就废了 | ✅ 怎么说都能理解 |
实现步骤
第一步:定义工具Schema
这是Function Calling的核心------用JSON告诉AI,你有哪些工具,每个工具干什么,需要什么参数。

python
TOOLS_SCHEMA = [
{
"type": "function",
"function": {
"name": "save_snippet",
"description": "保存一段代码片段到本地存储", # 这句话很重要!
"parameters": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "要保存的代码内容"
},
"language": {
"type": "string",
"description": "编程语言,如 python、java",
"enum": ["java", "python", "javascript"]
},
"tags": {
"type": "array",
"items": {"type": "string"},
"description": "标签,如 ['单例模式', '创建型']"
}
},
"required": ["code", "language"]
}
}
},
# ... 还有 search_snippet、delete_snippet 等
]
⚠️ 注意 :description 写得越清楚,AI判断越准确!
好例子:
json
"description": "保存代码片段,参数包括代码内容、编程语言、标签和分类"
坏例子:
json
"description": "保存"
第二步:调用LLM,传入工具定义
python
response = client.chat.completions.create(
model="mimo-v2-flash",
messages=conversation_history,
tools=TOOLS_SCHEMA, # 关键:传入工具定义
tool_choice="auto" # 让AI自动决定是否调用工具
)
第三步:处理LLM返回的工具调用
python
message = response.choices[0].message
# LLM说:我要调用 save_snippet
if message.tool_calls:
for tool_call in message.tool_calls:
tool_name = tool_call.function.name # "save_snippet"
arguments = json.loads(tool_call.function.arguments)
# arguments = {"code": "...", "language": "java", "tags": ["单例模式"]}
# 执行工具
result = execute_tool(tool_name, arguments)
# 把结果告诉LLM,让它生成最终回复
conversation_history.append({
"role": "tool",
"content": json.dumps(result)
})
第四步:LLM生成最终回复
python
# 再调一次LLM,这次带上工具执行结果
final_response = client.chat.completions.create(
model="mimo-v2-flash",
messages=conversation_history
)
print(final_response.choices[0].message.content)
# 输出:代码已保存!ID: 1,分类:设计模式,标签:单例模式、创建型
完整调用流程

时序图

运行效果
csharp
用户: "帮我存一下这段Java代码"
小助手: "好的,请把代码发给我"
用户:
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
小助手: "代码已保存!
- ID: 1
- 语言: Java
- 标签: 设计模式、单例模式
- 文件: snippets.json"
不管是说"存一下"、"保存"、"帮我留着"、"记下来",LLM都能理解。
今日收获
| 问题 | 答案 | 为什么需要 |
|---|---|---|
| Function Calling是什么? | 让AI自己判断调用哪个工具,不用你写if-else | 穷举关键词太累了 |
| 核心是什么? | 工具Schema------用JSON描述工具的能力和参数 | AI需要知道有什么工具可用 |
| description重要吗? | 非常重要!写得越清楚,AI判断越准确 | AI靠description理解工具用途 |
| 调用流程是怎样的? | 用户说话 → AI判断 → 执行工具 → AI生成回复 | 完整的Agent交互闭环 |
常见问题
Q1: Function Calling和普通API调用有什么区别?
普通API调用是固定的:调用方知道要调什么。Function Calling是动态的:AI根据用户说的话决定调什么。
Q2: 需要为每个项目都写工具Schema吗?
是的,每次调用LLM时都要传入tools参数,告诉LLM当前项目有哪些工具。
Q3: 可以同时调用多个工具吗?
可以!LLM可以一次返回多个tool_calls,Agent会依次执行。
明天预告
设计模式第一弹------单例模式。
每天学一个设计模式,结合今天做的代码片段管理器,边学边存,学一个存一个。一个月下来,常用的23种设计模式就能过一遍。
系列文章
- Day 1:Agent到底是什么?四个概念搞明白
- Day 2:Function Calling到底是什么?跟着AI老师从笨办法开始写
- Day 3:设计模式第一弹------单例模式(明天更新)
我是宸一,一个"规划狂魔但想坚持"的Java程序员。 正在用AI陪伴式学习AI,欢迎关注,一起进步。 老师:Hermes Agent(AI Agent)