Guide to Agent Architecture Patterns in AI: 8 Modular Designs from Production Code

Modern AI agents follow a modular architecture defined by the formula Agent = LLM + Context + Tools, implementing patterns like ReAct loops, async event-driven runtimes, multi-agent orchestration, and self-evolving learning systems to handle complex reasoning tasks.

This guide explores concrete implementation patterns found in the bojieli/ai-agent-book repository, documenting how to build production-grade agent systems. Understanding these agent architecture patterns in AI enables developers to swap components like LLM cores, memory stores, and tool registries without rewriting entire systems.

The Core Formula: Agent = LLM + Context + Tools

Every intelligent agent in the repository decomposes into three interchangeable components. This modular "plug-and-play" design forms the backbone of all architecture patterns described below.

The LLM (Large Language Model) handles reasoning and language generation, as seen in WebSearchAgent located in chapter1/web-search-agent/agent.py. The Context component provides stateful memory and retrieval-augmented generation capabilities, implemented in ContextAwareAgent within chapter3/context/agent.py. The Tools component covers perception and execution primitives like web search or code interpreters, exemplified by the moonshot/web-search:latest formula used by WebSearchAgent.

By swapping any of these three pieces, developers obtain new agent behaviors without architectural redesign. This separation of concerns allows independent scaling of reasoning capabilities, memory systems, and tool integrations.

ReAct Loop: Synchronous Reason-Act-Observe Cycles

The ReAct pattern enables agents to repeatedly call tools, observe results, and refine reasoning until producing a final answer. This iterative approach guarantees that agents gather external knowledge rather than relying on single LLM passes.

In chapter1/web-search-agent/agent.py, the WebSearchAgent.search_and_answer method implements this loop with a configurable max_iterations parameter (defaulting to 5). The implementation records each thought, action, observation, and answer in self.trace, enabling transparent debugging and evaluation. The agent pauses after each tool invocation, processes the observation, and either emits a final answer or generates the next action.

This synchronous pattern works best for deterministic workflows where step-by-step validation matters more than raw throughput.

Async Event-Driven Agents for I/O-Bound Operations

When agents interact with latency-prone resources like video transcription services or remote device controls, async event-driven architectures prevent blocking andenable concurrent operations.

Chapter 4 introduces an AgentRuntime in chapter4/async-agent/runtime.py that schedules tool fibers on a thread pool and processes callbacks upon completion. The runtime maintains an Event Loop as the central scheduler, wraps tool calls in lightweight Tool Fibers (coroutines executing _execute_formula), and tracks agent state through an AgentStatus finite-state machine.

This pattern allows the agent to continue processing or orchestrate other tasks while waiting for slow external APIs to return results.

Multi-Agent Collaboration via Staged Orchestration

Complex tasks require multi-agent collaboration, where specialized sub-agents cooperate via shared staged system prompts or a central orchestrator. This pattern separates concerns and prevents single-agent failure modes from collapsing entire systems.

The implementation in chapter10/multi-role-transfer/orchestrator.py defines a StagedAgent that dispatches to domain-specific sub-agents like PhoneAgent and ComputerAgent based on dialogue stage detection. The orchestrator parallelizes independent sub-tasks, aggregates their observations into unified responses, and isolates failures to specific branches. Each sub-agent focuses on narrow domains—such as phone registration or web browsing—while the orchestrator maintains global context.

Self-Evolving Agents That Learn from Execution Traces

Self-evolving agents ingest their own execution traces, extract learning signals, and update internal models or prompt templates. This creates systems that improve through operation rather than requiring manual re-engineering.

Chapter 8 describes this pattern in chapter8/self_evolving_tools/agent.py (referenced as chapter8/self_evolving_tools/agent.py in implementations). The agent periodically runs a knowledge-distillation pipeline via the distill_knowledge method, converting raw ReAct trajectories from self.trace into fine-tuning data. The core loop involves collecting execution traces, analyzing them with a meta-model to label successful patterns, and triggering lightweight fine-tuning jobs or prompt-template rewrites.

Coding Agents: LLM-Driven Code Interpretation

Coding agents generate executable code which runs immediately in sandboxed environments, feeding stdout back as new context. This pattern extends agent capabilities beyond text generation into deterministic computation and data manipulation.

The CodingAgent in chapter5/coding-agent/agents.py bundles a code_interpreter tool that captures execution output and appends results to conversation history. Safety mechanisms run code inside deterministic containers, catching exceptions and returning them as observations to prevent infinite loops. The LLM generates Python functions to solve mathematical or data-processing tasks, then observes the execution results before continuing reasoning.

Evaluation-Driven Architecture with Structured Telemetry

Production agents require rigorous observability. The evaluation-driven architecture exposes structured telemetry for every interaction, capturing API turns, latency metrics, and cost data.

Each agent method in chapter1/web-search-agent/agent.py appends structured entries to self.api_turns within _chat and _execute_formula implementations. These entries export to JSON for downstream analysis, providing evidence bases for scholarly reproducibility and production monitoring. This telemetry enables cost-aware routing decisions, latency SLA enforcement, and systematic performance regression detection.

