Guides
Go quickstart
Build a RAG chatbot in Go with zero frameworks. One file, one dependency.
This is the Go equivalent of the zero-to-chatbot guide. It inserts documents into Aether, retrieves relevant context, and calls Claude via net/http — no LLM SDK needed.
What you'll need
- Go 1.21+
- An Aether API key
- An Anthropic API key
Setup
mkdir aether-chatbot && cd aether-chatbot
go mod init aether-chatbot
go get github.com/quintessence-group/aether-sdk-go
Set your API keys:
export AETHER_API_KEY="your-aether-key"
export ANTHROPIC_API_KEY="your-anthropic-key"
The entire app
Create main.go and paste this:
package main
import (
"bufio"
"bytes"
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"strings"
"time"
aether "github.com/quintessence-group/aether-sdk-go"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
client := aether.New(aether.WithAPIKey(os.Getenv("AETHER_API_KEY")))
// Step 1: Load your knowledge base
docs := []string{
"Our return policy allows returns within 30 days of purchase with a receipt.",
"Shipping is free on orders over $50. Standard delivery takes 3-5 business days.",
"We accept Visa, Mastercard, and PayPal. We do not accept cryptocurrency.",
"Store hours are Monday-Saturday 9am-9pm and Sunday 10am-6pm.",
"Loyalty members earn 1 point per dollar spent. 100 points = $5 off.",
}
fmt.Println("Loading documents...")
for _, doc := range docs {
if _, err := client.InsertText(ctx, doc, "doc.txt"); err != nil {
log.Fatal(err)
}
}
fmt.Printf("Loaded %d documents.\n\n", len(docs))
// Step 2: Chat loop
scanner := bufio.NewScanner(os.Stdin)
for {
fmt.Print("Ask a question (or 'quit'): ")
if !scanner.Scan() {
break
}
question := strings.TrimSpace(scanner.Text())
if question == "quit" || question == "exit" || question == "q" {
break
}
// Find relevant documents
results, err := client.Retrieve(ctx, question, 3)
if err != nil {
log.Printf("Retrieve error: %v\n", err)
continue
}
var contextBuf bytes.Buffer
for _, r := range results {
fmt.Fprintf(&contextBuf, "%s\n\n", r.Content)
}
// Ask Claude, grounded in your documents
answer, err := askClaude(ctx, contextBuf.String(), question)
if err != nil {
log.Printf("Claude error: %v\n", err)
continue
}
fmt.Printf("\n%s\n\n", answer)
}
}
func askClaude(ctx context.Context, docContext, question string) (string, error) {
reqBody, _ := json.Marshal(map[string]any{
"model": "claude-sonnet-4-20250514",
"max_tokens": 300,
"system": "Answer based only on this context. If the answer isn't in the context, say so.\n\n" + docContext,
"messages": []map[string]string{{"role": "user", "content": question}},
})
req, err := http.NewRequestWithContext(ctx, "POST",
"https://api.anthropic.com/v1/messages", bytes.NewReader(reqBody))
if err != nil {
return "", err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-API-Key", os.Getenv("ANTHROPIC_API_KEY"))
req.Header.Set("Anthropic-Version", "2023-06-01")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
var result struct {
Content []struct{ Text string } `json:"content"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return "", err
}
if len(result.Content) == 0 {
return "", fmt.Errorf("empty response from Claude")
}
return result.Content[0].Text, nil
}
Run it
go run main.go
Try asking
- "What's your return policy?"
- "Do you take crypto?"
- "How do I earn loyalty points?"
Key Go patterns
Context propagation. Every Aether SDK call takes a context.Context as the first argument. In a real application, pass the request context from your HTTP handler (r.Context()) instead of context.Background() — this ensures cancellation and timeouts propagate correctly.
Error handling. The Aether Go SDK returns error as the second return value. Always check it:
results, err := client.Retrieve(ctx, question, 3)
if err != nil {
// err could be a network failure, 401 (bad key), 429 (rate limited), etc.
// For production, check the HTTP status code to decide whether to retry:
log.Printf("retrieve failed: %v", err)
}
No LLM SDK needed. Unlike Python and TypeScript, Go doesn't need an Anthropic or OpenAI SDK package. The net/http standard library handles API calls directly. This keeps your dependency tree small and avoids version conflicts.
Package status. The Go module path is github.com/quintessence-group/aether-sdk-go. The public module is available through the default Go module proxy, so the unversioned go get command above installs the latest release.
Make it yours
Use your own documents. Replace the docs slice with your content, or load files:
data, _ := os.ReadFile("./handbook.pdf")
client.Insert(ctx, data, "handbook.pdf", "application/pdf")
Use OpenAI instead. Swap the askClaude function for an OpenAI call — see the OpenAI integration for the Go example.
Add an HTTP server. Wrap the chat logic in net/http handlers — the Go full-stack example shows exactly this pattern.
Next steps
- Go full-stack example — complete Knowledge Base Manager with
net/http - API Reference — all endpoints with Go examples
- Anthropic integration — detailed RAG pattern with Claude
- OpenAI integration — RAG with GPT-4o