Lesson 1: Foundations of Agentic Systems – From Simple Prompting to ReAct Architectures
Lesson 1: Foundations of Agentic Systems – From Simple Prompting to ReAct Architectures
Learning Objective
Master the architectural transition from static prompt engineering to dynamic agentic loops, and implement a pure Python ReAct (Reasoning + Acting) execution engine from first principles.
The Hard Ceiling of Single-Turn Prompting
Single-turn prompting and chained completions fail when faced with real-world technical problems. When a business question requires multi-step data retrieval, intermediate calculations, and validation, an LLM cannot plan the entire sequence in advance without inspecting intermediate results.
Agentic architectures solve this limitation by enabling the model to observe the environment after each action before determining its next move.
The ReAct Pattern Explained
The ReAct framework (Yao et al., 2022) interleaves reasoning and acting in a continuous execution cycle:
- Thought: The agent articulates its current mental model and plans the immediate next step.
- Action: The agent invokes a designated external tool (e.g. database query, calculator, web search) with structured arguments.
- Observation: The execution environment runs the tool and returns the raw output to the agent’s context window.
- Reflection: The agent analyzes the observation. If the objective is met, it outputs the Final Answer; otherwise, it initiates the next Thought.
# Minimal Pure-Python ReAct Loop Skeleton
import json
class SimpleAgent:
def __init__(self, llm_client, tools: dict):
self.client = llm_client
self.tools = tools
self.memory = []
def run(self, user_goal: str, max_iterations: int = 5) -> str:
self.memory.append({"role": "user", "content": user_goal})
for step in range(max_iterations):
response = self.client.generate_thought_and_action(self.memory)
if response.get("is_final"):
return response["final_answer"]
action_name = response["action"]
action_input = response["action_input"]
# Execute tool safely
tool_fn = self.tools.get(action_name)
observation = tool_fn(**action_input) if tool_fn else f"Error: Tool {action_name} not found"
# Append feedback loop
self.memory.append({
"role": "system",
"content": f"Action: {action_name}nObservation: {json.dumps(observation)}"
})
return "Failure: Max execution iterations reached."
Worked Industry Example: Portfolio Valuation Agent
Consider an autonomous agent tasked with auditing portfolio valuations across international equities. The agent cannot compute current values in a single prompt because exchange rates and equity prices fluctuate dynamically.
Using ReAct, the agent first queries an FX rate tool to obtain the current EUR/GBP spot rate (Observation 1), queries a stock price endpoint for the underlying asset (Observation 2), executes a Python calculation tool to compute market capitalisation (Observation 3), and finally synthesizes a validated valuation brief.
Apply It to Your Work
Draft a state diagram for one repetitive investigation in your work (e.g. debugging a customer complaint or triaging a failed ETL pipeline). Identify the specific Thought, Action, and Observation cycles that an agent must execute.
The Beyond Machine Mentorship Bridge
Agentic design requires rigorous software engineering paired with deep mathematical intuition. In the Beyond Machine 1-on-1 Mentorship, Dr Stylianos Kampakis guides you through the architecture of enterprise-ready AI agents. Apply for 1-on-1 mentorship here.

