DEV Community

Cover image for Why AI Agents Break in Production (and How to Test for Each Failure Mode)
Hassann
Hassann

Posted on • Originally published at apidog.com

Why AI Agents Break in Production (and How to Test for Each Failure Mode)

Your agent worked in the demo: it read a ticket, called three APIs, and posted a clean summary. Then production happened—duplicate emails, retry loops that burned through token budgets, and payloads your frontend could not parse.

Try Apidog today

The gap between a working prototype and a reliable agent is usually not the model. It is the API layer around it. Every tool call is an HTTP request that can fail, throttle, time out, or return an unexpected payload. If you do not test those calls like production API integrations, one bad response can become an incident.

The practical approach is to test agent behavior at the API boundary: define tool contracts, mock dependency failures, run realistic scenarios, and assert on requests, responses, retries, and guardrails. This guide covers five failure modes and how to test them with Apidog.

Agents fail at the API boundary, not in the prompt

When an agent behaves incorrectly in production, editing the prompt is often the first reaction. Sometimes that helps. More often, the agent received a slow, malformed, rate-limited, or unexpected API response and then made a confident decision using bad input.

A typical agent step has four parts:

  1. The model selects a tool.
  2. Your application converts that selection into an HTTP request.
  3. An external service returns a response.
  4. Your application passes the result back to the model.

Three of these four steps are standard API integration work. Treat them accordingly: validate schemas, mock failures, and assert on behavior.

The reliability question is not only, “Is the model smart enough?” It is also:

Have we tested the ways this agent’s API calls can fail?

Failure mode 1: Tool calls drift from the contract

A common failure is an agent generating a call that does not match the API contract. It may invent a parameter, omit a required field, send a string instead of an integer, or use valid fields with invalid values.

For example, a booking agent might call:

POST /reservations

{
  "guests": "two"
}
Enter fullscreen mode Exit fullscreen mode

when the API requires:

{
  "guests": 2
}
Enter fullscreen mode Exit fullscreen mode

The API might return a 400. Worse, it might return 200 OK with an error hidden in the response body, and the agent may continue as if the reservation succeeded.

How to test it

Treat every tool invocation as a contract test:

  1. Define an input schema for every tool.
  2. Validate required fields, types, enums, and formats.
  3. Run the agent against those contracts.
  4. Fail the test when the generated request does not conform.

For example, a reservation tool schema should make the expected type explicit:

