An agent can reason correctly and still fail the task.
The moment an LLM calls a tool, the problem changes. The model is no longer only generating text. It is proposing an operation against another systemβan API, database, filesystem, browser, shell, email service, payment system, or physical device.
That external system can reject the request, time out, partially execute it, return malformed data, change between calls, or succeed while the agent fails to observe the success.
This creates a crucial engineering boundary:
The model decides what it wants to do. The tool determines what actually happened.
A reliable agent has to connect those two worlds without confusing intention with reality.
A tool call has a lifecycle
Instead of thinking:
MODEL β TOOL β RESULT
think:
INTENT
β
SELECT TOOL
β
CONSTRUCT ARGUMENTS
β
VALIDATE REQUEST
β
AUTHORIZE
β
EXECUTE
β
OBSERVE RESULT
β
VERIFY EFFECT
β
UPDATE STATE
β
DECIDE WHAT HAPPENS NEXT
Not every application needs every layer explicitly. But every consequential tool integration should have an answer for these questions.
The most dangerous gap is between execute and observe.
Six ways tool use fails
1. The agent selects the wrong tool
An agent may have access to search_customer, update_customer, and delete_customer and select the wrong operation.
Tool descriptions reduce this risk but do not eliminate it. The model is still interpreting natural-language intent and mapping it onto an action space.
A particularly important failure is an unnecessary write when a read would have been sufficient.
If the user asks:
βWhat address do we have for this customer?β
there is no justification for calling update_customer simply because that tool happens to be available.
2. The tool arguments are syntactically valid but semantically wrong
Consider:
{
"customer_id": "4821",
"amount": 1000,
"currency": "USD"
}
This can be perfectly valid JSON and still be the wrong payment.
Schema validation can establish that the request has the right shape. It cannot establish that the agent selected the right customer or intended amount.
This is the difference between syntactic validity and semantic validity.
3. The external system fails
The service may return:
- authentication failure;
- authorization failure;
- validation error;
- rate limit;
- timeout;
- temporary server error;
- malformed response;
- dependency failure.
These failures are not interchangeable.
A 400-class validation problem generally calls for correcting the request. A transient service failure may justify a bounded retry. A permission failure may require escalation. A timeout can be fundamentally ambiguous if the operation had a side effect.
4. The tool succeeds but the intended outcome does not
Suppose an API responds:
HTTP 200
status: accepted
That does not necessarily mean:
βThe user's requested outcome is complete.β
The operation may have been queued. A downstream process may still fail. The returned object may describe acceptance rather than completion.
The agent needs to understand the tool's semantics rather than treating a successful transport response as proof of business success.
5. The action has a side effect
Reading a document and deleting it are not equivalent kinds of tool calls.
A useful starting classification is:
READ
β
REVERSIBLE WRITE
β
HIGH-IMPACT / IRREVERSIBLE WRITE
Examples of high-impact operations can include sending an external message, deleting important data, publishing information, changing permissions, purchasing something, or transferring funds.
The exact classification is application-specific. βReversibleβ is not synonymous with βlow risk.β An action that can technically be undone may still cause reputational, financial, privacy, or operational harm.
6. Recovery itself causes another failure
This is where naive agent loops become dangerous.
Imagine:
Agent β send email
β
timeout
β
Agent β send email again
What happened during the timeout?
There are at least two possibilities:
A. Request never reached the server.
B. Server accepted request, but response was lost.
The agent cannot safely infer A from the absence of a response.
Unknown outcome is a real state.
That single idea is worth remembering.
Example: the payment timeout
Suppose an agent is authorized to initiate a payment.
The request is submitted and the network connection times out.
A naive agent says:
βThe payment failed. I'll retry.β
A robust system asks:
βDo I know whether the payment happened?β
If the external system supports an idempotency mechanism, the retry may be safely associated with the same logical operation. If not, the system may need to query the payment status first.
A safer conceptual flow is:
SUBMIT PAYMENT
β
TIMEOUT
β
OUTCOME UNKNOWN
β
RECONCILE EXTERNAL STATE
β
βββ SUCCESS β STOP
β
βββ CONFIRMED FAILURE β
β retry only if policy permits
β
βββ STILL UNKNOWN β
escalate / reconcile further
The important concept is not βalways use idempotency keys.β Their availability and semantics depend on the API. The important concept is designing for ambiguous outcomes rather than pretending they cannot happen.
Tool descriptions are part of the control surface
A tool schema should tell the model what the operation does, but it should also make dangerous distinctions explicit.
Compare:
update_customer(customer_id, address)
with a richer conceptual interface:
update_customer(
customer_id,
new_address,
confirmation_required,
reason
)
The exact API design depends on the system. The broader principle is that important constraints should be represented in machine-enforceable interfaces where possible, rather than existing only in prose in a prompt.
If an operation must never happen without authorization, the application should enforce authorization. Do not rely exclusively on:
βDear model, please remember to ask for confirmation.β
Prompts are useful instructions. They are not security boundaries.
Copy-paste prompt: learn tool reliability
I want to learn how AI agents fail when using tools.
Act as a systems-engineering tutor.
Give me a realistic agent task involving at least three tools. Do not give me the solution immediately.
For each proposed tool call, ask me to identify:
1. Why the tool is needed.
2. What inputs are required.
3. Which inputs can be syntactically valid but semantically wrong.
4. What can fail before execution.
5. What can fail during execution.
6. What can fail after execution.
7. Whether the operation has side effects.
8. Whether repeating it is safe.
9. How its result can be verified.
10. When the agent should stop and ask a human.
After I answer, explain the reasoning and introduce a failure I did not anticipate.
At the end, redesign the workflow with explicit validation, authorization, bounded recovery, verification, and termination conditions.
Do the exercise interactively. The point is to develop a habit of asking what actually happened? after every consequential operation.
Preconditions and postconditions
A useful engineering technique is to describe important actions with preconditions and postconditions.
For example:
ACTION: Delete temporary file
PRECONDITIONS:
- file belongs to current job
- file is classified as temporary
- user/job is authorized
- file is not required by another active process
ACTION:
- delete file
POSTCONDITIONS:
- deletion operation reports success
- file no longer exists
- no dependent operation is broken
The exact checks depend on the application, but this structure forces an important distinction:
What must be true before acting, and what must be true after acting?
Without a postcondition, an agent can confuse a successful tool invocation with a successful outcome.
Copy-paste prompt: audit a real workflow
I am going to describe an AI workflow I use.
Analyze it as a reliability engineer.
WORKFLOW:
[DESCRIBE WORKFLOW]
For every external action or tool call:
1. State the intended outcome.
2. Classify it as READ, REVERSIBLE WRITE, or HIGH-IMPACT WRITE.
3. Define the preconditions that should be checked.
4. Identify authorization requirements.
5. Identify syntactically valid but semantically dangerous inputs.
6. List transient failures.
7. List permanent failures.
8. Identify ambiguous outcomes.
9. State whether retrying is safe.
10. Define how external state should be reconciled after an ambiguous result.
11. Define the postconditions that establish success.
12. Define when the agent must stop and ask a human.
Do not recommend a retry merely because an error occurred.
For every retry, explain why duplicate execution is safe or how the system first establishes the operation's current state.
This prompt can expose weaknesses in workflows that looked perfectly reasonable when described only as a sequence of natural-language instructions.
Retries are not automatically recovery
A common pattern is:
failure β retry β retry β retry β give up
This is incomplete.
Before retrying, ask:
Is the failure transient?
A malformed argument is unlikely to become correct by repeating it.
Is repetition safe?
Reading a resource may be safe to repeat. Creating a second order may not be.
Can the operation be identified uniquely?
An idempotency key or equivalent operation identifier can help an external service recognize repeated attempts as the same logical operation, where supported.
Can we reconcile state?
If the outcome is unknown, querying the external system may be safer than immediately executing the action again.
A robust retry policy therefore looks more like:
ERROR
β
CLASSIFY FAILURE
β
TRANSIENT? ββ NO β REPAIR / ESCALATE
β YES
SAFE TO REPEAT?
βββ YES β BOUNDED RETRY
βββ NO β RECONCILE / ESCALATE
Partial success is another state
Suppose an agent has to:
1. Create a project.
2. Add three users.
3. Upload five files.
4. Publish the project.
If step 3 fails after three files have uploaded, the system is not simply βfailed.β It is in a partially completed state.
The next action should depend on what actually exists.
A robust agent therefore needs state that can represent intermediate outcomes:
PROJECT CREATED: yes
USERS ADDED: 3/3
FILES UPLOADED: 3/5
PUBLISHED: no
That state can drive recovery far more safely than a single Boolean such as success=false.
This leads directly into our next architectural topic: state machines.
Copy-paste prompt: break your own agent
Take the workflow we designed and act as an adversarial reliability tester.
Try to make it fail without changing the user's goal.
Test at least these scenarios:
- wrong tool selected;
- valid but semantically wrong arguments;
- missing permission;
- stale information;
- timeout before the external system receives the request;
- timeout after the external system receives the request;
- duplicate execution;
- partial execution;
- unexpected tool output;
- misleading success response;
- external state changing between two steps;
- tool becoming unavailable midway through the workflow.
For every failure:
1. Describe the state before the failure.
2. Describe what the agent observes.
3. Explain what the agent might incorrectly assume.
4. State the safest next action.
5. State whether it should retry, repair, reconcile, request clarification, or escalate.
6. Define the evidence needed before declaring success.
Finish by ranking the three most dangerous failures and explain why.
This is more useful than asking an LLM to produce a perfect happy-path workflow. Reliability engineering starts by making failure explicit.
A tool result is evidence, not truth
There is another subtle point.
Suppose a browser tool says:
βOrder submitted successfully.β
The agent should normally treat that as evidence produced by the tool, not as a metaphysical guarantee that the desired real-world outcome has occurred.
The strength of the evidence depends on the tool's contract.
A response such as:
request accepted
job_id = 9182
is different from:
transaction completed
transaction_id = 7319
And even the latter may require application-specific reconciliation if downstream effects matter.
This is why tool integration is fundamentally a contract-design problem as well as a prompting problem.
What should be enforced outside the model?
A useful rule is:
If violating a constraint would be unacceptable, enforce it outside the model whenever technically possible.
Examples:
- authentication β application/security layer;
- authorization β policy enforcement;
- parameter types β schema validation;
- financial limits β deterministic rules;
- allowed destinations β allowlists/policy;
- duplicate prevention β idempotency or transactional controls;
- final state β external verification;
- audit requirements β system logging.
The LLM can participate in these decisions, but critical controls should not depend solely on the LLM faithfully following instructions.
Your practical exercise
Choose one agent workflow you use today.
Write down just five things:
1. PRECONDITION
What must be true before the action?
2. ACTION
What exactly changes outside the model?
3. EXPECTED RESULT
What should the tool report?
4. POSTCONDITION
What evidence establishes that the intended outcome occurred?
5. UNKNOWN OUTCOME
What should happen if we cannot determine whether the action occurred?
Then ask your LLM to challenge every line.
If you discover that you cannot answer βHow do we know the action actually happened?β, that is not a minor documentation problem. You have found a reliability boundary in the agent.
The mature agent is not the one that never encounters tool failures.
It is the one that knows when an action succeeded, when it failed, when its outcome is unknown, and what evidence is required before taking the next consequential step.
"A tool call is not text. It is an attempted operation against another system, with inputs, failure modes, side effects, and an uncertain outcome."