Changer le thème

Appels API Ollama : de curl à l'interface compatible OpenAI SDK

Easton editorial illustration: modular AI application workbench

La commande curl dans le terminal ne renvoie qu’un demi-mot dans le JSON — deux heures perdues avant de comprendre que c’était le streaming. Ollama crache le contenu petit à petit par défaut ; chaque objet JSON ne contient que quelques caractères.

Pour déployer un LLM en local, Ollama abaisse la barrière : télécharger, installer, lancer, trois étapes. En revanche, les appels API prêtent à confusion : quelle différence entre l’API REST native et l’interface compatible OpenAI SDK ? Comment gérer le streaming ?

Cet article rassemble les pièges que j’ai rencontrés, de la commande curl à la migration zero-code vers le SDK OpenAI, plus quelques détails que la doc ne mentionne pas clairement.


Ollama propose deux interfaces API

Franchement, ça m’a embrouillé un moment. Ollama offre en réalité deux interfaces API complètement distinctes :

API REST native : http://localhost:11434/api/*

  • Endpoints : /api/generate (génération de texte), /api/chat (dialogue), /api/tags (liste des modèles)
  • Réponse en streaming par défaut (c’est le piège que j’ai rencontré à trois heures du matin)
  • Appel HTTP direct, sans SDK

Interface compatible OpenAI : http://localhost:11434/v1/*

  • Endpoints : /v1/chat/completions, /v1/completions, /v1/models
  • Entièrement compatible avec le SDK OpenAI (Python, JavaScript)
  • Compatible avec l’écosystème d’outils OpenAI existant

Pourquoi deux interfaces ? Chacune a son utilité. L’API native est plus légère et directe, idéale pour écrire son propre client HTTP ; l’interface compatible OpenAI permet d’utiliser le code SDK OpenAI existant sans modification — il suffit de changer base_url.

Honnêtement, c’est une conception maline. Elle s’adresse aux développeurs qui veulent un appel simple, comme aux équipes qui ont déjà du code dans l’écosystème OpenAI.


API REST native : commencer avec curl

Commençons par l’API native. C’est assez direct : une interface REST standard.

Appel curl de base

L’exemple le plus simple — génération de texte :

curl http://localhost:11434/api/generate -d '{
  "model": "llama3.2",
  "prompt": "Why is the sky blue?",
  "stream": false
}'

Notez le stream: false. Par défaut, Ollama renvoie le contenu en streaming. Pour obtenir une réponse JSON complète, il faut désactiver explicitement le streaming. Sinon, vous verrez une série de sorties comme celle-ci :

{"model":"llama3.2","response":"That","done":false}
{"model":"llama3.2","response":"'","done":false}
{"model":"llama3.2","response":"s","done":false}
{"model":"llama3.2","response":" a","done":false}
...
{"model":"llama3.2","response":"!","done":true}

Chaque objet JSON ne contient que quelques caractères, token par token. C’est le format NDJSON (Newline-Delimited JSON) — un objet JSON par ligne. Cette nuit-là à trois heures, je n’avais pas remarqué ça et j’avais parsé comme un JSON classique ; je n’avais récupéré que « That » du premier objet.

Le mode dialogue est plus pratique

La génération unique convient aux tâches simples, mais le mode dialogue est celui qu’on utilise vraiment :

curl http://localhost:11434/api/chat -d '{
  "model": "llama3.2",
  "messages": [
    { "role": "user", "content": "Hello!" }
  ],
  "stream": false
}'

Vous pouvez maintenir un tableau messages avec l’historique de la conversation, pour que le modèle garde le contexte. Essentiel pour construire une application de chat.

Voir les modèles installés

Parfois, vous voulez savoir quels modèles sont disponibles en local :

curl http://localhost:11434/api/tags

Le JSON renvoyé liste tous les modèles téléchargés, avec taille, date de modification, niveau de quantification, etc. Pratique.


