Mittelstufe 15 minAPI

Ollama über die API in eine Python-Anwendung integrieren REST

Ollama stellt auf Port 11434 zwei HTTP-APIs bereit: eine native API (/api/generate, /api/chat) und eine OpenAI-kompatible API (/v1/chat/completions). Letztere ist der Königsweg zur Integration der Ollama-API in Python: Ihr Code verwendet genau dasselbe SDK wie mit GPT-4, läuft aber auf Ihrem Rechner. Dieser Leitfaden behandelt konkrete Implementierungsmuster – Streaming, strukturiertes JSON, Function Calling – mit FastAPI- und Flask-Beispielen, die Sie direkt in ein Projekt kopieren können.

Von Mohamed Meguedmi·Aktualisierung 2026-08-27·Unter Windows, macOS und Linux getestet

#Warum die REST-API verwenden

Die CLI ollama run est ist praktisch zum Testen, aber sie wurde nicht für Aufrufe aus einer Anwendung konzipiert. Die REST-API hingegen wurde dafür entwickelt: Standard-HTTP-Anfragen, JSON-Eingabe und Ausgabe, Streaming über Server-Sent Events. Das nutzen alle Interfaces (Open WebUI, Cline, LangChain) im Hintergrund.

Kompatibilität mit OpenAI
Der Endpoint /v1/chat/completions akzeptiert genau den gleichen Payload wie api.openai.com/v1/chat/completions. Sie ändern die URL und den Schlüssel, und Ihr bestehender Code funktioniert.
Keine Neuerfindung
Das offizielle openai-SDK für Python (oder jeder beliebige HTTP-Client) kommuniziert direkt mit Ollama. Sie müssen sich nicht in einen speziellen Client einarbeiten.
Entkopplung der Laufzeitumgebung
Ihre Python-Anwendung läuft in ihrem Container, Ollama in seinem. Wenn Sie zu vLLM oder LM Studio wechseln, ändern Sie nur die base_url.
Mehrere Clients gleichzeitig
Mehrere Python-Skripte, ein Jupyter-Notebook und Open WebUI können auf dieselbe Ollama-Instanz zugreifen. Der Daemon verwaltet die Warteschlange selbstständig.
i
Native API vs. OpenAI-kompatible API
Ollama pflegt beide APIs. Die native API (/api/chat) bietet spezifische Parameter (num_ctx, num_predict, mirostat), ist aber weniger portabel. Die OpenAI-kompatible API deckt 95 % der Anforderungen ab und lässt sich auch mit jedem anderen Anbieter verwenden. Wählen Sie standardmäßig diese API.

#Voraussetzungen

Das Kit „Copilote Local“

Dieser Guide führt Sie zum Modell. Das Kit führt Sie zum Copiloten, der in Ihrem Editor Code schreibt.

  • Lebenslanger Online-Zugang
  • PDF + Dateien
  • Erstattung binnen 30 Tagen
Ollama installiert und gestartet
Der Daemon muss auf http://localhost:11434 lauschen. Prüfen Sie dies mit curl http://localhost:11434 – Sie müssen "Ollama is running" sehen.
Python 3.10+
Neuere SDKs (openai 1.x) erfordern mindestens Python 3.8, für moderne Annotationen jedoch Python 3.10+.
Ein chatkompatibles Modell
ollama pull qwen3.5:9b ou gemma4:12b. Pour le function calling, choisissez un modèle qui le supporte : Qwen 3.5, Granite 4.2, Mistral Small 24B, Devstral.
Ausreichend VRAM
Ein 9B-Modell in Q4 (wie Qwen 3.5 9B) benötigt etwa 6–7 GB VRAM, ein 12B-Modell (Gemma 4 12B) etwa 8 GB. Ohne GPU läuft es ebenfalls, allerdings mit 5–10 Tokens pro Sekunde.

#1. Die beiden APIs von Ollama

Bevor wir Python-Code schreiben, werfen wir im Terminal einen Blick auf die Endpunkte, um genau zu sehen, was passiert. Mit curl kommunizieren wir direkt mit dem Daemon, ohne jegliche Abstraktion.

