# From Factory Pattern to ReAct:

> Source: <https://pub.towardsai.net/from-factory-pattern-to-react-how-design-patterns-evolved-into-ai-architecture-43fd8923a8cb?source=rss----98111c9905da---4>
> Published: 2026-08-13 14:01:05+00:00

**From Object-Oriented to ML to Data Science to AI: How the Pattern Question Changed**

**In the early 2000s**, every serious engineer was learning the Gang of Four. Factory, Singleton, Decorator, Observer, Strategy, Command. Design patterns were not optional reading — they were the language of good software. They solved real problems: code reuse, extensibility, maintainability. Object-oriented systems were complex. Patterns made that complexity manageable.

**Then systems became distributed.**

New problems required new patterns. Pub-Sub for decoupling producers from consumers. CQRS for separating read and write concerns. Event Sourcing for immutable audit trails. Circuit Breaker for fault tolerance. Saga for distributed transactions across services. In Azure this meant Service Bus, Event Grid, Cosmos DB change feed, APIM retry policies. The pattern vocabulary moved from class design to system design. The engineers who mastered these patterns built distributed systems that held together under load. The ones who did not built systems that fell apart in production.

**In 2015**, I was building predictive models for a retail chain. The architecture question was simple: which algorithm? Random forest or gradient boosting for churn prediction. Logistic regression or SVM for product classification. The model was the system. The pattern was the algorithm.

**By 2018**, the vocabulary had shifted. Data Science had grown up. The question was no longer just which algorithm — it was how to build the pipeline. Feature engineering, training, evaluation, drift monitoring, retraining triggers. Azure ML Pipelines, MLflow for experiment tracking, feature stores for consistency between training and serving. The model was still at the centre. But the system around it had become an architecture.

**Then foundation models arrived and changed the question entirely.**

A single GPT model could classify, summarise, extract, and reason in natural language — without feature engineering, without retraining for each task. The algorithm decision almost disappeared. The new question was: how do you instruct the model? Prompt engineering became the core skill. RAG became the data integration pattern. Fine-tuning became the domain adaptation tool.

But there was a ceiling. A single prompt-response call could answer a question. It could not run a multi-step investigation. It could not coordinate across specialist domains. It could not reason about what to check next based on what it just found.

**That ceiling is where agentic AI began. Now systems are reasoning.**

And again, new problems require new patterns. When a system needs to think iteratively through a problem using tools — ReAct. When it needs to plan all steps before acting — Plan-and-Execute. When output quality needs self-verification — Reflection. When a problem spans genuinely independent domains — Orchestrator-Worker. When reliability demands multiple independent perspectives — Ensemble. When a strategic decision needs stress-testing through argument — Debate.

The instinct is the same. The layer is different.

Factory solved object creation complexity. Pub-Sub solved event decoupling across distributed services. ReAct solves iterative reasoning under uncertainty. Every generation of systems brought a new class of problems. Every generation of architects built a new vocabulary of patterns to solve them. AI patterns are the current generation of that vocabulary.

The engineers who mastered Gang of Four built better object-oriented systems. The engineers who mastered cloud patterns built better distributed systems. The engineers who master AI patterns will build better reasoning systems.

And just as dependency injection is a technique inside object-oriented patterns — not a pattern itself — RAG is a technique inside AI patterns, not a pattern itself. The technique makes the pattern effective. The pattern shapes the architecture. I spent months confusing these two layers. That confusion showed up in every design decision I made.

The rest of this article maps the full pattern vocabulary for AI systems — from how a single agent reasons to how multiple agents coordinate — with the same clarity that Gang of Four brought to object-oriented design.

**PATTERN *** How the AI reasons or coordinates. *ReAct, CoT, Orchestrator-Worker, Pipeline, Debate…

**FRAMEWORK *** The library that implements the pattern. *Azure AI Foundry SDK, Semantic Kernel, LangChain, AutoGen

**TECHNIQUE *** How you ground the model inside the pattern. *Prompt Engineering, RAG, Fine-Tuning

Choose pattern first. Then framework. Then technique. Choosing a technique before a pattern is the most common mistake I see — teams decide to use RAG before they have decided how the agent will reason. The pattern decision shapes everything else.

