Design wechseln

Ollama API in der Praxis: Entwicklungsleitfaden für Python- und Node.js-Clients

Easton editorial illustration: coding assistant migration bridge

Im Terminal ollama run gemma3 eingeben – die erste Antwort erscheint. Das lokale Modell läuft.

Als Nächstes stellt sich die Frage: Lässt sich das in ein eigenes Projekt einbinden? Kein API-Key, keine Kosten, alles lokal – das klingt verlockend.

In der Dokumentation finden sich offizielle SDKs für Python und JavaScript – und mit dem OpenAI-SDK genügen zwei Zeilen Anpassung. Einfacher als erwartet.

Einfach heißt nicht ohne Fallstricke. Wie sammelt man Streaming-Chunks? Wie schreibt man den Agent Loop für Tool-Calling? Wie trennt man im Thinking-Modus Reasoning und Antwort? Genau diese Stolpersteine behandeln wir hier.

Dieser Artikel füllt diese Lücken: Python und Node.js im Vergleich, natives SDK und OpenAI-kompatible Schnittstelle – ein vollständiger Leitfaden zur Cliententwicklung.

Falls Ollama noch nicht installiert ist, empfiehlt sich der Einstieg über den ersten Artikel der Serie: LangChain + Ollama Integration in der Praxis – zuerst das lokale Modell zum Laufen bringen.


Kapitel 1: Ollama-API-Grundlagen

Zuerst klären, wie die API funktioniert.

Ollama startet standardmäßig einen lokalen REST-API-Dienst unter http://localhost:11434/api. Im Browser erscheint die knappe Meldung „Ollama is running“ – dann läuft alles.

Wichtige Endpunkte

Zwei Kern-Endpunkte sollten Sie kennen:

EndpunktZweckBesonderheit
/api/chatMehrturn-Dialogmessages-Array, Kontext übertragbar
/api/generateEin-Turn-GenerierungEinfach, für Einmalaufgaben

Dazu gibt es /v1/chat/completions – der OpenAI-kompatible Endpunkt. Bestehende OpenAI-Projekte brauchen nur eine geänderte base_url; Details folgen später.

Erster Test mit curl

Am einfachsten testen Sie die API direkt:

curl http://localhost:11434/api/chat -d '{
  "model": "gemma3",
  "messages": [
    { "role": "user", "content": "Warum ist der Himmel blau?" }
  ]
}'

Die Antwort ist JSON. Entscheidend ist das Feld message.content – dort steht die Modellantwort.

Die Struktur sieht etwa so aus:

{
  "model": "gemma3",
  "created_at": "2026-04-18T01:23:45.678Z",
  "message": {
    "role": "assistant",
    "content": "Der Himmel erscheint blau, weil..."
  },
  "done": true
}

Das Feld done ist wichtig. Beim Streaming ist done in jedem Chunk false, nur im letzten Chunk true. Das brauchen Sie später bei der Streaming-Verarbeitung.

Streaming-Antworten

Standardmäßig wartet die API, bis die Generierung abgeschlossen ist, und liefert dann alles auf einmal. Für einen Schreibmaschinen-Effekt setzen Sie stream: true:

curl http://localhost:11434/api/chat -d '{
  "model": "gemma3",
  "messages": [{ "role": "user", "content": "Warum ist der Himmel blau?" }],
  "stream": true
}'

Jetzt erscheint zeilenweise JSON – jede Zeile ist ein Chunk. Sie müssen sie zusammensetzen, um die vollständige Antwort zu erhalten.

Manuelles Chunk-Handling ist mühsam – deshalb kapseln die offiziellen SDKs diese Details.


Kapitel 2: Python-SDK – vollständige Praxis

Das Python-SDK wird offiziell gepflegt und ist schnell installiert:

pip install ollama

Danach sofort nutzbar. Python 3.8+ wird unterstützt.

Basistest

Der einfachste Aufruf in wenigen Zeilen:

from ollama import chat

response = chat(
  model='gemma3',
  messages=[{'role': 'user', 'content': 'Warum ist der Himmel blau?'}]
)

print(response.message.content)

So einfach. chat() ist eine Shortcut-Funktion des SDK und erstellt intern einen Standard-Client zur lokalen Ollama-Instanz.

