Smart LLM model router - auto-starts proviz-server binary, no Docker required
Project description
ProvizElekto
Smart LLM model router. Picks the best model for each call based on context size, rate limits, and capabilities — and retries automatically on failure.
Your app → pz.call(step, fn) → CallResult
pz.call_litellm(step, messages) → CallResult
↕ (automatic)
select → LLM call → report → retry on failure
↕
proviz-server (Rust)
rate-limit state · catalog
Key difference from LiteLLM fallback: LiteLLM retries after failure. ProvizElekto picks the right model before the call — skipping models that are rate-limited or near their quota, can't fit the context, or lack required capabilities — then retries with the next eligible model automatically.
Two roles depending on the path
In the regular flow, the server is a pure router — it picks the model and returns credentials; your code makes the actual LLM call.
In the batch flow, the server becomes the caller:
# Regular: YOUR code calls the LLM
Your app → POST /select → ModelCandidate → your code → Mistral/OpenAI/...
↓
POST /report
# Batch: the SERVER calls Mistral on your behalf
Worker A ──┐
Worker B ──┤ POST /batch/submit → server accumulates over window_secs
Worker C ──┘
↓ server → POST Mistral /v1/batch/jobs (50% discount)
↓ server polls until complete
Worker A ──┐
Worker B ──┤ GET /batch/result/{id} → response
Worker C ──┘
The batch path pools requests from all workers into a single Mistral job — the only way to qualify for Mistral's 50% batch discount. No individual worker can do this on its own, so the server acts as the aggregation point and makes the Mistral call itself.
Deployment note: when using batch, the server process (including Docker) must have the Mistral API key env vars set. In the regular flow, API keys only need to be present in the caller's environment.
Features
- Context-aware selection - don't waste a 128k model on a 1k prompt
- Proactive quota tracking - sliding-window counters (RPM/TPM/RPD/TPD) plus atomic in-flight reservations; avoids over-booking before any 429 fires
- Provider-anchored windows - every successful call forwards
x-ratelimit-remaining-*headers back to the server; the window floor is clamped to provider reality so internal estimates can't drift below what the provider actually sees - Scored selection - multi-component scoring: fast headroom (RPS/RPM/TPM, 25%), daily budget (RPD/TPD, 20%), quality (20%), cost (15%), latency (10%), traffic balance (10%). Over-quota models stay eligible with lower scores —
AllModelsExhaustedonly fires when every model is in reactive 429 cooldown. - Traffic shaping - per-brand
traffic_weightsteers load proportionally across providers in a 5-minute rolling window; under-served brands get a higher score on the traffic component - Capability filtering - hard requirements for function calling, JSON mode
- Quality floor - reject models below a quality threshold per step
- Model groups - define named pools of models (e.g.
"fast-chat","coding-tier1") and restrict selection to that pool - Your keys, your models - curated catalog, no vendor proxy
- Zero-infra -
pip install proviz-elektoauto-starts the Rust server as a subprocess - Any language - HTTP API, not a library binding
- Pluggable storage - SQLite (default) or PostgreSQL
Installation
ProvizElekto consists of a Rust server and various clients.
pip install proviz-elekto # core only
pip install proviz-elekto[litellm] # + built-in LiteLLM integration
The proviz-server binary is bundled in the wheel.
CLI tool (proviz) is also included:
proviz --help
Documentation
- Catalog Setup — Seeding brands/models, adding rules, model groups
- Selection Algorithm — Scoring, headroom, priority, quality scores, retry hints
- HTTP API Reference —
/select,/report,/health,/catalog/reload - Deployment & Docker — Running the server, env vars, Docker, building from source
- Data Model — Table schemas for all
pz_*tables
Quickstart
With LiteLLM (recommended)
from proviz_elekto import ProvizElekto
pz = ProvizElekto(db_path="./proviz.db")
# or PostgreSQL: pz = ProvizElekto(database_url=os.environ["DATABASE_URL"])
result = pz.call_litellm(
step="verdict",
messages=[{"role": "user", "content": "Summarize this document..."}],
estimated_tokens=2500,
requires_json_mode=True,
)
print(result.provider, result.candidate.model_slug, result.total_tokens)
# → mistral mistral-small-latest 312
call_litellm() selects the best available model, calls it, reports the outcome, and retries with the next eligible model on any failure — automatically.
With a custom LLM caller
import anthropic
client = anthropic.Anthropic()
def my_llm(candidate):
return client.messages.create(
model=candidate.model_slug,
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)
result = pz.call("verdict", my_llm, estimated_tokens=100)
print(result.candidate.brand_slug, result.prompt_tokens)
Pass any callable that accepts a ModelCandidate and returns a response. ProvizElekto wraps it with the same select → report → retry loop.
Low-level API
If you need direct control over selection and reporting:
candidate = pz.select(step="verdict", estimated_tokens=2500)
try:
response = my_llm_call(candidate)
# Read provider rate-limit headers (Mistral/OpenAI style; Anthropic style also supported)
hdrs = getattr(response, "_hidden_params", {}).get("additional_headers") or {}
rem_req = hdrs.get("x-ratelimit-remaining-requests")
rem_tok = hdrs.get("x-ratelimit-remaining-tokens")
pz.report_success(
candidate.model_id,
estimated_tokens=candidate.estimated_tokens, # releases in-flight reservation
actual_tokens=response.usage.total_tokens, # improves TPM window accuracy
remaining_requests=int(rem_req) if rem_req is not None else None,
remaining_tokens=int(rem_tok) if rem_tok is not None else None,
)
# report_success is fire-and-forget — returns immediately, HTTP call runs in background
except RateLimitError as exc:
msg = str(exc).lower()
if "day" in msg or "daily" in msg:
error_type = "tpd"
elif "token" in msg:
error_type = "tpm"
else:
error_type = "rpm"
pz.report_rate_limit(candidate.model_id, error_type) # synchronous — must complete before retry
except Exception:
pz.report_error(candidate.model_id, "other")
estimated_tokens in each report call releases the in-flight reservation made at selection time. Omitting it is safe (legacy clients work unchanged) but leaves the in-flight counter inflated until the next selection clears it.
report_success is non-blocking: the HTTP call to proviz runs in a background daemon thread so the caller receives the LLM result without waiting for the round-trip. report_rate_limit and report_error remain synchronous because the model must be blocked in proviz before the retry select() call.
License
Apache-2.0
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 Distributions
Built Distributions
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 proviz_elekto-0.9.5-py3-none-win_amd64.whl.
File metadata
- Download URL: proviz_elekto-0.9.5-py3-none-win_amd64.whl
- Upload date:
- Size: 4.2 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
81714dd38d1a5fdfdb230c316cfbe4688a82f9f7f4f1536ea33505040f3a68bb
|
|
| MD5 |
e0b34989bf3dc32b485f2fc616373d63
|
|
| BLAKE2b-256 |
4ebac03aba07d71277755d14665c97d4d918d8ba65501d94de089be90020e8b2
|
Provenance
The following attestation bundles were made for proviz_elekto-0.9.5-py3-none-win_amd64.whl:
Publisher:
release.yml on JustGui/proviz-elekto
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
proviz_elekto-0.9.5-py3-none-win_amd64.whl -
Subject digest:
81714dd38d1a5fdfdb230c316cfbe4688a82f9f7f4f1536ea33505040f3a68bb - Sigstore transparency entry: 1721123407
- Sigstore integration time:
-
Permalink:
JustGui/proviz-elekto@9190792782b15bb4384b4570c23f96b401db9b0e -
Branch / Tag:
refs/tags/v0.9.5 - Owner: https://github.com/JustGui
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9190792782b15bb4384b4570c23f96b401db9b0e -
Trigger Event:
push
-
Statement type:
File details
Details for the file proviz_elekto-0.9.5-py3-none-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: proviz_elekto-0.9.5-py3-none-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 5.1 MB
- Tags: Python 3, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
227cc7ad5579b1e1c5683423887beb598085c1903f35fb6dc97749b16dcb8013
|
|
| MD5 |
f77ce4d60c8e12a4a4d7bda1f9165847
|
|
| BLAKE2b-256 |
409b16bde24693048b2ba89b68cf536033b19fea77a9b98442704a69f6d4afd6
|
Provenance
The following attestation bundles were made for proviz_elekto-0.9.5-py3-none-musllinux_1_2_x86_64.whl:
Publisher:
release.yml on JustGui/proviz-elekto
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
proviz_elekto-0.9.5-py3-none-musllinux_1_2_x86_64.whl -
Subject digest:
227cc7ad5579b1e1c5683423887beb598085c1903f35fb6dc97749b16dcb8013 - Sigstore transparency entry: 1721123286
- Sigstore integration time:
-
Permalink:
JustGui/proviz-elekto@9190792782b15bb4384b4570c23f96b401db9b0e -
Branch / Tag:
refs/tags/v0.9.5 - Owner: https://github.com/JustGui
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9190792782b15bb4384b4570c23f96b401db9b0e -
Trigger Event:
push
-
Statement type:
File details
Details for the file proviz_elekto-0.9.5-py3-none-manylinux_2_36_x86_64.whl.
File metadata
- Download URL: proviz_elekto-0.9.5-py3-none-manylinux_2_36_x86_64.whl
- Upload date:
- Size: 4.9 MB
- Tags: Python 3, manylinux: glibc 2.36+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cf9954a1b8dfda8205e97091d788f562ef3e155894736316ad4ec83fc080cda0
|
|
| MD5 |
3eb9381e9fcf45160f29c82b8e03bb5d
|
|
| BLAKE2b-256 |
6e86a5543cd7f240df8ef58fb1bd6a318ed62a7acee9cb2e4fd20e4f52bb3d63
|
Provenance
The following attestation bundles were made for proviz_elekto-0.9.5-py3-none-manylinux_2_36_x86_64.whl:
Publisher:
release.yml on JustGui/proviz-elekto
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
proviz_elekto-0.9.5-py3-none-manylinux_2_36_x86_64.whl -
Subject digest:
cf9954a1b8dfda8205e97091d788f562ef3e155894736316ad4ec83fc080cda0 - Sigstore transparency entry: 1721123528
- Sigstore integration time:
-
Permalink:
JustGui/proviz-elekto@9190792782b15bb4384b4570c23f96b401db9b0e -
Branch / Tag:
refs/tags/v0.9.5 - Owner: https://github.com/JustGui
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9190792782b15bb4384b4570c23f96b401db9b0e -
Trigger Event:
push
-
Statement type:
File details
Details for the file proviz_elekto-0.9.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: proviz_elekto-0.9.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 4.7 MB
- Tags: Python 3, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8ad0275bf1a74ad81fc0c2974091d95f3bcbdc6f9e88c3b2c5f34db8746f30a
|
|
| MD5 |
cec41708e5678cf28922385793cbbe4f
|
|
| BLAKE2b-256 |
427eb7e65e346230363ff429fc3bf8f2faf66001d536406dd53e1cec0f29aaed
|
Provenance
The following attestation bundles were made for proviz_elekto-0.9.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
release.yml on JustGui/proviz-elekto
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
proviz_elekto-0.9.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
b8ad0275bf1a74ad81fc0c2974091d95f3bcbdc6f9e88c3b2c5f34db8746f30a - Sigstore transparency entry: 1721123203
- Sigstore integration time:
-
Permalink:
JustGui/proviz-elekto@9190792782b15bb4384b4570c23f96b401db9b0e -
Branch / Tag:
refs/tags/v0.9.5 - Owner: https://github.com/JustGui
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9190792782b15bb4384b4570c23f96b401db9b0e -
Trigger Event:
push
-
Statement type:
File details
Details for the file proviz_elekto-0.9.5-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.
File metadata
- Download URL: proviz_elekto-0.9.5-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
- Upload date:
- Size: 9.1 MB
- Tags: Python 3, macOS 10.12+ universal2 (ARM64, x86-64), macOS 10.12+ x86-64, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dae8049eafb2a1373301fca5c09286cce08cf775c17c02e59167af3202f073f9
|
|
| MD5 |
e571ef8f8ed878206f67d3c338a860a0
|
|
| BLAKE2b-256 |
2a60ad39212b069e7ef4423534908990e0acc77b667feea8739b1faa02a9103c
|
Provenance
The following attestation bundles were made for proviz_elekto-0.9.5-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:
Publisher:
release.yml on JustGui/proviz-elekto
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
proviz_elekto-0.9.5-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl -
Subject digest:
dae8049eafb2a1373301fca5c09286cce08cf775c17c02e59167af3202f073f9 - Sigstore transparency entry: 1721123121
- Sigstore integration time:
-
Permalink:
JustGui/proviz-elekto@9190792782b15bb4384b4570c23f96b401db9b0e -
Branch / Tag:
refs/tags/v0.9.5 - Owner: https://github.com/JustGui
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@9190792782b15bb4384b4570c23f96b401db9b0e -
Trigger Event:
push
-
Statement type: