<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://tuanquang.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://tuanquang.com/" rel="alternate" type="text/html" /><updated>2026-04-02T04:24:13+00:00</updated><id>https://tuanquang.com/feed.xml</id><title type="html">Tuan Quang</title><subtitle>Your Name&apos;s academic portfolio</subtitle><author><name>Tuan Quang</name><email>anhtuanquang2016@gmail.com</email></author><entry><title type="html">Multi agent with LangChain</title><link href="https://tuanquang.com/posts/2026/01/multi-agent-with-langchain/" rel="alternate" type="text/html" title="Multi agent with LangChain" /><published>2026-01-01T00:00:00+00:00</published><updated>2026-01-01T00:00:00+00:00</updated><id>https://tuanquang.com/posts/2026/01/multi-agent</id><content type="html" xml:base="https://tuanquang.com/posts/2026/01/multi-agent-with-langchain/"><![CDATA[<h1 id="building-multi-agent-systems-with-langchain-a-production-ready-guide">Building Multi-Agent Systems with LangChain: A Production-Ready Guide</h1>

<hr />

<h2 id="introduction">Introduction</h2>

<p>As LLM applications grow in complexity, single-agent architectures start to hit their limits. Tasks that require planning, tool use, memory, and collaboration across different domains demand something more powerful — <strong>multi-agent systems</strong>.</p>

<p>In this post, we’ll walk through how to build a robust multi-agent pipeline using <strong>LangChain</strong> and <strong>LangGraph</strong>, covering everything from the core concepts to production patterns you can deploy today.</p>

<hr />

<h2 id="what-is-a-multi-agent-system">What Is a Multi-Agent System?</h2>

<p>A <strong>multi-agent system (MAS)</strong> is an architecture where multiple autonomous LLM-powered agents collaborate to solve complex tasks. Each agent has:</p>

<ul>
  <li>A <strong>role</strong> (e.g., Researcher, Writer, Critic)</li>
  <li>Access to specific <strong>tools</strong> (web search, code execution, databases)</li>
  <li>Its own <strong>memory</strong> and <strong>context</strong></li>
  <li>A defined <strong>communication protocol</strong> with other agents</li>
</ul>

<p>Think of it like a team of specialists — instead of one generalist trying to do everything, you delegate work to the right expert.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>User Request
     │
     ▼
┌─────────────┐
│  Supervisor │  ← Orchestrates and delegates
│    Agent    │
└──────┬──────┘
       │
  ┌────┴─────┬──────────┐
  ▼          ▼          ▼
┌──────┐  ┌──────┐  ┌──────┐
│ RAG  │  │Code  │  │Write │
│Agent │  │Agent │  │Agent │
└──────┘  └──────┘  └──────┘
</code></pre></div></div>

<hr />

<h2 id="why-langchain--langgraph">Why LangChain + LangGraph?</h2>

<p><strong>LangChain</strong> provides the building blocks:</p>
<ul>
  <li>Standardized LLM interfaces</li>
  <li>Tool and retriever abstractions</li>
  <li>Memory and prompt management</li>
</ul>

<p><strong>LangGraph</strong> extends LangChain with:</p>
<ul>
  <li>Stateful, graph-based agent orchestration</li>
  <li>Conditional routing between nodes</li>
  <li>Built-in support for cycles, checkpoints, and human-in-the-loop</li>
</ul>

<p>Together, they give you everything needed to build production-grade multi-agent pipelines.</p>

<hr />

<h2 id="core-concepts-before-we-build">Core Concepts Before We Build</h2>

<h3 id="1-agent-node">1. Agent Node</h3>
<p>Each agent in LangGraph is a <strong>node</strong> in a directed graph. A node receives state, processes it (via LLM + tools), and returns updated state.</p>

<h3 id="2-edges--routing">2. Edges &amp; Routing</h3>
<p><strong>Edges</strong> connect nodes. You can define:</p>
<ul>
  <li><strong>Static edges</strong> — always go from A → B</li>
  <li><strong>Conditional edges</strong> — route dynamically based on the agent’s output</li>
</ul>