Für eigene Verbindungsparameter – z. B. Ollama auf einem anderen Rechner – erstellen Sie einen Client:

from ollama import Client

client = Client(host='http://192.168.1.100:11434')
response = client.chat(model='gemma3', messages=[...])

Streaming

Streaming ist zentral: Nutzer sollen Text schrittweise sehen, nicht erst nach langer Wartezeit alles auf einmal.

from ollama import chat

stream = chat(
  model='gemma3',
  messages=[{'role': 'user', 'content': 'Warum ist der Himmel blau?'}],
  stream=True,
)

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

Ein häufiger Stolperstein: chunk ist ein Dictionary, kein Objekt. Zugriff über chunk['message']['content'], nicht chunk.message.content.

Asynchroner Client

Bei asynchroner Architektur – FastAPI, aiohttp – nutzen Sie den AsyncClient:

import asyncio
from ollama import AsyncClient

async def main():
  client = AsyncClient()
  
  # Nicht-streaming
  response = await client.chat(
    model='gemma3',
    messages=[{'role': 'user', 'content': 'Hallo'}]
  )
  print(response.message.content)
  
  # Streaming
  stream = await client.chat(
    model='gemma3',
    messages=[{'role': 'user', 'content': 'Warum ist der Himmel blau?'}],
    stream=True,
  )
  async for chunk in stream:
    print(chunk['message']['content'], end='', flush=True)

asyncio.run(main())

Asynchrones Streaming liefert einen async generator – mit async for iterieren. Logik wie bei der synchronen Variante, plus await und async.

Cloud Models

Interessant: Das Ollama-SDK unterstützt auch Cloud-Modelle. Manche große Modelle laufen lokal nicht – z. B. gpt-oss mit 120B – in der Cloud schon.

from ollama import chat

response = chat(
  model='gpt-oss:120b-cloud',
  messages=[{'role': 'user', 'content': 'Hallo'}]
)

Modelle mit Suffix -cloud nutzen die Cloud-API. Dafür brauchen Sie ein Ollama-Cloud-Konto und API-Key – die Konfiguration unterscheidet sich von der lokalen Variante; Details in der offiziellen Dokumentation.

Praktisch: kleine Modelle lokal (sparsam), große in der Cloud (ohne teure Hardware). Ein sinnvoller Mix.


Kapitel 3: Node.js-SDK – vollständige Praxis

Das Node.js-SDK ist ebenso schlank:

npm i ollama

Das Paket unterstützt Node.js und Browser. Im Browser separater Import:

// Node.js
import ollama from 'ollama'

// Browser
import ollama from 'ollama/browser'

Basistest

In Node.js ist alles standardmäßig asynchron:

import ollama from 'ollama'

const response = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: 'Warum ist der Himmel blau?' }],
})

console.log(response.message.content)

Im Vergleich zu Python: messages als Objekt statt Dictionary. Parameternamen sind konsistent – beim Sprachwechsel bleiben die Konzepte gleich.

Streaming

Node.js verarbeitet Streams nativ als async generator:

import ollama from 'ollama'

const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: 'Warum ist der Himmel blau?' }],
  stream: true,
})

for await (const chunk of stream) {
  process.stdout.write(chunk.message.content)
}

process.stdout.write statt console.log – letzteres fügt Zeilenumbrüche ein, unerwünscht bei zeichenweiser Ausgabe.

Eigene Konfiguration

Host und Headers lassen sich anpassen:

import ollama from 'ollama'

// Eigener Host
const client = new ollama.Ollama({ host: 'http://192.168.1.100:11434' })

// Oder globale Konfiguration
ollama.setDefaultHost('http://192.168.1.100:11434')

// Headers (z. B. Authentifizierung)
const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: 'Hallo' }],
  headers: { Authorization: 'Bearer xxx' },
})

Headers sind nützlich, wenn vor Ollama ein authentifizierender Proxy sitzt.

Streaming abbrechen

Mit abort() können laufende Stream-Generierungen abgebrochen werden:

import ollama from 'ollama'

const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: 'Schreib einen langen Text...' }],
  stream: true,
})

// Nutzer klickt auf Stopp
ollama.abort()

for await (const chunk of stream) {
  // Nach abort endet die Schleife früh
  process.stdout.write(chunk.message.content)
}

Unverzichtbar in Chat-Oberflächen – Nutzer müssen lange Antworten stoppen können.

