Prompt Engineering Mastery

Course Content

Prompt Engineering Mastery

6 sections · 32 lessons

What is ReAct prompting?


The loop, implemented with native tool callsquestionreasoncall toolreadresultargumentschecked against schemaerrors comeback as dataThe loop ends when the model answers without a tool call, or when the step limit hands it to a person.
The 2022 text template is gone, but the loop is the same — and the step limit is what keeps it from running forever.

What you need to know

The loop

  1. Reason — decide what information or action is needed next.
  2. Act — request a tool call with arguments.
  3. Observe — your code runs the tool and sends back the result.
  4. Repeat until the model gives a final answer, or a limit is hit.

Then and now

The 2022 ReAct paper put the loop in plain text, and the program parsed it with regular expressions:

Text
Thought: I need the invoice status.Action: find_invoice[INV-2291]Observation: {"status": "approved", "amount": 48200}

This is outdated. Parsing text breaks when the model changes its wording, and nothing checks the arguments. In 2026 you declare tools in the API request, and the model returns a structured tool call that your code validates and runs. Reasoning models think between tool calls on their own, so you do not need "Thought:" lines in the prompt.

Python
MAX_STEPS = 6messages = [{"role": "user", "content": question}]for step in range(MAX_STEPS):    reply = llm.chat(messages=messages, tools=TOOLS)   # your provider client    messages.append(reply.as_message())    if not reply.tool_calls:        break                                          # final answer    for call in reply.tool_calls:        args = validate(call.name, call.arguments)     # schema check        result = run_tool(call.name, args)             # returns error text on failure        messages.append(tool_result(call.id, result))else:    escalate_to_human(messages)                        # hit the step limit

The llm, validate and run_tool names stand for your own wrapper code; each provider SDK has its own message shapes, and several ship a "tool runner" helper that runs this loop for you. The important parts are the step limit, the validation before running, and errors returned to the model as results rather than swallowed.

Guardrails you must add

  • Step limit and timeout — agents can loop.
  • Typed schemas — reject bad arguments before they reach your database.
  • Permissions — read tools run freely; tools that pay, delete or email need rules or human approval.
  • Visible errors — "invoice not found" must reach the model; an empty result looks like a fact.
  • Untrusted observations — tool results can contain injected instructions; treat them as data.

A real-life example

An accounts-payable assistant answers: "Has Sharma Traders' invoice INV-2291 been paid?"

Without tools, the model says "Invoices are usually paid within 30 days, so it is likely paid" — useless. With a ReAct loop and two tools, find_invoice and get_payments:

Text
[model]  find_invoice(invoice_id="INV-2291")[tool]   {"supplier": "Sharma Traders", "amount": 48200, "status": "approved",          "due": "2026-09-30"}[model]  get_payments(invoice_id="INV-2291")[tool]   {"payments": []}[model]  INV-2291 (Rs 48,200) is approved but not yet paid. It is due on         30 September 2026.

Two tool calls, a correct answer, and a trace the finance team can audit. The schedule_payment tool is deliberately not given to this assistant; paying is a separate, human-approved flow.

Follow-up questions to expect

  • "How is ReAct different from function calling?" — ReAct is the reasoning-and-acting loop; function calling is the API feature used to implement the acting part reliably.
  • "How do you stop an agent looping forever?" — A hard step limit, a timeout, detecting repeated identical calls, and escalation when the limit is reached.
  • "What if a tool fails?" — Return the error as the tool result so the model can retry differently or explain; never return an empty success.