A lightweight Python decorator for caching, rate limiting, and retrying LLM API calls.
Project description
llmguard โ A Lightweight Python Decorator for Reliable LLM API Calls
A lightweight Python library that wraps any LLM API call (or any external, flaky, rate-limited API) with response caching, token-bucket rate limiting, automatic retries with exponential backoff, and usage statistics using a single decorator.
Instead of repeatedly solving these problems in every project, llmguard provides a reusable, production-friendly solution with a clean and simple API.
Why I Built This
While developing my AI Resume Matcher project using the Gemini API, I repeatedly encountered the same issues during development:
- Running the same prompt multiple times consumed API credits unnecessarily.
- Temporary API failures interrupted requests.
- Rate limits caused delays and failed requests.
- There was no simple way to measure how much caching was reducing API usage.
Rather than solving these problems inside one application, I extracted them into a reusable Python package that can be integrated into any LLM-powered project.
Features
- ๐ Simple
@llmguarddecorator - โก In-memory TTL response caching
- ๐ Automatic retries with exponential backoff and jitter
- ๐ชฃ Token-bucket rate limiting
- ๐ Built-in usage statistics
- ๐ฐ Estimated API cost savings
- ๐ฅ๏ธ Command-line interface for viewing statistics
- ๐งช Comprehensive unit tests
- ๐ฆ Packaged as a reusable Python library
Installation
Install from source
git clone https://github.com/aadhya-code/llmguard.git
cd llmguard
pip install -e .
Build the package
python -m build
Quick Start
from llmguard import llmguard
@llmguard(
cache_ttl=3600,
max_calls_per_period=10,
period_seconds=60,
max_retries=3,
cost_per_call=0.002
)
def ask_llm(prompt: str) -> str:
return call_some_llm_api(prompt)
# First call โ API request
response = ask_llm("Explain Retrieval-Augmented Generation")
# Second identical call โ Served from cache
response = ask_llm("Explain Retrieval-Augmented Generation")
Example
from llmguard import llmguard
@llmguard(
cache_ttl=1800,
max_calls_per_period=30,
period_seconds=60,
max_retries=5,
)
def generate(prompt):
return llm.generate(prompt)
print(generate("Summarise this research paper"))
CLI Usage
View usage statistics:
llmguard-stats
Example output:
llmguard usage stats
================================
Total wrapped calls: 47
Cache hits: 19
Cache misses: 28
Cache hit rate: 40.4%
Total retries used: 3
Rate-limit waits: 5
Estimated $ saved: $0.0380
Reset statistics:
llmguard-stats --reset
How It Works
Response Caching
- Generates a SHA-256 hash using the function name and arguments.
- Returns cached responses for identical requests.
- Supports configurable Time-To-Live (TTL) expiration.
Token-Bucket Rate Limiting
- Smoothly limits request rate.
- Prevents bursts that commonly occur with fixed-window rate limiters.
- Blocks only when necessary.
Automatic Retry
- Retries failed requests using exponential backoff.
- Adds random jitter to prevent retry storms.
- Raises a descriptive exception if all retry attempts fail.
Usage Statistics
Records:
- Total wrapped calls
- Cache hits
- Cache misses
- Retry count
- Rate-limit waits
- Estimated API cost savings
Statistics are persisted locally so they remain available across different program executions.
Project Structure
llmguard/
โ
โโโ llmguard/
โ โโโ __init__.py
โ โโโ cache.py
โ โโโ retry.py
โ โโโ rate_limiter.py
โ โโโ guard.py
โ โโโ stats.py
โ โโโ cli.py
โ
โโโ tests/
โ โโโ test_cache.py
โ โโโ test_retry.py
โ โโโ test_rate_limiter.py
โ โโโ test_guard.py
โ
โโโ pyproject.toml
โโโ README.md
โโโ LICENSE
Architecture
User Function
โ
โผ
@llmguard(...)
โ
โโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโ
โผ โผ โผ
TTL Cache Retry Handler Token Bucket
โ โ โ
โโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโ
โผ
External LLM API
Running Tests
Run all tests:
pytest -v
Generate a coverage report:
pytest --cov=llmguard
Version
Current Version:
v0.1.0
Future Improvements
- Async (
async/await) support - Persistent cache backend (SQLite/Redis)
- Additional provider examples (Gemini, OpenAI, Anthropic)
- GitHub Actions CI/CD
- Benchmark suite
- Configurable logging
License
This project is licensed under the MIT License.
Contributing
Contributions, suggestions, and bug reports are welcome.
If you find an issue or have an improvement, feel free to open an issue or submit a pull request.
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 llmguard_py-0.1.1.tar.gz.
File metadata
- Download URL: llmguard_py-0.1.1.tar.gz
- Upload date:
- Size: 12.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3bbb0e987c65e6346216109d057c3fc1d671cb9755e23ec854a6e50f8a22d140
|
|
| MD5 |
4d2448e9f85dc73db92a5fdfe45448f5
|
|
| BLAKE2b-256 |
a29a8df72758cf5d5a940ea783c466637093918d2e9119fa7946da955abc7f41
|
File details
Details for the file llmguard_py-0.1.1-py3-none-any.whl.
File metadata
- Download URL: llmguard_py-0.1.1-py3-none-any.whl
- Upload date:
- Size: 10.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
833d7520db5fd51407af72c9aae854a1c795a23922efbedadb6dbd59562945be
|
|
| MD5 |
cc40c72b3af9c347526027526e4933f4
|
|
| BLAKE2b-256 |
6086578ba7659e386e5ec76c46398a81662be780d37324755e509505121d2616
|