Changer le thème

Pratique Ollama API : guide de développement client Python et Node.js

Easton editorial illustration: coding assistant migration bridge

Vous tapez ollama run gemma3 dans le terminal, et la première réponse s’affiche. Le modèle local tourne.

La question suivante : peut-on l’intégrer à son propre projet ? Pas de clé API, pas de facturation, tout en local — c’est tentant.

En parcourant la doc, on découvre que l’équipe fournit des SDK Python et JavaScript, et qu’on peut même brancher le SDK OpenAI en changeant deux lignes. Plus simple que prévu.

Mais simple ne veut pas dire sans pièges. Comment accumuler le streaming ? Comment écrire la boucle Agent Loop pour l’appel d’outils ? Comment séparer raisonnement et réponse en mode thinking ? Ce sont des erreurs que j’ai déjà commises.

Cet article comble ces lacunes. Comparaison Python et Node.js, SDK natif et compatibilité OpenAI — un guide client complet.

Si Ollama n’est pas encore installé, commencez par l’intégration de LangChain avec Ollama pour faire tourner un modèle local.


Chapitre 1 : bases de l’API Ollama

Commençons par le fonctionnement de l’API.

Ollama démarre par défaut un service API REST local à l’adresse http://localhost:11434/api. Ouvrez cette URL dans le navigateur : un sobre « Ollama is running » confirme que le service fonctionne.

Principaux endpoints

Deux endpoints clés à retenir :

EndpointUsageCaractéristiques
/api/chatDialogue multi-toursAccepte un tableau messages, contexte transmissible
/api/generateGénération mono-tourDirect, adapté aux tâches ponctuelles

Il existe aussi /v1/chat/completions, l’endpoint compatible OpenAI. Si vous avez déjà un projet OpenAI, changez base_url et c’est parti — nous y reviendrons en détail.

Essai avec curl

Testons l’API de la manière la plus brute :

curl http://localhost:11434/api/chat -d '{
  "model": "gemma3",
  "messages": [
    { "role": "user", "content": "Pourquoi le ciel est-il bleu ?" }
  ]
}'

Le terminal affiche un flux JSON. Regardez le champ message.content : c’est la réponse du modèle.

Structure de réponse typique :

{
  "model": "gemma3",
  "created_at": "2026-04-18T01:23:45.678Z",
  "message": {
    "role": "assistant",
    "content": "Le ciel paraît bleu surtout parce que..."
  },
  "done": true
}

Le champ done est important. En streaming, chaque chunk a done: false ; seul le dernier a done: true. Nous l’utiliserons plus loin.

Réponse en streaming

Par défaut, l’API attend la fin de génération avant de tout renvoyer. Pour un effet « machine à écrire », ajoutez stream: true :

curl http://localhost:11434/api/chat -d '{
  "model": "gemma3",
  "messages": [{ "role": "user", "content": "Pourquoi le ciel est-il bleu ?" }],
  "stream": true
}'

Cette fois, le terminal affiche une ligne JSON par chunk. Il faut les accumuler pour reconstituer la réponse complète.

Gérer ces chunks à la main, c’est fastidieux. D’où l’intérêt des SDK officiels — ils encapsulent ces détails.


Chapitre 2 : SDK Python en pratique

Le SDK Python est maintenu par l’équipe Ollama. Installation simple :

pip install ollama

Compatible Python 3.8+, ce qui est pratique.

Appel de base

L’appel le plus simple tient en quelques lignes :

from ollama import chat

response = chat(
  model='gemma3',
  messages=[{'role': 'user', 'content': 'Pourquoi le ciel est-il bleu ?'}]
)

print(response.message.content)

chat() est un raccourci du SDK ; en interne, il crée un Client par défaut vers le service Ollama local.

Pour personnaliser la connexion — par exemple Ollama sur une autre machine — créez un Client :

from ollama import Client

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

Réponse en streaming

Le streaming est central : l’utilisateur voit le texte apparaître progressivement, pas d’un coup après une longue attente.

from ollama import chat

stream = chat(
  model='gemma3',
  messages=[{'role': 'user', 'content': 'Pourquoi le ciel est-il bleu ?'}],
  stream=True,
)

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

Piège courant : chunk est un dictionnaire, pas un objet. Utilisez chunk['message']['content'], pas chunk.message.content. Je suis tombé dedans au début — l’erreur m’a fait perdre du temps.

Client asynchrone

Pour une architecture async — FastAPI, aiohttp — utilisez le client asynchrone :

import asyncio
from ollama import AsyncClient

