Skip to main content

Free-first LLM routing for Python: local Ollama -> OpenRouter free models -> paid Anthropic API, with automatic fallback and a savings ledger.

Project description

llm-cascade

CI PyPI License: MIT Python versions

Free-first LLM routing for Python: local Ollama ($0) -> OpenRouter free models ($0) -> paid Anthropic API, with automatic fallback and a savings ledger. Zero required dependencies.

Why

Most teams route every prompt to the same frontier model regardless of how hard the task actually is, and the API bill grows with usage instead of with value delivered. llm-cascade flips that: it tries the cheapest tier that can plausibly do the job first, and only escalates when that tier is unreachable or genuinely too weak for the task. In production, that means classification, extraction, and summarization run for $0 on a local model or a free cloud model, while code review, planning, and long-form writing still get a frontier model -- and if the paid API is ever down or out of credits, your scheduled jobs degrade to a free tier instead of crashing.

Install

pip install llm-cascade

The base package has zero required third-party dependencies. To use the paid Anthropic tier, install the extra:

pip install "llm-cascade[anthropic]"

Without it, the local (Ollama) and free-cloud (OpenRouter) tiers still work end to end -- you'll only see an error if a task actually routes to the paid tier and the SDK isn't installed.

Quickstart

from llm_cascade import route

result = route("summarize", "Paste a long document here...")
print(result.text)        # the completion
print(result.tier)        # which tier served it: trivial/local/cheap/light/heavy
print(result.model)       # e.g. "local:ollama", "openrouter:qwen/...", "claude-sonnet-5"
print(result.cost_usd)    # 0.0 for local/free-cloud tiers

Or from the command line:

llm-cascade "Summarize this text: ..." --task summarize
llm-cascade --routes   # show the tier ladder and task -> tier table
llm-cascade --stats    # show cumulative cost and free-vs-paid call counts

How routing works

Each call resolves a task name (or a tier name directly) to a tier, then runs that tier's provider chain in order until one succeeds:

Tier Chain Use for
trivial local Ollama only ($0) high-volume micro-tasks, never worth the network
local local Ollama ($0) -> OpenRouter free ($0) -> paid mechanical NLP: classify, extract, summarize, translate
cheap OpenRouter free ($0) -> paid manual opt-in tier, invoke directly with task="cheap"
light paid (Sonnet); free-cloud only if LLM_CASCADE_LIGHT_FREE=1 customer-facing copy that needs reliable polish
heavy paid (Opus), adaptive thinking, high effort real reasoning: code, review, planning, long-form

If the paid API call fails for any reason -- bad or revoked key, no credits, a provider outage, a network blip -- llm-cascade degrades to the free tiers instead of raising, so scheduled or automated callers don't break outright. It only raises once every tier has been tried and failed.

The default task -> tier table:

classify, extract, summarize, translate, chat  -> local
rewrite                                        -> light
code, review, plan, creative                   -> heavy

Anything not in that table falls back to default_task_tier (light by default). See config/routes.example.toml for the full, commented schema.

Configuration

Configuration is resolved with this precedence (lowest to highest):

  1. Built-in defaults.
  2. An optional TOML file: ~/.llm_cascade/routes.toml, or the path given in LLM_CASCADE_CONFIG.
  3. Environment variables, for the handful of settings that make sense as env vars.

Copy config/routes.example.toml to ~/.llm_cascade/routes.toml to add your own task names, retune which tier handles a task, or override model ids and pricing.

Environment variables:

Variable Purpose
ANTHROPIC_API_KEY Enables the paid tier (light/heavy, and the final safety net).
OPENROUTER_API_KEY Enables the free-cloud tier (OpenRouter :free models).
LLM_CASCADE_CONFIG Path to a TOML config file, instead of ~/.llm_cascade/routes.toml.
LLM_CASCADE_LOG_PATH Path to the savings ledger, instead of ~/.llm_cascade/log.jsonl.
LLM_CASCADE_LIGHT_FREE Set to 1 to try free-cloud first on the light tier too.
LLM_CASCADE_NO_FREE_CLOUD Set to any value to disable the free-cloud tier globally.
LLM_CASCADE_HTTP_REFERER / LLM_CASCADE_APP_TITLE Sent as HTTP-Referer / X-Title on OpenRouter requests (optional; omitted if unset).
LLM_CASCADE_OPENROUTER_MODEL / LLM_CASCADE_OPENROUTER_MODELS Override the free model (singular) or ordered list (comma-separated) tried on OpenRouter.
LLM_CASCADE_OLLAMA_BASE_URL Ollama server URL (default http://localhost:11434).

See .env.example for a copy-pasteable starting point.

Savings ledger

Every call -- free or paid -- appends one line to a JSONL ledger (~/.llm_cascade/log.jsonl by default). stats() / llm-cascade --stats summarize it:

$ llm-cascade --stats
{
  "paid_calls": 3,
  "free_calls": 41,
  "total_cost_usd": 0.0842,
  "by_model": {
    "local:ollama": 30,
    "openrouter:qwen/qwen3-next-80b-a3b-instruct:free": 11,
    "claude-sonnet-5": 3
  }
}

Comparison

Unlike heavier multi-provider routers, llm-cascade ships with zero required dependencies and a single opinionated cascade -- it's a routing policy you can read in one file, not a platform.

Contributing

Issues and pull requests are welcome at github.com/luandv92/llm-cascade. Before opening a PR:

pip install -e ".[dev,anthropic]"
ruff check .
pytest tests/ -v

Tests never touch real networks -- Ollama, OpenRouter, and the Anthropic SDK are all mocked (see tests/conftest.py).

License

MIT -- see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

llm_cascade-0.1.0.tar.gz (23.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

llm_cascade-0.1.0-py3-none-any.whl (20.0 kB view details)

Uploaded Python 3

File details

Details for the file llm_cascade-0.1.0.tar.gz.

File metadata

  • Download URL: llm_cascade-0.1.0.tar.gz
  • Upload date:
  • Size: 23.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for llm_cascade-0.1.0.tar.gz
Algorithm Hash digest
SHA256 12cefcbb259fa1eac006c066b4782df4b3da94e906b0b62d28d47a91f8d4569f
MD5 7f9ce669061257c0d91a26eea6dea46a
BLAKE2b-256 b9558008886b8ce0457dd2fa93a9a910fbc29aad178eecacddbd6865474e9dc4

See more details on using hashes here.

File details

Details for the file llm_cascade-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: llm_cascade-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 20.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for llm_cascade-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7fad0346dde1842ecbf0cbcb22606a4667535cd2fed4d89cf691cea12af50190
MD5 1051f38ed198607607c01f34eb3b983a
BLAKE2b-256 b12fc7bb463b82dd2b535c3ff2cf2de53f6e7cf9b867a932b3b7008c4655b53d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page