PromptisePromptise
Docs
GitHub
Promptise - AI Framework LogoPromptise

The foundation layer for agentic intelligence. Build, secure and operate autonomous AI systems with Promptise Foundry.

pip install promptise

[01] Foundry

  • MCPcast
  • The Promptise Agent
  • Reasoning Engine
  • MCP
  • Agent Runtime
  • Prompt Engineering
  • Execution Engine
  • Agent Identity

[02] Resources

  • Documentation
  • GitHub
  • Guides
  • Learning Paths
  • Questions

[03] Company

  • About
  • Terms of Service
  • Privacy Policy
  • Cookie Policy
  • Subprocessors

© 2026 Promptise by Manser Ventures. All rights reserved.

Open source · Python

← Guides> AI Engineering

AI Agent Reasoning Patterns in Python: 9 Patterns Tested

ReAct, plan-and-execute, reflection, debate and code-action on the same three tasks, 12 runs each: which agent reasoning patterns were right, at what cost.

Level
Intermediate
Reading time
15 min
Published
Oct 15, 2026
By
Promptise Team
  • AI Agents
  • Reasoning Patterns
  • ReAct
  • Reflection
  • Debate
  • Python
  • Promptise Foundry

Agent reasoning patterns are the shapes an AI agent's work can take between a question and an answer: the ReAct loop of think, call a tool, read the result; a plan before acting; a self-check or a reflection before answering; a critic that argues with the first draft; a program instead of a loop. Promptise Foundry ships nine of them behind one argument. This guide explains each one from its source, then runs all nine on the same three expense questions, 4 runs per question, against a real MCP server. The short version: eight of the nine were right in all 12 of their runs, the default ReAct loop included. The exception was code-action, right 8 times in 12 and wrong on every month total. The extra steps bought nothing on these questions and cost plenty: the patterns that plan, check or debate used 2.3 to 6.9 times ReAct's tokens. Every snippet ran against Promptise Foundry 1.3.4 with GPT-5 mini, and every output is what it printed.

[01]

What are agent reasoning patterns?

A reasoning pattern decides which model calls happen, in what order, with what instructions, and when the agent stops. The baseline is ReAct, from the 2022 paper ReAct: Synergizing Reasoning and Acting in Language Models: one model, one loop, tools in between. Every other pattern adds steps around that loop or replaces it:

  • Self-check: the model checks its own work, in the same response or in a separate step.

  • Plan-and-execute: a planning step writes subgoals, the acting step works through them.

  • Reflection: after acting, a step reviews what happened, names mistakes, and decides whether to go on.

  • Debate: one step proposes, another attacks the proposal, a third judges.

  • Code as action: the model writes a program that calls the tools, and the program's output is the answer.

  • Self-directed: the model picks its own next step from a menu.

Each extra step is another model call, more tokens and more waiting. A step is worth it only if it catches mistakes the loop would make, and that's a question you answer by measuring, not by reading the pattern's name.


[02]

The nine built-in reasoning patterns in Promptise

In Promptise Foundry every agent runs on the Reasoning Graph, and build_agent(agent_pattern=...) picks the graph. These are the nine names it accepts (promptise.agent.AGENT_PATTERNS), and what each builds, read from promptise/engine/prebuilts.py in 1.3.4:

agent_pattern

Steps

What it does

react (default)

reason

One node with your tools loops until the model answers, up to 15 rounds. After 6 tool results it swaps the transcript for a ledger of facts

managed

reason

The same loop with the facts ledger from the first call, and room for 30 rounds

verify

reason

The same loop, told to answer in PLAN, SOLVE, VERIFY sections; 6 rounds at most

code-action

reason

The model writes one Python program that calls the tools, run in a Docker sandbox

peoatr

plan, act, think, reflect, answer

Structured plan, a tool loop, structured analysis and reflection that route back or on, then a separate answer step

research

search, verify, synthesize

A tool loop, a model that checks the findings against the tool results and can send the run back to search (twice at most), then a separate step that writes the answer

autonomous

agent

The model picks reason (a full tool loop), analyze or synthesize at each step, up to 15 steps; synthesize writes the answer

deliberate

think, plan, act, observe, reflect, answer

Think and plan first, a tool loop, then a reflection that can route back to act or plan, and a separate answer step

debate

proposer, critic, judge, answer

A proposer with your tools answers, a critic scores it and can send it back, a judge passes or fails it, and a separate step writes the answer

