Skip to main content

LLM Ledger

A production-ready Python SDK wrapping LiteLLM with deterministic caching, provenance tracking, and full audit trail.

Features

  • ✅ Deterministic Caching - SHA256-based content hashing for reproducible results
  • ✅ Provenance Tracking - Full metadata and source tracking
  • ✅ Audit Trail - Complete ledger of all LLM interactions
  • ✅ Token Accounting - Automatic token usage and cost estimation
  • ✅ Multi-Provider - Supports all LiteLLM providers (Anthropic, OpenAI, Azure, etc.)
  • ✅ Request Persistence - SQLite/PostgreSQL storage with full audit trail
  • ✅ Retry Logic - Automatic retry with exponential backoff via LiteLLM
  • ✅ Async Support - Full async/await support for high throughput
  • ✅ Type Safe - Complete type hints with Pydantic models

Installation

pip install llm-ledger

Or install from source:

git clone <repo>
cd llm-ledger
pip install -e .

Quick Start

Basic Usage

from llm_ledger import LedgerClient

client = LedgerClient()
response = client.quick_complete("Explain quantum computing in simple terms")
print(response)

Fluent Builder Pattern

response = (
    client.completion()
    .model("claude-sonnet-4")
    .system("You are a helpful assistant")
    .user("Summarize the key points from this document...")
    .temperature(0.0)
    .max_tokens(4000)
    .with_metadata(
        workflow_id="document_processing",
        chunk_id="section_3"
    )
    .execute()
)

print(f"Response: {response.content}")
print(f"Tokens: {response.usage.total_tokens}")
print(f"Cost: ${response.cost_estimate:.4f}")

With Full Provenance

from llm_ledger import LLMRequest, ProvenanceMetadata

metadata = ProvenanceMetadata(
    workflow_id="data_processing",
    chunk_id="chunk_12",
    section_id="section_3.2",
    source_id="document_v2.json",
    character_range=(1500, 2300),
    tags={"stage": "extraction"}
)

request = LLMRequest(
    model="claude-sonnet-4",
    messages=[
        {"role": "system", "content": "You are a helpful assistant"},
        {"role": "user", "content": "Analyze this text..."}
    ],
    temperature=0.0,
    metadata=metadata
)

response = client.complete(request)

Async Usage

import asyncio

async def process_chunks():
    requests = [create_request(chunk) for chunk in chunks]
    responses = await asyncio.gather(*[
        client.complete_async(req) for req in requests
    ])
    return responses

responses = asyncio.run(process_chunks())

Configuration

Environment Variables

Create a .env file:

# API Keys
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...

# Database
LLM_DATABASE_URL=postgresql://user:pass@localhost/llm_gateway

# Cache
LLM_CACHE_BACKEND=redis  # or "memory"
REDIS_URL=redis://localhost:6379/0
LLM_CACHE_TTL=3600  # seconds, 0 = no expiration

# Features
LLM_ENABLE_CACHE=true
LLM_ENABLE_PERSISTENCE=true

# Defaults
LLM_DEFAULT_MODEL=claude-sonnet-4
LLM_DEFAULT_TEMPERATURE=0.0
LLM_DEFAULT_MAX_TOKENS=4000

Programmatic Configuration

from llm_ledger import LedgerClient
from llm_ledger.cache import RedisCache

client = LedgerClient(
    cache_backend=RedisCache("redis://localhost:6379/0"),
    database_url="postgresql://localhost/llm_gateway",
    enable_cache=True,
    enable_persistence=True,
    default_model="claude-sonnet-4"
)

Caching

The SDK uses deterministic SHA256-based caching:

# First call - executes against LLM
response1 = client.quick_complete("What is machine learning?", temperature=0.0)
print(response1.from_cache)  # False
print(response1.latency_ms)  # e.g., 1200ms

# Second call - returns from cache
response2 = client.quick_complete("What is machine learning?", temperature=0.0)
print(response2.from_cache)  # True
print(response2.cache_key)   # SHA256 hash

# Different parameters = cache miss
response3 = client.quick_complete("What is machine learning?", temperature=0.5)
print(response3.from_cache)  # False

Cache statistics:

stats = client.get_stats()
print(stats["cache_hit_rate"])  # e.g., 0.67

Persistence & Querying

All requests and responses are automatically persisted:

# Query by provenance metadata
requests = client.query_requests(
    workflow_id="data_processing",
    chunk_id="chunk_12"
)

# Retrieve specific request/response
request = client.get_request(request_id)
response = client.get_response(response_id)

# Get token usage summary
from datetime import datetime
usage = client.persistence.get_token_usage_summary(
    start_date=datetime(2024, 1, 1),
    end_date=datetime(2024, 12, 31)
)

Advanced Features

Custom Retry Logic

LiteLLM handles retries automatically, configure via:

response = client.complete(
    request,
    num_retries=5,
    timeout=600  # 10 minutes
)

Batch Processing

requests = [create_request(text) for text in texts]
responses = await asyncio.gather(*[
    client.complete_async(req) for req in requests
])

Cache Control

# Bypass cache
response = client.complete(request, use_cache=False)

# Clear entire cache
client.clear_cache()

# Invalidate specific request
client.cache.invalidate(request)

Production Deployment

With PostgreSQL and Redis

from llm_ledger import LedgerClient
from llm_ledger.cache import RedisCache

client = LedgerClient(
    cache_backend=RedisCache("redis://prod-redis:6379/0"),
    database_url="postgresql://user:pass@prod-db/llm_gateway",
    enable_cache=True,
    enable_persistence=True,
    cache_ttl=86400  # 24 hours
)

With Docker Compose

services:
  app:
    environment:
      - LLM_DATABASE_URL=postgresql://postgres:password@db/llm_gateway
      - REDIS_URL=redis://redis:6379/0
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
  
  db:
    image: postgres:15
    
  redis:
    image: redis:7

Testing

from llm_ledger.testing import MockLLMClient

# For unit tests
mock_client = MockLLMClient()
mock_client.add_response("test prompt", "test response")

response = mock_client.quick_complete("test prompt")
assert response == "test response"

License

Apache 2.0 License

Contributing

Contributions welcome! Please see CONTRIBUTING.md for guidelines.

Metadata

Release files for llm-ledger 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for llm-ledger 0.1.1
File Size Uploaded
llm_ledger-0.1.1.tar.gz 15.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for llm-ledger 0.1.1
File Interpreter ABI Platform
llm_ledger-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 28.6 kB

Release files / llm_ledger-0.1.1.tar.gz

Download URL llm_ledger-0.1.1.tar.gz
Size 15.0 kB
Tags Source
SHA-256 checksum
How to use checksums
885b4d2879673e77a6dbc8410d05d2789376206ffeb743de27c76529cbe62db3
BLAKE2b-256 checksum
How to use checksums
b628ae2b5f0c945068a97386ea1142e5e44d84fa580eb1b78da626acbe9c0ac9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.9

Release files / llm_ledger-0.1.1-py3-none-any.whl

Download URL llm_ledger-0.1.1-py3-none-any.whl
Size 13.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
08f75b6bfdc8f32e960de307267696170e2b02e9cabc56a7eb4dcf702c24da17
BLAKE2b-256 checksum
How to use checksums
cd8703de8e36718f6b52fe0c31d79bf8bb699262d882e4f27ae0d1bbdfbf9e3e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.9

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page