Practical Implementation Examples

from chapter1.web_search_agent.agent import WebSearchAgent

agent = WebSearchAgent(verbose=True)

answer = agent.search_and_answer(
    "What is Moonshot AI's Context Caching technology?",
    max_iterations=4,
)
print("\nFinal answer:", answer)

Setting verbose=True prints the ReAct trace showing each thought, action, and observation step.

Async Event-Driven Execution

from chapter4.async_agent.runtime import AgentRuntime
from chapter4.async_agent.agent import AsyncWebSearchAgent

runtime = AgentRuntime()
agent = AsyncWebSearchAgent(runtime, verbose=False)

future = agent.search_and_answer_async(
    "List the latest Kimi model releases.",
    max_iterations=3,
)

print("Doing other work while waiting...")
answer = future.result()
print("\nAnswer:", answer)

The AgentRuntime schedules the web-search fiber while the main thread continues processing other events.

Multi-Agent Orchestration

from chapter10.multi_role_transfer.orchestrator import MultiAgentOrchestrator

orchestrator = MultiAgentOrchestrator(
    stages=["phone", "computer"],
    verbose=True,
)

question = "Help me register a new phone number and then book a meeting on Zoom."
answer = orchestrator.handle(question)
print("\nFinal answer:", answer)

The orchestrator delegates to specialized agents based on detected intent stages, merging their outputs into a coherent response.

Sandbox Code Execution

from chapter5.coding_agent.agents import CodingAgent

agent = CodingAgent(verbose=True)

question = "Write a Python function that returns the nth Fibonacci number."
answer = agent.solve(question)
print("\nResult:", answer)

Generated code executes in a sandbox with exceptions captured as observations to maintain the ReAct trace integrity.

Self-Evolving Knowledge Distillation

from chapter8.self_evolving_tools.agent import SelfEvolvingAgent

agent = SelfEvolvingAgent()

answer = agent.run_query("Explain the benefits of vector databases for RAG.")
print("\nAnswer:", answer)

agent.distill_knowledge()
print("Model fine-tuned on the latest trace.")

The distill_knowledge method extracts patterns from the collected trace to update the underlying model.

Summary

  • Modular Components: Agent systems decompose into interchangeable LLM, Context, and Tool components, enabling rapid experimentation without architectural rewrites.

  • ReAct Pattern: Synchronous reason-act-observe loops in agents like WebSearchAgent provide transparent, step-by-step reasoning with configurable iteration limits.

  • Async Runtime: Event-driven architectures using AgentRuntime and tool fibers prevent I/O blocking when calling latency-prone external services.

  • Multi-Agent Systems: Staged orchestration patterns route tasks to specialized sub-agents (PhoneAgent, ComputerAgent) for robust error isolation and parallel processing.

  • Self-Evolution: Execution traces fuel knowledge-distillation pipelines that automatically improve agent performance through fine-tuning.

  • Code Interpretation: Sandboxed code execution extends agent capabilities while containing safety risks through deterministic containers.

  • Observability: Structured telemetry via api_turns enables rigorous evaluation of cost, latency, and correctness in production environments.

Frequently Asked Questions

What differentiates ReAct from async agent architectures?

ReAct implementations use synchronous loops where the agent blocks waiting for each tool result before proceeding to the next reasoning step, as seen in WebSearchAgent.search_and_answer. Async architectures employ event loops and thread pools to schedule tool calls as fibers, allowing the agent to process other tasks or orchestrate multiple concurrent operations while waiting for slow I/O. Choose ReAct for deterministic debugging and async for high-throughput, latency-tolerant workflows.

How do multi-agent systems prevent total system failure when one sub-agent fails?

The multi-agent pattern in chapter10/multi-role-transfer/orchestrator.py isolates sub-agents into independent execution contexts with separate failure domains. The orchestrator monitors each agent's AgentStatus and can retry, substitute, or bypass failed sub-agents while maintaining the overall workflow. This design ensures that a failure in PhoneAgent does not collapse a session requiring both phone and computer operations.

Can self-evolving agents modify their own source code, or only update LLM weights?

According to the implementation in chapter8/self_evolving_tools/agent.py, the self-evolution pipeline primarily updates prompt templates and triggers fine-tuning jobs on the LLM weights using distilled knowledge from execution traces. While the architecture supports learning signals that could theoretically drive code generation, the repository's current distill_knowledge method focuses on model behavior updates rather than self-modifying source code.

What safety mechanisms prevent coding agents from executing malicious code?

The CodingAgent in chapter5/coding-agent/agents.py executes generated code within deterministic containers that isolate the host environment. The system captures all stdout and exceptions, returning them as observations rather than allowing uncaught errors to crash the agent. Additionally, timeout limits and restricted environment variables prevent infinite loops and unauthorized system access, ensuring the LLM cannot accidentally or intentionally damage the runtime environment.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →