Python OpenAI库调用Ollama实现对工具的调用

半兽人 发表于: 2025-04-28   最后更新时间: 2025-04-28 15:17:14  
{{totalSubscript}} 订阅, 36 游览

以下是一个简单的 Python 脚本,展示如何用 OpenAI 库调用 Ollama 的 qwen2.5 模型,实现对工具的调用:

import asyncio

from openai import AsyncOpenAI


class LLM:
    def __init__(self):
        self.model = "qwen2.5"
        self.max_tokens = 4096
        self.base_url = "http://127.0.0.1:11434/v1"
        self.api_key = "key"
        self.client = AsyncOpenAI(api_key=self.api_key, base_url=self.base_url)

    async def ask_tool(self, prompt, tools=None, temperature=1.0, timeout=None, **kwargs):
        """
        向模型发送带有工具调用的提示并获取回复

        Args:
            prompt (str): 用户输入的提示文本
            tools (list, optional): 可用的工具列表
            temperature (float, optional): 控制回复的随机性,默认为1.0
            timeout (int, optional): 请求超时时间
            **kwargs: 其他可选参数

        Returns:
            str: 模型的回复内容
        """
        messages = [{"role": "user", "content": prompt}]
        response = await self.client.chat.completions.create(
            model=self.model,
            messages=messages,
            temperature=temperature,
            max_tokens=self.max_tokens,
            tools=tools,
            tool_choice="auto",
            timeout=timeout,
            **kwargs,
        )
        print(response)
        return response.choices[0].message.content

if __name__ == "__main__":
    async def main():
        llm = LLM()

        # 测试工具调用
        tools = [
            {
                "type": "function",
                "function": {
                    "name": "get_current_time",
                    "description": "获取当前时间",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "timezone": {"type": "string", "description": "时区"}
                        }
                    }
                }
            }
        ]
        results = await llm.ask_tool("当前的北京时间是多少", tools=tools)
        print(results)

    asyncio.run(main())

安装openai依赖:

uv pip install openai

执行:

% python llm/ollama.tool.py

ChatCompletion(id='chatcmpl-441', choices=[Choice(finish_reason='tool_calls', index=0, logprobs=None, message=ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_au8ws2w9', function=Function(arguments='{"timezone":"Asia/Shanghai"}', name='get_current_time'), type='function', index=0)]))], created=1745823347, model='qwen2.5', object='chat.completion', service_tier=None, system_fingerprint='fp_ollama', usage=CompletionUsage(completion_tokens=23, prompt_tokens=157, total_tokens=180, completion_tokens_details=None, prompt_tokens_details=None))

返回内容如下(已格式化):

ChatCompletion(
    id='chatcmpl-441',
    choices=[
        Choice(
            finish_reason='tool_calls',
            index=0,
            logprobs=None,
            message=ChatCompletionMessage(
                content='',
                refusal=None,
                role='assistant',
                annotations=None,
                audio=None,
                function_call=None,
                tool_calls=[
                    ChatCompletionMessageToolCall(
                        id='call_au8ws2w9',
                        function=Function(
                            arguments='{"timezone":"Asia/Shanghai"}',
                            name='get_current_time'
                        ),
                        type='function',
                        index=0
                    )
                ]
            )
        )
    ],
    created=1745823347,
    model='qwen2.5',
    object='chat.completion',
    service_tier=None,
    system_fingerprint='fp_ollama',
    usage=CompletionUsage(
        completion_tokens=23,
        prompt_tokens=157,
        total_tokens=180,
        completion_tokens_details=None,
        prompt_tokens_details=None
    )
)

解释

  • choices:模型的回复列表,这里只有一个回复。
  • finish_reason='tool_calls':表示模型决定调用工具(function call),而不是直接回复文本。
  • message.content='':回复内容为空,因为模型选择了工具调用。
  • tool_calls:工具调用的详细信息。
    • id='call_au8ws2w9':本次工具调用的唯一ID。
    • function:要调用的函数信息。
      • name='get_current_time':要调用的函数名。
      • arguments='{"timezone":"Asia/Shanghai"}':传递给函数的参数(这里是时区)。
    • type='function':调用类型为函数。
  • 其他字段如 createdmodelusage 等为元数据。

总结

你的模型没有直接返回“北京时间”,而是决定调用你定义的 get_current_time 工具,并传递了参数 {"timezone":"Asia/Shanghai"}
这说明你的工具调用机制是正常的,下一步你需要实现 get_current_time 这个函数,并让系统能够根据工具调用结果返回最终答案。

完整的例子实现

import asyncio
import json
from datetime import datetime
import pytz

from openai import AsyncOpenAI


class LLM:
    def __init__(self):
        self.model = "qwen2.5"
        self.max_tokens = 4096
        self.base_url = "http://10.1.60.15:31434/v1"
        self.api_key = "key"
        self.client = AsyncOpenAI(api_key=self.api_key, base_url=self.base_url)

    async def ask_tool(self, prompt, tools=None, temperature=1.0, timeout=None, **kwargs):
        """
        向模型发送带有工具调用的提示并获取回复

        Args:
            prompt (str): 用户输入的提示文本
            tools (list, optional): 可用的工具列表
            temperature (float, optional): 控制回复的随机性,默认为1.0
            timeout (int, optional): 请求超时时间
            **kwargs: 其他可选参数

        Returns:
            str: 模型的回复内容
        """
        messages = [{"role": "user", "content": prompt}]
        response = await self.client.chat.completions.create(
            model=self.model,
            messages=messages,
            temperature=temperature,
            max_tokens=self.max_tokens,
            tools=tools,
            tool_choice="auto",
            timeout=timeout,
            **kwargs,
        )
        print(f"模型初次回复: {response}")
        tool_calls = response.choices[0].message.tool_calls
        if tool_calls:
            tool_call = tool_calls[0]
            print(f"检测到工具调用: {tool_call.function.name}, 参数: {tool_call.function.arguments}")
            tool_result = self.handle_tool_call(tool_call)
            print(f"本地工具返回: {tool_result}")
            messages.append({
                "role": "assistant",
                "content": "",
                "tool_calls": [tool_call]
            })
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "name": tool_call.function.name,
                "content": tool_result
            })
            response = await self.client.chat.completions.create(
                model=self.model,
                messages=messages,
                temperature=temperature,
                max_tokens=self.max_tokens,
                timeout=timeout,
                **kwargs,
            )
            print(f"最终模型回复: {response.choices[0].message.content}")
            return response.choices[0].message.content
        else:
            print(f"最终模型回复: {response.choices[0].message.content}")
            return response.choices[0].message.content

    def handle_tool_call(self, tool_call):
        """
        根据 tool_call 调用本地工具函数
        """
        function_name = tool_call.function.name
        arguments = json.loads(tool_call.function.arguments)
        if function_name == "get_current_time":
            return get_current_time(**arguments)
        else:
            return f"未实现的工具: {function_name}"


def get_current_time(timezone):
    tz = pytz.timezone(timezone)
    return datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")

if __name__ == "__main__":
    async def main():
        llm = LLM()

        # 测试工具调用
        tools = [
            {
                "type": "function",
                "function": {
                    "name": "get_current_time",
                    "description": "获取当前时间",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "timezone": {"type": "string", "description": "时区"}
                        }
                    }
                }
            }
        ]
        results = await llm.ask_tool("当前的北京时间是多少", tools=tools)
        print(results)

    asyncio.run(main())

安装依赖

uv pip install pytz

执行

% python llm/ollama.tool.py

模型初次回复: ChatCompletion(id='chatcmpl-633', choices=[Choice(finish_reason='tool_calls', index=0, logprobs=None, message=ChatCompletionMessage(content='', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_higvk9pm', function=Function(arguments='{"timezone":"Asia/Shanghai"}', name='get_current_time'), type='function', index=0)]))], created=1745824286, model='qwen2.5', object='chat.completion', service_tier=None, system_fingerprint='fp_ollama', usage=CompletionUsage(completion_tokens=23, prompt_tokens=157, total_tokens=180, completion_tokens_details=None, prompt_tokens_details=None))
检测到工具调用: get_current_time, 参数: {"timezone":"Asia/Shanghai"}
本地工具返回: 2025-04-28 15:11:26
最终模型回复: 当前的北京时间是2025年4月28日 15点11分26秒。请注意,这个时间是基于提供的工具响应。实际情况可能会有所不同,请以最新的时钟为准。
当前的北京时间是2025年4月28日 15点11分26秒。请注意,这个时间是基于提供的工具响应。实际情况可能会有所不同,请以最新的时钟为准。
更新于 2025-04-28

查看AI更多相关的文章或提一个关于AI的问题,也可以与我们一起分享文章