async def main():
  client = AsyncClient()
  
  # Non-streaming
  response = await client.chat(
    model='gemma3',
    messages=[{'role': 'user', 'content': 'Bonjour'}]
  )
  print(response.message.content)
  
  # Streaming
  stream = await client.chat(
    model='gemma3',
    messages=[{'role': 'user', 'content': 'Pourquoi le ciel est-il bleu ?'}],
    stream=True,
  )
  async for chunk in stream:
    print(chunk['message']['content'], end='', flush=True)

asyncio.run(main())

Le streaming async renvoie un async generator, parcouru avec async for. Même logique que la version synchrone, avec await et async.

Cloud Models

Le SDK Ollama prend aussi en charge les modèles cloud. Certains grands modèles — comme gpt-oss 120B — ne tournent pas en local, mais sont disponibles dans le cloud.

from ollama import chat

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

Un nom de modèle avec le suffixe -cloud passe par l’API cloud. Il faut un compte Ollama cloud et une clé API ; la configuration diffère du local — voir la doc officielle.

En pratique, c’est utile : petits modèles en local pour économiser, grands modèles dans le cloud pour éviter le matériel lourd. Un bon compromis.


Chapitre 3 : SDK Node.js en pratique

Le SDK Node.js est tout aussi concis :

npm i ollama

Ce package couvre Node.js et le navigateur. La version navigateur s’importe séparément :

// Node.js
import ollama from 'ollama'

// Navigateur
import ollama from 'ollama/browser'

Appel de base

En Node.js, tout est async par défaut — plus naturel :

import ollama from 'ollama'

const response = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: 'Pourquoi le ciel est-il bleu ?' }],
})

console.log(response.message.content)

Comparaison avec Python : messages en dictionnaire côté Python, en objet côté Node.js. Les noms de paramètres sont alignés — changer de langage ne change pas les concepts.

Réponse en streaming

Node.js gère le streaming nativement via async generator :

import ollama from 'ollama'

const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: 'Pourquoi le ciel est-il bleu ?' }],
  stream: true,
})

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

Utilisez process.stdout.write plutôt que console.log, car console.log ajoute un saut de ligne — vous ne voulez pas un retour à la ligne à chaque caractère.

Configuration personnalisée

Le SDK accepte host et headers personnalisés :

import ollama from 'ollama'

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

// Ou configuration globale
ollama.setDefaultHost('http://192.168.1.100:11434')

// Ajouter des headers (ex. authentification)
const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: 'Bonjour' }],
  headers: { Authorization: 'Bearer xxx' },
})

Le paramètre headers est pratique si un proxy d’authentification protège votre instance Ollama.

Annuler une génération en streaming

La méthode abort() interrompt une génération en cours :

import ollama from 'ollama'

const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: 'Rédige un long article...' }],
  stream: true,
})

// L'utilisateur clique sur Arrêter
ollama.abort()

for await (const chunk of stream) {
  // La boucle se termine tôt après abort
  process.stdout.write(chunk.message.content)
}

Indispensable pour une interface de chat : l’utilisateur peut arrêter la génération à tout moment.

Version navigateur

Usage similaire, avec quelques différences :

import ollama from 'ollama/browser'

// En navigateur, le streaming est obligatoire (CORS sur les grosses réponses JSON)
const stream = await ollama.chat({
  model: 'gemma3',
  messages: [{ role: 'user', content: 'Bonjour' }],
  stream: true,
})

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

Contrainte navigateur : le mode streaming est obligatoire. Les requêtes non streamées renvoient un gros JSON d’un coup ; les requêtes cross-origin risquent timeout ou blocage. Le streaming envoie des chunks — bien plus fiable.

Logique cohérente : une UI de chat en navigateur a de toute façon besoin d’un affichage progressif.


Chapitre 4 : appel d’outils en pratique

L’appel d’outils est la base des Agents. Ollama permet au modèle d’invoquer vos fonctions, puis de continuer la génération avec le résultat.

Le SDK Python offre un atout : passez directement des fonctions Python comme outils ; le SDK parse docstring et types de paramètres.

Parsing automatique des fonctions Python

def get_weather(city: str) -> str:
  """Obtenir la météo d'une ville

  Args:
    city: Nom de la ville, ex. Pékin, Shanghai

  Returns:
    Description météo
  """
  # Données simulées
  weather_data = {
    'Pékin': 'Ensoleillé, 18°C',
    'Shanghai': 'Nuageux, 22°C',
    'Canton': 'Pluie, 26°C',
  }
  return weather_data.get(city, f'Données météo introuvables pour {city}')

from ollama import chat

response = chat(
  model='qwen3',
  messages=[{'role': 'user', 'content': 'Quel temps fait-il à Pékin aujourd\'hui ?'}],
  tools=[get_weather],
)

print(response.message.content)

Le SDK convertit la fonction au format outil : nom depuis la fonction, description depuis la docstring, paramètres depuis les annotations. Pas besoin d’écrire le JSON Schema à la main.

Modèle Agent Loop

Ce n’est pas si simple : le modèle peut appeler plusieurs outils, ou enchaîner après un premier appel. Il faut une boucle.

Voici l’Agent Loop :

from ollama import chat

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

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

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

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

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

  if response.message.tool_calls:
    # Le modèle veut appeler un outil
    for call in response.message.tool_calls:
      func_name = call.function.name
      func_args = call.function.arguments
      result = tool_map[func_name](**func_args)

      # Ajouter le résultat à l'historique
      messages.append({
        'role': 'tool',
        'content': str(result),
        'tool_name': func_name,
      })
  else:
    # Plus d'appel d'outil — terminé
    print(response.message.content)
    break

La logique :

  1. Envoyer le message avec les définitions d’outils
  2. Si le modèle renvoie des tool_calls, exécuter les fonctions correspondantes
  3. Réinjecter les résultats dans l’historique, rappeler le modèle
  4. Boucler jusqu’à ce qu’il n’appelle plus d’outils

Ce modèle est incontournable pour un Agent : vous définissez les outils, le modèle décide quand, lesquels et dans quel ordre les appeler.

Mode thinking

Certains modèles — qwen3 par exemple — supportent le mode thinking : le modèle « réfléchit » avant de répondre.

from ollama import chat

stream = chat(
  model='qwen3',
  messages=[{'role': 'user', 'content': 'Pourquoi le ciel est-il bleu ?'}],
  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('=== Raisonnement ===')
print(thinking)
print('=== Réponse finale ===')
print(content)

En mode thinking, chaque chunk contient un champ thinking supplémentaire. Accumulez séparément raisonnement et réponse.

Fonctionnalité intéressante : vous voyez comment le modèle dérive la réponse. Utile pour l’éducation ou le débogage de prompts.


Chapitre 5 : SDK natif vs API compatible OpenAI

Deux options :

  1. SDK Ollama natif (tout ce qui précède)
  2. SDK OpenAI, en changeant l’adresse pour pointer vers Ollama

Lequel choisir ? Cela dépend de votre contexte.

Compatibilité OpenAI

Pour un projet OpenAI existant, la migration la moins coûteuse : changer base_url :

from openai import OpenAI

client = OpenAI(
  base_url='http://localhost:11434/v1',
  api_key='ollama',  # Obligatoire mais ignorée
)

response = client.chat.completions.create(
  model='gemma3',
  messages=[{'role': 'user', 'content': 'Pourquoi le ciel est-il bleu ?'}],
)

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

Le SDK OpenAI ne sait pas qu’Ollama est derrière — il parle à une « API OpenAI ».

Version Node.js identique :

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: 'Pourquoi le ciel est-il bleu ?' }],
})

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

Comparaison des deux approches

AspectSDK natifCompatible OpenAI
Installationpip install ollamaSDK OpenAI déjà installé
Appel d’outilsDocstring auto-parséeJSON Schema manuel
StreamingChunks en dictionnaireFormat OpenAI standard
Cloud ModelsSupportéNon supporté
Coût de migrationNul pour un nouveau projetMinimal pour un projet existant

Recommandations

Nouveau projet : SDK natif.

Raisons :

  • Appel d’outils plus simple — passez directement des fonctions Python
  • Plus de fonctionnalités (Cloud Models, mode thinking)
  • Doc et exemples officiels, dépannage plus facile

Migration d’un projet OpenAI existant : compatibilité OpenAI.

Raisons :

  • Deux lignes de code suffisent
  • Pas de réécriture de logique
  • Retour à OpenAI simple par la suite

En résumé : SDK natif pour plus de fonctionnalités, compatibilité OpenAI pour migrer plus vite. À vous de voir.

J’ai testé les deux. L’appel d’outils natif fait gagner du temps — pas de JSON Schema à écrire, une docstring claire suffit. Mais si le projet tourne déjà sur OpenAI, inutile de tout refactoriser pour Ollama.


Conclusion

Quelques points clés :

Appel de base : les SDK Python et Node.js sont bien conçus ; quelques lignes suffisent. Pensez à stream=True pour le streaming.

Appel d’outils : Agent Loop est le modèle central — boucler sur les tool_calls jusqu’à ce que le modèle s’arrête. Le SDK Python accepte des fonctions directement, sans JSON Schema.

