# any-llm: Mozilla's Python SDK for One Interface Across LLM Providers

> any-llm is a Python package from Mozilla that puts OpenAI, Anthropic, Mistral, Ollama and dozens more behind one completion() call. The pitch is real, but the provider extras and the LiteLLM migration path are where the decisions get made.

**mozilla-ai/any-llm** — Communicate with an LLM provider using a single interface

- Repository: https://github.com/mozilla-ai/any-llm
- Website: https://docs.mozilla.ai/any-llm
- Stars: 2,204 · Forks: 227
- Language: Python
- License: Apache-2.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/mozilla-ai-any-llm

## The problem any-llm removes: provider lock-in at the call site

Every provider ships its own Python client with its own request shape, its own auth story and its own response object. A codebase that talks to two providers ends up with two call paths, two sets of error types and two places to change when a model is deprecated. any-llm compresses that to one function. The README states the goal plainly: "Communicate with any LLM provider using a single, unified interface." Switching providers becomes a change to the provider argument rather than a rewrite.

The audience is Python developers building tooling that has to be provider-agnostic. Mozilla's own any-agent is cited in the README as a production consumer, which is the strongest signal in the repository about who this is built for. It is not aimed at teams that have standardized on one vendor and never intend to move; for them the abstraction is a layer of indirection with no payoff.

## How any-llm dispatches a call: extras, official SDKs, and two entry points

The mechanism is deliberately thin. any-llm does not reimplement HTTP calls to each provider. The README says it "Leverages official provider SDKs," and pyproject.toml confirms it: the anthropic extra pulls anthropic>=0.119.0,<1, the gemini and vertexai extras pull google-genai>=1.70.0, the bedrock extra pulls boto3, and mistral pulls mistralai>=2.0.0. The base install already depends on openai>=2.18.0, pydantic>2,<3, httpx and openresponses-types, so the OpenAI-shaped response object is available without any extra.

That design has a consequence worth naming. Because each provider is a separate extra, the set of providers you can reach is exactly the set you installed. There is no runtime plugin discovery described in the README. The all extra enumerates the full list in pyproject.toml, and it is long: mistral, anthropic, huggingface, gemini, vertexai, vertexaianthropic, cohere, cerebras, fireworks, gmi, groq, bedrock, azure, azureanthropic, azureopenai, cascadia, watsonx, together, sambanova, ollama, moonshot, neosantara, nebius, xai, databricks, deepseek, inception, openai, otari, openrouter, portkey, qiniu, requesty, lmstudio, llama, voyage, perplexity, platform, llamafile, llamacpp, sagemaker, github, zai, minimax, mzai, vllm, dashscope, deepinfra, atlascloud, telnyx, edenai, kenari and meta.

There are two entry points and the README is explicit about when to use each. The module-level completion() function is described as "Recommended for Bootstrapping and Experimentation" and creates a new client per call, which the README labels stateless. The AnyLLM class, created with AnyLLM.create(), is "Recommended for Production" because it reuses the client and therefore the connection pool. The README's own comparison table states both approaches support identical features: streaming, tools, responses API. The difference is connection handling, not capability.

A second surface exists for providers that implement the OpenAI-style Responses API. The responses() and aresponses() functions take an input_data argument instead of messages, and the README notes that a non-streaming call returns "an OpenAI-compatible Responses object alias" whose text is read via result.output_text.

## Installing any-llm and making a first call

The package name on PyPI is any-llm-sdk, not any-llm. The README requires Python 3.11 or newer, and pyproject.toml sets requires-python = ">=3.11", so a 3.10 interpreter will not install it. Install only the providers you need:

```bash
pip install 'any-llm-sdk[openai]'           # Just OpenAI
pip install 'any-llm-sdk[mistral,ollama]'   # Multiple providers
pip install 'any-llm-sdk[all]'              # All supported providers
```

