Ollama: Python SDK集成

Python SDK 是打开本地 AI 大门的钥匙——三行代码,从脚本到应用无缝衔接。

💡 提示:Python SDK(ollama 库)本质上是对Ollama REST API的封装——chat() 方法封装了 /api/chat 端点,generate() 封装了 /api/generatelist() 封装了 /api/tags。理解这层关系有助于排查问题:当SDK报错时,可以用curl直接调API确认是SDK问题还是Ollama服务问题。

📋 前置知识:需要先掌握以下内容

1. 你将学到


2. 一个 SaaS 创业者的真实故事

⚠️ 警告: Python SDK 直接调用 Ollama API 时,Ollama 无内置认证。如果你的 Ollama 绑定了 0.0.0.0,SDK 连接信息(如 http://your-server:11434)可能被他人利用。生产环境务必添加认证层。

(1) 痛点:Shell 脚本不够用

Alice 用 curl 搭建了 SupportBot 原型,但 Shell 脚本难以维护对话状态、处理错误、集成到 Web 服务。她需要一个正式的编程语言来构建生产级应用。

(2) 解法:Python SDK 三行集成

PYTHON
import ollama

response = ollama.chat(model='qwen2.5', messages=[
    {'role': 'user', 'content': 'Hello'}
])
print(response['message']['content'])

3. 安装与 API 概览

ℹ️ 信息: ollama Python SDK 默认连接 http://localhost:11434,无需额外配置。若 Ollama 运行在其他地址,可通过设置环境变量 OLLAMA_HOST 或在代码中指定 Client(host='http://...') 来覆盖。

💡 提示: Python SDK 的 chat() 方法比 generate() 更推荐——chat 支持多轮对话(messages 数组),generate 仅支持单轮。即使是单次提问,chat 的角色区分(system/user/assistant)也能获得更好的输出质量。

(1) 安装与连接验证

BASH
# Install the ollama Python package
pip install ollama

# Verify connection to Ollama server
python3 -c "import ollama; print(ollama.list())"

(2) 同步 vs 异步 API 对比

⚠️ 注意:使用异步API(AsyncClient)时,所有调用必须加 await 关键字,如 await client.chat(...)。忘记 await 会导致返回协程对象而非实际结果,程序不会报错但得不到正确输出。在FastAPI等异步框架中必须用异步API,否则会阻塞事件循环影响并发性能。

维度 同步 API 异步 API
模块 (AsyncClient)
调用方式
阻塞 阻塞当前线程 非阻塞,可并发
适用场景 脚本、简单工具 Web 服务、并发处理
流式支持

▶ 示例 1: 同步与异步基本调用

PYTHON
import ollama
import asyncio

# Synchronous call
def sync_chat():
    response = ollama.chat(
        model='qwen2.5',
        messages=[{'role': 'user', 'content': 'Hello!'}]
    )
    print(response['message']['content'])

# Asynchronous call
async def async_chat():
    client = ollama.AsyncClient()
    response = await client.chat(
        model='qwen2.5',
        messages=[{'role': 'user', 'content': 'Hello!'}]
    )
    print(response['message']['content'])

sync_chat()
asyncio.run(async_chat())

输出:

TEXT 📖 仅展示
# 函数定义成功

4. 核心方法详解

(1) chat() 方法

参数 类型 说明
str 模型名称
list[dict] 消息列表,每条含 role/content
bool 是否流式输出
str 输出格式:
dict 推理参数(temperature 等)
str 模型驻留时间

(2) generate() 方法

参数 类型 说明
str 模型名称
str 提示文本
str System Prompt
bool 是否流式
dict 推理参数

▶ 示例 2: chat 与 generate 对比

PYTHON
import ollama

# chat(): multi-turn with message history
response = ollama.chat(
    model='qwen2.5',
    messages=[
        {'role': 'system', 'content': 'You are a SQL expert.'},
        {'role': 'user', 'content': 'Write a query for top 5 customers'}
    ],
    stream=False,
    options={'temperature': 0.3}
)
print('chat:', response['message']['content'])

# generate(): single-shot text generation
response = ollama.generate(
    model='qwen2.5',
    prompt='Write a haiku about debugging',
    system='You are a poet.',
    stream=False
)
print('generate:', response['response'])

输出:

TEXT 📖 仅展示
chat:
generate:

5. 流式响应实现

(1) 流式输出原理

100%
sequenceDiagram
    participant P as Python App
    participant O as Ollama Server
    P->>O: chat(stream=True)
    loop Each token chunk
        O-->>P: chunk {"content": "word"}
        P->>P: print(word, end="")
    end
    O-->>P: chunk {"done": true}

▶ 示例 3: 同步流式输出

PYTHON
import ollama

# Stream chat response in real-time
stream = ollama.chat(
    model='qwen2.5',
    messages=[{'role': 'user', 'content': 'Explain RAG in 3 sentences'}],
    stream=True
)

for chunk in stream:
    content = chunk['message']['content']
    print(content, end='', flush=True)

print()  # newline at end

输出:

TEXT 📖 仅展示
# 执行成功

▶ 示例 4: 异步流式输出

PYTHON
import ollama
import asyncio

async def stream_chat():
    client = ollama.AsyncClient()
    stream = await client.chat(
        model='qwen2.5',
        messages=[{'role': 'user', 'content': 'Tell me about Ollama'}],
        stream=True
    )
    async for chunk in stream:
        content = chunk['message']['content']
        print(content, end='', flush=True)
    print()

asyncio.run(stream_chat())

输出:

TEXT 📖 仅展示
# 函数定义成功

6. 错误处理与类型注解

(1) 常见错误类型

错误 触发条件 处理方式
Ollama 服务未运行 启动服务或重试
模型不存在/参数错误 检查模型名和参数
推理超时 减小 num_ctx 或增大超时
format=json 输出异常 加 JSON 校验和重试

▶ 示例 5: 完善的错误处理

PYTHON
import ollama
import json
from typing import Optional

def safe_chat(
    model: str,
    messages: list[dict],
    temperature: float = 0.3,
    max_retries: int = 3
) -> Optional[str]:
    """Chat with error handling and retries."""
    for attempt in range(max_retries):
        try:
            response = ollama.chat(
                model=model,
                messages=messages,
                stream=False,
                options={'temperature': temperature}
            )
            return response['message']['content']

        except ConnectionError:
            print(f"Connection failed (attempt {attempt + 1})")
            if attempt == max_retries - 1:
                return None

        except ollama.ResponseError as e:
            print(f"API error: {e.error}")
            return None

        except Exception as e:
            print(f"Unexpected error: {e}")
            if attempt == max_retries - 1:
                return None

    return None

# Usage
result = safe_chat('qwen2.5', [
    {'role': 'user', 'content': 'What is your return policy?'}
])
if result:
    print(result)
else:
    print("Failed to get response")

输出:

TEXT 📖 仅展示
Failed to get response

7. 综合示例:SupportBot V1 Python 封装

PYTHON
# ============================================
# Comprehensive: SupportBot V1
# Python wrapper for e-commerce customer service
# ============================================

import ollama
from dataclasses import dataclass, field
from typing import Optional

@dataclass
class SupportBot:
    model: str = "qwen2.5"
    temperature: float = 0.4
    max_history: int = 10
    system_prompt: str = (
        "You are SupportBot, an e-commerce customer service agent. "
        "Be polite, concise, and helpful. "
        "If unsure, say 'Let me connect you with a human agent.'"
    )
    messages: list[dict] = field(default_factory=list)

    def __post_init__(self):
        self.messages = [
            {"role": "system", "content": self.system_prompt}
        ]

    def chat(self, user_input: str) -> str:
        self.messages.append({"role": "user", "content": user_input})
        try:
            response = ollama.chat(
                model=self.model,
                messages=self.messages[-self.max_history:],
                stream=False,
                options={"temperature": self.temperature}
            )
            assistant_msg = response["message"]["content"]
            self.messages.append({"role": "assistant", "content": assistant_msg})
            return assistant_msg
        except Exception as e:
            self.messages.pop()  # Remove failed user message
            return f"Error: {str(e)}"

    def stream_chat(self, user_input: str):
        self.messages.append({"role": "user", "content": user_input})
        full_response = []
        try:
            stream = ollama.chat(
                model=self.model,
                messages=self.messages[-self.max_history:],
                stream=True,
                options={"temperature": self.temperature}
            )
            for chunk in stream:
                content = chunk["message"]["content"]
                full_response.append(content)
                print(content, end="", flush=True)
            print()
            self.messages.append({"role": "assistant", "content": "".join(full_response)})
        except Exception as e:
            print(f"\nError: {e}")

    def reset(self):
        self.messages = [{"role": "system", "content": self.system_prompt}]

# Usage
if __name__ == "__main__":
    bot = SupportBot(model="qwen2.5", temperature=0.4)

    print("=== SupportBot V1 ===")
    print(bot.chat("Where is my order #12345?"))
    print()
    print(bot.chat("It has been 7 days since I ordered."))
    print()
    print(bot.chat("Can I get a refund instead?"))
💻 输出:

TEXT 📖 仅展示
=== SupportBot V1 ===
I'd be happy to check on your order #12345. Based on our records, your order is currently in transit and expected to arrive within 2-3 business days. You can track it at our website.

I understand your concern. If you'd prefer a refund instead of waiting, I can initiate that for you. Our refund policy covers orders that haven't been delivered within the estimated timeframe.

Yes, I can process a full refund for order #12345. The refund will be credited to your original payment method within 3-5 business days. Would you like me to proceed?

❓ 常见问题

Q pip install ollama 报错怎么办?
A 确保 Python >= 3.8 且 pip 已更新:。网络问题可用镜像:。
Q 同步和异步 API 怎么选?
A 脚本和简单工具用同步(更简单)。Web 服务(FastAPI/Django)用异步(不阻塞事件循环)。单用户场景两者差异不大。
Q 流式输出在 Jupyter Notebook 中不显示怎么办?
A Jupyter 对 支持有限。用 配合循环更新,或改用非流式模式。
Q 如何指定 Ollama 服务地址?
A 默认连接 localhost:11434。可通过环境变量 修改,或在代码中实例化 。
Q messages 列表太长会怎样?
A 超出模型上下文窗口(num_ctx)会被截断。建议实现滑动窗口,只保留最近 N 轮对话,或对早期对话做摘要压缩。
Q 如何获取推理速度等统计信息?
A 非流式响应中包含 、、 等字段。流式响应的最后一个 chunk 包含这些统计。

📖 小节


📝 作业

  1. 基础题(难度⭐):用 Python SDK 实现 和 各一次,对比输出差异。
  2. 进阶题(难度⭐⭐):实现一个流式聊天函数,带滑动窗口(保留最近 5 轮对话),并在对话超过 5 轮时自动丢弃最早消息。
  3. 挑战题(难度⭐⭐⭐):构建一个带错误重试、超时控制、JSON 格式输出的 SupportBot V1+,能将客服对话保存到文件并统计每次推理耗时。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