As companies incorporate generative AI systems into their processes, the jargon used in the field can no longer keep up with the growing complexity of these systems. Conversations in the sector seem to be drowning in technical expressions — prompt engineering is defined in the same way as data handling mechanisms (RAG), reasoning cycles (Agentic Patterns), and programming applications (LangChain, Semantic Kernel, and AutoGen).

The confusion in the classifications is not just an academic issue — this problem has practical significance as well. Engineering teams tend to create unnecessarily complicated structures for retrieving information, as they try to solve simple tasks with the help of sophisticated multi-agent systems or to develop complex automatic systems using basic prompts and fixed youtube scripts.

If one wants to create successful AI software solutions, the issue with the definitions needs to be addressed first. The article offers a four-partied classification of modern AI architectures in which all the components are considered in terms of their actions and place within the system.

To analyze AI systems, we create four specific operational levels of AI programming.

**The Core Taxonomy Matrix**

To systematically evaluate AI architectures, we partition the AI engineering stack into four distinct operational layers:

A reasoning pattern describes how one agent structures its own thinking — the internal logic loop it follows to go from input to output. These patterns are independent of any framework. The framework (LangChain, Semantic Kernel, LangGraph) is the implementation layer that operationalises whichever pattern you choose.

The pattern is the reasoning logic — how the agent interleaves thinking and acting. The framework is the implementation layer. LangChain’s AgentExecutor implements a ReAct-style loop for you; you can also implement it yourself directly against a model’s function-calling API without any framework at all.

Chain of Thought sits at the boundary between a reasoning pattern and a prompting technique. It is activated purely through the prompt — you tell the model to think step by step before answering, and it does. No tool loop, no multi-call architecture. Just structured internal reasoning before the final answer.

**Example **Use Case: margin impact calculation. A category manager asks: ‘If I give an extra 5% discount to all loyalty customers on electronics this weekend, what is the margin impact?’ A direct answer from the model is unreliable — the calculation has multiple steps. With CoT, the model reasons through it: number of eligible customers, average basket size in electronics, current margin percentage, incremental discount cost, offset from volume uplift estimate. The answer is more accurate because the model showed its working.

**The key nuance**: CoT is used inside other patterns. A ReAct agent that uses CoT in its reasoning prompt will produce better tool selections. A Plan-and-Execute planner that reasons step by step will produce better plans. CoT amplifies every other pattern it is combined with.

**Use CoT when **the answer requires multi-step reasoning, calculations, or logical inference. Always use it inside ReAct and Plan-and-Execute agents — it makes reasoning more reliable.

```
# CoT activated through prompt instruction# No special architecture -- just prompt structuresystem_prompt = '''You are a retail margin analyst.When given a pricing or promotion question, always:1. Identify the variables involved2. State your assumptions explicitly3. Work through the calculation step by step4. Show intermediate results before the final answer5. Flag any assumptions that could change the resultDo not jump to the final number. Show every step.'''# CoT inside a ReAct agent -- improves tool selection reasoningreact_system_prompt = '''You are a pricing response agent.Before calling any tool, think through:  - What information do I already have?  - What information do I still need?  - Which tool gives me exactly that information?  - What will I do with the result?Only then make the tool call.'''
```

Self-Consistency runs the same prompt multiple times and aggregates the results. You generate N independent answers from the same model, then take the majority answer or synthesise across answers. It is the simplest way to improve reliability without changing the model or the prompt structure.

**Example **Use Case: demand forecast confidence check. The system generates a 4-week demand forecast for a high-value SKU before a major promotion. Running the forecast once gives one number. Running it five times with different temperature settings and comparing the distribution of results gives you a confidence range — if all five forecasts cluster within 8%, the forecast is reliable. If they spread across 25%, flag for human review before committing the stock order.

**Use Self-Consistency when **reliability of output matters more than speed and cost, you need a confidence signal on the model’s answer, or the task is high-stakes and a single model call is not trustworthy enough.

ReAct is the most common single-agent action pattern. The agent loops: reason about the current state, decide on an action, call a tool, observe the result, reason again. This continues until the agent has enough information to answer. Each step depends on the result of the previous one.