Every multi-stage pattern returns structured output from the steps that decide where to go next (a plan with a quality score, a critique with a severity, a verdict with pass or fail), so those decisions actually route. Every stage has a budget, and every multi-stage pattern ends with a step whose only job is to write the reply.

You can also pass a graph of your own instead of a name. The plan-and-execute guide builds a plan, act, verify, reflect graph node by node and measures it against ReAct; this guide stays with the built-ins.


[03]

What you need

  • Python 3.10 or newer.

  • Promptise Foundry 1.3.4 or newer. The sandbox extra and Docker are needed only for code-action.

  • An API key for a model provider. The examples use openai:gpt-5-mini.

>_Terminal
pip install "promptise[sandbox]>=1.3.4"
export OPENAI_API_KEY="sk-..."

[04]

Compare agent reasoning patterns on one task set, step by step

Step 01

Give the agent an expense policy to apply

A fair test needs questions a pattern can get wrong. This MCP server holds one employee's September expense claims and the company's reimbursement rules, as text, the way policies are written. One rule has a trap: meals are capped at $60 per day, and Dana has two meal claims on September 5th.

Pythonexpenses_server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from promptise.mcp.server import MCPServer

server = MCPServer("expenses")

# Sample data: one employee's September expense claims and the policy.
CLAIMS = {
    "EX-101": {"employee": "Dana", "category": "meals", "date": "2026-09-02", "amount": 48.50, "receipt": True},
    "EX-102": {"employee": "Dana", "category": "taxi", "date": "2026-09-02", "amount": 32.00, "receipt": False},
    "EX-103": {"employee": "Dana", "category": "hotel", "date": "2026-09-03", "amount": 412.00, "receipt": True, "nights": 2},
    "EX-104": {"employee": "Dana", "category": "meals", "date": "2026-09-03", "amount": 74.20, "receipt": True},
    "EX-105": {"employee": "Dana", "category": "gift", "date": "2026-09-04", "amount": 55.00, "receipt": True},
    "EX-106": {"employee": "Dana", "category": "taxi", "date": "2026-09-04", "amount": 18.40, "receipt": False},
    "EX-107": {"employee": "Dana", "category": "meals", "date": "2026-09-05", "amount": 59.90, "receipt": True},
    "EX-108": {"employee": "Dana", "category": "taxi", "date": "2026-09-05", "amount": 41.75, "receipt": True},
    "EX-109": {"employee": "Dana", "category": "meals", "date": "2026-09-05", "amount": 14.30, "receipt": True},
}

POLICY = {
    "meals": "Meals are reimbursed up to $60.00 per day. Anything above that is not reimbursed.",
    "taxi": "Taxis are reimbursed in full with a receipt. Without a receipt, at most $25.00 per ride.",
    "hotel": "Hotels are reimbursed up to $180.00 per night.",
    "gift": "Gifts for clients are not reimbursable.",
}


@server.tool()
async def list_claims(employee: str, month: str) -> list[str]:
    """List the IDs of an employee's expense claims for a month, e.g. "2026-09".

    Args:
        employee: The employee's first name.
        month: The month as YYYY-MM.
    """
    return [cid for cid, c in CLAIMS.items() if c["employee"] == employee and c["date"].startswith(month)]


@server.tool()
async def get_claim(claim_id: str) -> dict:
    """Get one expense claim: category, date, amount in USD, receipt, and nights for hotels.

    Args:
        claim_id: A claim ID from list_claims, e.g. "EX-101".
    """
    if claim_id not in CLAIMS:
        raise ValueError(f"No claim {claim_id}")
    return {"id": claim_id, **CLAIMS[claim_id]}


@server.tool()
async def get_policy(category: str) -> str:
    """Get the reimbursement rule for an expense category: meals, taxi, hotel or gift.

    Args:
        category: The expense category.
    """
    if category not in POLICY:
        raise ValueError(f"No policy for {category}")
    return POLICY[category]


if __name__ == "__main__":
    server.run()

Three questions, each harder than the last: a lookup (one tool call), one rule applied to one claim (two calls), and the month's total (fourteen calls and every rule, including the per-day cap). The right answers, computed in plain Python:

Pythontruth.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
"""The right answers, computed straight from the server's data."""
from collections import defaultdict

from expenses_server import CLAIMS

