Building Eval Harnesses for Multi-Step Tasks

RoadmapsAI Engineering

Overview

An agent evaluation harness is an automated testing infrastructure that combines mock environments, execution trace normalization, and code-based graders to measure if an agent successfully achieved a multi-step task.

Because agents take actions that alter state (like deleting rows or writing files), simply asking an LLM judge 'did the agent succeed?' based on a chat transcript is unreliable. You must use deterministic unit tests to verify real environment changes.

Where used: Enterprise agent testing pipelines, Continuous integration for AI systems, Debugging multi-step agent trajectories

Why learn this

Code walkthrough

def test_agent_refund_task(mock_db):
    # 1. Run the agent in a mocked environment
    agent = RefundAgent(db=mock_db)
    trace = agent.run("Refund user 123 for their last purchase")

    # 2. Extract normalized steps from the trace
    steps = normalize_trace(trace)

    # 3. Trajectory Eval (LLM Judge)
    assert llm_judge(steps) == "SUCCESS", "Agent failed to plan correctly"

    # 4. Outcome Eval (Code Grader)
    # The actual source of truth: did the DB change?
    user_record = mock_db.execute("SELECT status FROM users WHERE id = 123")
    assert user_record['status'] == 'refunded', "Agent claimed success but DB didn't update"

Focus: The separation between trajectory eval (llm_judge) and the outcome eval (code grader asserting the database state). Helper names are placeholders — the control flow is the point.

Common mistakes

Recall questions

Understanding checks

If you only use an LLM-as-judge on an agent's raw chat transcript, what happens when the agent hallucinates calling a refund tool?

The judge will likely score the agent as successful based on the hallucinated text, even though no refund occurred.

An LLM judge reading a transcript cannot verify external state changes. It only evaluates what the agent claims happened.

You wrote a code-based grader for a LangGraph agent, but it silently fails to read trace data when evaluating a custom REST agent. What step was skipped?

The raw execution traces were not normalized into a shared schema before grading.

Different frameworks emit structurally different trace logs. A modular importer must normalize these logs into a consistent format so the grader knows where to look for data.

Practice tasks

Build a Code-Based Grader

Write a Python function `grade_refund_task(db_connection)` that queries the mock database for user ID 123 and asserts their `status` is 'refunded'.

Continue learning

Previous: Agent Evals: Trajectory vs Outcome Scoring

Return to AI Engineering Roadmap