Browser-Variante

Im Browser ähnliche Nutzung, mit Einschränkungen:

import ollama from 'ollama/browser'

// Im Browser nur Streaming – nicht-streamende Cross-Origin-Anfragen werden oft blockiert
const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: 'Hallo' }],
  stream: true,
})

for await (const chunk of stream) {
  document.getElementById('output').textContent += chunk.message.content
}

Einschränkung: Streaming ist Pflicht. Nicht-streamende Anfragen liefern große JSON-Antworten auf einmal – Cross-Origin-Timeouts oder Blockaden sind häufig. Streaming verteilt die Last auf viele kleine Chunks.

Für Chat-UIs im Browser ohnehin sinnvoll – dort will man ohnehin schrittweise Ausgabe.


Kapitel 4: Tool-Calling in der Praxis

Tool-Calling ist die Basis für Agents. Ollama kann definierte Funktionen aufrufen und die Ergebnisse in die weitere Generierung einfließen lassen.

Das Python-SDK erlaubt es, Python-Funktionen direkt als Tools zu übergeben – Docstring und Parametertypen werden automatisch geparst.

Automatisches Parsen von Python-Funktionen

def get_weather(city: str) -> str:
  """Wetterinformationen für eine Stadt abrufen

  Args:
    city: Stadtname, z. B. „Berlin“, „München“

  Returns:
    Wetterbeschreibung als String
  """
  # Simulierte Daten
  weather_data = {
    'Berlin': 'Sonnig, 18°C',
    'München': 'Bewölkt, 22°C',
    'Hamburg': 'Regen, 15°C',
  }
  return weather_data.get(city, f'Keine Wetterdaten für {city}')

from ollama import chat

response = chat(
  model='qwen3',
  messages=[{'role': 'user', 'content': 'Wie ist das Wetter in Berlin?'}],
  tools=[get_weather],
)

print(response.message.content)

Das SDK wandelt die Funktion in ein Tool-Schema um: Name aus Funktionsname, Beschreibung aus Docstring, Parameter aus Typannotationen – kein manuelles JSON Schema nötig.

Agent-Loop-Muster

Modelle rufen mehrere Tools auf oder wollen nach einem Tool-Aufruf weiter tools nutzen. Dafür brauchen Sie eine Schleife.

Das ist der Agent Loop:

from ollama import chat

def add(a: int, b: int) -> int:
  """Addition"""
  return a + b

def multiply(a: int, b: int) -> int:
  """Multiplikation"""
  return a * b

tools = [add, multiply]
tool_map = {'add': add, 'multiply': multiply}

messages = [{'role': 'user', 'content': 'Berechne (3 + 5) * 2'}]

while True:
  response = chat(model='qwen3', messages=messages, tools=tools)

  if response.message.tool_calls:
    # Modell will Tools aufrufen
    for call in response.message.tool_calls:
      func_name = call.function.name
      func_args = call.function.arguments
      result = tool_map[func_name](**func_args)

      # Tool-Ergebnis in Nachrichtenverlauf
      messages.append({
        'role': 'tool',
        'content': str(result),
        'tool_name': func_name,
      })
  else:
    # Keine Tool-Aufrufe mehr – fertig
    print(response.message.content)
    break

Ablauf:

  1. Nachricht mit Tool-Definitionen an das Modell
  2. Bei tool_calls die Funktion ausführen
  3. Ergebnis in den Verlauf, erneut an das Modell
  4. Wiederholen, bis keine Tools mehr aufgerufen werden

Standardmuster für Agents: Tools definieren, das Modell entscheidet wann, welche und in welcher Reihenfolge.

Thinking-Modus

Manche Modelle – z. B. qwen3 – unterstützen den Thinking-Modus: erst „denken“, dann antworten.

from ollama import chat

stream = chat(
  model='qwen3',
  messages=[{'role': 'user', 'content': 'Warum ist der Himmel blau?'}],
  stream=True,
  think=True,
)

thinking = ''
content = ''

for chunk in stream:
  if chunk.message.thinking:
    thinking += chunk.message.thinking
  elif chunk.message.content:
    content += chunk.message.content

print('=== Denkprozess ===')
print(thinking)
print('=== Finale Antwort ===')
print(content)

