- Cover, TOC, 5 dividers, 3 recap slides - 5 sections (chains, langgraph, deepagents, openswe, ecosystem) - design-system.js with theme tokens + 9 helper functions - research/: timeline + sources + per-tech notes - final-compile.js + merge.js for rebuild pipeline - output/: langchain-evolution.pptx (2.3 MB) + langchain-evolution.pdf (1.1 MB) + 7 sample previews
12 KiB
LangGraph (≥ 1.0)
Что это в одном абзаце
LangGraph — это низкоуровневый оркестрационный фреймворк LangChain Inc. для построения долгоживущих stateful-агентов. В отличие от LangChain (high-level create_agent), LangGraph даёт явный контроль над формой графа: узлы (add_node), рёбра (add_edge), условные переходы (add_conditional_edges), checkpointing, human-in-the-loop через interrupt, stream-режимы. С версии 1.0 (релиз 22 октября 2025) LangGraph — это production-ready durable runtime: состояние графа персистится автоматически, при падении сервера посреди long-running workflow он восстанавливается ровно с точки остановки. Вдохновлён Pregel и Apache Beam, public interface похож на NetworkX.
Метаданные на дату snapshot 2026-06-22:
- GitHub stars: ~35.4k
- Latest stable (Python):
langgraph==1.2.6(от 18.06.2026) - License: MIT
- JS-аналог:
@langchain/langgraph(npm)
Источники:
- README
github.com/langchain-ai/langgraph - https://changelog.langchain.com/announcements/langgraph-1-0-is-now-generally-available
- https://blog.langchain.com/langchain-langgraph-1dot0
- https://blog.langchain.com/fault-tolerance-in-langgraph
Ключевые API (≥ 1.0)
Импорты верхнего уровня
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.checkpoint.postgres import PostgresSaver
from langgraph.types import Command, interrupt, Send
Базовый граф с состоянием
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.checkpoint.memory import InMemorySaver
class State(TypedDict):
messages: Annotated[list, add_messages]
def node_a(state: State):
return {"messages": [{"role": "assistant", "content": "hi"}]}
builder = StateGraph(State)
builder.add_node("a", node_a)
builder.add_edge(START, "a")
builder.add_edge("a", END)
checkpointer = InMemorySaver()
graph = builder.compile(checkpointer=checkpointer)
config = {"configurable": {"thread_id": "1"}}
result = graph.invoke({"messages": []}, config=config)
Условные рёбра
def route(state: State) -> str:
return "tool_node" if state.get("needs_tool") else END
builder.add_conditional_edges("agent", route, {
"tool_node": "tool_node",
END: END,
})
Human-in-the-loop через interrupt
from langgraph.types import interrupt
def approval_node(state: State):
decision = interrupt({"question": "Approve?", "data": state["messages"]})
return {"approved": decision == "yes"}
Subgraphs
sub_builder = StateGraph(SubState)
sub_builder.add_node("x", x_node)
sub_graph = sub_builder.compile()
# В родительском графе
parent_builder.add_node("sub", sub_graph)
Store (долгосрочная память)
from langgraph.store.memory import InMemoryStore
store = InMemoryStore()
graph = builder.compile(checkpointer=checkpointer, store=store)
# Внутри ноды
store.put(("user_123", "prefs"), "key", {"value": "dark"})
Streaming
for mode, chunk in graph.stream({"messages": []}, config, stream_mode=["values", "updates"]):
print(mode, chunk)
Что нового в 1.0
- Durable execution (стабилизировано) — автоматическая персистенция state, восстановление ровно с точки падения. Без своего DB-кода.
- Built-in persistence как стабильное API —
checkpointerтеперь контракт, а не фича; Postgres / SQLite / memory — все first-class. - Human-in-the-loop first-class —
interrupt()стал стабильным API, поддерживает multi-day approval workflows. - Graph-based execution как production pattern — смесь детерминированных узлов и агентных.
- Deprecation:
langgraph.prebuilt.create_react_agent→ перенесён вlangchain.agents.create_agent(LangChain 1.0). - API stability promise — без breaking changes до 2.0.
- Middleware hooks (в 1.2) — fault tolerance: retries / timeouts / error handlers.
Что нужно раскрыть в презентации
- State, Channels, Reducers — что такое
Annotated[list, add_messages]и зачем нужен reducer. - Checkpointing —
InMemorySaverдля dev,PostgresSaverдля prod. Что хранится вStateSnapshot. - Threads —
configurable.thread_idкак ключ сессии. - Human-in-the-loop через
interrupt— не через callback, а через настоящий graph pause. - Subgraphs — композитность графов, parent может заходить в subgraph целиком.
- Send / Map-reduce — параллельные ветки графа.
- Streaming modes —
values/updates/events/messages/custom. - Store vs Checkpointer — checkpoint для сессии, store для cross-session долгосрочной памяти.
- Pregel / Beam inspiration — почему именно «graph», а не «chain».
8 рабочих примеров кода Python (≥ 1.0)
1. StateGraph с message reducer
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
class State(TypedDict):
messages: Annotated[list, add_messages]
def echo(state: State):
last = state["messages"][-1]
return {"messages": [{"role": "assistant", "content": f"echo: {last.content}"}]}
g = StateGraph(State)
g.add_node("echo", echo)
g.add_edge(START, "echo")
g.add_edge("echo", END)
app = g.compile()
print(app.invoke({"messages": [{"role": "user", "content": "hi"}]}))
2. Checkpointing + thread_id
from langgraph.checkpoint.memory import InMemorySaver
checkpointer = InMemorySaver()
app = g.compile(checkpointer=checkpointer)
cfg = {"configurable": {"thread_id": "user-1"}}
app.invoke({"messages": [{"role": "user", "content": "hi"}]}, cfg)
app.invoke({"messages": [{"role": "user", "content": "again"}]}, cfg)
# state["messages"] содержит оба сообщения — thread persistence работает
3. Conditional edges (роутинг по содержимому)
def route(state: State) -> str:
if "tool" in state["messages"][-1].content:
return "tool_node"
return END
builder.add_conditional_edges("agent", route, {"tool_node": "tool_node", END: END})
4. Human-in-the-loop через interrupt
from langgraph.types import interrupt
def approval(state: State):
answer = interrupt({"prompt": "Approve?", "context": state})
return {"approved": answer}
builder.add_node("approval", approval)
builder.add_edge(START, "approval")
app = builder.compile(checkpointer=InMemorySaver())
cfg = {"configurable": {"thread_id": "t1"}}
# Первый вызов упадёт в interrupt
try:
app.invoke({}, cfg)
except Exception:
pass
# Возобновляем с ответом пользователя
from langgraph.types import Command
result = app.invoke(Command(resume="yes"), cfg)
5. Send / Map-reduce (параллельные ветки)
from langgraph.types import Send
def fanout(state: State):
return [Send("process", {"item": i}) for i in state["items"]]
def process(state: dict):
return {"results": [state["item"] * 2]}
builder.add_conditional_edges("start", fanout)
builder.add_node("process", process)
6. Subgraphs
sub = StateGraph(SubState)
sub.add_node("inner", inner_fn)
sub.add_edge(START, "inner")
sub_compiled = sub.compile()
parent = StateGraph(ParentState)
parent.add_node("sub_block", sub_compiled)
parent.add_edge(START, "sub_block")
7. Store для долгосрочной памяти
from langgraph.store.memory import InMemoryStore
store = InMemoryStore()
app = builder.compile(checkpointer=InMemorySaver(), store=store)
def remember(state: State):
store.put(("user-1", "facts"), "name", {"value": "Alice"})
return {}
# В другом turn:
def recall(state: State):
fact = store.get(("user-1", "facts"), "name")
return {"user_name": fact.value["value"]}
8. Streaming
for event in app.stream({"messages": [{"role": "user", "content": "hi"}]}, stream_mode="values"):
print(event)
# Кастомный streaming через writer
def node(state: State):
writer = get_stream_writer()
writer({"progress": "50%"})
return {}
TypeScript-аналог
Все примеры имеют аналог в @langchain/langgraph:
import { StateGraph, START, END } from "@langchain/langgraph";
import { MemorySaver } from "@langchain/langgraph-checkpoint";
import { Annotation, messagesStateReducer } from "@langchain/langgraph";
const State = Annotation.Root({
messages: Annotation({ reducer: messagesStateReducer, default: () => [] }),
});
const g = new StateGraph(State)
.addNode("echo", (s) => ({ messages: [{ role: "assistant", content: "hi" }] }))
.addEdge(START, "echo")
.addEdge("echo", END);
const app = g.compile({ checkpointer: new MemorySaver() });
const cfg = { configurable: { thread_id: "t1" } };
const result = await app.invoke({ messages: [{ role: "user", content: "hi" }] }, cfg);
Где аналог есть: весь базовый API (StateGraph, conditional edges, checkpoint, interrupt).
Где нет / отличается: некоторые специфичные savers (PostgresSaver в JS требует отдельного пакета), Send API полностью паритетно.
Плюсы и минусы текущей версии (1.x)
Плюсы
- Durable execution из коробки — killer-фича для long-running агентов.
- HITL first-class API —
interrupt()вместо костылей с callback-ами. - Гибкость — можно построить любую топологию графа (циклы, ветки, параллелизм).
- Прозрачность — graph inspection в LangGraph Studio.
- Семантическая стабильность — semver до 2.0.
Минусы
- Кривая обучения — concepts (channels, reducers, send/receive) требуют времени.
- Boilerplate — базовый граф требует много кода по сравнению с
create_agent. - Checkpointing требует инфраструктуры — для prod нужен Postgres, настройка schema.
- Stream API многослойный —
stream_mode(values/updates/events/messages/debug) сбивает с толку. - Debugging сложных графов — без LangSmith Studio тяжело.
Заметки для презентации
- Подчеркнуть: LangGraph — runtime, не agent-harness.
create_agent(LangChain) иcreate_deep_agent(Deep Agents) работают поверх LangGraph. - Если есть HITL-сценарий — показать
interrupt()как killer-фичу 1.0. - Использовать аналогию: LangGraph = база данных для состояния агента, LangChain = ORM поверх.
- Упомянуть, что LangGraph вдохновлён Pregel (Google) и Apache Beam — это не новость из AI, это паттерн из распределённых систем.
- В 1.2 — fault tolerance (retries / timeouts / error handlers) — отдельная тема.