**Example **Use Case: competitor price response. A competitor drops electronics prices by 12%. The ReAct agent checks which of our SKUs overlap, checks inventory (no point discounting out-of-stock items), retrieves margin floors, checks active promotions, and recommends a price action per SKU. The path through this problem depends on what the data shows.

**Enterprise Use Case: Alternative Supplier Evaluation**

```
Thought: Primary lead time is 35 days against a coverage gap of ~21 days. I need to check whether Supplier B can cover this. Let me query their current lead time and terms.Action: query_supplier_portal(supplier_id="B", fields=["lead_time","min_order_qty","price","promotion"])Observation: Lead time 18 days. Min order £8,000. Volume promotion active - 7% discount on orders over £12,000. Promotion expires in 48 hours.Thought: Supplier B closes the 17-day lead-time gap. The promotion adds value but the £12K minimum exceeds standard parameters. I should also check Supplier C as a fallback before committing.Action: query_supplier_portal(supplier_id="C", fields=["lead_time","min_order_qty"])Observation: Lead time 22 days. Min order £5,000. Does not close the 21-day gap.Thought: Supplier C does not meet the lead-time requirement. Supplier B is the only viable alternative. The £12K order to capture the promotion requires approval above standard threshold (£10K). Generate recommendation.
```

**Use ReAct when **steps are unpredictable, each tool result changes what to check next, and the agent must reason its way through the problem.

**How It Works — Step by Step**

The agent produces a complete plan before any action. Stage one: a planner reads the task and generates all steps. Stage two: an executor works through them. The plan is visible and inspectable before execution begins — which is the feature that makes it different from ReAct.

**Example **Use Case: end-of-season markdown planning. Every run follows the same structure: identify slow-moving SKUs, calculate weeks of supply, determine markdown depth by category rules, check competitor levels, generate a per-store plan, route for finance approval. Finance reviews the plan before a single price changes.

**Use Plan-and-Execute when **the task is complex but structured, you want human review before execution, or the task is long-horizon with many steps.

**How It Works — Step by Step**

The agent generates output, evaluates it against a rubric, identifies failures, and rewrites. This loops until quality threshold is met or iteration limit is reached. The evaluator can be the same model or a separate cheaper model.

**Example **Use Case: product description generation. We needed SEO-optimised descriptions for 200,000 SKUs. Plain prompt: 71% passed quality review. With Reflection: 94% passed — without a human reviewer in the loop.

**Use Reflection when **output quality matters more than speed and you have a clear rubric.

**How It Works — Step by Step**

Multi-agent means multiple agents working together. The decision to go multi-agent is not about complexity — it is about whether the problem genuinely requires coordination across independent agents.

*“Multi-agent topology answers: how do agents hand work to each other? Execution pattern answers: how does each individual agent think? A well-designed multi-agent system specifies both — the outer coordination pattern and the inner reasoning loop for each agent.”*

One orchestrator receives the task, breaks it into subtasks, routes each to a specialist worker, and synthesises results. The orchestrator does not do domain work. Workers do not orchestrate. Clear separation.

**Example **Use Case: personalised offer generation. Customer Agent gets purchase history. Pricing Agent calculates the best eligible offer. Inventory Agent checks stock at nearest store. Orchestrator synthesises into a personalised message. Three independent domains, one coordination layer.

**Use Orchestrator-Worker when **the problem spans genuinely independent domains with separate data, tools, and governance.

**How It Works — Step by Step**

**Orchestrator role**: manages context passing between workers (Worker 2 receives Worker 1’s output as input), handles Worker 2’s occasional tool timeouts (retry once, then human queue), and writes the final output to PagerDuty.

A router agent classifies the incoming request and routes it to the right specialist agent. There is no synthesis — the router’s only job is classification and handoff. The specialist handles the full task end-to-end once it receives the routed request.

This is different from Orchestrator-Worker. In Orchestrator-Worker, the orchestrator breaks one task into subtasks for multiple agents and synthesises the results. In Router/Classifier, the router sends the entire task to one agent and that agent handles everything.

**Example **Use Case: unified customer service entry point. Customers ask about: order tracking, product specifications, return requests, loyalty points, store stock availability. A single GPT-4o mini classifier reads the query and routes to: Order Agent, Product Knowledge Agent, Returns Agent, Loyalty Agent, or Store Inventory Agent. The classifier is simple and cheap. The specialists are tuned for their domain.

