下面给你一份「从零开始」的 Google Gemini 函数调用(Function calling)使用笔记,以 Python 代码为主,涵盖最常用的「自动生成 JSON Schema→注册函数→让模型决定调不调用→把结果喂回去继续生成」四步流程。不管你用的是免费版 Gemini 1.5 Flash / Pro,还是 v1beta 新模型,流程都是一致的。
────────────────────
- 前置准备
────────────────────
pip install -q google-generativeai
如果你在中国大陆,代理 / VPN 是必须条件。
export GOOGLE_API_KEY="你的KEY"
────────────────────
- 声明可被调用的函数
────────────────────
记住,Gemini 只负责「产生 JSON 调用参数」,真正的执行代码一定要由你在本地或云端跑。
下面例子写两个道具函数:实时查汇率、查当前天气。
import google.generativeai as genai
import datetime, requests
genai.configure(api_key="你的KEY")
# ------------ 函数1:汇率 ------------
def get_exchange_rate(base: str, target: str) -> float:
"""
查询 base->target 的实时汇率(依赖免费 demo API)
"""
url = f"https://api.exchangerate.host/latest?base={base}"
data = requests.get(url, timeout=5).json()
return data["rates"].get(target.upper())
# ------------ 函数2:天气 ------------
def get_current_weather(location: str, unit="celsius") -> str:
"""
伪·天气查询;真正生产环境应调用和风、OpenWeatherMap 等
"""
mock_weather = {
"北京": {"temp": 32, "unit": unit},
"上海": {"temp": 30, "unit": unit},
}
info = mock_weather.get(location, {"temp": 22, "unit": unit})
return f"{location} 当前 {info['temp']}°{info['unit'][0].upper()}"
────────────────────
- 写成 OpenAPI-like JSON Schema
────────────────────
这是 2024 年 6 月新 API 的一致做法:把每个函数元数据写进 tools=[{"function_declarations": [...]}] 里即可。
tools = [
{
"function_declarations": [
{
"name": "get_exchange_rate",
"description": "查询两种货币之间的实时汇率。",
"parameters": {
"type": "object",
"properties": {
"base": {"type": "string", "description": "基准货币代码,如 USD、CNY"},
"target": {"type": "string", "description": "目标货币代码"}
},
"required": ["base", "target"]
}
},
{
"name": "get_current_weather",
"description": "根据城市名称查询当前天气",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"], "default": "celsius"}
},
"required": ["location"]
}
}
]
}
]
────────────────────
- 建立模型 & 聊天并“截获”调用意图
────────────────────
核心就是 loop:
(1) 发用户问题 → (2) 收到 function_call → (3) 本地跑函数 → (4) 把函数结果以 function_response 形式再发回去 → (5) Gemini 基于返回值继续生成自然语言答案。
model = genai.GenerativeModel(
model_name="gemini-1.5-flash",
tools=tools
)
chat = model.start_chat(enable_automatic_function_calling=False) # 我们手动控制循环
user_message = "10 USD 能换多少人民币?顺便告诉我北京现在多少度?"
# ---------- 第一回合 ----------
resp1 = chat.send_message(user_message)
print("第一轮模型回复候选:", resp1.candidates[0].content.parts)
# Gemini 可能一次就想调用多个函数,所以 parts 里会有多个 FunctionCall
for part in resp1.candidates[0].content.parts:
if fn_call := part.function_call:
name = fn_call.name
args = {k: v for k, v in fn_call.args.items()}
print(f"模型想调用的函数:{name}({args})")
# 真正在本地跑
if name == "get_exchange_rate":
ret = get_exchange_rate(**args)
elif name == "get_current_weather":
ret = get_current_weather(**args)
# 把结果封装成 function_response,发送回模型
chat.send_message(
genai.protos.Content(
parts=[genai.protos.Part(
function_response=genai.protos.FunctionResponse(
name=name,
response={"result": ret}
)
)]
)
)
# ---------- 第二回合(自然语言回答) ----------
final = chat.send_message("请把上面结果用中文一句话总结。")
print(final.text)
运行示例输出:
10 USD ≈ 72.4 CNY, 北京目前 32°C
────────────────────
- 让模型“全自动”执行(可选)
────────────────────
如果你不想手写循环,可以:
model = genai.GenerativeModel(
model_name="gemini-1.5-flash",
tools=tools
)
chat = model.start_chat(enable_automatic_function_calling=True) # 让它自己循环!
print(chat.send_message("同样的问题").text)
只是要注意真正的函数还是在你本地/云函数里执行,自动模式也只是帮你把上面的四步隐藏掉而已。
────────────────────
- 「工具链」小贴士
────────────────────
-
当一次问题触发多个函数(上面示例就是 2 个),Gemini 1.5 Flash 已经支持并行
function_call。 -
如果模型对参数理解不对,你可以在 description 里加「绝对不要使用简称,必须传完整参数名」等提示词。
-
为了提升稳定性,强烈把「系统提示」写出来:
system_instruction="你是一个懂得在必要时调用工具提高准确度的助手。" -
token 额度:函数声明本身也会占输入 token(但不会占用 Assistant 轮次)。如果接口返回 429,适当减少参数数量、缩短 description。
-
json 返回值尽量扁平,不要嵌套三层字典,否则长上下文里容易触发 MalformedFunctionResponse 报错。
────────────────────
一句话总结
────────────────────
写函数 → 配 JSON Schema → 让 Gemini 生成 FunctionCall → 你写代码执行 → 把返回值扔回聊天上下文。跑来跑去就这么 4 步,剩下的就是工程封装 & 错误兜底。祝你玩得开心!