<h3 id="3-shared-state">3. Shared State</h3>
<p>All agents share a <strong>state object</strong> — a typed dictionary passed through the graph. This is how agents communicate with each other.</p>

<h3 id="4-supervisor-pattern">4. Supervisor Pattern</h3>
<p>A <strong>Supervisor Agent</strong> is responsible for:</p>
<ul>
  <li>Receiving the user’s task</li>
  <li>Deciding which agent to call next</li>
  <li>Aggregating final results</li>
</ul>

<hr />

<h2 id="project-setup">Project Setup</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install </span>langchain langgraph langchain-openai langchain-community
</code></pre></div></div>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># .env
</span><span class="n">OPENAI_API_KEY</span><span class="o">=</span><span class="n">your_key_here</span>
<span class="n">TAVILY_API_KEY</span><span class="o">=</span><span class="n">your_key_here</span>  <span class="c1"># For web search tool
</span></code></pre></div></div>

<hr />

<h2 id="step-1-define-the-shared-state">Step 1: Define the Shared State</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TypedDict</span><span class="p">,</span> <span class="n">Annotated</span><span class="p">,</span> <span class="n">List</span>
<span class="kn">from</span> <span class="nn">langgraph.graph.message</span> <span class="kn">import</span> <span class="n">add_messages</span>

<span class="k">class</span> <span class="nc">AgentState</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
    <span class="n">messages</span><span class="p">:</span> <span class="n">Annotated</span><span class="p">[</span><span class="nb">list</span><span class="p">,</span> <span class="n">add_messages</span><span class="p">]</span>
    <span class="n">next_agent</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">task</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">research_output</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">final_output</span><span class="p">:</span> <span class="nb">str</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">add_messages</code> annotation ensures messages are <strong>appended</strong>, not overwritten, as they flow through the graph.</p>

<hr />

<h2 id="step-2-create-the-tools">Step 2: Create the Tools</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">langchain_community.tools.tavily_search</span> <span class="kn">import</span> <span class="n">TavilySearchResults</span>
<span class="kn">from</span> <span class="nn">langchain_core.tools</span> <span class="kn">import</span> <span class="n">tool</span>