Im Thinking-Modus enthält der Chunk ein zusätzliches thinking-Feld – Denkinhalt und finale Antwort getrennt akkumulieren.

Nützlich, um die Argumentationskette nachzuvollziehen – für Lernanwendungen oder Prompt-Debugging.


Kapitel 5: Natives SDK vs. OpenAI-kompatible API

Zwei Wege stehen zur Wahl:

  1. Natives Ollama-SDK (wie oben beschrieben)
  2. OpenAI-SDK mit angepasster Adresse

Welcher passt besser? Das hängt vom Projekt ab.

OpenAI-kompatible Schnittstelle

Bei bestehenden OpenAI-Projekten ist die günstigste Migration die Änderung von base_url:

from openai import OpenAI

client = OpenAI(
  base_url='http://localhost:11434/v1',
  api_key='ollama',  # Pflichtfeld, wird ignoriert
)

response = client.chat.completions.create(
  model='gemma3',
  messages=[{'role': 'user', 'content': 'Warum ist der Himmel blau?'}],
)

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

Das OpenAI-SDK „weiß“ nicht, dass dahinter Ollama läuft – es spricht mit einer scheinbar normalen OpenAI-API.

Node.js analog:

import OpenAI from 'openai'

const client = new OpenAI({
  baseURL: 'http://localhost:11434/v1',
  apiKey: 'ollama',
})

const completion = await client.chat.completions.create({
  model: 'gemma3',
  messages: [{ role: 'user', content: 'Warum ist der Himmel blau?' }],
})

console.log(completion.choices[0].message.content)

Vergleich der beiden Ansätze

AspektNatives SDKOpenAI-kompatibel
Installationpip install ollamaBestehendes OpenAI-SDK
Tool-CallingDocstring automatisch geparstJSON Schema manuell
StreamingDictionary-ChunksStandard OpenAI-Format
Cloud ModelsUnterstütztNicht unterstützt
MigrationsaufwandKeiner bei neuen ProjektenMinimal bei bestehenden

Empfehlung

Neue Projekte: natives SDK.

Gründe:

  • Tool-Calling bequemer – Python-Funktionen direkt übergeben
  • Mehr Features (Cloud Models, Thinking-Modus)
  • Offizielle Dokumentation und Beispiele

Migration bestehender OpenAI-Projekte: OpenAI-kompatible Schnittstelle.

Gründe:

  • Zwei Zeilen ändern genügen
  • Keine Logik-Umschreibung
  • Einfacher Wechsel zurück zu OpenAI

Kurz: natives SDK bietet mehr Funktionen, OpenAI-Kompatibilität migriert schneller – je nach Bedarf wählen.

Beide Varianten sind erprobt. Tool-Calling im nativen SDK spart viel Aufwand – kein manuelles JSON Schema, klarer Docstring reicht. Läuft das Projekt bereits auf OpenAI, lohnt sich kein Komplett-Umbau nur für Ollama.


Abschluss

Die wichtigsten Punkte:

Basistest: Python- und Node.js-SDK sind gut gekapselt – wenige Zeilen genügen. Streaming mit stream=True aktivieren.

Tool-Calling: Agent Loop ist das Kernmuster – tool_calls wiederholen, bis das Modell fertig ist. Im Python-SDK Funktionen direkt als Tools übergeben.

Thinking-Modus: qwen3 u. a. unterstützen ihn – Denkprozess und Antwort über separate Felder im Chunk trennen.

Wahl der Schnittstelle: Neue Projekte → natives SDK; bestehende OpenAI-Projekte → base_url anpassen.

Nächste Schritte:

  • Ollama noch nicht installiert? Serie starten und lokales Modell zum Laufen bringen
  • Passende Variante wählen (nativ oder OpenAI-kompatibel) und ausprobieren
  • Offizielle Dokumentation im Blick behalten – neue Features kommen laufend dazu

Lokale LLMs werden zugänglicher. Ollama verbirgt die Komplexität hinter einer einfachen API – Sie müssen nur wissen, wie man sie aufruft.

Das ist Teil zwei unserer Serie. Als Nächstes: Modelfile-Anpassung – Modelle auf Ihre Anforderungen trimmen.

Ollama-API-Cliententwicklung

Vollständiger Leitfaden zur Nutzung der Python- oder Node.js-SDK für die lokale Ollama-Modell-API

