{ "cells": [ { "cell_type": "markdown", "id": "63de0513", "metadata": { "papermill": { "duration": 0.014979, "end_time": "2026-05-27T04:26:13.888458+00:00", "exception": false, "start_time": "2026-05-27T04:26:13.873479+00:00", "status": "completed" }, "tags": [] }, "source": [ "# 03 · ReAct — Reason + Act, with the Thought *architecturally* guaranteed\n", "\n", "> **TL;DR.** Tool Use (notebook 02) with an explicit **Thought** step before every Action. We build it as **two LangGraph nodes** — a `think` node that runs the LLM *without* tools (so it can only produce text) and an `act` node that runs the LLM *with* tools. This is more reliable than the naive single-node version because the Thought channel **cannot be skipped** by the model.\n", ">\n", "> **Reach for it when** the task needs multi-step research where each step depends on the previous result.\n", "> **Avoid when** a single tool call obviously suffices — ReAct doubles the LLM-call count per round versus plain Tool Use.\n", "\n", "| Property | Value |\n", "|---|---|\n", "| Origin | Yao et al., *ReAct: Synergizing Reasoning and Acting in Language Models*, ICLR 2023 ([arXiv:2210.03629](https://arxiv.org/abs/2210.03629)) |\n", "| Reasoning type | Iterative think → act → observe → think → … |\n", "| External tools needed? | Yes (web search by default) |\n", "| Memory across episodes? | No |\n", "| Cost vs Tool Use | ≈ **2×** LLM calls per round (1 think + 1 act); same number of tool calls |\n", "| Implementation | Custom two-node graph (NOT `langgraph.prebuilt.create_react_agent`) — see § 3.1 |\n", "\n", "This notebook builds on notebook 02 (Tool Use). The key difference is *not* the graph topology (still very close to Tool Use) but the **explicit separation of reasoning from action**." ] }, { "cell_type": "markdown", "id": "97fee4d6", "metadata": { "papermill": { "duration": 0.014032, "end_time": "2026-05-27T04:26:13.922588+00:00", "exception": false, "start_time": "2026-05-27T04:26:13.908556+00:00", "status": "completed" }, "tags": [] }, "source": [ "## 2 · Architecture at a glance\n", "\n", "```mermaid\n", "flowchart LR\n", " A([user task]) --> TH[Think
LLM without tools
→ produces Thought
]\n", " TH --> AC[Act
LLM with tools
→ tool call OR final
]\n", " AC --> Q{tool_calls
present?}\n", " Q -->|yes| T[ToolNode]\n", " T --> TH\n", " Q -->|no| F([final answer])\n", "\n", " style TH fill:#e8f5e9,stroke:#388e3c\n", " style AC fill:#e3f2fd,stroke:#1976d2\n", " style T fill:#fff3e0,stroke:#f57c00\n", "```\n", "\n", "**Three nodes, one loop.** `think` runs the LLM *without* tools — it cannot call a tool even if it tries, so the only thing it can produce is a natural-language Thought. `act` runs the LLM *with* tools and is asked, *given the latest Thought*, to call a tool or finalise. The tool node loops back to `think` so every new Action is preceded by fresh reasoning." ] }, { "cell_type": "markdown", "id": "db5f0491", "metadata": { "papermill": { "duration": 0.012009, "end_time": "2026-05-27T04:26:13.942456+00:00", "exception": false, "start_time": "2026-05-27T04:26:13.930447+00:00", "status": "completed" }, "tags": [] }, "source": [ "## 3 · Theory\n", "\n", "### 3.1 · Why two nodes? Why not `create_react_agent`?\n", "\n", "LangGraph ships a prebuilt called `create_react_agent` that implements ReAct as a single agent node. It works like this:\n", "\n", "```python\n", "# The naive (and brittle) approach\n", "response = llm.bind_tools(tools).invoke(messages)\n", "# response is an AIMessage where:\n", "# - response.content = the \"Thought\" (in theory)\n", "# - response.tool_calls = the \"Action\" (in theory)\n", "```\n", "\n", "In theory the model packs Thought + Action into one AIMessage. **In practice — and this is observed live in our captured traces** — models like Llama 3.3 70B happily emit a `tool_calls` field with **empty `content`**. The Thought just… disappears. ReAct silently degrades to Tool Use.\n", "\n", "We initially used `create_react_agent` for this notebook and the captured run showed `thought_count=0` despite the system prompt explicitly asking for Thoughts. That's not ReAct — that's misleading.\n", "\n", "**The two-node architecture forces the Thought to exist.** The `think` node has no tools bound. The LLM literally cannot call a tool from that node — the only thing it can do is produce text. That text is the Thought, and it is **guaranteed**.\n", "\n", "| Approach | Thought guaranteed? | Cost per round | Pedagogically clear? |\n", "|---|---|---|---|\n", "| `create_react_agent` (single node) | No | 1 LLM call | yes but the Thought is implicit |\n", "| **Two-node (this notebook)** | **Yes** | **2 LLM calls** | yes and the Thought is explicit |\n", "| Manual text-parsed ReAct (old-school) | Yes (if format is followed) | 1 LLM call | brittle parsing required |\n", "\n", "### 3.2 · Why the Thought step actually helps (when it actually happens)\n", "\n", "The Thought step is not just decoration. When it really runs, it produces three real effects:\n", "\n", "1. **Better query selection.** Forcing the model to write \"I need to find X because Y\" before searching makes it commit to a hypothesis. Naive Tool Use often searches with the user's exact words; ReAct searches with what the agent *thinks* will best answer the question — usually more specific.\n", "2. **Inter-round coherence.** Thoughts accumulate in the message history. Round-3's reasoning can reference round-1's reasoning. Tool Use also has the message history, but without explicit Thoughts there's nothing for round 3 to reference except past tool outputs.\n", "3. **Debuggability.** When ReAct misbehaves, you read the Thoughts and immediately see the mistaken assumption. With Tool Use you see only `(query, result, query, result, …)` and have to guess.\n", "\n", "### 3.3 · Reasoning models — do they fix this without the two-node design?\n", "\n", "Modern *thinking* / reasoning models (Qwen3-Thinking, DeepSeek-R1, OpenAI gpt-oss-120b) produce internal `` reasoning **before** their visible response. With these models, `create_react_agent`'s single-node design works better because the model uses its reasoning budget to plan the tool call and tends to populate `content` more reliably.\n", "\n", "But two notes:\n", "\n", "- The `` block is **internal CoT**, hidden by default and not part of the message history. It's not a *user-visible* ReAct Thought.\n", "- Reasoning models are more expensive and slower. Defaulting to them across the whole repo would 5–10× the API bill.\n", "\n", "**Verdict:** the two-node architectural approach works on every tool-calling provider including the cheapest ones. We use it as the default. In § 10 we show what happens when you additionally swap to a reasoning model — you get *richer* Thoughts on top of the guarantee.\n", "\n", "### 3.4 · Where ReAct sits\n", "\n", "| Pattern | Loop body | Thought visible? | Plan ahead? | Use when |\n", "|---|---|---|---|---|\n", "| Tool Use (nb 02) | act → observe | no | no | one-shot lookups |\n", "| **ReAct** *(this notebook)* | **think → act → observe** | **yes (guaranteed)** | no | multi-step research |\n", "| Planning (nb 04) | plan once → execute | no (plan replaces) | yes | task decomposes upfront |\n", "| PEV (nb 06) | plan → exec → verify | partial | yes + verify | actions can fail silently |\n", "| Reflection (nb 01) | generate → critique → refine | yes (in critique) | no | quality > speed |\n", "| LATS (nb 22) | tree-search over ReAct branches | yes | implicit | large search space, has reward signal |\n", "\n", "### 3.5 · What still goes wrong (you'll see live in § 9)\n", "\n", "The two-node design forces a Thought *to exist*, but it can't force the Thought to be *substantive*:\n", "\n", "1. **Hollow thoughts.** \"Thought: I need to search for X\" is a thought-shaped string but doesn't really reason. Cap with a sterner prompt or use a reasoning model.\n", "2. **Thought–action mismatch.** Thought says \"search for X\" but the act node searches for Y. Modern models are usually consistent, but it happens — especially with smaller models.\n", "3. **Repeated thoughts.** When the model already has enough info, the second Thought just paraphrases the first. Wastes tokens; not strictly a bug.\n", "4. **Over-thinking simple tasks.** ReAct's 2-call overhead is wasted on 1-call tasks. Use **Adaptive RAG (nb 26)** or a router-style **Meta-Controller (nb 11)** to pick Tool Use vs ReAct vs Planning per task.\n" ] }, { "cell_type": "markdown", "id": "fed5c4c4", "metadata": { "papermill": { "duration": 0.013835, "end_time": "2026-05-27T04:26:13.968581+00:00", "exception": false, "start_time": "2026-05-27T04:26:13.954746+00:00", "status": "completed" }, "tags": [] }, "source": [ "## 4 · Setup" ] }, { "cell_type": "code", "execution_count": 1, "id": "a2bee99a", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T04:26:14.026043Z", "iopub.status.busy": "2026-05-27T04:26:14.026043Z", "iopub.status.idle": "2026-05-27T04:26:16.262056Z", "shell.execute_reply": "2026-05-27T04:26:16.262056Z" }, "papermill": { "duration": 2.264643, "end_time": "2026-05-27T04:26:16.268483+00:00", "exception": false, "start_time": "2026-05-27T04:26:14.003840+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "data": { "text/html": [ "
Provider: nebius  ·  Model: meta-llama/Llama-3.3-70B-Instruct ─────────────────────────────────────────────────────\n",
       "
\n" ], "text/plain": [ "\u001b[1;36mProvider: nebius · Model: meta-llama/Llama-\u001b[0m\u001b[1;36m3.3\u001b[0m\u001b[1;36m-70B-Instruct\u001b[0m \u001b[92m─────────────────────────────────────────────────────\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
LangSmith tracing: enabled                                                                                         \n",
       "
\n" ], "text/plain": [ "LangSmith tracing: enabled \n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from agentic_architectures import get_llm, enable_langsmith, settings\n", "from agentic_architectures.architectures import ReAct\n", "from agentic_architectures.ui import print_md, print_header, print_step\n", "\n", "traced = enable_langsmith()\n", "print_header(f\"Provider: {settings.llm_provider} · Model: {settings.llm_model}\")\n", "print_md(f\"LangSmith tracing: {'enabled' if traced else 'disabled'}\")" ] }, { "cell_type": "markdown", "id": "58455604", "metadata": { "papermill": { "duration": 0.009991, "end_time": "2026-05-27T04:26:16.288592+00:00", "exception": false, "start_time": "2026-05-27T04:26:16.278601+00:00", "status": "completed" }, "tags": [] }, "source": [ "## 5 · Library walkthrough\n", "\n", "Source: [`src/agentic_architectures/architectures/react.py`](../src/agentic_architectures/architectures/react.py).\n", "\n", "The class has three key pieces:\n", "\n", "1. **`_think(state)`** — invokes the LLM **without** binding tools. The model has no way to call a tool from this node; it can only produce text. The output is wrapped as an `AIMessage` with `additional_kwargs={\"react_step\": \"thought\"}` so downstream code can identify Thoughts separately from tool-calling AIMessages.\n", "2. **`_act(state)`** — invokes the LLM **with** tools bound. Given the latest Thought in the message history, asks the model to call a tool or finalise.\n", "3. **`build()`** — wires `think → act → tools → think` as a cycle; `act → END` is the exit when no tool calls remain.\n", "\n", "The two distinct instruction prompts (`THINK_INSTRUCTION`, `ACT_INSTRUCTION`) are appended *inline* to each invocation but **not** persisted in state — only the model's responses end up in the conversation history. That keeps the message log clean and reproducible." ] }, { "cell_type": "code", "execution_count": 2, "id": "3174e01b", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T04:26:16.317651Z", "iopub.status.busy": "2026-05-27T04:26:16.310763Z", "iopub.status.idle": "2026-05-27T04:26:16.340097Z", "shell.execute_reply": "2026-05-27T04:26:16.335827Z" }, "papermill": { "duration": 0.040418, "end_time": "2026-05-27T04:26:16.340097+00:00", "exception": false, "start_time": "2026-05-27T04:26:16.299679+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "--- THINK_INSTRUCTION ---\n", "Produce EXACTLY ONE short paragraph beginning with the literal word 'Thought:' that (a) reflects on what you have learned from the conversation so far, and (b) states the specific next step needed to advance toward an answer. Do NOT call any tools in this step — only produce the Thought.\n", "\n", "--- ACT_INSTRUCTION ---\n", "Based on your latest Thought above, take exactly ONE action:\n", " (a) Call exactly ONE tool whose arguments implement your Thought, OR\n", " (b) Write the final answer (no tool call) if you already have enough evidence. Include source URLs in the final answer.\n" ] } ], "source": [ "from agentic_architectures.architectures import react as r_mod\n", "\n", "print('--- THINK_INSTRUCTION ---')\n", "print(r_mod.ReAct.THINK_INSTRUCTION)\n", "print()\n", "print('--- ACT_INSTRUCTION ---')\n", "print(r_mod.ReAct.ACT_INSTRUCTION)" ] }, { "cell_type": "markdown", "id": "e6232800", "metadata": { "papermill": { "duration": 0.016111, "end_time": "2026-05-27T04:26:16.368653+00:00", "exception": false, "start_time": "2026-05-27T04:26:16.352542+00:00", "status": "completed" }, "tags": [] }, "source": [ "## 6 · Trace events\n", "\n", "A two-node ReAct trace contains five event types:\n", "\n", "| Event | Source | When emitted |\n", "|---|---|---|\n", "| `user` | the caller's `HumanMessage` | once, at the start |\n", "| `thought` | output of `_think` (marked `react_step=thought`) | once per round |\n", "| `tool_call` | `_act`'s AIMessage `tool_calls` | once per round (until the final round) |\n", "| `tool_result` | ToolNode's `ToolMessage` | once per tool call |\n", "| `agent` | `_act`'s final AIMessage (no tool calls) | once, at the end |\n", "\n", "The library's `_messages_to_trace` helper (in `tool_use.py`, shared with all tool-using architectures) checks the `react_step` marker so Thoughts are categorised correctly even though they look like normal AIMessages on the wire." ] }, { "cell_type": "markdown", "id": "4341a857", "metadata": { "papermill": { "duration": 0.015169, "end_time": "2026-05-27T04:26:16.395258+00:00", "exception": false, "start_time": "2026-05-27T04:26:16.380089+00:00", "status": "completed" }, "tags": [] }, "source": [ "## 7 · Build the graph\n", "\n", "The cell below renders the **actual compiled `StateGraph`** as a PNG. Three nodes — `think`, `act`, `tools` — and a cycle `tools → think`. If this diagram disagrees with § 2's static one, the implementation has drifted." ] }, { "cell_type": "code", "execution_count": 3, "id": "0e4254c7", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T04:26:16.431019Z", "iopub.status.busy": "2026-05-27T04:26:16.431019Z", "iopub.status.idle": "2026-05-27T04:26:26.011941Z", "shell.execute_reply": "2026-05-27T04:26:26.008126Z" }, "papermill": { "duration": 9.602655, "end_time": "2026-05-27T04:26:26.011941+00:00", "exception": false, "start_time": "2026-05-27T04:26:16.409286+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "---\n", "config:\n", " flowchart:\n", " curve: linear\n", "---\n", "graph TD;\n", "\t__start__([

__start__

]):::first\n", "\tthink(think)\n", "\tact(act)\n", "\ttools(tools)\n", "\t__end__([

__end__

]):::last\n", "\t__start__ --> think;\n", "\tact -.-> __end__;\n", "\tact -.-> tools;\n", "\tthink --> act;\n", "\ttools --> think;\n", "\tclassDef default fill:#f2f0ff,line-height:1.2\n", "\tclassDef first fill-opacity:0\n", "\tclassDef last fill:#bfb6fc\n", "\n" ] } ], "source": [ "from IPython.display import Image, display\n", "\n", "arch = ReAct(max_rounds=4)\n", "graph = arch.build()\n", "display(Image(graph.get_graph().draw_mermaid_png()))\n", "print(arch.diagram())" ] }, { "cell_type": "markdown", "id": "158af45c", "metadata": { "papermill": { "duration": 0.013752, "end_time": "2026-05-27T04:26:26.044301+00:00", "exception": false, "start_time": "2026-05-27T04:26:26.030549+00:00", "status": "completed" }, "tags": [] }, "source": [ "## 8 · Live run\n", "\n", "Concrete task: a multi-hop question whose answer requires at least one search. The citation requirement forces grounding." ] }, { "cell_type": "code", "execution_count": 4, "id": "220d41d1", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T04:26:26.074583Z", "iopub.status.busy": "2026-05-27T04:26:26.074583Z", "iopub.status.idle": "2026-05-27T04:26:54.297552Z", "shell.execute_reply": "2026-05-27T04:26:54.294057Z" }, "papermill": { "duration": 28.241068, "end_time": "2026-05-27T04:26:54.299106+00:00", "exception": false, "start_time": "2026-05-27T04:26:26.058038+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "data": { "text/html": [ "
Final answer ──────────────────────────────────────────────────────────────────────────────────────────────────────\n",
       "
\n" ], "text/plain": [ "\u001b[1;36mFinal answer\u001b[0m \u001b[92m──────────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
Based on the search results, the current CEO of OpenAI as of 2026-05-27 is Sam Altman. According to the information\n",
       "provided in the search results, Sam Altman has been the CEO of OpenAI since 2019.                                  \n",
       "\n",
       "Source URLs: https://www.businessinsider.com/sam-altman                                                            \n",
       "https://www.cnbc.com/2026/05/12/openai-trial-updates-sam-altman-set-to-testify-in-musk-suit.html                   \n",
       "https://techcrunch.com/2026/05/16/openai-co-founder-greg-brockman-reportedly-takes-charge-of-product-strategy/     \n",
       "
\n" ], "text/plain": [ "Based on the search results, the current CEO of OpenAI as of 2026-05-27 is Sam Altman. According to the information\n", "provided in the search results, Sam Altman has been the CEO of OpenAI since 2019. \n", "\n", "Source URLs: https://www.businessinsider.com/sam-altman \n", "https://www.cnbc.com/2026/05/12/openai-trial-updates-sam-altman-set-to-testify-in-musk-suit.html \n", "https://techcrunch.com/2026/05/16/openai-co-founder-greg-brockman-reportedly-takes-charge-of-product-strategy/ \n" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/html": [ "
2 tool call(s)  ·  3 thought(s)  ·  1 agent round(s) ──────────────────────────────────────────────────────────────\n",
       "
\n" ], "text/plain": [ "\u001b[1;36m2\u001b[0m\u001b[1;36m tool \u001b[0m\u001b[1;36mcall\u001b[0m\u001b[1;36m(\u001b[0m\u001b[1;36ms\u001b[0m\u001b[1;36m)\u001b[0m\u001b[1;36m · \u001b[0m\u001b[1;36m3\u001b[0m\u001b[1;36m \u001b[0m\u001b[1;36mthought\u001b[0m\u001b[1;36m(\u001b[0m\u001b[1;36ms\u001b[0m\u001b[1;36m)\u001b[0m\u001b[1;36m · \u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;36m agent \u001b[0m\u001b[1;36mround\u001b[0m\u001b[1;36m(\u001b[0m\u001b[1;36ms\u001b[0m\u001b[1;36m)\u001b[0m \u001b[92m──────────────────────────────────────────────────────────────\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from datetime import date\n", "\n", "TASK = (\n", " f\"As of {date.today().isoformat()}, who is the current CEO of OpenAI, \"\n", " f\"and when did they first assume that role? Provide at least one source URL.\"\n", ")\n", "\n", "result = arch.run(TASK)\n", "\n", "print_header(\"Final answer\")\n", "print_md(result.output)\n", "print()\n", "print_header(\n", " f\"{result.metadata['tool_calls']} tool call(s) · \"\n", " f\"{result.metadata['thought_count']} thought(s) · \"\n", " f\"{result.metadata['rounds']} agent round(s)\"\n", ")" ] }, { "cell_type": "markdown", "id": "db0bd2fd", "metadata": { "papermill": { "duration": 0.013282, "end_time": "2026-05-27T04:26:54.328830+00:00", "exception": false, "start_time": "2026-05-27T04:26:54.315548+00:00", "status": "completed" }, "tags": [] }, "source": [ "### 8.0 · What just happened, briefly\n", "\n", "Look at the three counts above:\n", "\n", "- **`thought_count`** — with the two-node architecture, this should be **≥ tool_calls** (typically `tool_calls + 1`: one Thought before each Action plus one final Thought before the answer). If `thought_count = 0`, something is wrong with the graph wiring.\n", "- **`tool_calls`** — for a 1-fact question with citation, expect 1–2. More than 3 = over-thinking.\n", "- **`rounds`** = number of finalising agent turns. Always 1 in a well-behaved run.\n", "\n", "§ 9 below quantifies each from the actual run and flags any pathologies." ] }, { "cell_type": "markdown", "id": "5a534364", "metadata": { "papermill": { "duration": 0.018868, "end_time": "2026-05-27T04:26:54.358437+00:00", "exception": false, "start_time": "2026-05-27T04:26:54.339569+00:00", "status": "completed" }, "tags": [] }, "source": [ "### 8.1 · Full Thought → Action → Observation trace" ] }, { "cell_type": "code", "execution_count": 5, "id": "d3604ced", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T04:26:54.394541Z", "iopub.status.busy": "2026-05-27T04:26:54.394541Z", "iopub.status.idle": "2026-05-27T04:26:54.658503Z", "shell.execute_reply": "2026-05-27T04:26:54.657882Z" }, "papermill": { "duration": 0.296722, "end_time": "2026-05-27T04:26:54.665500+00:00", "exception": false, "start_time": "2026-05-27T04:26:54.368778+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "data": { "text/html": [ "
 [1] USER\n",
       "
\n" ], "text/plain": [ "\u001b[1;35m›\u001b[0m \u001b[1m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1m]\u001b[0m\u001b[1m USER\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
As of 2026-05-27, who is the current CEO of OpenAI, and when did they first assume that role? Provide at least one \n",
       "source URL.\n",
       "
\n" ], "text/plain": [ "As of \u001b[1;36m2026\u001b[0m-\u001b[1;36m05\u001b[0m-\u001b[1;36m27\u001b[0m, who is the current CEO of OpenAI, and when did they first assume that role? Provide at least one \n", "source URL.\n" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/html": [ "
 [2] THOUGHT\n",
       "
\n" ], "text/plain": [ "\u001b[1;35m›\u001b[0m \u001b[1m[\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1m]\u001b[0m\u001b[1m THOUGHT\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
Thought: From the conversation so far, I have learned that I need to find the current CEO of OpenAI as of \n",
       "2026-05-27 and the date they first assumed that role. To advance toward an answer, the next step is to search for \n",
       "the most recent and reliable sources of information on OpenAI's leadership, such as official company announcements,\n",
       "reputable news articles, or the company's website, to determine \n",
       "
\n" ], "text/plain": [ "Thought: From the conversation so far, I have learned that I need to find the current CEO of OpenAI as of \n", "\u001b[1;36m2026\u001b[0m-\u001b[1;36m05\u001b[0m-\u001b[1;36m27\u001b[0m and the date they first assumed that role. To advance toward an answer, the next step is to search for \n", "the most recent and reliable sources of information on OpenAI's leadership, such as official company announcements,\n", "reputable news articles, or the company's website, to determine \n" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/html": [ "
 [3] ACTION → tavily_search\n",
       "
\n" ], "text/plain": [ "\u001b[1;35m›\u001b[0m \u001b[1m[\u001b[0m\u001b[1;36m3\u001b[0m\u001b[1m]\u001b[0m\u001b[1m ACTION → tavily_search\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
`OpenAI CEO as of 2026-05-27`\n",
       "
\n" ], "text/plain": [ "`OpenAI CEO as of \u001b[1;36m2026\u001b[0m-\u001b[1;36m05\u001b[0m-\u001b[1;36m27\u001b[0m`\n" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/html": [ "
 [4] OBSERVATION (tavily_search)\n",
       "
\n" ], "text/plain": [ "\u001b[1;35m›\u001b[0m \u001b[1m[\u001b[0m\u001b[1;36m4\u001b[0m\u001b[1m]\u001b[0m\u001b[1m OBSERVATION \u001b[0m\u001b[1m(\u001b[0m\u001b[1mtavily_search\u001b[0m\u001b[1m)\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
{'error': ValueError('Error 400: When time_range is set, start_date or end_date cannot be set')}...\n",
       "
\n" ], "text/plain": [ "\u001b[1m{\u001b[0m\u001b[32m'error'\u001b[0m: \u001b[1;35mValueError\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'Error 400: When time_range is set, start_date or end_date cannot be set'\u001b[0m\u001b[1m)\u001b[0m\u001b[1m}\u001b[0m\u001b[33m...\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/html": [ "
 [5] THOUGHT\n",
       "
\n" ], "text/plain": [ "\u001b[1;35m›\u001b[0m \u001b[1m[\u001b[0m\u001b[1;36m5\u001b[0m\u001b[1m]\u001b[0m\u001b[1m THOUGHT\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
Thought: From the conversation so far, I have learned that I need to find the current CEO of OpenAI as of \n",
       "2026-05-27 and the date they first assumed that role. To advance toward an answer, the next step is to search for \n",
       "the most recent and reliable sources of information on OpenAI's leadership, such as official company announcements,\n",
       "reputable news articles, or the company's website, to determine \n",
       "
\n" ], "text/plain": [ "Thought: From the conversation so far, I have learned that I need to find the current CEO of OpenAI as of \n", "\u001b[1;36m2026\u001b[0m-\u001b[1;36m05\u001b[0m-\u001b[1;36m27\u001b[0m and the date they first assumed that role. To advance toward an answer, the next step is to search for \n", "the most recent and reliable sources of information on OpenAI's leadership, such as official company announcements,\n", "reputable news articles, or the company's website, to determine \n" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/html": [ "
 [6] ACTION → tavily_search\n",
       "
\n" ], "text/plain": [ "\u001b[1;35m›\u001b[0m \u001b[1m[\u001b[0m\u001b[1;36m6\u001b[0m\u001b[1m]\u001b[0m\u001b[1m ACTION → tavily_search\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
`OpenAI CEO as of 2026-05-27`\n",
       "
\n" ], "text/plain": [ "`OpenAI CEO as of \u001b[1;36m2026\u001b[0m-\u001b[1;36m05\u001b[0m-\u001b[1;36m27\u001b[0m`\n" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/html": [ "
 [7] OBSERVATION (tavily_search)\n",
       "
\n" ], "text/plain": [ "\u001b[1;35m›\u001b[0m \u001b[1m[\u001b[0m\u001b[1;36m7\u001b[0m\u001b[1m]\u001b[0m\u001b[1m OBSERVATION \u001b[0m\u001b[1m(\u001b[0m\u001b[1mtavily_search\u001b[0m\u001b[1m)\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
{\"query\": \"OpenAI CEO as of 2026-05-27\", \"follow_up_questions\": null, \"answer\": null, \"images\": [], \"results\": \n",
       "[{\"url\": \"https://www.businessinsider.com/sam-altman\", \"title\": \"The career rise of OpenAI's billionaire CEO, Sam \n",
       "Altman - Business Insider\", \"score\": 0.8358192, \"publis...\n",
       "
\n" ], "text/plain": [ "\u001b[1m{\u001b[0m\u001b[32m\"query\"\u001b[0m: \u001b[32m\"OpenAI CEO as of 2026-05-27\"\u001b[0m, \u001b[32m\"follow_up_questions\"\u001b[0m: null, \u001b[32m\"answer\"\u001b[0m: null, \u001b[32m\"images\"\u001b[0m: \u001b[1m[\u001b[0m\u001b[1m]\u001b[0m, \u001b[32m\"results\"\u001b[0m: \n", "\u001b[1m[\u001b[0m\u001b[1m{\u001b[0m\u001b[32m\"url\"\u001b[0m: \u001b[32m\"https://www.businessinsider.com/sam-altman\"\u001b[0m, \u001b[32m\"title\"\u001b[0m: \u001b[32m\"The career rise of OpenAI's billionaire CEO, Sam \u001b[0m\n", "\u001b[32mAltman - Business Insider\"\u001b[0m, \u001b[32m\"score\"\u001b[0m: \u001b[1;36m0.8358192\u001b[0m, \"publis\u001b[33m...\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/html": [ "
 [8] THOUGHT\n",
       "
\n" ], "text/plain": [ "\u001b[1;35m›\u001b[0m \u001b[1m[\u001b[0m\u001b[1;36m8\u001b[0m\u001b[1m]\u001b[0m\u001b[1m THOUGHT\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
Thought: From the conversation so far, I have learned that I need to find the current CEO of OpenAI as of \n",
       "2026-05-27 and the date they first assumed that role. To advance toward an answer, the next step is to carefully \n",
       "review the search results provided, focusing on the most recent and reliable sources, such as official company \n",
       "announcements or reputable news articles, to identify the current CEO \n",
       "
\n" ], "text/plain": [ "Thought: From the conversation so far, I have learned that I need to find the current CEO of OpenAI as of \n", "\u001b[1;36m2026\u001b[0m-\u001b[1;36m05\u001b[0m-\u001b[1;36m27\u001b[0m and the date they first assumed that role. To advance toward an answer, the next step is to carefully \n", "review the search results provided, focusing on the most recent and reliable sources, such as official company \n", "announcements or reputable news articles, to identify the current CEO \n" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/html": [ "
 [9] FINAL ANSWER\n",
       "
\n" ], "text/plain": [ "\u001b[1;35m›\u001b[0m \u001b[1m[\u001b[0m\u001b[1;36m9\u001b[0m\u001b[1m]\u001b[0m\u001b[1m FINAL ANSWER\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
Based on the search results, the current CEO of OpenAI as of 2026-05-27 is Sam Altman. According to the information\n",
       "provided in the search results, Sam Altman has been the CEO of OpenAI since 2019. \n",
       "\n",
       "Source URLs:\n",
       "https://www.businessinsider.com/sam-altman \n",
       "https://www.cnbc.com/2026/05/12/openai-tria\n",
       "
\n" ], "text/plain": [ "Based on the search results, the current CEO of OpenAI as of \u001b[1;36m2026\u001b[0m-\u001b[1;36m05\u001b[0m-\u001b[1;36m27\u001b[0m is Sam Altman. According to the information\n", "provided in the search results, Sam Altman has been the CEO of OpenAI since \u001b[1;36m2019\u001b[0m. \n", "\n", "Source URLs:\n", "\u001b[4;94mhttps://www.businessinsider.com/sam-altman\u001b[0m \n", "\u001b[4;94mhttps://www.cnbc.com/2026/05/12/openai-tria\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "for i, t in enumerate(result.trace, 1):\n", " if t['type'] == 'user':\n", " print_step(f\"[{i}] USER\", t['content'][:200])\n", " elif t['type'] == 'thought':\n", " print_step(f\"[{i}] THOUGHT\", t['content'][:400])\n", " elif t['type'] == 'tool_call':\n", " args = t['args'] if isinstance(t['args'], dict) else str(t['args'])\n", " query = args.get('query', args) if isinstance(args, dict) else args\n", " print_step(f\"[{i}] ACTION → {t['tool']}\", f\"`{query}`\")\n", " elif t['type'] == 'tool_result':\n", " snippet = t['content'][:280].replace('\\n', ' ')\n", " print_step(f\"[{i}] OBSERVATION ({t['tool']})\", snippet + '...')\n", " elif t['type'] == 'agent':\n", " print_step(f\"[{i}] FINAL ANSWER\", (t.get('content') or '')[:300])\n", " print()" ] }, { "cell_type": "markdown", "id": "715a500d", "metadata": { "papermill": { "duration": 0.030104, "end_time": "2026-05-27T04:26:54.721317+00:00", "exception": false, "start_time": "2026-05-27T04:26:54.691213+00:00", "status": "completed" }, "tags": [] }, "source": [ "## 9 · What we just observed\n", "\n", "The cells above are live. Below: a quantitative + qualitative breakdown of the **actual** ReAct loop the Nebius-hosted Llama-3.3-70B agent produced on this run.\n", "\n", "### 9.1 · Quantitative summary\n", "\n", "| Metric | Value |\n", "|---|---|\n", "| Tool calls (Actions) | **2** |\n", "| Thoughts | **3** |\n", "| Agent rounds | 1 |\n", "| Thought:Action ratio | 1.50 (target: 1.0 for clean ReAct) |\n", "| Final answer length | 575 chars |\n", "\n", "### 9.2 · Thought ↔ Action alignment\n", "\n", "| # | Thought (truncated) | Action |\n", "|---|---|---|\n", "| 1 | Thought: From the conversation so far, I have learned that I need to find the current CEO of OpenAI as of 2026-05-27 and the date they first assumed that role. … | `OpenAI CEO as of 2026-05-27` |\n", "\n", "### 9.3 · Pathologies surfaced in this run\n", "\n", "- **Query repetition.** 1 of 2 actions were duplicate queries. ReAct's thought step is supposed to *prevent* this by forcing the model to justify the next call. When it happens anyway, the thoughts were probably hollow.\n", "\n", "### 9.4 · The final answer (verbatim)\n", "\n", "> Based on the search results, the current CEO of OpenAI as of 2026-05-27 is Sam Altman. According to the information\n", "> provided in the search results, Sam Altman has been the CEO of OpenAI since 2019. \n", "> \n", "> Source URLs: https://www.businessinsider.com/sam-altman \n", "> https://www.cnbc.com/2026/05/12/openai-trial-updates-sam-altman-set-to-testify-in-musk-suit.html \n", "> https://techcrunch.com/2026/05/16/o…\n", "\n", "### 9.5 · The takeaway\n", "\n", "When the Thought:Action ratio is **1.0** and queries are *different* round-to-round, ReAct is buying you genuine value over Tool Use — the thoughts are doing real work. When the ratio drops below 1.0 or thoughts are short and queries repeat, you're paying ReAct's extra-token cost for no benefit — switch back to Tool Use (notebook 02) or escalate to **Planning (nb 04)** which decomposes the task upfront." ] }, { "cell_type": "markdown", "id": "83420c5d", "metadata": { "papermill": { "duration": 0.023667, "end_time": "2026-05-27T04:26:54.769786+00:00", "exception": false, "start_time": "2026-05-27T04:26:54.746119+00:00", "status": "completed" }, "tags": [] }, "source": [ "## 10 · Try other providers · also: a reasoning model\n", "\n", "ReAct needs **tool-calling**, same as Tool Use. But this is also where ReAct shines with a *reasoning* model — the model's internal `` budget produces noticeably richer Thoughts.\n", "\n", "The cell below tries OpenAI/Anthropic/Groq if you have their keys set, AND swaps to **`Qwen/Qwen3-235B-A22B-Thinking-2507-fast`** on Nebius (which you already have a key for) to demonstrate the reasoning-model effect." ] }, { "cell_type": "code", "execution_count": 6, "id": "866324cf", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T04:26:54.838681Z", "iopub.status.busy": "2026-05-27T04:26:54.835537Z", "iopub.status.idle": "2026-05-27T04:27:18.000592Z", "shell.execute_reply": "2026-05-27T04:27:17.998028Z" }, "papermill": { "duration": 23.205607, "end_time": "2026-05-27T04:27:18.004324+00:00", "exception": false, "start_time": "2026-05-27T04:26:54.798717+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[skip] openai: no API key in .env\n", "[skip] anthropic: no API key in .env\n", "[skip] groq: no API key in .env\n" ] }, { "data": { "text/html": [ "
Re-running on Nebius Qwen3-Thinking (reasoning model) ─────────────────────────────────────────────────────────────\n",
       "
\n" ], "text/plain": [ "\u001b[1;36mRe-running on Nebius Qwen3-Thinking \u001b[0m\u001b[1;36m(\u001b[0m\u001b[1;36mreasoning model\u001b[0m\u001b[1;36m)\u001b[0m \u001b[92m─────────────────────────────────────────────────────────────\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "The current spot price of one ounce of gold is **$4,529.38 USD**, as reported by Yahoo Finance at 06:13 ET (10:13 GMT) on the latest market data. This reflects a 0.9% decline in spot gold prices amid renewed geopolitical tensions. \n", "\n", "Source: [Yahoo Finance - Gold Retreats as Renewed U.S. Attacks on \n", " thoughts: 2, tool_calls: 1\n", "\n", " First Thought from Qwen3-Thinking (notice the depth vs Llama):\n", " Thought: From the user's initial query requesting the current gold price with a source citation and the subsequent strict formatting instructions for this reflection, I've learned that precision in both data sourcing and response structure is critical; the specific next step required to advance toward an answer is to utilize a reliable financial data API or trusted market source to retrieve the re\n" ] } ], "source": [ "from agentic_architectures.llm.factory import provider_supports_tools\n", "\n", "# (a) Try other providers if their keys are set.\n", "for p in [\"openai\", \"anthropic\", \"groq\"]:\n", " key = settings.api_key_for(p)\n", " if key is None or not key.get_secret_value():\n", " print(f\"[skip] {p}: no API key in .env\")\n", " continue\n", " if not provider_supports_tools(p):\n", " print(f\"[skip] {p}: provider does not advertise tool-calling\")\n", " continue\n", " print_header(f\"Re-running ReAct on {p}\")\n", " r = ReAct(llm=get_llm(provider=p), max_rounds=2).run(\n", " \"What is the current price (USD) of one ounce of gold? Cite the source URL.\"\n", " )\n", " print(r.output[:300])\n", " print(f\" thoughts: {r.metadata['thought_count']}, tool_calls: {r.metadata['tool_calls']}\")\n", " print()\n", "\n", "# (b) Swap to a Nebius reasoning model — same key, just a different model name.\n", "print_header(\"Re-running on Nebius Qwen3-Thinking (reasoning model)\")\n", "thinking_llm = get_llm(\n", " provider=\"nebius\",\n", " model=\"Qwen/Qwen3-235B-A22B-Thinking-2507-fast\",\n", " temperature=0.0,\n", ")\n", "thinking_arch = ReAct(llm=thinking_llm, max_rounds=2)\n", "r = thinking_arch.run(\n", " \"What is the current price (USD) of one ounce of gold? Cite the source URL.\"\n", ")\n", "print(r.output[:300])\n", "print(f\" thoughts: {r.metadata['thought_count']}, tool_calls: {r.metadata['tool_calls']}\")\n", "if r.trace:\n", " first_thought = next((t['content'] for t in r.trace if t['type'] == 'thought'), '')\n", " print()\n", " print(' First Thought from Qwen3-Thinking (notice the depth vs Llama):')\n", " print(' ' + first_thought[:400].replace('\\n', '\\n '))" ] }, { "cell_type": "markdown", "id": "eef83965", "metadata": { "papermill": { "duration": 0.020135, "end_time": "2026-05-27T04:27:18.050302+00:00", "exception": false, "start_time": "2026-05-27T04:27:18.030167+00:00", "status": "completed" }, "tags": [] }, "source": [ "## 11 · Failure modes, safety, extensions\n", "\n", "### 11.1 · Where this breaks (even with the architectural guarantee)\n", "\n", "| Failure | Mechanism | Mitigation |\n", "|---|---|---|\n", "| **Hollow thoughts** | Thought-shaped string with no real reasoning content | Tighten THINK_INSTRUCTION; or switch to a reasoning model (see § 10) |\n", "| **Thought–action mismatch** | Thought says \"search for X\" but Act calls with Y | Real but rare with 70B+ models; check by comparing thought.text and tool.args programmatically |\n", "| **Repeated thoughts** | Second Thought paraphrases the first | Wasted tokens but not a correctness bug; cap `max_rounds` |\n", "| **Over-thinking simple tasks** | 2 LLM calls per round adds up | Route via **Meta-Controller (nb 11)** or **Adaptive RAG (nb 26)** to pick Tool Use vs ReAct |\n", "| **Tool result hallucination** | Agent ignores tool result and answers from training data | Switch to **Self-RAG (nb 25)** or **Corrective RAG (nb 24)** |\n", "\n", "### 11.2 · Production safety\n", "\n", "- All Tool-Use safety rules from notebook 02 apply: cap rounds, whitelist tools, sanitise tool output, per-tool timeouts.\n", "- The Thought text is **user-visible** if you stream the agent — sometimes Thoughts reveal system-prompt internals or expose reasoning the user shouldn't see. Filter or hide before display.\n", "\n", "### 11.3 · Three extensions\n", "\n", "1. **Score Thoughts with `LLMJudge`.** Reject low-quality Thoughts and force the agent to re-think. Bridge to **Reflection (nb 01)** inside ReAct rounds.\n", "2. **Tree-search over ReAct branches.** At each Thought, generate K alternative Thoughts and expand the most promising. **Tree of Thoughts (nb 09)** and **LATS (nb 22)** do exactly this.\n", "3. **Add a verifier.** After the final answer, a separate LLM checks whether cited sources actually support the claim. Move to **PEV (nb 06)** and **Corrective RAG (nb 24)**.\n", "\n", "### 11.4 · What to read next\n", "\n", "- [**04 · Planning**](./04_planning.ipynb) — decompose the task upfront instead of reacting step-by-step.\n", "- [**06 · PEV**](./06_pev.ipynb) — ReAct + verifier + replanning.\n", "- [**09 · Tree of Thoughts**](./09_tree_of_thoughts.ipynb) — ReAct generalised to search.\n", "- [**22 · LATS**](./22_lats.ipynb) — ToT + reward → MCTS over the ReAct space.\n", "- [**26 · Adaptive RAG**](./26_adaptive_rag.ipynb) — auto-route task → Tool Use / ReAct / Planning.\n", "\n", "### 11.5 · References\n", "\n", "1. Yao, S. et al. *ReAct: Synergizing Reasoning and Acting in Language Models.* ICLR 2023. [arXiv:2210.03629](https://arxiv.org/abs/2210.03629)\n", "2. LangGraph `create_react_agent` — [official docs](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent) (note: we deliberately do NOT use this — see § 3.1)\n", "3. Qwen3 reasoning models on Nebius — [studio.nebius.com](https://studio.nebius.com)\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.0" }, "papermill": { "default_parameters": {}, "duration": 69.020554, "end_time": "2026-05-27T04:27:19.521416+00:00", "environment_variables": {}, "exception": null, "input_path": "all-agentic-architectures/notebooks/03_react.ipynb", "output_path": "all-agentic-architectures/notebooks/03_react.ipynb", "parameters": {}, "start_time": "2026-05-27T04:26:10.500862+00:00", "version": "2.7.0" } }, "nbformat": 4, "nbformat_minor": 5 }