Skip to main content

LLM-as-Judge

An open-source platform for evaluating LLM outputs with an LLM judge: pairwise comparison, pointwise and reference-based grading, multi-candidate ranking, and RAG and agent evaluation, with position-bias mitigation and reliability analytics. One engine powers a Python library, a CLI, a REST API and a Streamlit dashboard. It runs on free tiers (Groq, with openai/gpt-oss-120b by default), on local models with Ollama, or entirely offline with a clearly labelled mock judge.

Open in Streamlit CI Coverage CodeQL Live Ollama Docs Release PyPI Python 3.11 to 3.14 License: MIT

Live demo · Documentation · Getting started · Changelog · Contributing


Contents

More documents: Deployment · Architecture · API reference · Benchmarks · Security policy


Why this exists

"LLM-as-Judge" is a common pattern for scoring subjective qualities — creativity, tone, code readability, factual accuracy — where there is no exact-match ground truth. Doing it well in production requires more than a single API call, and this project handles the parts that usually get skipped:

  • Structured, validated output. The judge is pinned to a strict JSON schema (via the provider's JSON mode), and every response is validated with Pydantic. The returned criteria must match the requested ones exactly. A malformed reply gets a bounded "repair" retry that tells the judge what was wrong.
  • Position-bias mitigation. LLM judges tend to favour whichever answer is shown first. Optionally, each pair is judged in both orders (concurrently) and the scores are averaged, cancelling that bias. The explanations shown always agree with the averaged verdict.
  • Self-consistency. Out-of-range scores are clamped (and flagged), and winners are recomputed from the numbers, so the verdict never contradicts the scores. Criteria on different scales are normalised before they're combined.
  • Injection resistance. Candidate outputs are treated as untrusted data, wrapped in boundary markers that carry a random per-request token.
  • Bias diagnostics. Results carry warnings for suspected prompt injection, verbosity bias, self-preference risk and order-dependent verdicts.
  • Resilience. Transient provider failures (rate limits, timeouts, 5xx) are retried with exponential backoff; permanent errors fail fast.
  • Scale. A concurrent batch runner grades thousands of rows from CSV/JSONL, isolating per-row failures so one bad row never aborts the run.

Features

Capability Description
Library, CLI, UI & REST API One evaluation core, four ways to use it.
Evaluation modes Pairwise (A vs B), pointwise, reference-based, multi-candidate ranking, RAG (faithfulness, context precision/recall) and agent trajectories.
Judge reliability Repeated-judgment consistency with confidence intervals; inter-judge agreement (Cohen's kappa, Spearman).
Multi-criteria Score on several criteria at once (built-in or custom), with optional weights.
Bias mitigation Optional A/B order swapping to reduce position bias.
Reliability warnings Flags prompt injection, verbosity bias, self-preference and order sensitivity.
Retries & repair Backoff for transient errors; repair retries for malformed replies.
Experiment tracking Run history in SQLite (default) or PostgreSQL/Supabase, run comparison with confidence intervals, Markdown reports, and a regression gate for CI.
Datasets & batches CSV/JSON/JSONL/YAML validation, checkpointed and resumable batch runs, per-model summaries, bundled benchmark samples.
Fully tested Offline unit and property-based tests (Hypothesis), no network calls in CI.
Pluggable providers Groq, Ollama (local), any OpenAI-compatible API, and an offline mock; add your own by implementing one method.
Typed & linted Pydantic models, mypy-clean, ruff-clean and ruff format-clean.

Screenshots

The dashboard with the live Groq judge (openai/gpt-oss-120b). Try it in the live demo.

Playground: a pairwise verdict RAG evaluation results
Playground. A pairwise verdict with per-criterion scores, explanations and a verbosity-bias warning. RAG evaluation. Faithfulness, relevance and context metrics, with a verdict for every claim.
Experiments: comparing two runs Analytics: trends across runs
Experiments. A regression check between two recorded runs, with a confidence interval and a caveat that their judge instructions differ. Analytics. Score trends across recorded runs, computed only from stored results.

Installation

Python 3.11 or later is required. The package is on PyPI as llm-as-judge-platform; it installs the llm_judge library and the llm-judge command:

pip install llm-as-judge-platform              # library and CLI
pip install "llm-as-judge-platform[all]"       # plus dashboard, REST API, YAML, PostgreSQL

To run the dashboard or work on the code, clone the repository:

git clone https://github.com/syed-waleed-ahmed/LLM-as-Judge.git
cd LLM-as-Judge

python -m venv .venv
# Windows:  .venv\Scripts\activate
# Unix:     source .venv/bin/activate

# Library + UI + dev tooling
pip install -e ".[ui,dev]"

# Or everything (UI, REST API, YAML, PostgreSQL)
pip install -e ".[all]"

Every GitHub Release also has the wheel and sdist attached. The dashboard lives in app.py and dashboard/, so it runs from a clone.

Upgrading an environment from before 2.3.0? The distribution was renamed from llm-as-judge, so remove the old one first with pip uninstall llm-as-judge. Otherwise its files can shadow the new install.

Then configure your key:

cp .env.example .env      # then edit .env and set GROQ_API_KEY

Get a free key at https://console.groq.com/keys. No key yet? Every command works offline with --provider mock, a deterministic heuristic judge (clearly labelled, not an LLM), or locally with --provider ollama.


Usage

1. Web app (Streamlit)

streamlit run app.py

A multi-page dashboard over the same engine:

Page What it does
Overview Which judge is active, session and stored-run statistics, recent runs
Playground Compare two outputs, grade one, check against a reference, or rank candidates, with optional judge instructions, charts, explanations and warnings
Datasets Upload CSV/JSON/JSONL/YAML (or pick a sample), validate, evaluate, chart and download results
Benchmarks Run a bundled sample and see per-system statistics
RAG evaluation Faithfulness, answer relevance, context precision and recall, with claim-level verdicts
Agent evaluation Paste or upload a trace: deterministic checks plus a judged grade
Experiments Compare two recorded runs: verdict, confidence interval, per-row changes; download Markdown reports
Analytics Across recorded runs: score trends, score distributions, per-criterion comparison, bias signals and operational reliability
Reliability Repeated-judgment consistency and agreement between judges
Settings Judge temperature and tie margin for your session, provider status and health checks, limits in effect, storage, cache and privacy controls
About How the results stay honest, privacy, how to run it yourself

The sidebar switches between the live judge (when a key is configured) and the offline mock judge. The mock judge works without any key, and its results are always labelled as not coming from an LLM. Charts use a colorblind-validated palette with separate light and dark versions.

For a public deployment, set JUDGE_DEMO_MODE=true. That adds per-session and daily live-call budgets and input caps, and keeps each visitor's data session-only. See DEPLOYMENT.md for free Streamlit Community Cloud hosting.

2. Command line

# List built-in criteria (no API key required)
llm-judge list-criteria

# Judge a single pair
llm-judge evaluate \
  --task "Write a friendly tweet announcing our new AI tool" \
  --output-a "Meet our new AI assistant - it saves you hours every week. Try it free!" \
  --output-b "We have released a new artificial intelligence product." \
  --criteria "Creativity,Brand Tone Adherence" \
  --mitigate-bias

# Weight criteria and record which models produced each output
llm-judge evaluate --task-file task.txt \
  --output-a-file a.txt --output-b-file b.txt \
  --criteria "Helpfulness,Conciseness" --weights "Helpfulness=2" \
  --model-a gpt-4o --model-b llama-3.1-8b-instant

# Read long inputs from files and emit raw JSON
llm-judge evaluate --task-file task.txt \
  --output-a-file a.txt --output-b-file b.txt --json

# Give the judge your own guidance (also: grade, rank, batch, benchmark)
llm-judge evaluate --task-file task.txt \
  --output-a-file a.txt --output-b-file b.txt \
  --instructions "Penalise answers that state facts without a source."

# Grade a whole dataset concurrently (checkpointed; resumable with --resume)
llm-judge batch --input examples/sample_batch.csv \
  --output results.csv --criteria Helpfulness --workers 8

# Run a bundled benchmark sample and print per-model statistics
llm-judge benchmark summarization

# Grade one output on its own, or against an expected answer
llm-judge grade --task "Explain DNS" --output-file answer.txt
llm-judge grade --task "When did Apollo 11 land?" \
  --output "In 1969." --reference "Apollo 11 landed on the Moon on 20 July 1969."

# Rank several candidates (round robin, or --strategy pointwise for fewer calls)
llm-judge rank --task "Write a tagline" --candidates-file candidates.json

candidates.json is either {"id": "text", ...} or a list of {"id": ..., "output": ..., "model": ...} objects.

3. Python library

from llm_judge import Criterion, Judge, resolve_criterion

judge = Judge()  # reads config from environment / .env

result = judge.evaluate(
    task_description="Summarise the text in one sentence.",
    output_a="A concise, accurate one-line summary.",
    output_b="A rambling three-paragraph response.",
    criteria=["Helpfulness", "Conciseness"],
    candidate_a_model="gpt-4o",  # optional; recorded in metadata
)

print(result.overall_winner)  # Winner.A
print(result.overall_score_a)  # weighted, scale-normalised score (0-1)
for warning in result.warnings:  # reliability signals worth a second look
    print(warning.code, warning.message)

# Custom criteria can set their own scale and weight.
coverage = Criterion(
    name="Coverage", description="Covers every key point.", scale_min=0, scale_max=100, weight=2
)
judge.evaluate("...", "...", "...", [resolve_criterion("Helpfulness"), coverage])

# Optional guidance for the judge: how strictly to score, what to penalise.
# It's recorded in result.metadata["instructions"] and in experiment runs.
judge.evaluate(
    "...",
    "...",
    "...",
    "Accuracy",
    instructions="Penalise answers that state facts without a source.",
)

The same Judge also grades single outputs and ranks candidates:

# Pointwise: grade one output on its own merits.
grade = judge.evaluate_pointwise("Explain DNS.", answer, ["Helpfulness", "Conciseness"])
print(grade.overall_score, grade.feedback)

# Reference-based: compare with an expected answer (defaults to Correctness + Completeness).
check = judge.evaluate_reference("When did Apollo 11 land?", "In 1968.", reference="20 July 1969.")
print(check.unsupported_claims)  # hallucination indicators
print(check.missing_information)  # key points the output omits
print(check.reference_metrics)  # exact_match, token_f1, optional semantic_similarity

# Ranking: round robin (every pair head to head) or pointwise (cheaper).
ranking = judge.rank("Write a tagline", {"v1": "...", "v2": "...", "v3": "..."})
for row in ranking.leaderboard:
    print(row.rank, row.candidate, row.score, (row.wins, row.losses, row.ties))

Every method has an async twin (aevaluate, aevaluate_pointwise, aevaluate_reference, arank, aevaluate_rag, aevaluate_agent). Each one runs the evaluation in a worker thread, so you can await it from async code without blocking the event loop, and run several concurrently:

import asyncio

results = await asyncio.gather(
    judge.aevaluate(task, a, b, "Helpfulness"),
    judge.aevaluate_pointwise(task, a, "Conciseness"),
)

Set JUDGE_CACHE_SIZE (for example 256) to reuse results of identical evaluations: same inputs, criteria, instructions, judge and settings. The cache is opt-in, in memory only, and used only at temperature 0. Hits are marked metadata["cache_hit"], and they don't spend provider quota. Consistency analysis never uses it.

Every pairwise evaluation returns a validated, versioned result:

{
  "schema_version": "1.3",
  "criteria": [
    {
      "criterion": "Helpfulness",
      "output_a_score": 8.0,
      "output_b_score": 3.0,
      "output_a_explanation": "Directly and accurately answers the task.",
      "output_b_explanation": "Vague and largely off-topic.",
      "winner": "A"
    }
  ],
  "overall_winner": "A",
  "overall_comment": "Output A is clearly more helpful.",
  "overall_score_a": 0.7778,
  "overall_score_b": 0.2222,
  "warnings": [],
  "metadata": {
    "model": "openai/gpt-oss-120b",
    "judge": { "provider": "groq", "model": "openai/gpt-oss-120b" },
    "candidates": { "A": { "model": "gpt-4o" }, "B": { "model": null } },
    "prompt_version": "2.0",
    "position_bias_mitigated": false,
    "latency_seconds": 0.93
  }
}

4. REST API

pip install -e ".[api]"              # from a clone; included in ".[all]"
llm-judge serve                      # http://127.0.0.1:8000, docs at /docs
curl -s http://127.0.0.1:8000/api/v1/evaluate/pairwise \
  -H "Content-Type: application/json" \
  -d '{"task_description": "Explain DNS", "output_a": "...", "output_b": "...",
       "criteria": ["Helpfulness", {"name": "Accuracy", "weight": 2}]}'
Endpoint Purpose
POST /api/v1/evaluate/{pairwise,pointwise,reference,rank} Single evaluations
POST /api/v1/evaluate/{rag,agent} RAG and agent-trajectory evaluation
POST /api/v1/analysis/consistency, GET /api/v1/runs/agreement Judge reliability
POST /api/v1/evaluate/batch Small synchronous batches (JUDGE_API_MAX_BATCH_ROWS)
POST /api/v1/jobs, GET /api/v1/jobs/{id}[/rows], DELETE /api/v1/jobs/{id} Background dataset jobs (bounded queue, cancellable, idempotent with Idempotency-Key)
POST /api/v1/datasets/validate Validate rows or CSV/JSONL/JSON/YAML content
GET /api/v1/benchmarks, POST /api/v1/benchmarks/{name}/jobs Bundled sample benchmarks
GET /api/v1/experiments, /runs, /runs/{id}[/rows], /runs/compare Experiment history and regression checks
GET /api/v1/system/status, /providers, /criteria, /statistics, GET /health Service information

Protections, all configurable:

  • API keys. JUDGE_API_KEYS (comma-separated), sent as X-API-Key or Authorization: Bearer.
  • Admin routes. Deleting runs and listing all jobs are disabled unless JUDGE_API_ADMIN_KEY is set.
  • Rate limiting. A per-client limit, with Retry-After on 429.
  • Size limit. Request bodies over the limit get a 413.
  • Concurrency cap. Excess load gets a 503, so free-tier quotas aren't exhausted silently.

Every error uses one JSON envelope with a request id, and request logs are structured JSON without bodies. serve binds to localhost by default and warns when exposed without API keys.

No always-free host is assumed for the API. Run it locally or on your own infrastructure. The public demo (Streamlit) doesn't depend on it.


Reliability safeguards

Safeguard What it does
Neutral schema The prompt shows the output shape with placeholders, never example scores or winners that could anchor the judge.
Untrusted-content boundaries The task and outputs sit between markers that carry a random per-request token. The judge is told to treat them as data and to ignore embedded instructions.
Exact criteria matching The reply must contain every requested criterion exactly once (case-insensitive). Missing, extra or duplicate criteria are rejected, never guessed.
Repair retries A reply that is malformed or doesn't match the schema is sent back with the reason it was rejected, up to JUDGE_MAX_PARSE_RETRIES times.
Brace-aware recovery JSON embedded in stray prose is recovered with a real JSON decoder, not string slicing.
Scale normalisation and weights Each score is mapped to 0-1 on its own scale before the weighted overall score is computed.
Consistent bias merges With mitigation on, explanations come from the ordering that agrees with the averaged verdict. When neither ordering agrees, both are kept and labelled.

Results also carry warnings (they never change scores):

Code Meaning
possible_prompt_injection An output contains text aimed at manipulating the judge.
possible_verbosity_bias The winner is much longer than the other output (JUDGE_VERBOSITY_RATIO).
self_preference_risk A candidate model is from the judge's own model family.
position_inconsistent The verdict changed when the outputs were swapped.
score_out_of_range The judge scored outside the scale; the score was clamped.
input_truncated An input exceeded JUDGE_MAX_INPUT_CHARS and was truncated.
provider_fallback The primary provider failed and a configured fallback (JUDGE_FALLBACK_PROVIDERS) answered instead.

These signals are heuristics. A clean result doesn't prove the absence of bias or manipulation, and a warning doesn't prove its presence.


RAG, agents and judge reliability

RAG evaluation

result = judge.evaluate_rag(
    "What is the range of the Aurora 3?",
    contexts=["The Aurora 3 has a range of up to 80 km.", "Showroom hours: 10-18."],
    answer="Up to 80 km, and it comes with a free helmet.",
    reference="Up to 80 km.",  # optional: enables context recall
)
result.faithfulness  # 0.5: share of the answer's claims supported by the contexts
result.unsupported_claims  # ['It comes with a free helmet.']: possible hallucinations
result.context_precision  # average precision of the relevant contexts, in rank order
result.context_recall  # share of the reference covered by the contexts
result.answer_relevance  # how directly the answer addresses the question

The judge returns claim-level verdicts and the metrics are computed from them, so every number can be traced back to specific claims and passages. Retrieved passages are fenced as untrusted data and scanned for prompt injection. CLI: llm-judge rag --question ... --context ... --answer ....

Agent evaluation

judge.evaluate_agent(trace) takes a framework-agnostic trace: the task, the available tools, the ordered steps (thought, tool_call, tool_result, message) and the final answer. It returns two separate assessments:

  • Deterministic checks. Unknown tools, missing required arguments, malformed calls, failed tool results, repeated identical calls, step-budget overruns, expected tools never used, and a missing final answer.
  • A judged grade on Task Completion, Tool Selection and Step Efficiency (configurable), optionally against a reference answer.

CLI: llm-judge agent --trace-file trace.json.

Judge reliability

  • measure_consistency(judge, task, output_a=..., output_b=...) judges the same input repeatedly. It reports agreement with the modal verdict, the spread, and a bootstrap 95% CI. At temperature 0 this only shows provider nondeterminism, so raise JUDGE_TEMPERATURE to probe sensitivity. CLI: llm-judge consistency ... --samples 5 --temperature 0.7.
  • judge_agreement(store, run_a, run_b) compares two recorded runs over the same rows, typically by two different judges. It uses Cohen's kappa for winners, and Spearman correlation plus mean absolute difference for scores. CLI: llm-judge experiments agreement <run-a> <run-b>.

All intervals come from repeated samples. None of them is a model's self-reported confidence or a calibrated probability.


Datasets, batches and benchmarks

llm-judge batch evaluates whole datasets in CSV, JSON, JSONL or YAML (YAML needs the yaml extra, which all includes). The dataset kind is inferred from the columns:

Kind Required columns Optional
pairwise task_description, output_a, output_b id, model_a, model_b
pointwise task_description, output id, model
reference task_description, output, reference id, model

Common column names such as prompt, question, response and ground_truth are mapped automatically. An id column is optional; the row index is used if it's missing.

id,task_description,output_a,output_b,model_a,model_b
1,Write a tagline,"Fast. Simple. Yours.","Our product is good.",system-alpha,system-beta
llm-judge datasets validate data.csv     # kinds, duplicates, missing values, fingerprint
llm-judge batch --input data.csv --output results.csv --workers 8
llm-judge batch --input data.csv --output results.csv --resume   # after a crash or Ctrl+C
llm-judge batch --input big.jsonl --output sample.csv --sample 200 --seed 1

Batch runs are built for large, flaky workloads:

  • Checkpointing. Every finished row is appended to <output>.checkpoint.jsonl straight away. The checkpoint is deleted after a fully successful run and kept otherwise.
  • Resume. --resume skips rows that already succeeded and retries the failed ones. It refuses to continue if a row changed since it was checkpointed, so results from two dataset versions are never mixed.
  • Bounded resources. At most 2 x workers requests are in flight, and files over JUDGE_MAX_DATASET_BYTES or JUDGE_MAX_DATASET_ROWS are rejected before parsing.
  • Failure isolation. A failing row is recorded with its error and never aborts the run.

Each run ends with a summary: winners and per-model win rates for pairwise data, and mean scores per model, mean token F1 and rows with unsupported claims for graded data.

Benchmarks

Nine small, original, synthetic datasets ship with the package for demos and smoke tests: general_qa, code_generation, summarization, rag, instruction_following, safety, math_reasoning, customer_support and data_extraction. Their candidate "systems" are neutral labels, not real models.

llm-judge datasets samples                       # list them
llm-judge benchmark safety                       # run one with the configured judge
llm-judge --provider mock benchmark general_qa   # fully offline and reproducible
llm-judge benchmark my_dataset.jsonl --output rows.csv

These samples are tiny, so treat their numbers as a demonstration, not as evidence about real models.

Experiment tracking and regression detection

Add --experiment NAME to batch or benchmark to record the run in a local SQLite database (JUDGE_DB_PATH, default .llm_judge/experiments.db). That needs no server and no account.

To share runs across machines, point JUDGE_DB_PATH at a PostgreSQL URL instead. A free Supabase project works: install the extra (pip install -e ".[postgres]"), then set JUDGE_DB_PATH=postgresql://postgres.<ref>:<password>@<host>:6543/postgres, the "Transaction pooler" connection string from the project's Connect dialog. Tables are created on first use, and both backends store the same data. DEPLOYMENT.md covers choosing a pooler and keeping the tables out of Supabase's REST API.

Each run stores its per-row results with reproducibility metadata: dataset fingerprint, judge provider and model, prompt version, criteria, relevant settings, and the library and Python versions. Raw task text, outputs and references are not stored, only their hashes. Judge explanations may still quote them.

llm-judge batch --input qa_v1.jsonl --output v1.csv --experiment qa --run-name v1
llm-judge batch --input qa_v2.jsonl --output v2.csv --experiment qa --run-name v2
llm-judge experiments runs --experiment qa
llm-judge experiments compare <v1-run-id> <v2-run-id> --fail-on-regression

# A shareable Markdown report: how the run was judged, results, failures,
# reproducibility details, and (with --baseline) the comparison
llm-judge experiments report <v2-run-id> --baseline <v1-run-id> --output report.md
  mean: 0.574 -> 0.259 (change -0.315, 95% CI [-0.556, -0.093], bootstrap)
  verdict: REGRESSION
  rows regressed: 3; rows improved: 0
    worse  qa-1: 0.667 -> 0.000

Rows are paired by id. The comparison reports the mean paired difference with a seeded bootstrap 95% confidence interval (a normal approximation above 5,000 pairs), and gives a verdict of regression, improvement, no significant change or insufficient data. It also lists the rows that moved most. --fail-on-regression makes it usable as a CI gate. The runs are flagged as not directly comparable when they used a different judge, prompt version, criteria or bias setting.

These are judge-scored differences: the judge's own noise and biases are part of what is measured.


Configuration

All settings are read from the environment (or .env). See .env.example.

Variable Default Description
JUDGE_PROVIDER groq groq, ollama, openai_compatible or mock.
GROQ_API_KEY — Required for the groq provider.
GROQ_MODEL openai/gpt-oss-120b Groq-hosted model to use.
JUDGE_OLLAMA_BASE_URL http://localhost:11434 Ollama server.
JUDGE_OLLAMA_MODEL llama3.2 Local model to judge with.
JUDGE_OPENAI_BASE_URL — Base URL of an OpenAI-compatible API (e.g. .../v1).
JUDGE_OPENAI_MODEL — Model name on that endpoint.
JUDGE_OPENAI_API_KEY — Optional bearer token for that endpoint.
JUDGE_OPENAI_JSON_MODE true Send response_format: json_object (disable for servers that reject it).
JUDGE_FALLBACK_PROVIDERS (empty) Opt-in fallback providers, comma-separated and tried in order when the primary fails (not mock).
JUDGE_TEMPERATURE 0.0 Sampling temperature (0 = deterministic).
JUDGE_REQUEST_TIMEOUT 60 Per-request timeout in seconds.
JUDGE_MAX_RETRIES 3 Retries for transient failures.
JUDGE_MAX_PARSE_RETRIES 1 Repair retries for malformed or schema-violating replies.
JUDGE_MITIGATE_POSITION_BIAS false Judge each pair in both orders.
JUDGE_PARALLEL_BIAS_RUNS true Run the two orderings concurrently.
JUDGE_TIE_MARGIN 0.06 Normalised (0-1) score gap treated as a tie (just over half a point on a 1-10 scale).
JUDGE_VERBOSITY_RATIO 2.0 Length ratio at which a long winner is flagged.
JUDGE_MAX_CRITERIA 20 Maximum criteria per evaluation.
JUDGE_MAX_CANDIDATES 8 Maximum candidates per ranking (round robin makes n(n-1)/2 comparisons).
JUDGE_MAX_INPUT_CHARS 50000 Longer inputs are truncated (with a warning).
JUDGE_MAX_INSTRUCTIONS_CHARS 2000 Longest judge guidance (instructions); longer text is truncated with a warning.
JUDGE_CACHE_SIZE 0 (off) Opt-in in-memory cache of identical temperature-0 results; hits are marked cache_hit.
JUDGE_EMBEDDINGS_PROVIDER (empty) ollama or openai_compatible: adds embedding-based semantic_similarity to reference grading.
JUDGE_EMBEDDINGS_MODEL (empty) Embedding model, e.g. nomic-embed-text on Ollama.
JUDGE_EMBEDDINGS_BASE_URL / JUDGE_EMBEDDINGS_API_KEY (provider defaults) Override the embeddings endpoint and key (default: the Ollama or OpenAI-compatible settings).
JUDGE_API_KEYS — Comma-separated keys required by /api/v1 (open if unset).
JUDGE_API_ADMIN_KEY — Enables admin routes (they're disabled if unset).
JUDGE_API_RATE_LIMIT 60 Requests per minute per client (0 disables).
JUDGE_API_MAX_BODY_BYTES 1000000 Larger request bodies get 413.
JUDGE_API_MAX_CONCURRENT 4 Concurrent evaluations before 503.
JUDGE_API_MAX_BATCH_ROWS / JUDGE_API_MAX_JOB_ROWS 50 / 1000 Row limits for sync batches and jobs.
JUDGE_API_MAX_QUEUED_JOBS 10 Waiting jobs before 429.
JUDGE_API_CORS_ORIGINS — Comma-separated allowed origins (CORS off if unset).
JUDGE_DEMO_MODE false Public-demo safeguards in the dashboard (quotas, caps, session-only storage).
JUDGE_DEMO_SESSION_CALLS / JUDGE_DEMO_DAILY_CALLS 25 / 500 Live judge calls per visitor session / per day.
JUDGE_DEMO_MAX_INPUT_CHARS / _MAX_ROWS / _MAX_CANDIDATES 4000 / 25 / 5 Demo input caps.
JUDGE_DB_PATH .llm_judge/experiments.db Experiment-tracking database: a SQLite file, or a postgresql:// URL such as Supabase (needs the postgres extra). Passwords are redacted wherever it's shown.
JUDGE_MAX_DATASET_BYTES 50000000 Larger dataset files are rejected before parsing.
JUDGE_MAX_DATASET_ROWS 100000 Maximum rows per dataset.
JUDGE_BATCH_MAX_WORKERS 4 Concurrency for batch mode (doubled when parallel bias runs are on).
LOG_LEVEL INFO Logging verbosity.

Providers

The judge runs on any of these backends. Pick one with JUDGE_PROVIDER or the --provider flag. Nothing here requires a paid service.

Provider API key Runs Notes
groq (default) yes (free) cloud Free plan, rate-limited per model. Default judge openai/gpt-oss-120b.
ollama no your machine Free local models via Ollama: ollama pull llama3.2. Verified live weekly in CI with qwen2.5:1.5b.
openai_compatible optional either Any /chat/completions server: LM Studio, vLLM, llama.cpp, or hosted free models. Verified live against Groq's OpenAI-compatible endpoint (https://api.groq.com/openai/v1).
mock no offline Deterministic heuristic, not an LLM. For demos, tests and trying the tool without a key.
llm-judge providers                      # what's available and configured
llm-judge --provider ollama health       # reachability check, no inference
llm-judge --provider mock evaluate --task "..." --output-a "..." --output-b "..."
from llm_judge import Judge
from llm_judge.providers import OllamaProvider, OpenAICompatibleProvider

judge = Judge(provider=OllamaProvider("qwen2.5:7b"))
judge = Judge(provider=OpenAICompatibleProvider("http://localhost:1234/v1", "local-model"))

Every result records which provider and model produced it (metadata.judge), and the library never switches provider or model silently. Mock results say so in every explanation.

Fallback (opt-in). Set JUDGE_FALLBACK_PROVIDERS (for example ollama) to try other providers, in order, when a call to the primary one fails. It is off by default and never silent:

  • a result answered by a fallback carries a provider_fallback warning;
  • it also carries metadata.fallback entries naming the provider that failed, the one that answered, and the error;
  • metadata.judge keeps naming the configured judge.

Two things never trigger a fallback: an exhausted demo budget, and a reply that fails validation (the repair retry handles that). The mock judge can't be a fallback, because its scores aren't LLM judgments. Third-party packages can add providers through the llm_judge.providers entry-point group (see llm_judge/providers/registry.py).

Small local models are weaker judges than large hosted ones. Expect noisier scores and more repair retries, and prefer a judge from a different model family than the candidates (the self_preference_risk warning flags this).


Architecture

flowchart LR
    subgraph Interfaces
        LIB[Python library]
        CLI[CLI]
        API[REST API]
        UI[Streamlit dashboard]
    end
    CORE[Evaluation core<br/>pairwise · pointwise · reference<br/>ranking · RAG · agents]
    SAFE[Safeguards<br/>fenced prompts · strict parsing<br/>bias and injection checks]
    DATA[Datasets and experiments<br/>resumable batches · SQLite or Postgres runs<br/>comparisons · reports]
    PROV[Providers<br/>Groq · Ollama · OpenAI-compatible · mock<br/>opt-in fallback · cache · quotas]
    LIB & CLI & API & UI --> CORE
    CLI & API & UI --> DATA
    DATA --> CORE
    CORE --> SAFE
    CORE --> PROV

ARCHITECTURE.md has the detailed diagram, the request flow and the design principles.

src/llm_judge/           # Installable package (src layout)
├─ config.py             # Typed settings (pydantic-settings); no import-time crash
├─ models.py             # Criterion / CriterionScore / JudgeResult (validated)
├─ criteria.py           # Built-in criteria presets + resolver
├─ prompts.py            # Versioned, injection-resistant prompt construction
├─ parsing.py            # Defensive JSON → validated JudgeResult
├─ scoring.py            # Pure helpers: criteria matching, normalisation, winners
├─ diagnostics.py        # Injection, verbosity and self-preference signals
├─ judge.py              # Core engine: retries, repair, bias mitigation, merging
├─ pointwise.py          # Single-output and reference-based grading
├─ ranking.py            # Multi-candidate round-robin / pointwise leaderboards
├─ metrics.py            # Deterministic reference metrics (exact match, token F1)
├─ rag.py                # RAG verdicts -> faithfulness, context precision/recall
├─ agents.py             # Agent trace checks + judged trajectory grade
├─ reliability.py        # Consistency, Cohen's kappa, Spearman agreement
├─ batch.py              # v1 batch API (kept for compatibility)
├─ datasets/             # Readers, validation, checkpointed runner, summaries,
│                        #   bundled synthetic samples
├─ experiments/          # Run store (SQLite or PostgreSQL), comparison, reports
├─ api/                  # FastAPI app: routes, security, job queue (`[api]` extra)
├─ cli.py                # `llm-judge` command-line interface
├─ logging_config.py     # Opt-in logging setup
├─ py.typed              # PEP 561 marker: ships type information
└─ providers/            # Pluggable LLM backends
   ├─ base.py            #   LLMProvider protocol, health, usage counters
   ├─ registry.py        #   Name -> provider factory, plugin discovery
   ├─ fallback.py        #   Opt-in fallback chain, recorded on every result
   ├─ groq_provider.py   #   Groq (default cloud judge)
   ├─ ollama_provider.py #   Local models via Ollama
   ├─ openai_compatible.py # Any /chat/completions endpoint
   └─ mock_provider.py   #   Offline heuristic judge (not an LLM)
app.py                   # Streamlit entry point (navigation)
dashboard/               # Dashboard pages, shared components, themed charts
tests/                   # Offline unit + property tests (fake providers)

The judge depends only on the LLMProvider protocol, so supporting a new backend means implementing a single complete_json method, with no changes to the judging logic.


Technology stack

Area Tools
Language and models Python 3.11 to 3.14, fully typed (mypy); Pydantic v2 and pydantic-settings
LLM providers Groq SDK; httpx for Ollama and OpenAI-compatible servers; an offline mock judge
Resilience tenacity retries that follow provider rate-limit hints; opt-in fallback and result cache
REST API FastAPI and Uvicorn
Dashboard Streamlit and Plotly
Storage and data SQLite (standard library) or PostgreSQL/Supabase (psycopg); CSV, JSON, JSONL and YAML (PyYAML)
Quality pytest, Hypothesis, ruff, mypy, Bandit, pip-audit, CodeQL, pre-commit
Delivery GitHub Actions, Docker, MkDocs Material on GitHub Pages, Streamlit Community Cloud

Every runtime dependency is open source, and every hosted service has a free tier.


Development

pip install -e ".[all,dev,docs]"   # or: make install

make check                 # lint, format check, type-check, Bandit and tests
make docs                  # build the documentation site (strict)

Without make, run the commands listed in CONTRIBUTING.md. Every test uses an in-memory fake provider, so the suite runs fully offline and deterministically, with no API key or network access. scripts/e2e_dashboard.py additionally drives the dashboard in a real browser (see its docstring).


Security

  • See SECURITY.md for the threat model: prompt injection, hostile datasets, CSV injection, secret leakage, quota abuse and API abuse, each with a tested mitigation. CI runs Bandit, pip-audit and CodeQL.
  • .env is git-ignored; never commit real keys.
  • If a key is exposed, rotate it immediately in the Groq console.
  • The library never logs secret values.

Found a vulnerability? Please report it privately, not in a public issue. SECURITY.md has the full policy.


Contributing

Contributions are welcome: bug reports, features, documentation, tests and new benchmark samples.


Limitations

  • LLM judges are imperfect. Position, verbosity and self-preference bias are mitigated and flagged, not eliminated. Scores are judgments, not ground truth. The bias warnings are heuristics.
  • Free tiers have limits. Groq's free plan caps tokens per minute and per day. Batches slow down when they hit the cap (retries follow Groq's own wait hints). The public demo caps live calls, and its app sleeps when idle.
  • The mock judge isn't an LLM. It's a text heuristic for demos and tests, and it ignores judge instructions. Its results are always labelled.
  • Semantic similarity is optional. Reference grading always combines the judge's correctness and completeness scores with exact match and token F1, which are lexical. Embedding-based semantic similarity needs an embedding backend (JUDGE_EMBEDDINGS_PROVIDER). Both embedding backends are verified live in CI against Ollama; Groq offers no embeddings API.
  • Single-node jobs. REST API jobs run in an in-process queue that doesn't survive a restart, and nothing scales horizontally. Recorded runs can live in PostgreSQL or Supabase, so they can outlive a single machine.
  • The REST API isn't hosted publicly. Run it locally or on your own server.

Roadmap

Version 2.0.0 completed the planned phases, and 2.1.0 closed the gaps a line-by-line review of the plan found: evaluation modes, providers, datasets, experiment tracking, the REST API, the dashboard, RAG and agent evaluation, security hardening, and documentation. Versions 2.2.0 and 2.3.0 added a PostgreSQL/Supabase experiment store, live CI checks against Ollama, and publishing to PyPI. Open items are more providers and more benchmark samples. See ROADMAP.md for the status of each phase.


Citing

If you use LLM-as-Judge in research, please cite it. GitHub's "Cite this repository" button (from CITATION.cff) gives APA and BibTeX formats.


License

MIT © Syed Waleed Ahmed

Metadata

Release files for llm-as-judge-platform 2.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for llm-as-judge-platform 2.4.0
File Size Uploaded Provenance Actions
llm_as_judge_platform-2.4.0.tar.gz 244.4 kB With provenance Details for llm_as_judge_platform-2.4.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for llm-as-judge-platform 2.4.0
File Interpreter ABI Platform Actions
llm_as_judge_platform-2.4.0-py3-none-any.whl Python 3 none any Details for llm_as_judge_platform-2.4.0-py3-none-any.whl

Total release size: 414.1 kB

Release files / llm_as_judge_platform-2.4.0.tar.gz

Download URL llm_as_judge_platform-2.4.0.tar.gz
Size 244.4 kB
Tags Source
SHA-256 checksum
How to use checksums
3176e38fe99b1efb6594f94306d5399694cd5f016deb25f1ada11deb153632fb
BLAKE2b-256 checksum
How to use checksums
f2dc43987dd22ec8c3713bc86403322fee9e98dc302c07b8178a1800b0ed4c9c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Nov 11, 2026.

Transparency log

Release files / llm_as_judge_platform-2.4.0-py3-none-any.whl

Download URL llm_as_judge_platform-2.4.0-py3-none-any.whl
Size 169.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9c064556d2996d71e43b39c71381814d2fb7941d9023406b962d7e23b87faa18
BLAKE2b-256 checksum
How to use checksums
9f40c7865840fc567db12683f8ddf1beabcac470c599ad9bb9743cb611a2cb71
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Nov 11, 2026.

Transparency log

Security for llm-as-judge-platform 2.4.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.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for llm_as_judge_platform-2.4.0.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 Nov 11, 2026.

Transparency log

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.

Release history Release notifications | RSS feed

This release

2.4.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page