⏱️ Estimated time: 45 min

  1. 1

    Step 1: SDK installieren und Basistest

    Python: `pip install ollama`, Node.js: `npm i ollama`.

    Nach der Installation mit minimalem Code die Verbindung testen:
    ```python
    from ollama import chat
    response = chat(model='gemma3', messages=[{'role': 'user', 'content': 'Hallo'}])
    print(response.message.content)
    ```

    Ollama-Dienst muss laufen (Standardport 11434), das gewünschte Modell muss heruntergeladen sein.
  2. 2

    Step 2: Streaming-Antworten implementieren

    Streaming aktivieren, damit Nutzer die Ausgabe Zeichen für Zeichen sehen:

    ```python
    from ollama import chat
    stream = chat(model='gemma3', messages=[...], stream=True)
    for chunk in stream:
    print(chunk['message']['content'], end='', flush=True)
    ```

    Hinweis: chunk ist ein Dictionary – Zugriff über `chunk['message']['content']`.
  3. 3

    Step 3: Tool-Calling konfigurieren (optional)

    Python-Funktionen als Tools definieren – SDK parst Docstring und Typannotationen automatisch:

    ```python
    def get_weather(city: str) -> str:
    """Wetterinformationen für eine Stadt abrufen"""
    return f'{city}: sonnig'

    response = chat(model='qwen3', messages=[...], tools=[get_weather])
    ```

    Agent Loop implementieren, der mehrfache Tool-Aufrufe verarbeitet, bis das Modell die finale Antwort liefert.
  4. 4

    Step 4: Natives SDK oder OpenAI-kompatible Schnittstelle wählen

    Neue Projekte: natives SDK empfohlen – mehr Features (Cloud Models, Thinking-Modus).

    Bestehende OpenAI-Projekte: nur zwei Zeilen ändern:
    ```python
    client = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')
    ```

    Migration mit minimalem Aufwand, jederzeit zurück zu OpenAI möglich.

FAQ

Welcher Standardport und welche Adresse hat die Ollama-API?
Ollama startet standardmäßig unter localhost:11434 einen REST-API-Dienst. Kern-Endpunkte: /api/chat (Mehrturn-Dialog), /api/generate (Ein-Turn-Generierung) sowie /v1/chat/completions für OpenAI-Kompatibilität.
Welchen Typ liefert das Python-SDK beim Streaming?
Streaming-Chunks sind Dictionaries, keine Objekte. Inhalt über chunk['message']['content'], nicht chunk.message.content. Der asynchrone Client liefert einen async generator – mit async for iterieren.
Welche Einschränkungen hat das Node.js-SDK im Browser?
Im Browser ist Streaming (stream: true) Pflicht – nicht-streamende Anfragen liefern große JSON-Antworten auf einmal, Cross-Origin-Requests laufen leicht in Timeouts oder werden blockiert. Import: `import ollama from 'ollama/browser'`.
Was ist das Agent-Loop-Muster?
Agent Loop verarbeitet Tool-Calling in einer Schleife: Nachricht an Modell → prüfen auf tool_calls → Funktion ausführen → Ergebnis in Nachrichtenverlauf → erneut Modell aufrufen → wiederholen, bis keine Tools mehr aufgerufen werden. Grundlage für Agent-Entwicklung.
Wie trennt man im Thinking-Modus Denkprozess und finale Antwort?
Im Thinking-Modus enthält der Streaming-Chunk ein zusätzliches thinking-Feld. Getrennt akkumulieren: if chunk.message.thinking → Denkinhalt sammeln, elif chunk.message.content → finale Antwort sammeln. Unterstützt u. a. von qwen3.
Natives SDK oder OpenAI-kompatible Schnittstelle – was wählen?
Neue Projekte: natives SDK – automatisches Parsen von Docstrings bei Tool-Calling, Cloud Models und Thinking-Modus. Bestehende OpenAI-Projekte: Kompatibilitätsschicht – nur base_url ändern, minimaler Migrationsaufwand, einfacher Wechsel zurück zu OpenAI.

9 Min. Lesezeit · Veröffentlicht am: 18. Apr. 2026 · Aktualisiert am: 14. Juli 2026

Kommentare

Melde dich mit GitHub an, um einen Kommentar zu hinterlassen

Easton BlogEaston Blog