Four Tool Calls to One Answer: A Research Run, Annotated

A research agent answers one question in four steps. Reading what changed in the transcript between each step explains more about how agents work than any diagram of the loop.

Someone asks a research agent: which of our competitors changed their pricing this year? Thirty seconds later there is an answer. In between, four tool calls happened, and each one was decided by something specific that had just landed in the transcript.

Walking through those four steps is more useful than any diagram of the agent loop, because it shows the one thing beginners consistently get wrong about how an agent decides what to do next.

What the agent starts with

Three things, and nothing else:

  • A system prompt: you are a research assistant, use search to verify claims, cite the page you took each fact from.
  • Two tools: web_search(query) returning titles and snippets, and fetch_page(url) returning the page text.
  • The question.

No memory of the person asking. No browsing history. No hidden scratchpad. Whatever the agent appears to "know" at step four has to have arrived through one of those two tools, in full view.

Step 1: the search that was shaped wrong

The agent's first move:

web_search("competitors that changed pricing this year")

Which returns generic listicles about pricing strategy. Nothing about any specific company.

This is worth pausing on, because a beginner's expectation is that the agent will craft a clever query. It usually doesn't on the first try, and the reason is visible in the transcript: at this moment the context contains only the system prompt and the question. The agent has no competitor names, because nobody gave it any and it hasn't looked any up. Rephrasing the question is genuinely the best available move.

💡 A first search that returns junk is not a malfunction. It is the agent doing the only thing the context supported.

Step 2: the refinement, and why it was possible

web_search("Acme Corp pricing change 2026")

Better results: a pricing page and a news item.

The interesting question is what changed between step 1 and step 2. Not the model, not the prompt, not the tools. The only difference is that the transcript now contains a failed search and its useless results.

This is the part beginners tend to model incorrectly. The agent is not remembering that its first search failed, in the way a person remembers. Every single turn, the entire transcript is sent to the model again from the beginning — system prompt, question, search call, search results — and the model produces the next line. It is re-reading, not recalling.

That has a practical consequence: if something isn't written into the transcript, it does not exist to the agent. A tool that fails silently and returns an empty string teaches the agent nothing, and it will happily make the same call again.

Step 3: fetching the page instead of trusting the snippet

fetch_page("https://example.com/acme/pricing")

Search gave a snippet that read like an answer. The agent fetched the page anyway, because the system prompt said to cite the page each fact came from, and a snippet is not a page.

Snippets are the most common source of confident wrong answers in research agents. They are truncated, sometimes stale, and often assembled from a part of the page that isn't the part that matters. An agent that answers from snippets alone will be fast, fluent, and occasionally quoting a price from two years ago.

Two calls where one looked sufficient is usually the correct trade in research work.

Step 4: the second competitor, and then it stopped

One more search-and-fetch pair for a second competitor, and the agent wrote its answer.

⚠️ Nothing made it stop. There was no counter, no rule saying "check three companies," no list of competitors it was working through. It stopped because, reading the transcript, producing an answer looked like the reasonable next line.

That is the fragile part of the whole run. Stopping is a judgement, not a mechanism. The same run with a slightly different first search might have checked one competitor and stopped, presenting a partial answer with the same confident tone. If completeness matters, it has to come from somewhere concrete: the list of competitors passed in with the question, or a check the code performs on the answer.

What actually decided each step

Every branch in that run came from one of four things:

  1. What was already in the transcript, especially the most recent tool result.
  2. Which tools exist and how their descriptions read.
  3. The standing instructions in the system prompt (which is why "cite the page" produced step 3).
  4. Whether the previous result looked useful enough to build on.

There is no fifth item. No hidden state, no memory the trace doesn't show.

🔍 Reading your own traces

Two habits make agent traces readable quickly:

Read the tool results before you read the final answer. The answer is the most polished part of the trace and the least informative. What the agent actually had to work with is in the tool results, and most bad answers are visible there — an empty result, an error string that got treated as data, a page that didn't contain what the snippet promised.

At each assistant turn, ask what new information made this turn different from the last one. If a turn issues a call that is nearly identical to the previous one, and no new information arrived in between, that is a loop starting. Catching it at turn three is much cheaper than capping it at turn twenty.

An agent run is a transcript that grows one message at a time, and everything the agent knows at the end is sitting in it. Debugging agents is mostly reading.

Keep reading

Similar posts

Matched on shared tags and category — the more bars, the stronger the overlap with what you just read.