Back to Blog
Source code and test output on a screen representing automated AI workflow regression testing

AI Workflow Regression Testing

10 min read

AI workflow regression testing should answer one practical question: can this exact release still complete the jobs users depend on? A prompt edit may improve average response quality while breaking a tool argument. A model upgrade may produce better prose but choose the wrong action. A renamed field may cause every CRM update to fail. Checking a few outputs by eye will not catch these failures reliably.

A small, versioned test suite built from real tasks and incidents gives the team a release gate. It can check deterministic facts, score judgment calls, inspect tool trajectories, and block a release when an agreed threshold falls. The suite does not need to pretend that every model response has one correct wording.

Why ordinary application tests miss AI workflow failures

A conventional unit test controls its inputs and expects a stable result. An AI workflow combines several changing parts: prompts, models, retrieval settings, tool descriptions, schemas, policies, and external services. The final answer can vary even when the workflow is healthy. It can also look plausible when an intermediate action was unsafe or simply wrong.

Consider an internal support workflow. It classifies a ticket, searches account data, drafts a reply, and proposes a refund. A polished final message does not prove that the workflow selected the right customer, respected the refund limit, or avoided calling a write tool before approval. Testing only the final text hides the most expensive failures.

An evaluation suite therefore needs more than string comparison. The OpenAI evaluation guide recommends task-specific tests, representative data, graders, and continuous evaluation. Anthropic advises teams to define success criteria before choosing test cases or grading methods in its evaluation guidance. Define acceptable behavior first, then measure it in ways that match the task.

Define the release contract before writing tests

Start with a short release contract. List what must remain true after any prompt, model, retrieval, or tool change. Separate these statements into three groups.

  1. Hard invariants are facts that cannot vary. A tool name must be allowed. An order identifier must match the input. A refund above the policy limit must require approval. Sensitive fields must not appear in the answer.
  2. Quality criteria allow several acceptable outputs. The reply should answer the question, use the retrieved policy correctly, and avoid unsupported claims.
  3. Operational limits constrain execution. The workflow must stop after a set number of tool calls, complete within a budget, and return a controlled error when a dependency fails.

Do not begin with a generic target such as "the response is good." It cannot produce a useful test or a release decision. Write criteria that a reviewer could apply consistently: "The answer cites the current cancellation policy and does not promise a refund," or "The workflow requests approval before calling issue_refund for amounts above the configured limit."

The contract should also name the unit under test. A prompt test checks one model call. A component test checks retrieval or a tool adapter. A workflow test checks the complete route from user input to final state. Keep all three, but use workflow tests for release decisions because component success does not prove that the pieces cooperate.

Build a compact dataset from real work

A useful first dataset can contain 30 to 60 cases. Coverage matters more than size. Draw cases from five sources:

  • common user requests that represent routine traffic;
  • past incidents and support tickets;
  • policy boundaries, such as values just below and above an approval limit;
  • malformed, missing, or contradictory inputs;
  • adversarial requests that try to bypass instructions or trigger an unauthorized tool.

Store each case as data, not test code. Include the input, fixed context, expected invariants, allowed tools, forbidden tools, and any rubric needed for a grader. Add tags such as routine, policy-boundary, tool-error, and security so failures can be grouped.

id: refund-over-limit
input: "Refund order A184 for 750 GBP"
context:
  role: support-agent
  refund_limit_gbp: 500
expected:
  required_tool: get_order
  forbidden_tool: issue_refund
  requires_approval: true
  final_answer_must_include:
    - approval required
tags:
  - policy-boundary
  - tool-authorization

Freeze external context during offline tests. Use a known policy document, a fixture database, and fake tool adapters. Otherwise a changing search index or live account record can make a healthy build look broken. Keep a smaller integration suite for live dependencies, but do not mix its network variability into every pull request.

When production reveals a new failure, reduce it to the smallest safe fixture and add it to the dataset. That turns an incident into a permanent regression test. Remove personal data and secrets before storing the fixture.

Use the right grader for each claim

Use deterministic assertions wherever the expected result is exact. They are fast, cheap, and easy to debug. Good candidates include schema validation, required fields, numeric limits, selected tool names, argument values, call counts, citation presence, and forbidden content.

Use model-based grading only for criteria that require judgment, such as whether an answer follows a policy or resolves the user's request. The rubric should describe observable evidence and include examples of passing and failing responses. Run the grader against a labeled sample before trusting it. If it disagrees with reviewers on obvious cases, improve the rubric or keep that criterion under human review.

The LangSmith evaluation documentation separates offline evaluation on datasets from online evaluation on production traces and supports both final-response and agent-trajectory checks. That distinction is useful even if you use another platform. Offline tests gate a candidate release. Online checks find new cases and detect behavior that escaped the test set.

Use a grading stack that assigns each claim to the simplest reliable check:

  • schema and type checks for every structured boundary;
  • exact assertions for permissions, limits, and required state changes;
  • semantic checks for supported claims and task completion;
  • trajectory checks for action order and unnecessary tool calls;
  • human review for a small sample of high-risk or disputed cases.

Avoid one composite score that hides the cause of failure. A build with excellent writing quality and one unauthorized action must fail, regardless of its average.

Inspect the tool trajectory, not just the answer

