Quality gates in CI¶
The gate command¶
llm-search-eval gate reads a report.json, checks it against thresholds,
prints a Markdown table of the checks, and exits with 1 when any check fails.
llm-search-eval gate reports/report.json \
--min ndcg@10=0.60 --min recall@10=0.70 \
--max-drop 0.01 \
--summary "$GITHUB_STEP_SUMMARY"
| Option | Meaning |
|---|---|
--min METRIC=VALUE |
The mean of the metric must be at least VALUE for every checked system. Repeatable. |
--max-drop X |
A metric may not fall by more than X (absolute). |
--max-relative-drop X |
A metric may not fall by more than X as a fraction, for example 0.02 for 2%. |
--metric M |
Metrics for the drop checks. Repeatable. Defaults to the primary metric. |
--reference OLD.json |
Compare each system with the same system in an earlier report instead of with the baseline system. |
--significant-only |
Fail on a drop only when the paired randomization test gives p below --alpha (default 0.05). |
--system NAME |
Check only these systems. Repeatable. |
--summary FILE / --json FILE |
Append the Markdown table to a file and write the results as JSON. |
Without --reference, drops are measured from the baseline system in the same
report, which fits a pull request that adds a candidate system next to the
current one. With --reference, keep a report.json from the default branch
(for example as an artifact or in the repository) and compare against it.
Exit codes: 0 passed, 1 a check failed, 2 invalid input.
GitHub Action¶
The repository is also a composite GitHub Action. It installs the tool, runs the evaluation, applies the gate, writes the gate result and the full report to the job summary, and posts or updates a comment on the pull request (see Pull request comments).
name: Search quality
on: pull_request
permissions:
contents: read
pull-requests: write # for the report comment
jobs:
evaluate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: .judge-cache.jsonl
key: judge-cache-${{ github.run_id }}
restore-keys: judge-cache-
- name: Evaluate rankings
id: search-eval
uses: sadrmanesh/llm-search-eval@v0.4.0
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
with:
queries: eval/queries.jsonl
products: eval/products.jsonl
qrels: eval/qrels.csv
systems: |
production=eval/runs/production.jsonl
candidate=eval/runs/candidate.jsonl
judges: |
openai=gpt-4o-mini
cache: .judge-cache.jsonl
prices: |
gpt-4o-mini=0.15,0.60
max-cost: "2"
pairwise-judge: openai=gpt-4o-mini
sample: "300"
stratify: segment
min: |
ndcg@10=0.55
max-drop: "0.01"
significant-only: "true"
- uses: actions/upload-artifact@v4
if: always()
with:
name: search-evaluation
path: ${{ steps.search-eval.outputs.report-dir }}
Inputs¶
| Input | Default | Description |
|---|---|---|
queries, products |
required | Dataset files. |
qrels |
Gold labels. | |
systems |
required | One NAME=PATH per line; the first is the baseline unless baseline is set. |
judges |
One judge spec per line; two or more form a panel. | |
aggregate |
majority |
Panel aggregation. |
calibrate |
false |
Judge gold pairs too and report agreement with gold. |
cache |
Judgment cache path. | |
prices |
One MODEL=INPUT,OUTPUT per line. |
|
max-cost, max-tokens, max-judgments |
Budget limits (see Cost and budgets). | |
pairwise-judge |
Pairwise judge spec; turns on pairwise comparison. | |
pairwise |
Pairs to compare, one A:B per line. Defaults to each system against the baseline. |
|
metrics, primary, baseline, permutations, title |
Evaluation settings. | |
bootstrap, confidence |
1000, 0.95 |
Confidence intervals; 0 resamples turns them off. |
sample, stratify |
Query sampling: a count, fraction or percentage, and a query field. | |
args |
Extra run arguments, one per line. |
|
min |
One METRIC=VALUE floor per line. |
|
max-drop, max-relative-drop |
Regression limits. | |
reference |
Earlier report.json to compare against. |
|
gate-metrics |
Metrics for the drop checks, one per line. | |
significant-only |
false |
Ignore drops that are not significant. |
fail-on-regression |
true |
Fail the step when the gate fails. |
comment |
true |
Post or update a pull request comment with the gate result and the report. |
comment-id |
report |
Comment identity; jobs with different ids keep separate comments. |
github-token |
${{ github.token }} |
Token for the comment. Needs pull-requests: write. |
output-dir |
llm-search-eval-report |
Report directory. |
python-version |
3.12 |
Python used by the action. |
package |
the action's own version | pip requirement to install instead. |
Outputs¶
| Output | Description |
|---|---|
report-dir |
Directory with all reports. |
report-json, report-html |
Paths to report.json and the dashboard. |
passed |
true when every gate check passed or no gate was configured. |
comment-url |
Link to the pull request comment, when one was posted. |
API keys are read from the environment of the step, as in the example above.
To check the cost before a paid run, call llm-search-eval estimate with the
same options in an earlier step; it exits with 1 when the budget is too
small.