Workflows vs Autonomous Agents & ReAct Loops
A software workflow follows a predetermined path through deterministic tasks and LLM calls. An autonomous agent, in contrast, actively determines its execution route at runtime using an iterative cycle of Observation, Thought, and Action.
- •Distinguish deterministic LLM workflows (DAGs) from dynamic agent loops.
- •Implement a robust ReAct (Reason + Act) loop with structured tool calling.
- •Handle recursion limits, token budget protection, and infinite loop guards.
In-Depth Architecture & Mechanics
The Spectrum: Workflow vs Agent
1. **Deterministic Chains**: Step A -> Step B -> Step C. The sequence is fixed in code; LLM calls only generate text or transform data within rigid slots. 2. **Router Chains**: An LLM classifies input and routes to 1 of N predefined paths. The branch is dynamic, but the subsequent flow is fixed. 3. **ReAct Pattern (Yao et al., 2022)**: - **Thought**: The model deliberates over the conversation history, available tools, and goal. - **Action**: The model emits a structured function call with strict parameter typing. - **Observation**: The execution environment invokes the tool, captures the output, and appends the result back to context. - **Looping**: Repeats until the agent emits a 'Final Answer' action or encounters an exit condition.
Failure Modes in Agentic Loops - **Semantic Loops**: The agent repeatedly calls the same tool with equivalent arguments because the observation doesn't explicitly resolve its doubt. - **Context Explosion**: Accumulating raw tool observations can quickly exhaust context windows and balloon inference costs. - **Tool Hallucination**: Emitting function arguments that do not conform to the JSON schema.
User Goal ──> [ Planner / LLM ]
│ ▲
▼ │ Observation
[ Tool Call ] ──┘
│
▼ Final Answer
[ User Output ]from typing import Annotated, TypedDict, List, Dict, Any
from pydantic import BaseModel, Field
class AgentState(TypedDict):
messages: List[Dict[str, Any]]
iterations: int
max_iterations: int
is_complete: bool
def reason_and_plan(state: AgentState) -> Dict[str, Any]:
if state["iterations"] >= state["max_iterations"]:
return {"is_complete": True, "messages": [{"role": "assistant", "content": "Reached max iteration budget."}]}
# In real runtime: Invoke LLM with tool definitions
# Returning mock step for demonstration
return {"iterations": state["iterations"] + 1}