granite-4.0-h-350m实战教程:Ollama本地大模型调用函数API完整示例
granite-4.0-h-350m实战教程:Ollama本地大模型调用函数API完整示例
想不想在本地电脑上,让一个轻量级AI模型帮你查天气、算汇率,甚至调用各种工具?今天咱们就来聊聊怎么用Ollama部署的granite-4.0-h-350m模型,实现函数调用功能。
你可能听说过GPT-4、Claude这些大模型能调用函数,但它们在云端,需要联网,有时候还贵。granite-4.0-h-350m这个模型只有3.5亿参数,非常小巧,能在你的笔记本上就跑起来,而且它原生支持函数调用。这意味着你可以让它帮你执行一些预设好的任务,比如“查一下北京明天的天气”,它就能理解你的意图,并返回一个结构化的请求,你再用这个请求去调用真正的天气API。
听起来是不是很酷?这篇文章就是一份手把手的教程,我会带你从零开始,在Ollama上部署这个模型,然后写一个完整的Python程序,演示如何定义函数、如何让模型理解并调用这些函数。整个过程不需要复杂的配置,跟着做就行。
1. 环境准备与模型部署
在开始写代码之前,我们得先把模型跑起来。这里假设你已经安装了Ollama。如果还没装,去Ollama官网下载安装,几分钟就好。
1.1 拉取并运行模型
打开你的终端(Windows用PowerShell或CMD,Mac/Linux用Terminal),输入以下命令来拉取granite-4.0-h-350m模型:
ollama pull granite4:350m-h
这个命令会从Ollama的模型库下载这个模型。granite4:350m-h是它的标签。下载完成后,你可以用下面这个命令启动一个交互式的聊天会话,先简单试试模型的基本对话能力:
ollama run granite4:350m-h
启动后,在提示符后输入问题,比如“你好,介绍一下你自己”,看看它的回复。按 Ctrl+D 可以退出这个交互模式。
不过,我们的目标是通过API来调用它,这样才方便集成到我们自己的程序里。
1.2 启动Ollama的API服务
Ollama默认会在本地启动一个API服务。通常在你安装完Ollama并运行过模型后,这个服务就已经在后台运行了。你可以通过访问 http://localhost:11434 来验证。在浏览器里打开这个地址,如果看到Ollama的欢迎页面或者返回一个简单的JSON响应,说明服务正常。
如果服务没启动,你可以在终端直接运行 ollama serve 来启动它。这个服务会一直运行,直到你关闭终端或手动停止它。
好了,模型和服务都准备好了,接下来我们进入正题:函数调用。
2. 函数调用基础概念
在深入代码之前,咱们先花两分钟搞明白“函数调用”在这里到底是什么意思。别被这个词吓到,其实很简单。
生活化比喻:想象一下,你有一个非常得力的AI助理。你告诉它:“帮我查查上海明天会不会下雨。” 一个笨助理可能直接回复你:“好的,我去查一下。”然后就没了。但一个聪明的、支持函数调用的助理会怎么做呢?它会理解你的意图是“查询天气”,然后它不会自己去网上搜(因为它没联网),而是会生成一张标准的“工作单”递给你。这张工作单上写着:“任务:调用get_weather函数;参数:location=上海,date=明天。” 你拿到这张标准格式的工作单,就可以自己去执行(比如调用一个真实的天气API),然后把结果告诉助理,助理再组织成自然语言回复你。
在这个例子里:
- 你:用户,提出自然语言请求。
- AI助理:granite-4.0-h-350m模型。
- 工作单:模型生成的、结构化的“函数调用请求”(Function Call)。
- 预设函数:你事先告诉AI助理它有哪些工具可用,比如
get_weather。 - 你(再次):根据“工作单”执行真实函数,将结果返回给AI助理。
- 最终回复:AI助理结合函数执行结果,生成最终的自然语言答案。
所以,整个过程是:用户提问 → 模型理解意图并决定调用哪个函数 → 生成结构化调用请求 → 用户端执行真实函数 → 将结果返回模型 → 模型生成最终回答。
接下来,我们就用代码把这一切实现出来。
3. 实战:构建一个函数调用演示程序
我们将创建一个Python脚本,这个脚本能定义几个工具函数(比如查天气、算汇率),然后让granite模型根据我们的问题,决定是否以及如何调用这些函数。
3.1 安装必要的Python库
首先,确保你安装了Python(建议3.8以上版本)。然后,我们需要一个库来方便地调用Ollama的API。虽然可以用原始的requests库,但这里我们用langchain-community库,它封装得更好用。打开终端,运行:
pip install langchain-community
3.2 编写完整的Python脚本
创建一个新文件,比如叫做 granite_function_calling.py,然后把下面的代码复制进去。我会逐段解释。
# granite_function_calling.py
import json
from langchain_community.llms import Ollama
from typing import List, Dict, Any, Optional
# 1. 定义我们提供给模型的“工具”(函数)列表
# 这里用JSON Schema格式来描述每个函数能做什么、需要什么参数
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "获取指定城市的当前天气情况",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市名称,例如:北京、上海"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "温度单位,摄氏度或华氏度",
"default": "celsius"
}
},
"required": ["location"]
}
}
},
{
"type": "function",
"function": {
"name": "currency_converter",
"description": "将一种货币转换为另一种货币",
"parameters": {
"type": "object",
"properties": {
"amount": {
"type": "number",
"description": "需要转换的金额数量"
},
"from_currency": {
"type": "string",
"description": "原始货币代码,例如:USD, CNY, EUR"
},
"to_currency": {
"type": "string",
"description": "目标货币代码,例如:USD, CNY, EUR"
}
},
"required": ["amount", "from_currency", "to_currency"]
}
}
}
]
# 2. 模拟的函数实现
# 注意:这些是“模拟”函数,因为我们没有连接真实的天气或汇率API。
# 在实际应用中,你会在这里调用真正的API。
def mock_get_current_weather(location: str, unit: str = "celsius") -> str:
"""模拟获取天气的函数"""
# 这里应该调用真实的天气API,例如OpenWeatherMap
# 为了演示,我们返回一个模拟数据
weather_data = {
"北京": {"temperature": 22, "condition": "晴朗", "humidity": 65},
"上海": {"temperature": 25, "condition": "多云", "humidity": 80},
"广州": {"temperature": 28, "condition": "小雨", "humidity": 90},
}
data = weather_data.get(location, {"temperature": 20, "condition": "未知", "humidity": 70})
temp = data["temperature"]
if unit == "fahrenheit":
temp = temp * 9/5 + 32 # 转换为华氏度
return json.dumps({
"location": location,
"temperature": temp,
"unit": unit,
"condition": data["condition"],
"humidity": f"{data['humidity']}%"
}, ensure_ascii=False)
def mock_currency_converter(amount: float, from_currency: str, to_currency: str) -> str:
"""模拟货币转换的函数"""
# 这里应该调用真实的汇率API,例如exchangerate-api.com
# 为了演示,我们使用一个固定的模拟汇率表
exchange_rates = {
("USD", "CNY"): 7.25,
("CNY", "USD"): 0.138,
("EUR", "USD"): 1.08,
("USD", "EUR"): 0.926,
("CNY", "EUR"): 0.128,
("EUR", "CNY"): 7.81,
}
rate = exchange_rates.get((from_currency.upper(), to_currency.upper()))
if rate is None:
# 如果汇率表中没有,假设1:1(仅用于演示)
rate = 1.0
converted_amount = amount * rate
return json.dumps({
"amount": amount,
"from_currency": from_currency.upper(),
"to_currency": to_currency.upper(),
"converted_amount": round(converted_amount, 2),
"exchange_rate": rate
}, ensure_ascii=False)
# 3. 主函数:处理用户查询,协调模型和工具调用
def run_conversation(user_query: str):
"""
处理一次完整的对话回合:
1. 将用户查询和可用工具发送给模型。
2. 解析模型响应,看它是否想调用函数。
3. 如果调用,则执行对应的模拟函数。
4. 将函数结果返回给模型,获取最终回答。
"""
# 初始化Ollama客户端,连接到本地服务
llm = Ollama(
model="granite4:350m-h", # 指定我们刚下载的模型
base_url="http://localhost:11434", # Ollama API地址
temperature=0.1, # 较低的温度使输出更确定
)
# 第一步:将用户问题和工具定义一起发送给模型
# 我们需要构造一个符合模型函数调用格式的提示
messages = [
{
"role": "user",
"content": user_query
}
]
# 关键:我们需要告诉模型有哪些函数可用。
# 对于granite模型,我们可以通过`tools`参数传递工具定义。
# 注意:不同模型对工具调用的支持方式可能略有不同,以下是一种通用方法。
try:
# 使用LangChain的封装方法调用模型,并传入工具定义
response = llm.invoke(
input=json.dumps({
"messages": messages,
"tools": tools, # 传入工具列表
"tool_choice": "auto", # 让模型自动决定是否调用工具
}, ensure_ascii=False)
)
# 解析模型的响应
# 注意:实际响应格式需要根据Ollama API的返回调整。
# 这里假设响应是一个JSON字符串,其中包含`tool_calls`字段。
response_data = json.loads(response)
except Exception as e:
# 如果上面的方式不工作,可能是模型或API格式问题。
# 我们采用更直接的方式:构造一个清晰的提示词。
print(f"尝试标准工具调用时遇到问题: {e},将使用备用提示词方法。")
prompt = f"""
你是一个AI助手,可以调用以下工具(函数)来帮助用户:
{json.dumps(tools, indent=2, ensure_ascii=False)}
用户的问题是:{user_query}
请根据用户问题判断是否需要调用上述工具。
如果需要调用,请严格按照以下JSON格式回复,且只回复这个JSON,不要有其他文字:
{{
"tool_call": {{
"name": "函数名",
"arguments": {{
"参数1": "值1",
"参数2": "值2"
}}
}}
}}
如果不需要调用任何工具,请直接回答用户的问题。
"""
messages = [{"role": "user", "content": prompt}]
response = llm.invoke(json.dumps({"messages": messages}, ensure_ascii=False))
response_data = response # 这次响应可能是JSON,也可能是普通文本
# 第二步:判断模型是否要求调用函数
tool_call = None
if isinstance(response_data, str):
# 如果响应是字符串,尝试解析为JSON
try:
parsed = json.loads(response_data)
if "tool_call" in parsed:
tool_call = parsed["tool_call"]
except json.JSONDecodeError:
# 如果不是JSON,说明模型直接回答了问题
print("模型直接回复:")
print(response_data)
return response_data
elif isinstance(response_data, dict):
# 如果响应已经是字典,检查是否有工具调用
if "tool_calls" in response_data and response_data["tool_calls"]:
tool_call = response_data["tool_calls"][0] # 取第一个工具调用
elif "tool_call" in response_data:
tool_call = response_data["tool_call"]
# 第三步:如果有工具调用,执行对应的函数
if tool_call:
print(f"模型要求调用函数: {tool_call.get('name')}")
print(f"参数: {tool_call.get('arguments')}")
func_name = tool_call.get("name")
args = tool_call.get("arguments", {})
# 根据函数名调用对应的模拟函数
if func_name == "get_current_weather":
location = args.get("location", "北京")
unit = args.get("unit", "celsius")
result = mock_get_current_weather(location, unit)
print(f"模拟天气函数返回: {result}")
elif func_name == "currency_converter":
amount = args.get("amount", 1.0)
from_curr = args.get("from_currency", "USD")
to_curr = args.get("to_currency", "CNY")
result = mock_currency_converter(amount, from_curr, to_curr)
print(f"模拟汇率函数返回: {result}")
else:
result = json.dumps({"error": f"未知函数: {func_name}"}, ensure_ascii=False)
# 第四步:将函数执行结果发送回模型,让模型生成最终回答
follow_up_prompt = f"""
你之前要求调用函数 `{func_name}`,参数是:{args}。
函数的执行结果是:{result}
请根据这个结果,用友好、自然的中文回答用户最初的问题:“{user_query}”
"""
final_response = llm.invoke(follow_up_prompt)
print("\n模型的最终回答:")
print(final_response)
return final_response
else:
# 如果没有工具调用,直接输出模型的回复
print("模型直接回复:")
print(response if isinstance(response, str) else json.dumps(response, ensure_ascii=False, indent=2))
return response
# 4. 运行几个测试案例
if __name__ == "__main__":
print("=== Granite-4.0-H-350m 函数调用演示 ===\n")
test_queries = [
"北京今天的天气怎么样?",
"把100美元换成人民币是多少钱?",
"上海明天会下雨吗?",
"500欧元相当于多少美元?",
"你好,请介绍一下你自己。"
]
for i, query in enumerate(test_queries, 1):
print(f"\n{'='*50}")
print(f"测试案例 {i}: {query}")
print(f"{'='*50}")
run_conversation(query)
print("\n")
代码有点长,别担心,我把它拆开讲你就明白了。
3.3 代码详解
-
定义工具 (
tools列表):我们告诉模型,它有两个“工具”可以用:get_current_weather(查天气)和currency_converter(算汇率)。每个工具都用JSON Schema详细描述了它的功能、需要的参数(比如location城市名)以及参数的类型和说明。这就像给AI助理一本工具说明书。 -
模拟函数 (
mock_*函数):我们写了两个Python函数来模拟真实API的调用。在实际项目中,你会把mock_get_current_weather里的模拟数据替换成调用真正天气API(如和风天气、OpenWeatherMap)的代码。mock_currency_converter也一样。 -
主逻辑 (
run_conversation函数):这是核心。它做了四件事:- 询问模型:把用户的问题和工具说明书一起发给granite模型,问它:“嘿,用户这么问,你觉得需要用哪个工具吗?需要的话,把参数填好给我。”
- 解析响应:模型可能会回复一个结构化的JSON,说“我要调用
get_current_weather,参数是location=北京”。我们的代码会尝试解析这个响应。 - 执行函数:如果模型说要调用函数,我们就根据函数名和参数,去执行对应的模拟函数(第2步写的那个),拿到模拟结果(比如
{“temperature”: 22, “condition”: “晴朗”})。 - 生成最终答案:我们把函数执行的结果(原始数据)再塞回给模型,说:“工具用完了,结果是这个,你组织一下语言,回答用户最初的问题吧。” 模型就会生成像“北京今天天气晴朗,气温22摄氏度”这样自然的句子。
-
测试部分:最后,我们准备了几个测试问题,从简单的天气、汇率查询,到不需要调用工具的普通问候,来全面演示整个流程。
3.4 运行脚本并查看结果
保存好 granite_function_calling.py 文件,确保你的Ollama服务正在运行(ollama serve)。然后在终端里运行这个脚本:
python granite_function_calling.py
你会看到类似下面的输出(具体内容因模型随机性可能略有不同):
=== Granite-4.0-H-350m 函数调用演示 ===
==================================================
测试案例 1: 北京今天的天气怎么样?
==================================================
模型要求调用函数: get_current_weather
参数: {'location': '北京', 'unit': 'celsius'}
模拟天气函数返回: {"location": "北京", "temperature": 22, "unit": "celsius", "condition": "晴朗", "humidity": "65%"}
模型的最终回答:
北京今天天气晴朗,气温22摄氏度,湿度65%。
==================================================
测试案例 2: 把100美元换成人民币是多少钱?
==================================================
模型要求调用函数: currency_converter
参数: {'amount': 100, 'from_currency': 'USD', 'to_currency': 'CNY'}
模拟汇率函数返回: {"amount": 100, "from_currency": "USD", "to_currency": "CNY", "converted_amount": 725.0, "exchange_rate": 7.25}
模型的最终回答:
根据当前汇率,100美元可以兑换725.00人民币。
==================================================
测试案例 5: 你好,请介绍一下你自己。
==================================================
模型直接回复:
你好!我是Granite-4.0-H-350m,一个轻量级的指令微调语言模型。我由IBM开发,擅长理解和遵循指令,可以协助完成文本摘要、分类、问答、代码补全等多种任务。我支持包括中文在内的多种语言,并且设计得足够小巧,便于在本地设备上运行。有什么我可以帮助你的吗?
看!对于前两个问题,模型成功识别出需要调用函数,并生成了正确的参数。我们执行模拟函数后,模型也能很好地利用返回的数据,组织成流畅的答案。第五个问题不需要工具,模型就直接回答了。
4. 常见问题与进阶技巧
第一次运行可能会遇到一些小问题,这里有一些提示。
4.1 可能遇到的问题
- 连接错误:如果报错说连接不上
localhost:11434,请确认Ollama服务是否已经运行。在终端输入ollama serve并保持终端打开。 - 模型未找到:如果报错说找不到
granite4:350m-h模型,请确认你是否已经用ollama pull granite4:350m-h成功下载了模型。 - JSON解析错误:我们的代码尝试将模型回复解析为JSON。有时模型可能不会返回完美的JSON。代码里已经做了备选方案(使用更详细的提示词),如果遇到问题,可以检查打印出来的原始响应,调整提示词格式。
- 函数调用不触发:如果模型对你的问题(如“北京天气”)没有触发函数调用,而是直接回答“我不知道”,可以尝试:
- 在提示词中更明确地要求它使用工具。
- 检查工具的描述 (
description) 是否足够清晰,让模型明白什么时候该用它。
4.2 进阶技巧与优化
- 接入真实API:这是最重要的一步。把
mock_get_current_weather和mock_currency_converter函数里的模拟数据,替换成真正的API调用。你需要注册相应的服务(如天气API、汇率API),获取API Key,然后用requests库发起网络请求。 - 处理多个工具调用:我们的示例一次只处理一个工具调用。复杂的请求可能需要按顺序调用多个工具。你可以修改逻辑,让模型和代码进行多轮交互。
- 使用更成熟的框架:对于生产环境,建议使用像 LangChain 或 LlamaIndex 这样的框架。它们对工具调用有更强大、更稳定的封装。例如,在LangChain中,你可以用
@tool装饰器来定义工具,然后让Agent自动协调整个过程,代码会更简洁。 - 调整模型参数:在初始化
Ollama客户端时,可以调整temperature(创造性,值越低越确定)、top_p等参数来影响模型生成函数调用的决策。 - 设计更好的工具描述:工具函数的名字和描述 (
name,description) 至关重要。清晰、准确的描述能极大提高模型正确调用工具的几率。
5. 总结
通过这篇教程,我们完成了一次完整的本地大模型函数调用实践。我们来回顾一下关键步骤:
- 部署模型:使用Ollama拉取并运行轻量级的
granite-4.0-h-350m模型。 - 理解原理:函数调用的本质是让AI理解意图,并生成结构化的“工作单”(调用请求),由我们的程序来执行具体任务。
- 编写代码:我们创建了一个Python脚本,定义了工具、模拟了函数执行,并编写了协调模型与工具的主逻辑。
- 测试验证:通过几个查询,验证了模型能够成功触发函数调用,并利用返回结果生成友好答案。
这个方案的优点非常明显:完全本地化、隐私安全、成本极低。你不需要将数据发送到云端,也不需要为API调用付费,就能拥有一个具备基础工具调用能力的AI助手。
当然,这只是一个起点。granite-4.0-h-350m 作为一个轻量级模型,在复杂逻辑和工具调用的准确性上可能无法与GPT-4等顶级模型相比。但对于许多简单的自动化任务、个人助手应用或者作为学习原型,它已经足够强大且非常实用。
你可以基于这个框架,添加更多有趣的工具,比如查日历、发邮件、控制智能家居,打造一个专属于你本地环境的智能助手。动手试试吧,乐趣就在其中。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐


所有评论(0)