Answers · AI evidence
How do I make LLM eval results reproducible and tamper-evident?
Last updated
TL;DR: Pin the exact model snapshot, record every generation setting (including seed and system_fingerprint), hash the dataset, prompts and scorer code, run several epochs and report the spread, then hash the final eval log and get the hash timestamped. Exact reruns usually aren't possible (seeds are best effort and models get retired), so the goal is a record that shows what ran and proves the results weren't changed afterwards.
What should I check, step by step?
1. Use a dated or pinned model ID (for example gpt-4o-2024-08-06), never a moving alias, and save the model value the API returns, since that's what actually answered.
- Record the generation settings: temperature, top_p, max tokens, seed, tools and system prompt. With OpenAI, also save system_fingerprint from each response, since it changes when the backend configuration changes.
- Hash the inputs: the dataset file, the prompt templates and the scorer or grader code (a git commit is fine). Put the hashes in the log.
- Run more than one epoch and report the spread, not just the best run. Sampling makes single runs noisy, and OpenAI calls seed best effort.
- Keep provider request and response ids. Inspect, for example, logs ModelEvent.request_ids and ModelOutput.response_id for OpenAI, Anthropic and several other providers.
- When the run is final, compute a SHA-256 of the log file and get that hash timestamped independently, so anyone can see if a score was edited later.
- If you edit scores after review, use a tool that keeps the history (Inspect's edit_score keeps the original value and provenance) and hash the edited log as a new version.
Why exact reproduction usually fails
OpenAI's API reference says seed makes a best effort to sample deterministically and determinism is not guaranteed. A changed system_fingerprint means the backend changed between runs.
- Models are retired. OpenAI's deprecations page lists shutdown dates and says GET /v1/models returns a shutdown_date for models that have one. After shutdown, an old eval can't be re-run on that model at all, so the saved log is the only record.
- Anthropic's models overview says every Claude model ID is a pinned snapshot, including the dateless IDs used from the 4.6 generation on, while for earlier models the short alias is a pointer that resolves to a dated ID. If your config used an alias, record the dated ID it resolved to.
What a good eval log contains
Inspect's EvalLog is a useful reference. It has the eval spec (task, model, creation time), the plan (solvers and generation config), aggregate results, token usage, and every sample with its input, output, target and score. inspect log export-config writes the run config back out so the same setup can be run again.
- The log is a file, and Inspect's docs show reading it, editing scores or tags, and writing it back. That's useful for corrections, but it means the file alone doesn't show the published numbers are the ones the run produced. A hash recorded and timestamped at the end of the run does.
- Keep the dataset hash next to the score. A result is meaningless if the test set changed between two runs being compared.
Deterministic checks versus model graders
Rules like 'is valid JSON matching this schema', 'contains no API keys' or 'matches this regex' give the same answer every time and can be re-checked by anyone with the output.
- Model-graded scores change with the grader model. Record the grader's model snapshot and prompt like any other model call, and treat its scores as less stable.
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: “Record a signed receipt for this eval run: the model snapshot, hashes of the dataset and of the final eval log, the seed, the scorer commit and when it ran.”
{
"tool": "record_ai_run",
"arguments": {
"model": "gpt-4o-2024-08-06",
"provider": "openai",
"prompt_sha256": "<sha256 of the dataset file>",
"output_sha256": "<sha256 of the final .eval log>",
"params": {
"seed": 42,
"temperature": 0,
"epochs": 5,
"scorer_commit": "<git sha>",
"accuracy": 0.87
},
"ran_at": "2026-10-30T14:00:00Z"
}
}- Needs an API key. Only hashes and the fields you send are recorded. The receipt is Ed25519-signed, timestamped by Rightshold's clock and written to its append-only ledger, whose blocks are also anchored to Bitcoin through OpenTimestamps. Later edits to the log won't match the hash.
- To have deterministic checks signed into the receipt, send one model output as text with checks such as [{"type": "json_schema", "schema": {...}}, {"type": "no_secrets"}]. Rightshold runs them and keeps only the hash of the text.
- verify_ai_run is free and needs no key: a reader sends the receipt id and the log to check it matches. The receipt doesn't prove the eval was well designed or that the named model produced the outputs.
Rightshold doesn't run your eval or score it. It records the hashes and settings you send, signs them and lets anyone check them later. Not legal advice.
What are the sources?
- OpenAI API reference: Create chat completion (seed)
- OpenAI API reference: The chat completion object (system_fingerprint)
- OpenAI: Deprecations (shutdown dates, shutdown_date field)
- Anthropic: Models overview (model IDs and aliases)
- Inspect AI: Log Files (EvalLog fields, request ids, editing logs, export-config)
- RFC 3161: Time-Stamp Protocol
- OpenTimestamps client
Related
- How to prove what an AI model said at a specific time
- How to stop an AI coding assistant from just agreeing with you
- How to log every AI agent tool call for audit
- Verified AI Runs
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}}'