Native API – /api/chat
curl http://localhost:11434/api/chat -d '{
  "model": "qwen3.5:9b",
  "messages": [{"role": "user", "content": "Bonjour"}],
  "stream": false
}'
OpenAI-API — /v1/chat/completions
curl http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3.5:9b",
    "messages": [{"role": "user", "content": "Bonjour"}]
  }'

Der zweite gibt einen Payload zurück, der exakt mit dem von OpenAI identisch ist: die Felder choices[0].message.content, id, model, usage. Das ermöglicht den direkten Austausch ohne Anpassungen.

→
Der API-Schlüssel wird ignoriert, ist aber erforderlich
Das openai-SDK verlangt einen Parameter api_key. Ollama prüft nichts – übergeben Sie "ollama" oder eine beliebige nicht leere Zeichenkette. Wenn Sie aus Gewohnheit Ihren echten OpenAI-Schlüssel angeben, bleibt er auf Ihrem Rechner. Verwenden Sie jedoch vorzugsweise eine neutrale Zeichenkette, um Verwechslungen zu vermeiden.

#2. Das OpenAI-SDK auf Ollama ausrichten

Das Grundmuster einer Integration der Ollama-API in Python passt in fünf Zeilen: Man installiert das OpenAI-SDK, instanziiert es mit der lokalen base_url und ruft chat.completions.create wie gewohnt auf.

Installation
pip install openai
client.py – grundlegender Aufruf
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="ollama",  # ignoré, mais requis par le SDK
)

reponse = client.chat.completions.create(
    model="qwen3.5:9b",
    messages=[
        {"role": "system", "content": "Tu réponds en français, de façon concise."},
        {"role": "user", "content": "Explique en une phrase ce qu'est un LLM."},
    ],
    temperature=0.3,
)

print(reponse.choices[0].message.content)

Starten Sie das Skript. Wenn Ollama läuft und das Modell heruntergeladen wurde, erhalten Sie einen Satz. Falls Sie eine ConnectionRefusedError sehen, überprüfen Sie mit ollama ps, ob der Daemon aktiv ist.

model
Der genaue Name, wie von ollama list angegeben (qwen3.5:9b, gemma4:12b, mistral-small usw.).
messages
Die Liste der Konversationsrunden. Unterstützte Rollen: system, user, assistant, tool.
temperature
0 für deterministisch, 0,7 für kreativ. Bei Datenextraktion bleiben Sie bei 0 oder 0,1.
max_tokens
Obergrenze für die Antwort. Optional – Ollama verwendet einen sinnvollen Standardwert für num_predict.

#3. Streaming Token für Token mit SSE

Für eine gute Benutzererfahrung (Chatbot, längere Textgenerierung) sollten Sie die Tokens nach und nach anzeigen, statt bis zum Ende zu warten. Ollama unterstützt Streaming über Server-Sent Events, und mit dem OpenAI-SDK lässt sich das mit einer einfachen Python-Schleife umsetzen.

streaming.py
from openai import OpenAI

client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")

flux = client.chat.completions.create(
    model="qwen3.5:9b",
    messages=[{"role": "user", "content": "Raconte une courte histoire de robot."}],
    stream=True,
)

for chunk in flux:
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)
print()

Jeder Chunk enthält ein Delta (den hinzugefügten Textabschnitt). Im letzten Chunk ist delta.content auf None gesetzt und finish_reason ausgefüllt – das ist das Stoppsignal.

!
flush=True nicht vergessen
Ohne flush=True puffert Python stdout zeilenweise, und der Streaming-Effekt verschwindet im Terminal. Bei einer HTTP-API hingegen übernimmt der Webserver (uvicorn, gunicorn) das Leeren des Puffers – Sie müssen sich nicht darum kümmern.

#4. JSON-Modus für strukturierte Ausgaben

