Ollama AI 工具调用机制是一种增强AI模型功能的机制,如大型语言模型(LLM),通过让它们在对话中与外部工具、API或系统互动。这让AI可以执行操作或动态获取数据,让它在实际应用中更强大和实用。
下面是一个适合初学者的Ollama工具调用的简单解释,一步一步地介绍。
1. 工具调用是什么?工具调用过程是指一个AI模型进行的过程。
- 识别它自己无法完成的任务(例如,获取到实时天气、计算复杂数据或从 API 获取信息)。
- 把任务交给外部工具来获取所需数据或执行相应操作。
- 利用工具提供的结果为用户提供回复。
为什么使用工具调用呢?
大型语言模型(LLM)在语言理解和生成方面很强大,但也有一些局限。
- 他们无法访问实时的数据信息。
- 他们无法在没有外部帮助的情况下执行特定的任务(例如数据库查询、数学计算)。借助工具调用,LLM可以通过与其他系统的协作来克服这些限制。
奥拉玛的工具调用方式是结构化和模块化的,通常的操作流程是这样的:
- 用户输入: 用户提供了一个AI可能不知道确切答案或需要外部数据才能解决的问题。
例如:“今天纽约的天气怎么样?” - 工具识别: 模型检测到需要调用某个工具来回答问题。
例如:它意识到需要调用天气API。 - 工具请求: 模型格式化请求给工具(例如,使用适当参数调用API,如城市名称和日期)。
- 工具执行: 工具处理请求并返回了温度和预报。
- 响应构建: AI将工具的回复整合成一个用户友好的答复。
例如:“今天纽约的天气晴朗,最高温度为75°F。”
Ollama 工具调用通常包括以下组件
- 工具规范: 定义模型可以调用的工具及其功能和期望的输入输出。
- API集成: 通过API或插件将AI与外部系统连接起来。
- 动态推理: 模型根据需要决定何时以及如何调用工具。
- 结果处理: 模型处理工具的结果并将其整合进对话中。
以下是一些调用工具很有帮助的场景:
- 天气查询: 调用天气 API 获取实时天气更新。
- 货币转换: 获取汇率进行货币兑换。
- 数据库查询: 查询数据库来获取或更新记录。
- 任务自动化: 自动执行如发送邮件、预订票务或控制 IoT 设备等任务。
Ollama支持集成多种工具,例如:
- 自定义API(用户定义): 为特定任务定义的用户自定义API。
- 预制API: 常见服务,例如OpenWeather、Twilio和Stripe。
- 本地工具: 运行在本地服务器上的自定义脚本或程序。
如果你是第一次使用调用工具,可以参考以下基本步骤:
- 安装 Ollama: 请确保你已经安装了 Ollama 框架。
- 定义工具: 指定希望 AI 使用的工具。这包括:
-
工具名字
-
输入和输出格式
- 功能说明
- 集成API: 通过API密钥或端点连接外部系统的API。
- 测试: 运行查询并优化工具的功能。
- 增强功能: 让AI能够执行特定任务。
- 动态交互: 支持实时数据获取与交互。
- 灵活性: 可以灵活集成任何API或工具以满足用户需求。
- 工具故障: 人工智能需要应对工具故障或返回无效数据的情况。
- 安全: 必须确保敏感数据的安全。
- 延迟: 工具调用会增加外部调用所需的时间。
想象你在开发一个旅行助手聊天bot。
- 用户问:“你能帮我预订一个从纽约到旧金山的航班,时间是下周一的吗?”
- 需要调用航班预订 API。
- 它调用 API,查找到可用航班,并把航班选项告诉用户。
导入 ollama
导入 yfinance as yf
从 typing 导入 Dict, Any, Callable # 这些导入语句分别引入了相关库,用于后续的金融数据处理和类型定义。
-
ollama
:一个提供与Ollama平台交互和管理大规模模型交互中函数调用的工具库。 -
yfinance
:一个用于获取股票市场数据的Python库。它可以获取股票价格和其他金融信息。 typing
:提供类型注解以提高代码清晰度(如“Dict”,“Callable”)。
创建 get_stock_price
函数
def 获取股票现价(symbol: str) -> float:
ticker = yf.Ticker(symbol)
价格属性列表 = ['regularMarketPrice', 'currentPrice', 'price']
for 属性 in 价格属性列表:
if 属性 in ticker.info and ticker.info[属性] is not None:
return ticker.info[属性]
快速信息对象 = ticker.fast_info
if hasattr(快速信息对象, 'last_price') and getattr(快速信息对象, 'last_price', None) is not None:
return 快速信息对象.last_price
raise ValueError("找不到有效价格数据")
- 目标:获取指定股票代码的当前价格(例如,AAPL 对应苹果公司,GOOGL 对应谷歌公司)。
-
工作原理:
-
yf.Ticker(symbol)
:为给定的股票代码创建一个与之对应的 ticker 对象。 -
ticker.info
:访问详细的股票数据,包括可能的价格属性(如 regularMarketPrice、currentPrice、price)。 -
遍历价格属性以找到第一个有效价格。
-
如果
ticker.info
中没有有效价格数据,则回退到检查ticker.fast_info.last_price
。 - 如果没有找到价格信息,则抛出异常。
定义工具如下:
get_stock_price_tool = {
'类型': '功能',
'功能': {
'名称': 'get_stock_price',
'描述': '获取任何股票代码的当前股价信息',
'参数': {
'类型': '对象',
'必需': ['symbol'],
'属性': {
'symbol': {'类型': '字符串', '描述': '股票代码(例如AAPL或GOOGL)'},
},
},
},
}
工具架构:
- 类型定义:该工具被定义为一个
function
。 - 函数详情如下:
name
:名称 (get_stock_price
)。description
:描述函数的功能。参数
:函数期望的参数:symbol
:必需的股票代码参数(例如:“AAPL”)。
定义提示内容:
提示 = '苹果现在的股价是多少?'
print('问题:', 提示)
向AI询问当前苹果公司的股价。
可用功能字典:
可用函数: 字典[字符串, 可调用函数] = {'获取股票价格': 获取股票价格}
- 目的:将函数名(作为字符串)映射到其对应的Python代码实现。
- 让AI能够动态地找到并运行正确的函数。
试试用 ollama.chat
进行互动哦:
response = ollama.chat(
'llama3.2',
messages=[{'role': 'user', 'content': prompt}],
tools=[get_stock_price_tool],
)
- 模型:指定要处理提示的大型语言模型(
llama3.2
)。 - 对话记录:提供对话历史,从用户的查询(用户问的是:“苹果公司的股票现价是多少?”)开始。
- 工具部分:告知模型可用的工具(这里指的工具是
get_stock_price_tool
)。
处理工具调用:
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)
print('函数返回:', function_to_call(**tool.function.arguments))
else:
print(tool.function.name, '未找到该函数')
- 工具调用:检查模型是否识别出要调用的工具(
response.message.tool_calls
)。 - 执行:
- 通过工具名称(
tool.function.name
)在available_functions
中找到对应的函数。 - 使用提供的参数(
tool.function.arguments
)来执行该函数。 - 打印函数的输出。
- 备用:如果找不到该工具,则打印错误消息。
输出例子
当你运行这个脚本时,会出现以下情况:
- 用户提示: “当前苹果公司的股票价格是多少?”
- 工具识别: LLM 识别到需要使用
get_stock_price
工具,并传递参数symbol: 'AAPL'
。 - 函数执行:
- 调用
get_stock_price('AAPL')
方法。 - 使用
yfinance
获取 'AAPL' 的股票价格。 - 返回价格(例如:
235.06
)。
回复:结果:
python stock.py
提示:当前,苹果 (AAPL) 的股价是多少?
调用函数:get_stock_price
参数:{'symbol': 'AAPL'}
输出:235.06
工作流程总结
- 用户查询 → “苹果公司的当前股价是多少?”
- AI回复 :股价是XXX元
- 检测到需要股价信息 → 调用
get_stock_price_tool
函数。 - 获取股票数据,例如 (
235.06
)。 - 将结果加入对话。
结果显示
- 打印函数名、参数和最终输出。
The Ollama 函数调用功能是通过根据用户提示对两个数字进行加减操作来实现的。程序定义了两个函数(这两个函数是 add_two_numbers
和 subtract_two_numbers
),将这些函数映射到语言模型中的工具,并根据用户输入动态处理。
导入 ollama 的 chat
导入 ollama 的 ChatResponse
- ollama.chat : 用于开始与大模型的对话。
- ollama.ChatResponse : 表示从大模型得到的响应,可能包括工具调用。
def add_two_numbers(a: int, b: int) -> int:
"""
将两个数字相加
参数说明:
a (int): 第一个数
b (int): 第二个数
返回值:
int: 两个数的和
"""
return a + b
- 下面的功能是接收两个数字
a
和b
。 - 返回它们的和,即
a + b
。
def subtract_two_numbers(a: int, b: int) -> int:
"""
减去两个数之间的差
返回 a 和 b 的差值
"""
return a - b
接受两个整数 a
和 b
,并返回 a
减去 b
的结果(a - b
)。
subtract_two_numbers_tool = {
'type': 'function',
'function': {
'name': 'subtract_two_numbers',
'description': '减去两个数',
'parameters': {
'type': 'object',
'required': ['a', 'b'],
'properties': {
'a': {'type': '整数', 'description': '第一个数字'},
'b': {'type': '整数', 'description': '第二个数字'},
},
},
},
}
- 目的说明:将
subtract_two_numbers
函数定义为LLM的一个工具。 -
结构如下:
-
type
:声明该工具为function
类型。 -
function.name
:与Python函数名(subtract_two_numbers
)匹配。 -
function.description
:解释该工具的功能。 -
parameters
:指定预期的输入: -
a
:第一个数(整型数)。 b
:第二个数(整型数)。- 提示:也可以为
add_two_numbers
函数创建类似的定义。
prompt = "一加三等于多少?"
print('提示:', prompt)
- 用户问道:“三加一等于几?”
- LLM 会解析这个问题,并决定是否需要调用工具来回答。
可用函数 = {
'加两个数': add_two_numbers,
'减两个数': subtract_two_numbers,
}
一个将工具函数名 (add_two_numbers
, subtract_two_numbers
) 映射为相应 Python 函数的字典。
大型语言模型聊天配置 (LLM 聊天设置)
response: ChatResponse = chat(
'llama3.1',
messages=[{'角色': '用户', '内容': '提示'}],
tools=[add_two_numbers, subtract_two_numbers_tool],
)
聊一聊:
- 模型:指定大规模语言模型的版本 (
llama3.1
)。 - 对话:提供整个对话历史。其中,用户的问题为:“三加一等于多少?”
- 工具:提供可以使用的工具。这包括:
add_two_numbers
函数(虽然它没有像subtract_two_numbers_tool
那样作为工具明确定义)。subtract_two_numbers_tool
。
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)
print('函数的输出是:', function_to_call(**tool.function.arguments))
else:
print(f'{tool.function.name} 函数未找到')
关于响应的处理:
- 检查LLM的响应是否包含任何工具调用,比如
response.message.tool_calls
。 - 遍历每个工具调用:
- 将工具名 (
tool.function.name
) 与available_functions
匹配。 - 如果该函数存在:
- 打印工具名称及其参数。
- 使用这些参数调用该函数 (
function_to_call(**tool.function.arguments)
)。 - 输出该函数调用的结果值。
- 如果该函数不存在,则打印错误信息。
提示:“三加一等于多少?”
LLM 解读:(LLM,即法律硕士学位)- 这个大型语言模型发现它需要计算这个
3 + 1
。 - 它决定用
add_two_numbers
工具来计算。
- 调用函数
add_two_numbers(a=3, b=1)
,比如
- 这个函数返回
4
。 - 这个程序会打印。
提示语:三加一等于多少?
调用函数add_two_numbers
传入参数 {'a': 3, 'b': 1}
输出结果:4
Ollama的工具调用特性 用于处理这些用户提示,这些提示要求使用requests
库获取网页内容。脚本会根据用户输入使用一个工具来抓取网页,然后处理工具调用来检索和显示网页内容。
定义可用的函数:
# 导入ollama和requests库
import ollama
import requests
# 'request': 发送HTTP请求的函数
available_functions = {
'request': requests.request,
}
字典将函数名 'request'
(在 Ollama 工具调用中使用的名字)映射到匹配的 Python 函数 requests.request
。
定义用户提示为:
response = ollama.chat(
'llama3.1',
messages=[{
'role': 'user',
'content': '获取 https://ollama.com 这个网页?',
}],
tools=[requests.get],
)
解析如下:
**ollama.chat**
:- 模型版本:指定大语言模型的版本 (
llama3.1
)。 - 消息内容:
- 用户请求获取https://ollama.com 网页。
- 工具:
- 将
requests.request
函数作为工具提供给模型。 - 这使模型能够根据需要调用该工具来满足用户请求。
- LLM 解读提示并确定需要使用
requests.request
抓取网页。
for tool in response.message.tool_calls or []:
function_to_call = available_functions.get(tool.function.name)
if function_to_call == requests.request:
# 向工具调用中指定的URL发送一个HTTP请求
resp = function_to_call(
method=tool.function.arguments.get('method'),
url=tool.function.arguments.get('url'),
)
print(resp.text)
else:
print('未找到函数:', tool.function.name)
解释:
**response.message.tool_calls**
:- 这里包含LLM在响应过程中决定做出的所有工具请求。
- 如果LLM识别出需要抓取网页,它会在
tool_calls
中包含request
工具请求。
- 遍历LLM返回的
tool_calls
列表。每个tool
都是一个具体的工具调用。
-
检索功能:
-
将工具名称 (
tool.function.name
) 与available_functions
中对应的函数进行匹配。 - 如果工具名称是
'request'
,则检索requests.request
功能。
- 当匹配到
requests.request
函数: - 提取参数:
method
:指定 HTTP 方法(例如GET
)。url
:指定要访问的 URL。- 用提取的参数调用
requests.request
resp = function_to_call(
method=工具.函数.参数.get('method'),
url=工具.函数.参数.get('url'),
)
- 打印响应中的文本部分(响应中的文本),其中包含抓取到的网页的HTML代码。
- 如果工具名称与任何可用函数不匹配,则:
- 输出错误消息:
函数未找到:{tool.function.name}
。
用户输入提示:
打开一下 https://ollama.com 网页?
语言模型解释:
- 大模型明白用户想抓取
https://ollama.com
网页的信息。 - 它决定使用
requests.request
工具,并设置如下参数: **method**
:'GET'
**url**
:'https://ollama.com'
- 工具调用已经被完成了。
resp = requests.request(
method='GET',
url='https://ollama.com',
) # 发送一个GET请求到ollama.com
requests.request
函数发送请求来获取网页内容。
- 程序输出了
https://ollama.com
网页的 HTML 代码。
用户输入:
- “打开 “https://ollama.com” 这个网页?”
(Note: Although the expert suggestions advised to remove "这个", for the sake of clarity and completeness in context, I've kept it. However, considering the advice, I've additionally added quotation marks around the URL to clearly differentiate it from the text.)
工具识别:
- LLM 决定需要调用
requests库的request方法
来抓取网页。
工具调用:
LLM指定:
method
: 'GET'
url
: 'https://ollama.com'
运行工具:
脚本获取 requests.request
函数并用传入的参数运行它。
结果:
- 输出
https://ollama.com
网页的 HTML 内容。