Design Patterns for ML Systems: Registry, Serving, and Agentic Orchestration
Design Patterns for ML Systems: Registry, Serving, and Agentic Orchestration
7.1 The Model Registry Pattern
7.1.1 Definition and Motivation
Imagine you are running a hospital's prediction system for patient discharge risk. One morning the accuracy drops — did someone change the code? Did the dataset shift? Did a colleague swap the algorithm overnight? Without a single place that records exactly what produced each model, answering that question becomes a forensic investigation. The model registry pattern solves this by giving every trained model a permanent, auditable identity.
A model registry is a centralized repository that stores every artifact associated with a trained machine learning model — the model binary, the dataset used to train it, the algorithm, the hyperparameters, the evaluation metrics, and system-level performance data. The registry assigns a unique version to each entry and timestamps it so that any past configuration can be retrieved and compared.
The Three Degrees of Change. In a typical machine learning system, three things can change that each warrant a new version:
| Variable | What changes | Example |
|---|---|---|
| Code | Preprocessing logic, feature engineering, pipeline scripts | Switching from min-max scaling to z-score normalization |
| Dataset | New training examples, distribution shifts, different time windows | Adding six months of recent patient records |
| Algorithm | Model family or architecture | Replacing a decision tree with a random forest |
Any change to even one of these three variables produces a different model. The registry captures which combination of these three variables produced a given version and what the results were.
Worked Example — COVID-19 Discharge Prediction. A data scientist trains a random forest
classifier on a COVID-19 patient discharge dataset (covid_data.csv). The pipeline logs accuracy
(78%), precision, recall, and F1 score. This becomes version 5 in the registry, tagged "COVID discharge RF
model," with stage set to staging.
Three months later the team wants to know: "Was version 3 better than version 5 on recall?" Without a registry, answering this means digging through old notebooks, checking out historical code commits, and hoping someone saved the metrics CSV. With a registry, the answer is two clicks away.
7.1.2 Historical Lineage: From Code Versioning to ML Versioning
The registry pattern did not appear from thin air — it extends a lineage of version-control thinking that software engineering has been refining for decades.
The Generations of Version Control.
- First generation (1970s–1980s) — File-level versioning. Tools like SCCS (Source Code Control System) and RCS (Revision Control System) tracked changes to individual files. One file, one history.
- Second generation (1990s–2000s) — Centralized systems. CVS (Concurrent Versions System) and Subversion (SVN) introduced a central server that held the canonical history. Multiple developers could check out, edit, and commit — but the central server was a single point of failure.
- Third generation (today) — Distributed systems. Git moved the full history to every developer's machine. Branching, merging, and collaboration became local operations. Git is now the dominant tool.
- ML versioning — Extends this lineage further. Traditional version control handles code. ML systems must version code + data + models together because all three co-determine the final artifact. A Git commit alone is insufficient — the same code with different data produces a different model.
Common Pitfall. Teams that version only their code (via Git) but not their data or models often find themselves unable to reproduce a result from three months ago. "We ran the same script" is not the same as "we got the same model" — the training data may have drifted, a dependency may have updated, or a random seed may have changed. A model registry closes this gap.
7.1.3 What Problem Does the Registry Solve?
Pipeline Antipatterns the Registry Addresses.
| Antipattern | Without Registry | With Registry |
|---|---|---|
| Unknown lineage | "Which dataset trained the model in production?" — nobody knows | One-click lookup |
| Lost hyperparameters | Experiments documented in scattered notebooks | Stored per-version |
| Irreproducible results | "We got 82% accuracy last month but can't reproduce it" | Full artifact replay |
| Ambiguous deployment | "Which version is live right now?" | Explicit stage tracking (staging → production) |
A registry makes "which model is in production right now?" a one-click question rather than a forensic investigation.
The model registry pattern is the ML world's answer to version control. It tracks the three degrees of change (code, data, algorithm) for every trained model, assigns version numbers, and makes any past configuration retrievable. This is foundational — every subsequent section in this lecture (MLflow, feature stores, serving paradigms) builds on the idea that models must be versioned and traceable.
7.2 MLflow Registry in Practice
7.2.1 Stage Management: Staging and Production
Think of the model registry like a product release pipeline. Software goes from development → QA → production. ML models follow a similar journey, but instead of testing features, you are validating prediction quality, fairness, and resource usage before exposing the model to real users.
MLflow is an open-source platform that implements the model registry pattern. It provides a web interface running on a configurable port (default: 5000) through which teams can browse, compare, and promote models. The key organizational concept is stage management — models move through lifecycle stages that control which version is exposed to production traffic.
MLflow Lifecycle Stages.
| Stage | Purpose | Typical state |
|---|---|---|
| None | Newly logged; not yet registered | Artifact sitting in experiment tracking |
| Staging | Pre-production testing and validation | Being evaluated against the current production model |
| Production | Live serving | Actively serving predictions to end users |
| Archived | Retired | Replaced by a newer version but kept for audit |
Multiple versions can coexist in each stage. A team can maintain version 4 in staging while version 5 is being validated, and version 3 in production. Promoting from staging to production is a deliberate, human-initiated action — not automatic.
Worked Example — COVID-19 Discharge Prediction in MLflow. A concrete demonstration used a
COVID-19 patient discharge dataset (covid_data.csv) with a random forest classifier. The pipeline
produced standard classification metrics — accuracy (78%), precision, recall, and F1 score — and logged them
alongside the model. When the run completed, the model appeared in the MLflow registry as "COVID discharge RF
model," version 5, with stage set to staging.
From the registry UI, the user can:
- Click to view all registered versions of the model
- See which stage each version occupies (staging, production, archived)
- Compare versions side-by-side — metrics, parameters, and system usage
- Promote a staging version to production when satisfied with validation results
7.2.2 What Gets Stored in a Registry Entry?
When a model is registered, MLflow captures a rich set of metadata. This is what turns a loose collection of experiments into a queryable, auditable inventory.
Contents of a Model Registry Entry.
| Category | What is stored | Example |
|---|---|---|
| Dataset | Which data file and what preprocessing was applied | covid_data.csv, normalized, train/test split 80/20 |
| Algorithm & hyperparameters | Model family and configured settings | Random forest, n_estimators=100, max_depth=12, criterion=gini
|
| Learned model | The trained artifact — weights, tree structures, coefficients | Serialized .pkl or .joblib file |
| Model-level metrics | Prediction quality scores | Accuracy 78%, precision 0.81, recall 0.74, F1 0.77 |
| System-level metrics | Resource consumption during training | CPU usage 80%, memory 4.2 GB, training time 47 seconds |
| Timestamp & version | When created, what distinguishes it from prior versions | Version 5, created 2024-11-15 14:32 UTC |
Q: Are the learned weights also stored as part of the MLflow registry?
A: Yes, they are definitely stored. There are two categories of parameters: model
parameters (hyperparameters like n_estimators or max_depth that you configure
before training) and system parameters (CPU usage, memory consumption on the node where training
ran). Both are captured alongside the version.
Q: What does a version capture in the registry beyond just a version number?
A: A version encapsulates the complete fingerprint of a training run — dataset, algorithm, model, and results. If you change the code, the data, or the algorithm, a new version is created. Each version is timestamped and carries its full lineage, so you can trace back exactly what combination of factors produced it.
Common Pitfall — Hyperparameters vs. Learned Parameters. Beginners often confuse
hyperparameters (settings chosen before training, like n_estimators=100) with
learned parameters (the weights or structures the model discovers from data, like the split
thresholds in each decision tree). The registry stores both, but they serve different purposes.
Hyperparameters tell you how the model was configured. Learned parameters tell you what the model
learned. You need both to fully reproduce a model.
7.2.3 The Bigger Picture
MLflow is one concrete implementation of the model registry pattern. Its stage management workflow (staging → production → archived) enforces a disciplined promotion process. Every registry entry captures the full artifact bundle — data, algorithm, hyperparameters, learned weights, metrics, and system usage. This section demonstrates the pattern; MLflow will be revisited when we discuss deployment with Docker, containers, and Kubernetes.
MLflow will be revisited during deployment discussions where Docker, containers, and Kubernetes enter the picture. The registry demo here is only to show the pattern — the deployment mechanics come later.
7.3 The Registry Pattern Beyond MLflow
7.3.1 Tool-Agnostic Pattern and Alternative Implementations
The model registry is a design pattern, not a specific product. Just as the Observer pattern can be implemented in Java, Python, or C++, the registry pattern can be implemented by MLflow, DVC, W&B, SageMaker, or even a well-structured folder convention. The value lies in the pattern itself — versioned, queryable model-lineage tracking — regardless of which tool you choose.
While MLflow is a popular open-source implementation, the registry pattern is tool-agnostic. Several production-grade alternatives exist, each with a different emphasis:
Registry Implementations Compared.
| Tool | Primary emphasis | Key strength | Typical adoption context |
|---|---|---|---|
| MLflow | Open-source experiment tracking + registry | Vendor-neutral, broad community support | Teams wanting a self-hosted, flexible solution |
| DVC (Data Version Control) | Data and model versioning on top of Git | Treats datasets as versioned artifacts alongside code; uses Git as the storage backbone | Teams with strong Git workflows who want to extend versioning to data |
| Weights & Biases (W&B) | Experiment tracking with rich visualization | Sweeps (hyperparameter search), beautiful dashboards, collaborative experiment comparison | Research-heavy teams that need deep experiment analysis |
| Amazon SageMaker Model Registry | AWS-native model lifecycle management | Tight integration with SageMaker training jobs, endpoints, and CI/CD pipelines (CodePipeline) | Organizations already invested in the AWS ecosystem |
7.3.2 What All Registries Share
Regardless of the tool, every model registry provides a common set of capabilities. Understanding these shared features helps you evaluate any new tool that enters the market.
Common Registry Capabilities.
- Version tracking: Every model artifact gets a unique identifier and version number. You can retrieve "version 3 of the fraud detection model" at any time.
- Lineage recording: The registry links each version back to its inputs — which dataset, which commit of the training code, which algorithm configuration.
- Stage management: Models move through stages (development → staging → production → archived) with controlled promotion.
- Metadata search: "Show me all models with accuracy above 90% that were trained on data after June 2024."
- Comparison: Side-by-side diff of two versions on metrics, parameters, and system usage.
7.3.3 Antipatterns the Registry Addresses
Pitfalls in Teams Without a Registry.
| Antipattern | Symptom | Consequence |
|---|---|---|
| "Mystery model in prod" | No one knows which dataset or hyperparameters produced the live model | Cannot diagnose drift or performance degradation |
| "Notebook archaeology" | Metrics are scattered across Jupyter notebooks and Slack messages | Wasting hours reconstructing what happened |
| "Reproduce-what?" | Team cannot reproduce a result from three months ago | Audit failures, regulatory risk, broken trust |
| "Promotion by accident" | Model goes to production without deliberate validation | Undetected regression shipped to users |
A registry makes "which model is in production right now?" a one-click question rather than a forensic investigation.
7.3.4 Choosing a Registry
The choice of registry tool depends on your team's ecosystem, not on technical superiority. If you are on AWS, SageMaker Model Registry integrates natively. If your team lives in Git, DVC extends that workflow to data and models. If you need rich experiment visualization, W&B excels. If you want open-source flexibility, MLflow is the default choice. The pattern is what matters — pick the tool that fits your infrastructure.
Decision heuristic: Start by asking "Where does our team already store code and run experiments?" — then pick the registry that integrates most naturally with that environment. Adopting a registry that fights your existing workflow will result in the team bypassing it, which defeats the purpose entirely.
7.4 Separating Models from Business Logic
7.4.1 Models as Replaceable Components
Consider a mobile banking app that predicts loan eligibility. The app's business logic — how the UI collects inputs, how it validates them, how it formats the response — changes rarely. The prediction model behind it, however, might be retrained monthly as new borrower data arrives. If the model is tangled into the business logic, every model update requires redeploying the entire application. Separating them lets you swap the model by updating a version pointer, leaving the application untouched.
A registry encourages treating the model as a replaceable component. The business logic — API routing, input validation, response formatting — stays fixed. The model behind it can be swapped by updating a version pointer in the registry. This separation means an A/B test can point 5% of traffic at model version 6 while the remaining 95% sees version 5, with no code deployment required.
Separation of Concerns in ML Systems.
| Layer | Responsibility | Change frequency |
|---|---|---|
| Business logic | API routing, input validation, error handling, response formatting, authentication | Changes with product requirements (weeks–months) |
| Model serving | Loading the model, running inference, returning predictions | Changes with model retraining (days–weeks) |
| Model artifact | The trained weights, tree structures, or parameters | Changes with every training run |
Each layer has a different change cadence. Tying them together forces unnecessary coupling — every model retrain triggers a business logic deployment, even though nothing in the business logic changed.
7.4.2 Practical Benefits of Separation
What Separation Enables.
- A/B testing without code deploys: Route 5% of traffic to model v6, 95% to v5. Measure which performs better. Swap the routing rule when satisfied — no application rebuild.
- Canary deployments: Roll out a new model to 1% of users first. If metrics degrade, revert the pointer. The rollback takes seconds because it is a configuration change, not a code deployment.
- Multi-model serving: The same business logic can invoke different models for different customer segments — e.g., a fraud model tuned for retail customers and a separate one for corporate customers.
- Faster iteration loop: Data scientists can push a new model version to the registry and promote it to staging without touching the application code. Engineers can deploy business logic changes without worrying about breaking model integration.
7.4.3 The Stable Interface Contract
Critical Requirement — The Interface Contract. Separation only works if the model exposes a stable interface: a consistent input schema (feature vector) and output schema (prediction format). If model v6 suddenly requires three extra features that v5 did not, the business logic breaks. The registry should track not just the model but also its expected input/output contract so that interface changes are caught before deployment.
Think of this like an API contract in microservices. The model is a service with a defined request/response schema. As long as the contract holds, the consumer (business logic) does not care what happens inside.
Separating models from business logic creates natural modularity. The business logic layer, model serving layer, and model artifact each change at their own pace. The registry acts as the central switchboard — updating a version pointer redeploys the model without touching anything else. A stable input/output contract between layers is essential for this pattern to work.
7.4.4 Connection to Model Composition
This separation also enables model composition — combining multiple models into a pipeline. For example, a fraud detection system might compose a quick binary classifier (is this suspicious?) with a deeper anomaly model (how suspicious, and why?). Each model is a replaceable component behind its own interface. We will explore composition patterns (ensembles, sequential decomposition, cascade prediction) more deeply in later sections.
7.5 Feature Stores and Training-Serving Skew
7.5.1 Definition and Registry Connection
Suppose you train a credit-scoring model using a feature called
average_transaction_amount_last_30_days. During training, you compute this by scanning a
historical database — slow, thorough, no time pressure. At serving time, a user applies for a loan right
now and expects an answer in seconds. If the serving code computes this feature differently — say,
using only the last 7 days because the full 30-day window is too slow to query live — the model receives data
that does not match what it was trained on. This silent mismatch is training-serving skew, and it
degrades prediction quality in ways that are hard to detect.
A feature store is a centralized catalog of feature definitions and pre-computed feature values. It emerged from the same registry thinking that produced model registries — if we version models, we should also version the features that feed into them.
What a Feature Store Provides.
| Capability | Description | Why it matters |
|---|---|---|
| Feature definition registry | A single source of truth for how each feature is computed | Eliminates duplicate or inconsistent feature implementations across training and serving |
| Feature computation engine | Runs the same code to produce features for both training and serving | Guarantees training-serving consistency — the model always sees features computed identically |
| Feature caching / precomputation | Stores pre-computed feature vectors for fast retrieval at serving time | Reduces latency from seconds (on-the-fly computation) to milliseconds (cache lookup) |
| Feature versioning | Tracks how feature definitions evolve over time | Enables auditing: "When did we change the income feature from gross to net?" |
7.5.2 Training-Serving Skew in Depth
The Skew Problem. Training-serving skew occurs when the features used to train a model differ from the features available at serving time. This discrepancy can arise from:
- Different computation logic: Training uses a SQL query on the data warehouse; serving uses a different implementation.
- Different data windows: Training uses 30-day aggregates; serving uses 7-day aggregates due to latency constraints.
- Schema drift: A column is renamed or its type changes between training and serving.
- Missing features: A feature is available in the training dataset (offline) but not in the serving pipeline (online).
The insidious part: the model does not crash. It still produces predictions. But those predictions are silently degraded because the model is operating on data it was never trained on.
Concrete Skew Scenario. A ride-sharing platform (like Ola or Uber) trains a demand
prediction model using features like ride_requests_last_hour, surge_multiplier, and
driver_count_in_radius. During training, driver_count_in_radius is computed by a
slow geospatial query over the full driver database. At serving time, to keep latency under 100 ms, the
serving system uses a cached, approximate count updated every 5 minutes.
If the cache is stale — say, a concert just ended and 50 drivers moved into the area — the model receives an outdated driver count. It over-predicts demand (because it thinks fewer drivers are available), triggering unnecessary surge pricing. The model is not wrong in a vacuum; it is wrong because the feature it sees at serving time does not match what it learned during training.
7.5.3 Feature Store Tools and Architecture
Several production-grade feature store implementations exist:
| Tool | Deployment model | Key strength |
|---|---|---|
| Feast | Open-source, self-hosted or cloud-managed | Lightweight; integrates with existing data infrastructure |
| Tecton | Managed service | Low-latency online serving with built-in monitoring |
| AWS SageMaker Feature Store | AWS-managed | Native integration with SageMaker training and endpoints |
| Hopsworks | Open-source, self-hosted | Full ML platform with feature store at the center |
A typical feature store architecture has two tiers:
┌─────────────────────────────────────────┐
│ Feature Store │
│ ┌───────────────┐ ┌────────────────┐ │
│ │ Offline Store │ │ Online Store │ │
│ │ (data lake / │ │ (Redis / │ │
│ │ warehouse) │ │ DynamoDB) │ │
│ │ Batch queries │ │ Low-latency │ │
│ │ Training data │ │ Serving data │ │
│ └───────────────┘ └────────────────┘ │
│ Same feature code computes both │
└─────────────────────────────────────────┘
The offline store holds historical feature values for training (batch queries, no latency constraint). The online store holds the latest feature values for serving (millisecond retrieval). Critically, the same feature computation code populates both stores — this is how skew is prevented.
7.5.4 Connection to the Registry
A model registry that tracks both the model and the feature definitions used to train it helps
operators detect skew before it affects users. If version 5 was trained with
driver_count_in_radius computed via geospatial query, but the current serving pipeline uses a
cached approximation, the registry entry makes this mismatch visible. Without it, the discrepancy hides behind
the model's apparent "working" status.
A feature store is the feature-layer equivalent of a model registry: a centralized, versioned store of how features are defined, computed, and served. Its primary mission is preventing training-serving skew — the silent degradation that occurs when the features at serving time do not match those at training time. By using the same computation code for both offline (training) and online (serving) feature generation, the feature store guarantees consistency. The registry connects to this by recording which feature version produced each model version.
7.6 The Two Serving Paradigms
When a trained model is put into production to make predictions, the architecture of how those predictions are delivered falls into one of two categories. These are deployment patterns — they describe how the model serves predictions, not how it was built.
The choice between batch and real-time serving is one of the most consequential architectural decisions in an ML system. It affects infrastructure cost, error handling strategy, latency requirements, and even which models are viable. Getting this choice wrong does not just waste compute — it can lead to bad predictions reaching users with no buffer for correction.
7.6.1 Batch Prediction (Offline Inference)
In batch prediction (also called offline inference), data accumulates over a period — hours or a full day — and predictions are generated on a schedule. A typical setup works like this:
Batch Prediction Pipeline.
- Data accumulation: Data lands in a database or data store throughout the day (customer transactions, sensor readings, user behavior events).
- Scheduled trigger: At a fixed time (say, midnight), a cron job or scheduler fires.
- Model loading: The model is loaded into memory.
- Bulk inference: All accumulated records are run through the model.
- Result storage: Predictions are written to a database or data warehouse.
- Model unloading: The model is released from memory.
- Application consumption: Downstream applications read the stored predictions when needed.
Because the model is not always in memory, batch prediction has lower infrastructure cost. You pay for compute only during the scheduled run window.
Batch Prediction Use Cases.
- Customer segmentation: A telecom company gets thousands of new subscribers each day. Running a nightly segmentation job classifies them into prepaid versus postpaid usage patterns. The results inform marketing campaigns the next morning.
- Product recommendations: An e-commerce platform accumulates browsing and purchase data during the day. A nightly job generates personalized recommendations that appear on the homepage the following day.
- Risk reporting: A bank collects loan applications throughout the day. A scheduled job scores all applicants' credit risk overnight. The loan officers review the results the next morning.
A common implementation uses AWS SageMaker with an S3 bucket as the data store. The SageMaker cron job pulls data from S3, runs the model, and writes predictions back to S3 or DynamoDB. Applications then read the stored predictions.
Q: In my work, we check in code and an overnight regression suite runs automatically at a fixed time. Is that an example of batch prediction?
A: Yes, that is batch prediction. You are accumulating changes during the day and running them at a scheduled time when the results are not needed immediately. Batch simply means scheduled, not real-time.
Q: Are bank transactions like NEFT (which take a few hours) batch prediction?
A: The transaction itself is real-time — the transfer should be reflected immediately in both accounts. But the prediction aspect is separate. If someone transfers an unusually large amount (say ₹1 lakh when their normal pattern is ₹5,000), the system flags that anomaly. That anomaly detection is a prediction that runs alongside the real-time transaction. The transaction is real-time; the fraud or anomaly check is also real-time.
7.6.2 Real-Time Prediction (Online Inference)
In real-time prediction (also called online inference or on-demand inference), the model stays loaded in memory continuously — 24 hours a day, 7 days a week, 365 days a year. A user sends a request, the model processes it immediately, and the response returns within milliseconds or seconds. Behind the scenes, an API receives the request, invokes the model, and returns the prediction.
Real-Time Prediction Architecture.
User request
│
▼
┌──────────────┐
│ API Gateway │ ← Authentication, rate limiting, routing
└──────┬───────┘
│
▼
┌──────────────────┐
│ Model Service │ ← Model always in memory, ready to serve
│ (REST / gRPC) │
└──────┬───────────┘
│
▼
Prediction response
│
▼
┌──────────────────┐
│ Logging & │ ← Every request/response logged for monitoring
│ Monitoring │
└──────────────────┘
Key infrastructure components:
- API gateway: Handles authentication, rate limiting, and routing.
- Prediction service: The model stays loaded in memory, ready to respond instantly.
- Auto-scaling: Traffic can be 0 requests for hours, then 1 million per second. The infrastructure must scale dynamically.
- Logging and monitoring: Every request and response must be logged for debugging, auditing, and drift detection.
- Message queues: (Kafka, RabbitMQ, AWS SQS) Buffer requests during traffic spikes to prevent overload.
Real-time prediction is necessary when the response must be immediate:
- Fraud detection: A credit card transaction hits the bank's system. Within milliseconds, a model must decide whether to approve or block it. Waiting until the next batch run is not an option — the fraud would already have succeeded.
- Dynamic pricing: When you open Ola or Uber, a pricing model considers current demand, available drivers, weather, and time of day to compute a fare. The price changes in real time as conditions change.
- Spam filtering: Every incoming email must be classified before it reaches the inbox. A batch job that runs once a day would let spam through for up to 24 hours.
- Generative AI applications: ChatGPT, Gemini, and similar systems give responses as soon as you type a prompt. They run APIs behind the scenes that invoke models in real time.
The architecture for real-time serving typically involves an API gateway, a model service, and auto-scaling
infrastructure. The examples discussed in earlier lectures — the microservices pattern with an API gateway on
localhost:8001, the pipe-and-filter pattern — are all real-time serving architectures once deployed
to production.
Q: What is the architectural difference between batch and real-time serving?
A: Real-time serving requires an API gateway, a prediction service always in memory, auto-scaling to handle unpredictable traffic spikes (0 requests for hours, then 1 million per second), logging, and message queues. Batch serving can be simpler: a database, a couple of servers, and an ETL job that processes data on schedule. ETL — Extract, Transform, Load — is a classic example of batch processing. The key difference is that real-time architectures must handle anytime requests; batch architectures handle scheduled requests.
7.6.3 Model Misbehavior: Risk and Remediation
Q: Can the model misbehave differently in batch versus real-time? Will the output quality vary?
A: The possibility of model misbehavior exists in both paradigms, but the consequences and correction mechanisms differ. In real-time inference, you are "working on a razor knife" — any wrong output goes directly to the user, and pulling the model back is difficult. When Gemini 1.0 launched as a competitor to ChatGPT 3.5, it hallucinated heavily on real-time prompts, and the team had to pull it down for about two months. In batch inference, the predictions land in a database or data warehouse first. If something is wrong, you can review, correct the model, and re-run before the predictions ever reach an end user. Batch provides a correction buffer that real-time does not. The accuracy of the model itself does not change between batch and real-time — the same model produces the same output — but the remediation path when it fails is very different.
Q: Do real-time predictions tend to be less accurate than batch?
A: If you are using a popular, mature LLM from a major provider — GPT-5.4, Gemini 3.5, Claude — real-time inference today is very reliable, far more than two to three years ago. But if you are deploying a small language model (SLM) developed in your own organization, or a fine-tuned model that is not yet battle-tested at scale, then the batch approach gives you more room to catch and fix errors before they reach users. The difference is not inherent to batch versus real-time — it is about model maturity and the stakes of getting it wrong.
Q: In batch inference, if a job gets stuck or errors out partway through, you need data reconciliation, right?
A: Yes, reconciliation checks — daily or weekly — are necessary. But compared to real-time, the blast radius is smaller. In real-time, a bad prediction hurts the user immediately. In batch, the bad predictions sit in a database where you can inspect and fix them before they cause harm.
7.6.4 The "Razor Knife" Analogy and Gemini 1.0
The Razor Knife Risk. The professor's analogy is precise: real-time inference is like cutting with a razor knife. One slip — one hallucinated response, one misclassified fraud alert — goes directly to the user. There is no undo button for a prediction already delivered. The Gemini 1.0 incident illustrates this: Google launched its LLM to compete with ChatGPT 3.5, but the model hallucinated so heavily on real-time prompts that it had to be pulled offline for approximately two months. That is the cost of real-time failure at scale — reputational damage, lost trust, and a forced withdrawal.
Why Batch Absorbs Shocks Better. Consider the same Gemini 1.0 scenario, but hypothetically deployed as batch. The hallucinated outputs would land in a database. A QA team or automated monitoring system would flag them before they reached users. The model could be fixed and the batch re-run — users would never see the bad output. This is the fundamental risk asymmetry: batch gives you a correction buffer; real-time does not.
7.6.5 Side-by-Side Comparison
Batch vs. Real-Time — Summary Table.
| Dimension | Batch (Offline) | Real-Time (Online) |
|---|---|---|
| Latency | Minutes to hours (scheduled) | Milliseconds to seconds (on-demand) |
| Model in memory | Loaded during run, then unloaded | Always loaded (24/7) |
| Infrastructure cost | Lower (pay for run window) | Higher (always-on compute, auto-scaling) |
| Error remediation | Predictions sit in DB; can review and re-run | Errors reach users immediately |
| Traffic pattern | Scheduled, predictable | Unpredictable, bursty |
| Typical examples | Segmentation, recommendations, risk reports | Fraud detection, dynamic pricing, spam, GenAI |
| Data reconciliation | Daily/weekly checks sufficient | Real-time monitoring required |
| Complexity | Simpler (DB + ETL + scheduler) | Higher (API gateway + auto-scaling + logging + queues) |
7.6.6 Real-World: Both Paradigms Coexist
Twitter (X) — Same Platform, Two Strategies. Within a single application like Twitter, both paradigms coexist:
- Real-time: Detecting racial discrimination in tweets. A severely discriminatory tweet needs immediate action — possibly legal. The model must classify the tweet before it spreads.
- Batch: Sentiment analysis on tweets about a product. The business does not need minute-by-minute sentiment updates. A nightly batch job that processes the day's tweets and generates a sentiment report is sufficient.
Same data, same platform, two different serving strategies — chosen based on the urgency of the prediction and the cost of delay.
Common Pitfall. Teams sometimes default to real-time for everything because it feels more "advanced." Real-time infrastructure is significantly more complex and expensive. If the business can tolerate minutes or hours of latency, batch is almost always the better choice: simpler, cheaper, and more forgiving of errors.
Batch and real-time are the two fundamental serving paradigms. Batch is scheduled, cheaper, and provides a correction buffer. Real-time is on-demand, more expensive, and offers no safety net — errors go directly to users (the "razor knife"). The choice depends on prediction urgency, error tolerance, and infrastructure budget. Many production systems use both, applying each where it fits. The accuracy of the model itself does not change — what changes is the remediation path when it fails.
7.7 Architectural Implications
7.7.1 Infrastructure and Cost Trade-offs
The batch and real-time distinction is not just a technical choice — it drives infrastructure decisions, cost models, and operational complexity. Choosing one over the other has cascading effects on everything from hardware provisioning to team skill requirements.
The fundamental trade-off is simple to state but hard to optimize: real-time systems pay for continuous readiness; batch systems pay only when they run. A real-time model server must keep GPU or high-RAM instances running around the clock, even during periods of zero traffic. A batch system can spin up resources at midnight, run the job in 20 minutes, and shut everything down — paying only for those 20 minutes.
Cost Profile Comparison.
| Cost dimension | Batch | Real-Time |
|---|---|---|
| Compute cost driver | Data volume per run | Traffic volume × uptime |
| Compute availability | Load model, run job, release | Model in memory 24/7 |
| Idle cost | Near zero (no job = no cost) | Significant (must maintain warm instances) |
| Scaling strategy | Vertical (bigger machine for the run) | Horizontal (more instances for traffic spikes) |
| GPU utilization | High during run, zero otherwise | Must be provisioned for peak traffic |
| Failure blast radius | Predictions land in DB; reviewable | Errors reach users immediately |
For real-time systems, the cost scales with traffic. If traffic is unpredictable (0 requests for hours, then a burst of 1 million), you need auto-scaling — which adds infrastructure complexity (Kubernetes, load balancers, scaling policies) and can cause latency during scale-up.
For batch systems, the cost scales with data volume. If the nightly batch processes 10 million records, the compute cost is proportional to that volume. It is predictable, plannable, and easier to budget.
7.7.2 Operational Complexity
Real-time systems demand operational maturity. Running a model server 24/7 requires:
- Monitoring and alerting: If the model starts returning errors or degraded predictions, the team must be paged immediately — not tomorrow morning.
- Auto-scaling infrastructure: Kubernetes, ECS, or equivalent with properly configured scaling policies. Under-provisioning causes latency spikes; over-provisioning wastes money.
- Model versioning at runtime: Swapping from v5 to v6 without downtime requires blue-green or canary deployment strategies.
- Logging and auditing: Every request and response must be logged for compliance, debugging, and drift detection. At 1 million requests per second, log storage and analysis become significant costs.
- Security: The model endpoint is always exposed. API authentication, rate limiting, and DDoS protection are mandatory.
Batch systems need fewer operational capabilities: a scheduler, a data pipeline, and a monitoring dashboard. The operational surface area is smaller.
7.7.3 The Middle Ground: Hybrid and Cached Approaches
Not everything is strictly batch or real-time. Several hybrid patterns exist:
- Near-real-time (micro-batch): Process data in small batches every few minutes instead of once a day. Spark Streaming uses this approach — data arrives in micro-batches (e.g., every 30 seconds), giving near-real-time latency with batch-style simplicity.
- Cached predictions (pre-computed serving): Run a batch job that pre-computes predictions for all possible inputs and stores them in a fast cache (Redis, DynamoDB). The serving layer looks up the cached prediction — real-time latency with batch economics. Works when the input space is finite (e.g., all possible product recommendations for each user segment).
- Asynchronous real-time: Accept the request in real time, queue it for model inference, and return the result when ready. The user does not get an instant response, but the system does not need to block. Used in applications where a few seconds of latency is acceptable (e.g., document analysis, video processing).
7.7.4 Choosing the Right Paradigm: Decision Framework
When to choose each paradigm.
| Question | If Yes → | If No → |
|---|---|---|
| Does the prediction need to be available within seconds? | Real-time | Batch |
| Can bad predictions be caught before reaching users? | Batch (correction buffer) | Real-time (need robust monitoring) |
| Is traffic unpredictable and bursty? | Real-time (with auto-scaling) | Batch (scheduled, predictable) |
| Is infrastructure budget constrained? | Batch (lower idle cost) | Real-time (higher always-on cost) |
| Does the input space allow pre-computation? | Cached predictions (hybrid) | Either, based on latency needs |
Pitfall — Over-Engineering for Real-Time. A common mistake is to build a full real-time serving infrastructure (API gateway, auto-scaling, monitoring, logging) when a simple nightly batch job would suffice. Start with batch. Move to real-time only when the business requirement demands it. The added complexity of real-time is not just infrastructure — it requires a team with 24/7 operational capability.
7.7.5 Cost Modeling Example
Illustrative Cost Comparison.
Suppose a model processes 5 million records per day:
- Batch approach: One
ml.m5.4xlargeSageMaker instance runs for 2 hours at ~$0.92/hour = $1.84/day. The instance is shut down for the remaining 22 hours. - Real-time approach: Two
ml.m5.4xlargeinstances running 24/7 for redundancy = 2 × $0.92 × 24 = $44.16/day. This does not include auto-scaling headroom, logging, or monitoring costs.
The real-time approach costs roughly 24× more for the same workload. The premium pays for immediacy — the ability to serve predictions the moment they are requested. If the business does not need that immediacy, batch is the rational choice.
The batch vs. real-time choice drives infrastructure cost, operational complexity, and team requirements. Real-time costs scale with traffic; batch costs scale with data volume. Real-time demands 24/7 operational maturity (monitoring, auto-scaling, security). Batch is simpler and cheaper but adds latency. Hybrid approaches (micro-batch, cached predictions, asynchronous serving) offer middle grounds. The rule of thumb: start with batch; go real-time only when the business demands it.
7.8 When to Use Which?
7.8.1 Decision Heuristic
The Core Question: You have a trained model and a business need. Should you deploy it as a batch pipeline that runs on a schedule, or as a real-time service that responds in milliseconds? The answer depends on one thing — how soon does the consumer need the result?
The decision heuristic is straightforward. If the user or downstream system needs the prediction now — within seconds of the request — choose real-time. If the prediction can wait hours or until the next business cycle, batch is more economical. Some systems use both: real-time for latency-sensitive decisions, batch for analytics and reporting.
The Latency-Volume Trade-off — Batch serving amortises compute over many records at once, so the per-record cost is low. Real-time serving must keep a model in memory and handle every request individually, so per-record cost is higher but time-to-result is near zero. Choose based on which constraint is tighter: budget or latency.
Think of it like ordering food. Ordering from a meal-prep service that delivers a week's worth of meals on Sunday is batch — cheap per meal, but you wait until the scheduled delivery. Ordering from a food-delivery app is real-time — you get it in 30 minutes, but you pay a premium per order. The food quality (model accuracy) might be the same; what changes is when you get it and how much it costs.
Decision Walkthrough — E-Commerce Product Recommendations
| Factor | Batch | Real-time |
|---|---|---|
| When does the user see results? | Next morning, precomputed | Instantly, per click |
| Infrastructure | Database + nightly cron job | API gateway + always-on model |
| Cost profile | Low per prediction, high latency | High per prediction, low latency |
| Best for | Homepage "Top picks for you" | "Customers also bought…" on product page |
| Failure impact | Caught before users see it | Errors hit users immediately |
The homepage recommendations can be batch — users do not expect them to change every second. The "also bought" sidebar must be real-time — it reacts to what the user is viewing right now.
Common Pitfall: Choosing real-time "just in case" when batch would suffice. Real-time systems demand API gateways, auto-scaling, model versioning at the serving layer, and round-the-clock monitoring. If your stakeholders can tolerate a few hours of latency, batch saves significant operational complexity and cost.
7.8.2 Hybrid Architectures
Many production systems do not choose one or the other — they combine both paradigms.
Hybrid Serving Pattern — Use a batch job to precompute predictions for the majority of cases (cheap, auditable), and a real-time model to handle edge cases, new users, or requests where the batch prediction is stale. The real-time path acts as a fallback or override.
Hybrid in Action — Fraud Detection
- Batch path (nightly): Run the fraud-scoring model over all transactions from the past 24 hours. Flag suspicious accounts. Store results in a database.
- Real-time path (live): For every new transaction arriving during the day, score it in real-time against the same model. If the score exceeds a threshold, block the transaction instantly.
- Reconciliation (weekly): Compare batch and real-time flags. Tune thresholds so the two paths stay aligned.
This gives you the cost efficiency of batch for historical analysis and the responsiveness of real-time for live decisions.
7.8.3 Quick Decision Checklist
Ask these five questions in order. The first one that gives a clear answer decides the paradigm:
- Does the consumer need the result within seconds? → Real-time.
- Can the prediction be precomputed and stored? → Batch.
- Is the input data only available in batches (e.g., nightly ETL)? → Batch.
- Does the prediction depend on live user context (location, session)? → Real-time.
- Do you need both historical analysis and live decisions? → Hybrid.
Batch is your default when latency is not a constraint — it is cheaper, simpler to operate, and easier to audit. Real-time is mandatory when the user or system cannot wait. Hybrid architectures blend the two: batch for the bulk of predictions, real-time for edge cases and live decisions. The choice is an architectural decision, not just a model-deployment decision — it shapes your infrastructure, monitoring, and cost structure.
Real-world: The patterns discussed throughout the course — pipe-and-filter, CQRS, RAG, microservices — all describe real-time serving architectures once deployed. Batch serving has not been demonstrated yet in the course examples because those patterns are fundamentally about handling live requests.
7.9 From Predictive to Generative to Agentic
7.9.1 The Three Paradigms of AI Systems
The Big Picture: AI systems have progressed through three distinct paradigms in roughly a decade — predictive, generative, and agentic. Each paradigm does not replace the previous one; it builds on top of it. Understanding where a problem sits on this spectrum tells you what architecture, tools, and expectations are appropriate.
Machine learning systems have evolved through three paradigms. Predictive AI answers "what will happen?" — will this customer churn, is this transaction fraudulent. Generative AI answers "create something" — write an email, generate an image, summarize a document. The third and newest paradigm is Agentic AI.
Predictive AI — Models that map inputs to a fixed set of outputs: a class label, a number, or a probability. The output space is bounded and defined at training time. Examples: churn prediction, fraud scoring, demand forecasting.
Generative AI — Models that produce new content (text, images, audio, code) in response to a prompt. The output space is open-ended. Examples: ChatGPT writing an essay, Stable Diffusion creating an image, a code copilot completing a function.
Agentic AI — AI systems that pursue complex goals with limited direct supervision. They reason, plan, use tools, and iterate over multiple steps. The output is not just an answer — it is a completed workflow.
An agent is any piece of software that can perform a task — a prediction model, a classifier, a regressor. Agentic AI is different: it refers to AI systems that can pursue complex goals with limited direct supervision. At its highest level of autonomy, you give a single prompt and the system figures out every step — which tools to use, what sub-tasks to decompose into, when to ask for clarification. We are not fully there yet, but building-block autonomy is already deployed: within a well-defined step, an agentic system can make decisions, call APIs, and iterate without step-by-step human instructions.
Same Problem, Three Paradigms — Customer Support
| Paradigm | What it does | Example |
|---|---|---|
| Predictive | Classifies the ticket: "billing" or "technical" | A logistic regression model assigns a category |
| Generative | Drafts a reply email to the customer | An LLM writes a polite response based on the ticket text |
| Agentic | Reads the ticket, checks the customer's account, issues a refund if eligible, and sends a personalised reply | A multi-step agent that calls APIs, verifies policy, and acts autonomously |
The predictive model labels. The generative model writes. The agentic system acts end-to-end.
7.9.2 Request-Response vs. Goal-Oriented
Traditional AI (predictive and generative) follows a request-response pattern. You ask a question; the system answers. With multi-turn interaction, it remembers the conversation window. But it has no tool access — everything it knows is from its training data. It is stateless: each request is treated as independent unless wrapped in a conversation context.
Request-Response vs. Goal-Oriented:
- Request-Response: One input → one output. No planning, no tools, no memory beyond the conversation window. Stateless by default.
- Goal-Oriented (Agentic): A goal is stated → the system decomposes it into sub-tasks, selects tools, executes steps, checks results, and iterates until the goal is met. Memory persists across interactions.
Think of the difference like this: a calculator is request-response — you type "2 + 2" and get "4." A human project manager is goal-oriented — you say "ship the feature by Friday" and they break it into tasks, assign people, track progress, and handle blockers. Agentic AI aspires to be closer to the project manager than the calculator.
Scope Warning: Today's agentic systems are not fully autonomous project managers. They operate within guardrails — defined tool sets, bounded contexts, and human oversight. The professor's framing is precise: "building-block autonomy is already deployed," meaning individual steps within a workflow can be autonomous, even if the overall workflow still has human checkpoints.
7.9.3 What Makes Agentic AI Architecturally Different
Agentic AI pursues goals over time. It uses multi-step reasoning, actively selects and invokes tools (web search, code execution, database queries), and maintains memory and context across interactions. The systems you interact with today — Codex generating entire codebases, Claude writing and testing code — are agentic applications. Behind the scenes, multiple agents run: one behaves like a developer, another like a tester, a third like a reviewer. They communicate, collaborate, and produce a finished result.
Four Architectural Shifts from Generative to Agentic:
- Tool use — The model can call external APIs, run code, or query databases rather than relying solely on training data.
- Multi-step reasoning — The system plans a sequence of actions rather than producing a single output.
- Persistent memory — State and context survive across turns and sessions, enabling learning from past interactions.
- Autonomous decision-making — The system chooses which action to take next, not just how to respond to a prompt.
Agentic Workflow — Code Generation with Codex/Claude
- Developer agent receives a feature request and writes initial code.
- Tester agent runs the code, identifies bugs, and reports failures.
- Reviewer agent checks code style and architectural consistency.
- Developer agent receives feedback and fixes the issues.
- Cycle repeats until all agents agree the code is ready.
No single LLM call produces the final output. The result emerges from multi-agent collaboration — a hallmark of agentic systems.
Predictive AI labels and scores. Generative AI creates content. Agentic AI pursues goals — it reasons, plans, uses tools, and iterates over multiple steps with minimal human direction. Today's agentic systems combine these paradigms: a generative model sits at the core, but it is wrapped in an architecture that gives it tool access, memory, and multi-step decision-making. Recognising which paradigm a problem requires is the first architectural decision you make.
7.10 Chatbot versus Agent: A Comparative View
7.10.1 Capability Comparison with Examples
Why This Comparison Matters: The terms "chatbot" and "agent" are often used interchangeably in industry, but they represent fundamentally different architectures. A chatbot talks. An agent acts. Confusing the two leads to mismatched expectations, wrong infrastructure choices, and failed projects.
Consider the prompt: "Plan my trip to Goa."
A chatbot (generative AI) will respond with text: "Here are the best beaches — Baga, Anjuna, Calangute. You should visit these restaurants. The weather in March is pleasant." It gives you information, but you must then separately search flights, compare hotels, and make bookings.
An agent (agentic AI) will search for flights, check hotel availability, compare prices, book the reservation (if you have granted booking permissions), and add the itinerary to your calendar. It chains multiple actions together to accomplish a goal, not just describe one.
Chatbot vs. Agent — Key Differences:
| Dimension | Chatbot (Generative AI) | Agent (Agentic AI) |
|---|---|---|
| Interaction model | Request-response: one prompt → one answer | Goal-oriented: one goal → multi-step execution |
| Tool access | None — relies solely on training data | Calls APIs, queries databases, executes code |
| Memory | Conversation window only (stateless between sessions) | Persistent memory across sessions and tasks |
| Autonomy | User drives every step | System decides which steps to take |
| Output | Information or content | Completed actions and outcomes |
| Error handling | None — if it gives wrong info, user detects it | Self-corrects: retries, selects alternatives, escalates |
Think of the difference like asking a librarian versus hiring a personal assistant. The librarian (chatbot) can tell you which books are relevant to your research — you still have to read them, take notes, and write the paper. The personal assistant (agent) reads the books, drafts the paper, formats the citations, and submits it — you review the output.
Practical Contrast — "Find me a cheap flight to Delhi"
| Step | Chatbot's Response | Agent's Actions |
|---|---|---|
| 1 | "You can check Skyscanner, MakeMyTrip, or Google Flights." | Opens Skyscanner API, searches for Bangalore → Delhi flights |
| 2 | (No further action) | Sorts results by price, filters by departure window |
| 3 | (No further action) | Checks if the cheapest option is refundable |
| 4 | (No further action) | Presents the top 3 options with prices and links |
| 5 | (No further action) | If you say "book it," completes the reservation |
The chatbot informs. The agent accomplishes.
7.10.2 Controlling Agent Behaviour: Preventing Unbounded Loops
Core Risk of Agentic Systems: Unlike chatbots, agents can take actions — they call APIs, execute code, and chain sub-tasks. Without constraints, an agent given "Plan my trip to Goa" might spiral: searching for the best beach → the best restaurant near that beach → the history of Goan cuisine → the spice trade routes of the 16th century. This is called agentic drift — the agent loses sight of the original goal and expands its scope indefinitely.
Q: How do we prevent an agent from going into a never-ending nested loop — for instance, planning a trip, then exploring the food, then how the food is cooked, then the history of the cuisine, and so on?
A: Prompt engineering is the primary control mechanism. There are five recommended steps for writing an effective prompt. First, tell the AI who it is — "You are a researcher with 20 years of biomedical experience." This constrains its domain of operation. Second, limit the search scope and number of responses — "Search flights between Bangalore and Delhi, but return only two options." Third, specify the exact output format and word count — "Write a cited summary report of 500 words in JSON format." Fourth, be aware of token consumption: start with a small request (100 responses), measure the token cost, and extrapolate before scaling up. Fifth, test the prompt on small inputs before running it at scale. An open-ended prompt with no constraints is what causes agentic drift; a well-structured prompt keeps the agent focused.
The Five-Step Prompt Methodology for Agent Control:
- Identity — Tell the agent who it is to constrain its domain. ("You are a travel planning assistant.")
- Scope limits — Restrict what it searches and how many results it returns. ("Return only 3 flight options.")
- Output format — Specify the exact structure and size of the response. ("Output a JSON object with fields: flight, price, duration.")
- Token awareness — Start small, measure cost, then scale. Never ask for 1 million results first.
- Iterative testing — Validate on small inputs before deploying at full scale.
Unconstrained vs. Constrained Prompt
Unconstrained (causes drift):
> "Plan my trip to Goa."
Constrained (five-step methodology applied):
> "You are a travel planning assistant with access to flight and hotel booking APIs. Find 3 round-trip flights from Bangalore to Goa departing on March 15 and returning March 18, sorted by price. For each flight, check hotel availability near the arrival airport for those dates. Return results as a JSON array with fields: airline, price, departure_time, hotel_name, hotel_price. Do not search for restaurants, activities, or historical information."
The second prompt gives the agent an identity, limits scope, specifies output format, and implicitly constrains token usage.
A chatbot generates information; an agent generates outcomes. The power of agentic AI comes from tool access, multi-step reasoning, and autonomy — but these same features create the risk of unbounded loops and scope creep. The five-step prompt methodology (identity, scope limits, output format, token awareness, iterative testing) is the primary control mechanism to keep agents focused and predictable. Well-structured prompts are to agents what API contracts are to microservices — they define what is in scope and what is not.
7.11 The Five Core Components of an AI Agent
The Architecture Blueprint: Every AI agent — whether it is a simple chatbot wrapper or a complex multi-agent orchestration — is built from the same five conceptual components. The specific implementation varies by tool and use case, but the conceptual architecture is universal. Think of these five components as the "organs" of an agent: remove any one, and the system cannot function as an agent.
Every AI agent is built from five components. The specific implementation varies by tool and use case, but the conceptual architecture is universal.
┌─────────────────────────────────────────────────────────┐
│ PLANNING │
│ Task decomposition & sub-task sequencing │
├─────────┬───────────────────────────────┬───────────────┤
│ MEMORY │ LLM CORE │ TOOLS │
│ (4 types)│ (Reasoning Engine) │ (Web, APIs, │
│ │ │ Code, DB) │
├─────────┴───────────────────────────────┴───────────────┤
│ ACTION LOOP │
│ Observe → Think → Act → Reflect │
└─────────────────────────────────────────────────────────┘
7.11.1 LLM Core — The Reasoning Engine
The large language model is the brain. It can be any foundation model — GPT-5.4, Gemini 3.5, Grok, Claude, or an open-weight model like Gemma or Mistral. In a multi-agent setup, different agents can use different LLMs. You might assign code-generation tasks to a model known for coding (like Claude or specialized GPT variants) while using a lighter model for classification. During experimentation, use smaller models (GPT-4.1 nano, Gemma 2B) to keep costs low. In production, switch to more capable models.
LLM Core — The foundation model that serves as the agent's reasoning engine. It interprets prompts, decides which tools to call, evaluates intermediate results, and generates natural-language outputs. It is stateless by itself — all context comes from the memory component.
Chain-of-thought reasoning is what makes LLMs effective as reasoning engines. When asked "Give me Python code for binary search," the model does not jump to the answer. It thinks: "We need a sorted array. If it is not sorted, the first step is to sort it. We then divide it into two halves. Compare the middle element with the target. If equal, return the index. If the target is smaller, search the left half; otherwise, search the right half." This intermediate reasoning — visible in tools like DeepSeek R1 — is the same process a human interviewer expects when asking the same question. Each reasoning step connects logically to the next.
Chain-of-Thought Reasoning — Binary Search (DeepSeek R1)
When you ask "Write Python code for binary search," a chain-of-thought model does not immediately output code. Instead, it reasons step by step:
- "First, I need a sorted array."
- "Define two pointers: left at index 0, right at the last index."
- "Find the middle index: mid = (left + right) // 2."
- "Compare arr[mid] with the target."
- "If equal → return mid. If target < arr[mid] → search left half. If target> arr[mid] → search right half."
- "Repeat until left > right (element not found)."
Only after this reasoning does it generate the Python function. This mirrors exactly what a human interviewer expects — not just the answer, but the thinking process behind it.
Model Selection Trade-off: Smaller models (Gemma 2B, Mistral 7B) are cheap and fast for experimentation, but they may fail at complex reasoning or tool-calling. Larger models (Claude, GPT-4+) handle multi-step reasoning reliably but cost 10–100× more per token. In production, match model capability to task complexity — do not use a 70B-parameter model for simple classification.
7.11.2 Memory — Persistence Across Interactions
Memory in agentic systems is not a single storage bucket. There are four distinct types, each serving a different need.
The Four Memory Types:
| Type | Analogy | Lifespan | Scope | Storage |
|---|---|---|---|---|
| In-context / working | Whiteboard in a meeting room | Session only | Per conversation | LLM context window |
| Semantic knowledge base | Textbook in a library | Permanent until updated | Global (all users) | Vector DB or fine-tuned model |
| External / episodic | Personal diary | Persistent across sessions | Per user | Vector DB with user partitioning |
| Procedural / skills | Sticky notes on a monitor | Transient (tool call duration) | Per task execution | In-memory during workflow |
In-context / working memory is the conversation window you see when you open ChatGPT. You give a prompt; the system responds. You follow up with "make it shorter" — it knows what "it" refers to because the conversation history is held in working memory. This is temporary: it persists only for the duration of the conversation session. It is the memory you, as a user, can see and scroll through.
Semantic knowledge base is an externally curated, static dataset. A medical domain knowledge base, for instance, contains policy documents, clinical guidelines, and research findings. Anyone asking a medical question gets the same answer drawn from this shared knowledge. It is global (not personalized) and relatively static (updated only when the knowledge base itself is updated). A fine-tuned model is an example: you take GPT-5.4 and fine-tune it on medical data. The resulting model carries that domain knowledge for all users.
External / episodic memory is personalized per user and dynamic. Consider a banking chatbot serving 100 customers. Customer A asks about a transaction two days ago. Today, Customer A asks a follow-up question. The chatbot looks up Customer A's previous interactions in a vector database and tailors the response. Customer B asking the same question would get a different answer because their transaction history is different. Episodic memory is persistent, personal, and updated with every user interaction.
Q: When I open ChatGPT, each chat has a context history. Is that stored in a vector database?
A: The in-context working memory — what you see in your chat window — is customer-facing. The episodic memory is how the system internally stores your data across sessions, not just within a single window. Internally, vector databases may be used for efficient retrieval, but the architecture depends on the provider's choices. The distinction is: in-context is what the user sees; episodic is how the system persists it for future retrieval.
Q: Why separate episodic memory and the knowledge base into different storage? Can't both use a vector database?
A: You can store both in a vector database — there is no technical prescription against it. The reason to separate them architecturally is that they have different access patterns. The knowledge base is static and read-heavy; episodic memory is dynamic, personalized, and updated at high frequency. Episodic memory may need a caching layer because many users query it simultaneously. The knowledge base may not. The CQRS pattern we studied earlier — separating reads from writes — applies here too: one data store optimized for frequent writes and personalization, another for static, globally consistent reads.
Q: How much past data does episodic memory retain when responding to a user?
A: It depends entirely on the organization's archival policy. If a customer support bot launched in March, the organization may keep all conversations since launch. Storage capacity today, especially with cloud providers, is effectively unlimited — the constraint is cost, not space. Organizations decide their retention policies based on compliance needs and cost models.
Q: In terms of learning, is there a difference between episodic and semantic memory?
A: Both use semantic retrieval under the hood — keyword-based plus embedding-based similarity search. The word "semantic" in the knowledge base name does not mean the other types are non-semantic. All four memory types leverage semantic understanding; the distinction is about whose data, how static, and who can access it.
Q: Where does the flow control — branching, if-else decisions, error handling — get stored?
A: Flow control falls under procedural memory or in-context memory, not external or semantic memory. The decision path — "if agent A succeeds, go to B; if A fails, go to C" — is part of the workflow state, temporarily held as the task executes.
Procedural memory / skills is the most transient form. When an agent calls a weather API, the API's response is temporarily held so it can be passed to the next agent in the workflow. It is not permanently stored; it is the working state of a function call. The distinction from in-context memory is that procedural memory specifically concerns data flowing through tool invocations — information the agent could not produce from its trained model and had to fetch from an external system.
CQRS Parallel: The separation of episodic memory (write-heavy, personalized) from semantic knowledge base (read-heavy, global) mirrors the CQRS (Command Query Responsibility Segregation) pattern from earlier lectures. The architectural principle is the same: when read and write patterns differ dramatically, separate the stores.
7.11.3 Action Loop — Observe, Think, Act, Reflect
The agent continuously cycles through four phases: observe the current state of the task, think about what step to take next, act by invoking a tool or generating output, and reflect on whether the action moved the goal closer. This loop runs until the task is complete or a stopping condition is met.
The O-TAR Loop (Observe-Think-Act-Reflect):
- Observe — Read the current state: what is the goal, what has been done so far, what tools returned.
- Think — Use the LLM core to reason about the next step: which tool to call, which sub-task to tackle.
- Act — Execute the chosen action: call an API, run code, generate a response.
- Reflect — Evaluate the result: did it succeed? Is the goal met? If not, loop back to Observe.
Action Loop in Practice — "Book me a flight to Delhi"
| Phase | What Happens |
|---|---|
| Observe | User wants a flight to Delhi. No prior actions taken. |
| Think | "I need to search for flights. I'll use the flight API." |
| Act | Calls flight search API: Bangalore → Delhi, March 15. |
| Reflect | Got 12 results. User didn't specify date range — need to filter. |
| Observe | 12 flights available. User's profile says "prefers morning flights." |
| Think | "Filter to departures before 12 PM. Sort by price." |
| Act | Filters and sorts. Top 3 morning flights selected. |
| Reflect | Goal achieved — user now has 3 filtered options. Loop ends. |
Stopping Conditions Are Critical: Without a well-defined stopping condition, the action loop can run indefinitely — the same agentic drift risk from Section 7.10. Every action loop must have: (a) a maximum iteration count, (b) a goal-completion check, or (c) a timeout.
7.11.4 Tools — The Interface to the External World
Tools are what let an AI agent reach beyond its training data. When ChatGPT 3.5 launched in 2022, asking "Who is the Prime Minister of India?" would return "As of my knowledge cutoff in September 2021, Narendra Modi is the Prime Minister." It could not access real-time information. Today, when you ask the same question, the model performs a web search, retrieves current information, and answers with the latest data.
Common tools include:
- Web search: retrieve current information beyond the model's training cutoff
- Code execution: run Python, SQL, or shell commands
- API calls: invoke external services (weather APIs, payment gateways, prediction endpoints)
- Database queries: read from or write to structured and vector databases
- File operations: read uploaded documents, generate output files
Tool as Capability Extension — A tool is any external system the agent can invoke to get information or perform actions it cannot do from its trained weights alone. Tools transform a knowledgeable text generator into a capable actor in the real world. The agent selects which tool to use; the tool executes and returns results.
JSON has become the standard data interchange format for tool communication because it is lightweight, universally supported, and human-readable. Every major cloud provider — AWS, Google Cloud, Azure — uses JSON for policy documents and API payloads.
Tool Selection — Choosing the Right Tool for the Job
| User Request | Tool Selected | Why |
|---|---|---|
| "What's the weather in Mumbai today?" | Web search / weather API | Model's training data does not include today's weather |
| "Sort this CSV by the revenue column" | Code execution (Python) | Requires processing structured data |
| "How many orders did we ship yesterday?" | Database query | Requires access to live business data |
| "Summarize this PDF" | File operations + LLM | Requires reading a file, then reasoning over it |
7.11.5 Planning — Task Decomposition
Planning is how an agent breaks a complex goal into manageable sub-tasks. A "plan my trip to Goa" request becomes: search flights → compare prices → check hotels → book flight → book hotel → add to calendar. Each sub-task may be handled by a different agent (a specialized LLM instance), and the results are assembled into the final output. Planning is the "divide and conquer" layer of agentic systems.
Planning — The component that takes a high-level goal and decomposes it into an ordered sequence of sub-tasks. Each sub-task is assigned to the appropriate tool or agent. Planning determines what to do and in what order; the action loop handles how to do each step.
Task Decomposition — "Build me a sales dashboard"
The planner breaks this into:
- Sub-task 1: Query the sales database for the last 90 days → Database tool
- Sub-task 2: Clean and aggregate the data by region and product → Code execution tool
- Sub-task 3: Generate visualizations (bar chart, trend line, pie chart) → Code execution tool
- Sub-task 4: Assemble charts into an HTML dashboard → Code execution tool
- Sub-task 5: Deploy the dashboard to a shared URL → File/Deployment tool
Each sub-task has clear inputs, outputs, and dependencies. The planner ensures they execute in the right order.
The five components — LLM Core (reasoning), Memory (persistence), Action Loop (execution cycle), Tools (external access), and Planning (decomposition) — form the universal architecture of every AI agent. The LLM thinks, memory remembers, the action loop drives progress, tools extend capability beyond training data, and planning breaks complex goals into manageable steps. Understanding this architecture lets you evaluate any agent framework (LangChain, CrewAI, OpenAI Agent Builder) by mapping its abstractions to these five components.
7.12 Agentic AI Applications in Production Today
7.12.1 Current Production Use Cases
Beyond Demos: Agentic AI is not just a research concept — production-grade agentic systems already exist and are used daily by millions of developers and knowledge workers. The key signal that a system is agentic (not just generative) is that it takes actions — it writes files, opens pull requests, queries databases, and manages state across multiple steps.
Production-grade agentic systems already exist. Codex and Claude for software development are the most visible examples: you describe a feature, and multiple agents collaborate — one writes the code, one generates test cases, one runs the test suite, one opens a pull request. The user reviews and merges.
Agentic Application Pattern — A recurring structure where an AI agent (or team of agents) autonomously performs a multi-step workflow that traditionally required a human. The pattern has three common elements: (1) a high-level goal given in natural language, (2) autonomous tool use to accomplish sub-tasks, and (3) a human review checkpoint before final action.
7.12.2 An Expanded View of Production Patterns
Additional agentic application patterns:
- Fix my code: an agent receives a bug report, analyzes the codebase, writes the fix, runs the existing tests, sees any failures, iterates, opens a PR. The left side is what a developer does manually (copy code into ChatGPT for debugging advice). The right side is the agent doing it autonomously.
- Research a topic: give an agent a research paper. It validates the claims, proofreads the text, identifies strengths and weaknesses, compares with existing literature, and suggests improvements.
- Manage an online store: an agent monitors inventory, adjusts prices dynamically, responds to customer queries, and processes orders.
- Monitor my inbox: an agent continuously reads incoming emails, drafts replies, flags urgent messages, and unsubscribes from junk — though most people still prefer human-in-the-loop for replies, especially in professional contexts.
Deep Dive: "Fix My Code" — Agent Workflow
| Step | Agent Action | Tool Used |
|---|---|---|
| 1. Receive bug report | Parses the issue description and stack trace | LLM Core (reasoning) |
| 2. Analyze codebase | Reads relevant source files, identifies the root cause | File operations + code execution |
| 3. Write the fix | Generates a patch for the affected function | LLM Core (code generation) |
| 4. Run tests | Executes the existing test suite against the patched code | Code execution |
| 5. Iterate | If tests fail, analyzes failures and adjusts the fix | LLM Core + code execution (action loop) |
| 6. Open PR | Creates a pull request with the fix, test results, and explanation | Git API / GitHub tool |
The agent replaces what a junior developer might spend 2–4 hours doing. The human reviewer remains in the loop to approve or reject the PR — a human-in-the-loop checkpoint.
Human-in-the-Loop Remains Essential: All production agentic systems today maintain human review before final execution. An agent that opens a PR is helpful; an agent that merges and deploys to production without review is dangerous. The industry consensus is: agents act autonomously up to the point of irreversible consequences, then humans decide.
7.12.3 The Spectrum of Agent Autonomy
Autonomy Levels in Production:
| Level | Description | Example |
|---|---|---|
| Level 1 — Assistive | Agent suggests; human executes | Copilot autocomplete, grammar correction |
| Level 2 — Collaborative | Agent drafts; human reviews and approves | Code fix PRs, email draft replies |
| Level 3 — Supervised autonomous | Agent acts within guardrails; human monitors | Inventory management, dynamic pricing |
| Level 4 — Fully autonomous | Agent acts without human review | Not yet mainstream; used in low-risk, high-volume tasks |
Most production systems today operate at Levels 2–3. The trend is toward Level 3 with expanding guardrails.
Comparing the Four Production Patterns
| Pattern | Goal | Tools | Autonomy Level | Human Checkpoint |
|---|---|---|---|---|
| Fix my code | Eliminate a bug | Code analysis, test runner, Git | Level 2 | PR review |
| Research a topic | Validate and improve a paper | Web search, PDF reader | Level 2 | Report review |
| Manage a store | Maximise revenue | Inventory DB, pricing API, chat | Level 3 | Weekly audit |
| Monitor inbox | Triage email efficiently | Email API, calendar API | Level 2 | Draft review before send |
Agentic AI is already in production across software development, research, e-commerce, and personal productivity. The common pattern is: a high-level goal → autonomous multi-step execution with tools → human review before irreversible action. The critical engineering challenge is not "can the agent do it?" but "can we trust the agent to do it unsupervised?" — and today, the answer is: only up to a defined autonomy boundary.
7.13 Multi-Agent Communication and the Need for Patterns
7.13.1 Communication Protocols for Agentic Systems
The Coordination Problem: A single AI agent can accomplish simple tasks on its own. But real-world goals — building software, processing insurance claims, managing a supply chain — require multiple agents to collaborate. The moment you have two or more agents working together, you face the same fundamental challenges that distributed systems engineers have dealt with for decades: How do they communicate? What happens when one fails? How do you maintain consistency across independent components?
When multiple agents collaborate on a task, they need communication protocols. The patterns studied earlier in the course — microservices, pipe-and-filter, event-driven, CQRS — were designed primarily for predictive and generative AI systems. In the agentic world, where multiple LLM instances act as independent agents passing work to each other, two patterns have emerged as particularly effective: the Saga pattern (for managing distributed, multi-step agent workflows) and the Blackboard pattern (for shared-state collaboration). The Saga pattern is the focus of the remainder of this lecture.
Why Patterns Transfer from Microservices to Agents:
An AI agent in a multi-agent system is architecturally similar to a microservice: it has its own state (memory), its own logic (LLM core + tools), and communicates with other agents through messages or shared data. The problems that arise — partial failures, inconsistent state, coordination overhead — are identical to those in distributed microservice architectures. The solutions (patterns) transfer directly.
7.13.2 The Parallel: Microservices → Agents
Mapping Microservice Concepts to Agent Concepts
| Microservice Concept | Agent Equivalent |
|---|---|
| Service | Individual AI agent (LLM instance + tools + memory) |
| API call between services | Agent-to-agent message or tool invocation |
| Database per service | Memory per agent (episodic, procedural) |
| Service failure | Agent hallucination, tool failure, or timeout |
| Distributed transaction | Multi-step agent workflow |
| Saga pattern | Compensating workflow when an agent step fails |
| Shared event bus (Blackboard) | Shared workspace where agents read/write state |
Think of it like a team of specialists in a hospital. The radiologist takes X-rays, the surgeon operates, the pharmacist dispenses medication, and the nurse monitors recovery. Each specialist is autonomous (like an agent), but they must coordinate. If the surgeon cancels the operation, the radiologist does not need to re-take the X-ray, but the pharmacist must cancel the medication order. That compensating action when something goes wrong is exactly what the Saga pattern formalises.
7.13.3 Two Patterns for Multi-Agent Collaboration
The Two Dominant Multi-Agent Patterns:
- Saga Pattern — Manages distributed, multi-step workflows where each step is performed by a different agent. If any step fails, compensating (undo) actions are executed in reverse order to restore consistency. Best for: transactional workflows (book flight → book hotel → update calendar).
- Blackboard Pattern — Provides a shared workspace where multiple agents read and write intermediate results. No agent owns the entire workflow; each contributes what it knows to a common "blackboard" until the problem is solved. Best for: collaborative reasoning (multiple specialists analysing the same data).
Why Existing Patterns Fall Short for Agents: Traditional request-response patterns (like simple REST APIs) assume synchronous, deterministic communication. Agent communication is asynchronous (an agent may take seconds or minutes to reason), non-deterministic (the same prompt can produce different outputs), and failure-prone (hallucinations, tool errors, context window limits). Patterns must account for these realities.
7.13.4 When to Use Which Pattern
| Criterion | Saga Pattern | Blackboard Pattern |
|---|---|---|
| Workflow type | Sequential steps with dependencies | Parallel contributions to shared problem |
| Failure handling | Compensating transactions (undo) | Graceful degradation (continue with available data) |
| State management | Each step owns its local state | Shared global state on the blackboard |
| Coordination | Orchestrator or event-driven | Self-organising; agents read and react |
| Agent example | Book flight → book hotel → add calendar | Multiple specialists each analyse a patient case |
Multi-agent systems face the same coordination challenges as distributed microservices: communication, failure handling, and state consistency. Two patterns have emerged as particularly effective — the Saga pattern for transactional, multi-step workflows with compensating rollbacks, and the Blackboard pattern for collaborative, shared-state problem solving. The rest of this lecture dives deep into the Saga pattern, which directly addresses the most common multi-agent challenge: what happens when one step in a multi-agent workflow fails?
7.14 Model Composition Patterns
Context Bridge: Before diving into the Saga pattern for multi-agent workflows, it is worth recognising that multi-model systems already exist in predictive AI. The composition strategies used there — combining, chaining, or cascading models — directly inspired the multi-agent communication patterns we now adapt for agentic systems. Understanding these three patterns gives you the conceptual foundation for thinking about how multiple AI components work together.
Before diving into the Saga pattern, it is worth noting that multi-model systems already exist in predictive AI. Three composition strategies are common.
7.14.1 Ensembles and Metamodels
Multiple models vote or a metamodel combines their outputs. Random forest is an ensemble of decision trees; stacking uses a secondary model to learn how to weight base model predictions.
Ensemble — Train multiple independent models on the same task and combine their outputs (majority vote, average, or weighted sum). The combined prediction is typically more robust than any single model because individual errors cancel out.
Metamodel (Stacking) — Train a second-level model that takes the outputs of several base models as input features and learns the optimal way to combine them. Unlike simple averaging, the metamodel can learn that "Model A is reliable for class X but not class Y."
Think of ensemble prediction like asking three doctors for a diagnosis. If all three agree, you are confident. If two agree and one disagrees, you trust the majority. A metamodel is like a chief physician who knows that Doctor A is excellent at cardiac cases but unreliable for neurological ones, and weighs their opinions accordingly.
Ensemble in Practice — Random Forest
| Component | Role |
|---|---|
| Individual decision tree | Makes a prediction based on a random subset of features |
| Random forest (100 trees) | Aggregates 100 tree predictions via majority vote |
| Stacking metamodel | A logistic regression that learns to weight each tree's output by reliability |
The random forest's power comes from diversity: each tree sees a different subset of data and features, so their errors are uncorrelated. The ensemble smooths them out.
7.14.2 Sequential Decomposition
One model's output becomes the next model's input. In a speech-to-text pipeline, an acoustic model converts audio to phonemes, a language model converts phonemes to words, and a punctuation model adds structure.
Sequential Decomposition — Break a complex task into a pipeline of simpler sub-tasks, each handled by a specialised model. The output of stage N is the input to stage N+1. Each model can be trained, evaluated, and replaced independently.
Sequential Pipeline — Speech-to-Text
Audio → [Acoustic Model] → Phonemes → [Language Model] → Words → [Punctuation Model] → Structured Text
| Stage | Model | Input | Output |
|---|---|---|---|
| 1 | Acoustic model | Raw audio waveform | Sequence of phonemes |
| 2 | Language model | Phonemes | Words and word boundaries |
| 3 | Punctuation model | Raw words | Punctuated, capitalised sentences |
Each model is simpler than a single end-to-end model would be. Each can be improved independently — upgrade the acoustic model without touching the language model.
Pipeline Risk — Error Propagation: In a sequential pipeline, errors compound. If the acoustic model mishears a phoneme, the language model receives incorrect input and may produce the wrong word. The punctuation model then punctuates a wrong sentence. This is identical to the training-serving skew risk in ML pipelines: feature encoding must be consistent between training and inference at every stage. When composing models, always validate intermediate outputs.
7.14.3 Cascade / Two-Phase Prediction
A fast, cheap model handles the common case; a slower, more accurate model handles the edge cases. A spam filter might use a lightweight rule-based model for obvious spam and invoke a deep learning model only for borderline messages.
Cascade (Two-Phase) Prediction — A fast model (low cost, moderate accuracy) screens all inputs. Only the inputs that the fast model is uncertain about are escalated to a slow model (high cost, high accuracy). This optimises the cost-accuracy trade-off: most inputs are handled cheaply; only hard cases incur the expensive model.
Think of it like airport security. Most passengers walk through the metal detector (fast, cheap screening). Only those who trigger an alarm get pulled aside for a full pat-down and luggage inspection (slow, thorough, expensive). The metal detector handles 95% of cases; the detailed inspection handles the remaining 5%.
Cascade in Practice — Spam Filtering
| Phase | Model | Input | Output | Volume |
|---|---|---|---|---|
| Phase 1 (fast) | Rule-based filter | Incoming email | "Spam" / "Not spam" / "Uncertain" | 100% of emails |
| Phase 2 (slow) | Deep learning classifier | "Uncertain" emails only | Final spam/not-spam decision | ~5–10% of emails |
Result: 90–95% of emails are classified in milliseconds by the rule-based filter. Only 5–10% (borderline cases) reach the expensive deep learning model. Total cost is a fraction of running the deep model on every email.
7.14.4 From Predictive Composition to Agent Composition
How Predictive Patterns Map to Agent Patterns:
| Predictive Pattern | Agent Equivalent | Key Idea |
|---|---|---|
| Ensemble / metamodel | Multiple agents voting on a decision | Combine independent agents for robustness |
| Sequential decomposition | Multi-step agent pipeline (agent A → agent B → agent C) | Chain agents where each agent's output feeds the next |
| Cascade / two-phase | Fast agent + escalation to specialised agent | Use cheap reasoning first, escalate to powerful model for hard cases |
Three model composition patterns from predictive AI — ensembles (combine independent models), sequential decomposition (chain models in a pipeline), and cascade/two-phase prediction (fast screen + slow escalation) — directly inspire how we design multi-agent systems. The architectural principles are the same: decompose complex tasks, specialise components, and combine results. The difference is that agent composition adds non-determinism, asynchronous execution, and the need for failure recovery — which is exactly what the Saga pattern addresses.
7.15 Why Memory Matters
7.15.1 From Stateless to Stateful Systems
The Fundamental Shift: All the microservices examples shown earlier in the course were stateless: each request triggered the same pipeline — receive input, run model, return response, forget everything. The next request has no knowledge of the previous one. In agentic systems, this no longer works. Memory transforms a stateless request-response system into a stateful, goal-pursuing agent.
All the microservices examples shown earlier in the course were stateless: each request triggered the same pipeline — receive input, run model, return response, forget everything. In agentic systems, this no longer works. An agent needs to remember the user's previous queries, the intermediate results of its own sub-tasks, and the outputs of other agents it collaborates with. This is why memory — in its four forms — is a first-class architectural concern in agentic design.
Stateless vs. Stateful:
| Property | Stateless (Microservices) | Stateful (Agentic) |
|---|---|---|
| Request handling | Each request is independent | Requests build on previous context |
| Memory | None between requests | Persistent across turns, sessions, and agents |
| Output quality | Same input → always same output | Improves with context: more history → better response |
| Failure recovery | Retry the same request | Resume from where the agent left off |
| User experience | "Start over every time" | "Continue where we left off" |
Think of the difference between a vending machine and a barista. A vending machine (stateless) does not remember you. Every time you press "coffee," it dispenses the same drink. A barista (stateful) remembers that you like oat milk, no sugar, extra shot — and asks "the usual?" when you walk in. The barista's memory transforms the interaction from a transaction into a relationship.
Why Stateless Fails for Agents — A Customer Support Scenario
| Turn | Stateless Bot | Stateful Agent |
|---|---|---|
| Turn 1 | User: "I ordered a laptop last week." Bot: "Can you provide your order number?" | User: "I ordered a laptop last week." Agent: Looks up recent laptop orders, finds Order #4521 |
| Turn 2 | User: "It arrived broken." Bot: "I'm sorry. What product are you referring to?" | User: "It arrived broken." Agent: Checks Order #4521, confirms delivery, initiates return |
| Turn 3 | User: "I already told you — the laptop!" Bot: "Can you provide your order number?" | User: "Can I get a refund?" Agent: Processes refund to original payment method, sends confirmation |
The stateless bot frustrates the user by forgetting everything between turns. The stateful agent tracks the conversation and acts progressively toward a resolution.
7.15.2 Memory as an Architectural Concern
Why Memory Is First-Class in Agentic Design:
Memory is not an afterthought or an add-on feature. It determines:
- Response quality — An agent with memory gives contextual, personalised answers. An agent without memory gives generic ones.
- Task continuity — Multi-step tasks require the agent to remember what it has already done and what remains.
- Collaboration — When multiple agents work together, they share results through memory (episodic or procedural). Without shared memory, agents cannot coordinate.
- Cost — More memory means more storage and retrieval cost. Less memory means worse responses. The trade-off is an architectural decision.
- Privacy and compliance — Episodic memory stores personal user data. Retention policies, access controls, and data deletion requirements all shape how memory is designed.
The Memory-Privacy Tension: The more an agent remembers, the better it serves the user — but the more personal data it stores. Regulations like GDPR require the ability to delete user data on request ("right to be forgotten"). Episodic memory systems must support selective deletion without corrupting other users' data. This is a design constraint, not an afterthought.
7.15.3 The Four Types at a Glance
Memory Type Summary (detailed in Section 7.11):
| Type | What It Stores | Lifespan | Scope | Primary Use |
|---|---|---|---|---|
| In-context / working | Current conversation window | Session | Per conversation | Multi-turn coherence |
| Semantic knowledge base | Domain knowledge, policies, documents | Permanent (until updated) | Global | Factual grounding |
| Episodic / external | Past user interactions, preferences | Persistent | Per user | Personalisation |
| Procedural / skills | Tool outputs, intermediate results | Transient | Per task | Workflow state passing |
Design for Change: When building memory systems, follow the same principle taught in pipeline design — modularity with stable interfaces. The memory interface (what an agent can read/write) should remain stable even if the underlying storage technology changes (vector DB today, graph DB tomorrow). Encapsulate the storage layer behind a clean API so agents do not depend on implementation details.
Memory is what transforms a stateless request-response system into a stateful, goal-pursuing agent. It is not a feature bolted on after the fact — it is a first-class architectural concern that shapes response quality, task continuity, multi-agent collaboration, cost, and privacy compliance. The four memory types (working, semantic, episodic, procedural) each serve distinct purposes and have different storage, access, and lifecycle requirements. Designing the memory layer with modularity and stable interfaces ensures the system can evolve without breaking agents that depend on it.
7.16 The Four Types of Memory
7.16.1 Reference Summary
Why does an AI agent forget? A large language model by itself has no persistent memory — it only sees the tokens in the current request window. The moment a conversation ends, everything is gone. This is like a brilliant consultant who suffers from amnesia between meetings. Memory is what turns a stateless model into a stateful agent that learns, adapts, and builds on past interactions.
Memory is the mechanism that lets an agent retain information across steps, sessions, and users. Without it, every interaction starts from scratch. There are four distinct types, each with its own storage strategy, lifespan, and purpose.
This section consolidates the memory discussion from §7.11.2 into a reference table.
The Four Types of Agent Memory
Think of an agent's memory system like the different ways a human professional remembers things:
| Type | What It Stores | Lifespan | Access Scope | Typical Storage |
|---|---|---|---|---|
| In-context / working memory | Current conversation, recent instructions, tool results | Single session | This conversation only | Model context window |
| Semantic knowledge base | Domain facts, reference material, curated documents | Permanent | All users, all sessions | Vector database (ChromaDB, Pinecone) + embeddings |
| External / episodic memory | Past interactions, user preferences, personalized history | Persistent | Per-user | Vector database or relational DB |
| Procedural memory / skills | Tool invocation state, intermediate results, workflow data | Task duration | Current workflow execution | In-memory, message queues, temp storage |
- In-context / working memory: Temporary, visible to the user, lasts for one conversation session. This is the "scratch pad" — what the model sees right now in its prompt window. When you open a new chat in ChatGPT, the context history you see is the working memory.
- Semantic knowledge base: Externally curated, static, global — the same for all users. Example: a fine-tuned medical model that "knows" drug interactions because it was trained on medical literature. This memory does not change from user to user.
- External / episodic memory: Personalized per user, persistent, dynamic — updated with every interaction. Stored in vector databases or similar retrieval systems. This is how a customer service bot remembers that you prefer email over phone calls.
- Procedural memory / skills: Transient state from tool invocations, passed between agents during a workflow execution. Think of this as the "sticky notes" an agent passes to itself while working through a multi-step task.
Analogy — The Hospital System
Imagine a hospital to understand the four memory types:
- Working memory = the whiteboard in the operating room. It shows the current patient's vitals, the procedure in progress. Erased after each surgery.
- Semantic knowledge base = the medical textbook library. Same books for every doctor, rarely updated, full of established medical knowledge.
- Episodic memory = each patient's medical history file. Unique to the patient, grows with every visit, accessible by any doctor treating that patient.
- Procedural memory = the surgical checklist used during an operation. Temporary, task-specific, discarded when the operation is complete.
Why separate episodic memory from the knowledge base?
A common mistake is to store everything in one giant database. The key distinction is who owns the data and how often it changes:
- The knowledge base is static and read-heavy — it is the same curated corpus for everyone. Think: "What are the known side effects of aspirin?"
- Episodic memory is dynamic and personalized — it changes with every user interaction. Think: "Last week, this patient reported a headache after taking aspirin."
Mixing them leads to retrieval confusion: the agent might answer a factual question with a single user's anecdote, or miss personalized context by returning only generic facts.
How Much Data Can Episodic Memory Hold?
The answer depends on organizational archival policy. Cloud storage is effectively unlimited — the real constraint is cost, not capacity. A typical vector database like Pinecone or ChromaDB can store millions of embedding vectors. The practical questions are:
- How far back do we want to look? (Relevance decay)
- What is the retrieval latency budget? (Larger stores → slower search)
- What are the storage and compute costs? (Embeddings are not free)
Q: When I open ChatGPT, each chat has a context history. Is that stored in a vector database?
A: No — that visible chat history is in-context working memory, held entirely within the model's context window for that session. The episodic memory is how the system internally stores data across sessions (e.g., "memory" features or fine-tuning data). These are two different layers.
The distinction between different memory stores raises another common question about their architecture.
Q: Why separate episodic memory and the knowledge base into different storage?
A: They have fundamentally different access patterns. The knowledge base is static and read-heavy — it changes rarely and serves the same content to every user. Episodic memory is dynamic, personalized, and write-heavy — it updates with every interaction and returns user-specific results.
Memory types also interact with workflow execution logic, which leads to a related question.
Q: Where does flow control — branching, error handling — get stored?
A: Flow control falls under procedural memory or in-context memory, temporarily held as the task executes. It is not persisted long-term because workflow logic is transient by nature — it only matters while the task is running.
Recap: An agent uses four memory types — working (session-scoped scratchpad), semantic (global knowledge), episodic (per-user history), and procedural (transient task state). Each has a different lifespan, access scope, and storage strategy. Separating them prevents retrieval confusion and enables the right trade-offs for each use case.
Bridge to 7.17: Memory gives an agent what to remember. But how do you control what the agent does with that memory at runtime? That is the job of prompt engineering — the topic of the next section.
Real-world: If you build agents using a visual builder (like the OpenAI Agent Builder), you have limited control over memory — you cannot attach a custom vector database or configure retention policies. To build a persistent, production-grade agent, you write your own Python code where you control the storage layer (ChromaDB, Pinecone, PostgreSQL with pgvector) and the memory logic.
7.17 Prompt Engineering as a Control Mechanism
7.17.1 The Five-Step Prompt Methodology
The hidden steering wheel. Most people think of prompt engineering as a way to get "better answers" from a chatbot. In agentic systems, it plays a far more critical role: it is the primary control mechanism that prevents runaway execution. An agent given a vague instruction like "find me the best flight" could search thousands of airlines, compare millions of routes, and burn through your entire token budget before returning a single result. The prompt is the steering wheel — and the tighter your grip, the more predictable the agent's path.
Prompt engineering is not just about getting better answers — it is the primary mechanism for constraining agent behavior and preventing runaway execution. When an agent has access to tools, memory, and multi-step reasoning, an unconstrained prompt is like handing a teenager the car keys with no destination, no speed limit, and no fuel gauge.
The Five-Step Prompt Methodology
Think of this as a checklist you run through every time you design a prompt for an agent:
- Establish identity — Tell the agent who it is and what expertise it has. This narrows the model's reasoning style.
- "You are a full-stack developer with 10 years of Python experience."
- Constrain search scope — Define the boundaries of where the agent can look and what it can return.
- "Search only within India. Return only two flight options."
- Specify output format — Demand a precise structure so downstream systems can parse the result.
- "Return the result as a JSON object with fields: airline, flight_number, departure_time, price."
- Monitor tokens — Always start small before scaling. Measure input tokens, context tokens, and output tokens.
- Start with 100 records to estimate token consumption before scaling to 1 million.
- Iterate — Test on small inputs, observe behavior, refine the prompt. Prompt engineering is empirical, not theoretical.
- If the agent returns 5 options instead of 2, tighten the constraint.
Analogy — The GPS Navigation Analogy
Think of the five steps like setting up a GPS for a road trip:
- Identity = "You are driving a truck" (the GPS adapts its route for truck-appropriate roads)
- Search scope = "Avoid toll roads and highways" (constrains the search space)
- Output format = "Show me the route with turn-by-turn directions" (specifies what you want back)
- Token monitoring = "Check fuel range before starting" (don't commit to a 500-mile route if you have 100 miles of gas)
- Iterate = "Take a short test drive first, then adjust the route" (validate before going all-in)
Without step 2, the GPS might route you through three countries. Without step 4, you might run out of fuel halfway.
Let us now apply this methodology to a concrete scenario.
Worked Example — Building an Agent Prompt Step by Step
Suppose you are building an agent that generates product descriptions for an e-commerce site.
Bad prompt: "Write product descriptions for our catalog."
- Result: The agent writes for all 10,000 products, uses inconsistent formats, and burns through tokens.
Applying the five-step methodology:
- Identity: "You are an e-commerce copywriter specializing in consumer electronics."
- Scope: "Process only the 'smartphones' category, max 50 products."
- Format: "For each product, output a JSON object: {product_name, tagline (max 10 words), description (max 150 words), key_features (array of 3-5 strings)}."
- Monitor: "Process 5 products first. Report the total tokens used per product."
- Iterate: "Based on the 5-product sample, adjust description length if token cost exceeds $0.05 per product."
This turns an open-ended, potentially infinite task into a bounded, measurable, repeatable process.
The Unconstrained Agent Anti-Pattern
Without these constraints, an agent given an open-ended prompt will:
- Expand its search scope indefinitely — searching more tools, more data sources, more iterations than necessary
- Consume excessive tokens — each reasoning step adds to the context window; the cost grows quadratically with chain length
- Produce irrelevant results — without a defined output format, the agent may return verbose natural language when you need structured data
- Enter nested loops — calling tools that call other tools, never reaching a termination condition
The symptom is an agent that "never finishes" or returns enormous, unfocused outputs. The root cause is always an insufficiently constrained prompt.
Q: Can the model handle a request for 1 million pages of output? Won't that create an infinite loop?
A: The request itself is valid, but issuing it directly would consume enormous tokens. A better approach: ask for 100 pages first. Observe the token consumption (input tokens + context tokens + output tokens). From that sample, calculate the cost for 1 million pages. You may discover that 1 million pages costs more than you are willing to spend, or that you can batch it into manageable chunks. Start small, measure, then scale.
Token Monitoring — The Cost-Awareness Skill
Token monitoring is the practice of tracking how many tokens a prompt consumes at each step of agent execution. A token is roughly 4 characters of English text. Every API call charges for both input and output tokens.
The key insight: token cost grows with chain length. Each step in an agent's reasoning chain must pass the full conversation history back to the model. After 10 steps of tool use, the context window contains all 10 tool results plus all 10 reasoning steps. This is why step 4 (monitor tokens) is not optional — it is the difference between a $0.10 task and a $100 task.
Pitfall — Prompt Engineering Is Not "Set and Forget"
A common mistake is to write a prompt once and assume it will work forever. In production agentic systems:
- Model providers update their models, changing behavior
- Input data distributions shift over time
- Tool APIs change their response formats
Prompt engineering requires continuous monitoring and iteration. Treat prompts like code — version them, test them, deploy them with rollback capability.
Recap: Prompt engineering is the primary control mechanism for agentic systems. The five-step methodology — identity, search scope, output format, token monitoring, iteration — turns an unconstrained agent into a predictable, cost-effective system. Always start small, measure, and scale deliberately.
Bridge to 7.18: The five steps above are a prompt-level technique. But when you zoom out, you realize that many agents share similar structural problems — coordination, memory, communication. That is where architectural patterns come in. The next section explores why patterns matter at the system level.
Real-world: Production teams at companies deploying AI agents maintain prompt registries — versioned collections of prompts with A/B testing. When a new model version ships, they test each prompt against a benchmark suite before deploying. This is prompt engineering treated as a first-class engineering discipline, not an afterthought.
7.18 Architectural Thinking: Why Patterns Matter
7.18.1 Patterns as Reusable Solutions
Why not just write code? You could solve every coordination problem from scratch. But imagine if every bridge engineer had to re-derive the physics of load-bearing structures instead of using proven designs. Software architecture patterns serve the same purpose: they are proven solutions to recurring problems, documented so that the next engineer does not start from zero.
An architectural pattern is a reusable, named solution to a common structural problem in software design. It is not a specific library or framework — it is a blueprint that tells you how to arrange components, how they communicate, and how they handle failure. Patterns have names so teams can communicate complex designs in a single phrase: "Let's use CQRS" carries more meaning than a paragraph of explanation.
Patterns the Course Has Covered So Far
| Pattern | Problem It Solves | Domain |
|---|---|---|
| Pipe-and-filter | Processing data through a sequence of transformations | Data pipelines, ETL |
| CQRS (Command Query Responsibility Segregation) | Separating read and write models for performance | High-throughput systems |
| Microservices | Decomposing a monolith into independently deployable services | Scalable backends |
| Event-driven | Decoupling producers and consumers via asynchronous messages | Reactive systems |
| Registry | Tracking versions and metadata of deployable artifacts | ML model management |
These patterns were developed for predictive and generative AI systems. They solve problems like "How do I serve a model?" and "How do I manage versions?"
Analogy — The Architect's Pattern Book
In physical architecture, a pattern book contains designs for common building types: a colonial house, a commercial warehouse, a hospital wing. An architect does not reinvent the hospital floor plan from scratch — they start with a proven pattern and adapt it to the site. Software patterns work the same way: you pick the pattern that matches your problem, then adapt it to your specific constraints.
What changes with Agentic AI?
Agentic AI introduces a new dimension that existing patterns do not fully address: multiple autonomous agents that must:
- Coordinate their actions — Agent A must wait for Agent B's output before proceeding
- Handle partial failures — If Agent C fails after Agents A and B have already completed their work, how do you undo what A and B did?
- Maintain consistent state — All agents must agree on the current state of the workflow, even when some are running on different machines with different data stores
These are not hypothetical edge cases — they are the normal operating conditions of any multi-agent system. The patterns we now need must solve exactly these problems.
Why the Saga Pattern Maps to Agentic AI
The Saga pattern was originally designed for distributed transactions in e-commerce and banking — domains where a single business operation (like placing an order) spans multiple independent services, each with its own database. The core idea:
- A business transaction is broken into a sequence of local transactions
- Each local transaction has a compensating transaction that can undo its effects
- If any step fails, the compensating transactions execute in reverse order
This maps directly onto multi-agent workflows:
| E-commerce Saga | Agent Saga |
|---|---|
| Order Service → Payment Service → Inventory Service | Research Agent → Analysis Agent → Report Agent |
| Each service has its own database | Each agent has its own context and tools |
| Compensating transaction = refund, cancel, restore | Compensating action = discard results, notify user, reset state |
| Failure at step 3 → undo steps 2 and 1 | Failure at Report Agent → undo Analysis and Research outputs |
Pitfall — "Patterns Are Just Theory"
A common student reaction: "I'll just handle failures in my try-catch block." This works for a single monolithic application. It does not work when:
- Each agent runs as a separate service with its own database
- There is no shared transaction coordinator across services
- Network partitions can cause some agents to succeed while others fail
- You need to undo work that was already committed to a remote database
Patterns are not academic exercises. They are battle-tested solutions to problems that will occur in production. Ignoring them means reinventing them poorly under deadline pressure.
Even when you accept that patterns matter, choosing the wrong one creates its own problems.
Pitfall — Choosing the Wrong Pattern
Not every problem needs the Saga pattern. If your agents all share a single database and run in a single process, a simple database transaction is sufficient. Saga introduces complexity — compensating logic, message ordering, failure detection — that is only justified when you genuinely have distributed state. Match the pattern to the actual architecture, not to what sounds impressive.
Recap: Architectural patterns are reusable blueprints for recurring structural problems. The patterns from predictive/generative AI (pipe-and-filter, CQRS, microservices, event-driven, registry) do not fully address the coordination, partial failure, and consistency challenges of multi-agent systems. The Saga pattern, borrowed from distributed transaction management in e-commerce and banking, maps directly onto agentic workflows because both domains face the same fundamental problem: how to maintain consistency across independent, autonomous participants.
Bridge to 7.19: We have established why the Saga pattern is relevant to agentic AI. The next section dives into the specific problem it solves: what exactly is a distributed transaction, and why is it so hard to get right?
Real-world: Companies like Netflix, Uber, and Amazon use architectural patterns extensively. Netflix's microservices architecture handles thousands of services; Uber's trip workflow is a real-world distributed transaction (match rider → assign driver → process payment → track ride). When these systems fail partially, they rely on exactly the kind of compensating logic that the Saga pattern formalizes.
7.19 The Problem: Distributed Transactions
7.19.1 All-or-None Multi-Step Operations
The fundamental tension of microservices. Microservices let teams build, deploy, and scale independently. But that independence comes at a cost: when a single business operation spans multiple services, there is no single database that can guarantee all-or-nothing completion. You have traded monolithic simplicity for distributed flexibility — and now you need a new way to handle failure.
A distributed transaction is a multi-step operation where each step runs as an independent service with its own local data store, and the overall transaction is "all or none" — every step must succeed for the transaction to be considered complete. If any step fails, all preceding steps must be undone.
Purpose — Why Distributed Transactions Exist
Modern applications decompose business operations across multiple independent services. Each service owns its data and runs in its own process — sometimes on different machines, in different data centers. A single user action (like placing an order) triggers a chain of operations across these services.
The core property that makes this hard: atomicity across service boundaries. In a single database, a transaction is atomic by default — either all changes commit or all roll back. Across multiple services, there is no shared database, no shared lock manager, and no global rollback mechanism. Each service commits to its own store independently.
Worked Example — Food Delivery Distributed Transaction
Consider ordering food through a delivery app (Swiggy, Zomato, Uber Eats). The transaction is not a single database write. It is a sequence of four steps, each handled by a different service:
Step 1: Order Service → Create order (select restaurant and items)
Step 2: Payment Service → Process payment (charge the user's account)
Step 3: Inventory Service → Update inventory (decrement restaurant's stock)
Step 4: Delivery Service → Deliver order (assign partner, complete delivery)
Each service has its own database:
- Order DB stores order records
- Payment DB stores transaction logs
- Inventory DB stores stock levels
- Delivery DB stores assignment and tracking data
Only when step 4 succeeds — the food reaches you — is the transaction truly complete.
Inputs and Outputs of a Distributed Transaction
| Aspect | Details |
|---|---|
| Input | A user action that triggers a multi-step business operation (e.g., "Place Order") |
| Steps | A sequence of N local transactions, each executed by an independent service |
| Each step commits locally | Each service writes to its own database and considers its part "done" |
| Output | All N steps succeed → transaction complete. Any step fails → partial state exists |
| Failure state | Some services have committed, others have not — the system is in an inconsistent state |
Trace — What Happens When a Step Fails
Continuing the food delivery example, trace the failure scenario when step 2 (payment) fails:
Step 1: Order Service → ✅ Order created (order_id: #4521)
Step 2: Payment Service → ❌ Payment declined (insufficient funds)
Current system state:
- Order DB: Order #4521 exists (status: "pending")
- Payment DB: No record (payment was never completed)
- Inventory DB: Stock already reserved (was decremented optimistically before payment)
- Delivery DB: No assignment (never reached this step)
The system is now in an inconsistent state — the order exists, inventory may be held, but no payment was received. Without a coordination mechanism, this orphaned order will remain in the database indefinitely.
Another failure trace — step 4 (delivery) fails:
Step 1: Order Service → ✅ Order created
Step 2: Payment Service → ✅ Payment processed (user charged ₹500)
Step 3: Inventory Service → ✅ Stock decremented
Step 4: Delivery Service → ❌ No delivery partner available
Current system state:
- Order DB: Order exists (status: "pending delivery")
- Payment DB: ₹500 charged to user
- Inventory DB: Stock decremented
- Delivery DB: No record
Now the user has been charged for food they will never receive. Inventory is held hostage. The system needs to undo steps 1, 2, and 3 — but each service has already committed its local transaction.
The Critical Difference: Local vs. Global
A single relational database can do BEGIN TRANSACTION ... COMMIT or ROLLBACK and
guarantee atomicity through its internal lock manager and write-ahead log. This is a local
transaction.
A distributed transaction spans multiple databases. There is no equivalent of
BEGIN TRANSACTION that works across Order DB, Payment DB, and Inventory DB simultaneously. This
is not a limitation of a specific technology — it is a fundamental consequence of data being partitioned
across independent services.
When to Use Distributed Transaction Thinking vs. Alternatives
You face a distributed transaction problem when all of these hold:
- The operation spans multiple independent services
- Each service has its own local data store
- The operation requires all-or-none semantics — partial completion is unacceptable
If any of these does not hold, you may not need the Saga pattern:
- Single database? Use a normal database transaction (ACID).
- Partial completion acceptable? Use eventual consistency without compensation.
- Read-only operation? No transaction needed — just query.
- Tightly coupled services? Consider whether you actually need microservices, or whether a modular monolith would be simpler.
When a distributed transaction does exist, the natural next question is: "Why not just use a global transaction protocol?"
Pitfall — "Why Not Just Use Two-Phase Commit (2PC)?"
Two-phase commit (2PC) is a classic protocol for distributed transactions: a coordinator asks all services to "prepare" (phase 1), then asks all to "commit" (phase 2). It guarantees atomicity — but at a heavy cost:
- Blocking: All participants must wait for the slowest before committing
- Single point of failure: If the coordinator crashes after "prepare" but before "commit," all participants are stuck holding locks
- Poor scalability: Latency grows linearly with the number of participants
- Not suitable for long-running transactions: A delivery that takes 30 minutes cannot hold database locks the entire time
For these reasons, 2PC works for short-lived transactions within a data center but fails for the kind of long-lived, cross-service operations that agentic AI workflows require. The Saga pattern is the modern alternative.
Recap: A distributed transaction is a multi-step operation across independent services, each with its own data store, requiring all-or-none semantics. The food delivery example (order → payment → inventory → delivery) shows how partial failures leave the system in an inconsistent state. There is no global rollback mechanism across services — which is exactly the problem the Saga pattern solves.
Bridge to 7.20: We have seen what goes wrong when a distributed transaction fails partway through. The next section introduces the Saga pattern's solution: compensating transactions — a way to undo committed work by executing application-level reverse operations.
Real-world: Every ride-hailing app (Uber, Ola) executes a distributed transaction when you book a ride: match rider → assign driver → estimate fare → process payment → track ride. If the driver cancels after assignment, the system must undo the fare hold, release the driver's schedule slot, and re-enter matching — all without a global rollback. This is a real-world Saga in action.
7.20 The Saga Solution: Compensating Transactions
7.20.1 Forward Transactions and Reverse Compensation
The key question: We know from §7.19 that distributed transactions leave the system in an inconsistent state when a step fails. The obvious question is: "How do you undo work that has already been committed to a remote database?" The Saga pattern's answer is elegant and practical: you don't roll back — you compensate forward by acting in reverse.
A saga is a sequence of local transactions. Each local transaction (T₁, T₂, …, Tₙ) updates the data store of a single service and publishes an event or message to trigger the next transaction. If the sequence completes, the saga is successful.
If transaction Tₙ₊₁ fails, the saga does not magically roll back — because T₁ through Tₙ have already committed to their local databases. Instead, the saga executes compensating transactions (Cₙ, Cₙ₋₁, …, C₁) in reverse order. Each Cᵢ undoes the effects of the corresponding Tᵢ.
Purpose — What the Saga Pattern Solves
The Saga pattern solves the distributed transaction problem by replacing a single global transaction with a sequence of local transactions, each paired with a compensating transaction. The core guarantees:
- Forward path: T₁ → T₂ → T₃ → … → Tₙ (each commits locally)
- Failure at step k: Execute Cₖ₋₁ → Cₖ₋₂ → … → C₁ (compensate in reverse)
- No global lock: Each service commits independently; no blocking
- Eventual consistency: After compensation, all services agree on a consistent state
The saga pattern has clear inputs and outputs for each transaction instance.
Inputs and Outputs
| Aspect | Details |
|---|---|
| Input | A sequence of N forward transactions, each with a defined compensating transaction |
| Forward execution | Each Tᵢ commits to its local service and triggers Tᵢ₊₁ |
| Compensation trigger | If Tₖ fails, the saga initiates backward compensation |
| Output (success) | All T₁…Tₙ complete; business operation is done |
| Output (failure) | Cₖ₋₁…C₁ execute; system returns to a consistent state equivalent to "nothing happened" |
Here is the step-by-step sequence for how compensation executes when a failure occurs.
Steps — How Compensation Works
- Forward chain executes: T₁ commits, sends message → T₂ commits, sends message → … → Tₙ
- Failure detected: Tₖ fails (throws an error, times out, returns a failure event)
- Compensation begins: The saga coordinator (or the failing service) publishes a failure event
- Reverse chain executes: Cₖ₋₁ runs (undoing Tₖ₋₁), then Cₖ₋₂ runs (undoing Tₖ₋₂), … down to C₁
- Consistent state reached: All services now reflect the state as if the saga never started
Worked Example — Food Delivery Compensation Chain
For the food delivery example from §7.19, the forward transactions and their compensating counterparts are:
| Step | Forward Transaction (T) | Compensating Transaction (C) |
|---|---|---|
| 1 | T₁: Create order | C₁: Cancel order |
| 2 | T₂: Process payment | C₂: Refund payment |
| 3 | T₃: Update inventory | C₃: Restore inventory |
| 4 | T₄: Deliver order | C₄: (no compensation — delivery is the terminal step) |
Scenario: T₄ fails (no delivery partner available)
Forward chain (already committed):
T₁ ✅ Order #4521 created
T₂ ✅ Payment of ₹500 processed
T₃ ✅ Inventory decremented (2 items removed from restaurant stock)
Failure:
T₄ ❌ No delivery partner available
Compensation chain (executes in reverse):
C₃ ✅ Restore inventory (add 2 items back to restaurant stock)
C₂ ✅ Refund payment (₹500 returned to user's account)
C₁ ✅ Cancel order (Order #4521 status → "cancelled")
Final state: Consistent — as if the order was never placed.
The compensation chain moves backward through the same communication mechanism that the forward chain used — the same message bus, the same API pattern, but in reverse.
Key insight: Compensating transactions are not automatic database
rollbacks. They are application-level logic — functions that you must write for every forward
transaction. When you call ROLLBACK in SQL, the database engine uses its write-ahead log to undo
changes automatically. A compensating transaction has no such mechanism. You must explicitly code "cancel
order," "refund payment," "restore inventory" as separate business logic. The naming convention uses a verb:
"cancel," "refund," "restore" — the opposite action of the forward verb.
Analogy — The Undo Button vs. Rewriting History
Think of the difference between a database rollback and a compensating transaction:
- Database rollback = pressing Ctrl+Z. The system automatically reverses the change using its internal log. You don't need to know what was changed.
- Compensating transaction = writing a correction letter. You must manually compose the opposite action. If you created an order, you must write "cancel order." If you charged a credit card, you must write "issue refund." The system cannot infer these actions — you must define them.
This is why compensation logic is more work than rollback — but it is the only viable approach in a distributed system where no single entity owns all the data.
The Critical Teaching Point: Compensating Transactions Are Not Idempotent by Default
A compensating transaction undoes a specific forward transaction. But what if the compensation itself fails? For example, the refund API is down when C₂ tries to execute. The saga must handle this:
- Retry with idempotency keys: Ensure that retrying C₂ does not double-refund
- Log the compensation state: Track which compensations have completed and which are pending
- Dead-letter queues: If a compensation fails repeatedly, route it to a queue for manual intervention
Designing compensating transactions that are idempotent (safe to execute multiple times) is a critical engineering requirement that many beginners overlook.
Q: Doesn't rolling back through multiple local databases take a lot of time and compute?
A: The concern is valid, but two factors mitigate it. First, these operations execute in milliseconds to seconds, not minutes. Modern cloud infrastructure and message brokers (Kafka, RabbitMQ) handle these communication flows at enormous scale. Second, the computational and storage capacity available today, especially from cloud providers, is effectively unlimited — the constraint is cost, not compute. Applications at the scale of Swiggy or Zomato on New Year's Eve process millions of concurrent sagas. Their infrastructure auto-scales to handle both successful transactions and compensating rollbacks. However, you raise an important secondary point: user experience. When a saga fails and a rollback occurs, the user does not get their order. Repeated failures — even at 0.1% of transactions — damage trust. Users switch platforms after bad experiences. The technical solution exists, but the business imperative is to minimize failures in the first place.
Pitfall — Forgetting That Compensation Is Not Free
Each compensating transaction has real costs:
- Financial: Refund processing fees, inventory restocking delays
- User experience: The user waited 5 minutes only to see "Order cancelled — refund in 3-5 business days"
- Data consistency window: Between the forward failure and the completion of all compensations, the system is in a transient inconsistent state
The Saga pattern handles technical consistency. It does not eliminate the business cost of failure. Design your forward transactions to succeed as often as possible.
Recap: The Saga pattern replaces global rollback with a chain of local compensating transactions executed in reverse order. Each forward transaction has a corresponding compensating action written as application-level logic (not an automatic database rollback). The food delivery example demonstrates: if delivery fails, restore inventory → refund payment → cancel order. Compensation is fast (milliseconds to seconds) and scalable, but it is not free — there are real financial and user experience costs.
Bridge to 7.21: We know what compensating transactions are. But how do the services actually communicate during a saga? Who triggers the next forward transaction? Who triggers compensation? The next section examines saga participants and the communication mechanisms that connect them.
Real-world: Amazon's order processing uses a saga-like pattern. When an order fails at the fulfillment stage, the system triggers reverse compensations: refund the payment, restock the items, and update the order status — all coordinated through their internal event system. During peak events like Prime Day, they process millions of such compensations per hour.
7.21 Saga Participants and Communication
7.21.1 Local Data Stores and Message Passing
The anatomy of a saga. A saga is not a single program — it is a conversation between independent services. Each service owns its data, does its work, and passes the baton to the next service. Understanding who the participants are and how they talk to each other is essential before you can design either orchestration-based or choreography-based sagas.
Each service in a saga is a saga participant. A saga participant is an independent service that executes one step of the saga — it performs a local transaction, has its own data store, and communicates with other participants through messages. Every participant has its own local data store — this is the defining property. The data store can be relational (PostgreSQL, MySQL), NoSQL (MongoDB, DynamoDB), or even a simple JSON file during prototyping.
Saga Participants — The Building Blocks
| Property | Description |
|---|---|
| Identity | Each participant is an independent service with its own process and deployment unit |
| Local data store | Each participant owns its database exclusively — no shared databases |
| Local transaction | Each participant executes exactly one step of the saga against its own store |
| Compensation pair | Each forward transaction has a corresponding compensating transaction defined |
| Communication | Participants exchange messages (events or commands) to coordinate the saga |
The Food Delivery Participants
In the food delivery saga, the four participants are:
┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Order Service │───▶│ Payment Service │───▶│Inventory Service │───▶│Delivery Service │
│ │ │ │ │ │ │ │
│ DB: orders │ │ DB: payments │ │ DB: stock_levels │ │ DB: assignments │
│ T₁: create │ │ T₂: charge │ │ T₃: decrement │ │ T₄: assign │
│ C₁: cancel │ │ C₂: refund │ │ C₃: restore │ │ C₄: (terminal) │
└──────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────┘
Each box is an independent service. Each "DB" is a separate database. No participant can access another participant's database directly.
Communication Mechanisms — How Participants Talk
Participants communicate through one of two mechanisms:
| Mechanism | How It Works | Latency | Coupling | Tools |
|---|---|---|---|---|
| Synchronous | Direct API calls (REST, gRPC). The caller waits for the response. | Low (milliseconds) | Tight — caller depends on callee being available | REST APIs, gRPC |
| Asynchronous | Event-based messaging through a message broker. The publisher emits an event and continues; subscribers react independently. | Higher (milliseconds to seconds) | Loose — publisher doesn't know or care about subscribers | Kafka, RabbitMQ, AWS SQS |
Asynchronous communication means the sender does not wait for the receiver to process the message. The message broker (Kafka, RabbitMQ, AWS SQS) is an intermediary that stores messages until subscribers are ready to consume them. This decouples participants in time — the publisher can send a message even if the subscriber is temporarily down.
Trace — Message Flow in the Food Delivery Saga
In the food delivery saga, when the order service creates an order, the message flow proceeds like this:
1. Order Service creates order → publishes "OrderCreated" event
Message: {order_id: 4521, user_id: "U100", restaurant_id: "R55", items: [...], total: 500}
- Payment Service (subscribed to "OrderCreated") → receives message
Processes payment → publishes "PaymentProcessed" event
Message: {order_id: 4521, payment_id: "P789", amount: 500, status: "success"}
- Inventory Service (subscribed to "PaymentProcessed") → receives message
Decrements stock → publishes "InventoryUpdated" event
Message: {order_id: 4521, items_decremented: [...], remaining_stock: {...}}
- Delivery Service (subscribed to "InventoryUpdated") → receives message
Assigns delivery partner → publishes "DeliveryAssigned" event
Message: {order_id: 4521, partner_id: "D42", eta: "25 min"}
Each participant only knows about its immediate predecessor's events — they do not need global awareness of the entire saga. The Payment Service does not know about the Delivery Service. This is loose coupling in action.
Why does loose coupling matter?
If participants communicated synchronously (direct API calls), then:
- The Order Service would need to know the addresses of Payment, Inventory, and Delivery services
- If the Payment Service is down, the Order Service would hang or fail
- Adding a new step (e.g., "Send Notification") would require modifying the Order Service
With asynchronous messaging through a broker:
- Participants publish events without knowing who listens
- If the Payment Service is down, the message waits in the broker until it recovers
- Adding a new step just means adding a new subscriber — no existing code changes
Pitfall — Confusing the Two Communication Styles
| Style | Direction | Use Case |
|---|---|---|
| Synchronous (request-response) | Caller → Callee → Caller waits | When you need the result immediately (e.g., "Is this item in stock?") |
| Asynchronous (event-driven) | Publisher → Broker → Subscriber(s), fire-and-forget | When you can proceed without waiting (e.g., "Order was created — whoever cares, react") |
In a saga, the forward chain is typically asynchronous — each step triggers the next through a message broker. This keeps the system responsive and decoupled. But compensation can sometimes use synchronous calls when the undo must happen immediately and confirmation is required.
A subtler but equally dangerous mistake involves how you set up the data stores themselves.
Pitfall — The Single Shared Database Trap
A subtle anti-pattern: each service has its "own" database, but they all run on the same PostgreSQL instance with cross-service SQL joins. This is not true separation. If the database instance goes down, all services fail simultaneously. True saga participants have independent data stores — different database instances, different failure domains.
Recap: A saga participant is an independent service with its own local data store that executes one step of a saga. Participants communicate through synchronous (REST/gRPC) or asynchronous (message broker) mechanisms. Asynchronous communication via message brokers like Kafka, RabbitMQ, or AWS SQS provides loose coupling — participants don't need to know about each other, and temporary failures don't cascade.
Bridge to 7.22: We know the participants and how they communicate. The remaining design question is: who coordinates them? One approach is a central coordinator — the orchestrator — that tells each participant when to execute, like a music conductor cueing each musician. That is the orchestration-based saga.
Real-world: Kafka is the backbone of sagas at companies like LinkedIn (which created Kafka), Uber, and Netflix. When you complete an Uber ride, a "TripCompleted" event flows through Kafka to trigger payment processing, driver rating, receipt generation, and analytics — all as independent subscribers reacting to the same event.
7.22 Orchestration-Based Saga
7.22.1 Centralized Controller Model
The coordination problem. We know from §7.21 that saga participants are independent services that communicate through messages. But who decides which participant runs next? Who tracks whether step 2 completed before step 3 starts? Who notices that step 4 failed and triggers compensation? This section introduces one answer: a centralized coordinator called the orchestrator.
In orchestration, a centralized controller — the orchestrator — manages the entire saga flow. The orchestrator knows the sequence: call service A, receive response, call service B, receive response, call service C, and so on. It also knows the compensation sequence: if service C fails, call C's compensation, then B's compensation, then A's compensation.
Purpose — What the Orchestrator Does
The orchestrator is the brain of an orchestration-based saga. It holds the complete picture:
- The forward sequence: which services to call, in what order
- The state of each step: completed, pending, failed, compensated
- The compensation logic: which compensating transactions to trigger and in what order
- Error handling: retries, timeouts, fallbacks
Without the orchestrator, each participant would need to know the full saga structure — creating tight coupling. The orchestrator absorbs all coordination logic, keeping participants simple and focused on their single task.
The Music Conductor Analogy
Think of the orchestrator as a music conductor standing at the front of an orchestra with a baton. In a symphony orchestra, one person makes hand movements that cue the violinists, then the percussionists, then the vocalists. Each musician watches the conductor and plays their part when signaled. The conductor knows the entire score — every note of every instrument. The musicians know only their own parts.
🎵 Conductor (Orchestrator)
╱ | ╲
╱ | ╲
🎻 Violins 🥁 Drums 🎤 Vocals
(Order) (Payment) (Delivery)
- The conductor cues the violins → they play their part (create order)
- Then cues the drums → they play their part (process payment)
- Then cues the vocals → they play their part (deliver)
If the drums make a mistake, the conductor signals the violins to "undo" their part and resets the piece. The musicians never talk to each other directly — all communication goes through the conductor.
Inputs and Outputs
| Aspect | Details |
|---|---|
| Input | A client request that triggers the saga (e.g., "Place order for user U100") |
| Orchestrator state | Maintains a state machine tracking each step: pending → in_progress → completed or
failed → compensating → compensated |
| Forward execution | Orchestrator calls each participant in sequence, waiting for a response before proceeding |
| Failure handling | On failure, orchestrator triggers compensation chain in reverse |
| Output (success) | All steps complete; orchestrator records final status |
| Output (failure) | All preceding steps compensated; orchestrator records failure reason |
With the orchestrator's role defined, here is how a complete orchestration-based saga executes step by step.
Steps — How Orchestration Works
- Client sends request to the orchestrator (e.g., "Place food delivery order")
- Orchestrator creates a saga instance — a stateful record tracking this specific transaction
- Orchestrator calls T₁ (Order Service: create order) and waits for response
- T₁ succeeds → orchestrator updates state: step 1 = completed, calls T₂
- Orchestrator calls T₂ (Payment Service: process payment) and waits
- T₂ succeeds → orchestrator updates state: step 2 = completed, calls T₃
- T₃ fails → orchestrator detects failure, transitions to compensation mode
- Orchestrator calls C₂ (Payment Service: refund) and waits for confirmation
- C₂ succeeds → orchestrator calls C₁ (Order Service: cancel order)
- C₁ succeeds → saga complete (compensated); orchestrator records final state
Trace — Orchestration State Machine
The orchestrator maintains a state machine for each saga instance:
Saga Instance #4521:
┌─────────────────────────────────────────────────────────────┐
│ Step │ Service │ Forward │ Compensation │ State │
│──────│─────────────│─────────│──────────────│───────────────│
│ 1 │ Order │ T₁ │ C₁ │ ✅ completed │
│ 2 │ Payment │ T₂ │ C₂ │ ✅ completed │
│ 3 │ Inventory │ T₃ │ C₃ │ ❌ failed │
│ 4 │ Delivery │ T₄ │ C₄ │ ⏹ skipped │
└─────────────────────────────────────────────────────────────┘
Compensation triggered:
→ Executing C₂ (refund payment)... ✅
→ Executing C₁ (cancel order)... ✅
→ All compensations complete. Saga status: COMPENSATED
This centralized view is one of the biggest advantages of orchestration — you can inspect the state of any saga at any time.
Now let us see how this looks in a real orchestration tool.
Worked Example — AWS Step Functions as Orchestrator
AWS Step Functions is a managed orchestration service. You define a state machine in JSON that specifies the sequence of Lambda functions or service calls:
{
"StartAt": "CreateOrder",
"States": {
"CreateOrder": {
"Type": "Task",
"Resource": "arn:aws:lambda:order-service",
"Next": "ProcessPayment",
"Catch": [{ "ErrorEquals": ["States.ALL"], "Next": "HandleFailure" }]
},
"ProcessPayment": {
"Type": "Task",
"Resource": "arn:aws:lambda:payment-service",
"Next": "UpdateInventory",
"Catch": [{ "ErrorEquals": ["States.ALL"], "Next": "RefundPayment" }]
},
"UpdateInventory": {
"Type": "Task",
"Resource": "arn:aws:lambda:inventory-service",
"Next": "DeliverOrder",
"Catch": [{ "ErrorEquals": ["States.ALL"], "Next": "RestoreInventory" }]
}
}
}
Step Functions handles retries, error catching, and the compensation path — all defined declaratively. You get a visual dashboard showing every saga instance's state in real time.
Pitfall — The Orchestrator as Single Point of Failure
If the orchestrator crashes mid-saga, all in-flight sagas are stuck. Mitigations:
- Persist orchestrator state: Store the saga state machine in a durable database, not just in memory. On recovery, the orchestrator reads its state and resumes.
- Use managed services: AWS Step Functions, Azure Durable Functions, and Temporal handle orchestrator reliability for you.
- High availability: Run multiple orchestrator instances behind a load balancer with shared state storage.
The orchestrator must be the most reliable component in the system — because everything depends on it.
Another common source of confusion is the relationship between orchestration and communication style.
Pitfall — Orchestration Does Not Mean Synchronous
A common misconception: "Orchestration means everything is synchronous (REST calls)." The pattern does not mandate a specific transport. The orchestrator can use synchronous calls (REST/gRPC) when it needs an immediate response. But it can also use asynchronous messaging (publish a command, wait for a response event) when participants need more time or when you want to decouple timing.
The defining property of orchestration is centralized control — not synchronous communication.
Complexity and Cost of Orchestration
| Factor | Impact |
|---|---|
| Development cost | You must build or configure the orchestrator (state machine, error handling, retry logic) |
| Operational cost | The orchestrator is a service that needs monitoring, scaling, and backup |
| Latency | Each hop through the orchestrator adds a small communication overhead |
| Debugging benefit | Centralized state makes it easy to inspect and debug any saga instance |
| Scalability | The orchestrator can become a bottleneck at very high throughput; mitigate with partitioning |
When to Use Orchestration vs. Alternatives
Use orchestration when:
- The saga has a well-defined, sequential flow (A → B → C)
- You need centralized visibility into the state of each transaction
- Compensation logic is complex and order-dependent
- You want a single place to manage retries, timeouts, and error handling
Consider choreography (next section) when:
- The flow is event-driven and loosely coupled (A publishes event; B, C, D all react independently)
- You want to avoid a single coordination point
- Participants are highly autonomous and should not depend on a central controller
Use a simple database transaction when:
- All operations touch a single database — no distribution problem exists
Recap: The orchestration-based saga uses a centralized orchestrator — like a music conductor with a baton — that manages the entire saga flow. The orchestrator tracks each step's state, calls participants in sequence, and triggers compensation in reverse on failure. AWS Step Functions is a real-world example. The main advantage is centralized visibility and control; the main risk is the orchestrator becoming a single point of failure (mitigated with persistent state and managed services).
Bridge to 7.23: Orchestration puts one brain in charge. But what if you want a more decentralized approach — where participants react to events independently, like runners in a relay race passing a baton? That is choreography-based saga, the subject of the next section.
Real-world: Netflix uses orchestration for its content delivery pipeline. When new content is uploaded, an orchestrator coordinates transcoding, subtitle generation, quality checks, and global distribution — each step handled by an independent service. If transcoding fails, the orchestrator triggers compensation (clean up partial files, notify the content team, reset the upload status).
7.23 Choreography-Based Saga
7.23.1 Decentralized Event-Driven Model
Choreography-based saga is a coordination pattern for distributed transactions where no single service acts as the central controller. Instead, every service communicates through a shared message broker (middleware that routes events between publishers and subscribers, such as Kafka, RabbitMQ, or AWS SQS). Each service knows only its own rule: "When I receive event X, I perform my local transaction and publish event Y." No single service holds a map of the entire sequence.
Hook: Imagine a relay race without a coach standing on the sidelines. Each runner has trained for their specific leg of the race. When the previous runner hands them the baton, they run their segment and hand off to the next runner. No one is calling out instructions from the edge of the track. The coordination is distributed — built into each runner's preparation, not into a central authority. This is exactly how choreography-based sagas work in distributed systems.
7.23.2 Purpose
The purpose of choreography-based saga is to coordinate a multi-step distributed transaction without a central authority. The result is maximum decoupling (services do not need to know about each other's existence — they only know the broker). This makes each service independently deployable, independently scalable, and independently maintainable by separate teams.
7.23.3 Inputs and Outputs
- Input to each service: An event arriving through the message broker (e.g.,
OrderCreated,PaymentProcessed). - Output from each service: A new event published back to the broker after the local
transaction commits (e.g.,
PaymentProcessed,InventoryUpdated). If the local transaction fails, the service publishes a failure event instead (e.g.,InventoryFailed).
Choreography mandates event-driven communication. Every participant publishes to and subscribes from the message broker. This is a fundamental distinction from orchestration, where the coordinator can use either synchronous (REST, gRPC) or asynchronous communication. In choreography, the transport is always asynchronous and broker-mediated.
7.23.4 Step-by-Step Process
Normal flow (happy path):
- An external trigger (e.g., a user placing an order) publishes an initial event —
OrderCreated— to the message broker. - Service A (Order Service) has already committed its local transaction and published this event. Its job is done.
- Service B (Payment Service), subscribed to
OrderCreated, receives the event, processes the payment locally, commits, and publishesPaymentProcessedto the broker. - Service C (Inventory Service), subscribed to
PaymentProcessed, receives the event, updates inventory locally, commits, and publishesInventoryUpdated. - The chain continues until all local transactions have completed. The full saga is complete.
Failure flow (compensation path):
- Suppose Service C (Inventory Service) fails — the requested item is out of stock.
- Instead of publishing
InventoryUpdated, Service C publishesInventoryFailedto the broker. - A compensating consumer (a service subscribed to failure events for that step) picks up
InventoryFailedand triggers the reverse compensation chain. - Payment Service, receiving the compensation trigger, executes its compensating transaction (refund) and
publishes
PaymentReversed. - Order Service, receiving
PaymentReversed, executes its compensating transaction (cancel the order) and publishesOrderCancelled.
Worked example — Food delivery order with choreography:
A customer places an order on a food delivery platform. The saga unfolds across three independent services:
| Step | Service | Event Received | Action | Event Published |
|---|---|---|---|---|
| 1 | Order Service | (user action) | Create order record | OrderCreated |
| 2 | Payment Service | OrderCreated |
Charge customer's payment method | PaymentProcessed |
| 3 | Inventory Service | PaymentProcessed |
Check stock, reserve items | InventoryUpdated |
Now suppose Inventory Service discovers the item is out of stock:
| Step | Service | Event Received | Action | Event Published |
|---|---|---|---|---|
| 4 | Inventory Service | PaymentProcessed |
Stock check fails | InventoryFailed |
| 5 | Payment Service | InventoryFailed |
Refund the customer | PaymentReversed |
| 6 | Order Service | PaymentReversed |
Cancel the order | OrderCancelled |
Notice the reverse order: the last service to fail triggers compensation that flows backward through the chain. Each compensating action is a normal local transaction — it just happens to undo the effect of a previous step.
7.23.5 Tracing the Flow
In choreography, tracing is harder than in orchestration because no single component holds the complete picture. To trace a saga:
- Each event must carry a correlation ID (a shared identifier that links all events belonging to the same saga instance).
- Observability tools (distributed tracing systems like Jaeger or OpenTelemetry) aggregate events from the broker using correlation IDs to reconstruct the full saga flow.
- Log aggregation across all services is essential for debugging.
Q: In orchestration, what communication mechanism does the orchestrator use?
A: The orchestration pattern itself does not prescribe a transport. Typically, orchestrators use synchronous communication — REST API or gRPC calls — because the orchestrator needs to wait for each step's result before deciding the next action. Choreography, by contrast, always uses a message broker — it is inherently event-driven. The distinction is: orchestration allows either synchronous or asynchronous transport; choreography requires asynchronous event-based transport.
Q: In choreography, what happens if a service fails? How does the rollback work?
A: The failing service publishes a failure event to the message broker. Consumers subscribed to failure events for that step trigger the compensating transactions. The message broker routes the failure to the right compensating consumers, which execute in reverse order. The practical demonstration of this will be covered in the next lecture with code examples.
7.23.6 Complexity Dimensions
Choreography-based sagas trade centralized simplicity for distributed flexibility. The key complexity dimensions are:
- Messaging infrastructure: You must set up and operate a message broker (Kafka, RabbitMQ, SQS). The broker becomes critical infrastructure — if it goes down, the entire saga stops.
- Event schema design: Every event type (
OrderCreated,PaymentFailed, etc.) must be carefully designed and versioned. Schema changes can break subscribers. - Distributed tracing: Without a central coordinator, you need correlation IDs and observability tools to follow a saga across services.
- Debugging difficulty: When something goes wrong, you must aggregate logs from multiple services and the broker to piece together what happened.
- Testing complexity: End-to-end tests must simulate event flows across multiple services. Contract testing between publishers and subscribers becomes essential.
- Message ordering: Events may not arrive in strict order. Services must handle out-of-order delivery gracefully (e.g., using sequence numbers or idempotent operations).
- Scaling: The broker scales horizontally to handle more events. Individual services scale independently by adding more consumer instances. There is no single bottleneck.
Common pitfall: Treating choreography as "simpler" because there is no orchestrator to build. In reality, the complexity does not disappear — it shifts from a central coordinator to the event schema design, broker configuration, and distributed tracing infrastructure. Teams new to choreography often underestimate the effort needed for reliable message delivery, idempotent processing, and observability.
7.23.7 When to Use Choreography
Choreography is the right choice when:
- Maximum service independence is the priority — teams own individual services and deploy autonomously.
- The flow is linear or simple — a straightforward chain of steps without complex conditional branching.
- Scalability is critical — no central bottleneck means the system scales horizontally.
- Real-time event-driven systems — IoT event pipelines, order processing, and notification systems.
Choreography is not ideal when:
- The flow has complex branching logic with many conditional paths (orchestration handles this more naturally).
- Centralized visibility is required for compliance or auditing.
- The flow is hard to reason about from events alone — if you need a whiteboard diagram to understand the sequence, an orchestrator might be clearer.
Choreography-based sagas distribute coordination across services via a shared message broker. Each service reacts to events and publishes new events. There is no central controller. This gives maximum decoupling and scalability at the cost of harder tracing and debugging. The relay-race-without-a-coach analogy captures it perfectly: every runner knows their leg, but no one is calling out instructions from the sideline.
7.23.8 Real-World Applications
Food delivery platforms (Swiggy, Zomato) and ride-hailing services (Ola, Uber) use choreography-based coordination for distributed transactions across their microservices architecture. These are multi-billion-dollar companies operating at massive scale — proof that choreography works in production for real-time, high-throughput event-driven systems.
Message brokers like Kafka, RabbitMQ, and AWS SQS provide the backbone for choreography-based sagas. Kafka, in particular, offers durable event storage (events are retained for a configurable period), which enables event sourcing and replay — capabilities that make choreography more robust in practice.
7.24 Orchestration versus Choreography: Trade-offs
7.24.1 Choosing Between Two Coordination Strategies
Orchestration and choreography are the two fundamental strategies for coordinating distributed transactions in a saga. Neither is universally better — they make different trade-offs along dimensions like control, coupling, debugging, and scalability. The right choice depends on your system's constraints: team structure, flow complexity, compliance needs, and scale requirements.
This section provides a decision framework. Use the comparison table below to evaluate which pattern fits your specific situation.
7.24.2 Comparison Table
| Dimension | Orchestration | Choreography |
|---|---|---|
| Control model | Centralized — one orchestrator sees and manages the entire flow | Distributed — no single component has a full view of the flow |
| Coupling | Orchestrator is coupled to all services (knows their interfaces and sequence) | Services are coupled only to the broker (each service is unaware of others) |
| Failure handling | Orchestrator manages retries, timeout logic, and compensation directly | Each service handles its own failures; compensation is triggered by failure events routed through the broker |
| Debugging | Easier — follow the orchestrator's state and execution log in one place | Harder — must aggregate events from the broker and logs from multiple services using correlation IDs |
| Scalability | Orchestrator can become a bottleneck under high load (single point of coordination) | Highly scalable — no central point; broker and services scale horizontally |
| Communication | Flexible — supports synchronous (REST, gRPC) or asynchronous (events) transport | Must be event-driven and asynchronous — all communication flows through the message broker |
| Data consistency | Orchestrator maintains saga state; strong consistency of the coordination layer | No central saga state; eventual consistency across services — events may arrive out of order |
| Testing | Can unit-test the orchestrator in isolation by mocking service responses | Requires contract testing between publishers/subscribers and end-to-end integration tests |
| Message delivery | Orchestrator controls retries explicitly; at-least-once delivery is sufficient | Idempotency is mandatory at every service — message brokers may redeliver events |
| Replay and recovery | Orchestrator persists saga state; failed steps can be retried from the last checkpoint | Full event sourcing needed to reconstruct saga state; replay depends on broker retention policy |
| Observability | Monitor orchestrator state and logs; single point for saga-level metrics | Need distributed tracing (e.g., OpenTelemetry) with correlation IDs across all services and the broker |
| Team structure | Requires coordination — central team maintains the orchestrator; service teams must align interfaces | Autonomous teams — each service team owns their service independently, including its event contracts |
| Technology | AWS Step Functions, Temporal, Camunda, custom orchestrator services | Kafka, RabbitMQ, AWS SQS, Amazon EventBridge |
| Ideal use case | Complex business flows with conditional branching, strict compliance requirements, long-running workflows | Simple linear chains, real-time event streams, high-throughput systems, microservices with independent teams |
| Cognitive overhead | Easier to reason about — the flow is visible in one place (the orchestrator's code or config) | Harder to reason about — the flow is implicit in the event subscriptions; requires understanding the full event graph |
How to read this table: Start with your most binding constraint. If your primary concern is debugging and compliance, orchestration likely wins. If your primary concern is independent team scalability and avoiding a central bottleneck, choreography likely wins. Most real-world systems end up somewhere in between.
7.24.3 The Hybrid Reality
In practice, production systems rarely use pure orchestration or pure choreography. The common hybrid pattern is:
- Orchestration for the critical path — the core business workflow (e.g., order → payment → fulfillment) uses an orchestrator for centralized control, visibility, and reliable compensation.
- Choreography for peripheral flows — side effects like sending confirmation emails, updating analytics, writing audit logs, and triggering notifications are handled via event-driven choreography. These flows are loosely coupled, tolerate eventual consistency, and do not need centralized control.
This hybrid approach gives you the best of both worlds: strong coordination where failures are expensive, and lightweight decoupling where eventual consistency is acceptable.
7.24.4 Decision Checklist
Use this quick checklist to guide your choice:
Choose orchestration when:
- The flow has complex branching logic (if-then-else, parallel forks, conditional compensation)
- You need centralized visibility for compliance, auditing, or regulatory reporting
- The flow is long-running (hours or days) and needs checkpoint-based recovery
- A single team maintains the coordination logic
Choose choreography when:
- The flow is a simple linear chain of steps
- Teams own individual services and need autonomous deployment cycles
- High throughput and low latency are priorities (no central bottleneck)
- The system is already event-driven (e.g., built on Kafka)
Choose a hybrid when:
- The critical business flow needs centralized control
- Side effects (notifications, analytics, audit) can tolerate eventual consistency
- You want to minimize coupling for non-critical paths while keeping the core path tightly coordinated
Common pitfall: Choosing choreography because it seems "simpler" (no orchestrator to build), then discovering that the complexity has shifted to event schema design, distributed tracing, and idempotency guarantees. Conversely, choosing orchestration for a simple linear flow adds unnecessary infrastructure. Match the pattern to the problem.
Orchestration trades decentralization for centralized visibility and control. Choreography trades visibility for maximum decoupling and scalability. The comparison is not about which is "better" — it is about which trade-offs your system can afford. Most production systems use a hybrid: orchestration for the critical path, choreography for side effects.
7.25 The Saga Pattern in Agentic AI Workflows
7.25.1 Agents as Saga Participants
The Saga pattern transfers directly to multi-agent AI systems. Each AI agent becomes a saga participant — an independently executing unit with its own local state, performing a specific sub-task, and communicating results to the next agent via messages or events. The same coordination mechanisms that manage partial failures in microservices apply to agents.
Hook: Think of a consulting firm tackling a complex client engagement. A senior partner (the supervisor) breaks the problem into specialized workstreams: market research, financial modeling, legal review, and strategic recommendations. Each specialist works independently with their own data and tools. If the financial modeler's analysis reveals a flaw, the partner does not restart the entire engagement — they reroute that piece to another modeler, ask for a revised analysis, or adjust the downstream work accordingly. This is exactly how the Saga pattern coordinates multi-agent AI systems.
7.25.2 What Is an Agent's "Local State"?
In the Saga pattern for microservices, each service has its own database. In agentic AI, each agent has its own local state — a conceptually equivalent idea:
- Conversation context: The messages exchanged between the agent and its tools or sub-agents so far.
- Retrieved documents: Results from vector database queries, web searches, or knowledge base lookups.
- Tool outputs: Return values from API calls, code execution, or file operations.
- Intermediate reasoning: Chain-of-thought traces, planning steps, and intermediate conclusions.
This local state is what makes each agent an independent participant. If one agent fails, its local state can be inspected, discarded, or used as input for a retry — just like a compensating transaction inspects and reverses a service's local database changes.
Why the Saga pattern matters for agents: LLM-based agents are not deterministic. They can hallucinate, produce irrelevant output, exceed token budgets, or fail to call the right tools. In a single-agent system, these failures are manageable. In a multi-agent system — where Agent A's output feeds into Agent B's input — a failure in Agent A can cascade through the entire workflow. The Saga pattern provides the coordination mechanism to handle these partial failures gracefully.
7.25.3 The Supervisor Agent as Orchestrator
In an orchestrated agentic saga, one agent takes the role of supervisor (also called an orchestrator agent or manager agent). The supervisor's responsibilities mirror the saga orchestrator:
- Receive the user's goal — e.g., "Plan a 5-day trip to Tokyo within a budget."
- Decompose into sub-tasks — search flights, find hotels, check calendar availability, assemble itinerary, validate budget.
- Assign sub-tasks to specialist agents — a flight search agent, a hotel recommendation agent, a calendar integration agent, a budget analysis agent.
- Collect outputs — each specialist returns its result (or a failure signal).
- Validate results — the supervisor checks whether outputs are coherent, complete, and within constraints.
- Invoke compensating logic on failure — if the hotel agent fails or returns no results, the supervisor does not halt the entire workflow. Instead, it applies a compensation strategy.
Multi-agent travel planning with saga coordination:
| Step | Agent | Task | Success | Failure Action |
|---|---|---|---|---|
| 1 | Flight Agent | Search flights for dates and budget | Returns 3 options | Retry with expanded date range |
| 2 | Hotel Agent | Find hotels near venue | Returns 5 options | Route to fallback agent with broader search |
| 3 | Calendar Agent | Check user availability | Returns free slots | Skip (use defaults) |
| 4 | Budget Agent | Validate total cost within budget | Itinerary approved | Adjust components, re-run steps 1–3 |
| 5 | Supervisor | Assemble final itinerary | Delivered to user | Return partial results with explanation |
If the Hotel Agent fails entirely (returns no results after retry), the supervisor's compensating logic might: (a) route the task to a different hotel search agent with different API access, (b) ask the user for relaxed constraints, or (c) deliver the itinerary without hotel recommendations and flag the gap. The key insight is that the workflow continues despite the partial failure — it does not collapse.
7.25.4 Compensation Strategies for Agents
In microservice sagas, compensating transactions reverse a committed database operation (e.g., refund a payment). In agentic sagas, compensation takes different forms because agents do not commit database transactions — they produce outputs (text, tool calls, structured data) that may need to be corrected or discarded.
The five compensation strategies for agents are:
| Strategy | What It Does | When to Use |
|---|---|---|
| Discard | Throw away the agent's output entirely | Output is irrelevant, hallucinated, or corrupted |
| Retry | Re-run the same agent with the same prompt | Transient failure (API timeout, rate limit) |
| Reprompt | Re-run the agent with a modified or more specific prompt | Output quality was poor but the task is valid |
| Reroute | Send the task to a different agent or model | The original agent is unsuitable for this sub-task |
| Fallback | Use a simpler, pre-computed, or default response | Time or token budget is exhausted; graceful degradation needed |
These strategies map directly to compensating transactions in traditional sagas: they are application-level functions that undo, correct, or work around the effect of a failed or suboptimal step.
7.25.5 Assumptions and Scope
The Saga pattern in agentic AI assumes:
- Agents are independently executing units — each agent runs its own inference, manages its own context window, and can fail independently.
- Communication is structured — agents pass structured messages (not free-form text) to enable the supervisor to parse and validate outputs.
- Failure is expected — LLM agents are probabilistic. The system is designed for failure recovery, not failure prevention.
- Token budgets are finite — retries and reprompts consume tokens and add latency. Compensation strategies must account for cost and time constraints.
Pitfall: Applying the Saga pattern naively to agents — treating every retry as identical. LLM agents are non-deterministic: the same prompt can produce different outputs on different runs. Compensation must account for this variability. A "retry" may succeed not because the transient error resolved, but because the model sampled a different token sequence. Design prompts and validation accordingly.
7.25.6 Industry Validation
Real-world: AWS published guidance on adapting the Saga pattern to agentic AI workflows approximately six months before this lecture. The adaptation recognizes that LLM-based agents, like microservices, are independently executing units with their own state, and they need a coordination mechanism that handles partial failures gracefully. This is not a theoretical exercise — it is an active area of industry adoption.
The pattern's core insight — forward steps followed by reverse compensation on failure — applies unchanged to agentic systems. What changes is the form of compensation: instead of database rollbacks, you have output discarding, reprompting, rerouting, and graceful degradation.
Every AI agent in a multi-agent system is a saga participant with its own local state. A supervisor agent acts as the orchestrator, decomposing goals, assigning sub-tasks, and invoking compensation (discard, retry, reprompt, reroute, fallback) when agents fail. The Saga pattern's reliability mechanisms — designed for microservices — transfer directly to agentic AI, where partial failures are the norm rather than the exception.
7.26 Key Terminology Summary
7.26.1 Glossary of Saga Pattern Terms
This glossary collects the core terms introduced across the Saga pattern sections (7.19–7.25). Each term includes a concise definition, a practical example, and a note on its relevance to agentic AI systems. Use this as a quick reference when reviewing the Saga pattern for exams or production design.
Saga
A sequence of local transactions coordinated to achieve a single logical outcome. Each local transaction has a paired compensating transaction that can undo its effect if a later step fails. The saga ensures that either all steps complete successfully, or the effects of completed steps are reversed.
Example: A food delivery order saga: create order → process payment → update inventory. If inventory update fails, the saga triggers compensating transactions: refund payment, then cancel order.
Saga participant
A service (or agent) that performs one local transaction within the saga and maintains its own data store or local state. Participants do not share databases — they communicate only through events or orchestrator commands.
Example: In the food delivery saga, the Order Service, Payment Service, and Inventory Service are each saga participants. In an agentic system, each AI agent (flight search agent, hotel agent, budget agent) is a participant.
Compensating transaction
The reverse operation that undoes the effect of a previously committed local transaction. Compensating transactions are application-level functions — they are not automatic database rollbacks. They execute in reverse order to unwind the saga's effects.
Example: The compensating transaction for "process payment" is "refund payment." For "create order," it is "cancel order." In agentic AI, compensation might mean "discard agent output" or "retry with a different prompt."
Key distinction: Compensating transactions are written by developers as application logic. They are not database-level undo operations. A payment refund requires calling the payment gateway's refund API — it is a new forward transaction that happens to reverse the effect of the original one.
Orchestration
A centralized saga coordination strategy where a single orchestrator (a dedicated service or function) knows the entire flow, invokes each participant in sequence, handles responses, and manages compensation. The orchestrator is the single source of truth for the saga's state.
Example: AWS Step Functions executing a workflow: the state machine definition specifies the sequence of steps, error handling, and retry logic. Each step invokes a Lambda function or service.
Choreography
A distributed saga coordination strategy where participants communicate solely through events on a message broker. There is no central controller. Each participant reacts to events it receives and publishes new events when its local transaction completes (or fails).
Example: A Kafka-based order pipeline where the Order Service publishes OrderCreated, the
Payment Service subscribes and publishes PaymentProcessed, and the Inventory Service subscribes and
publishes InventoryUpdated. No single service orchestrates the flow.
Distributed transaction
A multi-step operation that spans independent services (or agents), each with its own data store, requiring all-or-none completion. The challenge is that traditional ACID transactions cannot span multiple independent databases — hence the need for the Saga pattern.
Example: Booking a flight requires reserving a seat (airline service), charging a credit card (payment service), and sending a confirmation (notification service). Each step touches a different database.
Message broker
Middleware that receives events from publisher services and routes them to subscriber services. The broker decouples publishers from subscribers — neither needs to know about the other's existence. Common brokers include Apache Kafka (distributed event streaming platform), RabbitMQ (message queuing system), and AWS SQS (managed queue service).
Example: In a choreography-based saga, Service A publishes OrderCreated to a Kafka topic.
Service B, subscribed to that topic, receives the event and processes it. If Service B is temporarily down, the
broker holds the event until Service B recovers.
7.26.2 Terms in Context
How the terms connect in a single scenario:
Consider a multi-agent travel booking system:
- The system executes a distributed transaction — booking a trip requires flight, hotel, and calendar coordination.
- Each agent (flight, hotel, calendar) is a saga participant with its own local state.
- The supervisor agent acts as the orchestrator, managing the flow.
- If the hotel agent fails, the supervisor triggers a compensating transaction — rerouting to a fallback hotel agent.
- Alternatively, the system could use choreography — the flight agent publishes
FlightBookedto a message broker (e.g., Kafka), and the hotel agent subscribes to react. - The entire multi-step coordination is a saga — a sequence of local transactions with compensation.
These seven terms form the vocabulary of distributed transaction coordination. A saga is the overall pattern. Participants execute local transactions. Compensating transactions undo committed steps on failure. Orchestration and choreography are the two coordination strategies. Distributed transactions are the problem sagas solve. Message brokers are the infrastructure backbone of choreography. Understanding how these terms relate — not just their definitions — is the key to applying the pattern correctly.
Exam Guidance Summary
What the Midterm Covers
The midterm syllabus covers everything from the beginning of the course through the Blackboard pattern. Lecture 8 (the next class) will complete the Saga pattern — covering orchestration and choreography in detail with code examples — and introduce the Blackboard pattern. That will be the final topic included in the midterm.
About the Sample Questions
Sample questions will be released this week. They are indicative only — the format (question types, structure) will be representative, but the exact questions on the exam will differ. This course is being offered for the first time, so there are no past papers. Pay close attention to the sample questions when they arrive to understand the expected format, depth, and style.
High-Value Exam Topics
Exam note: Expect questions that ask you to distinguish between batch and real-time serving — when to choose each, the architectural implications, and the trade-offs.
Exam note: The Saga pattern is high-value material. Be prepared to explain compensating transactions (what they are, how they differ from database rollbacks), compare orchestration versus choreography (control, coupling, debugging, scalability), and describe how the pattern applies to agentic AI systems (agents as saga participants, supervisor as orchestrator, compensation strategies).
Key Concepts to Review
| Topic | What to Know |
|---|---|
| Batch vs. Real-time serving | When to choose each, architectural differences (API gateway, model loading, auto-scaling for real-time vs. ETL + database for batch), trade-offs (error blast radius, correction buffer) |
| Saga pattern | Distributed transactions, compensating transactions, orchestration vs. choreography, application to multi-agent systems |
| Model registry | Why versioning matters, what a version captures (dataset + algorithm + model + results), MLflow as the example tool |
| Agentic AI | Five core components (planning, memory, tools, action, reflection), chatbot vs. agent distinction, memory types |
| Feature stores | Training-serving skew, why separating features from business logic matters |
| Orchestration vs. Choreography | 15 comparison dimensions, when to choose each, hybrid patterns |
Do not memorize — understand. The exam tests whether you can apply concepts to new scenarios, not whether you can recite definitions. For example, you might be given a new business scenario and asked to choose between batch and real-time serving, justify your choice, and describe the architecture. Practice applying the patterns, not just listing them.
Key Industry Applications
Model Development and Registry
- MLflow: Open-source model registry used in the lecture demonstration. Integrates with any ML framework (scikit-learn, TensorFlow, PyTorch). Tracks model versions, parameters, metrics, and artifacts. The industry standard for experiment tracking and model lifecycle management.
- AWS SageMaker: Managed ML platform with built-in batch transform jobs. Uses S3 for data storage and DynamoDB for metadata. Provides end-to-end ML workflows from training to deployment.
Saga Orchestration and Workflow Management
- AWS Step Functions: Managed orchestration service for implementing orchestration-based sagas. Defines workflows as state machines with built-in error handling, retries, and parallel execution. The natural choice for orchestrating distributed transactions on AWS.
Agentic AI Tooling
- OpenAI Agent Builder / Agents SDK: Visual and programmatic tools for building multi-agent workflows. Supports Python and TypeScript deployment. Enables the supervisor-and-specialist agent pattern covered in Section 7.25.
Event-Driven Infrastructure
- Message brokers (Kafka, RabbitMQ, AWS SQS): The backbone of choreography-based sagas and event-driven architectures. Kafka provides durable event streaming with replay capability. RabbitMQ offers flexible message routing. SQS provides managed, serverless queuing.
Canonical Industry Examples
- Food delivery (Swiggy, Zomato): The canonical example of distributed transactions managed by the Saga pattern. Order creation, payment processing, inventory management, and delivery coordination are independent services coordinated via sagas.
- Ride hailing (Ola, Uber): Real-time dynamic pricing models and distributed transaction flows. Driver matching, fare calculation, payment processing, and ride tracking each run as independent services.
- Streaming (Disney Hotstar): An example of massive-scale infrastructure handling concurrent sagas — millions of viewers streaming simultaneously, each session involving multiple coordinated services.
Production Agentic Systems
- Codex, Claude: Production-grade agentic AI systems with multi-agent collaboration behind the scenes. These systems demonstrate the coordination patterns discussed in this lecture operating at scale.
Memory and Storage for Agents
- Vector databases (ChromaDB, Pinecone): Storage layer for episodic and semantic memory in agentic systems. Enable retrieval-augmented generation (RAG) by storing and querying document embeddings.
- Gemma 2B, Mistral 7B: Open-weight models suitable for local agent development and experimentation. Lower resource requirements make them accessible for building and testing multi-agent prototypes.
SEML Lecture 7 Notes · Design Patterns for ML Systems: Registry, Serving, and Agentic Orchestration
Sections Breakdown
Section covering The Model Registry Pattern
Section covering MLflow Registry in Practice
Section covering The Registry Pattern Beyond MLflow
Section covering Separating Models from Business Logic
Section covering Feature Stores and Training-Serving Skew
Section covering The Two Serving Paradigms
Section covering Architectural Implications
Section covering When to Use Which?
Section covering From Predictive to Generative to Agentic
Section covering Chatbot versus Agent: A Comparative View
Section covering The Five Core Components of an AI Agent
Section covering Agentic AI Applications in Production Today
Section covering Multi-Agent Communication and the Need for Patterns
Section covering Model Composition Patterns
Section covering Why Memory Matters
Section covering The Four Types of Memory
Section covering Prompt Engineering as a Control Mechanism
Section covering Architectural Thinking: Why Patterns Matter
Section covering The Problem: Distributed Transactions
Section covering The Saga Solution: Compensating Transactions
Section covering Saga Participants and Communication
Section covering Orchestration-Based Saga
Section covering Choreography-Based Saga
Section covering Orchestration versus Choreography: Trade-offs
Section covering The Saga Pattern in Agentic AI Workflows
Section covering Key Terminology Summary
Section covering Exam Guidance Summary
Section covering Key Industry Applications
Exam Revision Notes
Below is the distilled, exam-ready core. Every entry comes from the full explanation above. Use this section for rapid review; return to the main notes when a point needs more context.
The Model Registry Pattern
Must-know: A model registry versions code + data + models together. Three degrees of change (code, dataset, algorithm) each warrant a new version. The registry solves antipatterns like unknown lineage, lost hyperparameters, and irreproducible results.
Top pitfall: Versioning only code (via Git) but not data or models leads to irreproducible results — same script does not guarantee same model.
Self-check: What are the three degrees of change that each warrant a new version in a model registry?
Connects to: 7.2 (MLflow as a concrete implementation), 7.3 (Other registry tools), 7.4 (Registry enables model as replaceable component)
MLflow Registry in Practice
Must-know: MLflow stages: None → Staging → Production → Archived. Each registry entry stores dataset, algorithm, hyperparameters, learned weights, model metrics, and system metrics. Promotion is deliberate, not automatic.
Top pitfall: Confusing hyperparameters (pre-training settings) with learned parameters (weights discovered from data). The registry stores both but they serve different purposes.
Self-check: What are the four lifecycle stages in MLflow's model registry, and what does each mean?
Connects to: 7.1 (registry pattern definition), 7.3 (other registry tools), 7.4 (separating models from business logic)
The Registry Pattern Beyond MLflow
Must-know: The registry is a pattern, not a product. DVC extends Git to data. W&B emphasizes experiment visualization. SageMaker integrates with AWS. All share: version tracking, lineage, stage management, metadata search, comparison.
Top pitfall: Adopting a registry that fights your existing workflow leads the team to bypass it. Pick the tool that fits your infrastructure.
Self-check: Name four model registry tools and their primary emphasis.
Connects to: 7.1 (pattern definition), 7.2 (MLflow as implementation), 7.4 (registry enables model swapping)
Separating Models from Business Logic
Must-know: Separate business logic, model serving, and model artifact — each changes at a different cadence. The registry acts as a switchboard: updating a version pointer swaps the model without code deployment. A stable interface contract is required.
Top pitfall: If the model's input/output contract changes between versions (e.g., new required features), the business logic breaks. Track interface contracts in the registry.
Self-check: Why is it important to separate models from business logic, and what does the registry's role enable in this separation?
Connects to: 7.1 (registry pattern), 7.6 (serving paradigms), 7.14 (model composition patterns)
Feature Stores and Training-Serving Skew
Must-know: Training-serving skew: features at serving time differ from training time, silently degrading predictions. Feature stores prevent this by using the same computation code for both offline and online stores. Two-tier architecture: offline store (batch, training) and online store (low-latency, serving).
Top pitfall: The model does not crash from skew — it silently produces degraded predictions. The insidious nature makes skew hard to detect without a feature store or registry that tracks feature definitions per model version.
Self-check: What is training-serving skew, and how does a feature store prevent it?
Connects to: 7.1 (registry tracks features per model version), 7.2 (MLflow registry), 7.6 (serving paradigms determine feature latency requirements)
The Two Serving Paradigms
Must-know: Batch = scheduled, model loaded during run only, cheaper, correction buffer before predictions reach users. Real-time = on-demand, model always in memory, more expensive, errors reach users immediately. The model accuracy does not change — what changes is the remediation path. Key Q: overnight regression is batch; NEFT fraud detection is real-time. Architecture difference: real-time needs API gateway, auto-scaling, logging, message queues. Gemini 1.0 incident shows real-time risk.
Top pitfall: Defaulting to real-time for everything because it feels more 'advanced.' If the business tolerates minutes/hours of latency, batch is simpler, cheaper, and more forgiving.
Self-check: What is the 'razor knife' analogy, and how does it relate to the Gemini 1.0 incident? Give one use case each for batch and real-time serving.
Connects to: 7.5 (feature stores determine feature latency), 7.7 (infrastructure cost trade-offs), 7.4 (separation enables serving pattern choice)
Architectural Implications
Must-know: Real-time costs scale with traffic (24/7 always-on compute); batch costs scale with data volume (pay for run window only). Real-time demands monitoring, auto-scaling, logging, security. Hybrid patterns: micro-batch (near-real-time), cached predictions (pre-computed serving), async real-time. Decision rule: start batch, go real-time only when latency requirement demands it.
Top pitfall: Over-engineering for real-time when a nightly batch job would suffice. Real-time adds not just infrastructure cost but 24/7 operational burden.
Self-check: How do cost profiles differ between batch and real-time serving? What hybrid approaches exist between the two?
Connects to: 7.6 (serving paradigms definitions), 7.5 (feature store latency requirements), 7.4 (separation enables paradigm choice)
When to Use Which?
Must-know: Choose real-time when the consumer needs results in seconds; choose batch when predictions can wait hours. Hybrid architectures use batch for bulk predictions and real-time for edge cases and live decisions.
Top pitfall: Choosing real-time 'just in case' when batch would suffice — real-time demands API gateways, auto-scaling, always-on models, and 24/7 monitoring.
Self-check: A bank wants to score all transactions from yesterday for compliance reporting, but also block suspicious transactions as they happen. Which serving paradigms should it use?
Connects to: 7.6, 7.7
From Predictive to Generative to Agentic
Must-know: Three paradigms: Predictive AI maps inputs to bounded outputs; Generative AI creates open-ended content; Agentic AI pursues goals with tool use, multi-step reasoning, persistent memory, and autonomous decision-making.
Top pitfall: Confusing an 'agent' (any software that performs a task) with 'Agentic AI' (systems that pursue complex goals autonomously with reasoning, tools, and memory).
Self-check: Name the four architectural shifts that distinguish Agentic AI from Generative AI.
Connects to: 7.10, 7.11
Chatbot versus Agent: A Comparative View
Must-know: Chatbots generate information via request-response; agents generate outcomes via goal-oriented multi-step execution with tools. The five-step prompt methodology (identity, scope, format, token awareness, iterative testing) prevents agentic drift.
Top pitfall: Giving an agent an open-ended prompt with no constraints — this causes agentic drift where the agent expands scope indefinitely (e.g., trip planning → cuisine history → spice trade routes).
Self-check: What are the five steps of the prompt methodology used to control agent behaviour?
Connects to: 7.9, 7.11
The Five Core Components of an AI Agent
Must-know: Five core components: LLM Core (reasoning), Memory (in-context/working, semantic knowledge base, episodic/external, procedural/skills), Action Loop (O-TAR cycle), Tools (capability extension), Planning (task decomposition). Memory types differ by access pattern, lifespan, and scope — not by retrieval mechanism.
Top pitfall: Assuming all memory types are stored the same way — episodic (dynamic, personalized, write-heavy) and semantic (static, global, read-heavy) require different storage and caching strategies, paralleling CQRS.
Self-check: Name the four types of memory in an AI agent and explain why episodic and semantic memory are stored separately.
Connects to: 7.10, 7.15, 7.16
Agentic AI Applications in Production Today
Must-know: Production agentic systems follow a common pattern: high-level goal → autonomous multi-step execution with tools → human review before irreversible action. Four production patterns: fix-my-code, research-a-topic, manage-a-store, monitor-inbox. Most operate at autonomy Levels 2–3.
Top pitfall: Assuming agents in production operate fully autonomously — all current production systems maintain human-in-the-loop review before final, irreversible actions.
Self-check: Describe the common three-element pattern shared by all production agentic applications.
Connects to: 7.10, 7.13
Multi-Agent Communication and the Need for Patterns
Must-know: AI agents in multi-agent systems face the same coordination challenges as microservices. Two key patterns: Saga (sequential transactional workflows with undo) and Blackboard (parallel shared-state collaboration). Agent communication is asynchronous, non-deterministic, and failure-prone — unlike traditional synchronous API calls.
Top pitfall: Assuming agent-to-agent communication is synchronous and deterministic like REST APIs — agent communication is asynchronous (seconds to minutes), non-deterministic (same prompt yields different outputs), and failure-prone (hallucinations, tool errors).
Self-check: Why do multi-agent systems need the same patterns as distributed microservices? Name the two patterns discussed for agent collaboration.
Connects to: 7.14, 7.19, 7.20
Model Composition Patterns
Must-know: Three composition patterns: Ensembles (combine outputs of multiple models via voting/stacking), Sequential decomposition (chain models where each stage's output is the next stage's input), Cascade/two-phase (fast cheap model screens all inputs, slow accurate model handles only uncertain cases). These patterns directly map to multi-agent architectures.
Top pitfall: Ignoring error propagation in sequential pipelines — if stage 1 makes a mistake, all downstream stages inherit and amplify that error. Validate intermediate outputs.
Self-check: How does cascade/two-phase prediction optimise the cost-accuracy trade-off? Give an example.
Connects to: 7.13, 7.19
Why Memory Matters
Must-know: Stateless systems treat every request independently; stateful agentic systems remember across turns, sessions, and agents. Memory is a first-class architectural concern affecting response quality, task continuity, collaboration, cost, and privacy. The four memory types must be designed with modular, stable interfaces.
Top pitfall: Treating memory as an afterthought — it shapes every dimension of an agent system (quality, cost, privacy). Episodic memory storing personal data must support selective deletion for GDPR compliance.
Self-check: Explain why a stateless chatbot fails at multi-turn customer support and how stateful memory solves this.
Connects to: 7.11, 7.16
The Four Types of Memory
Must-know: Four memory types: in-context/working (session), semantic knowledge base (global/static), episodic (per-user/persistent), procedural (transient/task). Each has different lifespan, scope, and storage. Separation prevents retrieval confusion.
Top pitfall: Storing all data in one database — mixing episodic (personalized, dynamic) with semantic (global, static) leads to retrieval confusion where anecdotes pollute factual answers.
Self-check: Name the four types of agent memory and give one real-world analogy for each.
Connects to: 7.11 Five Core Components of an AI Agent, 7.17 Prompt Engineering as a Control Mechanism
Prompt Engineering as a Control Mechanism
Must-know: Five-step prompt methodology: (1) establish identity, (2) constrain search scope, (3) specify output format, (4) monitor tokens, (5) iterate. Unconstrained prompts lead to runaway execution and excessive token consumption.
Top pitfall: Treating prompt engineering as 'set and forget' — production prompts must be versioned, tested, and continuously updated as models and data distributions change.
Self-check: List the five steps of the prompt engineering methodology and explain what happens if you skip step 2 (constrain search scope).
Connects to: 7.10 Chatbot versus Agent, 7.18 Architectural Thinking
Architectural Thinking: Why Patterns Matter
Must-know: The Saga pattern maps from distributed transactions in e-commerce/banking to multi-agent workflows because both face the same challenge: maintaining consistency across independent, autonomous participants with their own state.
Top pitfall: Using try-catch for multi-agent failures — this only works in a monolith with shared state. Distributed agents need formal coordination patterns like Saga.
Self-check: Explain why the Saga pattern, designed for e-commerce, is relevant to agentic AI systems.
Connects to: 7.19 The Problem: Distributed Transactions, 7.20 The Saga Solution
The Problem: Distributed Transactions
Must-know: A distributed transaction spans multiple independent services with separate databases. All-or-none semantics mean partial completion is unacceptable. There is no global rollback — each service commits locally. Two-phase commit (2PC) is unsuitable for long-running transactions due to blocking and poor scalability.
Top pitfall: Assuming a regular database rollback works across services — each service commits independently, so there is no shared transaction boundary. Also: reaching for 2PC without understanding its blocking and scalability limitations.
Self-check: Using the food delivery example, explain what state the system is in after payment succeeds but delivery fails. Why can't a simple database rollback fix this?
Connects to: 7.18 Architectural Thinking, 7.20 The Saga Solution
The Saga Solution: Compensating Transactions
Must-know: Compensating transactions are APPLICATION-LEVEL logic, NOT automatic database rollbacks. Forward chain: T1→T2→T3. Failure at T3: execute C2→C1 (reverse order). Each compensation must be explicitly coded. They should be idempotent (safe to retry).
Top pitfall: Thinking compensating transactions are automatic rollbacks like SQL ROLLBACK — they are manually written business logic. Also: forgetting that compensation itself can fail, requiring idempotency and retry logic.
Self-check: In the food delivery example, what happens if the delivery step fails? List the compensation chain in order. Why is each compensating transaction application-level rather than automatic?
Connects to: 7.19 Distributed Transactions, 7.21 Saga Participants and Communication
Saga Participants and Communication
Must-know: Each saga participant owns its own database (no shared DB). Communication is either synchronous (REST/gRPC, tight coupling) or asynchronous via message brokers (Kafka, RabbitMQ, AWS SQS, loose coupling). Loose coupling means participants publish events without knowing subscribers — adding new steps requires no changes to existing code.
Top pitfall: Confusing shared database instance with separate databases — if all services share one PostgreSQL instance, a single failure takes down all services. Also: using synchronous calls throughout when asynchronous messaging would provide better decoupling.
Self-check: Explain the difference between synchronous and asynchronous communication in a saga. Why is asynchronous communication generally preferred for the forward chain?
Connects to: 7.20 Compensating Transactions, 7.22 Orchestration-Based Saga, 7.23 Choreography-Based Saga
Orchestration-Based Saga
Must-know: Orchestration uses a centralized orchestrator that holds the full saga state machine: forward sequence + compensation sequence + step states. It calls participants in order, detects failures, and triggers reverse compensation. AWS Step Functions is a real-world example. The orchestrator is a single point of failure (mitigate with persistent state).
Top pitfall: Thinking orchestration = synchronous. Orchestration means centralized control, not synchronous transport — the orchestrator can use async messaging. Also: not persisting orchestrator state means a crash loses all in-flight sagas.
Self-check: What is the role of the orchestrator in a saga? How does it handle failure? Why is it compared to a music conductor? What is its main risk and how do you mitigate it?
Connects to: 7.21 Saga Participants, 7.23 Choreography-Based Saga, 7.24 Orchestration vs. Choreography
Choreography-Based Saga
Must-know: Choreography = no central controller, services communicate through a message broker. Failure rollback: failing service publishes failure event, compensating consumers execute reverse transactions. Maximum decoupling but harder to trace/debug.
Top pitfall: Treating choreography as 'simpler' because there is no orchestrator — the complexity shifts to event schema design, broker configuration, and distributed tracing
Self-check: In a choreography-based saga, how does a payment service learn that it needs to refund a customer after an inventory failure downstream?
Connects to: 7.22, 7.24, 7.25
Orchestration versus Choreography: Trade-offs
Must-know: Orchestration = centralized control, easier debugging, potential bottleneck. Choreography = distributed via broker, max decoupling, harder tracing. Hybrid approach is common in production: orchestration for critical path, choreography for side effects.
Top pitfall: Choosing choreography because it seems simpler, then underestimating the complexity of event schema design, distributed tracing, and idempotency guarantees
Self-check: A team is building a payment processing flow with strict compliance auditing. Should they use orchestration or choreography, and why?
Connects to: 7.22, 7.23, 7.25
The Saga Pattern in Agentic AI Workflows
Must-know: Each AI agent = saga participant with own local state. Supervisor agent = orchestrator. Compensation strategies for agents: discard, retry, reprompt, reroute, fallback. Partial failures are the norm in LLM-based systems.
Top pitfall: Treating every agent retry as identical — LLM agents are non-deterministic, so the same prompt can produce different outputs on different runs
Self-check: In a multi-agent research workflow, the summarization agent produces a hallucinated summary. What compensation strategy should the supervisor apply and why?
Connects to: 7.20, 7.22, 7.23, 7.24
Key Terminology Summary
Must-know: Seven key terms: saga (sequence of local transactions with compensation), saga participant (service/agent with own state), compensating transaction (application-level undo, NOT database rollback), orchestration (centralized coordinator), choreography (distributed via broker), distributed transaction (multi-service all-or-none), message broker (Kafka/RabbitMQ/SQS).
Top pitfall: Confusing compensating transactions with database rollbacks — they are application-level functions written by developers
Self-check: What is the difference between a compensating transaction and a database rollback? Give an example of each.
Connects to: 7.19, 7.20, 7.22, 7.23, 7.24
Was this lecture useful?
BitsNotes AI Assistant
Subject Notes AssistantConfigure AI Chat
Choose how to access the chatbotSigned in as
Powered by BitsNotes — 20 messages per day. No API key needed. Want unlimited access? Use "Bring Your Own Key" mode.
Sign in to use AI Chat
Get 20 free AI messages per day to ask questions about your lecture notes. Sign in with Google or GitHub — it takes 5 seconds.
Sign In to BitsNotesSwitch to "Bring Your Own Key" tab above for unlimited access with any OpenAI-compatible provider.