meals_by_day = defaultdict(float)
paid = {}
for cid, c in CLAIMS.items():
    if c["category"] == "meals":
        meals_by_day[c["date"]] += c["amount"]
    elif c["category"] == "taxi":
        paid[cid] = c["amount"] if c["receipt"] else min(c["amount"], 25.00)
    elif c["category"] == "hotel":
        paid[cid] = min(c["amount"], 180.00 * c["nights"])
    elif c["category"] == "gift":
        paid[cid] = 0.0
meals = sum(min(total, 60.00) for total in meals_by_day.values())

print("EX-108:", CLAIMS["EX-108"]["category"], f"${CLAIMS['EX-108']['amount']:.2f}")
print(f"EX-103 reimbursed: ${paid['EX-103']:.2f}")
print(f"September total reimbursed: ${meals + sum(paid.values()):.2f}")
print(f"(capping meals per claim instead of per day gives ${sum(min(c['amount'], 60) for c in CLAIMS.values() if c['category'] == 'meals') + sum(paid.values()):.2f})")
Output
EX-108: taxi $41.75
EX-103 reimbursed: $360.00
September total reimbursed: $613.65
(capping meals per claim instead of per day gives $627.85)

The last line is the trap. Apply the meal cap to each claim instead of each day, and you get $627.85.

Step 02

Switch the reasoning pattern with one argument

One script runs any pattern. It counts model calls and tokens with a small LangChain callback, which sees every model call whatever the pattern, and prints the path the agent took through its graph:

Pythonusage.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from langchain_core.callbacks import BaseCallbackHandler


class Usage(BaseCallbackHandler):
    """Count model calls and tokens for one run."""

    def __init__(self):
        self.calls = self.input_tokens = self.output_tokens = 0

    def on_llm_end(self, response, **kwargs):
        self.calls += 1
        usage = response.generations[0][0].message.usage_metadata or {}
        self.input_tokens += usage.get("input_tokens", 0)
        self.output_tokens += usage.get("output_tokens", 0)

    def __str__(self):
        return f"{self.calls} model calls, {self.input_tokens:,} input + {self.output_tokens:,} output tokens"
Pythonrun_pattern.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import asyncio
import sys
import time

from promptise import build_agent
from promptise.config import StdioServerSpec

from usage import Usage

QUESTION = "How much will Dana be reimbursed in total for her September 2026 expense claims?"


async def main(pattern: str):
    agent = await build_agent(
        model="openai:gpt-5-mini",
        servers={"expenses": StdioServerSpec(command=sys.executable, args=["expenses_server.py"])},
        agent_pattern=pattern,
    )
    try:
        usage = Usage()
        start = time.perf_counter()
        result = await agent.ainvoke(
            {"messages": [{"role": "user", "content": QUESTION}]},
            config={"callbacks": [usage]},
        )
        print(">>>", result["messages"][-1].content)
        print("path:", " -> ".join(agent.last_report.nodes_visited))
        print(f"usage: {usage}, {time.perf_counter() - start:.1f} s")
    finally:
        await agent.shutdown()


asyncio.run(main(sys.argv[1] if len(sys.argv) > 1 else "react"))
>_Terminal
python run_pattern.py react
Output
>>> Dana will be reimbursed a total of $627.85 for September 2026.

Breakdown by claim:
- EX-101 (meals 48.50) → reimbursed $48.50 (under $60/day cap)
- EX-102 (taxi 32.00, no receipt) → reimbursed $25.00 (no-receipt cap $25/ride)
- EX-103 (hotel 412.00, 2 nights) → reimbursed $360.00 (2 nights × $180/night cap)
- EX-104 (meals 74.20) → reimbursed $60.00 (meals cap $60/day)
- EX-105 (gift 55.00) → reimbursed $0.00 (gifts not reimbursable)
- EX-106 (taxi 18.40, no receipt) → reimbursed $18.40 (≤ $25 no-receipt cap)
- EX-107 (meals 59.90) → reimbursed $59.90
- EX-108 (taxi 41.75, receipt) → reimbursed $41.75 (taxi reimbursed in full with receipt)
- EX-109 (meals 14.30) → reimbursed $14.30

Total = $627.85.
path: reason -> reason -> reason -> reason
usage: 4 model calls, 2,961 input + 1,473 output tokens, 12.1 s

The path shows the ReAct loop: the same reason node four times, three rounds of tool calls and one round that answered. The answer is wrong, and it doesn't look wrong. EX-107 and EX-109 are both meals on September 5th, together $74.20, and the loop capped each claim at $60 instead of the day, so it paid $627.85 instead of $613.65. Change the argument to peoatr, research or any other name to send the same question through a different graph.

