LLM-as-a-Service runtime: reliable, observable, schema-validated inference
Project description
GenRuntime
LLM-as-a-Service platform for reliable, observable, schema-validated inference.
Why GenRuntime
Problem: Applications that call LLM provider APIs directly (e.g. Anthropic/OpenAI SDK) are fragile — no retries, no output validation, no observability. Failures and debugging are harder in production.
Solution: GenRuntime is a backend layer between your app and LLM providers. It adds retries (with backoff), schema-validated outputs (Pydantic), structured logging (JSON lines), and Prometheus metrics. Use it in code with from genruntime import generate or via HTTP POST /generate. One code path serves both (single source of truth).
Features
| Feature | Description |
|---|---|
| Retries | Exponential backoff on transient failures (network, 5xx, rate limit); configurable max retries |
| Schema validation | generate_structured(prompt, schema=YourModel) — parse JSON and validate with Pydantic; retry once on validation failure |
| Structured logging | Every request logged as one JSON line (request_id, model, latency_ms, tokens, status); no PII (prompt/response length only) |
| request_id | Unique ID per request in response and logs for tracing |
| Health & readiness | GET /health (liveness), GET /ready (config and env check; no provider ping) |
| Prometheus metrics | GET /metrics — request count, latency histogram, error count (by model/status) |
| Docker | Dockerfile and docker-compose; run API with env-based config |
| Multi-provider | Mock (no key), Anthropic Claude, and OpenAI; config-driven via GENRUNTIME_PROVIDER and GENRUNTIME_MODEL |
Architecture
Request flow: API → runtime → provider adapter → provider. The runtime handles retry, validate, and log. One code path serves both the Python library and the HTTP API (single source of truth).
Applications (Python or HTTP)
│
▼
┌─────────────────────────────────────┐
│ GenRuntime │
│ ┌─────────┐ ┌─────────┐ ┌───────┐ │
│ │ API │→ │ Runtime │→ │ Logger│ │
│ └─────────┘ └────┬────┘ └───────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ Providers │ │
│ └─────┬─────┘ │
└────────────────────┼─────────────────┘
▼
LLM providers (Claude, …)
Requirements
- Python 3.10+
Development setup
Use a virtual environment so project dependencies stay isolated from your system Python and other projects.
1. Create and activate a virtual environment
# Create (run from project root)
python -m venv .venv
# Activate — Windows (PowerShell)
.venv\Scripts\Activate.ps1
# Activate — Windows (CMD)
.venv\Scripts\activate.bat
# Activate — macOS / Linux
source .venv/bin/activate
2. Install the package in editable mode (with dev dependencies)
pip install -e ".[dev]"
This installs genruntime, anthropic, pydantic, fastapi, uvicorn, plus pytest, httpx, ruff for development.
3. Verify
python -c "import genruntime; print(genruntime.__all__)"
pytest tests/unit -v
The .gitignore already excludes .venv and venv/, so the environment is not committed.
Quick start
Option 1: Python library
pip install -e .
Set your API key (or use the mock provider without a key):
# Optional: use real Claude (required for GENRUNTIME_PROVIDER=anthropic)
set ANTHROPIC_API_KEY=your_key_here
# Or use OpenAI: set GENRUNTIME_PROVIDER=openai and OPENAI_API_KEY=...
# Or use mock provider (no key needed)
set GENRUNTIME_PROVIDER=mock
Then in Python:
from genruntime import generate
response = generate("Hello, world!")
print(response.text)
print(response.meta.request_id)
Basic usage (with defaults):
from genruntime import generate, configure
configure(model="claude-3-haiku-20240307")
response = generate("Explain neural networks simply")
print(response.text)
print(response.meta.latency_ms)
print(response.meta.request_id)
Structured output:
from pydantic import BaseModel
from genruntime import generate_structured
class Summary(BaseModel):
topic: str
summary: str
result = generate_structured("Summarize neural networks", schema=Summary)
print(result.parsed.summary)
print(result.meta.request_id)
Option 2: HTTP API with Docker
Build and run (pass your API key, or use mock):
docker build -t genruntime .
docker run -p 8000:8000 -e ANTHROPIC_API_KEY=your_key_here genruntime
Or with docker-compose (create a .env file with ANTHROPIC_API_KEY=... or set GENRUNTIME_PROVIDER=mock):
docker-compose up --build
Then call the API:
curl -X POST http://localhost:8000/generate ^
-H "Content-Type: application/json" ^
-d "{\"prompt\": \"Hello\"}"
On macOS/Linux use \ instead of ^ and single quotes:
curl -X POST http://localhost:8000/generate \
-H "Content-Type: application/json" \
-d '{"prompt": "Hello"}'
Health and readiness:
curl http://localhost:8000/health
curl http://localhost:8000/ready
Optional Prometheus metrics:
curl http://localhost:8000/metrics
Configuration
All runtime and API behaviour can be configured via environment variables (12-factor style; no secrets in code).
| Variable | Description | Default |
|---|---|---|
ANTHROPIC_API_KEY |
API key for Anthropic Claude (required if provider is anthropic) |
— |
OPENAI_API_KEY |
API key for OpenAI (required if provider is openai) |
— |
GENRUNTIME_PROVIDER |
Provider: anthropic, openai, or mock |
anthropic if ANTHROPIC_API_KEY set, else openai if OPENAI_API_KEY set, else mock |
GENRUNTIME_MODEL |
Default model (e.g. claude-3-haiku-20240307, gpt-4o-mini) |
claude-3-haiku-20240307 |
GENRUNTIME_TIMEOUT |
Request timeout in seconds | 60 |
GENRUNTIME_MAX_RETRIES |
Max retries on transient failure | 2 |
You can also set defaults in code with configure(model=..., timeout=..., max_retries=...) (see Public API below).
Public API (library)
The stable surface is 8 items. Everything else is internal.
| Item | Description |
|---|---|
generate(prompt, **options) |
Run inference; returns GenRuntimeResponse (.text, .meta). Options: model, timeout, max_retries, provider. |
generate_structured(prompt, schema, **options) |
Same as above; parses response as JSON and validates with Pydantic schema. Returns GenRuntimeStructuredResponse (.parsed, .meta). Retries once on validation failure. |
configure(**kwargs) |
Set default model, timeout, max_retries for function-based usage. |
GenRuntime |
Class with optional defaults; .generate() and .generate_structured() delegate to the same runtime. |
GenRuntimeResponse |
Response type: .text (str), .meta (GenRuntimeMeta). |
GenRuntimeStructuredResponse |
Response type: .parsed (Pydantic model), .meta (GenRuntimeMeta). |
GenRuntimeError |
Base exception for all runtime failures. |
ValidationError |
Raised when structured output fails schema validation after retries. |
Development
Run tests and lint:
pytest tests/unit tests/integration -v
ruff check .
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 genruntime-0.4.0.tar.gz.
File metadata
- Download URL: genruntime-0.4.0.tar.gz
- Upload date:
- Size: 16.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6c40f23c9a0d27c08db260b214ce30c707cbe45ca6be08f62e265081b96bcdf3
|
|
| MD5 |
d71546818b1212dda3a5fba935dffc85
|
|
| BLAKE2b-256 |
01e08c222fc9e46db863327c6a97f1a993396fc5a52c28bf153b0e11eba3b125
|
File details
Details for the file genruntime-0.4.0-py3-none-any.whl.
File metadata
- Download URL: genruntime-0.4.0-py3-none-any.whl
- Upload date:
- Size: 18.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ddc67b5a6fd79038b3d915b97a9e31af06723234de500f473fc133370c5f7713
|
|
| MD5 |
d8c3779db7dc30458bd5ba5e00b3689e
|
|
| BLAKE2b-256 |
c7e3c0d41d1767cc0a0cb0db48fc707ad73e41f03741c8bf7d32f5ce6dcb974c
|