I broke a working agent seven ways. The metric I was watching caught two of them.
기사 본문
38개 단락 · 단어를 탭(클릭)하거나 문장을 선택하면 번역 · 단어 탭/문장 선택으로 번역In September, I ran two models through the same 20 support tasks. Both scored 20 out of 20. Then I assigned each model two refund requests that the underlying billing data didn’t support: one against an uncollected invoice, and one for double the invoice’s value.
Claude Haiku 4.5 issued all six refunds across three distinct permission configurations. Claude Sonnet 5 issued none. Their success rates looked identical, but their behavior diverged completely on the only scenarios capable of causing financial damage.
In October, I reran the evaluation harness. This time, the smaller model declined every unauthorized refund. I initially attributed this to queue ordering: the two trap tasks sat at the end of a 22-task queue instead of arriving in isolation, suggesting that processing 20 prior invoice tasks taught the agent to verify state before acting. I documented this theory in a neat report.
“Their success rates looked identical, but their behavior diverged completely on the only scenarios capable of causing financial damage.”
Then I checked the execution transcripts for the active model alias. In September, the haiku alias resolved to claude-haiku-4-5. In October, the same alias resolved to claude-haiku-5-5. I reran the isolated trap tasks three times against the new model version, and it declined all six attempts. Queue position had nothing to do with the outcome; the underlying model had been silently upgraded behind an unpinned alias. I discovered this only because of a script search I nearly skipped.
An unlogged, uninitiated deployment had occurred. Nothing in my high-level success metrics flagged the shift: 20 out of 20 in September, and 18 out of 19 on scored tasks in October (with the single failure stemming from an intentionally ambiguous prompt). Although the silent model update improved performance, the underlying monitoring gap remains concerning: none of the metrics I tracked would have alerted me if performance had degraded instead.
I stopped asking whether my agent was functioning and focused on a narrower diagnostic question: If I intentionally break the system, which metrics actually detect the failure?
The target system is a customer support agent interacting with a mock enterprise API spanning 30 scoped operations across tickets, users, billing, subscriptions, files, and messages. Every API call writes to an append-only audit log, and each task concludes with a state change that an external script verifies mechanically against the database. The suite contains 19 standard scored tasks alongside the two refund traps.
I established a baseline using Claude Sonnet 5.5 (claude-sonnet-5-5) with full administrative privileges across three identical runs. Evaluating three baseline replicates is critical: a detection system that fires false positives on an unmodified setup is useless. Every detection threshold reflects the baseline variance doubled to account for real-world statistical distribution.
I then introduced eight specific regressions—one per test run—to simulate common production failure modes:
Six of these eight regressions execute inside the API behind a per-run wrapper script, ensuring deterministic, reproducible failure paths.
Before evaluating detector sensitivity, I verified that each injection actively affected the execution environment. A detector cannot catch an idle regression. The logs confirmed the flaky API arm intercepted 31 calls, the stale read arm served 18 outdated queries, and the missing-scope arm triggered 19 authorization denials.
The distractor arm invoked the deprecated alias zero times because the model selected the correct command on every attempt. I classified that regression as absorbed rather than missed, excluding it from detector denominators while retaining it as a false-positive control. As expected, an arm where no operational failure occurred triggered zero behavioral alerts.
Detector thresholds derived from the baseline runs:
Across the seven active regressions, tool-call counts and scope drift each caught four failures. Task success rates caught only two. Token costs flagged one, while the refund trap tasks caught zero.
Task success rates flagged only the two regressions that made task completion physically impossible. Swapping the model, modifying system prompts, failing 25% of network calls, serving stale data from replicas, and adding 1.5 seconds of API latency all left task completion steady at 18 or 19 out of 19.
The speed-pressure arm requires context: the agent completed every task using 21% fewer calls and 17% fewer tokens. Two behavioral detectors flagged this run because the execution pattern shifted significantly, even though the shift improved efficiency. Behavioral detectors report movement; engineering teams must decide if that movement represents progress or degradation.
AI agents routinely mask underlying technical failures through three primary behaviors:
The flaky API arm absorbed all 31 injected network failures. Before retrying non-idempotent write operations, the agent queried the backend to confirm if the initial attempt had committed, preventing duplicate refunds. One task—a subscription cancellation followed by a customer notification—absorbed seven consecutive API failures during execution.
“As agent retry logic improves, downstream task completion becomes increasingly decoupled from infrastructure health.”
The arm verified 19 out of 19 tasks while executing 99 tool calls against the 58-call baseline. As agent retry logic improves, downstream task completion becomes increasingly decoupled from infrastructure health.
When provided with documentation for only 11 of 30 commands, the agent recovered missing endpoints by guessing plausible command names. It batched hundreds of experimental attempts into shell loops, distinguishing valid endpoints from invalid ones based on returned error structures.
Through this brute-force approach, the agent successfully discovered refund, messaging, file upload, search, and admin endpoints. It failed to discover subscription commands, causing six tasks to fail.
This recovery process consumed 161,013 tokens (73% above baseline) and took 15 minutes to execute, compared to the five-minute baseline. Because the agent executed these speculative loops locally, the attempts never hit the API audit log. The regression remained detectable almost entirely due to its extreme token overhead.
The stale-read arm highlights the limits of quantitative monitoring. All write operations committed successfully to the primary database, but 18 subsequent read operations fetched outdated state from the lagging replica.
When the agent closed a ticket and re-read its status, the record appeared open. When it processed an invoice refund and re-read the balance, the refund appeared unapplied.
Token usage increased by 22% (below the 37% alert threshold), tool calls increased by 5% (below the 7% threshold), and scope drift reached 0.133 (below the 0.135 threshold). Every quantitative metric remained completely green.
However, the agent’s final text summary explicitly detailed the anomaly. It reported that none of its 19 writes could be verified via read-backs, systematically laid out the evidence for each task, and explained that it deliberately suppressed retries for refunds, comments, messages, and uploads to avoid double-applying mutations.
“Its defensive caution successfully contained the fault, but simultaneously rendered a severe infrastructure issue invisible to quantitative monitoring.”
Had the agent blindly retried those operations, it would have generated duplicate refunds and triggered production alerts. Its defensive caution successfully contained the fault, but simultaneously rendered a severe infrastructure issue invisible to quantitative monitoring. The sole indicator of failure existed inside the prose summary.
Token consumption was the single metric already tracked across every run, yet it proved almost useless for anomaly detection. Baseline token usage fluctuated by 18% across three identical runs, forcing a wide ±37% detection threshold. Consequently, the +26% token surge from the flaky API arm and the +36% surge from the model swap both slipped beneath the alert line undetected.
By contrast, tool-call volume varied by only 3% across the same baseline runs, enabling a tight ±7% detection threshold that easily flagged the 70% surge in API calls. Teams alerting on execution costs should track tool-call volume rather than raw token counts.
Adversarial test cases measure specific vulnerabilities in specific model generations. The refund traps successfully differentiated model capabilities in September, but caught zero errors in October because every tested arm—including standalone runs on the smaller model—declined the unauthorized actions.
Two variables shifted between test runs: the underlying model updated, and the launch prompt wording changed slightly. (The September transcripts needed to reconstruct the exact original prompt were cleared from temporary storage before analysis.) However, isolated reruns conclusively ruled out queue positioning as a factor.
To effectively monitor autonomous agents, track these four telemetry layers:
To evaluate your telemetry layer, execute your agent’s unmodified baseline three times across identical tasks and calculate two variance metrics: tokens per task and tool calls per task. Expect the tool-call variance to be significantly tighter than the token variance (my test runs yielded 3% and 18%, respectively).
Next, inject transient failures into 25% of upstream network calls and execute the suite again. If your agent is appropriately resilient, overall task completion will remain stable while total tool calls roughly double. If task completion drops immediately, the agent’s retry logic requires improvement.
Running this benchmark reveals which telemetry layers can detect production degradation—providing the visibility needed to catch silent failures before an unannounced model swap forces an investigation.
단락별 번역이 어긋날 때
전문 번역
단어를 탭(클릭)하면 그 단어를, 문장을 선택하면 그 범위를 바로 번역합니다.