This run was made for the page, after the measured ones below, where ReAct got the month total right 4/4. That's the honest picture of the default loop on this question: usually right, sometimes caught by the trap, and nothing in the reply tells you which.

Step 03

Run every pattern on every question

A helper script ran each pattern on each question 4 times, with a fresh agent every run, and checked each reply for the right number (and the category, for the lookup). Model calls and tokens are means per run, time is the median, cost is GPT-5 mini at $0.25 per million input and $2.00 per million output tokens. All 108 runs cost $0.73.

Pattern

Lookup

One rule

Month total

Model calls

Tokens

Time

Cost per run

react (default)

4/4

4/4

4/4

3.0

2,442

7.1 s

$0.0021

verify

4/4

4/4

4/4

3.2

3,405

9.6 s

$0.0032

managed

4/4

4/4

4/4

3.0

2,676

7.3 s

$0.0022

code-action

4/4

4/4

0/4

1.1

4,319

34.8 s

$0.0075

peoatr

4/4

4/4

4/4

7.0

9,165

31.2 s

$0.0087

research

4/4

4/4

4/4

5.0

5,495

16.0 s

$0.0051

autonomous

4/4

4/4

4/4

7.3

6,944

19.1 s

$0.0052

deliberate

4/4

4/4

4/4

8.2

16,755

51.7 s

$0.0156

debate

4/4

4/4

4/4

6.9

10,322

40.7 s

$0.0109

A right number is checked automatically, so read the replies too: a reply that names two totals and asks you to pick would count as right if one of them is. None of the measured month-total replies did that, but the debate run shown below does. And mind the sample size: 4 runs per cell is enough to see a pattern break, not to rank two good ones.

What stands out:

  • Eight patterns were right in all 12 runs: react, verify, managed, peoatr, research, autonomous, deliberate, debate. On the month total, the five multi-stage patterns were right 20 times in 20 and the three one-node loops 12 times in 12.

  • The default loop didn't miss this time. In the same experiment on Promptise 1.3.3, ReAct got the month total right 2 times in 4 and managed 3 times in 4, every miss the $627.85 trap; here both were right every time, and the demo run above missed again. The graphs are the same in both versions; 1.3.4 changed what runs around them (no tool summary in the prompt by default, the facts ledger the loop switches to after six tool results, the iteration limit), and four runs a cell can't tell that apart from luck. Read it as: the loop falls for the trap now and then.

  • Extra steps cost tokens and seconds. The cheapest multi-stage pattern, research, used 2.3 times ReAct's tokens; deliberate used 6.9 times and took a median 52 seconds against ReAct's 7.

  • The checks rarely changed the path. Research's verify step never sent a run back to search (0 of 12), deliberate's reflection never routed back to act or plan (0 of 12), and debate's critic or judge sent the proposer back 2 times in 12.

  • Code-action was right 8/12, and wrong on all 4 month totals, each with a different number. It's the one pattern here whose program has to turn policy sentences into numbers before it has read them; more on that below.


[05]

ReAct and its one-node variants: react, managed and verify

The ReAct agent is the default for good reasons, and the table shows them: right on every measured run, 3.0 model calls and about 2,442 tokens a run, a median 7.1 seconds. Its weakness is the one every single-loop agent has: the node that gathered the data also does the reasoning, in the same context, in one pass. When it misreads a rule, as in the demo run above, nothing gets a second look.

The two variants change the prompt, not the shape. managed replaces the tool transcript with a deduplicated ledger of facts from the first call, so long loops stay small; the context engineering guide measures that idea in depth. Here it cost about the same as ReAct (1.1 times the tokens) and was right 12/12. verify makes the model write PLAN, SOLVE and VERIFY sections in its answer, for about 1.4 times ReAct's tokens, and was right 12/12. It has a limit of its own: the node gets 6 rounds, and a model that fetches one item per round can run out and raise GraphIterationLimitError before it answers (it didn't here).

A self-check written by the same model in the same response checks the arithmetic it did, not the reading of the rule it chose. That's the case for a separate step, if your runs show the loop misreading rules.


[06]

Plan-and-execute with a separate answer step: peoatr and research

