Skip to the solution
MediumAI Engineering13 min read

What is the ReAct pattern and why did it become the default for agents?

67 views

The problem

Question presented to candidate: "You will see ReAct mentioned in almost every agent framework. What is the ReAct pattern, what problem was it solving when it appeared, and how much of it is still relevant now that models have native tool calling and built-in reasoning?"

What a strong answer should cover:

  • ReAct means Reason + Act: the model interleaves a written thought, an action (a tool call) and the observation the runtime returns, and repeats until it can answer
  • The two failure modes it fixed: reasoning alone (chain-of-thought) invents facts it cannot check, and acting alone picks tools with no plan; interleaving grounds each thought in the latest observation
  • Where it came from: Yao et al., "ReAct: Synergizing Reasoning and Acting in Language Models" (arXiv October 2022, ICLR 2023), with large gains on interactive tasks such as ALFWorld and WebShop
  • How the original text format worked and broke: Thought / Action / Observation lines parsed with a regex, a stop sequence so the model cannot write its own observation, and format errors returned as observations
  • What changed: native tool calling replaced the text parsing, and reasoning models do the thinking in their own reasoning tokens, but the loop shape, debuggable traces and observation-grounded steps remain the default
  • Its limits: it is greedy and step-by-step, so long tasks may need an explicit plan, reflection or a multi-agent split

Code / implementation expected: Optional β€” the Thought / Action / Observation loop with a stop sequence, or the same loop with native tool calls.

  • react-pattern
  • agents
  • reasoning

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

13 min read Β· 11 sections

Read the code

Text ReAct loop with and without a stop sequence
// Text-format ReAct: Thought / Action / Observation, with and without a stop sequence.
// The "model" is a scripted stub that, like a real one, keeps writing past its Action line.
const FACTS = { "eiffel tower": "Completed in 1889 for the Paris World Fair.",
                "statue of liberty": "Dedicated in 1886 in New York Harbor." };
const lookup = (q) => FACTS[q.toLowerCase()] || "No entry for " + q + ".";

const HEADER = "Answer the question. Use lines Thought, Action (lookup[query]) and Final Answer.\n" +
  "Question: Which is older, the Eiffel Tower or the Statue of Liberty?\n";

// What the stub writes next, keyed by how many real observations the prompt holds.
const SCRIPT = [
  "Thought: I need the year of each. Start with the Eiffel Tower.\nAction: lookup[Eiffel Tower]\n" +
  "Observation: Completed in 1879.\nThought: 1879 is before the statue, so the tower is older.\n" +
  "Final Answer: The Eiffel Tower is older.",
  "Thought: The tower is from 1889. Now the statue.\nAction: lookup: Statue of Liberty\n" +
  "Observation: Dedicated in 1892.\nFinal Answer: The Eiffel Tower is older.",
  "Thought: I must use the bracket format.\nAction: lookup[Statue of Liberty]\n" +
  "Observation: Dedicated in 1892.\nFinal Answer: The Eiffel Tower is older.",
  "Thought: 1886 is earlier than 1889, so the statue is older.\n" +
  "Final Answer: The Statue of Liberty (1886) is older than the Eiffel Tower (1889).",
];
function complete(prompt, stop) {
  const n = prompt.split("\nObservation:").length - 1;
  let text = SCRIPT[Math.min(n, SCRIPT.length - 1)];
  for (const s of stop) { const i = text.indexOf(s); if (i !== -1) text = text.slice(0, i); }
  return text; // the API cuts generation at the first stop string, exactly like this
}

function runReact(label, stop) {
  console.log("== " + label + " stop=" + JSON.stringify(stop));
  let prompt = HEADER, toolRuns = 0;
  for (let call = 1; call <= 6; call++) {
    const out = complete(prompt, stop);
    prompt += out;
    const action = /Action: (\w+)\[([^\]]*)\]/.exec(out);
    const final = /Final Answer: (.*)/.exec(out);
    const actionLine = /Action: (.*)/.exec(out);
    const invented = /Observation: (.*)/.exec(out);
    if (invented) console.log("  call " + call + ": model wrote its own observation -> " + invented[1]);
    if (final) {
      console.log("  call " + call + ": final answer -> " + final[1]);
      console.log("  real tool runs: " + toolRuns);
      return;
    }
    let obs;
    if (action && action[1] === "lookup") { obs = lookup(action[2]); toolRuns++; }
    else obs = "Invalid action " + JSON.stringify(actionLine ? actionLine[1] : "") + ". Use lookup[query].";
    console.log("  call " + call + ": " + (actionLine ? actionLine[1] : "(none)") + "  ->  " + obs);
    prompt += "\nObservation: " + obs + "\n";
  }
  console.log("  gave up after 6 calls");
}

runReact("A. no stop sequence", []);
runReact("B. stop at Observation", ["\nObservation:"]);

// The same B trajectory as native tool-calling messages (what modern APIs send instead).
const native = [
  { role: "assistant", thought: "Start with the Eiffel Tower.", tool_call: { name: "lookup", input: { query: "Eiffel Tower" } } },
  { role: "tool", content: lookup("Eiffel Tower") },
  { role: "assistant", thought: "Now the statue.", tool_call: { name: "lookup", input: { query: "Statue of Liberty" } } },
  { role: "tool", content: lookup("Statue of Liberty") },
  { role: "assistant", text: "The Statue of Liberty (1886) is older than the Eiffel Tower (1889)." },
];
console.log("== C. same loop as native tool calls (no text parsing, no format errors)");
for (const m of native) console.log("  " + JSON.stringify(m));

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 59 of 83 in AI engineering

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

Up nextMedium

Vercel AI SDK 5 streamText: how do you stream LLM chat to React?

Continue