OpenRouter-compatible LLM router with unified batch support. Route requests across OpenAI, Anthropic, and Google with a single API.
Project description
anymodel-py
OpenRouter-compatible LLM router with unified batch support. Self-hosted, zero fees.
Route requests across OpenAI, Anthropic, and Google with a single API. Add any OpenAI-compatible provider. Run as an SDK or standalone HTTP server.
Why anymodel?
One SDK, 11+ providers, no vendor lock-in. Swap models by changing a string, not rewriting your integration.
Self-hosted and transparent. Your API keys, your infrastructure, zero routing fees. Unlike OpenRouter, nothing passes through a third party.
Native batch APIs (OpenAI, Anthropic, Google) run at 50% cost with zero config. For other providers, anymodel falls back to concurrent execution automatically.
Zero provider SDK dependencies. The only runtime requirement is httpx. Server mode is drop-in compatible with the OpenAI SDK, so existing code works without changes.
Install
pip install anymodel-py
For server mode, install with the server extra:
pip install anymodel-py[server]
Quick Start
Set your API keys as environment variables:
export OPENAI_API_KEY=sk-...
export ANTHROPIC_API_KEY=sk-ant-...
export GOOGLE_API_KEY=AIza...
SDK Usage
from anymodel import AnyModel
client = AnyModel()
response = await client.chat.completions.create(
model="anthropic/claude-sonnet-4-6",
messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)
Streaming
stream = await client.chat.completions.create(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "Write a haiku"}],
stream=True,
)
async for chunk in stream:
print(chunk.choices[0].delta.content or "", end="", flush=True)
Supported Providers
Set the env var and go. Models are auto-discovered from each provider's API.
| Provider | Env Var | Example Model |
|---|---|---|
| OpenAI | OPENAI_API_KEY |
openai/gpt-4o |
| Anthropic | ANTHROPIC_API_KEY |
anthropic/claude-sonnet-4-6 |
GOOGLE_API_KEY |
google/gemini-2.5-pro |
|
| Mistral | MISTRAL_API_KEY |
mistral/mistral-large-latest |
| Groq | GROQ_API_KEY |
groq/llama-3.3-70b-versatile |
| DeepSeek | DEEPSEEK_API_KEY |
deepseek/deepseek-chat |
| xAI | XAI_API_KEY |
xai/grok-4 |
| Together | TOGETHER_API_KEY |
together/meta-llama/Llama-3.3-70B-Instruct-Turbo |
| Fireworks | FIREWORKS_API_KEY |
fireworks/accounts/fireworks/models/llama-v3p3-70b-instruct |
| Perplexity | PERPLEXITY_API_KEY |
perplexity/sonar-pro |
| Ollama | OLLAMA_BASE_URL |
ollama/llama3.3 |
Ollama runs locally with no API key. Just set OLLAMA_BASE_URL (defaults to http://localhost:11434/v1).
Fallback Routing
Try multiple models in order. If one fails, the next is attempted:
response = await client.chat.completions.create(
model="",
models=[
"anthropic/claude-sonnet-4-6",
"openai/gpt-4o",
"google/gemini-2.5-pro",
],
route="fallback",
messages=[{"role": "user", "content": "Hello"}],
)
Batch Processing
Process many requests with native provider batch APIs or concurrent fallback. OpenAI, Anthropic, and Google batches run server-side at up to 50% cost. Other providers fall back to concurrent execution automatically.
Submit and wait
results = await client.batches.create_and_poll(
model="openai/gpt-4o-mini",
requests=[
{"custom_id": "req-1", "messages": [{"role": "user", "content": "Summarize AI"}]},
{"custom_id": "req-2", "messages": [{"role": "user", "content": "Summarize ML"}]},
{"custom_id": "req-3", "messages": [{"role": "user", "content": "Summarize NLP"}]},
],
)
for result in results.results:
print(result.custom_id, result.response.choices[0].message.content)
Native batches (OpenAI, Anthropic, Google) are processed asynchronously on the provider's infrastructure. For all other providers, anymodel runs requests concurrently with adaptive rate limiting. See Advanced Usage for BatchBuilder, submit-now-check-later, adaptive concurrency, and batch configuration.
Server Mode
Run as a standalone HTTP server compatible with the OpenAI SDK:
anymodel serve --port 4141
Point any OpenAI-compatible client at http://localhost:4141/api/v1. See Advanced Usage for the full endpoint reference.
Configuration
client = AnyModel(
anthropic={"api_key": "sk-ant-..."},
openai={"api_key": "sk-..."},
google={"api_key": "AIza..."},
aliases={
"default": "anthropic/claude-sonnet-4-6",
"fast": "anthropic/claude-haiku-4-5",
"smart": "anthropic/claude-opus-4-6",
},
defaults={
"temperature": 0.7,
"max_tokens": 4096,
"retries": 2,
"timeout": 120,
},
)
# Use aliases as model names
response = await client.chat.completions.create(
model="fast",
messages=[{"role": "user", "content": "Quick answer"}],
)
Configuration can also be loaded from an anymodel.config.json file. Both camelCase and snake_case keys are accepted (apiKey or api_key, pollInterval or poll_interval). See Advanced Usage for config file details and resolution order.
Built-in Resilience
- Retries: Automatic retry with exponential backoff on 429/502/503 errors (configurable via
defaults.retries) - Rate limit tracking: Per-provider rate limit state from response headers. Automatically skips rate-limited providers during fallback routing.
- Adaptive concurrency: Auto mode discovers your provider's actual rate limit ceiling using TCP-style slow-start + AIMD, reading
x-ratelimit-remaining-requestsheaders proactively. - Parameter translation:
max_tokensautomatically sent asmax_completion_tokensfor newer OpenAI models. Unsupported parameters stripped before forwarding. - Smart batch defaults: Automatic
max_tokensestimation per-request in batches. Calculates safe values from input size and model context limits, preventing truncation and overflow without manual tuning. - Memory-efficient batching: Concurrent batch requests are streamed from disk. Only N requests (default 5) are in-flight at a time, making 10K+ request batches safe without memory spikes.
- High-volume IO: All batch file operations use concurrency-limited async queues with atomic durable writes (temp file + fsync + rename) to prevent corruption on crash.
See Advanced Usage for tool calling, structured output, BatchBuilder, adaptive concurrency, custom providers, transforms, generation stats, auto pricing, and more.
See Also
| Package | Description |
|---|---|
| anymodel | TypeScript version of this package |
| anymodel-go | Go version of this package |
| @probeo/anyserp | Unified SERP API router for TypeScript |
| @probeo/workflow | Stage-based pipeline engine for TypeScript |
Support
If anymodel is useful to you, consider giving it a star. It helps others discover the project.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file anymodel_py-0.6.3.tar.gz.
File metadata
- Download URL: anymodel_py-0.6.3.tar.gz
- Upload date:
- Size: 65.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
70234b563a883f233ef70229293e628a98c0169bfc7b2c4df6959e942384f0e9
|
|
| MD5 |
3da079ee67f002c1723e3d2be7992f1c
|
|
| BLAKE2b-256 |
2b8476a1cd9a4362fa05714044743899f88847b11b178fdab45b6aa3480b02f2
|
File details
Details for the file anymodel_py-0.6.3-py3-none-any.whl.
File metadata
- Download URL: anymodel_py-0.6.3-py3-none-any.whl
- Upload date:
- Size: 66.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7620e2c87af0fcbe91f8fce8b567c64d44cb459bb73275fefeea847fcef422cb
|
|
| MD5 |
3c33370919b6958bac42278528fdf53a
|
|
| BLAKE2b-256 |
26a3ff4c4b566c127f91a5d8015d4f37109b1480c6756320bc6226f85c5477d9
|