peoatr is the full plan-and-execute pattern: a structured plan with a quality score, a tool loop for the active subgoal, a structured think step that decides between another tool call and reflection, a reflect step that routes to answer, replan or continue, and an answer step that writes the reply from what was gathered. It was right in all 12 runs, for 2.3 times ReAct's model calls, 3.8 times the tokens and a median 31.2 seconds. Its think step sent it back to act in 1 run; its reflection never asked for a new plan.

research is the cheapest of the multi-stage patterns. It's a tool loop, then a verify step, then a synthesize step that writes the answer. Here's a run:

>_Terminal
python run_pattern.py research
Output
>>> Using Dana’s September claims (EX-101 through EX-109) and the company policies (meals: up to $60/day; taxis: full with receipt, otherwise at most $25/ride; hotels: $180/night; gifts not reimbursable), here is the calculation:

Meals (policy: up to $60/day)
- 2026-09-02 EX-101: $48.50 → reimbursed $48.50
- 2026-09-03 EX-104: $74.20 → capped to $60.00
- 2026-09-05 EX-107 $59.90 + EX-109 $14.30 = $74.20 → capped to $60.00
Meals total = 48.50 + 60.00 + 60.00 = 168.50

Taxis (policy: full with receipt; without receipt, ≤ $25/ride)
- EX-102 (no receipt) $32.00 → capped to $25.00
- EX-106 (no receipt) $18.40 → reimbursed $18.40
- EX-108 (receipt) $41.75 → reimbursed $41.75
Taxis total = 25.00 + 18.40 + 41.75 = 85.15

Hotel (policy: $180.00 per night)
- EX-103: $412.00 for 2 nights → cap 2 × $180 = $360.00
Hotel total = 360.00

Gifts (not reimbursable)
- EX-105 $55.00 → reimbursed $0.00

Grand total reimbursement = 168.50 + 85.15 + 360.00 + 0.00 = $613.65

Result: Dana will be reimbursed $613.65 for September 2026.

Sources: claim details EX-101…EX-109 and company policies (meals, taxis, hotels, gifts).
path: search -> search -> search -> search -> verify -> synthesize
usage: 6 model calls, 6,134 input + 3,596 output tokens, 24.6 s

Right in all 12 runs at 2.3 times ReAct's tokens and a median 16.0 seconds. The verify step is a model call that compares the findings with the tool results and returns a verdict; a failed verdict sends the run back to search with the issues listed, twice at most. Here it passed every time, 12 of 12, because the findings were already right, so the verify call was insurance paid on every run. The synthesize step is where the answer gets its shape: grouped by category, with the per-day meal cap spelled out. The plan-and-execute guide builds a graph like this by hand, with a check written in code.


[07]

Reflection agents: deliberate

A reflection agent reviews its own work, names its mistakes and decides whether to go on. deliberate chains think, plan, act, observe and reflect, and ends with an answer step. Here's a run, trimmed in the middle:

>_Terminal
python run_pattern.py deliberate
Output
>>> I retrieved Dana’s September 2026 claims (EX-101…EX-109) and the applicable policies. Below are the results and the reimbursement calculation.
…
2) Applicable reimbursement policy (from policy lookups)
- Meals: reimbursed up to $60.00 per day (total of meal items on the same calendar day capped at $60).  
- Taxi: reimbursed in full with a receipt. Without a receipt, at most $25.00 per ride.  
- Hotel: reimbursed up to $180.00 per night. (EX-103 shows 2 nights.)  
- Gifts for clients: not reimbursable.
…
3) Total reimbursable amount (single total, USD)
- Total reimbursable = $613.65 USD

4) Short breakdown by category and adjustments
- Meals: Claimed $196.90 → Reimbursed $168.50. Withheld $28.40 (meal daily caps: 2026-09-03 withheld $14.20; 2026-09-05 withheld $14.20).  
- Hotel: Claimed $412.00 → Reimbursed $360.00. Withheld $52.00 (cap $180 × 2 nights = $360).  
- Taxi: Claimed $92.15 → Reimbursed $85.15. Withheld $7.00 (2026-09-02 taxi $32.00 had no receipt and is capped at $25.00).  
- Gift: Claimed $55.00 → Reimbursed $0.00. Withheld $55.00 (non-reimbursable).
…
If you want, I can: mark items as Approved/Denied, export these lines to CSV, or produce a payment instruction for $613.65.
path: think -> plan -> act -> act -> act -> act -> act -> act -> act -> observe -> reflect -> answer
usage: 12 model calls, 20,595 input + 9,763 output tokens, 60.5 s

