TechByteByByte

Single-Agent Architectures

Level 6 begins here: assembling everything from Modules 1-12 into complete, recognizable architectural patterns, each suited to different real task requirements.

#AI Agents#AI#Architecture#Level 6

Begin with the problem

One agent can often solve a task with fewer moving parts than a team of agents. Architecture begins with the simplest loop that meets the measured need.

task uncertainty + tools + risk → choose the smallest suitable single-agent pattern

What you will learn

  • Compare direct tool use, router, planner, ReAct, reflection, and hybrid single-agent designs.
  • Match architecture complexity to task uncertainty and risk.
  • See that these patterns can be combined rather than treated as competing products.
  • Start with the smallest architecture that meets the requirement.

Current real-system grounding: OpenAI’s official agent quickstart includes tools and handoffs, while Google’s Agents overview lists current agent frameworks and managed agents.

These official links document available product features. They do not reveal every provider’s private implementation, hidden reasoning, default setting, or internal limit.

1. The problem this module solves

Modules 1-12 covered individual pieces — the loop, tools, planning, ReAct, reflection, memory, state. This module assembles them into complete, recognizable architectural patterns — helping you recognize which combination of pieces a specific task actually calls for, rather than always reaching for every capability at once.


2. Basic Single Agent — The Minimal Version

flowchart LR
    G[Goal] --> LLM[LLM] --> A[Answer]
appropriate when: the task is a SINGLE reasoning step, no
tools, no loop needed at all -- this is actually Module 1, Section
5's "LLM application," included here for completeness of the
spectrum.

3. Tool-Using Agent — Adds Environment Interaction

flowchart TD
    G[Goal] --> Loop{Agent Loop<br/>Module 4}
    Loop --> R[Reason] --> T[Tool Call<br/>Module 6-7]
    T --> O[Observation] --> Loop
    Loop --> Done[Final Answer]
