Ollama: Python SDK Integration

The Python SDK is the key that opens the door to local AI — three lines of code, seamless transition from script to application.

💡 Tip: The Python SDK (ollama library) is essentially a wrapper around the Ollama REST API — the chat() method wraps /api/chat, generate() wraps /api/generate, and list() wraps /api/tags. Understanding this relationship helps with troubleshooting: when the SDK throws an error, you can use curl to call the API directly to determine if it's an SDK issue or an Ollama service issue.

📋 Prerequisites: You need to master the following first

1. What You Will Learn


2. A Real Story from a SaaS Founder

⚠️ Warning: When the Python SDK directly calls the Ollama API, Ollama has no built-in authentication. If your Ollama is bound to 0.0.0.0, SDK connection information (e.g., http://your-server:11434) may be exploited by others. In production, always add an authentication layer.

(1) The Pain Point: Shell Scripts Aren't Enough

Alice built a SupportBot prototype with curl, but Shell scripts are hard to maintain for conversation state, error handling, and integration with web services. She needs a proper programming language to build production-grade applications.

(2) The Solution: Python SDK Three-Line Integration

PYTHON
import ollama

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

3. Installation and API Overview

ℹ️ Info: The ollama Python SDK defaults to connecting to http://localhost:11434, requiring no additional configuration. If Ollama is running at a different address, you can override it by setting the OLLAMA_HOST environment variable or specifying Client(host='http://...') in code.

💡 Tip: The Python SDK's chat() method is recommended over generate()chat supports multi-turn dialogue (messages array), while generate only supports single-turn. Even for single-shot questions, chat's role distinction (system/user/assistant) yields better output quality.

(1) Installation and Connection Verification

BASH
# Install the ollama Python package
pip install ollama

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

(2) Synchronous vs Asynchronous API Comparison

⚠️ Note: When using the asynchronous API (AsyncClient), all calls must be prefixed with await, e.g., await client.chat(...). Forgetting await returns a coroutine object instead of the actual result — the program won't error but won't produce correct output. In async frameworks like FastAPI, you must use the asynchronous API; otherwise, it blocks the event loop and hurts concurrent performance.

Dimension Synchronous API Asynchronous API
Module ollama ollama (AsyncClient)
Call style ollama.chat() await client.chat()
Blocking Blocks current thread Non-blocking, concurrent
Use case Scripts, simple tools Web services, concurrent processing
Streaming support for chunk in stream async for chunk in stream

▶ Example 1: Synchronous and Asynchronous Basic Calls

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())

Output:

TEXT
# Function defined successfully

4. Core Methods Deep Dive

(1) chat() Method

Parameter Type Description
model str Model name
messages list[dict] Message list, each containing role/content
stream bool Whether to stream output
format str Output format: json
options dict Inference parameters (temperature, etc.)
keep_alive str Model memory retention time

(2) generate() Method

Parameter Type Description
model str Model name
prompt str Prompt text
system str System Prompt
stream bool Whether to stream
options dict Inference parameters

▶ Example 2: chat vs generate Comparison

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'])

Output:

TEXT
chat:
generate:

5. Streaming Response Implementation

(1) Streaming Output Principle

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}

▶ Example 3: Synchronous Streaming Output

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

Output:

TEXT
# Execution successful

▶ Example 4: Asynchronous Streaming Output

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())

Output:

TEXT
# Function defined successfully

6. Error Handling and Type Annotations

(1) Common Error Types

Error Trigger Condition Handling
ConnectionError Ollama service not running Start service or retry
ResponseError Model not found / invalid parameters Check Model name and parameters
TimeoutError Inference timeout Reduce num_ctx or increase timeout
JSONDecodeError format=json output anomaly Add JSON validation and retry

▶ Example 5: Robust Error Handling

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")

Output:

TEXT
Failed to get response

7. Comprehensive Example: SupportBot V1 Python Wrapper

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?"))
💻 Output:

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?

❓ FAQ

Q pip install ollama fails, what should I do?
A Ensure Python >= 3.8 and pip is updated: pip install --upgrade pip. For network issues, use a mirror: pip install ollama -i https://pypi.tuna.tsinghua.edu.cn/simple.
Q How do I choose between synchronous and asynchronous APIs?
A Use synchronous for scripts and simple tools (simpler). Use asynchronous for web services (FastAPI/Django) to avoid blocking the event loop. The difference is minimal for single-user scenarios.
Q Streaming output doesn't display in Jupyter Notebook, what should I do?
A Jupyter has limited support for flush=True. Use IPython.display.clear_output with loop updates, or switch to non-streaming mode.
Q How do I specify the Ollama server address?
A Default connection is localhost:11434. Change via the OLLAMA_HOST environment variable, or instantiate Client(host='http://...') in code.
Q What happens when the messages list gets too long?
A Content exceeding the Model's context window (num_ctx) will be truncated. We recommend implementing a sliding window, keeping only the last N turns, or summarizing earlier conversations.
Q How do I get Inference speed and other statistics?
A Non-streaming responses contain total_duration, eval_count, prompt_eval_count fields. The last chunk of streaming responses contains these statistics.

📖 Summary


📝 Exercises

  1. Basic (Difficulty ⭐): Use the Python SDK to implement both chat() and generate() once each, comparing output differences.
  2. Intermediate (Difficulty ⭐⭐): Implement a streaming chat function with a sliding window (keeping the last 5 turns), automatically discarding the oldest messages when conversation exceeds 5 turns.
  3. Advanced (Difficulty ⭐⭐⭐): Build a SupportBot V1+ with error retry, timeout control, and JSON format output that saves customer service conversations to a file and logs Inference time for each call.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

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

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