Gestion des réponses en streaming

Ce point mérite une section dédiée. Le streaming Ollama a une particularité : il ne renvoie pas le contenu d’un coup, mais token par token.

Streaming en Python

Avec la bibliothèque requests en Python :

import requests
import json

url = "http://localhost:11434/api/chat"
payload = {
    "model": "llama3.2",
    "messages": [{"role": "user", "content": "Write a short poem"}],
    "stream": True
}

response = requests.post(url, json=payload, stream=True)
for line in response.iter_lines():
    if line:
        chunk = json.loads(line)
        print(chunk.get("message", {}).get("content", ""), end="", flush=True)

Le point clé est response.iter_lines() — il permet de lire le flux NDJSON ligne par ligne. Chaque chunk ne contient peut-être que quelques caractères ; il faut les accumuler pour obtenir la réponse complète.

Streaming en JavaScript

Côté frontend, avec l’API fetch, c’est similaire :

const response = await fetch('http://localhost:11434/api/chat', {
  method: 'POST',
  body: JSON.stringify({
    model: 'llama3.2',
    messages: [{ role: 'user', content: 'Hello!' }],
    stream: true
  })
});

const reader = response.body.getReader();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  const chunk = new TextDecoder().decode(value);
  // Traiter chaque chunk...
}

Le streaming est un peu plus complexe que le mode non streamé, mais l’expérience utilisateur est bien meilleure — vous voyez le modèle « réfléchir » et produire sa sortie en temps réel, au lieu d’attendre longtemps avant qu’un gros bloc de texte apparaisse.


Interface compatible OpenAI SDK : migration zero-code

C’est la partie que je préfère. Ollama fournit une interface API entièrement compatible OpenAI ; vous pouvez migrer votre code existant quasi sans friction.

Exemple avec le SDK Python OpenAI

Utilisez directement le SDK officiel OpenAI :

from openai import OpenAI

client = OpenAI(
    base_url='http://localhost:11434/v1/',
    api_key='ollama'  # Non vérifiée en local, valeur quelconque
)

response = client.chat.completions.create(
    model="llama3.2",
    messages=[{"role": "user", "content": "Hello!"}]
)

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

La seule modification : définir base_url et une api_key quelconque. Le reste du code reste identique.

Bascule développement / production

Cette fonctionnalité est particulièrement utile. En développement, utilisez Ollama en local ; en production, OpenAI :

# .env développement
OPENAI_API_KEY=anyrandomtext
LLM_ENDPOINT="http://localhost:11434/v1"
MODEL=llama3.2

# .env production
OPENAI_API_KEY=sk-XXXXXXXXXXXXXXXXXXXXXXXX
LLM_ENDPOINT="https://api.openai.com/v1"
MODEL=gpt-3.5-turbo

Le code lit simplement les variables d’environnement :

import os
from openai import OpenAI

client = OpenAI(
    base_url=os.getenv('LLM_ENDPOINT'),
    api_key=os.getenv('OPENAI_API_KEY')
)

En développement, pas besoin de payer l’API OpenAI — les tests locaux suffisent. En production, changez les variables d’environnement pour basculer vers OpenAI.

Endpoints pris en charge

L’interface compatible OpenAI d’Ollama prend en charge ces endpoints :

EndpointFonctionNiveau de support
/v1/chat/completionsGénération de dialoguePrise en charge complète
/v1/completionsComplétion de textePrise en charge complète
/v1/modelsListe des modèlesPrise en charge complète
/v1/embeddingsEmbeddings de textePrise en charge complète
/v1/responsesNouvelle API de réponsesPrise en charge complète

Il existe aussi un endpoint expérimental /v1/images/generations, mais sa stabilité n’est pas encore suffisante.

Alias de modèles

Petite astuce : vous pouvez créer des alias pour vos modèles. Par exemple, pour que le code ressemble à un appel GPT-3.5 :

