Ollama 是一个优秀的本地部署与管理大模型的框架。通过 Ollama,我们可以在本地部署、定制自己的大模型服务。Ollama 支持使用流行的模型(如 Llama 3.1、qwen 2.5)进行工具调用。针对用户的问题提示(promt),大模型可判断是否使用工具并执行工具,根据工具的执行结果来回答用户的问题。设定一系列的工具集,可以增强大模型的能力,使大模型能够执行更复杂的任务,或与外部世界进行交互。
函数即工具
在 Ollama 中,可以将 Python 函数作为工具传递给大模型,从而让大模型在回答问题时调用这些工具。 Ollama-python 库通过 Pydantic,对函数文档进行解析,生成 JSON Schema。函数的 JSON Schema 保存有以下信息:
- 工具类型,其值为 function
- 函数定义 function
- 函数名称 name
- 函数入参信息(需要的参数、每个参数的定义)
以数学运算的加法为例,加法函数定义为(使用类型注解和 Google 风格的文档字符串来定义函数):
def add_two_numbers(a: float, b: float) -> float:
"""
Add two numbers (including decimals)
Args:
a (float): The first number
b (float): The second number
Returns:
float: The sum of the two numbers
"""
return a + b
Ollama-python 会自动将上面的加法函数定义转为以下 JSON:
{
"type":"function",
"function":{
"name":"add_two_numbers",
"description":"Add two numbers (including decimals)",
"parameters":{
"type":"object",
"required":[
"a",
"b"
],
"properties":{
"a":{
"type":"float",
"description":"The first number"
},
"b":{
"type":"float",
"description":"The second numberr"
}
}
}
}
}
我们可以将函数作为工具,传递给大模型,大模型在回答用户问题时,会判断是否要调用工具:
from ollama import Client
from ollama import ChatResponse
client = Client()
prompt = '10 加 4 等于多少?'
messages = [{'role': 'user', 'content': prompt}]
response: ChatResponse = client.chat(
model='qwen2.5:7b',
messages=messages,
tools=[add_two_numbers] # add_two_numbers 可以是一个函数,或是包含函数信息的 json
)
数学运算应用
大模型在回答高位数字的数学运算时,一般给不出正确的答案。下面的示例,介绍如何通过调用工具,让大模型准确地回答高位数字运算相关的问题。
代码逻辑
-
定义工具函数:
- 定义了四个基本的数学运算函数:加法、减法、乘法和除法。
- 每个函数都带有类型注解和文档字符串。Ollama 可根据函数定义生成 JSON Schema。
- 除了直接传递函数,还可以手动定义工具的 JSON Schema(如 subtract_two_numbers_tool)。
-
调用工具并处理响应:
- 用户输入一个问题。
- Ollama 模型根据问题决定是否调用工具。如果模型请求调用工具,代码会根据模型提供的参数调用相应的函数,并将结果反馈给模型。
- 最终,模型根据工具的输出生成回答。
from ollama import Client
from ollama import ChatResponse
def add_two_numbers(a: float, b: float) -> float:
"""
Add two numbers (including decimals)
Args:
a (float): The first number
b (float): The second number
Returns:
float: The sum of the two numbers
"""
return a + b
def multiply_two_numbers(a: float, b: float) -> float:
"""
Multiply two numbers (including decimals)
Args:
a (float): The first number
b (float): The second number
Returns:
float: The product of the two numbers
"""
return a * b
def divide_two_numbers(a: float, b: float) -> float:
"""
Divide one number by another (including decimals)
Args:
a (float): The numerator
b (float): The denominator
Returns:
float: The quotient of a divided by b
"""
if b == 0:
raise ZeroDivisionError("Division by zero is not allowed.")
return a / b
def subtract_two_numbers(a: float, b: float) -> float:
"""
Subtract two numbers
"""
return a - b
# Tools can still be manually defined and passed into chat
subtract_two_numbers_tool = {
'type': 'function',
'function': {
'name': 'subtract_two_numbers',
'description': 'Subtract two numbers',
'parameters': {
'type': 'object',
'required': ['a', 'b'],
'properties': {
'a': {'type': 'float', 'description': 'The first number'},
'b': {'type': 'float', 'description': 'The second number'},
},
},
},
}
# 主函数:调用工具并处理模型的响应
def call_tools(prompt):
client = Client() # 创建 Ollama 客户端实例
messages = [{'role': 'user', 'content': prompt}] # 用户输入的消息
# 定义可用的函数工具
available_functions = {
'add_two_numbers': add_two_numbers,
'subtract_two_numbers': subtract_two_numbers,
'multiply_two_numbers': multiply_two_numbers,
'divide_two_numbers': divide_two_numbers
}
# 调用 Ollama 的 chat 方法,传递工具
response: ChatResponse = client.chat(
model='qwen2.5:7b', # 使用的模型
messages=messages, # 用户输入的消息
tools=[add_two_numbers, subtract_two_numbers_tool, multiply_two_numbers, divide_two_numbers]
)
# 如果模型请求调用工具
if response.message.tool_calls:
for tool in response.message.tool_calls:
if function_to_call := available_functions.get(tool.function.name): # 获取对应的函数
print('调用函数:', tool.function.name)
print('函数参数:', tool.function.arguments)
output = function_to_call(**tool.function.arguments) # 调用函数并获取输出
print('函数输出:', output)
else:
print('找不到函数:', tool.function.name)
messages.append(response.message) # 将工具调用结果添加到消息中
messages.append({'role': 'tool', 'content': str(output), 'name': tool.function.name})
# 获取最终响应
final_response = client.chat(model='qwen2.5:7b', messages=messages)
print('AI 助手回答:', final_response.message.content)
else:
print('AI 助手判断不需要调用工具')
final_response = client.chat(model='qwen2.5:7b', messages=messages)
print('AI 助手回答:', final_response.message.content)
# 程序入口
if __name__ == '__main__':
prompt = input("用户: ") # 获取用户输入
call_tools(prompt) # 调用主函数
提问示例
- 35.324 乘以 27035070694.348 是多少?
- 现在要进一批货,单价是 2456.324,数量是65345677,总价是多少? 程序运行结果(运行结果正确):
尝试让 deepseek-r1 回答上述问题。deepseek-r1可以回答上面的问题,但需要深度思考 231 秒。基于工具+ qwen2.5:7b,即可以较快地回答上面的问题。
目前上架 Ollama 的 deepseek-r1 模型还不支持工具调用。笔者会关注 deepseek-r1 模型后续在 Ollama 上的更新情况。若 Ollama 上的 deepseek-r1 模型支持工具调用,模型推理能力加上工具集,相信大模型服务能完成更复杂的任务。
文章来源:微信公众号-数智脉动,原始发表时间:2025年02月17日。