parry
Zero-config rate limiting, caching, and cost control for LLM calls.
One line to install. No rewrites. Works with OpenAI, Anthropic, LangChain and LlamaIndex.
Documentation: www.anshumanbuilds.dev/parry
Drop parry in front of any OpenAI or Anthropic client and get response caching, per-model rate limiting, cost tracking, budget limits and retry with backoff. You don't configure anything or change your call sites, and it doesn't lock you into its own SDK. The hot path (hashing, LRU cache, token buckets, the pricing ledger) is Rust, exposed through PyO3.
Install
pip install llm-parry
The package is published as llm-parry; you import it as parry. Wheels are abi3, so one wheel per platform covers Python 3.10 – 3.14.
From source (needs a Rust toolchain):
pip install "git+https://github.com/IND-Anshuman/parry.git"
Quickstart
import parry
import openai
parry.install() # ← this is the only line you add
client = openai.OpenAI()
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello"}],
)
# ↑ cached, rate-limited, cost-tracked, retried on transient failure
print(parry.stats())
# ParryStats(cache_hits=0, cache_misses=1, tokens_cached=0, total_cost_usd=0.000043, ...)
Run the same request again and it comes back from memory: no network round trip and no cost.
What you get for free
- ✅ Response caching: identical requests are served from an in-memory LRU (10,000 entries, 1 h TTL by default).
- ✅ Per-model rate limiting: a token bucket per
provider:model. The defaults match the providers' published tier-1 limits. - ✅ Cost tracking: per session and per model, and per day and lifetime when you turn on SQLite storage.
- ✅ Hard budget limits:
max_cost_usd=10raisesparry.BudgetExceededbefore the request that would cross the limit is sent. - ✅ Retry with exponential backoff and jitter on 429s, timeouts, connection errors, 5xx and overload. It honours
Retry-Afterand never retries 400/401/403/404. - ✅ Streaming: streams pass through untouched, are metered, and the assembled result is cached for the next non-streaming call.
- ✅ Sync and async clients,
.with_raw_response, the OpenAI Responses API, and Anthropicbeta.messages. - ✅ LangChain and LlamaIndex: both work through
install(), and both also have callback handlers.
Before / after
Before, every script reinvents the same thing:
for attempt in range(5):
try:
if prompt in my_cache:
return my_cache[prompt]
time.sleep(my_rate_limiter.wait_time("gpt-4o"))
r = client.chat.completions.create(model="gpt-4o", messages=msgs)
my_spend += r.usage.prompt_tokens * 2.5e-6 + r.usage.completion_tokens * 1e-5
if my_spend > BUDGET:
raise RuntimeError("over budget")
my_cache[prompt] = r
return r
except openai.RateLimitError:
time.sleep(2 ** attempt)
After:
parry.install(max_cost_usd=10)
r = client.chat.completions.create(model="gpt-4o", messages=msgs)
When to use parry
- Iterating on prompts and pipelines. Re-running a notebook or an eval script stops re-paying for every unchanged call.
- Batch jobs that hit 429s. The token bucket spaces requests out before the provider rejects them, and retries absorb the 429s that still happen.
- Agents and RAG apps with a spend ceiling.
max_cost_usdis a hard stop, andparry.stats()tells you where the money went, model by model.
When NOT to use parry
- Multi-process or multi-host deployments. The cache and rate limiter live in one process. Use a shared cache and an API gateway instead.
- High-concurrency distributed systems. Limits are per process, not coordinated across replicas.
- When you need sampled outputs to vary. Identical requests return the
same cached answer even at
temperature=1. Turn caching off withparry.install(cache=False)orwith parry.bypass():.
Configuration
from parry import Parry
guard = Parry(
cache=True, # response cache
rate_limit=True, # per-model token buckets
cost_tracking=True, # accumulate spend
retry=True, # retry transient failures
max_cost_usd=10.0, # hard stop (default: None)
cache_ttl=3600, # seconds (None = no expiry, still size-bounded)
cache_size=10_000, # entries; the cache is always bounded
on_rate_limit="wait", # or "raise" → parry.RateLimited
max_wait=60.0, # longest parry will wait for a rate-limit slot
max_attempts=3, # total attempts per request, including the first
storage="parry.db", # optional SQLite persistence (cache + ledger)
)
guard.set_rate_limit("gpt-4o", requests_per_minute=60)
guard.set_rate_limit("gpt-4o-mini", requests_per_minute=500, tokens_per_minute=200_000)
guard.set_pricing("my-finetune", input_per_million=3.0, output_per_million=12.0)
parry.install(guard) # whole process
with guard: # ...or just this block
...
guard.wrap(client) # ...or just this client
print(guard.stats.summary())
Every option, default and failure mode is documented in docs/configuration.md.
Integrations
LangChain. ChatOpenAI and ChatAnthropic call the official SDKs
underneath, so parry.install() covers them, caching included:
import parry
from langchain_openai import ChatOpenAI
parry.install()
llm = ChatOpenAI(model="gpt-4o-mini")
llm.invoke("What is a token bucket?") # second identical call is a cache hit
If you'd rather not hook the SDK globally, add the callback. It does rate limiting, budget enforcement and cost tracking, but not caching, because LangChain callbacks can't return a response:
from parry import Parry
from parry.integrations.langchain import ParryCallback
guard = Parry(max_cost_usd=5)
llm = ChatOpenAI(model="gpt-4o-mini", callbacks=[ParryCallback(guard)])
LlamaIndex.
from llama_index.core import Settings
from llama_index.core.callbacks import CallbackManager
from parry.integrations.llamaindex import ParryHandler
Settings.callback_manager = CallbackManager([ParryHandler(guard)])
More detail is in docs/integrations.md.
Benchmarks
Measured with benches/overhead_bench.py, which drives the
real OpenAI SDK through an in-memory HTTP transport. No network is involved,
so the difference between rows is parry's own cost. Release build:
| Path | Time per call | parry overhead |
|---|---|---|
| Unguarded SDK call (baseline, in-memory transport) | 604 µs | — |
| Guarded, cache miss | 669 µs | +65 µs (0.065 ms) |
| Guarded, cache hit (no HTTP at all) | 10 µs | 0.02× the baseline |
Linux x86_64, Python 3.13.5, openai 2.54.0, median of 5 batches of 1000 calls.
How it works
parry.install() replaces create on the SDK resource classes
(openai.resources.chat.completions.Completions, ...Responses,
anthropic.resources.messages.Messages and their async twins) with a thin
hook. On each call the hook finds the active guard and runs:
cache lookup → budget pre-check → rate-limit acquire → original create (with retry) → record cost → store in cache
With no active guard, the hook calls the original method directly. See docs/architecture.md.
Links
- Documentation: https://www.anshumanbuilds.dev/parry/
- Source: https://github.com/IND-Anshuman/parry
- Issues and pricing updates: https://github.com/IND-Anshuman/parry/issues
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
License
MIT. See LICENSE.
Metadata
Release files for llm-parry 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| llm_parry-0.1.0.tar.gz | 189.8 kB | With provenance | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| llm_parry-0.1.0-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| llm_parry-0.1.0-cp310-abi3-musllinux_1_2_x86_64.whl | CPython 3.10 | abi3 | Linux musl 1.2+ x86-64 | Details |
| llm_parry-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| llm_parry-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| llm_parry-0.1.0-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
| llm_parry-0.1.0-cp310-abi3-macosx_10_12_x86_64.whl | CPython 3.10 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 22.5 MB
Release files / llm_parry-0.1.0.tar.gz
| Download URL | llm_parry-0.1.0.tar.gz |
|---|---|
| Size | 189.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
073aaf950355e61aa8c7e971f96766c2c9c6ad07177640f47927dba1cd3ea5be
|
|
BLAKE2b-256 checksum How to use checksums |
6ea27617795911c5634a36db1fe51bcafac3c9fd08d07287e4c938319039cca8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logRelease files / llm_parry-0.1.0-cp310-abi3-win_amd64.whl
| Download URL | llm_parry-0.1.0-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 3.7 MB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
589ea0d0954d99815b26210cce831bc3a78dfe27cba0a294c17636b6b801bf25
|
|
BLAKE2b-256 checksum How to use checksums |
2d798cff4c5915e0bd3553b6b5a9fc26395517c0bff8e49b8b6a7eeb39d3b8ea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logRelease files / llm_parry-0.1.0-cp310-abi3-musllinux_1_2_x86_64.whl
| Download URL | llm_parry-0.1.0-cp310-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 4.0 MB |
| Tags | CPython 3.10 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
6df7f6307f4205d1aa5dd22718f6e906546479c4f7615edcdea1d14cefb0afe7
|
|
BLAKE2b-256 checksum How to use checksums |
29375d1f53e73dfa1f77b57b5ff45696cfa3176a75fbf7a9f0165be2a8af7edf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logRelease files / llm_parry-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | llm_parry-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 3.7 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
c87cd7d7bbde23d90571bcbb49b8228967ec537d8cfbe3ba995164eddd13307e
|
|
BLAKE2b-256 checksum How to use checksums |
576343e31c59669593d6ec87daf33f0da048ca1abd6c55b3f927d119771852f5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logRelease files / llm_parry-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | llm_parry-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 3.7 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
dd42ef2bd0be941f1d4d30b7b8defd2b1728f5fd9031416fbc1a16827b88ac7b
|
|
BLAKE2b-256 checksum How to use checksums |
c03d91fb7aa060500d12bb1afe69a897541ee0653b183b16931fdf094cef4838
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logRelease files / llm_parry-0.1.0-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | llm_parry-0.1.0-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 3.6 MB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
cb2a6d69f2aa7be0facfe2f537b17d4cc96a900c06bd819130e0417d027a5d21
|
|
BLAKE2b-256 checksum How to use checksums |
545a96901b563e96e735a154bcf9dfd43c108c040bd2c6ef1e205c2dfddc0e76
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logRelease files / llm_parry-0.1.0-cp310-abi3-macosx_10_12_x86_64.whl
| Download URL | llm_parry-0.1.0-cp310-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 3.7 MB |
| Tags | CPython 3.10 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
0826fdb0f7308343e826f15c896703b6f47551700daf2cd32af611533d2ce52b
|
|
BLAKE2b-256 checksum How to use checksums |
6ace52fb06b84576d247824e43f4f69d76f570abf3fd3e3a6a4ceb197395cac1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logSecurity for llm-parry 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 7 files in this release have been uploaded with provenance metadata.
Attestation for llm_parry-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.