Gemma 4 原生支持函数调用(Function Calling),意味着你可以用它做的不只是聊天——而是真正能调 API、查数据库、搜网页的 AI Agent。这篇教程从零开始,用 Python 带你写一个能用的 Agent。
函数调用是什么?
简单说,就是让模型在需要的时候调用你预先定义好的工具,而不是瞎猜。
比如你问「东京现在天气怎么样?」,模型不会编一个答案,而是输出一个结构化的请求来调你的天气 API,你执行完把结果返回去,模型再基于真实数据生成回答。
流程是这样的:
用户:「东京天气怎么样?」
→ 模型:{"function": "get_weather", "args": {"city": "Tokyo"}}
→ 你的代码调天气 API → 返回 {"temp": 22, "condition": "sunny"}
→ 模型:「东京现在 22°C,晴天。」用 JSON Schema 定义工具
首先要告诉 Gemma 4 有哪些工具可用。每个工具用 JSON Schema 描述名称、用途和参数:
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取城市的当前天气。当用户问天气时使用。",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名,如 'Tokyo'、'Beijing'"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位"
}
},
"required": ["city"]
}
}
},
{
"type": "function",
"function": {
"name": "calculate",
"description": "执行数学计算。用户问数学问题时使用。",
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "数学表达式,如 '2 + 2'、'sqrt(144)'"
}
},
"required": ["expression"]
}
}
},
{
"type": "function",
"function": {
"name": "web_search",
"description": "搜索网络获取最新信息。用户问近期事件或你不确定的事实时使用。",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索关键词"
},
"num_results": {
"type": "integer",
"description": "返回结果数量(默认 3)"
}
},
"required": ["query"]
}
}
}
]工具描述写得好不好很关键,模型就是根据描述来决定什么时候调哪个工具的。
完整的 Agent 循环
下面是一个用 Ollama API 跑 Gemma 4 的完整 Python Agent:
import json
import requests
import math
OLLAMA_URL = "http://localhost:11434/api/chat"
MODEL = "gemma4:12b"
# 工具实现
def get_weather(city: str, unit: str = "celsius") -> dict:
"""模拟天气 API —— 实际使用时替换成真实 API"""
return {
"city": city,
"temperature": 22,
"unit": unit,
"condition": "sunny",
"humidity": 45
}
def calculate(expression: str) -> dict:
"""安全的数学计算"""
allowed_names = {
"sqrt": math.sqrt,
"sin": math.sin,
"cos": math.cos,
"pi": math.pi,
"e": math.e,
"abs": abs,
"round": round
}
try:
result = eval(expression, {"__builtins__": {}}, allowed_names)
return {"expression": expression, "result": result}
except Exception as e:
return {"expression": expression, "error": str(e)}
def web_search(query: str, num_results: int = 3) -> dict:
"""模拟搜索 —— 实际使用时替换成真实搜索 API"""
return {
"query": query,
"results": [
{"title": f"关于 {query} 的结果", "snippet": "相关信息..."}
]
}
# 函数名到实现的映射
TOOL_MAP = {
"get_weather": get_weather,
"calculate": calculate,
"web_search": web_search,
}
def call_gemma(messages: list, tools: list) -> dict:
"""通过 Ollama 调用 Gemma 4"""
response = requests.post(OLLAMA_URL, json={
"model": MODEL,
"messages": messages,
"tools": tools,
"stream": False
})
return response.json()
def run_agent(user_input: str, tools: list, max_steps: int = 5):
"""多步骤 Agent 循环"""
messages = [
{
"role": "system",
"content": "你是一个有用的助手。需要时使用提供的工具。天气、计算和实时信息必须使用工具,不要猜测。"
},
{"role": "user", "content": user_input}
]
for step in range(max_steps):
response = call_gemma(messages, tools)
message = response["message"]
# 检查模型是否要调工具
if "tool_calls" in message and message["tool_calls"]:
for tool_call in message["tool_calls"]:
func_name = tool_call["function"]["name"]
func_args = tool_call["function"]["arguments"]
print(f" → 调用 {func_name}({func_args})")
# 执行工具
if func_name in TOOL_MAP:
result = TOOL_MAP[func_name](**func_args)
else:
result = {"error": f"未知工具: {func_name}"}
# 把工具调用和结果加到消息列表
messages.append(message)
messages.append({
"role": "tool",
"content": json.dumps(result, ensure_ascii=False)
})
else:
# 模型给出最终文本回答
print(f"Agent: {message['content']}")
return message["content"]
return "Agent 达到最大步数,未能完成。"
# 运行
if __name__ == "__main__":
run_agent("东京天气怎么样?8500 的 15% 是多少?", tools)这个 Agent 能处理多步骤查询。当你问「东京天气怎么样?8500 的 15% 是多少?」时,Gemma 4 会分别调 get_weather 和 calculate,然后把两个结果合成一个自然的回答。
多步骤 Agent 模式
真实的 Agent 经常需要链式调用,后面的调用依赖前面的结果:
# 示例:「帮我找附近的餐厅,然后查一下那边的天气」
# 第 1 步:模型调 web_search("附近餐厅")
# 第 2 步:模型看到结果,调 get_weather(从结果中提取的城市)
# 第 3 步:模型综合两个结果给出推荐
# Agent 循环天然支持这种模式——每次工具结果
# 加回对话后,模型根据完整历史决定下一步做什么结构化输出让工具调用更可靠
Gemma 4 支持结构化输出,可以强制模型按特定 JSON 格式回复。当你需要 Agent 的最终答案是机器可读格式时很有用:
response = requests.post(OLLAMA_URL, json={
"model": MODEL,
"messages": messages,
"format": {
"type": "object",
"properties": {
"answer": {"type": "string"},
"confidence": {"type": "number"},
"sources": {
"type": "array",
"items": {"type": "string"}
}
},
"required": ["answer", "confidence"]
},
"stream": False
})这保证输出是符合 schema 的合法 JSON,不用再解析自由格式的文本碰运气。
实用技巧
| 技巧 | 原因 |
|---|---|
| 工具描述写详细 | 模型靠描述决定用哪个工具 |
用 required 标记必填字段 | 防止模型漏掉关键参数 |
| 工具数量控制在 5-10 个 | 太多会让模型搞混 |
| 描述里加示例 | "如 'Beijing'、'Shanghai'" 帮模型正确格式化参数 |
| 优雅地处理错误 | 返回错误信息让模型可以重试或告知用户 |
| 设最大步数限制 | 防止模型一直调工具进入死循环 |
常见坑
模型无视工具直接回答: 在系统提示里明确要求用工具。加一句「天气、数学、实时信息必须使用工具,绝对不要猜测。」
参数类型不对: 模型给整数参数传了字符串 "3" 而不是 3?在工具实现里加类型转换。
模型不必要地调工具: 工具描述要精确说明什么时候用。「仅当用户明确问天气时使用」比「获取天气信息」好得多。
下一步
- 想先学 Ollama API 基础? 看 Gemma 4 API 教程 更温和的入门
- 要选适合 Agent 的模型? 12B 是最佳平衡——看 模型选择指南
- 做多模态 Agent? 看 多模态指南 给 Agent 加上视觉能力
函数调用让 Gemma 4 从聊天机器人变成真正的工具。接上真实的 API——天气、搜索、数据库、邮件——你就有了一个能在现实世界执行操作的 AI Agent,全部跑在你自己的机器上。



