Agent patternsPatternProven

ReAct

Also called: reason and act, thought-action-observation

ReAct interleaves reasoning and acting: the model thinks, takes one action, reads the result, and thinks again. It is the loop underneath most agents, and its defining property is that the next step is chosen after seeing the last result.

James Phoenix
Understanding Data Updated July 26, 2026

ReAct is the cycle that turns tool use into an agent: thought, action, observation, repeat. The model reasons about what to do, does one thing, sees what happened, and reasons again with that result in hand.

The loop is short:

TypeScript
const messages = [{ role: 'user', content: task }]

for (let step = 0; step < MAX_STEPS; step++) {
  const response = await model({ messages, tools })
  messages.push(response)              // thought + action

  // no action means it is answering
  if (!response.toolCalls?.length) break

  for (const call of response.toolCalls) {
    const result = await runTool(call)
    messages.push({                    // observation
      role: 'tool',
      toolCallId: call.id,
      content: result,
    })
  }
}

Everything the agent has learned lives in messages, which is why the loop works and also why it degrades: the history *is* the state.

What a trace looks like

Text
Thought:      Tests fail on CI, not locally. Check the CI config.
Action:       read_file(".github/workflows/test.yml")
Observation:  node-version: 18
Thought:      Local is Node 22. Check what the package requires.
Action:       read_file("package.json")
Observation:  "engines": { "node": ">=20" }
Thought:      That is it. CI runs 18, the package needs 20+.

Nothing here could have been planned up front. Step two only makes sense once step one has returned.

Where it is the right shape

When the path depends on what you find. Debugging, exploration, research, anything where the second move is a function of the first result. If you can write the steps down before starting, prompt chaining is cheaper and far easier to debug.

The costs

  • Context grows every step. Each observation is appended forever, so long runs hit context rot. Truncate old observations, or write findings to a scratchpad and drop the raw output.
  • Errors compound. A wrong conclusion at step three shapes steps four through twelve, and the loop rarely revisits it.
  • Bound the steps. MAX_STEPS is not optional. Without it a confused agent will keep paying for its own confusion.
Tip
Log the full trace, not just the final answer. When a ReAct agent produces something wrong, the failure is almost always visible as one bad observation or one wrong inference several steps back, and the trace is the only place you can see it.

Related terms

Engineering context for real systems?

Getting the right information into the window at the right time is most of the job. If you want that thinking applied to your product, that is what I do.

See how I can help