A complete answer, with the meal cap applied per day, and a path that shows every stage: think, plan, seven act rounds (tool calls, then a summary), observe, reflect, answer. The plan and reflect steps return structured output, so the reflection can send the agent back to act or to a new plan. In the measured runs it never needed to (0 of 12). It was right in all 12 runs and the most expensive pattern here, at 6.9 times ReAct's tokens and a median 51.7 seconds. The reply also shows what a planning step can add that nobody asked for: an "exact format requested" table and approval statuses the question never mentioned.

If you want a reflection that carries over between runs rather than within one, the self-improving agent guide covers lessons an agent keeps.


[08]

LLM debate: proposer, critic and judge

Debate is self-critique with separate roles: a proposer answers with the agent's tools, a critic scores the answer and sends it back when the severity is above 0.3, a judge passes or fails it (a fail also sends it back), and an answer step writes the reply. The critic and the judge get three rounds each. Here is debate on the month total, trimmed:

>_Terminal
python run_pattern.py debate
Output
>>> Summary answer — two possible totals depending on whether EX-105 (gift) is reimbursable:

- If EX-105 is NOT reimbursable (e.g., it's a client gift): Dana reimbursed = $613.65.
- If EX-105 IS reimbursable: Dana reimbursed = $668.65.

…
Gift (EX-105)
- Claim: $55.00, receipt true.
- Policy only states “Gifts for clients are not reimbursable.” The claim metadata has category="gift" but does not identify recipient (client vs. internal). Tool results do not state whether EX-105 was a client gift. Therefore:
  - If EX-105 is a client gift → reimbursed $0.00.
  - If EX-105 is not a client gift (internal/other and otherwise allowed) → reimbursed $55.00.
…
If you confirm whether EX-105 was a client gift (or provide recipient info) and the timezone rule for daily caps (if different from claim dates), I will finalize the single correct reimbursable total.
path: proposer -> proposer -> proposer -> proposer -> critic -> judge -> answer
usage: 7 model calls, 8,376 input + 6,976 output tokens, 44.2 s

The proposer fetched the claims and policies (four proposer rounds in the path), the critic and judge let the draft through, and the answer step wrote the reply. The math is right, and the reply is a hedge: the policy only says gifts "for clients" aren't reimbursable, so this run offered a second total in case the gift wasn't for a client, and asked the reader to decide. Whether that's diligence or noise depends on your reader; it's the kind of reply a debate produces that a ReAct loop rarely does.

In the measured runs debate was right 12/12, at 4.2 times ReAct's tokens and a median 40.7 seconds. The critic or judge sent the proposer back 2 times in 12 (on the lookup). On questions the plain loop already gets right, the argument has little to find. Debate pays when a critic can find something, which takes a task with room for disagreement or a critic with a check of its own. If you want separate agents with their own tools rather than roles inside one graph, see the multi-agent system guide.


[09]

Autonomous and code-action

autonomous lets the model choose each step from a menu: reason (with tools), analyze or synthesize. A chosen reason step runs its whole tool loop, the routing exchange stays out of the conversation, and when the agent decides it's done, synthesize writes the answer if it hasn't already. It was right in 12/12 runs, at 2.8 times ReAct's tokens and a median 19.1 seconds, and every path is one node, agent, because the choices happen inside it.

code-action was right 8/12 (lookup 4/4, one rule 4/4, month total 0/4), at 1.8 times ReAct's tokens and a median 34.8 seconds. The model writes one Python program that calls the tools in a Docker sandbox, and the program's printed result is the answer. Its programs had to turn the policy sentences into numbers before they had read them, so each one guessed with regular expressions and keyword lists: one looked for up to $X, another for a per_night field the policy doesn't have. The four month totals were all different and all wrong ($272.15, $756.05, $428.40, $634.85; $756.05 is every claim paid in full), each one printed as confidently as a right answer, and none raised an error. The tokens are high for a single model call because writing a program that guards against every shape of result is long output. Code-action shines on large, structured data, not on rules written as sentences: the code-action agent guide measures it against ReAct on 30 orders and 37 tool calls, where it was right every time with defaults, and the code execution sandbox guide covers the container.


[10]

Which reasoning pattern when

Based on these runs and on what each graph does in 1.3.4:

If the task is

Use

Why

A lookup, a single rule, or gather and add up

react (the default)

Right in every measured run here, the fastest and cheapest; it can still misread a rule now and then

Long tool loops that re-fetch facts

managed

Same loop with a bounded facts ledger

Rules the loop keeps misapplying

research

The cheapest pattern with a separate answer step, 2.3x ReAct's tokens, with a check that can send it back

Multi-step work where order matters

peoatr

Plans, reflects and routes; about 3.8x the tokens

Exact computation over large structured data

code-action

One program, no tool results in the context; needs Docker, and here it failed on rules written as sentences

A check you can write as code

A custom graph with a code check

Free, fast, and it can't be talked into passing

An answer that should survive a critic

debate

About 4.2x the tokens; expect hedged replies

Open-ended work where the model picks the steps

autonomous

Bring your own node pool for your own steps

Careful, slow work where cost doesn't matter

deliberate

The most thorough reply, at 6.9x the tokens

The ratios in that table come from this task set: one model, one server, three questions. They tell you what to try first, not what wins on your task. The prompt testing guide shows how to turn questions like these into a test you can rerun whenever you change the pattern or the model.


[11]

Honest limits

  • Small N, one model. 4 runs per question per pattern with GPT-5 mini. With four runs a cell, one flipped answer moves a score by a quarter: ReAct's month total was 2 of 4 on Promptise 1.3.3 and 4 of 4 here, and the one extra run made for this page missed.

  • The checks are paid for on every run. Research's verify step, debate's critic and judge, and the reflection steps are a model call each, whether they find something or not, and on these questions they almost never did.

  • A right number isn't always a clean answer. Multi-stage patterns write long, careful replies, and a critic can push the answer toward hedging, as in the debate run above. Check the replies, not only a score.

  • Every stage has a budget. verify gets 6 tool rounds, react 15, managed 30; the multi-stage patterns cap each stage (for example max_act_steps, max_search_steps, max_rounds) and hand over to the answer step when one is used up, so a long task can end with a partial answer rather than an error.

  • And the whole run has one. build_agent(max_agent_iterations=25) caps the node executions of a run, and since 1.3.4 a limit of N allows exactly N. The longest path here was 14 nodes (a debate); a run that reaches the limit raises GraphIterationLimitError. None did here.

  • Code-action needs Docker and the right kind of task. On rules written as prose it guessed, and its wrong answers looked like right ones; the code-action agent guide covers its tool budget, which fails quietly too.


[12]

Frequently asked questions

What are agent reasoning patterns?

The control flow of an AI agent: which model calls happen, in what order, with which instructions and tools, and when the agent stops. ReAct, plan-and-execute, reflection, self-critique, debate and code-as-action are the common ones.

What is the ReAct pattern?

Reason plus act: the model decides on a tool call, sees the result, and repeats until it can answer. It's the default in most agent frameworks, including Promptise, and on these tool tasks it was right as often as any pattern, at the lowest cost and in the least time.

Does a reflection step make an agent more accurate?

Not on these questions. The reflection steps never sent the agent back, and the plain ReAct loop was right as often without one. A reflection helps when it finds something specific to fix and can send the agent back, so test it on the questions your loop actually gets wrong.

Does multi-agent debate improve LLM accuracy?

Sometimes, when the critic can find real problems. Here the built-in debate was right 12/12, as was ReAct, and its critic or judge sent a draft back 2 times in 12 runs, at 4.2 times ReAct's tokens.

Which agent reasoning pattern should I use?

Start with the default ReAct loop and measure it on your own questions. If it misapplies rules on gather-then-compute questions, add a separate answer step (research is the cheapest way here); if it computes over large structured data, try code-action. Add planning, reflection or debate when a run shows the mistake they'd catch, or when the cost doesn't matter.


[13]

Where to go next

  • Reasoning Patterns and Prebuilt Patterns: every agent_pattern and its factory function.

  • Reasoning Graph and Nodes: the engine and every node type, including the reasoning nodes used above.

  • Building Custom Reasoning: graph shapes from pipelines to parallel research.

  • Code-Action Agents in Python: the code-action pattern over an MCP server, measured against ReAct.

  • Plan-and-Execute Agents in Python: build plan, act, verify and reflect by hand, with a check written in code.

  • Context Engineering for AI Agents: what the ledger behind managed saves on long runs.

  • Best LLM for AI Agents: the other half of the accuracy question.

Learning paths

Want more structure? Paths put guides in order, like a short course.

See the paths →

Keep going.

Browse every guide by topic and level, or follow a learning path that puts them in order.

All guidesLearning paths