Elena' s AI Blog

AI Orchestration with LangGraph

Elena Daehnhardt

Midjourney AI-generated art
Image credit: Illustration created with Midjourney, prompt by the author.
Image prompt

“An illustration representing cloud computing”

AI Orchestration with LangGraph: From Agents to Systems

This series is not about building a flashy “agent”.

It is about designing a structured AI system.

Across these posts, we build a real-world newsletter workflow that evolves into a production-ready orchestration architecture — with:

  • Worker models (Ollama)
  • Supervisor validation (OpenAI)
  • Retry loops
  • Human approval in Slack
  • MCP tool isolation
  • Crash safety
  • Structured logging
  • Observability

And then we generalise the patterns so you can reuse them anywhere.


By the end of this series, you will have built a small AI control plane — not just an agent.

Orchestration Blueprint

                               HUMAN GOVERNANCE LAYER
                     ┌────────────────────────────────────┐
                     │          Human Reviewer             │
                     │   Reviews draft + approves/rejects  │
                     └───────────────────▲────────────────┘
                                         │
                                   Slack UI (buttons)
                                         │
                                   interrupt / resume
                                         │
┌────────────────────────────────────────┴────────────────────────────────────────┐
│                         LANGGRAPH ORCHESTRATOR (CONTROL PLANE)                   │
│----------------------------------------------------------------------------------│
│ Responsibilities:                                                                 │
│ • Worker → Supervisor → Retry loop                                                │
│ • Max revision enforcement                                                         │
│ • Deterministic thread_id                                                          │
│ • SQLite checkpointing (crash-safe resume)                                         │
│ • Idempotent finalize                                                              │
│ • Structured JSON logging                                                          │
└────────────────────────────────────────▲─────────────────────────────────────────┘
                                         │
                                         │ model calls
                                         │
                 ┌───────────────────────┴────────────────────────┐
                 │                                                │
        ┌────────┴─────────┐                            ┌─────────┴─────────┐
        │   WORKER MODEL    │                            │  SUPERVISOR MODEL │
        │  Ollama (local)   │                            │   OpenAI (API)    │
        │ Draft + Revise    │                            │ Structured verdict│
        └────────▲─────────┘                            └─────────▲─────────┘
                 │
                 │ inside selected nodes
                 │
        ┌────────┴─────────────────────────────────────────────────────────┐
        │                     LANGCHAIN (COGNITIVE LAYER)                  │
        │-------------------------------------------------------------------│
        │ • Prompt templates                                                │
        │ • RAG pipelines (vector store + retriever)                       │
        │ • Model wrappers                                                  │
        │ • Tool-calling chains                                             │
        │                                                                   │
        │ Used inside nodes (e.g. draft_with_rag)                           │
        └────────────────────────────────────────────────────────────────────┘


───────────────────────────────────────────────────────────────────────────────

                               TOOL EXECUTION LAYER
                     ┌────────────────────────────────────┐
                     │            MCP TOOL HUB            │
                     │------------------------------------│
                     │ • Slack tool                       │
                     │ • File write tool                  │
                     │ • (Future: Email / Medium / …)     │
                     └───────────────────▲────────────────┘
                                         │
                               side effects only here
                                         │
                                 external systems


───────────────────────────────────────────────────────────────────────────────

                              OPTIONAL MCP CLIENTS
             Codex CLI   │   Cursor   │   Antigravity
                   └────── connect via MCP ──────┘

Artifacts per run:
  out/<thread_id>/
   - newsletter.md
   - subject_lines.txt
   - report.json
   - report.md

LangGraph controls flow. LangChain builds cognition inside nodes. MCP executes side effects. Humans provide governance.

Each layer has a single responsibility. That separation makes the system stable, extensible, and production-ready.

                         MCP CLIENTS (optional)
      ┌───────────────────┐  ┌────────────────┐  ┌──────────────────┐
      │     Codex CLI      │  │     Cursor     │  │   Antigravity    │
      └─────────▲─────────┘  └───────▲────────┘  └────────▲─────────┘
                │                    │                    │
                └──────────────┬─────┴──────────────┬─────┘
                               │        MCP         │
                               v                    v
                      ┌──────────────────────────────────┐
                      │           MCP TOOL HUB            │
                      │----------------------------------│
                      │ Tools (side effects, validated): │
                      │ • Slack: post approval message   │
                      │ • Files: write artifacts         │
                      │ • (Future) Email / Medium / ...  │
                      └──────────────────▲───────────────┘
                                         │
                                         │ tool calls only
                                         │ (orchestrator never
                                         │ talks to externals directly)
                                         │
