# GoAI SDK > Go SDK for building AI applications. One unified API across 25+ LLM providers. GoAI SDK is an open-source Go library inspired by the Vercel AI SDK, designed idiomatically for Go with generics, interfaces, and channels. It provides a single API surface for text generation, streaming, structured output, embeddings, image generation, and tool calling across 25+ providers. - Website: https://goai.sh - GitHub: https://github.com/zendev-sh/goai - GoDoc: https://pkg.go.dev/github.com/zendev-sh/goai - License: MIT - Go version: 1.25+ - Dependencies: core requires only `golang.org/x/oauth2` for Vertex AI. Optional `observability/otel` submodule uses separate go.mod with OTel SDK. ## Install ``` go get github.com/zendev-sh/goai@latest ``` Provider packages are included — no separate installs needed. ```go import ( "github.com/zendev-sh/goai" "github.com/zendev-sh/goai/provider/openai" "github.com/zendev-sh/goai/provider/anthropic" "github.com/zendev-sh/goai/provider/google" "github.com/zendev-sh/goai/provider/bedrock" "github.com/zendev-sh/goai/provider/azure" "github.com/zendev-sh/goai/provider/vertex" ) ``` All providers auto-resolve API keys from environment variables. No explicit configuration needed. --- ## Core Functions ### GenerateText Non-streaming text generation with optional auto tool loop. ```go func GenerateText(ctx context.Context, model provider.LanguageModel, opts ...Option) (*TextResult, error) ``` When tools with `Execute` functions are provided and `MaxSteps > 1`, it automatically runs a tool loop: generate → execute tools → re-generate, up to MaxSteps times. Example: ```go model := openai.Chat("gpt-4o") // auto-reads OPENAI_API_KEY result, err := goai.GenerateText(context.Background(), model, goai.WithSystem("You are a helpful assistant."), goai.WithPrompt("What is the capital of France?"), ) fmt.Println(result.Text) fmt.Printf("Tokens: %d in, %d out\n", result.TotalUsage.InputTokens, result.TotalUsage.OutputTokens) ``` ### StreamText Streaming text generation via Go channels. ```go func StreamText(ctx context.Context, model provider.LanguageModel, opts ...Option) (*TextStream, error) ``` TextStream provides three consumption modes: - `Stream()` — channel of raw `provider.StreamChunk` (all chunk types) - `TextStream()` — channel of `string` (text only) - `Result()` — blocks until complete, returns final `*TextResult` `Stream()` and `TextStream()` are mutually exclusive. `Result()` can always be called after either. Example: ```go stream, err := goai.StreamText(ctx, model, goai.WithPrompt("Write a haiku about Go."), ) for text := range stream.TextStream() { fmt.Print(text) } result := stream.Result() fmt.Printf("Tokens: %d in, %d out\n", result.TotalUsage.InputTokens, result.TotalUsage.OutputTokens) ``` ### GenerateObject[T] Type-safe structured output using Go generics. Auto-generates JSON Schema from T. Supports MaxSteps/tool loop: when tools with `Execute` functions are provided and `MaxSteps > 1`, it runs a tool loop before producing the final structured object. ```go func GenerateObject[T any](ctx context.Context, model provider.LanguageModel, opts ...Option) (*ObjectResult[T], error) ``` Example: ```go type Recipe struct { Name string `json:"name" jsonschema:"description=Recipe name"` Ingredients []string `json:"ingredients"` Steps []string `json:"steps"` Difficulty string `json:"difficulty" jsonschema:"enum=easy|medium|hard"` } result, err := goai.GenerateObject[Recipe](ctx, model, goai.WithPrompt("Chocolate chip cookies recipe"), ) fmt.Printf("Recipe: %s (Difficulty: %s)\n", result.Object.Name, result.Object.Difficulty) ``` ### StreamObject[T] Streaming structured output with partial objects. ```go func StreamObject[T any](ctx context.Context, model provider.LanguageModel, opts ...Option) (*ObjectStream[T], error) ``` - `PartialObjectStream()` — channel emitting progressively populated partial objects - `Result()` — blocks until complete, returns final validated object ### Embed Single text embedding. ```go func Embed(ctx context.Context, model provider.EmbeddingModel, value string, opts ...Option) (*EmbedResult, error) ``` ### EmbedMany Batch text embeddings with auto-chunking and parallel processing. ```go func EmbedMany(ctx context.Context, model provider.EmbeddingModel, values []string, opts ...Option) (*EmbedManyResult, error) ``` ### GenerateImage Image generation from text prompt. ```go func GenerateImage(ctx context.Context, model provider.ImageModel, opts ...ImageOption) (*ImageResult, error) ``` Uses `ImageOption` (not `Option`): `WithImagePrompt`, `WithImageCount`, `WithImageSize`, `WithAspectRatio`, `WithImageProviderOptions`, `WithImageMaxRetries`, `WithImageTimeout`. ### Message Builders ```go goai.SystemMessage(text string) provider.Message goai.UserMessage(text string) provider.Message goai.AssistantMessage(text string) provider.Message goai.ToolMessage(toolCallID, toolName, output string) provider.Message ``` ### SchemaFrom[T] Generates JSON Schema from Go type via reflection. Compatible with OpenAI strict mode. ```go func SchemaFrom[T any]() json.RawMessage ``` Supported struct tags: - `json:"name"` — property name - `json:"-"` — exclude field - `jsonschema:"description=..."` — adds description - `jsonschema:"enum=a|b|c"` — restricts to enum values Supported types: string, bool, int/uint (all sizes), float32/64, slices, maps (string keys), structs (embedded structs flattened), pointers (nullable). --- ## Options All options use the functional options pattern: `goai.With*(...)`. ### Core Options - `WithSystem(s string)` — system prompt - `WithPrompt(s string)` — single user message (shorthand) - `WithMessages(msgs ...provider.Message)` — conversation history - `WithPromptCaching(bool)` — enable provider-specific prompt caching ### Tool Options - `WithTools(tools ...Tool)` — available tools - `WithMaxSteps(n int)` — max auto tool loop iterations (default: 1 = no loop) - `WithToolChoice(tc string)` — "auto" | "none" | "required" | "" ### Generation Options - `WithMaxOutputTokens(n int)` — response length limit - `WithTemperature(t float64)` — randomness control - `WithTopP(p float64)` — nucleus sampling - `WithTopK(k int)` — limit sampling to top K tokens - `WithFrequencyPenalty(p float64)` — penalize tokens by frequency - `WithPresencePenalty(p float64)` — penalize tokens already present - `WithSeed(s int)` — seed for deterministic generation - `WithStopSequences(seqs ...string)` — stop sequences ### Infrastructure Options - `WithMaxRetries(n int)` — retry count for transient errors (default: 2) - `WithTimeout(d time.Duration)` — request timeout - `WithHeaders(h map[string]string)` — additional HTTP headers - `WithProviderOptions(opts map[string]any)` — provider-specific parameters ### Telemetry Hooks - `WithOnRequest(fn func(RequestInfo))` — before each API call - `WithOnResponse(fn func(ResponseInfo))` — after each API call - `WithOnStepFinish(fn func(StepResult))` — after each generation step - `WithOnToolCall(fn func(ToolCallInfo))` — after each tool execution ### Structured Output Options - `WithExplicitSchema(schema json.RawMessage)` — override auto-generated schema - `WithSchemaName(name string)` — schema name (default: "response") ### Embedding Options - `WithMaxParallelCalls(n int)` — max concurrent API calls for EmbedMany (default: 4) - `WithEmbeddingProviderOptions(opts map[string]any)` — provider-specific embedding params ### Image Options (ImageOption type) - `WithImagePrompt(prompt string)` — text prompt - `WithImageCount(n int)` — number of images (default: 1) - `WithImageSize(size string)` — dimensions (e.g., "1024x1024") - `WithAspectRatio(ratio string)` — aspect ratio (e.g., "16:9") - `WithImageProviderOptions(opts map[string]any)` — provider-specific image params - `WithImageMaxRetries(n int)` - max retries for image generation (default: 2) - `WithImageTimeout(d time.Duration)`: timeout for the image generation call (overall deadline, not per attempt) --- ## Tools Tools let the model call functions defined in your code. ### Defining a Tool `goai.NewTool` builds a tool from a typed input struct: the JSON Schema is generated from the struct and the model's arguments are unmarshaled into it before execute runs (no hand-written schema, no manual unmarshaling). ```go tool := goai.NewTool("get_weather", "Get weather for a city.", func(ctx context.Context, params struct { City string `json:"city" jsonschema:"description=City name"` }) (string, error) { return fmt.Sprintf("72F and sunny in %s", params.City), nil }) ``` For a hand-written JSON Schema or a provider-defined tool, build the `goai.Tool` struct directly (set `InputSchema` and an `Execute` that receives raw JSON). ### Auto Tool Loop Set `WithMaxSteps(n)` where n > 1 to enable automatic tool execution: ```go result, err := goai.GenerateText(ctx, model, goai.WithPrompt("What's the weather in Tokyo and London?"), goai.WithTools(weatherTool), goai.WithMaxSteps(5), ) ``` Loop: generate → execute tools → append results → re-generate → repeat until model stops or MaxSteps reached. ### Tools Without Execute If a tool has no `Execute` function, it's sent to the model as a definition only. Tool calls appear in `result.ToolCalls` for manual handling. ### StepResult Fields - `Number` (int) — 1-based step index - `Text` (string) — text generated in this step - `ToolCalls` ([]provider.ToolCall) — tool calls requested - `FinishReason` (provider.FinishReason) — why this step stopped - `Usage` (provider.Usage) — token usage - `Response` (provider.ResponseMetadata) — provider metadata - `Sources` ([]provider.Source) — citations --- ## Providers All providers auto-resolve credentials from environment variables. ### Tier 1 — Dedicated implementations | Provider | Import | Chat | Embed | Image | Provider Tools | Auth Env Var | |----------|--------|------|-------|-------|----------------|--------------| | OpenAI | `provider/openai` | ✅ gpt-4o, o3 | ✅ text-embedding-3-* | ✅ gpt-image-1 | 4 (web search, code interpreter, image gen, file search) | `OPENAI_API_KEY` | | Anthropic | `provider/anthropic` | ✅ claude-* | — | — | 10 (web search, web fetch, computer use, bash, text editor, code execution) | `ANTHROPIC_API_KEY` | | Google | `provider/google` | ✅ gemini-* | ✅ text-embedding-004 | ✅ imagen-* | 3 (google search, URL context, code execution) | `GOOGLE_GENERATIVE_AI_API_KEY` or `GEMINI_API_KEY` | | Bedrock | `provider/bedrock` | ✅ anthropic.*, meta.* | ✅ titan-embed-*, cohere.embed-*, nova-2-*, marengo-* | — | — | `AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY` | | Azure | `provider/azure` | ✅ gpt-4o, claude-* | — | ✅ | — | `AZURE_OPENAI_API_KEY` | | Vertex AI | `provider/vertex` | ✅ gemini-* | ✅ | ✅ | — | ADC (Application Default Credentials) | ### Tier 2 | Provider | Import | Auth Env Var | |----------|--------|--------------| | Cohere | `provider/cohere` | `COHERE_API_KEY` | | Mistral | `provider/mistral` | `MISTRAL_API_KEY` | | MiniMax | `provider/minimax` | `MINIMAX_API_KEY` | | xAI (Grok) | `provider/xai` | `XAI_API_KEY` | | Groq | `provider/groq` | `GROQ_API_KEY` | | DeepSeek | `provider/deepseek` | `DEEPSEEK_API_KEY` | ### Tier 3 — OpenAI-compatible Fireworks (`FIREWORKS_API_KEY`), Together (`TOGETHER_AI_API_KEY`), DeepInfra (`DEEPINFRA_API_KEY`), OpenRouter (`OPENROUTER_API_KEY`), Perplexity (`PERPLEXITY_API_KEY`), Cerebras (`CEREBRAS_API_KEY`). ### Local / Custom - Ollama — `localhost:11434`, no auth, embed support - vLLM — `localhost:8000`, optional auth, embed support - RunPod — serverless vLLM on RunPod (`RUNPOD_API_KEY`, auto-resolves endpoint URL) - Compatible — any OpenAI-compatible endpoint via `provider/compat` ### Common Provider Options ```go // Each provider exports its own With* options: openai.WithAPIKey(key) // static API key openai.WithTokenSource(ts) // dynamic auth (OAuth, service accounts) openai.WithBaseURL(url) // override endpoint openai.WithHeaders(h) // custom HTTP headers openai.WithHTTPClient(c) // custom HTTP transport ``` --- ## Provider-Defined Tools Built-in tools provided by specific providers, executed server-side. ### OpenAI - `openai.Tools.WebSearch()` — web search - `openai.Tools.CodeInterpreter()` — sandboxed Python execution - `openai.Tools.ImageGeneration()` — image generation via Responses API - `openai.Tools.FileSearch(opts...)` - semantic search over vector stores ### Anthropic - `anthropic.Tools.WebSearch()` — web search - `anthropic.Tools.WebFetch()` — fetch and process URLs - `anthropic.Tools.Computer(opts)` - mouse/keyboard control - `anthropic.Tools.Bash()` — shell execution - `anthropic.Tools.TextEditor()` — file editing - `anthropic.Tools.CodeExecution()` — sandboxed Python execution ### Google - `google.Tools.GoogleSearch()` — Google Search grounding - `google.Tools.URLContext()` — fetch and process URLs from prompt - `google.Tools.CodeExecution()` — sandboxed Python execution ### xAI - `xai.Tools.WebSearch()` — web search - `xai.Tools.XSearch()` — X (Twitter) search ### Groq - `groq.Tools.BrowserSearch()` — interactive browser search --- ## Quick Start Examples ### Basic chat ```go result, _ := goai.GenerateText(ctx, openai.Chat("gpt-4o"), goai.WithPrompt("Hello!"), ) fmt.Println(result.Text) ``` ### Streaming ```go stream, _ := goai.StreamText(ctx, anthropic.Chat("claude-sonnet-4-6"), goai.WithMessages(goai.UserMessage("Write a poem.")), ) for chunk := range stream.TextStream() { fmt.Print(chunk) } ``` ### Structured output ```go type City struct { Name string `json:"name"` Country string `json:"country"` Population int `json:"population"` } result, _ := goai.GenerateObject[City](ctx, google.Chat("gemini-2.5-flash"), goai.WithPrompt("Info about Tokyo"), ) fmt.Printf("%s, %s — pop: %d\n", result.Object.Name, result.Object.Country, result.Object.Population) ``` ### Tool calling with agent loop ```go result, _ := goai.GenerateText(ctx, model, goai.WithTools(weatherTool, calculatorTool), goai.WithMaxSteps(5), goai.WithPrompt("What's 72F in Celsius? Then check Tokyo weather."), ) fmt.Println(result.Text) ``` ### Embeddings ```go model := google.Embedding("text-embedding-004") result, _ := goai.Embed(ctx, model, "Hello world") fmt.Printf("Dimensions: %d\n", len(result.Embedding)) ``` ### Switching providers (one line change) ```go // Just change the model — all functions work identically model := openai.Chat("gpt-4o") model := anthropic.Chat("claude-sonnet-4-6") model := google.Chat("gemini-2.5-flash") model := groq.Chat("llama-3.3-70b-versatile") model := ollama.Chat("llama3.2") ``` --- ## Runnable Examples All examples at https://github.com/zendev-sh/goai/tree/main/examples: - `examples/chat/` — basic GenerateText - `examples/streaming/` — StreamText with TextStream() - `examples/structured/` — GenerateObject[T] and StreamObject[T] - `examples/embedding/` — Embed, EmbedMany, cosine similarity - `examples/citations/` — Sources from grounded responses - `examples/tools/` — single-step tool call - `examples/agent-loop/` — multi-step agent with callbacks - `examples/web-search/` — web search across OpenAI, Anthropic, Google - `examples/web-fetch/` — Anthropic URL fetching - `examples/computer-use/` — Anthropic computer use tools - `examples/code-execution/` — Anthropic code execution - `examples/code-interpreter/` — OpenAI code interpreter - `examples/google-search/` — Google Search grounding - `examples/google-code-execution/` — Gemini code execution - `examples/image-generation/` — OpenAI image generation tool - `examples/file-search/` — OpenAI vector store file search --- ## Observability The `observability/langfuse` package provides first-class Langfuse tracing. Pass the Langfuse client's hook functions to `WithOnRequest`, `WithOnResponse`, and `WithOnStepFinish` to capture traces, spans, and token usage in your Langfuse dashboard. ```go import "github.com/zendev-sh/goai/observability/langfuse" ``` --- ## Links - Docs: https://goai.sh - GitHub: https://github.com/zendev-sh/goai - GoDoc: https://pkg.go.dev/github.com/zendev-sh/goai - Compare: https://goai.sh/compare.html