Wenn Sie die Antwort parsen möchten (Extraktion, Klassifizierung, Payload-Generierung), reicht die Aufforderung „Gib JSON zurück“ im Prompt nicht aus – das Modell fügt oft zusätzlichen Text davor oder danach ein. Der JSON-Modus zwingt den Decoder, ausschließlich gültiges JSON zu erzeugen.

json_mode.py
from openai import OpenAI
import json

client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")

reponse = client.chat.completions.create(
    model="qwen3.5:9b",
    messages=[
        {"role": "system", "content": (
            "Tu extrais des informations structurées. "
            "Réponds uniquement avec un objet JSON contenant les clés : "
            "nom (string), age (int), ville (string)."
        )},
        {"role": "user", "content": "Marie a 34 ans, elle habite à Lyon."},
    ],
    response_format={"type": "json_object"},
    temperature=0,
)

donnees = json.loads(reponse.choices[0].message.content)
print(donnees)
# {'nom': 'Marie', 'age': 34, 'ville': 'Lyon'}

response_format={"type": "json_object"} aktiviert den JSON-Modus. Bei Ollama bedeutet das eine Beschränkung auf Ebene des Samplers: Jedes Token, das ungültiges JSON erzeugen würde, wird verworfen. Das ist zuverlässiger, als per Prompt „Antworte in JSON“ vorzugeben und zu beten.

→
Nennen Sie im Prompt "JSON"
Wie bei OpenAI setzt der JSON-Modus voraus, dass das Wort "JSON" mindestens einmal im Gespräch vorkommt (in einer System- oder User-Nachricht). Andernfalls erzeugen einige Modelle ein leeres Objekt. Beschreiben Sie das erwartete Schema im System-Prompt — das gibt den Inhalt vor; der JSON-Modus garantiert lediglich die Syntax.

#5. Funktionen aufrufen (Toolverwendung)

Function Calling ermöglicht es dem Modell, zu signalisieren, dass es eine Python-Funktion aufrufen möchte, statt direkt zu antworten. Nicht alle Modelle unterstützen dies – prüfen Sie auf ollama.com/library, ob unter den Fähigkeiten die Angabe „tools“ erscheint. Qwen 3.5, Granite 4.2, Mistral Small 24B und Devstral unterstützen dies nativ.

tools.py
from openai import OpenAI
import json

client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")

# 1. Une fonction Python réelle
def meteo(ville: str) -> dict:
    # En vrai, vous appelleriez Open-Meteo ou autre
    return {"ville": ville, "temperature_c": 18, "conditions": "nuageux"}

# 2. Sa description au format OpenAI
outils = [{
    "type": "function",
    "function": {
        "name": "meteo",
        "description": "Donne la météo actuelle d'une ville française.",
        "parameters": {
            "type": "object",
            "properties": {
                "ville": {"type": "string", "description": "Nom de la ville"},
            },
            "required": ["ville"],
        },
    },
}]

messages = [{"role": "user", "content": "Quel temps fait-il à Bordeaux ?"}]

# 3. Premier appel : le modèle décide d'appeler la fonction
reponse = client.chat.completions.create(
    model="qwen3.5:9b",
    messages=messages,
    tools=outils,
)

appel = reponse.choices[0].message.tool_calls[0]
args = json.loads(appel.function.arguments)
resultat = meteo(**args)

# 4. Second appel : on renvoie le résultat au modèle pour la réponse finale
messages.append(reponse.choices[0].message)
messages.append({
    "role": "tool",
    "tool_call_id": appel.id,
    "content": json.dumps(resultat),
})

finale = client.chat.completions.create(model="qwen3.5:9b", messages=messages)
print(finale.choices[0].message.content)

Die Schleife hat zwei Durchläufe: Der erste gibt tool_calls zurück (das Modell sagt „Rufe meteo mit ville=Bordeaux auf“), der zweite liefert die Antwort in natürlicher Sprache, nachdem Sie die Funktion ausgeführt und ihr Ergebnis eingespeist haben. Im Produktionsbetrieb wiederholen Sie die Schleife, solange tool_calls nicht leer ist.

