Integrating LangGraph for Graph-Based AI Agents

We design and deploy artificial intelligence systems: from prototype to production-ready solutions. Our team combines expertise in machine learning, data engineering and MLOps to make AI work not in the lab, but in real business.
Showing 1 of 1All 1566 services
Integrating LangGraph for Graph-Based AI Agents
Medium
from 1 week to 3 months
Frequently Asked Questions

AI Development Areas

AI Solution Development Stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1317
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1226
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    925
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1156
  • image_logo-advance_0.webp
    B2B Advance company logo design
    620
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    894

When developing complex AI agents, we often encounter situations where linear LangChain Expression Language (LCEL) chains stop being effective. When cyclical processing, conditional transitions based on intermediate step results, or pauses for human confirmation are required, LCEL falls short. That's exactly where LangGraph comes in—a library that extends LangChain and allows building agents as directed graphs with explicit state. Our experience deploying LangGraph in production includes projects for fintech, logistics, and legal services. We guarantee a fault-tolerant architecture and full documentation.

LangGraph implements the StateGraph concept, where each node is a function and edges are transitions. The agent's state is described with a TypedDict and can automatically merge messages. This makes it easy to implement loops and multi-agent systems.

Why agents need a graph, not a chain?

Linear LCEL chains are fine for simple pipelines: take input, apply a sequence of steps, get output. But real agent scenarios often require going back to a previous step, running parallel checks, or pausing execution for manual control. LangGraph's graph model solves these problems naturally: cycles are edges leading back; parallelism is multiple nodes executing simultaneously; human-in-the-loop is built-in interruptions.

Basic graph structure

from langgraph.graph import StateGraph, END
from langgraph.checkpoint.memory import MemorySaver
from langgraph.prebuilt import ToolNode
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage
from typing import TypedDict, Annotated
import operator

class AgentState(TypedDict):
    messages: Annotated[list, operator.add]  # Automatically concatenated
    user_id: str
    iteration_count: int

llm = ChatOpenAI(model="gpt-4o")

def agent_node(state: AgentState) -> AgentState:
    response = llm.bind_tools(tools).invoke(state["messages"])
    return {"messages": [response], "iteration_count": state["iteration_count"] + 1}

def should_continue(state: AgentState) -> str:
    last_msg = state["messages"][-1]
    if last_msg.tool_calls:
        return "tools"
    return END

# Build the graph
graph = StateGraph(AgentState)
graph.add_node("agent", agent_node)
graph.add_node("tools", ToolNode(tools))

graph.set_entry_point("agent")
graph.add_conditional_edges("agent", should_continue, {"tools": "tools", END: END})
graph.add_edge("tools", "agent")  # Loop: after tools, back to agent

app = graph.compile(checkpointer=MemorySaver())

Persistent state and interrupts

LangGraph supports checkpoint saving between runs and pauses for human approval:

from langgraph.checkpoint.postgres import PostgresSaver
from psycopg import Connection

# Persistence in PostgreSQL
conn = Connection.connect("postgresql://user:pass@localhost/langgraph_db")
checkpointer = PostgresSaver(conn)

# Interrupt: graph stops before the specified node
app = graph.compile(
    checkpointer=checkpointer,
    interrupt_before=["execute_payment"],  # Requires human confirmation
)

config = {"configurable": {"thread_id": "order_12345"}}

# Run until the break point
result = app.invoke({"messages": [HumanMessage("Pay the invoice for 50000 RUB")]}, config)
# Graph stopped before execute_payment

# After human review, continue
app.invoke(None, config)  # None = resume from current state

Multi-agent: Supervisor pattern

from langgraph.graph import StateGraph, END
from typing import Literal

class SupervisorState(TypedDict):
    messages: Annotated[list, operator.add]
    next_agent: str

AGENTS = ["researcher", "analyst", "writer"]

supervisor_prompt = f"""You are a supervisor of a multi-agent system.
Based on the request and current progress, choose the next agent: {AGENTS}
Or return FINISH if the task is complete.
"""

def supervisor_node(state: SupervisorState):
    response = llm.with_structured_output(
        {"next": {"type": "string", "enum": AGENTS + ["FINISH"]}}
    ).invoke([{"role": "system", "content": supervisor_prompt}] + state["messages"])
    return {"next_agent": response["next"]}

def route_to_agent(state: SupervisorState) -> str:
    if state["next_agent"] == "FINISH":
        return END
    return state["next_agent"]

# Create agents
def make_agent_node(name: str, system_prompt: str):
    agent_llm = ChatOpenAI(model="gpt-4o").bind_tools(get_tools_for(name))
    def node(state):
        result = agent_llm.invoke(
            [{"role": "system", "content": system_prompt}] + state["messages"]
        )
        return {"messages": [result]}
    return node

graph = StateGraph(SupervisorState)
graph.add_node("supervisor", supervisor_node)
graph.add_node("researcher", make_agent_node("researcher", "Research the topic and find facts"))
graph.add_node("analyst", make_agent_node("analyst", "Analyze data and draw conclusions"))
graph.add_node("writer", make_agent_node("writer", "Formulate the final answer"))

graph.set_entry_point("supervisor")
graph.add_conditional_edges("supervisor", route_to_agent)
for agent in AGENTS:
    graph.add_edge(agent, "supervisor")

multi_agent = graph.compile()

Streaming and real-time output

# Streaming events from the graph
async for event in app.astream_events(
    {"messages": [HumanMessage("Analyze Q1 sales")]},
    config={"configurable": {"thread_id": "analysis_001"}},
    version="v2",
):
    kind = event["event"]
    if kind == "on_chat_model_stream":
        print(event["data"]["chunk"].content, end="", flush=True)
    elif kind == "on_tool_start":
        print(f"\n[Tool call: {event['name']}]")
    elif kind == "on_tool_end":
        print(f"[Tool result received]")

How nested graphs simplify modularity?

LangGraph supports SubGraphs—nested graphs. You can define a graph for document processing and then include it as a regular node in the parent graph. This allows decomposing complex systems into reusable components.

# Subgraph for document processing
doc_graph = StateGraph(DocumentState)
doc_graph.add_node("extract", extract_text)
doc_graph.add_node("classify", classify_document)
doc_graph.add_node("validate", validate_structure)
# ... build the subgraph

doc_subgraph = doc_graph.compile()

# Include subgraph in parent
main_graph = StateGraph(MainState)
main_graph.add_node("process_document", doc_subgraph)  # Subgraph as node
main_graph.add_node("send_result", send_to_crm)
main_graph.add_edge("process_document", "send_result")

Practical case: contract review system (from our practice)

Task: one of our clients—a legal department of a large company—received 30–50 contracts daily. Each contract required 1–2 hours of lawyer time. We built a graph agent on LangGraph that automated the review.

Graph:

  1. extract_node — parse PDF, extract structure
  2. classify_node — contract type (supply, services, lease, NDA)
  3. risk_check_node — parallel checks: financial terms, duration, liability
  4. legal_rules_node — check against corporate list of prohibited clauses
  5. human_review — interrupt for contracts with risk_score > 7
  6. finalize_node — generate conclusion and recommendations
app = graph.compile(
    checkpointer=PostgresSaver(conn),
    interrupt_before=["human_review"],  # Pause only for risky ones
)

Routing: low risk → automatic approval; high risk → pause for lawyer with agent's draft conclusion.

Results:

  • Standard contract review time: 90 min → 8 min
  • Automatic approval without lawyer: 61% of contracts
  • Missed non-standard clauses: 0 (vs ~3% manual due to fatigue)
  • Legal department workload: -58%

Comparison of LangGraph and LCEL

Criteria LCEL LangGraph
Structure Linear chain Arbitrary graph
Loops No Yes
State Passed via pipe TypedDict with merge strategy
Checkpoint No PostgreSQL, Redis, SQLite
Human-in-the-loop No interrupt_before/after
Use case Simple pipelines Agents, multi-agent systems

LangGraph components

Component Purpose Example
StateGraph Defines state and nodes StateGraph(AgentState)
Node Processing function agent_node
Edge Connection between nodes graph.add_edge("tools", "agent")
Conditional Edge Conditional transition should_continue
Checkpointer State persistence MemorySaver, PostgresSaver
Interrupt Pause for HITL interrupt_before=["node"]

What our LangGraph integration includes

  • Architecture session: analyze the task, select graph topology, define human-in-the-loop points.
  • Code development: implement nodes, edges, state, integrate with your LLM and tools.
  • Persistence setup: PostgreSQL, Redis, or SQLite for checkpoints.
  • Environment integration: deploy via Docker/Kubernetes, connect monitoring (LangSmith).
  • Testing: unit tests, load testing with latency recording (p99).
  • Documentation: full graph description, API, operation guide.
  • Team training: workshop on LangGraph for your developers.

Estimated timelines

  • Basic ReAct agent on LangGraph: 3 to 5 days.
  • Multi-agent system with supervisor: 2 to 3 weeks.
  • Human-in-the-loop workflow with persistence: 1 to 2 weeks.
  • Production integration with PostgreSQL checkpoint: +3–5 days.

Pricing is determined individually—we assess the project free of charge within one business day. Contact us for a consultation: our certified engineers will help choose the architecture for your task. Request a preliminary assessment, and we will prepare a commercial proposal with a quality guarantee and transparent timelines.