gollm: A Unified Go Interface for OpenAI, Anthropic, Groq, Ollama and OpenRouter
Unified Go interface for Language Model (LLM) providers. Simplifies LLM integration with flexible prompt management and common task functions.
At a glance
- What is it?
- gollm wraps several LLM providers behind one Go API and adds prompt construction, chain-of-thought helpers, JSON schema validation and a prompt optimizer. The provider abstraction is the part that holds up; the prompt optimizer is the part you should treat as experimental until you read its source.
- Who is it for?
- Adopt gollm if you are writing Go services that need to talk to more than one LLM provider and you want the provider switch to be a SetProvider call rather than a rewrite. Do not adopt it if you need a stable, documented optimizer API or if your prompts are simple enough that a single provider SDK would do.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 178 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem gollm addresses: provider churn in Go services
If your Go service calls OpenAI directly, switching to Anthropic means rewriting the request construction, the response parsing, the retry loop and the error types. gollm's README frames the package as a way to avoid that: a unified interface across OpenAI, Anthropic, Groq, Ollama, Mistral and OpenRouter, with the model and provider chosen through options rather than through a separate client library. The intended audience is Go engineers building AI-backed services, not researchers and not Python users. The README's own framing is that gollm helps you build AI golems, an image that tells you something about the project's tone: it is opinionated and a little theatrical, which is worth knowing before you put it in a production dependency list. The concrete benefit is narrower than the marketing language suggests. You still need an API key per provider, still need to know which model names each provider accepts, and still need to handle the fact that providers differ in what they support. What gollm removes is the per-provider client code and the retry plumbing.
How the abstraction is structured: providers, options, prompts
The entry point is gollm.NewLLM, which takes a variadic list of options. The README shows SetProvider, SetModel, SetAPIKey, SetMaxTokens, SetTemperature, SetMaxRetries, SetRetryDelay, SetLogLevel and SetMemory. Each returns an option value applied during construction, and NewLLM returns an error, so provider and model validation happens at startup rather than on the first request. That is the right place for it. Requests go through llm.Generate(ctx, prompt), which takes a context.Context, so cancellation and deadlines propagate to the underlying HTTP call. Prompts are built with gollm.NewPrompt plus modifiers: WithContext, WithDirectives, WithOutput. This is a small builder rather than a template engine, and the README separates it from the Prompt Templates feature, which is a distinct mechanism. The provider layer is where the real abstraction lives. The README lists OpenRouter-specific options that do not exist on other providers: fallback_models, auto_route, prompt caching, reasoning tokens and provider routing preferences, set through llm.SetOption. That is the honest shape of the design. gollm gives you a common surface, and then a per-provider escape hatch for capabilities the common surface cannot express. If you use the escape hatch, you are no longer provider-portable, and the README does not pretend otherwise.
Getting it running: install, configure, first call
Installation is a single command: go get github.com/teilomillet/gollm. The README's basic example reads the key from the environment with os.Getenv("OPENAI_API_KEY") and fails with log.Fatalf if it is empty, then constructs the client with gollm.SetProvider("openai"), gollm.SetModel("gpt-4o-mini"), gollm.SetMaxTokens(200), gollm.SetMaxRetries(3), gollm.SetRetryDelay(time.Second*2) and gollm.SetLogLevel(gollm.LogLevelInfo). The prompt is gollm.NewPrompt with a single string, and the call is llm.Generate(ctx, prompt). The README also states that configuration can come from environment variables, code, or configuration files, though the example shown uses code. For OpenRouter the README shows a second construction path with SetProvider("openrouter") and a model string of the form anthropic/claude-3-5-sonnet, followed by llm.SetOption("fallback_models", []string{"openai/gpt-4o", "mistral/mistral-large"}). Two details in the README are worth flagging before you copy them. The first is that the quick reference block for Prompt Creation is truncated mid-call in the material available here, so the exact argument list for WithOutput is not fully verifiable from this README alone. The second is that SetAPIKey appears in the examples with a literal string placeholder; the environment-variable pattern in the basic example is the one to follow.
Chain of thought, templates and structured output
Above the transport layer, gollm ships task-level helpers. ChainOfThought is described as a pre-built function for reasoning tasks, and the README groups it with the prompt engineering features rather than with the provider code. Prompt Templates are a separate mechanism from NewPrompt's builder methods. Structured output is the feature with the most concrete promise: JSON schema generation and validation, so that a model's response is checked against a schema rather than parsed optimistically. Model comparison is also built in, described as testing performance across providers and models for the same task, which is the natural companion to a provider abstraction. Memory retention is offered as a way to keep context across interactions, configured through SetMemory, which the README's quick reference shows taking a value of 4096. Treat these as convenience layers over the same Generate call. The README does not document, in the material available, what happens when schema validation fails, whether the error is retried, or whether the raw model output is preserved for debugging. Those are the questions that decide whether structured output is usable in a service that cannot afford to drop a response.
The prompt optimizer is the weakest-documented part
The README lists a Prompt Optimizer as a key feature: it refines prompts automatically, with support for custom metrics and different rating systems. It appears in the quick reference and again in advanced usage. What the README does not provide, in the material available here, is a worked example of the optimizer API, the list of built-in metrics, or an explanation of how many model calls an optimization run costs. That last point matters more than it looks. Any optimizer that rates prompts needs to evaluate them, and evaluation means inference calls. If the optimizer runs N candidates against M examples, your bill scales with N times M, and the README gives no guidance on bounding that. There is also a circularity worth naming: the optimizer uses an LLM to judge prompts intended for an LLM. Custom metrics exist precisely because the default rating may not match your task, which is an admission that the default is a guess. None of this means the optimizer is broken. It means it is the feature to read the source for before you depend on it, and the feature most likely to change between versions.
Where gollm is the wrong choice
If you only ever call one provider, gollm adds a layer between you and the vendor SDK without removing any work. You lose direct access to that provider's newest parameters on the day they ship, because gollm has to expose them first, and you take on the upgrade cadence of a third-party package. The OpenRouter options are a good illustration: fallback_models and auto_route are reachable only through SetOption with string keys, which means a typo in an option name is a runtime problem rather than a compile error. If your team needs compile-time guarantees about which provider features are in use, a typed per-provider client is a better fit. There is also the question of what the abstraction cannot hide. Providers differ in token counting, in system-prompt handling, in whether they support JSON schema enforcement or only JSON mode, and in rate-limit semantics. gollm's README lists the providers it supports and states that retries are built in, but it does not claim to normalize these differences, and it would be unreasonable to expect it to. A unified interface over divergent backends will always leak somewhere. The practical consequence is that switching providers in gollm is cheap at the call site and expensive at the prompt and validation layers, where provider behaviour actually differs.
Alternatives and the difference in approach
The obvious comparison is LangChainGo, which also targets Go and multiple providers. The approaches differ in where the structure lives. LangChainGo is built around composable chains and a larger ecosystem of integrations, so the unit of work is a pipeline of steps you assemble. gollm's unit of work is a single LLM value plus a prompt, with the higher-level behaviours (chain of thought, optimization, comparison) shipped as functions rather than as composable graph nodes. That makes gollm smaller and easier to read end to end, and it makes LangChainGo more suitable when your application is genuinely a multi-step pipeline with branching. A second alternative is to skip the abstraction and use the official provider SDKs directly, wrapping them behind an interface you define. That interface will be narrower than gollm's, tailored to the two or three methods your application actually calls, and it will not include a prompt optimizer or a model comparison harness. For a service with a fixed provider and a small number of call sites, that is less code than adopting gollm and configuring it. The choice comes down to whether you want the task-level helpers. If you do, gollm is the smaller dependency. If you do not, the abstraction is overhead.
Licence and the cost of tracking upstream
gollm is Apache-2.0. That is a permissive licence with an explicit patent grant, and it permits commercial use, modification and redistribution provided you keep the licence and notice files and state significant changes. It is compatible with being vendored into a proprietary Go service. This is not legal advice, and if your organisation has a policy on patent clauses or notice obligations, run the licence text past whoever owns that policy. On maintenance cost, the material available here shows no retrieved releases, which means version pinning is the only reliable way to control what you get: pin a commit or tag in go.mod rather than tracking main, because a provider abstraction changes whenever a provider changes its API. The package is not archived and the last push is recent, but a single-maintainer project with a broad provider surface has a specific failure mode. When one provider ships a breaking API change, the fix lands in gollm and you wait for it, or you fork. Budget for that by keeping your own call sites behind a thin interface so that replacing gollm later is a contained change rather than a rewrite.
Editorial conclusion
Adopt gollm if you are writing Go services that need to talk to more than one LLM provider and you want the provider switch to be a SetProvider call rather than a rewrite. Do not adopt it if you need a stable, documented optimizer API or if your prompts are simple enough that a single provider SDK would do. Before committing, verify three things in the repository: the provider implementations under the llms package, how structured output validation behaves when the model returns malformed JSON, and whether the optimizer's default metric suits your task.
Community notes