Skip to content

Start Here

If this is your first pass through the repo, do not start with the pattern list.

Start by running one tiny agent. Then read the trace. Once you can see the loop, the rest of the patterns have somewhere to attach in your head.

30-Second Run

This example uses MockLLM, so it does not need an API key or network.

UV_CACHE_DIR=.uv_cache PYTHONPATH=src uv run --no-sync python examples/21_react_loop.py

Expected output:

4
[trace] .traces/21_react_loop.jsonl

What Just Happened

The task is deliberately boring: compute 2+2.

That is the point. We want the control flow to be obvious:

  1. The model emits a structured action: call the add tool.
  2. The runtime executes the tool and records the observation: 4.
  3. The model emits a final answer.
  4. The runner stops because the action type is final.

This is the smallest useful agent loop.

The Code

Open the full example
from __future__ import annotations

from pathlib import Path

from agent_patterns_lab.patterns.react import run_react
from agent_patterns_lab.runtime import MockLLM, RunLimits, Tool, ToolRegistry, Tracer


def main() -> None:
    tracer = Tracer()

    def add(args: dict) -> str:
        return str(int(args["a"]) + int(args["b"]))

    tools = ToolRegistry([Tool(name="add", description="Add two integers", handler=add)])

    model = MockLLM(
        [
            '{"type":"tool","tool":"add","args":{"a":2,"b":2}}',
            '{"type":"final","answer":"4"}',
        ]
    )

    out = run_react(
        model,
        task="Compute 2+2.",
        tools=tools,
        limits=RunLimits(max_steps=5),
        tracer=tracer,
    )

    print(out)
    trace_path = tracer.export_jsonl(Path(".traces") / "21_react_loop.jsonl")
    print(f"[trace] {trace_path}")


if __name__ == "__main__":
    main()

The Three Ideas to Notice

1. The model is scripted here

MockLLM returns two pre-written responses. That makes the example deterministic, which is what you want while learning a control pattern.

2. Tools are plain Python functions

The add tool takes a dictionary and returns a string. Nothing magical happens at the tool boundary.

3. The loop is controlled by code

The model can suggest an action, but the runtime decides whether to parse it, call a tool, append an observation, stop, or fail.

Where to Go Next

  • Read Mental Model to understand workflows, agent loops, and multi-agent systems.
  • Read Choose a Pattern when you have a concrete failure mode.
  • Read ReAct if you want to understand the loop in detail.