Clients Go pour Ollama : comparaison des SDK et exemples avec Qwen3/GPT-OSS
Intégrez Ollama avec Go : guide de l'API, exemples et bonnes pratiques en production.
Ce guide fournit un aperçu complet des SDK Go pour Ollama disponibles et compare leurs ensembles de fonctionnalités.
Nous explorerons des exemples pratiques en Go pour appeler les modèles Qwen3 et GPT-OSS hébergés sur Ollama, à la fois via des appels REST API bruts et le client Go officiel, y compris un traitement détaillé des modes de réflexion et non-réflexion dans Qwen3.

Pourquoi Ollama + Go ?
Ollama expose un petit API HTTP pragmatique (généralement en cours d’exécution à http://localhost:11434) conçu pour les charges de travail generate et chat, avec un support natif de streaming et des fonctionnalités de gestion de modèles. La documentation officielle couvre en détail les structures de requête/réponse /api/generate et /api/chat ainsi que les sémantiques de streaming.
Go est un excellent choix pour créer des clients Ollama grâce à son support fort de la bibliothèque standard pour HTTP, une excellente gestion du JSON, des primitives de concurrence natives et des interfaces statiquement typées qui captent les erreurs à la compilation. Pour voir comment Ollama se compare à vLLM, Docker Model Runner, LocalAI et aux fournisseurs de cloud — y compris quand choisir chacun — consultez LLM Hosting : Comparaison de l’hébergement local, auto-hébergé et cloud.
À partir d’octobre 2025, voici les options de SDK Go que vous envisagerez probablement.
SDK Go pour Ollama — ce qui est disponible ?
| SDK / Package | Statut et « propriétaire » | Portée (Generate/Chat/Streaming) | Gestion des modèles (pull/list/etc.) | Extras / Notes |
|---|---|---|---|---|
github.com/ollama/ollama/api |
Packaging officiel dans le dépôt Ollama ; utilisé par le CLI ollama lui-même |
Couverture complète mappée au REST ; streaming supporté | Oui | Considéré comme le client Go canonique ; l’API miroir les documents de manière étroite. |
LangChainGo (github.com/tmc/langchaingo/llms/ollama) |
Framework communautaire (LangChainGo) avec module LLM Ollama | Chat/Completion + streaming via des abstractions du framework | Limité (la gestion des modèles n’est pas l’objectif principal) | Idéal si vous souhaitez des chaînes, des outils, des magasins vectoriels en Go ; moins d’un SDK brut. |
github.com/swdunlop/ollama-client |
Client communautaire | Se concentre sur le chat ; bons expérimentations d’appel d’outils | Partiel | Conçu pour expérimenter avec l’appel d’outils ; pas une surface complète à 1:1. |
Autres SDK communautaires (ex. ollamaclient, « go-ollama-sdk » tiers) |
Communautaire | Varie | Varie | La qualité et la couverture varient ; évaluez par dépôt. |
Recommandation : Pour la production, préférez github.com/ollama/ollama/api — il est maintenu avec le projet principal et miroir l’API REST.
Qwen3 & GPT-OSS sur Ollama : mode de réflexion vs non-réflexion (ce que vous devez savoir)
- Le mode de réflexion d’Ollama sépare la « raison » du modèle de la sortie finale lorsqu’il est activé. Ollama documente un comportement d’activation/désactivation de la réflexion de premier plan à travers les modèles pris en charge.
- (https://www.glukhov.org/fr/llm-performance/benchmarks/qwen3-30b-vs-gpt-oss-20b/ “Qwen3:30b vs GPT-OSS:20b : détails techniques, performance et comparaison de vitesse”) prend en charge le basculement dynamique : ajoutez
/thinkou/no_thinkdans les messages système/utilisateur pour basculer les modes tour par tour ; l’instruction la plus récente gagne. - GPT-OSS : les utilisateurs rapportent que désactiver la réflexion (ex.
/set nothinkou--think=false) peut être peu fiable surgpt-oss:20b; planifiez de filtrer/cacher toute réflexion que votre interface utilisateur ne doit pas afficher.
Partie 1 — Appel d’Ollama via REST brut (Go, net/http)
Types partagés
D’abord, définissons les types communs et les fonctions d’assistance que nous utiliserons dans nos exemples :
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
// ---- Types de l'API de chat ----
type ChatMessage struct {
Role string `json:"role"`
Content string `json:"content"`
}
type ChatRequest struct {
Model string `json:"model"`
Messages []ChatMessage `json:"messages"`
// Certains serveurs exposent le contrôle de la réflexion comme un drapeau booléen.
// Même si omis, vous pouvez toujours contrôler Qwen3 via /think ou /no_think.
Think *bool `json:"think,omitempty"`
Stream *bool `json:"stream,omitempty"`
Options map[string]any `json:"options,omitempty"`
}
type ChatResponse struct {
Model string `json:"model"`
CreatedAt string `json:"created_at"`
Message struct {
Role string `json:"role"`
Content string `json:"content"`
Thinking string `json:"thinking,omitempty"` // présent lorsque la réflexion est activée
} `json:"message"`
Done bool `json:"done"`
}
// ---- Types de l'API de génération ----
type GenerateRequest struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
Think *bool `json:"think,omitempty"`
Stream *bool `json:"stream,omitempty"`
Options map[string]any `json:"options,omitempty"`
}
type GenerateResponse struct {
Model string `json:"model"`
CreatedAt string `json:"created_at"`
Response string `json:"response"` // texte final pour non-stream
Thinking string `json:"thinking,omitempty"` // présent lorsque la réflexion est activée
Done bool `json:"done"`
}
// ---- Fonctions d'assistance ----
func httpPostJSON(url string, payload any) ([]byte, error) {
body, err := json.Marshal(payload)
if err != nil {
return nil, err
}
c := &http.Client{Timeout: 60 * time.Second}
resp, err := c.Post(url, "application/json", bytes.NewReader(body))
if err != nil {
return nil, err
}
defer resp.Body.Close()
return io.ReadAll(resp.Body)
}
// bptr retourne un pointeur à une valeur booléenne
func bptr(b bool) *bool { return &b }
Chat — Qwen3 avec réflexion ACTIVÉE (et comment la désactiver)
func chatQwen3Thinking() error {
endpoint := "http://localhost:11434/api/chat"
req := ChatRequest{
Model: "qwen3:8b-thinking", // tout tag :*-thinking que vous avez tiré
Think: bptr(true),
Stream: bptr(false),
Messages: []ChatMessage{
{Role: "system", Content: "Vous êtes un assistant précis."},
{Role: "user", Content: "Expliquez la récursion avec un exemple court en Go."},
},
}
raw, err := httpPostJSON(endpoint, req)
if err != nil {
return err
}
var out ChatResponse
if err := json.Unmarshal(raw, &out); err != nil {
return err
}
fmt.Println("🧠 réflexion:\n", out.Message.Thinking)
fmt.Println("\n💬 réponse:\n", out.Message.Content)
return nil
}
// Pour désactiver la réflexion pour le prochain tour, faites :
// (a) définissez Think=false, et/ou
// (b) ajoutez "/no_think" au message système/utilisateur le plus récent (commutation douce de Qwen3).
// Qwen3 respecte l'instruction /think ou /no_think la plus récente dans les conversations multi-tours.
func chatQwen3NoThinking() error {
endpoint := "http://localhost:11434/api/chat"
req := ChatRequest{
Model: "qwen3:8b-thinking",
Think: bptr(false),
Stream: bptr(false),
Messages: []ChatMessage{
{Role: "system", Content: "Vous êtes bref. /no_think"},
{Role: "user", Content: "Expliquez la récursion en une phrase."},
},
}
raw, err := httpPostJSON(endpoint, req)
if err != nil {
return err
}
var out ChatResponse
if err := json.Unmarshal(raw, &out); err != nil {
return err
}
// S'attendre à ce que la réflexion soit vide ; toujours gérer défensivement.
if out.Message.Thinking != "" {
fmt.Println("🧠 réflexion (inattendue):\n", out.Message.Thinking)
}
fmt.Println("\n💬 réponse:\n", out.Message.Content)
return nil
}
(La commutation douce de Qwen3 /think et /no_think est documentée par l’équipe Qwen ; l’instruction la plus récente gagne dans les conversations multi-tours.)
Chat — GPT-OSS avec réflexion (et une note)
func chatGptOss() error {
endpoint := "http://localhost:11434/api/chat"
req := ChatRequest{
Model: "gpt-oss:20b",
Think: bptr(true), // demande une réflexion séparée si prise en charge
Stream: bptr(false),
Messages: []ChatMessage{
{Role: "user", Content: "Qu'est-ce que la programmation dynamique ? Expliquez l'idée centrale."},
},
}
raw, err := httpPostJSON(endpoint, req)
if err != nil {
return err
}
var out ChatResponse
if err := json.Unmarshal(raw, &out); err != nil {
return err
}
// Quirck connu : désactiver la réflexion peut ne pas supprimer entièrement la réflexion sur gpt-oss:20b.
// Filtrez toujours la réflexion dans l'interface utilisateur si vous ne souhaitez pas l'afficher.
fmt.Println("🧠 réflexion:\n", out.Message.Thinking)
fmt.Println("\n💬 réponse:\n", out.Message.Content)
return nil
}
Les utilisateurs rapportent que désactiver la réflexion sur gpt-oss:20b (ex. /set nothink ou --think=false) peut être ignoré — prévoyez un filtrage côté client si nécessaire.
Génération — Qwen3 et GPT-OSS
func generateQwen3() error {
endpoint := "http://localhost:11434/api/generate"
req := GenerateRequest{
Model: "qwen3:4b-thinking",
Prompt: "En 2–3 phrases, à quoi servent les arbres B dans les bases de données ?",
Think: bptr(true),
}
raw, err := httpPostJSON(endpoint, req)
if err != nil {
return err
}
var out GenerateResponse
if err := json.Unmarshal(raw, &out); err != nil {
return err
}
if out.Thinking != "" {
fmt.Println("🧠 réflexion:\n", out.Thinking)
}
fmt.Println("\n💬 réponse:\n", out.Response)
return nil
}
func generateGptOss() error {
endpoint := "http://localhost:11434/api/generate"
req := GenerateRequest{
Model: "gpt-oss:20b",
Prompt: "Expliquez brièvement la rétropropagation dans les réseaux de neurones.",
Think: bptr(true),
}
raw, err := httpPostJSON(endpoint, req)
if err != nil {
return err
}
var out GenerateResponse
if err := json.Unmarshal(raw, &out); err != nil {
return err
}
if out.Thinking != "" {
fmt.Println("🧠 réflexion:\n", out.Thinking)
}
fmt.Println("\n💬 réponse:\n", out.Response)
return nil
}
Les formes REST et le comportement de streaming proviennent directement de la référence de l’API Ollama.
Partie 2 — Appel d’Ollama via le SDK Go officiel (github.com/ollama/ollama/api)
Le package officiel expose un Client avec des méthodes qui correspondent à l’API REST. Le CLI Ollama lui-même utilise ce package pour communiquer avec le service, ce qui en fait le choix le plus sûr pour la compatibilité.
Installer
go get github.com/ollama/ollama/api
Chat — Qwen3 (réflexion ACTIVÉE / DÉSACTIVÉE)
package main
import (
"context"
"fmt"
"log"
"github.com/ollama/ollama/api"
)
func chatWithQwen3Thinking(ctx context.Context, thinking bool) error {
client, err := api.ClientFromEnvironment() // respecte OLLAMA_HOST si défini
if err != nil {
return err
}
req := &api.ChatRequest{
Model: "qwen3:8b-thinking",
// De nombreuses constructions de serveur exposent la réflexion comme un drapeau de niveau supérieur ;
// en outre, vous pouvez contrôler Qwen3 via /think ou /no_think dans les messages.
Think: api.Ptr(thinking),
Messages: []api.Message{
{Role: "system", Content: "Vous êtes un assistant précis."},
{Role: "user", Content: "Expliquez le tri fusion avec un court extrait de code Go."},
},
}
var resp api.ChatResponse
if err := client.Chat(ctx, req, &resp); err != nil {
return err
}
if resp.Message.Thinking != "" {
fmt.Println("🧠 réflexion:\n", resp.Message.Thinking)
}
fmt.Println("\n💬 réponse:\n", resp.Message.Content)
return nil
}
func main() {
ctx := context.Background()
if err := chatWithQwen3Thinking(ctx, true); err != nil {
log.Fatal(err)
}
// Exemple : non-réflexion
if err := chatWithQwen3Thinking(ctx, false); err != nil {
log.Fatal(err)
}
}
Chat — GPT-OSS (gérer la réflexion de manière défensive)
func chatWithGptOss(ctx context.Context) error {
client, err := api.ClientFromEnvironment()
if err != nil {
return err
}
req := &api.ChatRequest{
Model: "gpt-oss:20b",
Think: api.Ptr(true),
Messages: []api.Message{
{Role: "user", Content: "Qu'est-ce que la mémoïsation et quand est-elle utile ?"},
},
}
var resp api.ChatResponse
if err := client.Chat(ctx, req, &resp); err != nil {
return err
}
// Si vous souhaitez cacher la réflexion, faites-le ici indépendamment des drapeaux.
if resp.Message.Thinking != "" {
fmt.Println("🧠 réflexion:\n", resp.Message.Thinking)
}
fmt.Println("\n💬 réponse:\n", resp.Message.Content)
return nil
}
Génération — Qwen3 & GPT-OSS
func generateWithQwen3(ctx context.Context) error {
client, err := api.ClientFromEnvironment()
if err != nil {
return err
}
req := &api.GenerateRequest{
Model: "qwen3:4b-thinking",
Prompt: "Résumez le rôle d'un arbre B dans l'indexation.",
Think: api.Ptr(true),
}
var resp api.GenerateResponse
if err := client.Generate(ctx, req, &resp); err != nil {
return err
}
if resp.Thinking != "" {
fmt.Println("🧠 réflexion:\n", resp.Thinking)
}
fmt.Println("\n💬 réponse:\n", resp.Response)
return nil
}
func generateWithGptOss(ctx context.Context) error {
client, err := api.ClientFromEnvironment()
if err != nil {
return err
}
req := &api.GenerateRequest{
Model: "gpt-oss:20b",
Prompt: "Expliquez la descente de gradient en termes simples.",
Think: api.Ptr(true),
}
var resp api.GenerateResponse
if err := client.Generate(ctx, req, &resp); err != nil {
return err
}
if resp.Thinking != "" {
fmt.Println("🧠 réflexion:\n", resp.Thinking)
}
fmt.Println("\n💬 réponse:\n", resp.Response)
return nil
}
La surface du package officiel miroire les documents REST et est mise à jour en parallèle avec le projet principal.
Réponses en streaming
Pour les réponses en temps réel, définissez Stream: bptr(true) dans votre demande. La réponse sera livrée comme des morceaux JSON délimités par des nouvelles lignes :
func streamChatExample() error {
endpoint := "http://localhost:11434/api/chat"
req := ChatRequest{
Model: "qwen3:8b-thinking",
Think: bptr(true),
Stream: bptr(true), // Activer le streaming
Messages: []ChatMessage{
{Role: "user", Content: "Expliquez l'algorithme de tri rapide étape par étape."},
},
}
body, _ := json.Marshal(req)
resp, err := http.Post(endpoint, "application/json", bytes.NewReader(body))
if err != nil {
return err
}
defer resp.Body.Close()
decoder := json.NewDecoder(resp.Body)
for {
var chunk ChatResponse
if err := decoder.Decode(&chunk); err == io.EOF {
break
} else if err != nil {
return err
}
// Traiter la réflexion et le contenu à mesure de leur arrivée
if chunk.Message.Thinking != "" {
fmt.Print(chunk.Message.Thinking)
}
fmt.Print(chunk.Message.Content)
if chunk.Done {
break
}
}
return nil
}
Avec le SDK officiel, utilisez une fonction de rappel pour gérer les morceaux de streaming :
func streamWithOfficialSDK(ctx context.Context) error {
client, _ := api.ClientFromEnvironment()
req := &api.ChatRequest{
Model: "qwen3:8b-thinking",
Think: api.Ptr(true),
Messages: []api.Message{
{Role: "user", Content: "Expliquez les arbres de recherche binaire."},
},
}
err := client.Chat(ctx, req, func(resp api.ChatResponse) error {
if resp.Message.Thinking != "" {
fmt.Print(resp.Message.Thinking)
}
fmt.Print(resp.Message.Content)
return nil
})
return err
}
Travail avec Qwen3 réflexion vs non-réflexion (guidance pratique)
-
Deux leviers :
- Un drapeau booléen
thinkingsupporté par la fonctionnalité de réflexion d’Ollama ; et - Les commandes de commutation douce de Qwen3
/thinket/no_thinkdans le message système/utilisateur le plus récent. L’instruction la plus récente gouverne le prochain tour(s).
- Un drapeau booléen
-
Posture par défaut : non-réflexion pour les réponses rapides ; passer à réflexion pour les tâches nécessitant une réflexion étape par étape (math, planification, débogage, analyse complexe de code).
-
Interfaces utilisateur en streaming : lorsque la réflexion est activée, vous pouvez voir des raisonnements/contenu intercalés dans les cadres en streaming — tamponnez ou affichez-les séparément et donnez aux utilisateurs un commutateur « afficher le raisonnement ». (Voir les documents de l’API pour le format de streaming.)
-
Conversations multi-tours : Qwen3 se souvient du mode de réflexion des tours précédents. Si vous souhaitez basculer au milieu d’une conversation, utilisez à la fois le drapeau et la commande de commutation douce pour une fiabilité accrue.
Notes pour GPT-OSS
- Traitez la réflexion comme présente même si vous avez essayé de la désactiver ; filtrez côté client si votre interface utilisateur ne doit pas l’afficher.
- Pour les applications de production utilisant GPT-OSS, implémentez une logique de filtrage côté client capable de détecter et d’éliminer les motifs de réflexion si nécessaire.
- Testez soigneusement votre variante spécifique de modèle GPT-OSS, car le comportement peut varier entre différentes quantifications et versions.
Bonnes pratiques et conseils de production
Gestion des erreurs et des délais
Implémentez toujours une gestion appropriée des délais et de la récupération d’erreurs :
func robustChatRequest(ctx context.Context, model string, messages []api.Message) (*api.ChatResponse, error) {
// Définissez un délai raisonnable
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
client, err := api.ClientFromEnvironment()
if err != nil {
return nil, fmt.Errorf("création du client : %w", err)
}
req := &api.ChatRequest{
Model: model,
Messages: messages,
Options: map[string]interface{}{
"temperature": 0.7,
"num_ctx": 4096, // taille de la fenêtre de contexte
},
}
var resp api.ChatResponse
if err := client.Chat(ctx, req, &resp); err != nil {
return nil, fmt.Errorf("requête de chat échouée : %w", err)
}
return &resp, nil
}
Gestion des connexions et réutilisation
Réutilisez le client Ollama entre les requêtes au lieu de créer un nouveau client à chaque fois :
type OllamaService struct {
client *api.Client
}
func NewOllamaService() (*OllamaService, error) {
client, err := api.ClientFromEnvironment()
if err != nil {
return nil, err
}
return &OllamaService{client: client}, nil
}
func (s *OllamaService) Chat(ctx context.Context, req *api.ChatRequest) (*api.ChatResponse, error) {
var resp api.ChatResponse
if err := s.client.Chat(ctx, req, &resp); err != nil {
return nil, err
}
return &resp, nil
}
Configuration de l’environnement
Utilisez des variables d’environnement pour une déploiement flexible :
export OLLAMA_HOST=http://localhost:11434
export OLLAMA_NUM_PARALLEL=2
export OLLAMA_MAX_LOADED_MODELS=2
Le SDK officiel respecte automatiquement OLLAMA_HOST via api.ClientFromEnvironment().
Surveillance et journalisation
Implémentez une journalisation structurée pour les systèmes de production :
func loggedChat(ctx context.Context, logger *log.Logger, req *api.ChatRequest) error {
start := time.Now()
client, _ := api.ClientFromEnvironment()
var resp api.ChatResponse
err := client.Chat(ctx, req, &resp)
duration := time.Since(start)
logger.Printf("model=%s duration=%v error=%v tokens=%d",
req.Model, duration, err, len(resp.Message.Content))
return err
}
Conclusion
-
Pour les projets Go,
github.com/ollama/ollama/apiest le choix le plus complet et prêt pour la production. Il est maintenu en parallèle avec le projet principal Ollama, utilisé par le CLI officiel, et fournit une couverture complète de l’API avec une compatibilité garantie. -
Pour les abstractions de niveau supérieur, envisagez LangChainGo lorsque vous avez besoin de chaînes, d’outils, de magasins vectoriels et de pipelines RAG — bien que vous deviez sacrifier un peu de contrôle de bas niveau pour la commodité.
-
Qwen3 vous donne un contrôle propre et fiable sur le mode de réflexion à la fois avec des drapeaux et des commutateurs au niveau du message (
/think,/no_think), ce qui le rend idéal pour les applications nécessitant à la fois des réponses rapides et une réflexion approfondie. -
Pour GPT-OSS, planifiez toujours de nettoyer la sortie de réflexion côté client lorsqu’il est nécessaire, car le drapeau de désactivation de la réflexion peut ne pas être respecté de manière cohérente.
-
En production, implémentez une gestion correcte des erreurs, une réutilisation des connexions, des délais et de la surveillance pour construire des applications Ollama-powered robustes.
La combinaison de la forte typage de Go, du bon support de concurrence et de l’API directe d’Ollama en fait un stack idéal pour construire des applications alimentées par l’IA — des chatbots simples aux systèmes RAG complexes.
Points clés
Voici un résumé rapide pour choisir votre approche :
| Cas d’utilisation | Approche recommandée | Pourquoi |
|---|---|---|
| Application en production | github.com/ollama/ollama/api |
Support officiel, couverture complète de l’API, maintenu avec le projet principal |
| Pipeline de chaînes/outils/magasin vectoriel | LangChainGo | Abstractions de haut niveau, intégrations avec les magasins vectoriels |
| Apprendre/expérimenter | REST brut avec net/http | Transparence totale, pas de dépendances, éducatif |
| Prototypage rapide | SDK officiel | Équilibre entre simplicité et puissance |
| Interface utilisateur de chat en streaming | SDK officiel avec rappels | Support de streaming intégré, API propre |
Conseils de sélection des modèles :
- Qwen3 : Meilleur pour les applications nécessitant un contrôle du mode de réflexion, des conversations multi-tours fiables
- GPT-OSS : Bonne performance mais nécessite un traitement défensif de la sortie de réflexion/raisonnement
- Autres modèles : Testez soigneusement ; le comportement de réflexion varie selon la famille de modèles
Références et lecture supplémentaire
Documentation officielle
- Référence API Ollama — Documentation complète de l’API REST
- Package Go officiel Ollama — Documentation du SDK Go
- Dépôt GitHub Ollama — Code source et problèmes
Alternatives SDK Go
- Intégration Ollama de LangChainGo — Pour les applications basées sur les chaînes
- swdunlop/ollama-client — Client communautaire avec appel d’outils
- xyproto/ollamaclient — Autre option communautaire
Ressources spécifiques aux modèles
- Documentation Qwen — Informations officielles sur les modèles Qwen
- Informations sur GPT-OSS — Détails sur les modèles GPT-OSS
Sujets connexes
- Création d’applications RAG avec Go — Exemples de LangChainGo
- Package Go context — Essentiel pour les délais et l’annulation
- Meilleures pratiques pour le client HTTP Go — Documentation de la bibliothèque standard
Liens utiles
Pour une comparaison plus large d’Ollama avec d’autres infrastructures LLM locales et en nuage, consultez notre LLM Hosting : Comparaison de l’hébergement local, auto-hébergé et cloud.
- Installer et configurer Ollama
- Feuille de triche Ollama
- Feuille de triche Go
- Réclassification de documents texte avec Ollama et modèle d’embedding Qwen3 - en Go
- Contrainte des LLM avec Sortie Structurée : Ollama, Qwen3 & Python ou Go
- Comparaison des LLM : Qwen3:30b vs GPT-OSS:20b
- Problèmes de sortie structurée d’Ollama GPT-OSS