Answers · AI evidence
How do I detect silent model drift between AI runs using recorded baselines and replayed inputs?
Last updated
TL;DR: Keep a fixed canary set of real inputs, run it on a schedule against the same model ID and settings, and compare each run with a recorded baseline on three levels: the identifiers the provider returns (reported model version, system_fingerprint where available), exact output hashes, and deterministic checks plus task metrics with confidence intervals. A changed identifier is a direct signal. A drop in exact-match rate on its own is weak, because sampling and batching make even temperature-0 outputs vary. A statistically clear drop in check pass rate or task accuracy, with the model ID unchanged, is silent drift. Record the baseline and every comparison run with signed receipts before you look at the result, so nobody can redraw the baseline after the fact. record_ai_run seals each run, verify_ai_run replays a new output against a baseline hash, and verify_recorder checks a disclosed stretch of your drift log.
What should I check, step by step?
1. Pick 50 to 500 canary inputs from real traffic, covering the tasks you care about, with inputs and expected properties frozen and hashed. Don't tune prompts on them.
- Pin everything you control: model ID, settings, prompt template commit, tool schemas, retrieved context (store it, don't re-retrieve). Drift you introduce yourself isn't model drift.
- Record a baseline run: for each item the output hash, the reported model value, system_fingerprint or modelVersion, deterministic check results (JSON schema valid, required fields present, no secrets, length) and a task score. Seal it before analysing.
- Run each item several times (for example 5) in the baseline, so you know the normal spread: exact-match rate between repeats and the natural variance of the score.
- Replay the same inputs on a schedule (daily, and after any provider announcement). Log identifiers first: any change in reported model version or fingerprint is a drift event to investigate even if scores look fine.
- Compare pass rates and scores against the baseline with an interval, not a single number: a two-proportion test or bootstrap interval on pass rate, and alert only when the change is outside the baseline's own run-to-run spread.
- Look at per-category and per-check results, not only the average. Drift often shows up as one format or task class breaking while the overall mean barely moves.
- When drift is confirmed, keep the evidence: baseline receipt, comparison receipt, the items that flipped and their outputs. That is what a provider support ticket or an internal incident review needs.
Silent drift is real and hard to see from inside one session
Chen, Zaharia and Zou (2023) measured GPT-3.5 and GPT-4 in March and June 2023 and found large behaviour changes on the same tasks under the same names, including a sharp drop in GPT-4's accuracy at identifying prime numbers and changes in how often generated code ran directly.
- Anthropic's September 2025 postmortem describes three overlapping infrastructure bugs (a routing error, output corruption and a compiler issue in token selection) that intermittently degraded Claude responses from early August to early September 2025, with no model change. Anthropic wrote that its own evaluations didn't capture the degradation and that it would run quality evaluations continuously on production systems. The same idea works from the customer side.
- Because the model ID didn't change in either case, a config audit would have shown nothing. Only replaying fixed inputs and comparing results with a recorded baseline shows it.
Why exact output matching alone gives false alarms
OpenAI describes seed as best effort and says determinism is not guaranteed. Thinking Machines' 2025 write-up on nondeterminism in LLM inference shows a main cause: kernels that aren't batch-invariant, so the same prompt at temperature 0 can produce different tokens depending on server load.
- So treat a changed output hash as a hint and use it to choose items to inspect. Use the baseline's repeat runs to learn the normal exact-match rate; a fall well below that rate, or flips concentrated in one task type, is more meaningful than any single mismatch.
- Deterministic checks are the most stable signal: valid JSON against a schema, required fields, refusal markers, length limits. They don't depend on wording, so a drop in their pass rate is hard to explain by sampling noise.
Keeping the baseline honest
A drift claim is only as good as the baseline. If the baseline lives in a spreadsheet you can edit, anyone (including you) can argue it was adjusted after the fact. Seal the baseline run before analysing it: hash the per-item results file and record it with a signed timestamp.
- Record each comparison run the same way, with the same canary-set hash and settings hash, so a reader can see that the two runs are comparable and which one came first.
- If your agent keeps its own hash-chained log of drift checks and commits the head to a ledger, you can later disclose just the relevant stretch (for example the week drift started) and others can confirm it wasn't edited, without publishing the whole log.
How do I ask Rightshold about this (free, no key)?
Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “Seal today's drift-canary run: same canary-set hash and settings as the baseline, the reported model version and fingerprint, the results-file hash, and the pass rate of the JSON-schema check.”
{
"tool": "record_ai_run",
"arguments": {
"model": "gpt-4o-2024-08-06",
"provider": "openai",
"prompt_sha256": "<sha256 of the frozen canary set file>",
"output_sha256": "<sha256 of today's per-item results file>",
"params": {
"run": "drift-canary",
"baseline_receipt": "<air_ id of the baseline run>",
"settings_sha256": "<sha256 of pinned settings>",
"system_fingerprints": [
"<values returned today>"
],
"items": 200,
"repeats": 5,
"schema_pass_rate": 0.955,
"baseline_schema_pass_rate": 0.99
},
"ran_at": "2026-11-07T17:00:00Z"
}
}- Needs an API key. Seal the baseline the same way first, before you analyse it, and put its receipt id in each later run's params.
- verify_ai_run is free and keyless: send a baseline item's receipt id with today's output text to test whether it is byte-identical to the recorded output. A mismatch is a hint, not proof of drift, because outputs vary between identical requests.
- verify_recorder is free: if your agent keeps a signed, hash-chained drift log checkpointed with recorder_checkpoint, disclose the relevant entries and anyone can confirm they are unaltered and in order since the checkpoint time.
- Receipts are on Rightshold's append-only ledger, anchored to Bitcoin through OpenTimestamps. They prove what was recorded and when, not that drift happened or why.
Rightshold doesn't run your canary set or decide whether drift occurred. It signs and timestamps the run records and log checkpoints you send so the baseline and comparisons can be checked later. Not a monitoring service and not legal advice.
What are the sources?
- Chen, Zaharia, Zou (2023): How is ChatGPT's behavior changing over time? (arXiv:2307.09009)
- Anthropic: A postmortem of three recent issues (Sept 2025)
- Thinking Machines Lab: Defeating Nondeterminism in LLM Inference (2025)
- OpenAI API reference: Create chat completion (seed) and the chat completion object (system_fingerprint)
- Gemini API reference: GenerateContentResponse (modelVersion)
- Verified AI Runs on Rightshold
- Flight recorder on Rightshold
Related
- How to prove which model version, prompt and settings produced an AI output
- How to version an LLM judge and keep a frozen eval set so scores stay comparable
- How to report false-positive rates with confidence intervals on a frozen holdout
- How to make LLM eval results reproducible and tamper-evident
Not legal advice. JSON · Markdown · All answers
Get a free API key in one call
No card and no email needed. 100 free credits; the license and policy checks stay free without a key.
curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_... # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
-H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'