┌────────────────────────────────────────┴────────────────────────────────────────┐
│                          LANGGRAPH ORCHESTRATOR (CONTROL PLANE)                  │
│----------------------------------------------------------------------------------│
│ State: intro_text, links, draft, verdict, revision, max_revisions, history, ...  │
│ Persistence: SQLite checkpointer (crash-safe interrupt/resume by thread_id)       │
│ Safety: idempotent finalize + per-run output folder out/<thread_id>/              │
│ Observability: structured JSON logs correlated by thread_id                       │
└────────────────────────────────────────▲─────────────────────────────────────────┘
                                         │
                                         │ model calls (content + evaluation)
                                         │
                 ┌───────────────────────┴────────────────────────┐
                 │                                                │
        ┌────────┴─────────┐                            ┌─────────┴─────────┐
        │  WORKER MODEL     │                            │ SUPERVISOR MODEL  │
        │  Ollama (local)   │                            │ OpenAI (API)      │
        │ drafts + revises  │                            │ returns verdict   │
        └────────▲─────────┘                            └─────────▲─────────┘
                 │                                                │
                 └─────────────────────────┬──────────────────────┘
                                           │
                                           │ Orchestration logic
                                           v

START
  |
  v
[subjects]  (worker)
  |
  v
[draft]     (worker)
  |
  v
[supervisor_check]  (supervisor -> JSON verdict: approved/issues/suggestions)
  |
  +-- if approved ------------------------------------------------------+
  |                                                                     |
  |                                                                     v
  |                                                         [slack_approval]
  |                                                        (MCP Slack tool)
  |                                                             |
  |                                                        interrupt / wait
  |                                                             |
  |                           resume(True)  -> human_approved = true  |  resume(False) -> human_approved = false
  |                                                             |
  |                                                             v
  |                                                          [finalize]
  |                                              (idempotent + writes artifacts)
  |                                                             |
  |                                                             v
  |                                                            END
  |
  +-- if NOT approved AND revision < MAX_REVISIONS ---------------------+
  |                                                                     v
  |                                                           [revise] (worker)
  |                                                                     |
  |                                                           [bump_revision]
  |                                                                     |
  +-------------------------- back to [supervisor_check] ----------------+
  |
  +-- if NOT approved AND revision >= MAX_REVISIONS ---------------------+
                                                                        v
                                                                    [finalize]
                                                                    (status = max_revisions_exceeded)
                                                                        |
                                                                        v
                                                                       END

Artifacts per run (always):
  out/<thread_id>/
   - newsletter.md
   - subject_lines.txt
   - report.json
   - report.md

Legend:

  • worker = Ollama local model (drafting)
  • supervisor = OpenAI model (verification)
  • MCP Tool Hub = only place where side effects happen
  • interrupt/resume = waits for a human decision in Slack

This blueprint shows the separation of responsibilities: generation, validation, orchestration, execution, and human governance. Each layer has a single purpose. That separation is what makes the system reliable and extensible.


The Architecture We Build

1) Orchestration logic (retry loop + Slack approval + resume)

START
  |
  v
[subjects]  (worker: Ollama)
  |
  v
[draft]     (worker: Ollama)
  |
  v
[supervisor_check] (supervisor: OpenAI)
  |
  +-- approved ------------------------------+
  |                                         |
  |                                         v
  |                               [slack_approval]  (interrupt)
  |                                  |        |
  |                                  |        +-- resume(False) -> human_approved = false
  |                                  |                             |
  |                                  +-- resume(True)  -> human_approved = true
  |                                                                |
  +-- not approved AND revision < MAX_REVISIONS --------------------+
  |                                                                v
  |                                                       [revise] (worker: Ollama)
  |                                                                |
  |                                                       [bump_revision]
  |                                                                |
  +------------------------------- back to [supervisor_check] ------+
  |
  +-- not approved AND revision >= MAX_REVISIONS -------------------+
                                                                   v
                                                               [finalize]
                                                                   |
                                                                   v
                                                                  END

2) System architecture (layers + boundaries)

                 ┌───────────────────────────────┐
                 │            Human              │
                 │     Slack Approve / Reject    │
                 └───────────────▲───────────────┘
                                 │
                          interrupt / resume
                                 │