!
Nicht alle Modelle sind gleich
Bei einem Modell, das Tools nur schlecht unterstützt (das alte Llama 2, Mistral 7B v0.1), erhalten Sie fehlerhaft formatierte Aufrufe oder halluzinierte Argumente. Falls Ihnen das passiert: (1) prüfen Sie, ob das Modell Tools offiziell unterstützt, (2) senken Sie die Temperatur auf 0, (3) vereinfachen Sie das Parameterschema.

#6. Ollama über FastAPI verfügbar machen

Typischer Fall: Ihr Frontend ruft Ihr Python-Backend auf, das wiederum Ollama aufruft. FastAPI handhabt asynchrone Abläufe sauber, und die Streaming-Ausgabe gelangt über eine StreamingResponse bis zum Browser.

Abhängigkeiten
pip install fastapi uvicorn openai
main.py
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from openai import OpenAI

app = FastAPI()
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")

class Question(BaseModel):
    message: str
    model: str = "qwen3.5:9b"

@app.post("/chat")
def chat(q: Question):
    reponse = client.chat.completions.create(
        model=q.model,
        messages=[{"role": "user", "content": q.message}],
    )
    return {"reponse": reponse.choices[0].message.content}

@app.post("/chat/stream")
def chat_stream(q: Question):
    def generateur():
        flux = client.chat.completions.create(
            model=q.model,
            messages=[{"role": "user", "content": q.message}],
            stream=True,
        )
        for chunk in flux:
            delta = chunk.choices[0].delta.content
            if delta:
                yield delta
    return StreamingResponse(generateur(), media_type="text/plain")
Server starten
uvicorn main:app --reload --port 8000
Im Befehlszeileninterface testen
curl -N -X POST http://localhost:8000/chat/stream \
  -H "Content-Type: application/json" \
  -d '{"message": "Écris un haïku sur Paris."}'

Die Option -N (--no-buffer) von curl deaktiviert die clientseitige Pufferung, damit Sie den Stream in Echtzeit sehen können. Im JavaScript-Frontend lesen Sie den ReadableStream der fetch-Antwort – genauso wie bei der OpenAI-API.

#7. Flask-Chatbot mit Historie

Für einen vollständigen Chatbot muss der Nachrichtenverlauf zwischen den Gesprächsrunden erhalten bleiben. Hier ist eine minimalistische Flask-Version, die die Unterhaltung im Arbeitsspeicher hält (im Produktivbetrieb durch eine echte Session/DB ersetzen).

Abhängigkeiten
pip install flask openai
app.py
from flask import Flask, request, jsonify, Response
from openai import OpenAI
from collections import defaultdict

app = Flask(__name__)
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")

# Historiques par session — en prod : Redis, Postgres, etc.
historiques: dict[str, list] = defaultdict(lambda: [
    {"role": "system", "content": "Tu es un assistant en français, concis et utile."},
])

@app.post("/chat/<session_id>")
def chat(session_id: str):
    message = request.json["message"]
    historique = historiques[session_id]
    historique.append({"role": "user", "content": message})

    reponse = client.chat.completions.create(
        model="qwen3.5:9b",
        messages=historique,
    )
    contenu = reponse.choices[0].message.content
    historique.append({"role": "assistant", "content": contenu})
    return jsonify({"reponse": contenu})

@app.post("/chat/<session_id>/stream")
def chat_stream(session_id: str):
    message = request.json["message"]
    historique = historiques[session_id]
    historique.append({"role": "user", "content": message})

    def generateur():
        morceaux = []
        flux = client.chat.completions.create(
            model="qwen3.5:9b",
            messages=historique,
            stream=True,
        )
        for chunk in flux:
            delta = chunk.choices[0].delta.content
            if delta:
                morceaux.append(delta)
                yield delta
        historique.append({"role": "assistant", "content": "".join(morceaux)})

    return Response(generateur(), mimetype="text/plain")

@app.delete("/chat/<session_id>")
def reset(session_id: str):
    historiques.pop(session_id, None)
    return "", 204

if __name__ == "__main__":
    app.run(port=5000, debug=True)