appropriate when: the task needs to OBSERVE or ACT on real
systems, and the number of needed steps is unknown in
advance (Module 1's core justification for the loop).

4. Planning Agent — Adds Up-Front Structure

flowchart TD
    G[Goal] --> D[Decompose<br/>Module 8]
    D --> E[Execute Each Subtask<br/>via Tool-Using Loop]
    E --> Ch{Discovery changes<br/>the plan?}
    Ch -->|Yes| Rev[Revise Plan]
    Ch -->|No| Next{More subtasks?}
    Rev --> Next
    Next -->|Yes| E
    Next -->|No| Done[Final Answer]
appropriate when: the task has MULTIPLE real subtasks
with real DEPENDENCIES between them (Module 8) -- purely reactive
step-by-step reasoning would risk inefficient or
inconsistent ordering.

5. ReAct Agent — Records an Action Rationale

flowchart TD
    O[Observation] --> Th[Thought<br/>Module 9]
    Th --> A[Action]
    A --> NO[New Observation]
    NO --> Th
    Th --> Done[Finish]
Appropriate when: DEBUGGABILITY and ACTION-TRACE TRANSPARENCY matter,
or when a structured action rationale may help the agent divide a
complex task into manageable decisions. As Module 9 explains, that
written rationale is generated text, not the model's hidden internal
reasoning, and its value should be tested with evaluations.

6. Reflection Agent — Adds Self-Verification

flowchart TD
    Gen[Generate Output] --> Ev[Evaluate<br/>Module 10]
    Ev --> Acc{Acceptable?}
    Acc -->|No| Rev[Revise] --> Gen
    Acc -->|Yes| Done[Finish]
appropriate when: output QUALITY matters enough to
justify the extra generate-evaluate-revise cost (Module 10) -- e.g.,
customer-facing content, generated code.

7. Agent With Memory — Adds Cross-Session Continuity

flowchart TD
    LTM[(Long-Term Memory<br/>Module 11)] -->|retrieve relevant| C[Assembled Context]
    S[Current State] --> C
    C --> LLM[LLM] --> A[Action]
    A -->|selectively persist| LTM
appropriate when: the SAME user or context recurs across
MULTIPLE sessions, and real continuity (Module 11's "remembers
this customer prefers email") measurably improves the experience.

8. Agent With RAG — Adds Knowledge Retrieval

flowchart TD
    G[Goal] --> D{Retrieval<br/>Needed?}
    D -->|Yes| RAG[Retrieve from<br/>Knowledge Base<br/>your RAG course]
    D -->|No| LLM
    RAG --> LLM[LLM Reasoning]
    LLM --> A[Action / Answer]
appropriate when: the task needs INFORMATION beyond the
model's training knowledge -- directly connecting to your RAG
course's entire justification. Module 14 covers this pattern's
AGENTIC extension in full depth.

9. A Real Developer Example — Matching Architecture to Task

TechCorp TaskBest-Fit ArchitectureWhy
“What’s our standard return policy?”Basic single agent (or Agent + RAG if policy is in a document)One-shot, no real multi-step reasoning needed
“Check this order’s shipping status.”Tool-using agentNeeds a real, live lookup; simple, single-purpose
“Plan next quarter’s product launch checklist.”Planning agentmulti-part with real dependencies
“Draft a customer apology email.”Reflection agentOutput quality benefits from self-check
“Help this returning customer, who we’ve spoken with before.”Agent with memoryreal continuity across sessions matters
“Answer questions about our 500-page compliance manual.”Agent with RAGneeds retrieval from a large knowledge base

10. A Simple Agentic AI Connection

Real production agents combine several of these patterns simultaneously — a customer support agent might use tools, memory, AND RAG together. This module’s patterns are composable building blocks, not mutually exclusive categories — Module 23’s production architecture shows exactly this kind of combination.


11. How Is This Used in AI?

🤖 How Is This Used in AI?

Recognizing which architectural pattern a task calls for — rather than defaulting to the most complex combination available — is a core, practical skill in agent system design, directly affecting cost, latency, and reliability, exactly Module 1’s original evolution-story principle applied at the architecture-selection level.


12. Real-World Applications

  • Scoping a new agent feature: identifying which capabilities (tools, planning, reflection, memory, RAG) the actual task requires
  • System design interviews, where correctly matching architecture to requirements is a common evaluation criterion
  • Incrementally building up an agent’s capability, adding patterns only as justified by real task needs

13. Common Mistakes

Incorrect idea: Defaulting to the most feature-complete architecture regardless of task needs.

Why it is incorrect: As shown directly in Section 9, a simple task doesn’t need memory, RAG, planning, and reflection all at once.

Incorrect idea: Treating these patterns as mutually exclusive rather than composable.

Why it is incorrect: As shown directly in Section 10, real production agents combine multiple patterns together.

Incorrect idea: Adding reflection or planning to a simple, single-step task.

Why it is incorrect: As shown directly throughout Sections 2-8, each pattern exists to solve a SPECIFIC real need — adding it without that need is pure overhead.


14. Limitations

  • These patterns are useful teaching categories, but real systems often blend them in ways that don’t map perfectly cleanly onto one single label
  • Choosing the right architecture requires understanding the task’s actual requirements — a skill that develops through this module’s practice, but has no purely mechanical formula

15. Quick Reference

flowchart TD
    Q{What does the<br/>task need?}
    Q -->|Nothing beyond one answer| Basic[Basic Single Agent]
    Q -->|Real-world observation/action| Tool[Tool-Using Agent]
    Q -->|Multi-part, dependent subtasks| Plan[Planning Agent]
    Q -->|Visible, debuggable reasoning| React[ReAct Agent]
    Q -->|Output quality verification| Refl[Reflection Agent]
    Q -->|Cross-session continuity| Mem[Agent with Memory]
    Q -->|Large external knowledge base| RAGA[Agent with RAG]

16. Code — Implementing an Architecture Recommendation Function

🎯 Target of this example: implement Section 9’s real developer example directly — a function mapping real task requirements onto this module’s architecture patterns, exactly demonstrating the decision process a real engineer applies when scoping a new agent feature.

Example 1 — Simple

from enum import Enum

class ArchitectureType(Enum):
    BASIC = "basic_single_agent"
    TOOL_USING = "tool_using_agent"
    PLANNING = "planning_agent"
    REACT = "react_agent"
    REFLECTION = "reflection_agent"
    MEMORY = "agent_with_memory"
    RAG = "agent_with_rag"

def recommend_architecture(needs_tools: bool, needs_planning: bool, needs_explicit_reasoning: bool,
                            needs_self_evaluation: bool, needs_persistent_memory: bool,
                            needs_knowledge_retrieval: bool) -> ArchitectureType:
    """A decision function mapping real task requirements onto the
    architecture patterns from Sections 2-8, exactly Section 9's
    real developer example made into reusable logic."""
    if needs_knowledge_retrieval:
        return ArchitectureType.RAG
    if needs_persistent_memory:
        return ArchitectureType.MEMORY
    if needs_self_evaluation:
        return ArchitectureType.REFLECTION
    if needs_explicit_reasoning:
        return ArchitectureType.REACT
    if needs_planning:
        return ArchitectureType.PLANNING
    if needs_tools:
        return ArchitectureType.TOOL_USING
    return ArchitectureType.BASIC

scenarios = [
    ("Simple Q&A, no tools", dict(needs_tools=False, needs_planning=False, needs_explicit_reasoning=False,
                                    needs_self_evaluation=False, needs_persistent_memory=False, needs_knowledge_retrieval=False)),
    ("Multi-step trip planner", dict(needs_tools=True, needs_planning=True, needs_explicit_reasoning=False,
                                       needs_self_evaluation=False, needs_persistent_memory=False, needs_knowledge_retrieval=False)),
    ("Enterprise knowledge assistant", dict(needs_tools=True, needs_planning=False, needs_explicit_reasoning=False,
                                              needs_self_evaluation=False, needs_persistent_memory=False, needs_knowledge_retrieval=True)),
]

for name, reqs in scenarios:
    arch = recommend_architecture(**reqs)
    print(f"{name}: {arch.value}")

Expected Output:

Simple Q&A, no tools: basic_single_agent
Multi-step trip planner: planning_agent
Enterprise knowledge assistant: agent_with_rag

What we conclude from this example: each scenario correctly maps to its appropriate architecture based purely on its stated requirements — exactly Section 9’s table, made into working, repeatable decision logic.

Example 2 — Intermediate

from dataclasses import dataclass, field
from enum import Enum

class ArchitectureType(Enum):
    BASIC = "basic_single_agent"
    TOOL_USING = "tool_using_agent"
    PLANNING = "planning_agent"

@dataclass
class ArchitectureComponents:
    """Directly implements Section 10's composability claim -- a
    REAL agent's architecture is a real COMBINATION of components,
    not a single mutually-exclusive label."""
    has_loop: bool = False
    has_tools: bool = False
    has_planning: bool = False
    has_reflection: bool = False
    has_memory: bool = False
    has_rag: bool = False

    def describe(self) -> str:
        active = [name for name, value in [
            ("loop", self.has_loop), ("tools", self.has_tools), ("planning", self.has_planning),
            ("reflection", self.has_reflection), ("memory", self.has_memory), ("rag", self.has_rag),
        ] if value]
        return " + ".join(active) if active else "basic (no additional components)"

# A real production customer support agent -- combines SEVERAL
# patterns simultaneously, exactly Section 10's point.
support_agent = ArchitectureComponents(
    has_loop=True, has_tools=True, has_memory=True, has_rag=True,
)
simple_agent = ArchitectureComponents()

print(f"Support agent architecture: {support_agent.describe()}")
print(f"Simple agent architecture: {simple_agent.describe()}")

Expected Output:

Support agent architecture: loop + tools + memory + rag
Simple agent architecture: basic (no additional components)

What we conclude from this example: the support agent’s architecture is correctly described as a real COMBINATION of four components working together, rather than forced into a single label like “tool-using agent” OR “agent with memory” — exactly Section 10’s claim that real production agents compose these patterns rather than choosing just one.

Example 3 — Production Grade

from dataclasses import dataclass, field
from enum import Enum

class Component(Enum):
    LOOP = "agent_loop"
    TOOLS = "tools"
    PLANNING = "planning"
    REFLECTION = "reflection"
    MEMORY = "memory"
    RAG = "rag"

@dataclass
class TaskRequirements:
    description: str
    needs_realtime_data: bool = False
    has_multipart_dependencies: bool = False
    output_quality_critical: bool = False
    spans_multiple_sessions: bool = False
    needs_large_knowledge_base: bool = False

class ArchitectureDesigner:
    """A production-style designer implementing Section 9's FULL
    decision process as a reusable, auditable tool --
    returning BOTH the recommended components AND the rationale for
    each, directly supporting the scoping conversations Section 12
    describes."""

    def design(self, requirements: TaskRequirements) -> dict:
        components = []
        rationale = []

        if requirements.needs_realtime_data:
            components.extend([Component.LOOP, Component.TOOLS])
            rationale.append("Real-time data needed -> loop + tools (Module 4, 6)")
        if requirements.has_multipart_dependencies:
            components.append(Component.PLANNING)
            rationale.append("Multi-part dependencies -> planning (Module 8)")
        if requirements.output_quality_critical:
            components.append(Component.REFLECTION)
            rationale.append("Output quality critical -> reflection (Module 10)")
        if requirements.spans_multiple_sessions:
            components.append(Component.MEMORY)
            rationale.append("Spans multiple sessions -> memory (Module 11)")
        if requirements.needs_large_knowledge_base:
            components.append(Component.RAG)
            rationale.append("Large knowledge base -> RAG (your RAG course)")

        if not components:
            rationale.append("No real multi-step or tool need identified -> basic single agent")

        return {"components": components, "rationale": rationale}

designer = ArchitectureDesigner()

# TechCorp's returning-customer support scenario -- needs
# several components together
requirements = TaskRequirements(
    description="Help a returning customer with a shipping issue, referencing our policy manual",
    needs_realtime_data=True, spans_multiple_sessions=True, needs_large_knowledge_base=True,
)

design = designer.design(requirements)
print(f"Task: {requirements.description}\n")
print("Recommended components:")
for component in design["components"]:
    print(f"  - {component.value}")
print("\nRationale:")
for r in design["rationale"]:
    print(f"  - {r}")

Expected Output:

Task: Help a returning customer with a shipping issue, referencing
our policy manual

Recommended components:
  - agent_loop
  - tools
  - memory
  - rag

Rationale:
  - Real-time data needed -> loop + tools (Module 4, 6)
  - Spans multiple sessions -> memory (Module 11)
  - Large knowledge base -> RAG (your RAG course)

What we conclude from this example: the designer produces BOTH a concrete component list AND an explicit rationale explaining WHY each component was recommended — exactly the kind of useful, auditable output a real architecture-scoping conversation needs, directly connecting every recommendation back to the specific module that covers it.


17. Interview Questions

Q: Why shouldn’t a team default to building every agent with the most feature-complete architecture (tools, planning, reflection, memory, and RAG all together)?

Ans: Each architectural component exists to solve a specific, real need — planning is worth its overhead only when a task has real, multi-part dependencies; reflection is worth its extra generate- evaluate-revise cost only when output quality benefits from self-verification; memory and RAG add real infrastructure only worth building when cross-session continuity or large-knowledge-base retrieval are required. Defaulting to every component regardless of actual task needs adds unnecessary complexity, cost, and latency without a corresponding real benefit.

Q: Explain why these architectural patterns should be understood as composable building blocks rather than mutually exclusive categories.

Ans: Real production agents very often need several capabilities simultaneously — a customer support agent might need tools for real-time lookups, memory for cross-session continuity with returning customers, and RAG for referencing a large knowledge base, all working together. Treating “tool-using agent” and “agent with memory” as mutually exclusive labels would force an artificial choice between capabilities a real system needs combined, rather than recognizing that these patterns compose naturally.

Q: For a task requiring an agent to draft customer-facing emails and verify they meet company tone guidelines before sending, which architectural components would you recommend, and why?

Ans: This task benefits from the reflection pattern — generating a draft, then explicitly evaluating it against the tone guidelines as real, checkable requirements, and revising if it doesn’t meet them, directly connecting to Module 10’s generate- evaluate-revise loop. If checking tone guidelines requires looking up company style documentation, RAG might also be warranted. Planning would likely be unnecessary overhead here, since drafting a single email doesn’t have the kind of multi-part, dependent subtask structure that planning is designed to address.

Q: How would you approach scoping a new agent feature’s architecture at the start of a project?

Ans: I’d start by identifying the task’s real requirements rather than defaulting to a specific architecture — does it need real-time data (pointing toward tools and the agent loop), does it have multi-part dependencies (pointing toward planning), does output quality benefit from self-verification (reflection), does it span multiple sessions with the same user (memory), and does it need information beyond the model’s training knowledge (RAG). Mapping each real requirement to its corresponding architectural component, and only including components justified by real task needs, avoids both under-building (missing a capability the task actually requires) and over-building (adding unnecessary complexity).


18. What You Should Remember

  • This module’s seven patterns — basic, tool-using, planning, ReAct, reflection, memory, and RAG — each solve a specific, real task requirement, not a universal upgrade path.
  • Architecture should be chosen based on real task requirements, not defaulted to the most feature-complete option — verified directly through a working recommendation function correctly matching simple, planning-heavy, and knowledge-heavy scenarios to their appropriate patterns.
  • Real production agents compose multiple patterns together — verified directly through a designer that recommends and justifies multiple components simultaneously for a multi-need task.

19. Quick Practice

For an agent idea from your own domain of interest, walk through Section 9’s decision process explicitly — which of this module’s seven patterns does it need, and which would be unnecessary overhead?

20. Next Step

Next: Module 14 — Agentic RAG — connecting directly to your RAG course: how a real agent decides whether retrieval is needed at all, evaluates retrieval quality, and searches again when the first attempt falls short.

Author
TechByteByByte Editorial Team
Reviewed by
TechByteByByte Admin
Published
Last reviewed