← Back to curriculum

Module 8 — Agentic AI

Planning vs execution — ReAct

ReAct traces, planner and executor prompts, retry and replan logic, UI reasoning traces, and workflow vs agentic replan.

~90 min read + exercises

Planning vs execution — ReAct

Before we begin

A single agent with twelve tools and a vague system prompt often mixes strategy and API calls — hallucinated cities, skipped steps, or loops on the wrong tool.

Planning vs execution splits roles:

Plannerwhat should we do, in what order?
Executorrun tools with correct arguments and handle API errors.

This pattern is the backbone of your travel planner project and appears in almost every production agent interview.

Figure

Planner + executor

Planneritinerary stepsExecutorweather / maps APIs
Strategy separate from reliable tool execution.

What you will learn

  • Explain the ReAct pattern (Reason + Act) with a full trace.
  • Design planner and executor prompts and outputs.
  • Handle retries, replanning, and visible reasoning in the UI.
  • Know when a fixed workflow is enough vs full agentic replan.

Before this lesson


ReAct — Reason and Act

ReAct (Reason + Act) alternates natural language reasoning with tool actions:

  1. Thought — internal reasoning (“I need weather before outdoor activities.”)
  2. Action — tool name + arguments
  3. Observation — tool result from your app
  4. Repeat until Final answer

Why thoughts help

  • Model commits to a plan before acting — fewer random tool calls.
  • You can show thoughts in the UI — users trust “checked weather API” more than a black box.
  • Debugging — read the trace when something fails.

Optional in production: hide raw thoughts from users but log them for support.


Full worked trace — Rome weekend

User: “Sat–Sun in Rome with kids — avoid rain if possible.”

text
Thought 1: I need weather for both days before suggesting activities.
Action 1: get_weather(city="Rome", start="2025-06-28", days=2)
Observation 1: {"sat": {"condition": "rain", "high_c": 19}, "sun": {"condition": "clear", "high_c": 26}}
 
Thought 2: Saturday rainy — indoor family options. Sunday clear — parks or outdoor museums.
Action 2: search_places(city="Rome", tags=["family", "indoor"], limit=5)
Observation 2: [{"name": "Explora Museum", ...}, {"name": "Vatican Museums", ...}]
 
Thought 3: I have enough to draft a balanced itinerary.
Final answer: [structured 2-day plan with times, citing weather per day]

Count: 2 tool rounds + 1 synthesis. Without ReAct-style structure, models often answer from memory without calling tools at all.


Planner agent (design)

Job: break the user goal into ordered steps without calling external APIs (optional but recommended for reliability).

Planner system prompt (sketch):

text
You are a travel planner. Output ONLY valid JSON:
{
  "steps": [
    {"id": 1, "description": "...", "tool_hint": "get_weather"},
    ...
  ],
  "assumptions": ["budget not specified — assume mid-range"]
}
Do not invent API results. Do not call tools.

Example planner output:

json
{
  "steps": [
    {"id": 1, "description": "Fetch weekend weather for Rome", "tool_hint": "get_weather"},
    {"id": 2, "description": "Find kid-friendly venues matching weather", "tool_hint": "search_places"},
    {"id": 3, "description": "Synthesize day-by-day itinerary", "tool_hint": null}
  ],
  "assumptions": ["Travel dates: this coming Sat–Sun"]
}

Why JSON plan?

  • Executor has a checklist — easier to eval (Lesson 7).
  • Planner cannot hallucinate temp_c: 22 — only the executor sees API data.
  • UI can show plan steps before execution starts.

Executor agent (design)

Job: for one plan step, pick the right tool, validate args, run it, return structured observation.

Executor system prompt (sketch):

text
You execute ONE plan step. You have tools: get_weather, geocode_city, search_places.
Return either a tool call OR a step completion summary with facts from observations only.
Never fabricate temperatures or opening hours.

Executor for step 1:

text
Action: get_weather(city="Rome", start="2025-06-28", days=2)
Observation: {"sat": "rain", "sun": "clear"}
Step 1 complete.

If the executor role is merged with ReAct in a single agent, use the same discipline: thought → action → observation per step.


Retry and failure handling

Real APIs fail. Design explicit recovery:

text
Attempt 1: get_weather("Pariss") → error: city not found
Thought: Likely typo — retry Paris
Attempt 2: get_weather("Paris") → success

Rules:

RuleValue (example)
Max retries per tool call3
Max total loop iterations10–15
After retries exhaustedReturn error to planner for replan OR ask user

Replan example:

text
Observation: flights API rate-limited for 60s
Planner revision: skip flight prices; use train estimate; note limitation in final answer

LangGraph (Lesson 6) models execute → (success|retry|replan) as graph edges — a graph is a diagram of nodes (steps) and arrows (transitions).


Showing reasoning in the UI

Users and stakeholders want transparency. Your travel project should expose a trace array:

json
[
  {"type": "thought", "text": "Need weather first"},
  {"type": "tool", "name": "get_weather", "args": {"city": "Rome"}, "ok": true},
  {"type": "observation", "summary": "Sat rain, Sun clear"},
  {"type": "final", "text": "Day 1: Explora Museum..."}
]

Render as a collapsible timeline — not raw JSON dumps.


Workflow vs agentic replan

ApproachFlow
Fixed workflowPlan (once) → Execute step 1 → 2 → 3 → Done
Agentic replanPlan → Execute step 1 → failurenew plan → continue

Use fixed workflow when steps are stable and failures are rare. Use replan when tools fail often or user goals shift mid-session (“actually make it Florence”).

Hybrid (recommended): planner runs once; executor may retry; only serious failures trigger full replan.


Orchestration vs plain LLM

Single LLM replyOrchestrated planner + executor
Tool useMay skip toolsExecutor forced per step
DebugOne blobPer-step traces
Cost1 call2+ calls
Quality on complex tasksLowerHigher

Agent orchestration = coordinating multiple LLM calls, tools, and state — not one magic prompt.


Prompt templates (copy-paste starters)

Planner user message:

text
Goal: {user_message}
Known preferences: {memory_snippet}
Output JSON plan only.

Executor user message:

text
Current step: {step_json}
Completed observations: {prior_observations}
Execute this step using tools.

Version these in git like application code.


Check yourself

  1. Write one Thought → Action → Observation triple for a weather query.
  2. Why separate planner from executor?
  3. What happens after 3 failed get_weather retries?
  4. What would you show in the UI trace for trust?

What's next

Lesson 4 — Agent memory — short-term session state and long-term user preferences.