llm-diff ⚡
git diff, but for LLM behavior.
You swapped gpt-4o for gpt-4o-mini to cut costs. You upgraded Llama 3.1 to 3.2 because the benchmarks went up. Did your model's behavior actually get better — or did it just get chattier, start ignoring your formatting rules, and flip its answers when you rephrase a question?
Benchmarks measure capability. llm-diff measures behavior — and shows you exactly what changed, in the format every engineer already speaks: a diff.
- baseline ollama/qwen2.5:0.5b
+ candidate openai/gpt-4o-mini
One command. Three behavioral dimensions. Colored deltas. CI-friendly exit codes.
Install
pip install llm-diff
Quickstart
Compare a local Ollama model against an OpenAI model:
export OPENAI_API_KEY=sk-...
llm-diff ollama/qwen2.5:0.5b openai/gpt-4o-mini
Illustrative output (baseline vs candidate shown for clarity):
- baseline ollama/baseline-model
+ candidate openai/candidate-model
╭──────────────────────┬──────────────────┬──────────────┬──────────────┬────────╮
│ Dimension │ Metric │ - baseline │ + candidate │ Δ │
├──────────────────────┼──────────────────┼──────────────┼──────────────┼────────┤
│ Instruction Fidelity │ fidelity score │ 1.00 │ 0.50 │ -0.50 │
│ Verbosity Profile │ total words │ 41 │ 118 │ +77 │
│ │ preamble words │ 0 │ 9 │ +9 │
│ │ markdown headers │ 0 │ 3 │ +3 │
│ Reasoning Consistency│ consistency │ 1.00 │ 1.00 │ 0.00 │
│ Latency │ avg latency (s) │ 0.84 │ 1.92 │ +1.08 │
╰──────────────────────┴──────────────────┴──────────────┴──────────────┴────────╯
Δ = candidate − baseline · green improvement · red regression
More recipes:
# Two local models, fully offline
llm-diff ollama/qwen2.5:0.5b ollama/llama3.2:1b
# Any OpenAI-compatible server: vLLM, LM Studio, llama.cpp, TGI, ...
llm-diff openai/my-finetune openai/my-base \
--openai-base-url http://localhost:8000/v1
# Open-weight models via Hugging Face Inference Providers (OpenAI-compatible)
llm-diff "openai/meta-llama/Llama-3.3-70B-Instruct" "openai/Qwen/Qwen3-8B" \
--openai-base-url https://router.huggingface.co/v1 --api-key $HF_TOKEN
# Machine-readable report for dashboards and CI artifacts
llm-diff ollama/qwen2.5:0.5b openai/gpt-4o-mini --json > diff.json
# Audit the raw responses behind every score
llm-diff ollama/qwen2.5:0.5b ollama/llama3.2:1b --show-responses
Model specs are backend/model. Unprefixed specs fall back to --backend (default: ollama), and only the first slash is parsed — so HuggingFace-style ids like meta-llama/Llama-3.3-70B-Instruct pass through intact.
The three dimensions (MVP)
| Dimension | The question it answers | How it's scored |
|---|---|---|
| Instruction Fidelity | Does the model obey strict formatting constraints? | Probe demands exactly 3 bullets, no introduction. +0.5 for exactly 3 bullet lines, +0.5 for a clean start with zero preamble. |
| Verbosity Profile | How much does the model say, and how much of it is filler? | One open-ended explanation, measured three ways: total words, filler-preamble words ("Certainly! Here is…"), and markdown header count. |
| Reasoning Consistency | Does the same logic get the same answer when reworded? | Two isomorphic syllogisms with nonsense words (memorization-resistant). Score 1.0 if the Yes/No verdict survives the reframing, 0.0 if it flips. |
Every diff runs at temperature=0 by default, so results are as reproducible as the backends allow.
Built for CI
llm-diff speaks exit codes: 0 all probes succeeded, 1 fatal config error, 2 usage error, 3 partial diff (some probes failed — shown as ERR rows, never a crash). Transient failures (timeouts, 429s, 5xx) are retried with exponential backoff; hard failures surface immediately with actionable messages.
# .github/workflows/model-swap.yml (sketch)
- run: llm-diff ollama/current-prod ollama/candidate --json > diff.json
- run: python scripts/check_thresholds.py diff.json # gate on deltas
Native --fail-if "fidelity<0.8" gating is on the roadmap below.
Roadmap: from 3 dimensions to 7
The MVP battery is deliberately small — a fast smoke test, not a benchmark. The v1.0 goal is seven dimensions with a much larger, community-built probe set:
| # | Dimension | Status |
|---|---|---|
| 1 | Instruction Fidelity | ✅ shipped |
| 2 | Verbosity Profile | ✅ shipped |
| 3 | Reasoning Consistency | ✅ shipped |
| 4 | Hallucination Propensity — does the model invent facts, citations, and APIs under pressure? | 🔜 planned |
| 5 | Refusal Sensitivity — does the model over-refuse benign requests, and did that change between versions? | 🔜 planned |
| 6 | Domain Retention — did niche knowledge (SQL dialects, legal terms, medical vocab) survive the new release? | 🔜 planned |
| 7 | Sycophancy Drift — does the model cave and change correct answers when the user pushes back? | 🔜 planned |
Also planned for v0.2: custom probe packs via YAML (llm-diff a b --probes my_domain.yaml), N-way comparison matrices, a native hf/ backend prefix for Hugging Face Inference Providers, and --fail-if threshold gating for CI.
Contributing
The most valuable thing you can contribute is a probe set. The three built-in probes prove the mechanism; the community can make it comprehensive. If you know how models should behave in your domain — medicine, law, code review, customer support, your native language — you can encode that knowledge as probes + scorers, no ML expertise required.
Great first contributions:
- Probe packs — propose a set of prompts + expected behaviors for one dimension (open an issue with the
probe-packlabel to discuss the format). - Scorers — every scorer is a pure function of response text in
llm_diff/scorers.py, trivially unit-testable. Sharpen the heuristics or add new ones. - Backends — the transport layer in
llm_diff/core.pyis ~100 lines per backend.
Dev setup:
git clone https://github.com/SiddharthFX/llm-diff
cd llm-diff
pip install -e ".[dev]"
pytest # fully offline — tests run against a bundled mock backend
See CONTRIBUTING.md for guidelines. Adding a dimension end-to-end touches exactly three places: a prompt in probes.py, a score_* function in scorers.py, and one hook in evaluate() — the table, summary, JSON report, and exit codes pick it up automatically.
Research
This tool exists to answer a bigger question: do successive LLM releases trade behavioral fidelity for benchmark scores? Read the study design in WHITEPAPER.md — and help us run it.
License
MIT © 2026 Pluto AI Research Lab
Metadata
Release files for pluto-llm-diff 0.1.0
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 | Actions |
|---|---|---|---|---|
| pluto_llm_diff-0.1.0.tar.gz | 28.2 kB | Without provenance | Details for pluto_llm_diff-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pluto_llm_diff-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for pluto_llm_diff-0.1.0-py3-none-any.whl |
Total release size: 51.4 kB
Release files / pluto_llm_diff-0.1.0.tar.gz
| Download URL | pluto_llm_diff-0.1.0.tar.gz |
|---|---|
| Size | 28.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3f49f233c44688729cb1f2ed145989ef3c4b25e20cf7fe6374028dff9b299398
|
|
BLAKE2b-256 checksum How to use checksums |
808bacb55eb0cbd037870a5124047d476d91f01e29fb2daab39cd526b639d6d1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.10
|
Release files / pluto_llm_diff-0.1.0-py3-none-any.whl
| Download URL | pluto_llm_diff-0.1.0-py3-none-any.whl |
|---|---|
| Size | 23.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
887884accb1dacca3682bad0dca115d414b8e7735805d206b94b024677ae4a33
|
|
BLAKE2b-256 checksum How to use checksums |
8024ea3ca5900440a3f83b10c55fc8566ed0688c168c90f73b0e4cf82077ceee
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.10
|
Security for pluto-llm-diff 0.1.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A 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.