ReWOO
ReWOO (Reasoning WithOut Observation) plans every
tool call up front, runs them, then writes the answer from the
results. It is the cost-saving sibling of
Plan-and-Execute: each step in
the plan is a real tool call, steps refer to earlier steps’
outputs with {{En}} placeholders, and independent steps run in
parallel. Use it for tool-heavy tasks where the sequence of calls is
predictable. From Xu et al. 2023, ReWOO: Decoupling Reasoning from
Observations for Efficient Augmented Language Models.
Total cost: 2 LLM calls + N tool calls. ReAct on the same task needs roughly N+1 LLM calls (one per turn). For tool-heavy workloads where the planner can predict the call sequence upfront, ReWOO is 30–50% cheaper.
Pattern
- Planner. ONE LLM call. Output is a JSON list of steps. Each
step has shape:
Args may reference prior steps via
{"id": "E1", "tool": "<tool_name>", "args": {...}}{{En}}placeholders (or the paper’s#E1form):{"args": {"url": "{{E1}}"}}will use E1’s output as theurlargument. A{"steps": [...]}object is accepted too, and the JSON is found even inside prose or a code fence. - Executor. Walk the plan. Steps with no
{{En}}references (or only references to already-completed steps) run in parallel. Dependent steps wait for their referenced step to finish. Each tool call is gated like a ReAct tool call and shows up astool_call/tool_resultevents. A step whose input failed, or that references a step the plan doesn’t have, is skipped instead of run. - Synthesizer. ONE LLM call combining the original prompt + the tool results (each step’s call and its output) into the final answer.
Usage
from loomflow import Agent, tool
from loomflow.architecture import ReWOO
@tool
async def search(query: str) -> str:
"""Web search."""
...
@tool
async def fetch(url: str) -> str:
"""Fetch a URL."""
...
agent = Agent(
"Research the topic and produce a summary with citations.",
model="claude-opus-4-7",
architecture=ReWOO(),
tools=[search, fetch],
)
result = await agent.run("Recent advances in agent harnesses.")Or by string:
agent = Agent("...", model="...", architecture="rewoo", tools=[search, fetch])When ReWOO pays off
- Tool-heavy workloads (search / fetch / DB / API calls) where the planner can list the calls upfront.
- Independent steps: Multiple searches that can run in parallel.
- Cost matters: You save the per-turn LLM call ReAct would make between every tool result.
When ReAct is still better
- The plan depends on tool output you can’t predict. If the search result reshapes the next call, ReAct’s “think between each tool call” loop is needed.
- Failure recovery. ReWOO commits to the plan; a failed tool call doesn’t trigger replanning, and the steps that need its output are skipped. ReAct re-thinks every turn.
Placeholders are textual substitution. {{E1}} is replaced with
E1’s tool result string before the dependent tool runs. For complex
data flows (extract a URL out of a JSON blob), have the model produce
a more structured plan upfront, or fall back to ReAct.