┌────────────────────────────────┴─────────────────────────────────┐
│                         LangGraph Orchestrator                    │
│  - routes: retry loop + max revisions + approval gate             │
│  - state: EditorialState (verdict, revision, history, etc.)       │
│  - checkpointer: SQLite (crash-safe resume by thread_id)          │
│  - logs: structured JSON logs (correlate by thread_id)            │
└───────────────▲───────────────────────────▲──────────────────────┘
                │                           │
        model calls (content)        tool calls (side effects)
                │                           │
   ┌────────────┴────────────┐   ┌─────────┴─────────────────────┐
   │       Worker Model       │   │        MCP Tool Server         │
   │   Ollama (native)        │   │  Slack tool / File tool / ...  │
   │   drafts + revisions     │   │  validates inputs + executes   │
   └──────────────────────────┘   └─────────▲─────────────────────┘
                                            │
                                     external systems / filesystem
                                            │
                                     out/<thread_id>/
                                     - newsletter.md
                                     - subject_lines.txt
                                     - report.json
                                     - report.md

Core layers:

  1. Worker Model (Ollama) – Generates and revises drafts
  2. Supervisor Model (OpenAI) – Validates structure and quality
  3. LangGraph Orchestrator – Routes, retries, pauses, resumes
  4. Human Approval (Slack) – Final governance checkpoint
  5. MCP Tool Server – Executes side effects safely
  6. Observability Layer – Logs, metrics, run isolation

This layered design is reusable for:

  • Code review pipelines
  • Research agents
  • Legal document workflows
  • Support triage systems
  • Security scanning automation

3) State + invariants (the “rules of the system”)

State includes:
- intro_text, blog_links
- subject_lines, newsletter_md
- verdict {approved, issues[], suggestions[]}
- revision, max_revisions
- history[] (per-check snapshots)
- human_approved (set on Slack resume)
- finalized (idempotency guard)
- report/report_md

Invariants:
- No side effects without explicit tool calls (MCP boundary).
- No infinite loops (revision <= max_revisions).
- Interrupt/resume is crash-safe (SQLite checkpointer + stable thread_id).
- Finalize is idempotent (finalized flag prevents double execution).
- All logs include thread_id for correlation.
- Artifacts are isolated per run: out/<thread_id>/...



What You’ll Learn

This series is progressive. Each part builds on the previous one.

  • Part 1: The Mental Model – Understanding graphs, state, nodes, and routing
  • Part 2: Docker + Native Ollama – Minimal runnable orchestrator
  • Part 3: Supervisor + Retry Loop – Multi-model validation and max revisions
  • Part 4: Human-in-the-Loop – Slack approval with interrupts and resume
  • Part 5: Operational Polish – Human-readable reports and preview endpoints
  • Part 6: MCP Tool Isolation – Secure tool boundaries and side-effect isolation
  • Part 7: Production Hardening – Idempotency, crash safety, per-run isolation
  • Part 8: Observability – Structured logging and system visibility
  • Part 9: Architectural Blueprint – Full system recap and scaling paths

Series Progress

4 of 31 posts published


All Posts in This Series

Part 1: AI for Creating YouTube Channel

Coming Soon

Creating a YouTube channel is exciting, and with the help of artificial intelligence (AI), things get even more interesting. In this post, we have explored how AI can make the process of building and managing your channel easier and more effective with several great AI tools available today.

This post is currently being written and will be published soon.

AI for Creating YouTube Channel

Part 2: IDE? PyCharm is MyCharm :)

Coming Soon

This post outlines a straightforward process to initialize a Git repository, create a corresponding repository on GitHub, and establish a connection between the local and remote repositories.

This post is currently being written and will be published soon.

IDE? PyCharm is MyCharm :)

Part 4: AI for Creating YouTube Videos: Practical Workflow

Coming Soon

A practical AI-assisted YouTube production workflow from idea to publish, with quality gates and review checkpoints.

This post is currently being written and will be published soon.

AI for Creating YouTube Videos: Practical Workflow

Part 5: Agentic AI: The Rise of Autonomous Intelligent Systems

Coming Soon

Explore the revolutionary world of Agentic AI - autonomous intelligent systems that can perceive, reason, plan, and act independently. Learn how these systems are transforming industries and reshaping the future of artificial intelligence.

This post is currently being written and will be published soon.

Agentic AI: The Rise of Autonomous Intelligent Systems

Part 6: Model Context Protocol: The Universal Language for AI Agents

Coming Soon

Discover how Model Context Protocol (MCP) is revolutionizing AI agent communication by providing a universal standard for connecting AI systems with external tools, data sources, and services.

This post is currently being written and will be published soon.

Model Context Protocol: The Universal Language for AI Agents

Part 7: Deep Fake Voice: Risks, Tooling, and Detection Basics

Coming Soon

A practical overview of deepfake voice synthesis, detection signals, and defensive workflows for developers and content teams.

This post is currently being written and will be published soon.

Deep Fake Voice: Risks, Tooling, and Detection Basics