ollama cp llama3.2 gpt-3.5-turbo

Ainsi, model="gpt-3.5-turbo" dans votre code utilisera en réalité llama3.2 en local. Utile lors de la migration de code.


Quelle approche choisir ?

Après tout ça, vous vous demandez peut-être : laquelle utiliser ?

Cas d’usage de l’API REST native

Convient dans ces situations :

  • Vous voulez l’appel le plus léger possible
  • Vous n’avez pas besoin de l’écosystème OpenAI SDK
  • Vous écrivez votre propre client HTTP (appareils embarqués, environnements spéciaux)
  • Vous devez contrôler finement les détails du streaming

L’API native est plus directe, plus bas niveau. Si vous maîtrisez HTTP, vous serez à l’aise.

Cas d’usage de l’interface compatible OpenAI SDK

Convient dans ces situations :

  • Vous avez déjà du code basé sur le SDK OpenAI
  • Vous devez migrer rapidement vers un déploiement local
  • Vous utilisez la chaîne d’outils OpenAI (LangChain, LlamaIndex, etc.)
  • Vous devez basculer entre environnements dev et prod

En bref, si vous voulez réutiliser du code existant sans le modifier, prenez l’interface compatible OpenAI.

Mon conseil

Franchement, en développement je préfère l’interface compatible OpenAI SDK — peu de modifications, la chaîne d’outils fonctionne, le débogage est simple. Mais l’API native convient mieux dans certains cas, par exemple pour un outil CLI minimaliste ou un environnement qui ne supporte pas le SDK OpenAI.


Extraits de code pratiques

Quelques extraits que j’utilise souvent.

Chat en streaming Python (SDK OpenAI)

from openai import OpenAI

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

stream = client.chat.completions.create(
    model="llama3.2",
    messages=[{"role": "user", "content": "Write a poem"}],
    stream=True
)

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

Dialogue complet JavaScript (API native)

async function chat(messages) {
  const response = await fetch('http://localhost:11434/api/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'llama3.2',
      messages: messages,
      stream: false
    })
  });
  return await response.json();
}

// Maintenir l'historique de conversation
let conversation = [
  { role: 'user', content: 'Hello!' }
];

const result = await chat(conversation);
conversation.push({
  role: 'assistant',
  content: result.message.content
});

console.log(result.message.content);

Exemple avec appel d’outils

Ollama prend aussi en charge le Function Calling (appel d’outils) :

from openai import OpenAI

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

tools = [
  {
    "type": "function",
    "function": {
      "name": "get_weather",
      "description": "Get current weather",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {"type": "string"}
        },
        "required": ["location"]
      }
    }
  }
]

response = client.chat.completions.create(
  model="llama3.2",
  messages=[{"role": "user", "content": "What's the weather in Tokyo?"}],
  tools=tools
)

if response.choices[0].message.tool_calls:
  print("Model wants to call:", response.choices[0].message.tool_calls[0].function.name)

En résumé

Le design de l’API Ollama est équilibré — l’API REST native pour la légèreté et la simplicité, le SDK OpenAI pour la commodité et la compatibilité écosystème. Chaque approche a ses cas d’usage ; tout dépend de vos besoins.

Si vous débutez avec Ollama, je recommande de commencer par l’interface compatible OpenAI SDK — prise en main rapide, peu de modifications. Une fois à l’aise, choisissez l’API native selon vos besoins concrets.

Et un dernier point : le streaming est un piège classique. Par défaut, c’est activé ; si vous n’en avez pas besoin, définissez explicitement stream: false, sinon vous risquez de rester fixé sur un demi-mot à trois heures du matin, comme moi.


Références

Deux façons d'appeler l'API Ollama

Flux complet d'appel, de l'API native curl à l'interface compatible OpenAI SDK