For an agentic workflow, record each model decision, tool call, tool result, state transition, and final response. Then test the trace against the release contract.

The support example might require this sequence:

  1. Read the user request.
  2. Call get_order with the supplied order identifier.
  3. Compare the requested amount with the policy limit.
  4. Create an approval request when the amount exceeds the limit.
  5. Explain the pending approval without calling issue_refund.

The exact wording can vary. The action order cannot. A trajectory assertion catches a workflow that asks for approval after issuing the refund, or one that repeatedly calls get_order because it ignored a successful result.

Trajectory tests should allow harmless flexibility. If two read-only tools can run in either order, test the required set rather than one rigid sequence. If a write must follow approval, encode that partial order explicitly. This keeps tests focused on risk instead of implementation trivia.

Also test argument semantics. Confirm that identifiers came from the current request or trusted context, amounts use the correct currency, and optional fields did not inherit stale values from another run. A tool name alone is not enough evidence that the action was correct.

Run AI workflow regression testing in CI

A release pipeline should compare a candidate against a pinned baseline. Record the model version, prompt version, tool schemas, retrieval snapshot, dataset revision, grader version, and sampling settings for both runs. Without this manifest, a changed score cannot be traced to one cause.

Run deterministic checks first. Stop early on schema errors, forbidden tools, permission violations, or broken fixtures. Then run model calls and quality graders. Tools such as the open source Promptfoo evaluation framework show how assertions and evaluations can be automated in CI, but the same design works with a small custom runner.

Set gates by risk class rather than one global average:

  • hard invariants require a 100 percent pass rate;
  • critical policy cases permit no regression from the accepted baseline;
  • routine quality cases must meet a stated threshold and remain within an agreed change band;
  • cost, latency, and tool-call counts must stay within explicit ceilings.

Use enough repeated runs for cases where sampling variance matters. Do not repeat every deterministic case. Mark unstable cases and investigate why they vary instead of quietly widening the threshold.

Keep the pull-request suite small enough to finish promptly. Run the broader dataset nightly or before a production release. A slow suite that engineers bypass provides no protection.

Diagnose failures without chasing the average

When a gate fails, group results by dataset tag, changed component, and failure type. Ask what changed before editing the prompt.

A tool schema failure may come from a renamed field. A retrieval failure may come from the index snapshot. A policy-grader decline may expose an ambiguous rubric. A latency increase may follow an extra tool loop. Prompt edits are only one possible cause.

Save the candidate trace beside the baseline trace. A focused diff should show changed tool selections, arguments, retrieved documents, state transitions, grader reasons, tokens, and timing. This makes the failure reproducible and gives the owner of each component something concrete to inspect.

Treat flaky tests as defects. First pin all controllable inputs. Then check whether the criterion permits legitimate variation. If the behavior itself is unstable, keep the case visible and block high-risk releases until the team understands it. Re-running until a red build turns green only hides uncertainty.

External tool failures need a separate classification. A timeout from a fake adapter tests recovery logic. A real vendor outage during an integration run says little about response quality. Report infrastructure failures separately so they do not masquerade as model regressions.

Avoid five common evaluation mistakes

Tests cover only happy paths

Routine cases establish basic usefulness, but incidents usually sit at boundaries. Include missing identifiers, conflicting instructions, denied permissions, empty retrieval, tool timeouts, and repeated requests.

One model grader decides everything

A grader should not decide exact numeric limits, tool authorization, or schema validity. Deterministic code is clearer for those claims.

The test set changes with the release

If a candidate and its evaluation dataset change together, a new score may not be comparable. Review dataset changes separately and rerun the accepted baseline against the revised set.

The test ignores the action trace

A correct final answer can follow an unsafe action. Test side effects and their order directly.

The team optimizes for the benchmark

Keep a holdout set and add fresh production cases. If engineers repeatedly tune against the same visible examples, the suite measures familiarity rather than general reliability.

Verify that the suite protects a release

Before relying on the gate, run three deliberate experiments.

First, introduce a known schema break and confirm that deterministic checks fail before model grading begins. Second, alter a tool description so the agent chooses a forbidden write action and confirm that a trajectory gate blocks it. Third, weaken a policy instruction and confirm that quality checks detect unsupported approval or refund claims.

Review the resulting report with an engineer who did not build the runner. They should be able to identify the failing case, violated criterion, changed component, and baseline difference without reading raw logs. If they cannot, improve the report before adding more tests.

Track escaped failures after launch. Each meaningful incident should produce a sanitized fixture, a clear assertion or rubric, and an owner. Over time, the suite becomes a history of the workflow's real risks rather than a static demonstration set.

Put the first gate in place

Choose one high-value workflow and collect ten routine cases, ten boundary cases, and ten past or plausible failures. Write hard invariants first, then add only the judgment-based graders the task needs. Pin the candidate and baseline manifests, run both, and block the next release on permission, schema, and side-effect regressions.

That first gate will not prove the workflow is perfect. It will give the team a repeatable way to decide whether a change is safer than the version already in production. Add every confirmed escape to the dataset, and the release process will get sharper with real use.

References


About Fire In Belly: Independent senior engineering from Tallinn, Estonia. We design and build AI workflow automation with the release gates, trajectory checks, and regression suites described above, at published fixed prices. Schedule a call to discuss your next project.