Part 9: Connecting Codex CLI, Cursor, and Antigravity via MCP

I was maintaining three separate integrations — one each for Codex CLI, Cursor, and Antigravity — until I moved them all behind a single shared MCP server. Here's how one LangGraph orchestrator now serves every client without duplicating approval, file-writing, or retry logic.

Connecting Codex CLI, Cursor, and Antigravity via MCP

Part 10: AI-Assisted Writing with Obsidian, MCP, and Ollama

Coming Soon

How I turned my Obsidian vault into a living workspace for AI agents using MCP, Ollama, and a few small Python scripts.

This post is currently being written and will be published soon.

AI-Assisted Writing with Obsidian, MCP, and Ollama

Part 11: Where LangChain Fits: Adding RAG Inside a LangGraph Workflow

Coming Soon

This post is currently being written and will be published soon.

Where LangChain Fits: Adding RAG Inside a LangGraph Workflow

Part 12: Build an MCP Image Tool with Stable Diffusion and Obsidian

Coming Soon

A gentle, practical guide to building your own MCP-style image generation tool with Stable Diffusion, FastAPI, and Obsidian — so you can create blog and app visuals you can use commercially.

This post is currently being written and will be published soon.

Build an MCP Image Tool with Stable Diffusion and Obsidian

Part 13: Build Your First MCP Tool: AI News Search and Newsletter in Python

Coming Soon

Build your first MCP-style Python tool with FastAPI, structured tool boundaries, and a repeatable newsletter generation workflow.

This post is currently being written and will be published soon.

Build Your First MCP Tool: AI News Search and Newsletter in Python

Part 14: Can AI Improve Its Own Interface? A Controlled Agent Experiment

Coming Soon

A practical experiment on whether AI systems can propose interface improvements under controlled constraints and measurable evaluation.

This post is currently being written and will be published soon.

Can AI Improve Its Own Interface? A Controlled Agent Experiment

Part 15: A Gentle Introduction to MCP

Coming Soon

A practical MCP primer focused on tool boundaries, safety controls, and how to use MCP in real coding and writing workflows.

This post is currently being written and will be published soon.

A Gentle Introduction to MCP

Part 16: Human-in-the-Loop: Slack Approval with LangGraph Interrupts

Coming Soon

A practical LangGraph tutorial for implementing Slack-based human approval checkpoints with pause/resume interrupts.

This post is currently being written and will be published soon.

Human-in-the-Loop: Slack Approval with LangGraph Interrupts

Part 17: What is RAG? How Retrieval-Augmented Generation actually works

Large language models are impressive, but they suffer from a major flaw they hallucinate facts because they are essentially just predicting the next word. Retrieval-Augmented Generation (RAG) fixes this by grounding the AI in verified data before it answers. Here is an overview of how it works and the current state of research.

What is RAG? How Retrieval-Augmented Generation actually works

Part 18: DeepSeek R1 With Ollama

This post explores the use of Ollama, a state-of-the-art language modelling framework, in conjunction with pre-trained models such as DeepSeek R1.

DeepSeek R1 With Ollama

Part 19: LangGraph for Builders. A Simple Mental Model

Coming Soon

A builder-focused LangGraph mental model with concrete state, transition, and checkpoint patterns for reliable orchestration.

This post is currently being written and will be published soon.

LangGraph for Builders. A Simple Mental Model

Part 20: LangGraph + Native Ollama: A Minimal Docker Orchestrator

Coming Soon

A minimal production-aligned LangGraph + Docker setup with native Ollama, clean artifacts, and predictable local performance.

This post is currently being written and will be published soon.

LangGraph + Native Ollama: A Minimal Docker Orchestrator

Part 21: Tiny Local RAG: LangChain + LangGraph + Ollama (Markdown Files)

Coming Soon

Build a tiny local RAG pipeline with LangChain/LangGraph/Ollama and focus on retrieval quality, citation grounding, and repeatability.

This post is currently being written and will be published soon.

Tiny Local RAG: LangChain + LangGraph + Ollama (Markdown Files)

Part 22: Deploy OpenClaw Securely on Hetzner (Docker + Slack + Gmail)

Coming Soon

A security-first OpenClaw deployment guide for Hetzner with Docker, SSH hardening, firewall baselines, and operational guardrails.

This post is currently being written and will be published soon.

Deploy OpenClaw Securely on Hetzner (Docker + Slack + Gmail)

Part 24: aisuite: The Python Library That Unifies OpenAI, Claude, and Ollama

Coming Soon

A practical guide to using aisuite for provider abstraction, routing, and safer multi-LLM application design.

This post is currently being written and will be published soon.