⏱️ Estimated time: 10 min

  1. 1

    Step 1: Vérifier qu'Ollama est installé et en cours d'exécution

    Commencez par vérifier qu'Ollama fonctionne correctement :

    • Dans le terminal : ollama list (pour voir les modèles téléchargés)
    • Ou visitez : http://localhost:11434 (doit afficher Ollama is running)
    • Port par défaut : 11434
  2. 2

    Step 2: Choisir la méthode d'appel

    Selon votre cas d'usage :

    • API REST native : adaptée aux appels légers et aux clients personnalisés
    • Compatible OpenAI SDK : idéale si vous avez déjà du code OpenAI, migration rapide
  3. 3

    Step 3: Utiliser l'API REST native (via curl)

    Appel curl de base :

    • Génération de texte : curl http://localhost:11434/api/generate -d '{"model": "llama3.2", "prompt": "...", "stream": false}'
    • Mode dialogue : curl http://localhost:11434/api/chat -d '{"model": "llama3.2", "messages": [...], "stream": false}'
    • Attention : le streaming est activé par défaut ; définissez stream: false pour le désactiver
  4. 4

    Step 4: Utiliser l'interface compatible OpenAI SDK

    Appel avec le SDK Python OpenAI :

    • Définissez base_url='http://localhost:11434/v1/'
    • api_key peut être n'importe quelle valeur (non vérifiée en local)
    • Le reste du code est identique à OpenAI
    • Changement d'environnement : modifiez base_url (local en dev, OpenAI en prod)
  5. 5

    Step 5: Gérer les réponses en streaming

    Points clés pour le streaming :

    • Python : response.iter_lines() pour lire le NDJSON ligne par ligne
    • JavaScript : response.body.getReader() pour lire le flux
    • Chaque chunk ne contient que quelques caractères ; il faut accumuler la réponse complète
    • Mode non streamé : définissez stream: false pour obtenir un JSON complet

FAQ

Quelle est la différence entre l'API native Ollama et l'interface compatible OpenAI SDK ?
L'API native est plus légère et directe, avec streaming par défaut (format NDJSON), idéale pour un client HTTP personnalisé. L'interface compatible OpenAI SDK est entièrement compatible avec le SDK OpenAI ; il suffit de changer base_url, pratique pour migrer rapidement du code OpenAI existant.
Pourquoi mon appel API Ollama ne renvoie qu'un demi-mot ?
C'est le comportement par défaut du streaming. Ollama sort les tokens un par un au format NDJSON ; chaque objet JSON ne contient que quelques caractères. Solutions :

• Définissez stream: false pour obtenir un JSON complet
• Ou traitez correctement le flux NDJSON : lisez ligne par ligne et accumulez le contenu
Comment utiliser Ollama en local en développement et OpenAI en production ?
Utilisez une variable d'environnement : en développement, LLM_ENDPOINT="http://localhost:11434/v1" ; en production, "https://api.openai.com/v1". Le code lit base_url depuis la variable d'environnement, le reste ne change pas.
Quels endpoints OpenAI Ollama prend-il en charge ?
Prise en charge complète : /v1/chat/completions, /v1/completions, /v1/models, /v1/embeddings, /v1/responses. Prise en charge expérimentale : /v1/images/generations (stabilité insuffisante).
Peut-on créer des alias pour les modèles Ollama ?
Oui. Commande : ollama cp llama3.2 gpt-3.5-turbo — le code avec model="gpt-3.5-turbo" utilisera en réalité llama3.2 en local. Astuce utile lors de la migration de code.
Ollama prend-il en charge l'appel d'outils (Function Calling) ?
Oui. Via l'interface compatible OpenAI SDK, utilisez le paramètre tools pour définir le schéma des fonctions ; le modèle renverra le champ tool_calls indiquant la fonction à appeler.

8 min de lecture · Publié le: 3 avr. 2026 · Mis à jour le: 27 juil. 2026

Commentaires

Connectez-vous avec GitHub pour laisser un commentaire

Easton BlogEaston Blog