This guide covers how to evaluate event-driven agentic workflows using the Lightspeed Evaluation Framework. While the framework's default mode evaluates synchronous HTTP request-response interactions, the agentic evaluation mode supports CRD-based workflows where the "answer" is a trajectory of events and a final cluster state.
OpenShift Agentic Lightspeed systems is event-driven: Proposal CRDs are applied, workflows are executed, and cluster state changes. The evaluation framework now supports a proposal agent type in order to monitor the cluster state and evaluate agent results against it.
- OpenShift cluster with the Agentic Lightspeed operator installed
ocorkubectlCLI available in PATHKUBECONFIGenvironment variable pointing to a valid kubeconfig- RBAC permissions for Proposal CRD operations in the target namespace
- Judge LLM API key (e.g.,
OPENAI_API_KEY) forproposal_evaluation_correctness
agents:
enabled: true
default:
agent: openshift_agentic_lightspeed
agent_config:
timeout: 600
openshift_agentic_lightspeed:
type: proposal
namespace: openshift-lightspeed
auto_approve: true
cleanup_proposals: true
timeout: 900
poll_interval: 2| Field | Type | Default | Description |
|---|---|---|---|
namespace |
string | (required) | Kubernetes namespace containing Proposal resources |
auto_approve |
bool | true |
Automatically approve proposals when phase is Proposed |
cleanup_proposals |
bool | true |
Delete eval proposals after status is captured |
timeout |
int | 900 |
Total timeout in seconds for the proposal lifecycle |
cli_timeout |
int | 30 |
Timeout in seconds for individual oc/kubectl commands |
poll_interval |
int | 2 |
Seconds between status polls |
cache_dir |
string | null |
Location of cached queries |
cache_enabled |
bool | true |
Enable caching |
For agentic workflows, each turn uses proposal_spec to define the proposal and expected_proposal_status to define success criteria.
| Field | Type | Required | Description |
|---|---|---|---|
description |
string | No | Human-readable label for reports (falls back to query) |
proposal_spec |
dict | Conditional | Inline proposal spec — contains request, targetNamespaces, workflow phase gates |
expected_proposal_status |
dict | Conditional | Assertions to check against the proposal status |
expected_outcome |
string | Conditional | Expected outcome description for LLM-as-judge evaluation |
expected_analysis_outcome |
string | No | Optional per-phase expected outcome for analysis/diagnosis |
expected_execution_outcome |
string | No | Optional per-phase expected outcome for execution/actions |
expected_verification_outcome |
string | No | Optional per-phase expected outcome for verification |
proposal_status |
dict | No | Raw CRD status populated by the driver (framework-managed) |
proposal_results |
dict | No | Child Result CRs populated by ProposalAmender (framework-managed) |
queryremains required but can be auto-populated fromproposal_spec.requestwhen absent.
The simplest agentic evaluation — analysis phase only, no execution or verification:
- conversation_group_id: analysis_only
description: Analysis-only — diagnose without remediating
setup_script: agentic/scripts/setup.sh
cleanup_script: agentic/scripts/cleanup.sh
turns:
- turn_id: turn_1
proposal_spec:
request: >-
A pod named oomkill-demo in namespace test-ns
is in CrashLoopBackOff. Analyze the root cause.
targetNamespaces:
- test-ns
tools:
skills:
- image: quay.io/harpatil/agentic-skills:latest
paths:
- /skills/find-token
analysis:
agent: eval-default
expected_proposal_status:
phase: Completed
turn_metrics:
- custom:proposal_statusComplete remediation workflow with deterministic assertions and LLM-as-judge:
- conversation_group_id: full_lifecycle
description: OOMKill remediation — full lifecycle with LLM-as-judge
setup_script: agentic/scripts/setup.sh
cleanup_script: agentic/scripts/cleanup.sh
turns:
- turn_id: turn_1
proposal_spec:
request: >-
A pod named oomkill-demo in namespace test-ns
is in CrashLoopBackOff due to OOMKill. Analyze the root cause,
fix the memory configuration, and verify the fix.
targetNamespaces:
- test-ns
tools:
skills:
- image: quay.io/harpatil/agentic-skills:latest
paths:
- /skills/find-token
analysis:
agent: eval-default
execution:
agent: eval-default
verification:
agent: eval-default
expected_proposal_status:
phase: Completed
max_duration: "15m"
max_attempts: 5
analysis:
min_options: 1
options:
- risk_in: [low, medium]
confidence_in: [medium, high]
execution:
phase: Succeeded
verification:
passed: true
expected_outcome: >-
Root cause: the pod oomkill-demo is OOMKilled because its container
memory limit is too low. Remediation: increase the container memory
limit and verify the pod reaches Running state.
turn_metrics:
- custom:proposal_status
- custom:proposal_evaluation_correctness
turn_metrics_metadata:
"custom:proposal_evaluation_correctness":
threshold: 0.75The proposal driver manages the full Proposal CR lifecycle:
- Build Proposal CR — Merge
proposal_spec+request+ agent config - Create CR on cluster — Auto-generated name:
eval-<uuid8> - Poll status — Loop every
poll_intervalseconds - Auto-approve — If phase is
Proposedandauto_approveis enabled - Terminal phase —
Completed/Failed/Denied/Escalated - Populate turn_data —
proposal_status(full status dict) +proposal_results(child Result CRs) +response(Markdown workflow summary) - Cleanup proposal CR — Delete the created CR (if
cleanup_proposalsis enabled) - Metrics evaluate —
custom:proposal_statusand/orcustom:proposal_evaluation_correctnesson enriched data
Setup/cleanup scripts are only needed for infrastructure (deploying the workload to trigger, LLM provider CRs, sandbox CRs, etc.). The driver handles Proposal CR lifecycle autonomously.
A single metric that runs all assertion checks from expected_proposal_status in sequence, failing fast at the first failure. Score is 1.0 if all checks pass, 0.0 on first failure.
Checks run in order: phase → timing → analysis → execution → verification.
Phase checks:
| Field | Type | Description |
|---|---|---|
phase |
string | Exact phase match (e.g., Completed, Failed, Escalated) |
phase_in |
list[string] | Phase must be one of these values |
Timing checks:
| Field | Type | Description |
|---|---|---|
max_duration |
string | Max elapsed time across conditions. Go-style duration: "5m", "2m30s", "1h" |
max_attempts |
int | Max number of execution attempts. Read from status.attempts or inferred from RetryingExecution conditions |
Analysis checks:
| Field | Type | Description |
|---|---|---|
analysis.min_options |
int | Minimum number of analysis options required |
analysis.options[].risk_in |
list[string] | Allowed risk levels for the option (case-insensitive) |
analysis.options[].confidence_in |
list[string] | Allowed confidence levels (case-insensitive) |
analysis.options[].diagnosis_contains |
list[string] | Substrings the diagnosis summary must contain (case-insensitive) |
analysis.options[].components[].type |
string | Component type to assert on |
analysis.options[].components[].match |
dict | Exact field match on component |
analysis.options[].components[].match_contains |
dict | Substring match on component fields (case-insensitive) |
analysis.options[].components[].required |
list[string] | Fields that must be present on the component |
analysis.options[].components[].absent |
bool | Assert that this component type does not exist |
Execution checks:
| Field | Type | Description |
|---|---|---|
execution.phase |
string | Expected execution phase (e.g., Succeeded, Failed) |
Verification checks:
| Field | Type | Description |
|---|---|---|
verification.passed |
bool | Whether verification passed (status == "True" on Verified condition) |
verification.summary_contains |
string | Substring the verification message must contain (case-insensitive) |
Condition checks:
| Field | Type | Description |
|---|---|---|
conditions[].type |
string | Condition type to assert on (e.g., Executed, Verified) |
conditions[].status |
string | Expected condition status (e.g., "True", "False") |
conditions[].reason |
string | Expected condition reason (e.g., Skipped, Succeeded) |
On retried proposals, analysis and execution checks use the latest (most recent) Result CR, so assertions reflect the final execution state.
Evaluates agentic remediation workflow quality using a Judge LLM. Scores 0.0–1.0 across three dimensions (only phases present in the workflow are scored; absent dimensions are marked N/A):
- Diagnosis — Is the root cause correctly identified? Are the proposed actions sound and safe?
- Execution — Were the remediation actions carried out? Are they safe, well-scoped, and minimal?
- Verification — Do the checks confirm the specific issue was resolved?
Threshold: 0.75
Required fields: response (populated automatically during execution), expected_outcome