Webhook icon
Schedule icon
Script icon
Loop icon
If icon
SlackIncomingWebhook icon
Log icon
Fail icon

Gate LLM Judge Drift Before It Silently Changes Verdicts

Score LLM judge verdicts against gold labels, flag every flip with direction, alert Slack per false pass and gate the run when agreement drops.

Categories
AI

How it works

  1. on_judgments_publish (io.kestra.plugin.core.trigger.Webhook, keyed with the LLM_JUDGE_WEBHOOK_KEY secret) receives the gold set items with their expected and current judge verdicts from your evaluation runner. weekly_judge_audit (io.kestra.plugin.core.trigger.Schedule, cron 0 8 * * 1) is the safety net and ships disabled: true until an operator turns it on.
  2. score_judgments (io.kestra.plugin.scripts.python.Script on python:3.12-slim) prefers the posted run and falls back to a bundled twelve item example so trial runs still produce a report. Every item with both a valid pass or fail expected and judged verdict is scored; a mismatch becomes a flip row tagged false_pass when the gold said fail and the judge said pass, or false_reject for the opposite. The agreement rate, the flip rows, the false pass and false reject counts and the sample sufficiency flag are printed as a single ::{"outputs": ...}:: line.
  3. review_flips (io.kestra.plugin.core.flow.Loop, concurrencyLimit: 1) walks the scored flip rows one at a time. flag_flip (io.kestra.plugin.core.flow.If) branches on the flip direction, so a dangerous false pass gets its own alert_false_pass (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) naming the item and both verdicts, while a false reject lands on log_false_reject as recorded throughput loss.
  4. gate_consistency (io.kestra.plugin.core.flow.If) branches on the consistency verdict. An agreement rate under min_agreement_pct, or an empty sample, reaches alert_drift with the full drift picture, then fail_gate (io.kestra.plugin.core.execution.Fail) turns the run red. A consistent judge lands on log_consistent.
  5. The flow level errors handler (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) reports any failure with the execution id, because a dead scorer looks exactly like a consistent judge.

What you get

  • Agreement rate between the current judge revision and your gold verdicts, with a configurable floor that the gate enforces.
  • Per flip rows tagged false pass or false reject, so the dangerous direction is separated from the wasteful one.
  • One focused Slack alert per false pass item plus a fleet escalation when the agreement floor is breached.
  • agreement_rate, flip_count, flipped_items, false_pass_count and false_reject_count as typed outputs for dashboards and regression follow-up.
  • A disabled weekly audit as a second net once the webhook path is trusted.

Who it's for

  • ML engineers who maintain LLM-as-judge evaluation pipelines and need to catch judge revision drift before it changes production verdicts.
  • QA and safety teams who own the gold set and need every judge flip surfaced with evidence.
  • Platform teams who want judge consistency gated in the same pipeline as the rest of the model evaluation checks.

Why orchestrate this with Kestra

Judge drift is invisible until someone notices the same input getting a different verdict weeks later. Kestra gives the evaluation runner a webhook to land on, a scorer whose agreement floor lives in version control, a Loop that names every false pass with its item id, a branch that separates escalation from the all clear, and outputs that a model card or regression dashboard can consume. A cron script can compute agreement, but it has no alert routing, no execution history and no gate.

Prerequisites

  • A worker with Docker access, the scorer runs in python:3.12-slim.
  • An evaluation runner that POSTs gold set items with expected and current judge verdicts to the webhook, or rely on the bundled example run for trial runs.
  • A Slack incoming webhook for the per flip alerts and for failure alerts.

Secrets

  • LLM_JUDGE_WEBHOOK_KEY: key segment guarding the judgment webhook URL, anyone holding it can trigger a consistency gate run.
  • SLACK_WEBHOOK_URL: Slack incoming webhook for the per flip alerts and failure alerts.

Quick start

  1. Add the two secrets to your Kestra namespace.
  2. Run the flow once with the default inputs and confirm agreement_rate reads 75.0, flip_count reads 3, false_pass_count reads 1, false_reject_count reads 2 and sample_sufficient reads true, and that the false pass and escalation Slack alerts arrived.
  3. Raise min_agreement_pct to 100 and re-run to watch the same run pass as consistent while the agreement rate stays identical.
  4. Point your evaluation runner at /api/v1/{tenant}/executions/webhook/{namespace}/llm-judge-consistency-gate/{LLM_JUDGE_WEBHOOK_KEY} and enable weekly_judge_audit once the path is trusted.

How to extend

  • Persist the flip rows to a warehouse with io.kestra.plugin.jdbc.postgresql.Queries to chart agreement trends across judge revisions.
  • Add a second comparison against the previous run's verdicts so regressions that match the current gold label but flipped from the last run are also caught.
  • Fan out per gold set with io.kestra.plugin.core.flow.ForEachItem over a subflow that scores one gold set each.
  • Push the agreement rate into a model registry annotation with io.kestra.plugin.core.http.Request right after the gate passes.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.