promptmetrics
Production radar for LLM apps. Capture a baseline of live traffic, get alerted when latency, cost, or behavior drifts.
promptmetrics records every LLM call to a local SQLite database, computes a statistical fingerprint of "what good looked like at deploy time," and tells you when the recent window has drifted. Single file, pip-installable, no account, no SaaS bill.
Install
pip install promptmetrics
Requires Python 3.10+.
5-minute quickstart
1. Decorate the call you care about
from openai import OpenAI
from promptmetrics import track
client = OpenAI()
@track("summarize_v1", model="gpt-4o-mini")
def summarize(text: str):
return client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": f"Summarize: {text}"}],
)
That's it. Every call is appended to ~/.promptmetrics/promptmetrics.db with input, output, latency, and token counts. The decorator never raises if storage fails — your app keeps running.
2. Capture a baseline once you have history
promptmetrics baseline summarize_v1 --window 168
Summarises the last 7 days of traces (mean / p50 / p95 / p99 latency, mean tokens) and stores them as the active baseline.
3. Check for drift
promptmetrics check summarize_v1 --window 1
Compares the most recent hour against the baseline and prints a report. Exits non-zero on DRIFTED so it composes with cron, CI, and shell pipelines.
Try it without an LLM
git clone https://github.com/pallaprolus/promptmetrics && cd promptmetrics
pip install -e .
python demo.py
promptmetrics baseline demo --db ./demo.db --window 24 --min-samples 100
promptmetrics check demo --db ./demo.db --window 1
The demo.py script seeds 300 healthy traces and 60 deliberately drifted ones so you can see a real DRIFTED report on your first run.
What it detects
| Detector | Method | Default threshold |
|---|---|---|
| Latency | Kolmogorov–Smirnov test on the latency distribution plus a percentile-ratio check on p95 | WARNING at +15% p95, DRIFTED at +30% p95 |
| Cost | Mean total-tokens ratio vs baseline | WARNING at +15%, DRIFTED at +30% |
The KS test only fires when the recent window is slower than the baseline — a faster system is good news, not an alert.
Programmatic API
from promptmetrics import PromptMetrics
with PromptMetrics() as r:
baseline = r.capture_baseline("summarize_v1", window_hours=168)
report = r.check_drift("summarize_v1", window_hours=1)
print(report.severity)
for result in report.results:
print(result.drift_type, result.severity, result.detail)
Custom token / output extractors
If your call returns something promptmetrics can't introspect, pass extractors:
@track(
"rag_query",
extract_output=lambda r: r.answer,
extract_tokens=lambda r: (r.usage.input_tokens, r.usage.output_tokens),
)
def rag_query(question: str): ...
OpenAI- and Anthropic-style usage objects are detected automatically.
Sensitive data: prompts and outputs are stored verbatim
By default, @track writes the full input and output of every call to the local SQLite database. If your prompts contain PII, secrets, customer data, or anything you wouldn't want sitting in ~/.promptmetrics/ indefinitely, scrub it with the redact_input / redact_output hooks:
import re
from promptmetrics import track
EMAIL = re.compile(r"\b[\w.+-]+@[\w-]+\.[\w.-]+\b")
SSN = re.compile(r"\b\d{3}-\d{2}-\d{4}\b")
def scrub(text: str) -> str:
text = EMAIL.sub("[EMAIL]", text)
text = SSN.sub("[SSN]", text)
return text
@track("support_reply", redact_input=scrub, redact_output=scrub)
def reply(customer_message: str): ...
The redactor runs before the trace is written, so the raw values never touch disk. If your redactor raises, the trace is recorded with an empty string and the error is logged — pass raise_on_error=True to fail loudly instead.
The DB is a plain SQLite file at ~/.promptmetrics/promptmetrics.db (override with PromptMetrics(db_path=...) or --db). Treat it like any other file with sensitive data: back it up, encrypt the volume, or delete it on a schedule.
Strict mode for CI
@track("nightly_eval", raise_on_error=True)
def eval_run(): ...
By default the decorator never raises — observability shouldn't break production. In CI or eval pipelines where silent metric corruption is worse than a crash, set raise_on_error=True so extractor, redactor, and storage failures all surface as exceptions.
What's deliberately out of scope (for v0.1)
- Slack / Discord / PagerDuty alerting
- Semantic / quality drift (LLM-as-judge, embedding similarity)
- Hosted dashboard
- Multi-baseline versioning, A/B comparison
- Cloud sync
These are planned for v0.2+. The schema already reserves loop_id and step_index columns for the next feature on the roadmap: agent-loop drift detection for multi-step agents.
License
MIT
Metadata
Release files for promptmetrics 0.1.1
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 | |
|---|---|---|---|---|
| promptmetrics-0.1.1.tar.gz | 19.7 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| promptmetrics-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 36.4 kB
Release files / promptmetrics-0.1.1.tar.gz
| Download URL | promptmetrics-0.1.1.tar.gz |
|---|---|
| Size | 19.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f6963b3929e890edc1abe06ccf456561b54745ad81621d96b150397b6163aeba
|
|
BLAKE2b-256 checksum How to use checksums |
a5fee86c3815e86ea6f61fa1dd50e81ba47f935299b9da5e87af217267e8e91f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 May 3, 2026.
Transparency logRelease files / promptmetrics-0.1.1-py3-none-any.whl
| Download URL | promptmetrics-0.1.1-py3-none-any.whl |
|---|---|
| Size | 16.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0b4c582ccd9a0ead65c6592b8a71578e540007ce67400fb179c5e25aced0a8e4
|
|
BLAKE2b-256 checksum How to use checksums |
aa1dd2e61177a630c3788f63ae72f29cbfa297ca78b5f573c3a9045456cea229
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 May 3, 2026.
Transparency logSecurity for promptmetrics 0.1.1
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 2 files in this release have been uploaded with provenance metadata.
Attestation for promptmetrics-0.1.1.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 May 3, 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.