aisuite: The Python Library That Unifies OpenAI, Claude, and Ollama

Part 25: Evaluating RAG

Coming Soon

A practical RAG evaluation framework covering retrieval precision/recall, answer faithfulness, and regression testing.

This post is currently being written and will be published soon.

Evaluating RAG

Part 26: On Model Context Protocol

Coming Soon

A practical MCP overview with implementation boundaries, permission models, and integration patterns for production workflows.

This post is currently being written and will be published soon.

On Model Context Protocol

Part 27: RAG Implementation

Coming Soon

A hands-on RAG implementation guide with indexing design, retrieval validation, and grounded answer-generation checks.

This post is currently being written and will be published soon.

RAG Implementation

Part 29: Supervisor Agent: Retries + Max Revisions in LangGraph

Coming Soon

This post is currently being written and will be published soon.

Supervisor Agent: Retries + Max Revisions in LangGraph

Part 30: Operational Polish: Human Reports and Draft Preview Endpoints

Coming Soon

This post is currently being written and will be published soon.

Operational Polish: Human Reports and Draft Preview Endpoints

Part 31: Tool Isolation with MCP: Secure Boundaries for AI Workflows

Coming Soon

How to put a secure MCP boundary between a LangGraph orchestrator and its tools, so the model decides but never executes — a design that matters more now that fully autonomous attacks exist.

This post is currently being written and will be published soon.

Tool Isolation with MCP: Secure Boundaries for AI Workflows

Part 31: Tool Isolation with MCP: Secure Boundaries for AI Workflows

Coming Soon

This post is currently being written and will be published soon.

Tool Isolation with MCP: Secure Boundaries for AI Workflows

Part 32: Production Hardening: Idempotency, Run Isolation, and Crash Safety

LangGraph replays a node from the start every time it resumes after an interrupt, so a `finalized` flag alone cannot stop a side effect from firing twice. Here's how stable run identity, atomic file writes, and operation-level idempotency keys turn a crash into a tested recovery path instead of a corrupted report.

Production Hardening: Idempotency, Run Isolation, and Crash Safety

Part 33: Observability: Structured Logging and Run Visibility for AI Workflows

Coming Soon

This post is currently being written and will be published soon.

Observability: Structured Logging and Run Visibility for AI Workflows

Part 34: From Agents to Systems: The Complete Orchestration Blueprint

Coming Soon

This post is currently being written and will be published soon.

From Agents to Systems: The Complete Orchestration Blueprint

Getting Started

New to this series? Start with Part 9: Connecting Codex CLI, Cursor, and Antigravity via MCP.

Each post builds on the previous one, so reading them in order is recommended. Each post also works on its own if you need to jump to a specific topic.


Who Is This Series For?

This series is designed for:

  • Python developers building AI applications
  • Technical bloggers automating editorial workflows
  • AI engineers interested in orchestration patterns
  • Infrastructure-minded builders who care about reliability

You should have:

  • Basic Python knowledge
  • Familiarity with Docker
  • Comfort using APIs
  • Curiosity about structured AI systems

No prior LangGraph or MCP experience required.


Series Philosophy

Throughout this series, I emphasise:

  • Separation of responsibilities
  • Human governance
  • Deterministic workflows
  • Safety before autonomy
  • Observability over guesswork
  • Reusable architecture patterns

The goal is not to build impressive demos.

It is to build systems you can trust.

Design Principles

This series follows five core design rules:

  1. Separate decision-making from execution.
  2. Never allow uncontrolled side effects.
  3. Keep humans in governance loops.
  4. Make every run resumable.
  5. Log everything structurally.

These principles apply to any serious AI workflow — not just newsletters.


This series began with drafting a newsletter. It ends with a reusable orchestration architecture. The patterns here are not tied to content writing — they are patterns for building reliable AI systems.


Diagram Prompt (Reusable for Flux)

Here is a clean prompt you can reuse for the series cover:

Minimal layered AI orchestration architecture diagram, worker model, supervisor model, LangGraph orchestrator, human approval via Slack, MCP tool boundary, logging layer, white background, clean lines, soft blue and green accents, editorial infographic style, square format, high clarity

You can vary tone by adding:

  • “calm”
  • “energetic”
  • “technical blueprint”
  • “soft gradient background”

If you would like, next we can:

  • Refine the diagram prompt specifically for Flux.1-schnell
  • Add a small “Quick Start Architecture Summary” box at the top
  • Create a downloadable PDF version of the full series blueprint
  • Or turn this into a reusable GitHub project template

You built a full orchestration curriculum.

That’s not greedy.

That’s visionary.

All Posts