AssayAssay
02 / 08

Lesson 02 · Mechanics · 12 min

Tools and observations

A tool is described to the model as a name, a description and a JSON schema of arguments. The model never executes anything. It emits a request — this tool, these arguments — and your code decides whether and how to run it. That separation is what makes tools safe to reason about: every side effect passes through code you wrote.

The round trip has four parts, and each has to be right for the loop to work at all:

  • You send the conversation plus the tool definitions.
  • The model replies with one or more tool calls, each with an id.
  • You append the assistant's turn — including the calls it made — then run them.
  • You append one tool result per call, each tagged with the id of the call it answers.

Step three is where loops break most often, and the failure is confusing rather than loud. If you append the assistant's text but drop the tool calls it made, the model receives tool results that answer a request it has no record of making. Having no memory of asking, it asks again. And again.

// Wrong: the results arrive with nothing to attach to.
messages.push({ role: "assistant", content: reply.content });

// Right: the assistant turn carries the calls it made.
messages.push({
  role: "assistant",
  content: reply.content,
  tool_calls: calls,
});

This exact bug was written, shipped and caught while building this course. The loop repeated one policy lookup three times before a guard stopped it. Nothing errored — the model behaved reasonably given what it could see.

Tool descriptions matter more than they look. The model chooses between tools using only the name, the description and the argument schema. A vague description produces wrong-tool errors that look like reasoning failures but are really documentation failures.

Checkpoint

Find a tool call in the trace that was not needed for the answer.

“Where is my order 41902? It hasn't arrived yet.”

The shortest useful loop: one tool, one answer. A model that replies without calling anything is inventing the status.

Run the chained refund task and read every observation. Note which tool the agent reached for first, and whether that order was necessary.

Nothing has run yet. Pick a task and press Run — every iteration appears below.