Go-clients voor Ollama: SDK-vergelijking en Qwen3/GPT-OSS-voorbeelden
Integreer Ollama met Go: SDK-handboek, voorbeelden en productiebest practices.
Deze gids biedt een uitgebreid overzicht van beschikbare Go SDKs voor Ollama en vergelijkt hun functionaliteiten.
We zullen praktische Go-voorbeelden bespreken voor het aanroepen van Qwen3 en GPT-OSS-modellen die worden gehost op Ollama—zowel via ruwe REST API-aanroepen als de officiële Go-client—waaronder gedetailleerde behandeling van denk- en niet-denkmodes in Qwen3.
Waarom Ollama + Go?
Ollama biedt een klein, pragmatisch HTTP API (meestal draaiend op http://localhost:11434
) die is ontworpen voor genereren en chatten-taken, met ingebouwde ondersteuning voor streaming en modelbeheer. De officiële documentatie bespreekt uitgebreid de /api/generate
en /api/chat
aanvraag/antwoordstructuren en streamingsemantiek.
Go is een uitstekende keuze voor het bouwen van Ollama-clients vanwege de sterke ondersteuning van de standaardbibliotheek voor HTTP, uitstekende JSON-verwerking, native concurrentieprimitieven en statisch getypeerde interfaces die fouten op tijd van compilatie detecteren.
Tot oktober 2025 zijn hier de Go SDK-opties die je waarschijnlijk zult overwegen.
Go SDKs voor Ollama — wat is beschikbaar?
SDK / Package | Status & “eigenaar” | Scope (Generate/Chat/Streaming) | Model mgmt (pull/list/etc.) | Extras / Notes |
---|---|---|---|---|
github.com/ollama/ollama/api |
Officiële package binnen de Ollama-repo; gebruikt door de ollama CLI zelf |
Volledige coverage gemapt op REST; streaming ondersteund | Ja | Wordt beschouwd als de kanonieke Go-client; API spiegelt documentatie nauwkeurig. |
LangChainGo (github.com/tmc/langchaingo/llms/ollama ) |
Community framework (LangChainGo) met Ollama LLM-module | Chat/Completion + streaming via frameworkabstrakties | Beperkt (modelbeheer is geen primaire doelstelling) | Prima als je ketens, tools, vectoropslag in Go wilt; minder van een ruwe SDK. |
github.com/swdunlop/ollama-client |
Community client | Focus op chat; goede tool-calling experimenten | Deelgeldig | Gemaakt voor het experimenteren met toolcalling; geen 1:1 volledige oppervlakte. |
Andere community SDKs (bijv. ollamaclient , derde partij “go-ollama-sdk”) |
Community | Varieert | Varieert | Kwaliteit en coverage varieert; beoordeel per repo. |
Aanbeveling: Voor productie, voorkeur geven aan github.com/ollama/ollama/api
—het wordt onderhouden met het kernproject en spiegelt de REST API nauwkeurig.
Qwen3 & GPT-OSS op Ollama: denken vs niet-denken (wat je moet weten)
- Denkmodus in Ollama schept een scheiding tussen de model’s “redenering” en het eindresultaat wanneer deze is ingeschakeld. Ollama documenteert een eerste klasse aanzetten/uitzetten van denken gedrag over de ondersteunde modellen.
- (https://www.glukhov.org/nl/post/2025/10/qwen3-30b-vs-gpt-oss-20b/ “Qwen3:30b vs GPT-OSS:20b: Technische details, prestaties en snelheid vergelijking”) ondersteunt dynamisch schakelen: voeg
/think
of/no_think
toe in systeem/gebruikersberichten om modi te schakelen per beurt; de nieuwste instructie wint. - GPT-OSS: gebruikers melden dat uitzetten van denken (bijv.
/set nothink
of--think=false
) onbetrouwbaar kan zijn opgpt-oss:20b
; plan om filteren/verbergen van elke redenering die je UI niet moet tonen.
Deel 1 — Ollama aanroepen via ruwe REST (Go, net/http)
Gedeelde types
Eerst definiëren we de algemene types en helperfuncties die we overal in onze voorbeelden zullen gebruiken:
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
// ---- Chat API Types ----
type ChatMessage struct {
Role string `json:"role"`
Content string `json:"content"`
}
type ChatRequest struct {
Model string `json:"model"`
Messages []ChatMessage `json:"messages"`
// Sommige servers tonen denkcontrole als een boolean vlag.
// Zelfs als deze wordt overgeslagen, kun je Qwen3 nog steeds beïnvloeden via /think of /no_think tags.
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"` // aanwezig wanneer denken is ingeschakeld
} `json:"message"`
Done bool `json:"done"`
}
// ---- Generate API Types ----
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"` // eindtekst voor niet-stream
Thinking string `json:"thinking,omitempty"` // aanwezig wanneer denken is ingeschakeld
Done bool `json:"done"`
}
// ---- Helper Functions ----
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 retourneert een pointer naar een booleanwaarde
func bptr(b bool) *bool { return &b }
Chat — Qwen3 met denken AAN (en hoe je het UIT kan zetten)
func chatQwen3Thinking() error {
endpoint := "http://localhost:11434/api/chat"
req := ChatRequest{
Model: "qwen3:8b-thinking", // elke :*-thinking tag die je hebt getrokken
Think: bptr(true),
Stream: bptr(false),
Messages: []ChatMessage{
{Role: "system", Content: "Je bent een nauwkeurige assistent."},
{Role: "user", Content: "Leg recursie uit met een korte Go-voorbeeld."},
},
}
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("🧠 denken:\n", out.Message.Thinking)
fmt.Println("\n💬 antwoord:\n", out.Message.Content)
return nil
}
// Zet denken UIT voor de volgende beurt door:
// (a) Think=false instellen, en/of
// (b) "/no_think" toevoegen aan de meest recente systeem/gebruikersbericht (Qwen3 zachte schakelaar).
// Qwen3 respecteert de laatste /think of /no_think instructie in meervoudige chats.
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: "Je bent kort. /no_think"},
{Role: "user", Content: "Leg recursie in één zin uit."},
},
}
raw, err := httpPostJSON(endpoint, req)
if err != nil {
return err
}
var out ChatResponse
if err := json.Unmarshal(raw, &out); err != nil {
return err
}
// Verwacht dat denken leeg is; behandel toch voorzichtig.
if out.Message.Thinking != "" {
fmt.Println("🧠 denken (onverwacht):\n", out.Message.Thinking)
}
fmt.Println("\n💬 antwoord:\n", out.Message.Content)
return nil
}
(Qwen3’s /think
en /no_think
zachte schakelaar is gedocumenteerd door de Qwen-team; de laatste instructie wint in meervoudige chats.)
Chat — GPT-OSS met denken (en een opmerking)
func chatGptOss() error {
endpoint := "http://localhost:11434/api/chat"
req := ChatRequest{
Model: "gpt-oss:20b",
Think: bptr(true), // verzoek gescheiden redenering als ondersteund
Stream: bptr(false),
Messages: []ChatMessage{
{Role: "user", Content: "Wat is dynamisch programmeren? Leg het kernidee uit."},
},
}
raw, err := httpPostJSON(endpoint, req)
if err != nil {
return err
}
var out ChatResponse
if err := json.Unmarshal(raw, &out); err != nil {
return err
}
// Bekende kluif: uitschakelen van denken kan niet volledig onderdrukken redenering op gpt-oss:20b.
// Filter altijd/verberg denken in UI als je het niet wilt tonen.
fmt.Println("🧠 denken:\n", out.Message.Thinking)
fmt.Println("\n💬 antwoord:\n", out.Message.Content)
return nil
}
Gebruikers melden dat uitschakelen van denken op gpt-oss:20b (bijv. /set nothink
of --think=false
) kan worden genegeerd—plan voor clientzijde filtering als nodig is.
Generate — Qwen3 en GPT-OSS
func generateQwen3() error {
endpoint := "http://localhost:11434/api/generate"
req := GenerateRequest{
Model: "qwen3:4b-thinking",
Prompt: "In 2–3 zinnen, wat zijn B-Bomen gebruikt voor in databases?",
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("🧠 denken:\n", out.Thinking)
}
fmt.Println("\n💬 antwoord:\n", out.Response)
return nil
}
func generateGptOss() error {
endpoint := "http://localhost:11434/api/generate"
req := GenerateRequest{
Model: "gpt-oss:20b",
Prompt: "Leg backpropagation in neurale netwerken kort uit.",
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("🧠 denken:\n", out.Thinking)
}
fmt.Println("\n💬 antwoord:\n", out.Response)
return nil
}
REST vormen en streaminggedrag komen rechtstreeks van de Ollama API-verwijzing.
Deel 2 — Ollama aanroepen via de officiële Go SDK (github.com/ollama/ollama/api
)
Het officiële pakket biedt een Client
met methoden die overeenkomen met de REST API. De Ollama CLI zelf gebruikt dit pakket om met de service te communiceren, wat het veiligste keuze is voor compatibiliteit.
Installatie
go get github.com/ollama/ollama/api
Chat — Qwen3 (denken AAN / UIT)
package main
import (
"context"
"fmt"
"log"
"github.com/ollama/ollama/api"
)
func chatWithQwen3Thinking(ctx context.Context, thinking bool) error {
client, err := api.ClientFromEnvironment() // respecteert OLLAMA_HOST als ingesteld
if err != nil {
return err
}
req := &api.ChatRequest{
Model: "qwen3:8b-thinking",
// Veel serverbouwen tonen denken als een topniveau vlag;
// bovendien kun je Qwen3 beïnvloeden via /think of /no_think in berichten.
Think: api.Ptr(thinking),
Messages: []api.Message{
{Role: "system", Content: "Je bent een nauwkeurige assistent."},
{Role: "user", Content: "Leg mergesort uit met een korte Go-snippet."},
},
}
var resp api.ChatResponse
if err := client.Chat(ctx, req, &resp); err != nil {
return err
}
if resp.Message.Thinking != "" {
fmt.Println("🧠 denken:\n", resp.Message.Thinking)
}
fmt.Println("\n💬 antwoord:\n", resp.Message.Content)
return nil
}
func main() {
ctx := context.Background()
if err := chatWithQwen3Thinking(ctx, true); err != nil {
log.Fatal(err)
}
// Voorbeeld: niet-denken
if err := chatWithQwen3Thinking(ctx, false); err != nil {
log.Fatal(err)
}
}
Chat — GPT-OSS (redenering defensief behandelen)
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: "Wat is memoisatie en wanneer is het nuttig?"},
},
}
var resp api.ChatResponse
if err := client.Chat(ctx, req, &resp); err != nil {
return err
}
// Als je redenering wilt verbergen, doe het hier ongeacht vlaggen.
if resp.Message.Thinking != "" {
fmt.Println("🧠 denken:\n", resp.Message.Thinking)
}
fmt.Println("\n💬 antwoord:\n", resp.Message.Content)
return nil
}
Generate — 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: "Samenvat de rol van een B-Boom in indexering.",
Think: api.Ptr(true),
}
var resp api.GenerateResponse
if err := client.Generate(ctx, req, &resp); err != nil {
return err
}
if resp.Thinking != "" {
fmt.Println("🧠 denken:\n", resp.Thinking)
}
fmt.Println("\n💬 antwoord:\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: "Leg gradient descent in eenvoudige termen uit.",
Think: api.Ptr(true),
}
var resp api.GenerateResponse
if err := client.Generate(ctx, req, &resp); err != nil {
return err
}
if resp.Thinking != "" {
fmt.Println("🧠 denken:\n", resp.Thinking)
}
fmt.Println("\n💬 antwoord:\n", resp.Response)
return nil
}
Het oppervlak van het officiële pakket spiegelt de REST-documentatie en wordt bijgewerkt met het kernproject.
Streaming responses
Voor real-time streaming, stel Stream: bptr(true)
in in je aanvraag. Het antwoord wordt geleverd als newline-delimited JSON chunks:
func streamChatExample() error {
endpoint := "http://localhost:11434/api/chat"
req := ChatRequest{
Model: "qwen3:8b-thinking",
Think: bptr(true),
Stream: bptr(true), // Streaming inschakelen
Messages: []ChatMessage{
{Role: "user", Content: "Leg de quicksort algoritme stap voor stap uit."},
},
}
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
}
// Verwerk denken en inhoud terwijl ze aankomen
if chunk.Message.Thinking != "" {
fmt.Print(chunk.Message.Thinking)
}
fmt.Print(chunk.Message.Content)
if chunk.Done {
break
}
}
return nil
}
Met de officiële SDK, gebruik een callbackfunctie om streamingchunks te verwerken:
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: "Leg binaire zoekbomen uit."},
},
}
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
}
Werken met Qwen3 denken vs niet-denken (praktische richtlijnen)
-
Twee koppels:
- Een boolean
denken
vlag ondersteund door Ollama’s denkfunctie; en - Qwen3’s zachte schakelaar commando’s
/think
en/no_think
in de nieuwste systeem/gebruikersbericht. De meest recente instructie beheerst de volgende beurt(en).
- Een boolean
-
Standaard houding: niet-denken voor snelle antwoorden; verhoog naar denken voor taken die stap-voor-stap redenering vereisen (wiskunde, planning, debuggen, complexe codeanalyse).
-
Streaming UI’s: wanneer denken is ingeschakeld, zie je mogelijk door elkaar lopende redenering/inhoud in gestreamde frames—buffer of render ze apart en geef gebruikers een “toon redenering” schakelaar. (Zie API-documentatie voor streamingformaat.)
-
Meervoudige gesprekken: Qwen3 onthoudt de denkmodus van vorige beurten. Als je deze midden in een gesprek wilt schakelen, gebruik zowel de vlag als de zachte schakelaarcommando voor betrouwbaarheid.
Opmerkingen voor GPT-OSS
- Behandel redenering als aanwezig zelfs als je het probeert uit te schakelen; filter op de client als je UX het niet moet tonen.
- Voor productieapplicaties die GPT-OSS gebruiken, implementeer clientzijde filteringlogica die kan detecteren en verwijderen van redeneringspatronen als nodig is.
- Test je specifieke GPT-OSS modelvariant grondig, omdat gedrag kan variëren tussen verschillende kwantificaties en versies.
Best practices en productietips
Foutafhandeling en time-outs
Implementeer altijd correcte time-outafhandeling en foutherstel:
func robustChatRequest(ctx context.Context, model string, messages []api.Message) (*api.ChatResponse, error) {
// Stel een redelijke time-out in
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
client, err := api.ClientFromEnvironment()
if err != nil {
return nil, fmt.Errorf("client aanmaken: %w", err)
}
req := &api.ChatRequest{
Model: model,
Messages: messages,
Options: map[string]interface{}{
"temperature": 0.7,
"num_ctx": 4096, // contextwindowgrootte
},
}
var resp api.ChatResponse
if err := client.Chat(ctx, req, &resp); err != nil {
return nil, fmt.Errorf("chat aanvraag mislukt: %w", err)
}
return &resp, nil
}
Verbindingspoolen en hergebruik
Hergebruik de Ollama-client over meerdere aanvragen in plaats van elke keer een nieuwe aan te maken:
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
}
Omgevingsconfiguratie
Gebruik omgevingsvariabelen voor flexibele implementatie:
export OLLAMA_HOST=http://localhost:11434
export OLLAMA_NUM_PARALLEL=2
export OLLAMA_MAX_LOADED_MODELS=2
De officiële SDK respecteert automatisch OLLAMA_HOST
via api.ClientFromEnvironment()
.
Monitoring en logboekregistratie
Implementeer gestructureerde logboekregistratie voor productiesystemen:
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
}
Conclusie
-
Voor Go-projecten,
github.com/ollama/ollama/api
is de meest volledige, productie-geoorloofde keuze. Het wordt onderhouden met het Ollama-kernproject, gebruikt door de officiële CLI en biedt uitgebreide API-coverage met gegarandeerde compatibiliteit. -
Voor hogere niveau abstrakties, overweeg LangChainGo wanneer je ketens, tools, vectoropslag en RAG-pijplijnen nodig hebt—hoewel je dan enige lage niveau controle moet opofferen voor handigheid.
-
Qwen3 geeft je schone, betrouwbare controle over denkmodus met zowel vlaggen als berichtniveau schakelaars (
/think
,/no_think
), waardoor het ideaal is voor toepassingen die zowel snelle antwoorden als diepe redenering nodig hebben. -
Voor GPT-OSS, plan altijd om verwerking van redenering clientzijde te doen wanneer nodig, aangezien de denkuitgeschakeld vlag mogelijk niet consistent wordt gevolgd.
-
In productie, implementeer correcte foutafhandeling, verbindingspoolen, time-outs en monitoring om robuuste Ollama-aangedreven toepassingen te bouwen.
De combinatie van Go’s sterke typen, uitstekende ondersteuning voor concurrentie en Ollama’s eenvoudige API maakt het een ideaal stack voor het bouwen van AI-aangedreven toepassingen—van eenvoudige chatbots tot complexe RAG-systemen.
Belangrijkste conclusies
Hier is een snelle verwijzing voor het kiezen van je aanpak:
Gebruikgeval | Aanbevolen aanpak | Waarom |
---|---|---|
Productietoepassing | github.com/ollama/ollama/api |
Officiële ondersteuning, volledige API-coverage, onderhouden met kernproject |
RAG/ketens/tools pijplijn | LangChainGo | Hogere niveau abstrakties, integraties met vectoropslag |
Leren/experimenteren | Ruwe REST met net/http | Volledige transparantie, geen afhankelijkheden, educatief |
Snel prototyperen | Officiële SDK | Evenwicht tussen eenvoud en kracht |
Streaming chat UI | Officiële SDK met callbacks | Ingebouwde streamingondersteuning, nette API |
Modelkeuze richtlijnen:
- Qwen3: Beste voor toepassingen die een controleerbare denkmodus vereisen, betrouwbare meervoudige gesprekken
- GPT-OSS: Sterke prestaties maar vereist defensieve afhandeling van denk/redenering uitvoer
- Andere modellen: Test grondig; denkgedrag varieert per modelfamilie
Referenties & verdere lezing
Officiële documentatie
- Ollama API referentie — Volledige REST API-documentatie
- Officiële Ollama Go-pakket — Go SDK-documentatie
- Ollama GitHub-repository — Broncode en problemen
Alternatieven voor de Go SDK
- LangChainGo Ollama-integratie — Voor toepassingen op basis van keten
- swdunlop/ollama-client — Community-client met tool-aanroep
- xyproto/ollamaclient — Een andere community-optie
Modelspecifieke bronnen
- Qwen documentatie — Officiële Qwen-modelinformatie
- GPT-OSS informatie — GPT-OSS-modeldetails
Gerelateerde onderwerpen
- RAG-toepassingen bouwen met Go — LangChainGo-voorbeelden
- Go context-pakket — Essentieel voor time-outs en annulering
- Go HTTP-client best practices — Documentatie van de standaardbibliotheek
Andere nuttige links
- Installeer en configureer Ollama
- Ollama cheat sheet
- Go cheat sheet
- Hoe Ollama parallelle aanvragen verwerkt
- Herordenen van tekstdocumenten met Ollama en Qwen3 Embedding-model — in Go
- Vergelijking van Go-ORMs voor PostgreSQL: GORM vs Ent vs Bun vs sqlc
- Beperken van LLMs met gestructureerde uitvoer: Ollama, Qwen3 & Python of Go
- Gebruik van Ollama in Python-code
- LLM-vergelijking: Qwen3:30b vs GPT-OSS:20b
- Ollama GPT-OSS Structured Output Issues