Mode thinking : qwen3 et d’autres modèles le supportent ; vous voyez le raisonnement du modèle. Traitez séparément les champs thinking et content dans chaque chunk.

Choix d’approche : nouveau projet → SDK natif ; projet OpenAI existant → changez l’adresse.

Prochaines étapes :

  • Si Ollama n’est pas installé, commencez par le premier article de la série pour faire tourner un modèle local
  • Choisissez l’approche adaptée (native ou compatible OpenAI) et testez
  • La doc officielle évolue — de nouvelles fonctionnalités arrivent régulièrement

Faire tourner un LLM en local devient de plus en plus accessible. Ollama cache la complexité derrière une API simple. Il suffit de savoir l’appeler — le reste, c’est son travail.

Voici le deuxième article de cette série. Le prochain portera sur la personnalisation via Modelfile — comment adapter un modèle à vos besoins.

Développement client Ollama API

Guide complet pour appeler l'API de modèles locaux Ollama avec les SDK Python ou Node.js

⏱️ Estimated time: 45 min

  1. 1

    Step 1: Installer le SDK et tester un appel de base

    Côté Python : `pip install ollama`. Côté Node.js : `npm i ollama`.

    Après l'installation, testez la connexion avec le code le plus simple :
    ```python
    from ollama import chat
    response = chat(model='gemma3', messages=[{'role': 'user', 'content': 'Bonjour'}])
    print(response.message.content)
    ```

    Assurez-vous que le service Ollama est démarré (port 11434 par défaut) et que le modèle correspondant est téléchargé.
  2. 2

    Step 2: Implémenter la réponse en streaming

    Activez le mode streaming pour afficher la sortie caractère par caractère :

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

    Attention : chunk est un dictionnaire ; accédez au contenu via `chunk['message']['content']`.
  3. 3

    Step 3: Configurer l'appel d'outils (optionnel)

    Définissez des fonctions Python comme outils ; le SDK analyse automatiquement docstring et annotations de type :

    ```python
    def get_weather(city: str) -> str:
    """Obtenir la météo d'une ville"""
    return f'{city}: Ensoleillé'

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

    Implémentez une boucle Agent Loop pour gérer plusieurs appels d'outils jusqu'à la réponse finale.
  4. 4

    Step 4: Choisir entre SDK natif et compatibilité OpenAI

    Pour un nouveau projet, le SDK natif est recommandé (Cloud Models, mode thinking, etc.).

    Pour un projet OpenAI existant, deux lignes suffisent :
    ```python
    client = OpenAI(base_url='http://localhost:11434/v1', api_key='ollama')
    ```

    Coût de migration minimal ; retour à OpenAI possible à tout moment.

FAQ

Quel est le port et l'adresse par défaut de l'API Ollama ?
Ollama démarre une API REST sur localhost:11434 par défaut. Les endpoints clés sont /api/chat (dialogue multi-tours) et /api/generate (génération mono-tour), plus /v1/chat/completions pour la compatibilité OpenAI.
Quel type renvoie le streaming du SDK Python ?
Le streaming du SDK Python renvoie un dictionnaire, pas un objet. Accédez au contenu avec chunk['message']['content'], pas chunk.message.content. Le client asynchrone renvoie un async generator, parcouru avec async for.
Quelles limitations du SDK Node.js en environnement navigateur ?
La version navigateur doit utiliser le mode streaming (stream: true), car les requêtes non streamées renvoient un gros JSON d'un coup, sujet aux timeouts ou blocages CORS. L'import diffère aussi : `import ollama from 'ollama/browser'`.
Qu'est-ce que le modèle Agent Loop ?
Agent Loop est une boucle pour l'appel d'outils : envoyer un message au modèle → vérifier les tool_calls → exécuter les fonctions → réinjecter les résultats dans l'historique → rappeler le modèle → boucler jusqu'à ce qu'il n'appelle plus d'outils. C'est la base pour construire un Agent.
Comment séparer raisonnement et réponse finale en mode thinking ?
En mode thinking, chaque chunk streaming contient un champ thinking supplémentaire. Accumulez séparément : si chunk.message.thinking, accumulez le raisonnement ; elif chunk.message.content, accumulez la réponse. qwen3 et d'autres modèles le supportent.
Comment choisir entre SDK natif et compatibilité OpenAI ?
Nouveau projet : SDK natif (docstring auto-parsée, Cloud Models, mode thinking). Projet OpenAI existant : compatibilité — changez base_url, migration minimale, retour à OpenAI facile.

11 min de lecture · Publié le: 18 avr. 2026 · Mis à jour le: 30 juil. 2026

Commentaires

Connectez-vous avec GitHub pour laisser un commentaire

Easton BlogEaston Blog