**Use Router/Classifier when **a single entry point receives diverse query types that each need a specialist handler. The router keeps the entry point simple and the specialists focused.

Agents are arranged in a chain. Agent 1 processes the input and passes output to Agent 2. Agent 2 processes and passes to Agent 3. There is no central orchestrator — the output of each agent is the input to the next. The pipeline is linear and ordered.

This is different from Orchestrator-Worker and Router/Classifier. In a pipeline, each agent adds to, transforms, or validates the work of the previous agent. The task passes through every stage in sequence.

**Example **Use Case: supplier invoice processing. A new invoice arrives. The Extract Agent pulls structured data from the PDF (supplier ID, line items, amounts, delivery dates). The Validate Agent checks the extracted data against the purchase order in the ERP system — quantities match? prices match? terms match? The Enrich Agent adds GL codes and cost centre mappings. The Approval Agent evaluates against auto-approval rules and either approves or flags for human review. Each agent does one job and passes a richer document to the next.

**Use Sequential/Pipeline when **the task has clear stages where each stage transforms the output of the previous one, stages are independent enough to be handled by specialists, and you want each stage to be independently testable and replaceable.

Multiple agents receive the same task simultaneously. They work independently and produce independent answers. The results are then aggregated — by majority vote, by a synthesis agent, or by a scoring function. No agent sees the other agents’ reasoning during the task.

The purpose is reliability and bias reduction. A single model has blind spots. Running three or five agents on the same problem and aggregating reduces the chance that one model’s bias or error drives the final answer.

**Example **Use Case: demand forecast for new product launch. When a new product enters the range with no sales history, demand forecasting is high-uncertainty. We run three specialist forecasting agents in parallel: Market Analogy Agent (finds the most similar historical product launch, bases forecast on that trajectory), Category Trend Agent (models demand from category growth rate and competitor product performance), Macro Signals Agent (incorporates search trend data, seasonal index, and promotional calendar). The three forecasts are synthesised by a fourth agent that weights them by historical accuracy per category.

**Use Parallel/Ensemble when **reliability matters more than speed and cost, you have multiple valid approaches to the same problem, or the task is high-stakes and you want to surface uncertainty through disagreement between agents.

Orchestrators managing orchestrators. A top-level orchestrator delegates to sub-orchestrators, each of which manages its own workers. This mirrors real geographic or organisational hierarchy and handles scale that a single orchestrator cannot manage.

**Example **Use Case: national markdown planning across 500 stores. The top-level orchestrator delegates by region. Each regional sub-orchestrator manages store-level pricing agents for its stores. Different margin rules apply per region. Different competitive sets per region. The hierarchy maps directly to the business structure.

**Use Hierarchical when **more than 15–20 worker agents makes a single orchestrator unmanageable, or genuine organisational hierarchy with different rules per level exists.

**How It Works — Step by Step**

While design patterns define the *logic* of how agents think and interact, Frameworks and Execution Engines supply the concrete software infrastructure required to run those patterns in production.

A common pitfall in AI engineering is confusing the *pattern* with the *framework* (e.g., assuming “ReAct” requires “LangChain”). In reality, frameworks are simply SDKs that manage state persistence, asynchronous execution, tool orchestration, telemetry, and error handling.

Without a framework, implementing agentic patterns requires building substantial infrastructure boilerplate:

When evaluating execution engines, architects should analyze three major framework paradigms: **LangChain / LangGraph**, **Microsoft Semantic Kernel (SK)**, and **Microsoft AutoGen**.

**Core Philosophy & Architecture**

**Key Architectural Strengths**

**Implementation Pattern (LangGraph State Machine)**

``` python
from typing import Annotated, TypedDictfrom langgraph.graph import StateGraph, ENDfrom langgraph.graph.message import add_messages# 1. Define explicit State Schemaclass AgentState(TypedDict):    messages: Annotated[list, add_messages]    next_step: str# 2. Define Graph Nodes (Functions/Agents)def supervisor_node(state: AgentState):    # Evaluates state and determines routing    return {"next_step": "telemetry_worker"}def telemetry_worker_node(state: AgentState):    # Executes tool calls for telemetry    return {"messages": ["Pulled 500 error spikes from APM"]}# 3. Build Graph Topographyworkflow = StateGraph(AgentState)workflow.add_node("supervisor", supervisor_node)workflow.add_node("telemetry_worker", telemetry_worker_node)workflow.set_entry_point("supervisor")workflow.add_conditional_edges("supervisor", lambda state: state["next_step"])workflow.add_edge("telemetry_worker", END)app = workflow.compile()
```

