Initial commit: LangChain evolution tutorial deck (132 slides)

- 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
This commit is contained in:
2026-06-22 11:29:03 +03:00
parent ed5b5c91bf
commit 75601988c2
220 changed files with 13069 additions and 3 deletions
+328
View File
@@ -0,0 +1,328 @@
# 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)
### Импорты верхнего уровня
```python
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
```
### Базовый граф с состоянием
```python
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)
```
### Условные рёбра
```python
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
```python
from langgraph.types import interrupt
def approval_node(state: State):
decision = interrupt({"question": "Approve?", "data": state["messages"]})
return {"approved": decision == "yes"}
```
### Subgraphs
```python
sub_builder = StateGraph(SubState)
sub_builder.add_node("x", x_node)
sub_graph = sub_builder.compile()
# В родительском графе
parent_builder.add_node("sub", sub_graph)
```
### Store (долгосрочная память)
```python
from langgraph.store.memory import InMemoryStore
store = InMemoryStore()
graph = builder.compile(checkpointer=checkpointer, store=store)
# Внутри ноды
store.put(("user_123", "prefs"), "key", {"value": "dark"})
```
### Streaming
```python
for mode, chunk in graph.stream({"messages": []}, config, stream_mode=["values", "updates"]):
print(mode, chunk)
```
---
## Что нового в 1.0
1. **Durable execution (стабилизировано)** — автоматическая персистенция state, восстановление ровно с точки падения. Без своего DB-кода.
2. **Built-in persistence как стабильное API**`checkpointer` теперь контракт, а не фича; Postgres / SQLite / memory — все first-class.
3. **Human-in-the-loop first-class**`interrupt()` стал стабильным API, поддерживает multi-day approval workflows.
4. **Graph-based execution как production pattern** — смесь детерминированных узлов и агентных.
5. **Deprecation:** `langgraph.prebuilt.create_react_agent` → перенесён в `langchain.agents.create_agent` (LangChain 1.0).
6. **API stability promise** — без breaking changes до 2.0.
7. **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
```python
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
```python
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 (роутинг по содержимому)
```python
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
```python
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 (параллельные ветки)
```python
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
```python
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 для долгосрочной памяти
```python
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
```python
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`:
```typescript
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) — отдельная тема.