Getting started¶
This tutorial walks you through your first AI chat, end to end: activate a
provider, resolve a credential, send a Chat message, and then ask for a
structured Ask response unmarshalled straight into a Go struct.
You will do everything in one self-contained Go program so you can watch each moving part. We use Anthropic Claude here; the same shape works for every provider — you would swap only the blank import, the provider constant, and the credential env var.
Prerequisites¶
- Go 1.26 or newer.
- An Anthropic API key exported as
ANTHROPIC_API_KEY. - A new module to experiment in:
mkdir chat-tutorial && cd chat-tutorial
go mod init example.test/chat-tutorial
go get gitlab.com/phpboyscout/go/chat
go get gitlab.com/phpboyscout/go/chat-anthropic
Step 1 — Activate a provider¶
Providers live in separate modules and are switched on by a blank import —
the same pattern as database drivers or image/* decoders. Importing
chat-anthropic for its init() side effect registers the claude provider
with the core:
import (
"gitlab.com/phpboyscout/go/chat"
_ "gitlab.com/phpboyscout/go/chat-anthropic" // registers ProviderClaude
)
Without this import, chat.New with ProviderClaude returns
unsupported provider: claude. The SDK-free claude-local provider is the only
one that needs no import — it ships in the core.
Step 2 — Construct a client¶
chat.New takes package-owned Settings: a Config describing provider
behaviour, and an optional *slog.Logger. Leave Token empty and the client
falls back to the well-known ANTHROPIC_API_KEY environment variable.
client, err := chat.New(ctx, chat.Settings{
Config: chat.Config{
Provider: chat.ProviderClaude,
SystemPrompt: "You are a concise assistant.",
},
})
If no Model is set, Claude defaults to claude-opus-4-8.
Step 3 — Send a message¶
Chat sends a prompt and returns the text reply. Message history is retained on
the client, so follow-up calls continue the same conversation.
reply, err := client.Chat(ctx, "Name three uses for a CLI tool, one line each.")
if err != nil {
log.Fatal(err)
}
fmt.Println(reply)
Step 4 — Ask for structured output¶
Ask unmarshals the model's answer directly into a Go value. Set a
ResponseSchema on the Config and the provider is forced to return JSON
matching your struct.
type Summary struct {
Title string `json:"title"`
Points []string `json:"points"`
}
structured, err := chat.New(ctx, chat.Settings{
Config: chat.Config{
Provider: chat.ProviderClaude,
ResponseSchema: Summary{},
SchemaName: "summary",
},
})
if err != nil {
log.Fatal(err)
}
var out Summary
if err := structured.Ask(ctx, "Summarise the Go language in a title and three points.", &out); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n%v\n", out.Title, out.Points)
The complete program¶
package main
import (
"context"
"fmt"
"log"
"gitlab.com/phpboyscout/go/chat"
_ "gitlab.com/phpboyscout/go/chat-anthropic"
)
type Summary struct {
Title string `json:"title"`
Points []string `json:"points"`
}
func main() {
ctx := context.Background()
client, err := chat.New(ctx, chat.Settings{
Config: chat.Config{
Provider: chat.ProviderClaude,
SystemPrompt: "You are a concise assistant.",
},
})
if err != nil {
log.Fatal(err)
}
reply, err := client.Chat(ctx, "Name three uses for a CLI tool, one line each.")
if err != nil {
log.Fatal(err)
}
fmt.Println(reply)
structured, err := chat.New(ctx, chat.Settings{
Config: chat.Config{
Provider: chat.ProviderClaude,
ResponseSchema: Summary{},
SchemaName: "summary",
},
})
if err != nil {
log.Fatal(err)
}
var out Summary
if err := structured.Ask(ctx, "Summarise the Go language in a title and three points.", &out); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n%v\n", out.Title, out.Points)
}
Run it:
Success criterion¶
The program prints a one-line-per-use answer, then a title and three bullet
points parsed into the Summary struct. If you see unsupported provider:
claude, the blank import in step 1 is missing; if you see a credential error,
ANTHROPIC_API_KEY is not exported.
Next steps¶
- Swap providers or point at a local model: Choose & configure a provider.
- Give the model tools it can call: Call tools (the ReAct loop).
- Stream long replies token by token: Stream responses.
- Understand the loop and the seams: Architecture.