Engineering

Designing reliable agent tool calls

Most agent reliability problems that look like model problems are tool design problems. The model is asked to compensate for an interface that should not have been that shape.

NEOB Engineering Published Updated 10 min read
ai-agentstool-usearchitecturereliability

A tool is an interface between something that reasons probabilistically and something that has consequences. That asymmetry should drive every design decision, and mostly it does not - tools get generated from existing API surfaces and inherit shapes that assume a careful, deterministic caller.

Narrow tools beat generic tools

Given a generic create_calendar_event, the agent has to know opening hours, service durations, buffer times, and which resource handles which service. That knowledge ends up in the prompt, where it cannot be tested, cannot be versioned meaningfully, and degrades as the prompt grows.

Given find_slots(service, earliest, latest), the same knowledge lives in code. The prompt only has to be good at conversation.

GenericNarrow
Business rules live inThe promptThe tool
TestableNot reallyOrdinary unit tests
Wrong-answer modePlausible but invalid eventEmpty result
Prompt sizeGrows with every ruleStable
New rule costsPrompt edit + regression riskCode change + test
The same capability, two interfaces.

If a rule can be violated by a sentence in a prompt, it is not a rule. It is a suggestion with good intentions.

Idempotency is not optional

Agents retry. They retry because a call timed out, because the user asked "did that go through?", because a loop re-entered a step. Any tool with a side effect needs an idempotency key that is derived from the *intent*, not generated per attempt.

Derive the key from what makes two calls the same request
// Wrong: a fresh key per attempt means a retry creates a second booking.
const key = crypto.randomUUID()

// Right: same hold + same customer = same booking, however many times
// the agent (or the caller) asks for it.
const key = hash(`${holdId}:${customer.phone}:${slot.startsAt}`)

Distinguish "failed" from "the answer is no"

The most common tool-layer bug we see: a lookup with no results reported as an error. The agent then does the reasonable thing with an error - it retries. The retry also returns no results. The agent is now in a loop that cannot terminate, and the caller is listening to it.

  • Error - the tool could not answer: network failure, auth expired, upstream 500. Retrying may help.
  • Empty result - the tool answered, and the answer is nothing. Retrying will never help.
  • Refusal - the tool declined: out of scope, not permitted for this tenant. Retrying is a permission violation, not a retry.

Normalise these at the boundary, not in each tool. Wrapping an upstream API is where you decide which of its status codes mean which of the three - and it is the only place that decision can be made consistently.

Descriptions are prompts

Tool descriptions are read by the model at selection time and are, functionally, part of the prompt. We have watched two servers exposing the same capability produce noticeably different agent behaviour purely because of how their descriptions were worded.

  • Say what the tool does and when not to use it. Negative guidance disambiguates more than positive guidance.
  • Name the units and the timezone. duration is ambiguous; durationMinutes is not.
  • Describe the empty case explicitly, so an empty result is expected rather than surprising.
  • Keep names distinct across the catalogue. Two tools called search from different servers is a selection error waiting to happen.

Gate by consequence, not by tool

The useful axis for permissions is not which tool is being called but what it does to the world. Reads run freely; writes need a scope; irreversible actions need a human. Classifying by consequence means a new tool inherits the right treatment without anyone remembering to configure it.

  1. 01Proposed action
  2. 02Classify consequence
  3. 03Scope check
  4. 04Human approval if irreversible
  5. 05Execute
  6. 06Verify effect

The verify step is the one most often skipped. Confirming that a call returned 200 is not confirming that the intended thing happened - and an agent that assumes otherwise reports success it has not earned.

What we are still unsure about

How far the narrow-tool principle scales. Every business rule pushed into a tool is a rule the agent cannot adapt around, and there is presumably a point where a catalogue of very narrow tools is more brittle than a general one plus good instructions. We have not found that point, but we do not believe it is absent.