<span class="c1"># Web search tool
</span><span class="n">search_tool</span> <span class="o">=</span> <span class="n">TavilySearchResults</span><span class="p">(</span><span class="n">max_results</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>

<span class="c1"># Custom code execution tool
</span><span class="o">@</span><span class="n">tool</span>
<span class="k">def</span> <span class="nf">run_python</span><span class="p">(</span><span class="n">code</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="s">"""Execute Python code and return the output."""</span>
    <span class="kn">import</span> <span class="nn">io</span><span class="p">,</span> <span class="n">contextlib</span>
    <span class="n">output</span> <span class="o">=</span> <span class="n">io</span><span class="p">.</span><span class="n">StringIO</span><span class="p">()</span>
    <span class="k">with</span> <span class="n">contextlib</span><span class="p">.</span><span class="n">redirect_stdout</span><span class="p">(</span><span class="n">output</span><span class="p">):</span>
        <span class="k">exec</span><span class="p">(</span><span class="n">code</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">output</span><span class="p">.</span><span class="n">getvalue</span><span class="p">()</span>
</code></pre></div></div>

<hr />

<h2 id="step-3-build-the-individual-agents">Step 3: Build the Individual Agents</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">langchain_openai</span> <span class="kn">import</span> <span class="n">ChatOpenAI</span>
<span class="kn">from</span> <span class="nn">langchain_core.prompts</span> <span class="kn">import</span> <span class="n">ChatPromptTemplate</span><span class="p">,</span> <span class="n">MessagesPlaceholder</span>
<span class="kn">from</span> <span class="nn">langgraph.prebuilt</span> <span class="kn">import</span> <span class="n">create_react_agent</span>

<span class="n">llm</span> <span class="o">=</span> <span class="n">ChatOpenAI</span><span class="p">(</span><span class="n">model</span><span class="o">=</span><span class="s">"gpt-4o"</span><span class="p">,</span> <span class="n">temperature</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>

<span class="c1"># --- Research Agent ---
</span><span class="n">research_agent</span> <span class="o">=</span> <span class="n">create_react_agent</span><span class="p">(</span>
    <span class="n">llm</span><span class="p">,</span>
    <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">search_tool</span><span class="p">],</span>
    <span class="n">state_modifier</span><span class="o">=</span><span class="p">(</span>
        <span class="s">"You are a Research Agent. Your job is to gather accurate, "</span>
        <span class="s">"up-to-date information on the given topic using web search. "</span>
        <span class="s">"Be thorough and cite your sources."</span>
    <span class="p">)</span>
<span class="p">)</span>

<span class="c1"># --- Code Agent ---
</span><span class="n">code_agent</span> <span class="o">=</span> <span class="n">create_react_agent</span><span class="p">(</span>
    <span class="n">llm</span><span class="p">,</span>
    <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">run_python</span><span class="p">],</span>
    <span class="n">state_modifier</span><span class="o">=</span><span class="p">(</span>
        <span class="s">"You are a Code Agent. You write clean, efficient Python code "</span>
        <span class="s">"to solve analytical or data processing tasks. Always test your code."</span>
    <span class="p">)</span>
<span class="p">)</span>

<span class="c1"># --- Writer Agent ---
</span><span class="n">writer_agent</span> <span class="o">=</span> <span class="n">create_react_agent</span><span class="p">(</span>
    <span class="n">llm</span><span class="p">,</span>
    <span class="n">tools</span><span class="o">=</span><span class="p">[],</span>
    <span class="n">state_modifier</span><span class="o">=</span><span class="p">(</span>
        <span class="s">"You are a Writer Agent. Given research and data, you produce "</span>
        <span class="s">"clear, concise, and well-structured written content for technical audiences."</span>
    <span class="p">)</span>
<span class="p">)</span>
</code></pre></div></div>

<hr />

<h2 id="step-4-build-the-supervisor">Step 4: Build the Supervisor</h2>

<p>The Supervisor is the brain of the system — it reads the current state and decides which agent to invoke next.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">langchain_core.output_parsers</span> <span class="kn">import</span> <span class="n">JsonOutputParser</span>
<span class="kn">from</span> <span class="nn">pydantic</span> <span class="kn">import</span> <span class="n">BaseModel</span>

<span class="n">SUPERVISOR_SYSTEM_PROMPT</span> <span class="o">=</span> <span class="s">"""
You are a Supervisor orchestrating a team of AI agents. 
Given the current task and conversation, decide who should act next.

Available agents:
- researcher: Gathers information from the web
- coder: Writes and executes Python code
- writer: Produces final written output
- FINISH: The task is complete

Respond ONLY with a JSON object: next
"""</span>

<span class="k">class</span> <span class="nc">RouterOutput</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
    <span class="nb">next</span><span class="p">:</span> <span class="nb">str</span>

<span class="k">def</span> <span class="nf">supervisor_node</span><span class="p">(</span><span class="n">state</span><span class="p">:</span> <span class="n">AgentState</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">AgentState</span><span class="p">:</span>
    <span class="n">messages</span> <span class="o">=</span> <span class="p">[</span>
        <span class="p">{</span><span class="s">"role"</span><span class="p">:</span> <span class="s">"system"</span><span class="p">,</span> <span class="s">"content"</span><span class="p">:</span> <span class="n">SUPERVISOR_SYSTEM_PROMPT</span><span class="p">},</span>
        <span class="o">*</span><span class="n">state</span><span class="p">[</span><span class="s">"messages"</span><span class="p">],</span>
    <span class="p">]</span>
    <span class="n">response</span> <span class="o">=</span> <span class="n">llm</span><span class="p">.</span><span class="n">with_structured_output</span><span class="p">(</span><span class="n">RouterOutput</span><span class="p">).</span><span class="n">invoke</span><span class="p">(</span><span class="n">messages</span><span class="p">)</span>
    <span class="k">return</span> <span class="p">{</span><span class="s">"next_agent"</span><span class="p">:</span> <span class="n">response</span><span class="p">.</span><span class="nb">next</span><span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="step-5-define-agent-node-wrappers">Step 5: Define Agent Node Wrappers</h2>

<p>Each agent node wraps the underlying agent and updates the shared state.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">research_node</span><span class="p">(</span><span class="n">state</span><span class="p">:</span> <span class="n">AgentState</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">AgentState</span><span class="p">:</span>
    <span class="n">result</span> <span class="o">=</span> <span class="n">research_agent</span><span class="p">.</span><span class="n">invoke</span><span class="p">(</span><span class="n">state</span><span class="p">)</span>
    <span class="k">return</span> <span class="p">{</span>
        <span class="s">"messages"</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s">"messages"</span><span class="p">],</span>
        <span class="s">"research_output"</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s">"messages"</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="n">content</span>
    <span class="p">}</span>

<span class="k">def</span> <span class="nf">code_node</span><span class="p">(</span><span class="n">state</span><span class="p">:</span> <span class="n">AgentState</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">AgentState</span><span class="p">:</span>
    <span class="n">result</span> <span class="o">=</span> <span class="n">code_agent</span><span class="p">.</span><span class="n">invoke</span><span class="p">(</span><span class="n">state</span><span class="p">)</span>
    <span class="k">return</span> <span class="p">{</span><span class="s">"messages"</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s">"messages"</span><span class="p">]}</span>

<span class="k">def</span> <span class="nf">writer_node</span><span class="p">(</span><span class="n">state</span><span class="p">:</span> <span class="n">AgentState</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">AgentState</span><span class="p">:</span>
    <span class="n">result</span> <span class="o">=</span> <span class="n">writer_agent</span><span class="p">.</span><span class="n">invoke</span><span class="p">(</span><span class="n">state</span><span class="p">)</span>
    <span class="k">return</span> <span class="p">{</span>
        <span class="s">"messages"</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s">"messages"</span><span class="p">],</span>
        <span class="s">"final_output"</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s">"messages"</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="n">content</span>
    <span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="step-6-assemble-the-graph">Step 6: Assemble the Graph</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">langgraph.graph</span> <span class="kn">import</span> <span class="n">StateGraph</span><span class="p">,</span> <span class="n">END</span>

<span class="c1"># Initialize graph
</span><span class="n">workflow</span> <span class="o">=</span> <span class="n">StateGraph</span><span class="p">(</span><span class="n">AgentState</span><span class="p">)</span>

<span class="c1"># Add nodes
</span><span class="n">workflow</span><span class="p">.</span><span class="n">add_node</span><span class="p">(</span><span class="s">"supervisor"</span><span class="p">,</span> <span class="n">supervisor_node</span><span class="p">)</span>
<span class="n">workflow</span><span class="p">.</span><span class="n">add_node</span><span class="p">(</span><span class="s">"researcher"</span><span class="p">,</span> <span class="n">research_node</span><span class="p">)</span>
<span class="n">workflow</span><span class="p">.</span><span class="n">add_node</span><span class="p">(</span><span class="s">"coder"</span><span class="p">,</span> <span class="n">code_node</span><span class="p">)</span>
<span class="n">workflow</span><span class="p">.</span><span class="n">add_node</span><span class="p">(</span><span class="s">"writer"</span><span class="p">,</span> <span class="n">writer_node</span><span class="p">)</span>

<span class="c1"># Set entry point
</span><span class="n">workflow</span><span class="p">.</span><span class="n">set_entry_point</span><span class="p">(</span><span class="s">"supervisor"</span><span class="p">)</span>

<span class="c1"># Conditional routing from supervisor
</span><span class="n">workflow</span><span class="p">.</span><span class="n">add_conditional_edges</span><span class="p">(</span>
    <span class="s">"supervisor"</span><span class="p">,</span>
    <span class="k">lambda</span> <span class="n">state</span><span class="p">:</span> <span class="n">state</span><span class="p">[</span><span class="s">"next_agent"</span><span class="p">],</span>
    <span class="p">{</span>
        <span class="s">"researcher"</span><span class="p">:</span> <span class="s">"researcher"</span><span class="p">,</span>
        <span class="s">"coder"</span><span class="p">:</span> <span class="s">"coder"</span><span class="p">,</span>
        <span class="s">"writer"</span><span class="p">:</span> <span class="s">"writer"</span><span class="p">,</span>
        <span class="s">"FINISH"</span><span class="p">:</span> <span class="n">END</span><span class="p">,</span>
    <span class="p">}</span>
<span class="p">)</span>

<span class="c1"># All agents report back to supervisor
</span><span class="n">workflow</span><span class="p">.</span><span class="n">add_edge</span><span class="p">(</span><span class="s">"researcher"</span><span class="p">,</span> <span class="s">"supervisor"</span><span class="p">)</span>
<span class="n">workflow</span><span class="p">.</span><span class="n">add_edge</span><span class="p">(</span><span class="s">"coder"</span><span class="p">,</span> <span class="s">"supervisor"</span><span class="p">)</span>
<span class="n">workflow</span><span class="p">.</span><span class="n">add_edge</span><span class="p">(</span><span class="s">"writer"</span><span class="p">,</span> <span class="s">"supervisor"</span><span class="p">)</span>

<span class="c1"># Compile
</span><span class="n">graph</span> <span class="o">=</span> <span class="n">workflow</span><span class="p">.</span><span class="nb">compile</span><span class="p">()</span>
</code></pre></div></div>

<hr />

<h2 id="step-7-run-the-pipeline">Step 7: Run the Pipeline</h2>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">initial_state</span> <span class="o">=</span> <span class="p">{</span>
    <span class="s">"messages"</span><span class="p">:</span> <span class="p">[</span>
        <span class="p">{</span><span class="s">"role"</span><span class="p">:</span> <span class="s">"user"</span><span class="p">,</span> <span class="s">"content"</span><span class="p">:</span> <span class="p">(</span>
            <span class="s">"Research the top 3 vector databases for RAG in 2024, "</span>
            <span class="s">"write Python code to benchmark their query latency, "</span>
            <span class="s">"then write a summary report of your findings."</span>
        <span class="p">)}</span>
    <span class="p">],</span>
    <span class="s">"task"</span><span class="p">:</span> <span class="s">"Vector DB research and benchmark"</span><span class="p">,</span>
    <span class="s">"next_agent"</span><span class="p">:</span> <span class="s">""</span><span class="p">,</span>
    <span class="s">"research_output"</span><span class="p">:</span> <span class="s">""</span><span class="p">,</span>
    <span class="s">"final_output"</span><span class="p">:</span> <span class="s">""</span><span class="p">,</span>
<span class="p">}</span>

<span class="c1"># Stream the execution
</span><span class="k">for</span> <span class="n">step</span> <span class="ow">in</span> <span class="n">graph</span><span class="p">.</span><span class="n">stream</span><span class="p">(</span><span class="n">initial_state</span><span class="p">,</span> <span class="p">{</span><span class="s">"recursion_limit"</span><span class="p">:</span> <span class="mi">20</span><span class="p">}):</span>
    <span class="k">for</span> <span class="n">node_name</span><span class="p">,</span> <span class="n">output</span> <span class="ow">in</span> <span class="n">step</span><span class="p">.</span><span class="n">items</span><span class="p">():</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"</span><span class="se">\n</span><span class="si">{</span><span class="s">'='</span><span class="o">*</span><span class="mi">50</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Node: </span><span class="si">{</span><span class="n">node_name</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
        <span class="k">if</span> <span class="s">"messages"</span> <span class="ow">in</span> <span class="n">output</span><span class="p">:</span>
            <span class="k">print</span><span class="p">(</span><span class="n">output</span><span class="p">[</span><span class="s">"messages"</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="n">content</span><span class="p">[:</span><span class="mi">500</span><span class="p">])</span>
</code></pre></div></div>

<hr />

<h2 id="adding-memory-with-checkpointing">Adding Memory with Checkpointing</h2>

<p>For long-running or multi-turn workflows, add <strong>persistence</strong> with LangGraph’s checkpointer:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">langgraph.checkpoint.memory</span> <span class="kn">import</span> <span class="n">MemorySaver</span>

<span class="n">memory</span> <span class="o">=</span> <span class="n">MemorySaver</span><span class="p">()</span>
<span class="n">graph</span> <span class="o">=</span> <span class="n">workflow</span><span class="p">.</span><span class="nb">compile</span><span class="p">(</span><span class="n">checkpointer</span><span class="o">=</span><span class="n">memory</span><span class="p">)</span>

<span class="c1"># Each run is tied to a thread_id
</span><span class="n">config</span> <span class="o">=</span> <span class="p">{</span><span class="s">"configurable"</span><span class="p">:</span> <span class="p">{</span><span class="s">"thread_id"</span><span class="p">:</span> <span class="s">"session_001"</span><span class="p">}}</span>

<span class="n">result</span> <span class="o">=</span> <span class="n">graph</span><span class="p">.</span><span class="n">invoke</span><span class="p">(</span><span class="n">initial_state</span><span class="p">,</span> <span class="n">config</span><span class="o">=</span><span class="n">config</span><span class="p">)</span>

<span class="c1"># Resume from checkpoint later
</span><span class="n">follow_up</span> <span class="o">=</span> <span class="p">{</span>
    <span class="s">"messages"</span><span class="p">:</span> <span class="p">[{</span><span class="s">"role"</span><span class="p">:</span> <span class="s">"user"</span><span class="p">,</span> <span class="s">"content"</span><span class="p">:</span> <span class="s">"Now compare pricing for those databases."</span><span class="p">}]</span>
<span class="p">}</span>
<span class="n">result2</span> <span class="o">=</span> <span class="n">graph</span><span class="p">.</span><span class="n">invoke</span><span class="p">(</span><span class="n">follow_up</span><span class="p">,</span> <span class="n">config</span><span class="o">=</span><span class="n">config</span><span class="p">)</span>  <span class="c1"># Remembers full prior context
</span></code></pre></div></div>

<hr />

<h2 id="human-in-the-loop">Human-in-the-Loop</h2>

<p>LangGraph supports <strong>interrupting</strong> the graph for human review before critical steps:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">langgraph.checkpoint.memory</span> <span class="kn">import</span> <span class="n">MemorySaver</span>

<span class="n">graph</span> <span class="o">=</span> <span class="n">workflow</span><span class="p">.</span><span class="nb">compile</span><span class="p">(</span>
    <span class="n">checkpointer</span><span class="o">=</span><span class="n">MemorySaver</span><span class="p">(),</span>
    <span class="n">interrupt_before</span><span class="o">=</span><span class="p">[</span><span class="s">"writer"</span><span class="p">]</span>  <span class="c1"># Pause before writer runs
</span><span class="p">)</span>

<span class="c1"># After review, resume
</span><span class="n">graph</span><span class="p">.</span><span class="n">invoke</span><span class="p">(</span><span class="bp">None</span><span class="p">,</span> <span class="n">config</span><span class="o">=</span><span class="n">config</span><span class="p">)</span>  <span class="c1"># Pass None to continue from checkpoint
</span></code></pre></div></div>

<hr />

<h2 id="production-patterns--best-practices">Production Patterns &amp; Best Practices</h2>

<h3 id="-design-patterns">✅ Design Patterns</h3>

<table>
  <thead>
    <tr>
      <th>Pattern</th>
      <th>When to Use</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Supervisor</strong></td>
      <td>General task delegation across diverse agents</td>
    </tr>
    <tr>
      <td><strong>Sequential Pipeline</strong></td>
      <td>Fixed, ordered steps (ETL-style workflows)</td>
    </tr>
    <tr>
      <td><strong>Parallel Fan-out</strong></td>
      <td>Independent subtasks that can run concurrently</td>
    </tr>
    <tr>
      <td><strong>Hierarchical</strong></td>
      <td>Complex tasks needing sub-supervisors</td>
    </tr>
  </tbody>
</table>

<h3 id="-reliability">✅ Reliability</h3>

<ul>
  <li><strong>Set <code class="language-plaintext highlighter-rouge">recursion_limit</code></strong> to prevent infinite agent loops</li>
  <li><strong>Add validation nodes</strong> between agents to catch bad outputs early</li>
  <li><strong>Use structured outputs</strong> (<code class="language-plaintext highlighter-rouge">with_structured_output</code>) for routing decisions</li>
  <li><strong>Log every node transition</strong> for debugging and auditability</li>
</ul>

<h3 id="-cost-optimization">✅ Cost Optimization</h3>

<ul>
  <li>Route simple subtasks to cheaper models (e.g., <code class="language-plaintext highlighter-rouge">gpt-4o-mini</code>)</li>
  <li>Cache tool results with <code class="language-plaintext highlighter-rouge">@lru_cache</code> or Redis for repeated queries</li>
  <li>Use <code class="language-plaintext highlighter-rouge">interrupt_before</code> to review expensive steps before execution</li>
</ul>

<h3 id="-observability">✅ Observability</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Integrate LangSmith for full tracing
</span><span class="kn">import</span> <span class="nn">os</span>
<span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">[</span><span class="s">"LANGCHAIN_TRACING_V2"</span><span class="p">]</span> <span class="o">=</span> <span class="s">"true"</span>
<span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">[</span><span class="s">"LANGCHAIN_PROJECT"</span><span class="p">]</span> <span class="o">=</span> <span class="s">"multi-agent-prod"</span>
</code></pre></div></div>

<hr />

<h2 id="real-world-use-case-legal-ai-pipeline">Real-World Use Case: Legal AI Pipeline</h2>

<p>Here’s how this architecture maps to a <strong>legal document analysis system</strong> (a pattern applicable to any domain):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>User Query: "Summarize this employment contract and flag any non-standard clauses"
     │
     ▼
┌──────────────┐
│  Supervisor  │
└──────┬───────┘
       │
  ┌────┴──────────────┐
  ▼                   ▼
┌──────────┐    ┌──────────────┐
│  RAG     │    │   Clause     │
│  Agent   │    │  Classifier  │
│(retrieve │    │   Agent      │
│  docs)   │    │              │
└────┬─────┘    └──────┬───────┘
     │                 │
     └────────┬─────────┘
              ▼
       ┌────────────┐
       │  Writer    │
       │  Agent     │
       │ (summary + │
       │  flags)    │
       └────────────┘
</code></pre></div></div>

<p>Each agent focuses on what it does best — retrieval, classification, and generation — while the supervisor ensures the right agent is engaged at the right time.</p>

<hr />

<h2 id="conclusion">Conclusion</h2>

<p>Multi-agent systems with LangChain and LangGraph unlock a new tier of LLM application complexity. The key principles to take away:</p>

<ol>
  <li><strong>Decompose</strong> complex tasks into specialized agent roles</li>
  <li><strong>Use shared state</strong> for clean inter-agent communication</li>
  <li><strong>The Supervisor pattern</strong> scales well across most real-world use cases</li>
  <li><strong>Checkpointing and HITL</strong> are essential for production reliability</li>
  <li><strong>Observe everything</strong> — LangSmith traces save hours of debugging</li>
</ol>

<p>The architecture described here is the same foundation powering production legal AI, financial analysis, and research automation systems being built today.</p>

<hr />

<h2 id="further-reading">Further Reading</h2>

<ul>
  <li><a href="https://langchain-ai.github.io/langgraph/">LangGraph Documentation</a></li>
  <li><a href="https://python.langchain.com/docs/concepts/agents/">LangChain Multi-Agent Concepts</a></li>
  <li><a href="https://smith.langchain.com/">LangSmith Observability</a></li>
  <li><a href="https://blog.langchain.dev/">CrewAI vs LangGraph: When to Use Which</a></li>
</ul>

<hr />

<p><em>Have questions or want to see a deeper dive on any section? Drop a comment below or reach out on GitHub <a href="https://github.com/tuanquang95">@tuanquang95</a>.</em></p>]]></content><author><name>Tuan Quang</name><email>anhtuanquang2016@gmail.com</email></author><category term="multi-agent" /><category term="langchain" /><category term="LLMOPS" /><category term="AI Engineering" /><summary type="html"><![CDATA[Building Multi-Agent Systems with LangChain: A Production-Ready Guide]]></summary></entry></feed>