Course Content
Prompt Engineering Mastery
6 sections · 32 lessons
What is ReAct prompting?
What you need to know
The loop
- Reason — decide what information or action is needed next.
- Act — request a tool call with arguments.
- Observe — your code runs the tool and sends back the result.
- 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:
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.
1MAX_STEPS = 62messages = [{"role": "user", "content": question}]34for step in range(MAX_STEPS):5 reply = llm.chat(messages=messages, tools=TOOLS) # your provider client6 messages.append(reply.as_message())7 if not reply.tool_calls:8 break # final answer9 for call in reply.tool_calls:10 args = validate(call.name, call.arguments) # schema check11 result = run_tool(call.name, args) # returns error text on failure12 messages.append(tool_result(call.id, result))13else:14 escalate_to_human(messages) # hit the step limitThe 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:
[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.