**Core Philosophy & Architecture**

**Key Architectural Strengths**

**Implementation Pattern (Semantic Kernel C# Agent / Plugin)**

```
using Microsoft.SemanticKernel;using Microsoft.SemanticKernel.Agents;// 1. Define Native Enterprise Pluginpublic class TelemetryPlugin {    [KernelFunction, System.ComponentModel.Description("Fetches error metrics for a microservice")]    public async Task<string> GetErrorMetricsAsync(string serviceName)    {        // Native C# API call or DB query        return await HttpClient.GetStringAsync($"https://api.internal/metrics/{serviceName}");    }}// 2. Register Plugin with Kernelvar builder = Kernel.CreateBuilder();builder.AddAzureOpenAIChatCompletion("gpt-4o", "https://endpoint.openai.azure.com", "api-key");builder.Plugins.AddFromType<TelemetryPlugin>("Telemetry");Kernel kernel = builder.Build();// 3. Define Orchestration via Chat Completion AgentChatCompletionAgent agent = new(){    Name = "RCAAgent",    Instructions = "Investigate system anomalies using Telemetry tools.",    Kernel = kernel};
```

**Core Philosophy & Architecture**

**Key Architectural Strengths**

**Implementation Pattern (Conversational Agent Group)**

``` python
from autogen import AssistantAgent, UserProxyAgent# 1. Define Worker Agents with Code Execution Capabilitiesuser_proxy = UserProxyAgent(    name="Admin",    human_input_mode="NEVER",    code_execution_config={"work_dir": "workspace", "use_docker": True})engineer = AssistantAgent(    name="SoftwareEngineer",    llm_config={"config_list": [{"model": "gpt-4o"}]},    system_message="Write Python code to solve issues. Output code blocks for Admin to run.")# 2. Trigger Conversational Loopuser_proxy.initiate_chat(    engineer,    message="Fetch error logs from https://api.internal/logs and output a summary graph.")
```

While frameworks speed up initial development, they introduce significant abstractions, potential vendor lock-in, and dependency updates.

**Architects should consider building a Lightweight Custom Loop when:**

**Azure AI Foundry Agents SDK **Best for: ReAct, Reflection Production-grade. Built-in tracing and evaluation. Azure-native. My default for production single-agent work.

**Semantic Kernel **Best for: Plan-and-Execute, Orchestrator-Worker, Pipeline Strong planner abstractions. Plugin architecture maps well to worker agents. Enterprise-ready on Azure.

**AutoGen **Best for: Orchestrator-Worker, Debate, Hierarchical Microsoft multi-agent framework. Designed for agent-to-agent conversation. Strong for debate and ensemble patterns.

**LangChain **Best for: Any pattern (prototyping) Fast to prototype. Large community. Heavy abstraction makes production debugging harder. Build POC, then rebuild.

Framework selection rule: which pattern did you choose? Pick the framework with the strongest native implementation for that pattern. Do not pick a framework first and then fit the pattern to it.

I now open every AI architecture session with the same question: what is your pattern?

Not: are you using RAG? Not: which model? Not: which framework? The pattern question forces the right answer first — how does the AI reason or coordinate? Once that is clear, the framework and technique decisions follow logically.

The pattern map is now clear: six single-agent patterns covering the full range of how one agent can reason. Seven multi-agent patterns covering how agents can coordinate. Three techniques for grounding the model within whichever pattern you choose.

[From Factory Pattern to ReAct:
How Design Patterns Evolved
into AI Architecture](https://pub.towardsai.net/from-factory-pattern-to-react-how-design-patterns-evolved-into-ai-architecture-43fd8923a8cb) was originally published in [Towards AI](https://pub.towardsai.net) on Medium, where people are continuing the conversation by highlighting and responding to this story.