{
  "type": "object",
  "required": ["guests", "date"],
  "properties": {
    "guests": {
      "type": "integer",
      "minimum": 1
    },
    "date": {
      "type": "string",
      "format": "date"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Use Apidog to store tool contracts and validate the agent’s outgoing requests against them. A mismatch should identify the exact invalid field before it reaches production.

For a deeper walkthrough, see testing an AI agent’s tool calls and testing agents that call your APIs.

Failure mode 2: Upstream errors and rate limits

Every dependency can return a 429, 500, malformed response, or timeout. A robust agent backs off and retries safely. A fragile one either gives up immediately or retries aggressively until it causes more throttling and drains its budget.

Patterns for this kind of agent error recovery are a recurring concern because healthy APIs do not exercise the failure handling you need to verify.

How to test it

Mock the dependency and return a controlled sequence of failures:

  1. Return 429 Too Many Requests with a Retry-After header.
  2. Return 500 Internal Server Error.
  3. Return a successful response.
  4. Assert that the agent retries correctly and eventually succeeds or exits safely.

Your tests should verify that the agent:

  • Respects Retry-After.
  • Uses backoff and jitter.
  • Stops after a bounded number of retries.
  • Avoids hammering an unavailable service.
  • Opens a circuit breaker when appropriate.
  • Reports a useful failure when recovery is exhausted.

A retry must also be safe. If the action sends an email, creates an order, or charges a customer, a repeated request must not repeat the side effect. Use an idempotency key for operations that can be retried.

A simple test scenario can look like this:

Attempt 1 -> 429 + Retry-After: 2
Attempt 2 -> 500
Attempt 3 -> 200

Expected:
- Wait before retrying
- Do not exceed configured retry limit
- Send the same idempotency key on retries
- Complete the action once
Enter fullscreen mode Exit fullscreen mode

Read what a rate-limit-exceeded response means before simulating provider throttling. For implementation patterns, see AI agent error recovery.

Failure mode 3: Non-deterministic output

Even at temperature zero, model output is not always byte-for-byte identical. Hardware, batching, provider-side changes, and runtime differences can introduce variation. The long vLLM discussion on reproducibility shows why seeds and temperature are not enough.

If your tests compare exact response strings, they become flaky. Flaky tests get ignored, which is worse than having no test at all. The same principles described in what causes flaky tests apply to agent tests.

How to test it

Assert on structure and meaning instead of exact wording.

Avoid this:

expect(response.text).toBe("Your order total is $42.00.");
Enter fullscreen mode Exit fullscreen mode

Prefer assertions like this:

expect(response).toMatchObject({
  action: "order_summary",
  total: expect.any(Number)
});

expect(response.total).toBeGreaterThanOrEqual(0);
expect(response.total).toBeLessThanOrEqual(cart.total);
Enter fullscreen mode Exit fullscreen mode

Useful checks include:

  • The response validates against a JSON schema.
  • The correct tool was selected.
  • The tool call has valid parameters.
  • Required keys are present.
  • Forbidden fields are absent.
  • Numeric values are within acceptable ranges.
  • The output contains the expected action or status.

For example, test the semantic requirement:

The reply must contain:
- a total
- a currency
- no customer payment details
- a total between 0 and the cart value
Enter fullscreen mode Exit fullscreen mode

That test tolerates natural wording changes while still catching a real regression.

See testing non-deterministic AI agents for more strategies. If your agent stores context across runs, review how agent memory works as well.

Failure mode 4: Runaway cost

Agents loop, and loops cost money. A stuck agent can retry a failing operation thousands of times, repeatedly call the same tool, or keep expanding its context until a small workload becomes an expensive one.

Cost is a reliability issue, not just a finance issue. The same bugs that increase spending also make agents slow and unpredictable.

How to test it

Track cost-related signals for every test run:

  • Number of model calls
  • Number of tool calls
  • Tokens per run
  • Retry count
  • Total execution time
  • Context size

Then enforce limits:

max_tool_calls = 10
max_retries_per_request = 3
max_tokens_per_task = configured budget
max_execution_time = configured timeout
Enter fullscreen mode Exit fullscreen mode

Your recovery-path tests should assert on call count, not only final success:

expect(mockApi.callCount).toBeLessThanOrEqual(3);
expect(agent.toolCallCount).toBeLessThanOrEqual(10);
Enter fullscreen mode Exit fullscreen mode

An agent that reaches the correct answer after 40 API calls may still be a production incident waiting to happen.

For practical ways to reduce usage, see reducing agent token costs.

Failure mode 5: Missing guardrails

The most damaging failures happen when an agent successfully performs the wrong real-world action: sending an email, deleting a record, placing an order, or modifying production data.

The model may have followed its instructions exactly. The system failed because nothing stood between the model’s decision and a live, irreversible API call.

How to test it

Add explicit control points around side effects:

  1. Allowlist actions that can run without approval.
  2. Require human confirmation for destructive or irreversible actions.
  3. Add a dry-run mode that reports intended actions without executing them.
  4. Limit the scope of actions the agent can perform.

For example:

Allowed automatically:
- Read ticket
- Search customer record
- Draft email

Requires approval:
- Send email
- Delete record
- Issue refund
- Create order
Enter fullscreen mode Exit fullscreen mode

Then test the guardrail path with mocked side-effecting endpoints:

Given:
- The agent decides to send an email
- Approval has not been granted

Expect:
- The agent creates a confirmation request
- The live email endpoint is not called
Enter fullscreen mode Exit fullscreen mode

Do not assume the guardrail works because the code exists. Assert that the mock endpoint received zero calls until approval is provided.

The OWASP Top 10 for LLM applications is a useful checklist for identifying actions and data that need protection. For approval flows and blast-radius controls, see AI agent guardrails.

How to structure an agent test

The five failure modes use the same repeatable test structure:

  1. Capture tool schemas

    Define the request and response contracts for every tool the agent can call.

  2. Mock dependencies

    Control status codes, timing, headers, bodies, and side effects.

  3. Run a scenario

    Drive the agent through normal and failure paths, including conditions that live APIs will not reliably produce on demand.

  4. Assert on behavior

    Validate request shape, retry behavior, call count, output structure, and guardrail activation.

A minimal test matrix might look like this:

Scenario Mock response Expected behavior
Invalid tool argument 400 validation error Agent reports or corrects invalid input
Rate-limited API 429 with Retry-After Agent backs off and retries within limits
Temporary outage 500 then 200 Agent recovers without duplicate side effects
Malformed payload Invalid JSON or missing field Agent stops or handles the invalid response safely
Destructive action Approval required Agent requests confirmation and does not call live action

Start with one tool, make it reliable, then add the next one.

The agent reliability checklist

Before shipping an agent, verify the following:

  • [ ] Every tool call is validated against a schema.
  • [ ] Contract violations fail a test.
  • [ ] 429, 500, timeout, and malformed-response cases are simulated.
  • [ ] Retry behavior uses backoff and has a bounded attempt count.
  • [ ] Retried actions are idempotent and cannot double-charge or double-send.
  • [ ] Tests assert on structure and meaning, not exact output strings.
  • [ ] Token usage and tool-call counts are measured per run.
  • [ ] Budget caps stop runaway loops.
  • [ ] Destructive actions require an allowlist or human approval.
  • [ ] Guardrail paths are tested with mocks.

Where Apidog fits—and where it does not

Apidog is not an agent framework, model host, or evaluation harness. It does not build or run your agent.

Its role is the API layer your agent depends on:

  • Store and design contracts for agent tools.
  • Validate outgoing requests against those contracts.
  • Mock dependencies and failure responses such as 429, 500, timeouts, and malformed bodies.
  • Assert on schemas, response shapes, required keys, and value ranges.

That makes it useful for rehearsing the API failures an agent must handle before users encounter them. For the broader QA context, read agentic AI testing.

Frequently asked questions

Is agent reliability a model problem or an engineering problem?

Mostly engineering. Model choice matters, but many production incidents come from bad tool calls, unhandled rate limits, missing idempotency, and missing guardrails.

Can I test an agent without hitting its real APIs?

Yes—and you should. Mock dependencies so you can force failures, control timing, and avoid real-world side effects. This is the reliable way to test recovery and approval paths.

How do I test output that changes on every run?

Assert on schemas, tool-call shape, required fields, forbidden fields, and numeric ranges instead of exact strings. See testing non-deterministic AI agents.

What should I test first?

Start with destructive-action guardrails and error recovery. These protect against the most expensive failures: harmful side effects and loops that drain your budget.

Start with one failure mode

You do not need to implement every test at once. Pick the failure mode with the highest risk—usually guardrails or error recovery—and test it this week.

Program the failure. Run the agent. Inspect the requests it makes and the actions it avoids.

When your agent handles a simulated 429 with bounded backoff instead of entering a budget-draining loop, you will have a stronger reason to trust it than a green demo.

Download Apidog to design tool contracts, mock dependency failures, and validate the API behavior your agent depends on.

Top comments (0)