Then export the key for whichever provider you chose. The README lists OPENAI_API_KEY, ANTHROPIC_API_KEY and MISTRAL_API_KEY as examples and notes you can also pass keys directly in code.

```bash
export MISTRAL_API_KEY="your-key-here"
export OPENAI_API_KEY="your-key-here"
```

A first call uses the separate provider and model parameters, which the README calls the recommended form:

```python
from any_llm import completion
import os

assert os.environ.get('MISTRAL_API_KEY')

response = completion(
    model="mistral-small-latest",
    provider="mistral",
    messages=[{"role": "user", "content": "Hello!"}]
)
print(response.choices[0].message.content)
```

What you should see is the assistant text printed from response.choices[0].message.content, the same access path you would use with the OpenAI client. The README documents an alternative combined syntax, model="mistral:mistral-small-latest", in the form <provider_id>:<model_id>. For repeated calls, AnyLLM.create() is the production-shaped variant:

```python
from any_llm import AnyLLM

llm = AnyLLM.create("mistral", api_key="your-mistral-api-key")

response = llm.completion(
    model="mistral-small-latest",
    messages=[{"role": "user", "content": "Hello!"}]
)
```

If you are on an OpenAI-compatible gateway or local server that has no dedicated provider entry, the README points to a "Custom OpenAI-compatible Endpoints" page in the docs rather than telling you to write your own adapter.

## Migrating from LiteLLM to any-llm: what actually changes

The README addresses LiteLLM users directly and the claim is narrow: "Your API keys and environment variables carry over unchanged." That is a statement about credentials, not about behaviour. What changes is the import and the model string format. LiteLLM's slash-separated model="openai/gpt-4o" becomes any-llm's colon-separated model="openai:gpt-4o", and the import moves from litellm to any_llm.

```python
# before
from litellm import completion
response = completion(model="openai/gpt-4o", messages=[...])

# after
from any_llm import completion
response = completion(model="openai:gpt-4o", messages=[...])
```

The README calls that "the full migration, no proxy, no extra config," and for the simple completion path that is a fair description. The honest caveat is that the README says only that API keys and environment variables carry over; it does not claim that every LiteLLM feature maps one-to-one, and it directs readers to the Supported Providers page to map existing model strings. If your LiteLLM usage leans on features outside completion, streaming and tools, treat the mapping page as required reading before you delete the old import.

## Where any-llm is the wrong layer: proxies, non-Python services, and the all extra

any-llm is a library, not a gateway. If you need budget management, API key management, usage analytics or multi-tenant support, the README does not solve that in-process; it points to a separate project, mozilla-ai/otari. Teams that assumed the SDK would also centralize spend control will be installing a second component.

The second limitation is language. The repository is Python, the package requires Python 3.11 or newer, and nothing in the README describes bindings for other runtimes. A Go or TypeScript service cannot import this. For those, a proxy that speaks HTTP is the right shape and any-llm is not.

The third is the all extra. Because provider support is expressed as optional dependencies, installing any-llm-sdk[all] pulls in every provider SDK in that list, including boto3, the google-genai stack and the anthropic vertex variant. That is a large dependency surface for a project that may only ever call two providers, and it is entirely avoidable by naming the extras you use. The base install is comparatively light: pydantic, openai, openresponses-types, rich, httpx and typing_extensions.

Finally, the Responses API is conditional. The README frames responses() as being for "providers that implement the OpenAI-style Responses API," which implies the call is not universally available across the provider list. The README does not enumerate which providers qualify, so that has to be confirmed against the docs before you build on it.

## Alternatives to any-llm and the difference in approach

LiteLLM is the comparison the README itself invites, and it is the closest one. The practical difference visible here is the model string convention and the migration story: any-llm uses provider:model while LiteLLM uses provider/model, and any-llm's README claims environment variables carry over unchanged. Beyond that, the README does not attempt a feature-by-feature comparison, so a team choosing between them should test the specific calls they depend on rather than trusting the naming similarity.

