Klien Go untuk Ollama: Perbandingan SDK dan contoh Qwen3/GPT-OSS
Integrasi Ollama dengan Go: Panduan SDK, contoh, dan praktik terbaik untuk produksi.
Panduan ini memberikan gambaran menyeluruh tentang SDK Go untuk Ollama yang tersedia dan membandingkan set fitur mereka.
Kita akan menjelajahi contoh praktis Go untuk memanggil model Qwen3 dan GPT-OSS yang berjalan di Ollama—baik melalui raw REST API calls dan official Go client—termasuk penanganan rinci dari mode thinking dan non-thinking di Qwen3.
Mengapa Ollama + Go?
Ollama mengekspos sebuah API HTTP kecil yang pragmatis (biasanya berjalan di http://localhost:11434
) yang dirancang untuk beban kerja generate dan chat, dengan dukungan streaming bawaan dan kemampuan manajemen model. Dokumentasi resmi secara menyeluruh menuturkan struktur permintaan/ respons /api/generate
dan /api/chat
serta semantik streaming.
Go adalah pilihan yang sangat baik untuk membangun klien Ollama karena dukungan library standar yang kuat untuk HTTP, penanganan JSON yang sangat baik, primitif konkurensi bawaan, dan antarmuka bertipe statis yang menangkap kesalahan saat kompilasi.
Sejak Oktober 2025, berikut adalah pilihan SDK Go yang paling mungkin Anda pertimbangkan.
SDK Go untuk Ollama — apa yang tersedia?
SDK / Package | Status & “owner” | Lingkup (Generate/Chat/Streaming) | Manajemen model (pull/list/etc.) | Ekstra / Catatan |
---|---|---|---|---|
github.com/ollama/ollama/api |
Resmi package di dalam repo Ollama; digunakan oleh CLI ollama itu sendiri |
Lengkap penuturan yang dipetakan ke REST; streaming didukung | Ya | Dianggap sebagai kanonik klien Go; API meniru dokumentasi secara dekat. |
LangChainGo (github.com/tmc/langchaingo/llms/ollama ) |
Kerangka komunitas (LangChainGo) dengan modul LLM Ollama | Chat/Completion + streaming melalui abstraksi kerangka | Terbatas (manajemen model bukan tujuan utama) | Bagus jika Anda ingin rantai, alat, penyimpanan vektor dalam Go; kurang dari SDK mentah. |
github.com/swdunlop/ollama-client |
Klien komunitas | Fokus pada chat; eksperimen tool-calling yang baik | Parsial | Dibangun untuk eksperimen dengan pemanggilan alat; bukan permukaan penuh 1:1. |
SDK komunitas lainnya (misalnya, ollamaclient , SDK pihak ketiga “go-ollama-sdk”) |
Komunitas | Beragam | Beragam | Kualitas dan cakupan bervariasi; evaluasi per repo. |
Rekomendasi: Untuk produksi, pilih github.com/ollama/ollama/api
—dikelola bersama proyek inti dan meniru API REST.
Qwen3 & GPT-OSS di Ollama: thinking vs non-thinking (apa yang perlu diketahui)
- Mode thinking di Ollama memisahkan “penalaran” model dari output akhir ketika diaktifkan. Ollama mendokumentasikan perilaku aktif/non-aktif thinking sebagai fitur kelas satu di seluruh model yang didukung.
- (https://www.glukhov.org/id/post/2025/10/qwen3-30b-vs-gpt-oss-20b/ “Qwen3:30b vs GPT-OSS:20b: Detail teknis, perbandingan kinerja dan kecepatan”) mendukung toggle dinamis: tambahkan
/think
atau/no_think
dalam pesan sistem/pengguna untuk beralih mode secara berulang; instruksi terbaru menang. - GPT-OSS: pengguna melaporkan bahwa menonaktifkan thinking (misalnya,
/set nothink
atau--think=false
) bisa tidak andal padagpt-oss:20b
; rencanakan untuk menyaring/menghilangkan setiap penalaran yang tidak boleh ditampilkan UI Anda.
Bagian 1 — Memanggil Ollama melalui raw REST (Go, net/http)
Tipe yang dibagi
Pertama, mari kita definisikan tipe umum dan fungsi bantu yang akan kita gunakan di seluruh contoh kita:
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
// ---- Tipe API Chat ----
type ChatMessage struct {
Role string `json:"role"`
Content string `json:"content"`
}
type ChatRequest struct {
Model string `json:"model"`
Messages []ChatMessage `json:"messages"`
// Beberapa server mengekspos kontrol thinking sebagai bendera boolean.
// Bahkan jika dihilangkan, Anda masih dapat mengontrol Qwen3 melalui /think atau /no_think tag.
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"` // hadir ketika thinking diaktifkan
} `json:"message"`
Done bool `json:"done"`
}
// ---- Tipe API Generate ----
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"` // teks akhir untuk non-stream
Thinking string `json:"thinking,omitempty"` // hadir ketika thinking diaktifkan
Done bool `json:"done"`
}
// ---- Fungsi Bantu ----
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 mengembalikan pointer ke nilai boolean
func bptr(b bool) *bool { return &b }
Chat — Qwen3 dengan thinking ON (dan cara mematikannya)
func chatQwen3Thinking() error {
endpoint := "http://localhost:11434/api/chat"
req := ChatRequest{
Model: "qwen3:8b-thinking", // tag :*-thinking apa pun yang telah Anda unduh
Think: bptr(true),
Stream: bptr(false),
Messages: []ChatMessage{
{Role: "system", Content: "Anda adalah asisten yang presisi."},
{Role: "user", Content: "Jelaskan rekursi dengan contoh pendek 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("🧠 thinking:\n", out.Message.Thinking)
fmt.Println("\n💬 jawaban:\n", out.Message.Content)
return nil
}
// Matikan thinking untuk putaran berikutnya dengan:
// (a) mengatur Think=false, dan/atau
// (b) menambahkan "/no_think" ke pesan sistem/pengguna terbaru (Qwen3 switch lembut).
// Qwen3 menghormati instruksi /think atau /no_think terbaru dalam percakapan multi-putaran.
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: "Anda ringkas. /no_think"},
{Role: "user", Content: "Jelaskan rekursi dalam satu kalimat."},
},
}
raw, err := httpPostJSON(endpoint, req)
if err != nil {
return err
}
var out ChatResponse
if err := json.Unmarshal(raw, &out); err != nil {
return err
}
// Harapkan thinking untuk kosong; tetap tangani secara defensif.
if out.Message.Thinking != "" {
fmt.Println("🧠 thinking (tidak diharapkan):\n", out.Message.Thinking)
}
fmt.Println("\n💬 jawaban:\n", out.Message.Content)
return nil
}
(Switch lembut Qwen3 /think
dan /no_think
didokumentasikan oleh tim Qwen; instruksi terakhir menang dalam percakapan multi-putaran.)
Chat — GPT-OSS dengan thinking (dan catatan)
func chatGptOss() error {
endpoint := "http://localhost:11434/api/chat"
req := ChatRequest{
Model: "gpt-oss:20b",
Think: bptr(true), // minta pemisahan penalaran jika didukung
Stream: bptr(false),
Messages: []ChatMessage{
{Role: "user", Content: "Apa itu pemrograman dinamis? Jelaskan ide intinya."},
},
}
raw, err := httpPostJSON(endpoint, req)
if err != nil {
return err
}
var out ChatResponse
if err := json.Unmarshal(raw, &out); err != nil {
return err
}
// Catatan yang diketahui: menonaktifkan thinking mungkin tidak sepenuhnya menghambat penalaran pada gpt-oss:20b.
// Selalu saring/hilangkan thinking dalam UI jika Anda tidak ingin menampilkan hal itu.
fmt.Println("🧠 thinking:\n", out.Message.Thinking)
fmt.Println("\n💬 jawaban:\n", out.Message.Content)
return nil
}
Pengguna melaporkan bahwa menonaktifkan thinking pada gpt-oss:20b (misalnya, /set nothink
atau --think=false
) dapat diabaikan—rencanakan untuk penyaringan sisi klien jika diperlukan.
Generate — Qwen3 dan GPT-OSS
func generateQwen3() error {
endpoint := "http://localhost:11434/api/generate"
req := GenerateRequest{
Model: "qwen3:4b-thinking",
Prompt: "Dalam 2–3 kalimat, apa yang digunakan B-Trees dalam basis data?",
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("🧠 thinking:\n", out.Thinking)
}
fmt.Println("\n💬 jawaban:\n", out.Response)
return nil
}
func generateGptOss() error {
endpoint := "http://localhost:11434/api/generate"
req := GenerateRequest{
Model: "gpt-oss:20b",
Prompt: "Jelaskan secara singkat backpropagation dalam jaringan saraf.",
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("🧠 thinking:\n", out.Thinking)
}
fmt.Println("\n💬 jawaban:\n", out.Response)
return nil
}
Bentuk REST dan perilaku streaming berasal langsung dari referensi API Ollama.
Bagian 2 — Memanggil Ollama melalui SDK Go resmi (github.com/ollama/ollama/api
)
Paket resmi mengekspos sebuah Client
dengan metode yang sesuai dengan API REST. CLI Ollama itu sendiri menggunakan paket ini untuk berbicara dengan layanan, yang membuatnya menjadi pilihan teraman untuk kompatibilitas.
Instalasi
go get github.com/ollama/ollama/api
Chat — Qwen3 (thinking ON / OFF)
package main
import (
"context"
"fmt"
"log"
"github.com/ollama/ollama/api"
)
func chatWithQwen3Thinking(ctx context.Context, thinking bool) error {
client, err := api.ClientFromEnvironment() // menghormati OLLAMA_HOST jika diatur
if err != nil {
return err
}
req := &api.ChatRequest{
Model: "qwen3:8b-thinking",
// Banyak konstruksi server mengekspos thinking sebagai bendera tingkat atas;
// selain itu, Anda dapat mengontrol Qwen3 melalui /think atau /no_think dalam pesan.
Think: api.Ptr(thinking),
Messages: []api.Message{
{Role: "system", Content: "Anda adalah asisten yang presisi."},
{Role: "user", Content: "Jelaskan merge sort dengan snippet Go pendek."},
},
}
var resp api.ChatResponse
if err := client.Chat(ctx, req, &resp); err != nil {
return err
}
if resp.Message.Thinking != "" {
fmt.Println("🧠 thinking:\n", resp.Message.Thinking)
}
fmt.Println("\n💬 jawaban:\n", resp.Message.Content)
return nil
}
func main() {
ctx := context.Background()
if err := chatWithQwen3Thinking(ctx, true); err != nil {
log.Fatal(err)
}
// Contoh: non-thinking
if err := chatWithQwen3Thinking(ctx, false); err != nil {
log.Fatal(err)
}
}
Chat — GPT-OSS (handle reasoning secara defensif)
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: "Apa itu memoization dan kapan berguna?"},
},
}
var resp api.ChatResponse
if err := client.Chat(ctx, req, &resp); err != nil {
return err
}
// Jika Anda bermaksud menyembunyikan penalaran, lakukan di sini terlepas dari bendera.
if resp.Message.Thinking != "" {
fmt.Println("🧠 thinking:\n", resp.Message.Thinking)
}
fmt.Println("\n💬 jawaban:\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: "Ringkas peran B-Tree dalam indeksing.",
Think: api.Ptr(true),
}
var resp api.GenerateResponse
if err := client.Generate(ctx, req, &resp); err != nil {
return err
}
if resp.Thinking != "" {
fmt.Println("🧠 thinking:\n", resp.Thinking)
}
fmt.Println("\n💬 jawaban:\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: "Jelaskan descent gradien dalam istilah sederhana.",
Think: api.Ptr(true),
}
var resp api.GenerateResponse
if err := client.Generate(ctx, req, &resp); err != nil {
return err
}
if resp.Thinking != "" {
fmt.Println("🧠 thinking:\n", resp.Thinking)
}
fmt.Println("\n💬 jawaban:\n", resp.Response)
return nil
}
Permukaan paket resmi meniru dokumentasi REST dan diperbarui bersama proyek inti.
Respons streaming
Untuk respons streaming real-time, atur Stream: bptr(true)
dalam permintaan Anda. Respons akan dikirim sebagai potongan JSON yang dipisahkan baris:
func streamChatExample() error {
endpoint := "http://localhost:11434/api/chat"
req := ChatRequest{
Model: "qwen3:8b-thinking",
Think: bptr(true),
Stream: bptr(true), // Aktifkan streaming
Messages: []ChatMessage{
{Role: "user", Content: "Jelaskan algoritma quicksort langkah demi langkah."},
},
}
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
}
// Proses thinking dan konten saat tiba
if chunk.Message.Thinking != "" {
fmt.Print(chunk.Message.Thinking)
}
fmt.Print(chunk.Message.Content)
if chunk.Done {
break
}
}
return nil
}
Dengan SDK resmi, gunakan fungsi callback untuk menangani potongan 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: "Jelaskan pohon pencarian biner."},
},
}
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
}
Bekerja dengan Qwen3 thinking vs non-thinking (panduan praktis)
-
Dua tombol:
- Bendera boolean
thinking
yang didukung oleh fitur thinking Ollama; dan - switch lembut Qwen3
/think
dan/no_think
dalam pesan sistem/pengguna terbaru. Instruksi terbaru mengatur putaran berikutnya.
- Bendera boolean
-
Postur default: non-thinking untuk jawaban cepat; tingkatkan ke thinking untuk tugas yang membutuhkan penalaran langkah demi langkah (matematika, perencanaan, debugging, analisis kode kompleks).
-
UI streaming: ketika thinking diaktifkan, Anda mungkin melihat penalaran/konten yang tercampur dalam frame streaming—buffer atau render secara terpisah dan berikan pengguna toggle “tampilkan penalaran”. (Lihat dokumentasi API untuk format streaming.)
-
Percakapan multi-putaran: Qwen3 mengingat mode thinking dari putaran sebelumnya. Jika Anda ingin beralih di tengah percakapan, gunakan bendera dan switch lembut untuk keandalan.
Catatan untuk GPT-OSS
- Anggap penalaran sebagai hadir bahkan jika Anda mencoba menonaktifkannya; saring di sisi klien jika UX Anda tidak boleh menampilkannya.
- Untuk aplikasi produksi yang menggunakan GPT-OSS, implementasikan logika penyaringan sisi klien yang dapat mendeteksi dan menghilangkan pola penalaran jika diperlukan.
- Uji model GPT-OSS spesifik Anda secara menyeluruh, karena perilaku mungkin bervariasi antara kuantisasi dan versi berbeda.
Praktik terbaik dan tips produksi
Penanganan kesalahan dan timeout
Selalu implementasikan penanganan timeout dan pemulihan kesalahan yang tepat:
func robustChatRequest(ctx context.Context, model string, messages []api.Message) (*api.ChatResponse, error) {
// Tetapkan timeout yang wajar
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
client, err := api.ClientFromEnvironment()
if err != nil {
return nil, fmt.Errorf("membuat klien: %w", err)
}
req := &api.ChatRequest{
Model: model,
Messages: messages,
Options: map[string]interface{}{
"temperature": 0.7,
"num_ctx": 4096, // ukuran jendela konteks
},
}
var resp api.ChatResponse
if err := client.Chat(ctx, req, &resp); err != nil {
return nil, fmt.Errorf("permintaan chat gagal: %w", err)
}
return &resp, nil
}
Pemrosesan koneksi dan penggunaan ulang
Gunakan ulang klien Ollama di antara permintaan alih-alih membuat satu baru setiap kali:
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
}
Konfigurasi lingkungan
Gunakan variabel lingkungan untuk pengembangan fleksibel:
export OLLAMA_HOST=http://localhost:11434
export OLLAMA_NUM_PARALLEL=2
export OLLAMA_MAX_LOADED_MODELS=2
SDK resmi secara otomatis menghormati OLLAMA_HOST
melalui api.ClientFromEnvironment()
.
Pemantauan dan logging
Implementasikan logging terstruktur untuk sistem produksi:
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
}
Kesimpulan
-
Untuk proyek Go,
github.com/ollama/ollama/api
adalah pilihan terlengkap dan siap produksi. Dikelola bersama proyek inti Ollama, digunakan oleh CLI resmi, dan menyediakan cakupan API menyeluruh dengan kompatibilitas yang dijamin. -
Untuk abstraksi tingkat tinggi, pertimbangkan LangChainGo ketika Anda membutuhkan rantai, alat, penyimpanan vektor, dan pipeline RAG—meskipun Anda akan menukar sedikit kontrol tingkat rendah untuk kenyamanan.
-
Qwen3 memberi Anda kontrol bersih dan andal terhadap mode thinking dengan bendera dan toggle pesan tingkat pesan (
/think
,/no_think
), membuatnya ideal untuk aplikasi yang membutuhkan jawaban cepat dan penalaran mendalam. -
Untuk GPT-OSS, selalu rencanakan untuk membersihkan output penalaran di sisi klien ketika diperlukan, karena bendera disable thinking mungkin tidak selalu dihormati.
-
Di produksi, implementasikan penanganan kesalahan yang tepat, pemrosesan koneksi, timeout, dan pemantauan untuk membangun aplikasi berbasis Ollama yang andal.
Kombinasi tipe kuat Go, dukungan konkurensi yang sangat baik, dan API Ollama yang sederhana membuatnya menjadi stack ideal untuk membangun aplikasi berbasis AI—dari chatbot sederhana hingga sistem RAG kompleks.
Poin penting
Berikut adalah referensi cepat untuk memilih pendekatan Anda:
Kasus Penggunaan | Pendekatan yang Direkomendasikan | Mengapa |
---|---|---|
Aplikasi produksi | github.com/ollama/ollama/api |
Dukungan resmi, cakupan API lengkap, dikelola bersama proyek inti |
RAG/rantai/alat pipeline | LangChainGo | Abstraksi tingkat tinggi, integrasi dengan penyimpanan vektor |
Pembelajaran/eksperimen | Raw REST dengan net/http | Transparansi penuh, tanpa ketergantungan, pendidikan |
Prototipe cepat | SDK resmi | Keseimbangan antara kesederhanaan dan kekuatan |
UI chat streaming | SDK resmi dengan callback | Dukungan streaming bawaan, API bersih |
Panduan pemilihan model:
- Qwen3: Terbaik untuk aplikasi yang memerlukan kontrol mode thinking yang dapat diatur, percakapan multi-putaran yang andal
- GPT-OSS: Kinerja yang kuat tetapi memerlukan penanganan defensif terhadap output penalaran
- Model lainnya: Uji secara menyeluruh; perilaku thinking bervariasi berdasarkan keluarga model
Referensi & bacaan lanjutan
Dokumentasi resmi
- Referensi API Ollama — Dokumentasi lengkap API REST
- Paket Go resmi Ollama — Dokumentasi SDK Go
- Repository GitHub Ollama — Kode sumber dan isu
Alternatif SDK Go
- Integrasi Ollama LangChainGo — Untuk aplikasi berbasis rantai
- swdunlop/ollama-client — Klien komunitas dengan pemanggilan alat
- xyproto/ollamaclient — Opsi komunitas lainnya
Sumber daya spesifik model
- Dokumentasi Qwen — Informasi model Qwen resmi
- Informasi GPT-OSS — Detail model GPT-OSS
Topik terkait
- Membangun aplikasi RAG dengan Go — Contoh LangChainGo
- Paket konteks Go — Penting untuk timeout dan pembatalan
- Praktik terbaik klien HTTP Go — Dokumentasi perpustakaan standar
Tautan yang Berguna Lainnya
- Pasang dan konfigurasi Ollama
- Kartu cepat Ollama
- Kartu cepat Go
- Bagaimana Ollama Mengelola Permintaan Paralel
- Mengurutkan ulang dokumen teks dengan Ollama dan Model Qwen3 Embedding - dalam Go
- Membandingkan ORM Go untuk PostgreSQL: GORM vs Ent vs Bun vs sqlc
- Membatasi LLM dengan Output Terstruktur: Ollama, Qwen3 & Python atau Go
- Menggunakan Ollama dalam Kode Python
- Perbandingan LLM: Qwen3:30b vs GPT-OSS:20b
- Masalah Output Terstruktur Ollama GPT-OSS