diff --git a/cookbook/gollem_go_agent_framework/README.md b/cookbook/gollem_go_agent_framework/README.md new file mode 100644 index 000000000000..729f985d086c --- /dev/null +++ b/cookbook/gollem_go_agent_framework/README.md @@ -0,0 +1,119 @@ +# Gollem Go Agent Framework with LiteLLM + +A working example showing how to use [gollem](https://github.com/fugue-labs/gollem), a production-grade Go agent framework, with LiteLLM as a proxy gateway. This lets Go developers access 100+ LLM providers through a single proxy while keeping compile-time type safety for tools and structured output. + +## Quick Start + +### 1. Start LiteLLM Proxy + +```bash +# Simple start with a single model +litellm --model gpt-4o + +# Or with the example config for multi-provider access +litellm --config proxy_config.yaml +``` + +### 2. Run the examples + +```bash +# Install Go dependencies +go mod tidy + +# Basic agent +go run ./basic + +# Agent with type-safe tools +go run ./tools + +# Streaming responses +go run ./streaming +``` + +## Configuration + +The included `proxy_config.yaml` sets up three providers through LiteLLM: + +```yaml +model_list: + - model_name: gpt-4o # OpenAI + - model_name: claude-sonnet # Anthropic + - model_name: gemini-pro # Google Vertex AI +``` + +Switch providers in Go by changing a single string — no code changes needed: + +```go +model := openai.NewLiteLLM("http://localhost:4000", + openai.WithModel("gpt-4o"), // OpenAI + // openai.WithModel("claude-sonnet"), // Anthropic + // openai.WithModel("gemini-pro"), // Google +) +``` + +## Examples + +### `basic/` — Basic Agent + +Connects gollem to LiteLLM and runs a simple prompt. Demonstrates the `NewLiteLLM` constructor and basic agent creation. + +### `tools/` — Type-Safe Tools + +Shows gollem's compile-time type-safe tool framework working through LiteLLM's tool-use passthrough. The tool parameters are Go structs with JSON tags — the schema is generated automatically at compile time. + +### `streaming/` — Streaming Responses + +Real-time token streaming using Go 1.23+ range-over-function iterators, proxied through LiteLLM's SSE passthrough. + +## How It Works + +Gollem's `openai.NewLiteLLM()` constructor creates an OpenAI-compatible provider pointed at your LiteLLM proxy. Since LiteLLM speaks the OpenAI API protocol, everything works out of the box: + +- **Chat completions** — standard request/response +- **Tool use** — LiteLLM passes tool definitions and calls through transparently +- **Streaming** — Server-Sent Events proxied through LiteLLM +- **Structured output** — JSON schema response format works with supporting models + +``` +Go App (gollem) → LiteLLM Proxy → OpenAI / Anthropic / Google / ... +``` + +## Why Use This? + +- **Type-safe Go**: Compile-time type checking for tools, structured output, and agent configuration — no runtime surprises +- **Single proxy, many models**: Switch between OpenAI, Anthropic, Google, and 100+ other providers by changing a model name string +- **Zero-dependency core**: gollem's core has no external dependencies — just stdlib +- **Single binary deployment**: `go build` produces one binary, no pip/venv/Docker needed +- **Cost tracking & rate limiting**: LiteLLM handles cost tracking, rate limits, and fallbacks at the proxy layer + +## Environment Variables + +```bash +# Required for providers you want to use (set in LiteLLM config or env) +export OPENAI_API_KEY="sk-..." +export ANTHROPIC_API_KEY="sk-ant-..." + +# Optional: point to a non-default LiteLLM proxy +export LITELLM_PROXY_URL="http://localhost:4000" +``` + +## Troubleshooting + +**Connection errors?** +- Make sure LiteLLM is running: `litellm --model gpt-4o` +- Check the URL is correct (default: `http://localhost:4000`) + +**Model not found?** +- Verify the model name matches what's configured in LiteLLM +- Run `curl http://localhost:4000/models` to see available models + +**Tool calls not working?** +- Ensure the underlying model supports tool use (GPT-4o, Claude, Gemini) +- Check LiteLLM logs for any provider-specific errors + +## Learn More + +- [gollem GitHub](https://github.com/fugue-labs/gollem) +- [gollem API Reference](https://pkg.go.dev/github.com/fugue-labs/gollem/core) +- [LiteLLM Proxy Docs](https://docs.litellm.ai/docs/simple_proxy) +- [LiteLLM Supported Models](https://docs.litellm.ai/docs/providers) diff --git a/cookbook/gollem_go_agent_framework/basic/main.go b/cookbook/gollem_go_agent_framework/basic/main.go new file mode 100644 index 000000000000..838149a8ff94 --- /dev/null +++ b/cookbook/gollem_go_agent_framework/basic/main.go @@ -0,0 +1,41 @@ +// Basic gollem agent connected to a LiteLLM proxy. +// +// Usage: +// +// litellm --model gpt-4o # start proxy in another terminal +// go run ./basic +package main + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/fugue-labs/gollem/core" + "github.com/fugue-labs/gollem/provider/openai" +) + +func main() { + proxyURL := "http://localhost:4000" + if u := os.Getenv("LITELLM_PROXY_URL"); u != "" { + proxyURL = u + } + + // Connect to LiteLLM proxy. NewLiteLLM creates an OpenAI-compatible + // provider pointed at the given URL. + model := openai.NewLiteLLM(proxyURL, + openai.WithModel("gpt-4o"), // any model name configured in LiteLLM + ) + + // Create and run a simple agent. + agent := core.NewAgent[string](model, + core.WithSystemPrompt[string]("You are a helpful assistant. Be concise."), + ) + + result, err := agent.Run(context.Background(), "Explain quantum computing in two sentences.") + if err != nil { + log.Fatal(err) + } + fmt.Println(result.Output) +} diff --git a/cookbook/gollem_go_agent_framework/go.mod b/cookbook/gollem_go_agent_framework/go.mod new file mode 100644 index 000000000000..89d9033aa225 --- /dev/null +++ b/cookbook/gollem_go_agent_framework/go.mod @@ -0,0 +1,5 @@ +module github.com/BerriAI/litellm/cookbook/gollem_go_agent_framework + +go 1.25.1 + +require github.com/fugue-labs/gollem v0.1.0 diff --git a/cookbook/gollem_go_agent_framework/go.sum b/cookbook/gollem_go_agent_framework/go.sum new file mode 100644 index 000000000000..1eb6c5ac9fc8 --- /dev/null +++ b/cookbook/gollem_go_agent_framework/go.sum @@ -0,0 +1,2 @@ +github.com/fugue-labs/gollem v0.1.0 h1:QexYnvkb44QZFEljgAePqMIGZjgsbk0Y5GJ2jYYgfa8= +github.com/fugue-labs/gollem v0.1.0/go.mod h1:htW1YO81uysSKVOkYJtxhGCFrzm+36HBFxEWuECoHKQ= diff --git a/cookbook/gollem_go_agent_framework/proxy_config.yaml b/cookbook/gollem_go_agent_framework/proxy_config.yaml new file mode 100644 index 000000000000..18265a002bc7 --- /dev/null +++ b/cookbook/gollem_go_agent_framework/proxy_config.yaml @@ -0,0 +1,16 @@ +model_list: + - model_name: gpt-4o + litellm_params: + model: openai/gpt-4o + api_key: os.environ/OPENAI_API_KEY + + - model_name: claude-sonnet + litellm_params: + model: anthropic/claude-sonnet-4-20250514 + api_key: os.environ/ANTHROPIC_API_KEY + + - model_name: gemini-pro + litellm_params: + model: vertex_ai/gemini-2.0-flash + vertex_project: my-project + vertex_location: us-central1 diff --git a/cookbook/gollem_go_agent_framework/streaming/main.go b/cookbook/gollem_go_agent_framework/streaming/main.go new file mode 100644 index 000000000000..42bc9bbe34ac --- /dev/null +++ b/cookbook/gollem_go_agent_framework/streaming/main.go @@ -0,0 +1,56 @@ +// Streaming responses from gollem through LiteLLM. +// +// Uses Go 1.23+ range-over-function iterators for real-time token +// streaming via LiteLLM's SSE passthrough. +// +// Usage: +// +// litellm --model gpt-4o +// go run ./streaming +package main + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/fugue-labs/gollem/core" + "github.com/fugue-labs/gollem/provider/openai" +) + +func main() { + proxyURL := "http://localhost:4000" + if u := os.Getenv("LITELLM_PROXY_URL"); u != "" { + proxyURL = u + } + + model := openai.NewLiteLLM(proxyURL, + openai.WithModel("gpt-4o"), + ) + + agent := core.NewAgent[string](model) + + // RunStream returns a streaming result that yields tokens as they arrive. + stream, err := agent.RunStream(context.Background(), "Write a haiku about distributed systems") + if err != nil { + log.Fatal(err) + } + + // StreamText yields text chunks in real-time. + // The boolean argument controls whether deltas (true) or accumulated + // text (false) is returned. + fmt.Print("Response: ") + for text, err := range stream.StreamText(true) { + if err != nil { + log.Fatal(err) + } + fmt.Print(text) + } + fmt.Println() + + // After streaming completes, the final response is available. + resp := stream.Response() + fmt.Printf("\nTokens used: input=%d, output=%d\n", + resp.Usage.InputTokens, resp.Usage.OutputTokens) +} diff --git a/cookbook/gollem_go_agent_framework/tools/main.go b/cookbook/gollem_go_agent_framework/tools/main.go new file mode 100644 index 000000000000..ed41a95ffef9 --- /dev/null +++ b/cookbook/gollem_go_agent_framework/tools/main.go @@ -0,0 +1,64 @@ +// Gollem agent with type-safe tools through LiteLLM. +// +// The tool parameters are Go structs — gollem generates the JSON schema +// automatically at compile time. LiteLLM passes tool definitions through +// transparently to the underlying provider. +// +// Usage: +// +// litellm --model gpt-4o +// go run ./tools +package main + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/fugue-labs/gollem/core" + "github.com/fugue-labs/gollem/provider/openai" +) + +// WeatherParams defines the tool's input schema via struct tags. +// The JSON schema is generated at compile time — no runtime reflection needed. +type WeatherParams struct { + City string `json:"city" description:"City name to get weather for"` + Unit string `json:"unit,omitempty" description:"Temperature unit: celsius or fahrenheit"` +} + +func main() { + proxyURL := "http://localhost:4000" + if u := os.Getenv("LITELLM_PROXY_URL"); u != "" { + proxyURL = u + } + + model := openai.NewLiteLLM(proxyURL, + openai.WithModel("gpt-4o"), + ) + + // Define a type-safe tool. The function signature enforces correct types. + weatherTool := core.FuncTool[WeatherParams]( + "get_weather", + "Get current weather for a city", + func(ctx context.Context, p WeatherParams) (string, error) { + unit := p.Unit + if unit == "" { + unit = "fahrenheit" + } + // In production, call a real weather API here. + return fmt.Sprintf("Weather in %s: 72°F (22°C), sunny", p.City), nil + }, + ) + + agent := core.NewAgent[string](model, + core.WithTools[string](weatherTool), + core.WithSystemPrompt[string]("You are a helpful weather assistant. Use the get_weather tool to answer weather questions."), + ) + + result, err := agent.Run(context.Background(), "What's the weather like in San Francisco and Tokyo?") + if err != nil { + log.Fatal(err) + } + fmt.Println(result.Output) +}