The second alternative is not a library at all. If the requirement is centralized keys, budgets and analytics across services in several languages, the pattern is a gateway in front of the providers, and the README names mozilla-ai/otari for exactly that. The difference in approach is architectural: any-llm removes provider differences inside a Python process, while a gateway removes them at the network boundary so any client can benefit. They are complementary, and the README treats them that way by linking out rather than folding the feature in.

The third option is doing nothing. If you call one provider and have no plans to move, the provider's own SDK gives you its full feature set on day one, including anything the provider ships after any-llm's last release. The unified interface is only worth its indirection when the second provider is a real possibility.

## Maintenance, licence and the upgrade cost you are signing up for

The repository is not archived. The last push was on 2026-09-09, and the most recent release listed is 1.27.1 on 2026-09-04, with 1.27.0 the day before and 1.26.0 on 2026-08-17. That cadence suggests active work, and the version numbering is worth noting: the project is past 1.27, so the API is not in a 0.x churn phase.

The licence is Apache-2.0, declared both in the repository and in pyproject.toml as license = {text = "Apache-2.0"}. That is a permissive licence with an explicit patent grant, and it is compatible with commercial use. This is not legal advice; if you are redistributing the package or bundling it into a product, read the LICENSE file in the repository root and get your own counsel.

The upgrade cost is concentrated in one place: the optional-dependencies table. Adding a provider means adding an extra, and removing one means editing an install line. The base dependency on openai>=2.18.0 and anthropic>=0.119.0,<1 means provider SDK majors can move under you, and the anthropic upper bound is pinned below 1, so a future anthropic 1.x will require an any-llm release before you can adopt it. That is a normal consequence of wrapping official SDKs, but it is the coupling you accept in exchange for not writing the adapters yourself.

## Conclusion

Adopt any-llm if you are writing Python 3.11+ code that needs to reach several providers and you want the provider choice to be a string rather than an architecture. Skip it if your stack is not Python, if you only ever call one provider, or if you need a proxy that sits in front of non-Python services; the project points at mozilla-ai/otari for that. Before committing, verify three things: that the provider you actually need has an extra listed in pyproject.toml, that your existing model strings map cleanly through the provider:model form, and that the Responses API path is implemented for your provider rather than only for OpenAI.

## FAQ

### Is any-llm open source?

Yes. The repository declares the Apache-2.0 licence, and pyproject.toml repeats it as license = {text = "Apache-2.0"}. The source lives at mozilla-ai/any-llm on GitHub.

### Is the any-llm API free to use?

The SDK itself is Apache-2.0 licensed and installs from PyPI as any-llm-sdk. Any cost comes from the model providers you call, since you supply keys such as MISTRAL_API_KEY or OPENAI_API_KEY yourself.

### How do I use any-llm?

Install the SDK with an extra for your provider, set that provider's API key environment variable, then call completion() with model, provider and messages. The README shows the response text at response.choices[0].message.content.

### What is the any-llm alternative to LiteLLM?

The README positions any-llm against LiteLLM directly. Keys and environment variables carry over, but you change the import to any_llm and switch model strings from the provider/model form to provider:model, for example openai:gpt-4o.

### Does any-llm work with Claude Code?

The README does not mention Claude Code. It documents Anthropic as a supported provider through the anthropic extra, so Anthropic models can be called through completion(), but nothing in the documentation describes a Claude Code integration.

## Sources

- [License: Apache-2.0](https://github.com/mozilla-ai/any-llm/blob/main/LICENSE)
- [mozilla-ai/any-llm on GitHub](https://github.com/mozilla-ai/any-llm)
- [Project website](https://docs.mozilla.ai/any-llm)
- [README](https://github.com/mozilla-ai/any-llm/blob/main/README.md)
- [Releases](https://github.com/mozilla-ai/any-llm/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mozilla-ai-any-llm
