DEV Community

Cover image for Your Agent Eval Set Is Rotting: Build a Failure-Mining Loop for Google ADK
Raju Dandigam
Raju Dandigam

Posted on

Your Agent Eval Set Is Rotting: Build a Failure-Mining Loop for Google ADK

An agent evaluation set starts healthy. It contains the obvious intents, a few tool failures, and the happy paths used during development.

Six months later, production has changed. New tools exist. Users phrase requests differently. A fallback introduced last quarter now handles 30% of traffic. Yet CI still runs the same twelve examples and reports green.

The problem is not only stale prompts. The eval set itself is rotting.

A durable evaluation program needs a controlled path from observed failures back into tests:

observed run -> candidate -> human review -> sanitization
             -> eval case -> CI -> release comparison
Enter fullscreen mode Exit fullscreen mode

First, define a failure candidate

Do not copy complete production conversations into a test folder. Create a bounded intermediate record:

type FailureCandidate = {
  candidateId: string;
  detectedAt: string;
  intent: string;
  terminalOutcome: "failed" | "escalated" | "wrong_outcome";
  firstFailureRole?: "model" | "tool" | "handoff" | "policy";
  toolSequence: string[];
  reasonCode: string;
  sourceReference: string; // restricted internal pointer
};
Enter fullscreen mode Exit fullscreen mode

This record is for triage. It is not automatically an eval case, and it should not contain raw customer content unless your approved process requires it.

Mine patterns, not anecdotes

The loudest incident is not necessarily the most representative. Select candidates across several dimensions:

  • intent and workflow;
  • tool and failure role;
  • successful recovery versus escalation;
  • common and rare trajectory shapes;
  • model, prompt, policy, and dataset version;
  • outcome severity.

A simple trajectory signature helps deduplicate repeated symptoms:

import { createHash } from "node:crypto";

function signature(c: FailureCandidate): string {
  return createHash("sha256")
    .update([
      c.intent,
      c.terminalOutcome,
      c.reasonCode,
      c.toolSequence.join(">"),
    ].join("|"))
    .digest("hex");
}
Enter fullscreen mode Exit fullscreen mode

The hash does not prove two failures have the same cause. It creates a grouping candidate for human review. Keep a few examples from a large cluster, but do not allow one outage to dominate the suite.

Convert only after review

A useful promotion checklist is:

  1. confirm the failure is real rather than an instrumentation or harness defect;
  2. identify the smallest reproducible input and environment state;
  3. remove personal, proprietary, and transient data;
  4. label the expected tool behavior and business outcome;
  5. record why the case deserves long-term coverage;
  6. assign an owner and review date.

The resulting case should be synthetic or safely transformed:

{
  "caseId": "refund-policy-stale-cache",
  "input": "Can this synthetic order still be refunded?",
  "fixture": "order-after-policy-window.json",
  "expected": {
    "requiredTools": ["lookup_order", "lookup_policy"],
    "forbiddenTools": ["issue_refund"],
    "outcome": "ask_or_decline"
  }
}
Enter fullscreen mode Exit fullscreen mode

Evaluate more than the final answer

Google's Agents CLI evaluation model distinguishes dimensions such as tool-use quality, multi-turn tool use, trajectory quality, task success, and final-response quality. That separation is important: a fluent answer can follow the wrong path, while an awkward answer may have used tools correctly. See the official evaluation guide.

Use deterministic checks for stable facts:

  • a protected tool was absent;
  • authorization preceded execution;
  • a handoff included required fields;
  • the run completed within a controlled call budget.

Use semantic graders for questions that genuinely require judgment, such as helpfulness or groundedness. Keep their reports separate so engineers know whether CI found a structural violation or a probabilistic quality regression.

Where local traces help

I maintain AgentInspect; it is one concrete implementation of this broader pattern. With agent-inspect@6.19.0, a TypeScript team can turn supported local traces into bounded facts and deterministic trajectory checks. It is not a production sampling or dataset-management platform. Production selection, privacy review, and ADK evaluation remain separate responsibilities.

That boundary is useful: the same failure can move through distinct trust zones instead of silently becoming training or test data.

Add retirement, not only promotion

Eval suites also need deletion rules. Retire or revise a case when:

  • its feature no longer exists;
  • its fixture depends on an obsolete schema;
  • several cases test the same invariant;
  • the original expected behavior is no longer correct.

Track suite composition by intent and failure role. A growing case count is not evidence of improving coverage.

Measure the health of the suite itself

Give each case provenance and a review clock:

type EvalCaseMetadata = {
  caseId: string;
  promotedFrom: string;
  owner: string;
  addedAt: string;
  reviewAfter: string;
  intent: string;
  firstFailureRole: "model" | "tool" | "handoff" | "policy";
};
Enter fullscreen mode Exit fullscreen mode

A small dashboard can then expose coverage by intent, age, failure role, and last meaningful failure. Flag cases that have not been reviewed after a tool-schema or policy revision. The point is not to delete old cases automatically; it is to make stale expectations visible before they become release authority.

Watch the promotion funnel as well: candidates detected, candidates reviewed, cases accepted, duplicates rejected, and cases retired. A sudden drop between detection and review often signals an ownership problem rather than an agent-quality improvement.

Close the loop deliberately

The goal is not to replay production. It is to convert reviewed failures into small, safe, owned regression cases. Start with the last ten meaningful incidents. Group them, select representatives, sanitize them, and label both trajectory and outcome expectations.

An eval set stays useful when production teaches it—through a controlled review boundary, not an automatic data pipe.

References

Top comments (0)