i
Kontextgrenze
Je länger der Gesprächsverlauf wird, desto mehr Tokens verbrauchen Sie bei jedem Aufruf. Für Qwen 3.5 beträgt das standardmäßige Kontextfenster in Ollama 2048 Tokens – darüber hinaus werden ältere Nachrichten ohne Hinweis abgeschnitten. Vergrößern Sie das Kontextfenster über die native API oder überschreiben Sie den Standardwert mit einem Modelfile (num_ctx 8192 oder 32768).

#Für die Produktion

Ollama über das Netzwerk verfügbar machen
Standardmäßig lauscht der Daemon nur auf 127.0.0.1. Um den Zugriff von anderen Rechnern zu erlauben, starten Sie ihn mit OLLAMA_HOST=0.0.0.0 – und schalten Sie einen Reverse-Proxy mit Authentifizierung davor, sonst kann jeder im Netzwerk Ihre Modelle nutzen.
Nebenläufigkeit und Warteschlange
Ollama serialisiert die Anfragen pro Modell. Um mehrere Benutzer parallel zu bedienen, starten Sie mehrere Instanzen oder wechseln Sie zu vLLM, das dynamisches Batching nativ unterstützt.
Clientseitige Timeouts
Eine Anfrage an ein noch nicht geladenes Modell kann 10–30 s dauern (Laden in den VRAM). Stellen Sie das Timeout des OpenAI-Clients mit OpenAI(..., timeout=120) ein, statt den Standardwert der Bibliothek von 10 Minuten beizubehalten; beim Reverse Proxy ist das Timeout jedoch oft kurz.
Modell geladen halten
Standardmäßig entlädt Ollama ein Modell nach 5 Minuten Inaktivität aus dem Speicher. Übergeben Sie bei API-Aufrufen keep_alive="30m" über die native API /api/chat oder lassen Sie regelmäßig einen Ping senden, um einen Kaltstart bei der ersten Benutzeranfrage zu vermeiden.
Beobachtbarkeit
Protokollieren Sie systematisch model, prompt_tokens und completion_tokens (in reponse.usage enthalten). Das sind Ihre Inferenzmetriken – hilfreich, um zu erkennen, wenn ein Modell langsamer wird oder die Tokenzahl eines Prompts stark ansteigt.
→
Wechsel von der OpenAI-API
Wenn Sie bereits Code haben, der mit api.openai.com kommuniziert, kann die Umstellung auf Ollama in zwei Zeilen erfolgen: Ändern Sie base_url="https://api.openai.com/v1" in base_url="http://localhost:11434/v1" und passen Sie den Modellnamen an. Alles andere – Streaming, JSON-Modus, Tools – funktioniert gleich. Das ist der große Vorteil des OpenAI-kompatiblen Endpunkts.

#Weiterführende Informationen

Sie verfügen über die Grundbausteine. Je nach Anwendungsfall bieten sich drei Möglichkeiten zur Vertiefung an:

Einen Agenten bauen, der selbstständig entscheidet
Der Leitfaden zu lokalen KI-Agenten in Python mit LangChain erweitert Function Calling zu einer vollständigen Agentenschleife mit der Verwaltung mehrerer Werkzeuge und mehrstufigem Schlussfolgern.
RAG für Ihre Dokumente hinzufügen
Damit Ihre App auf Grundlage eines internen Korpus (PDFs, Notizen, Code) antwortet, binden Sie eine Vektordatenbank an. Der Einführungsleitfaden zu lokalem RAG vermittelt die Grundlagen.
Das Verhalten des Modells anpassen
Statt den System-Prompt bei jedem Aufruf zu wiederholen, erstellen Sie mithilfe eines Modelfile eine Variante. Der Leitfaden zur Anpassung mit Ollama Modelfile zeigt, wie Sie einen französischsprachigen Assistenten oder einen Programmiermodus unter einem wiederverwendbaren Modellnamen festlegen.
Hat Ihnen dieser Guide geholfen?

Haben Sie Feedback, einen Fehler entdeckt oder möchten Sie etwas präzisieren? Geben Sie uns Bescheid – so wird der Guide für alle besser.