Skip to content

LCORE-2802: Add OKP RAG quality regression benchmarks and baseline comparison - #265

Closed
alessandralanz wants to merge 16 commits into
lightspeed-core:mainfrom
alessandralanz:lcore-regression
Closed

LCORE-2802: Add OKP RAG quality regression benchmarks and baseline comparison#265
alessandralanz wants to merge 16 commits into
lightspeed-core:mainfrom
alessandralanz:lcore-regression

Conversation

@alessandralanz

@alessandralanz alessandralanz commented Jun 26, 2026

Copy link
Copy Markdown

Description

Adds an evaluation framework for OKP RAG quality regression testing against the lightspeed-stack. Includes:

  • 97 OKP RAG benchmark conversations covering single-turn knowledge, multi-turn retention, edge cases, and
    negative/off-topic queries
  • Baseline comparison script (compare_against_baseline) with --check-only mode for CI gating
  • System config for PR-gate evaluation using gpt-4o-mini as the judge LLM
  • Version-controlled baseline snapshot (102 evaluations)
  • A/B/C comparison script for comparing multiple evaluation runs

Type of change

  • Refactor
  • New feature
  • Bug fix
  • CVE fix
  • Optimization
  • Documentation Update
  • Configuration Update
  • Bump-up service version
  • Bump-up dependent library
  • Bump-up library or tool used for development (does not change the final image)
  • CI configuration change
  • Unit tests improvement

Tools used to create PR

Identify any AI code assistants used in this PR (for transparency and review context)

  • Assisted-by: Claude (Claude Code CLI)
  • Generated by: N/A

Related Tickets & Documents

Checklist before requesting a review

  • I have performed a self-review of my code.
  • PR has passed all pre-merge test jobs.
  • If it is a core feature, I have added thorough tests.

Testing

  • Please provide detailed steps to perform tests related to this code change.

  • How were the fix/results from this change verified? Please provide relevant screenshots or results.

  • make pre-commit passes all checks (pylint, pyright, ruff, black, etc.)

    • GitLab CI pipeline runs 97 conversations producing 506 evaluations against a live lightspeed-stack instance with OKP enabled
    • Baseline comparison script validates current results against stored baseline

Summary by CodeRabbit

  • New Features
    • Added regression comparison tooling to compare a current evaluation run against a baseline and surface score/pass-rate deltas.
    • Added an LCORE regression gate configuration with metric thresholds, output/export settings, and logging defaults.
    • Added a stored baseline summary snapshot for LCORE regression checks.
    • Extended custom:tool_eval with an “expect no tool calls” mode for negative test scenarios.
  • Tests
    • Added tests covering summary loading, delta/threshold regression classification, markdown reporting, and custom:tool_eval no-tools behavior.

…. Checked against a live OKP image with 85% pass rate
… Guide's dataset sizing and distribution recommendations
…s quality regression to PR code changes vs OKP data changes using pairwise A/B/C comparisons and shared test helpers have been moved to conftest.py
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds an LCORE regression PR-gate configuration, tool-calling benchmark scenarios, a baseline comparison CLI for detecting metric regressions, negative tool-call assertions, supporting fixtures and tests, and a baseline evaluation snapshot.

Changes

LCORE regression gate

Layer / File(s) Summary
Gate configuration and benchmark inputs
config/lcore_regression/system-config-pr-gate.yaml, eval_data/lcore_regression/tool_calling_quality.yaml, baselines/lcore_regression/current_baseline_summary.json, script/regression/__init__.py
Defines execution, model, metric, output, visualization, and logging settings; adds tool-selection, no-tool, and combined-quality benchmarks; records a baseline summary snapshot; and documents the regression package.
Negative tool-call evaluation
src/lightspeed_evaluation/core/metrics/custom/custom.py, src/lightspeed_evaluation/core/system/validator.py, tests/unit/core/metrics/custom/test_custom.py
Supports expect_no_tools for custom:tool_eval, bypasses expected-tool requirements in that mode, scores empty or present tool calls, and tests both negative and standard evaluation paths.
Baseline summary comparison
script/regression/compare_against_baseline.py
Loads exactly one summary per run, computes score and pass-rate deltas, classifies critical and non-critical regressions, renders terminal or Markdown output, and controls failure exit status.
Comparison fixtures and tests
tests/script/conftest.py, tests/script/test_compare_against_baseline.py
Adds summary construction and JSON-writing helpers, updates metric identifiers, and tests summary discovery, threshold behavior, missing metrics, configurable thresholds, and Markdown reporting.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as compare_against_baseline.main
    participant Loader as find_and_load_summary
    participant Delta as compute_metric_deltas
    participant Report as generate_markdown_summary

    User->>CLI: provide baseline and current directories
    CLI->>Loader: load baseline and current summary JSON
    Loader-->>CLI: return evaluation summaries
    CLI->>Delta: compute metric deltas and statuses
    Delta-->>CLI: return PASS, WARN, or FAIL results
    opt markdown output requested
        CLI->>Report: render markdown summary
        Report-->>CLI: return report text
    end
    CLI-->>User: print results and return exit status
