Getting Started
Until now you have built tools and connected to APIs. In this step you will learn the patterns that tie everything together into an autonomous agent. An architecture is the control flow that determines how an agent reasons, acts, and decides when it is done.
The most important architecture to understand is ReAct (Reasoning + Acting). It was introduced in a 2022 research paper and has become the default pattern for most agent implementations. The idea is simple: before every action, the agent writes out its reasoning. After every action, it observes the result and decides what to do next.
Here is the core loop in pseudocode:
while not done:
thought = llm("Given the goal and observations so far, what should I do next?")
action = parse_action(thought)
observation = execute_tool(action)
history.append(thought, action, observation)
if thought contains final answer:
done = True
Key Concepts
Plan-and-Execute separates planning from execution. Instead of interleaving thought and action on every step, the agent first creates a complete plan, then executes each step:
async def plan_and_execute(goal: str, tools: list) -> str:
# Phase 1: Create the plan
plan = await llm_call(
f"Break this goal into 3-5 concrete steps: {goal}\n"
f"Available tools: {[t['name'] for t in tools]}\n"
f"Return a numbered list of steps."
)
results = []
# Phase 2: Execute each step
for step in parse_steps(plan):
result = await execute_step(step, tools)
results.append(result)
# Phase 3: Synthesize
return await llm_call(
f"Goal: {goal}\nResults: {results}\nSynthesize a final answer."
)
This architecture works well for multi-step tasks where the overall strategy can be determined upfront. It is less adaptive than ReAct but more predictable.
Self-reflection adds a review loop where the agent evaluates its own output before returning it. This catches errors, hallucinations, and incomplete answers:
draft = await generate_answer(question, context)
critique = await llm_call(
f"Review this answer for accuracy and completeness:\n"
f"Question: {question}\nAnswer: {draft}\n"
f"List any issues or improvements needed."
)
if "no issues" not in critique.lower():
final = await llm_call(
f"Revise this answer based on the critique:\n"
f"Original: {draft}\nCritique: {critique}"
)
Goal decomposition is the skill of breaking complex tasks into manageable subtasks. A well-designed agent can recursively decompose goals: "Research competitors and write a report" becomes "1. Identify top 5 competitors, 2. Gather data on each, 3. Compare features, 4. Write summary." Each subtask can be handled by a focused sub-agent or tool sequence.
Hands-On Practice
Implement ReAct from scratch without LangChain or any framework. Give the agent access to two or three simple tools (a calculator, a search stub, a string manipulation function) and test it with questions that require multiple steps. Watch how the reasoning trace helps you debug when the agent goes wrong.
The key lesson here is that architectures are just patterns. Once you understand the core loop, you can adapt it. Most production agents use a hybrid approach: ReAct for general problem solving, Plan-and-Execute for structured workflows, and self-reflection for high-stakes outputs.