Skip to main content

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 @llmguard decorator
  • โšก 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


Download files

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

Source Distribution

llmguard_py-0.1.1.tar.gz (12.1 kB view details)

Uploaded Source

Built Distribution

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

llmguard_py-0.1.1-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

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

Hashes for llmguard_py-0.1.1.tar.gz
Algorithm Hash digest
SHA256 3bbb0e987c65e6346216109d057c3fc1d671cb9755e23ec854a6e50f8a22d140
MD5 4d2448e9f85dc73db92a5fdfe45448f5
BLAKE2b-256 a29a8df72758cf5d5a940ea783c466637093918d2e9119fa7946da955abc7f41

See more details on using hashes here.

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

Hashes for llmguard_py-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 833d7520db5fd51407af72c9aae854a1c795a23922efbedadb6dbd59562945be
MD5 cc40c72b3af9c347526027526e4933f4
BLAKE2b-256 6086578ba7659e386e5ec76c46398a81662be780d37324755e509505121d2616

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