Loading

Suggested reviewers: asamal4, bsatapat-jpg, rioloc, xmican10

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: OKP RAG regression benchmarks plus baseline comparison for PR gating.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@script/regression/compare_abc_runs.py`:
- Around line 89-110: The verdict logic in compare_abc_runs currently ignores
total cumulative critical regressions unless pr_deltas is None, so a split A→B
and B→C failure can still pass. Update the gate in the main decision block to
consider total_has_critical alongside the existing pr_has_critical and
okp_has_critical checks, using the same verdict flow in the compare_abc_runs
function so any critical total regression returns a failing result when
intended.

In `@script/regression/compare_against_baseline.py`:
- Around line 141-157: The status calculation in compare_against_baseline should
not default to PASS when a baseline metric is present but the current run is
missing it. Update the logic around score_delta/status in the comparison flow to
treat “present in baseline, missing in current” as a degraded outcome, and apply
the same handling for pass_rate_delta where relevant. Use the existing
compare_against_baseline metric handling and CRITICAL_METRICS thresholding so
missing current values are reported as WARN or FAIL instead of PASS.
- Around line 232-252: The compare script’s check-only mode is emitting the
baseline/current summary prints before the args.check_only branch, so stdout
contains more than the required single token. In compare_against_baseline.py,
update the control flow around compute_metric_deltas and the check-only handling
so the summary prints are skipped when args.check_only is set, leaving only the
final ok/regression output from the check_only path.

In `@tests/script/test_compare_against_baseline.py`:
- Around line 48-51: The missing-directory test in
test_raises_on_missing_directory is nondeterministic because it hardcodes a /tmp
path that may exist on some machines. Update the test to use pytest’s tmp_path
fixture and construct a guaranteed-missing subpath (for example via tmp_path
with a non-created child) before calling find_and_load_summary, so the
FileNotFoundError assertion always exercises the intended path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e9f84c03-82ee-4691-8e2f-cb77a7f724fc

📥 Commits

Reviewing files that changed from the base of the PR and between 6ff47a6 and 5d59325.

📒 Files selected for processing (9)
  • baselines/lcore_regression/current_baseline_summary.json
  • config/lcore_regression/system-config-pr-gate.yaml
  • eval_data/lcore_regression/okp_rag_quality.yaml
  • script/regression/__init__.py
  • script/regression/compare_abc_runs.py
  • script/regression/compare_against_baseline.py
  • tests/script/conftest.py
  • tests/script/test_compare_abc_runs.py
  • tests/script/test_compare_against_baseline.py

Comment thread script/regression/compare_abc_runs.py Outdated
Comment thread script/regression/compare_against_baseline.py
Comment thread script/regression/compare_against_baseline.py Outdated
Comment thread tests/script/test_compare_against_baseline.py Outdated
@xmican10

xmican10 commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Thanks!! I came across your PR, and I'm not sure if it's ready yet, but I'm wondering a few things:

  • What is the source of these QnAs? Is it our private GitLab repo?
  • Since OKP is a paid Red Hat capability, I'm wondering if keeping the QnAs and expected responses in a public repo is a risk. Even if the answers seem generic, they could reveal internal knowledge base structure, coverage, and quality characteristics. Should these live in a private repo instead?
  • The data files are huge, can't we move it away from the ls-eval tooling? Or create even more separation and move it all to a separate repo?

cc: @asamal4 @Anxhela21

@alessandralanz
alessandralanz marked this pull request as draft July 1, 2026 13:10
@alessandralanz

Copy link
Copy Markdown
Author

@xmican10 Thank you so much for the feedback! These are all great points, and I've addressed them just now with my latest push:

  • What is the source of these QnAs? Is it our private GitLab repo?

The queries and expected responses are from datasets provided by the OpenShift Installer and RHEL product groups (they are the only ones currently rated as gold) that can be found in Lightspeed Core's Evaluation Data GitLab repository. The evaluation data has been removed fro this public repo and is now cloned at pipeline runtime from a forked version of the internal Evaluation Data GitLab repo.

  • Since OKP is a paid Red Hat capability, I'm wondering if keeping the QnAs and expected responses in a public repo is a risk. Even if the answers seem generic, they could reveal internal knowledge base structure, coverage, and quality characteristics. Should these live in a private repo instead?

I agree that keeping the full Q&A datasets in the public repo is a risk, so I have removed okp_rag_quality.yaml and have updated the pipeline so that it pulls the evaluation data from the internal source at runtime instead.

  • The data files are huge, can't we move it away from the ls-eval tooling? Or create even more separation and move it all to a separate repo?

The baseline summary has been stripped to 3KB and now only contains aggregate metric scores (pass rates, means, confidence intervals) with no per-conversation IDs, topic names, or individual scores. The comparison scripts only need these aggregate values. The large evaluation data files have been moved to the internal GitLab repo and are no longer part of this PR.

@alessandralanz
alessandralanz marked this pull request as ready for review July 2, 2026 15:42
@xmican10

xmican10 commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Thanks @alessandralanz for actively addressing my concerns!

Thinking a bit further into the future, keeping the regression tests within ls-eval itself might expand the scope of the tooling without adding direct value for the standard ls-eval user.
Would it be possible to move these regression tests out of ls-eval into a separate repository dedicated entirely to this type of testing?

Wdyt @asamal4 and @Anxhela21? I'd love to get your thoughts on this from an architectural perspective.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/lightspeed_evaluation/core/system/validator.py (1)

132-138: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated expect_no_tools check logic across two validator sites.

The same 5-line expect_no_tools detection is copy-pasted at two locations. Extracting a shared helper keeps the logic in sync and makes the metadata resolution path explicit. Additionally, both validator sites read directly from turn_data.turn_metrics_metadata, while custom.py resolves tool-eval metadata through _get_tool_eval_metadata (which may use MetricManager). This is safe today because expect_no_tools is only set per-turn, but the two resolution paths could diverge if system-level defaults ever include this flag.

  • src/lightspeed_evaluation/core/system/validator.py#L132-L138: Replace the inline 5-line check with a call to the extracted helper.
  • src/lightspeed_evaluation/core/system/validator.py#L517-L523: Replace the inline 5-line check with the same helper call.
♻️ Proposed helper extraction
+def _is_tool_eval_negative_assertion(turn_data: TurnData) -> bool:
+    """Check if tool_eval is in expect_no_tools (negative assertion) mode.
+
+    Args:
+        turn_data: Turn data to inspect.
+
+    Returns:
+        True if expect_no_tools is enabled for custom:tool_eval.
+    """
+    turn_metadata = turn_data.turn_metrics_metadata or {}
+    tool_eval_meta = turn_metadata.get("custom:tool_eval", {})
+    return tool_eval_meta.get("expect_no_tools", False)

At lines 132–138:

     # Negative assertion mode: no required fields needed
-    if metric_identifier == "custom:tool_eval":
-        turn_metadata = turn_data.turn_metrics_metadata or {}
-        tool_eval_meta = turn_metadata.get("custom:tool_eval", {})
-        if tool_eval_meta.get("expect_no_tools", False):
-            return True, ""
+    if metric_identifier == "custom:tool_eval" and _is_tool_eval_negative_assertion(turn_data):
+        return True, ""

At lines 517–523:

                 # Skip expected_tool_calls validation for negative assertion mode
-                if metric == "custom:tool_eval":
-                    turn_metadata = turn_data.turn_metrics_metadata or {}
-                    tool_eval_meta = turn_metadata.get("custom:tool_eval", {})
-                    if tool_eval_meta.get("expect_no_tools", False):
-                        continue
+                if metric == "custom:tool_eval" and _is_tool_eval_negative_assertion(turn_data):
+                    continue
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lightspeed_evaluation/core/system/validator.py` around lines 132 - 138,
Extract the duplicated expect_no_tools detection from validator.py lines 132-138
and 517-523 into one shared helper that resolves custom:tool_eval metadata
through the established _get_tool_eval_metadata path, then replace both inline
checks with calls to that helper while preserving the existing True, "" result
and default-false behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/lightspeed_evaluation/core/system/validator.py`:
- Around line 132-138: Extract the duplicated expect_no_tools detection from
validator.py lines 132-138 and 517-523 into one shared helper that resolves
custom:tool_eval metadata through the established _get_tool_eval_metadata path,
then replace both inline checks with calls to that helper while preserving the
existing True, "" result and default-false behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6fe83464-8f0d-4abb-a308-8d14e38fc338

📥 Commits

Reviewing files that changed from the base of the PR and between db2d156 and 52adde6.

📒 Files selected for processing (5)
  • config/lcore_regression/system-config-pr-gate.yaml
  • eval_data/lcore_regression/tool_calling_quality.yaml
  • src/lightspeed_evaluation/core/metrics/custom/custom.py
  • src/lightspeed_evaluation/core/system/validator.py
  • tests/unit/core/metrics/custom/test_custom.py

@Anxhela21

Anxhela21 commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

@xmican10, I do agree. Initially we decided to keep it here because we already have an evaluation e2e test for lightspeed-stack in this repo.

@alessandralanz can these scripts exist in the gitlab e2e test? These benchmarks can be saved in gitlab https://gitlab.cee.redhat.com/lightspeed-core/evaluation-data and retrieved as needed for the e2e test?

@alessandralanz

Copy link
Copy Markdown
Author

Closing this PR, the baseline comparison scripts, eval data, and CI pipeline have been consolidated into a dedicated internal repo: gitlab.cee.redhat.com/lightspeed-core/quality-regression-suite. The compare_against_baseline.py script and tests live there now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants