LangGraph
Multi-Agent-Systeme und Workflows mit LangGraph
Inhaltsverzeichnis
- Kurzüberblick: Warum LangGraph?
- Zentrale Konzepte
- Quickstart
- Grundaufbau: Workflows als State Machine
- State sauber definieren (vertieft)
- Nodes: Bausteine des Workflows
- Typische Workflows
- Edges & Conditional Routing
- Streaming: Schritte sichtbar machen
- Checkpointing & Sessions
- Human-in-the-Loop (Approval & Formulare)
- Multi-Agent-Workflows (Fortgeschritten)
- Best Practices
- Troubleshooting
- Erweiterungen / Fortgeschrittene Themen
- Zusammenfassung
- Abgrenzung zu verwandten Dokumenten
Kurzüberblick: Warum LangGraph?
LangChain bietet Modelle, Tools und einfache Agenten. LangGraph baut darauf auf und ermöglicht:
- Abläufe in mehreren Schritten
- Bedingte Entscheidungswege
- Mehrere Agenten (Rollen)
- Sitzungen, die wieder aufgenommen werden können
- Human-in-the-Loop
Zentrale Konzepte
| Konzept | Bedeutung |
|---|---|
| State | Gemeinsamer Zustand, der durch den Workflow wandert |
| Node | Ein einzelner Bearbeitungsschritt |
| Edge | Verbindung zwischen Schritten |
| Conditional Routing | Entscheidung, welcher Pfad als Nächstes läuft |
| Checkpointing | Speichert Zustand für Resume und Debugging |
| Interrupt | Technischer Halt für Human-in-the-Loop |
Quickstart
Der schnellste Weg zum Verständnis ist ein Mini-Workflow.
Ein Workflow besteht aus:
- State: zentrale Daten
- Nodes: Bearbeitungsschritte
- Edges: Ablaufsteuerung
State definieren
from typing import TypedDict, Annotated
from langgraph.graph.message import add_messages
class ChatState(TypedDict):
messages: Annotated[list, add_messages]
step: int
Ein einzelner Node
from langchain.chat_models import init_chat_model
llm = init_chat_model("openai:gpt-5.4-nano")
def agent_node(state: ChatState) -> ChatState:
response = llm.invoke(state["messages"])
return {"messages": [response], "step": state["step"] + 1}
Graph bauen
from langgraph.graph import StateGraph, START, END
g = StateGraph(ChatState)
g.add_node("agent", agent_node)
g.add_edge(START, "agent")
g.add_edge("agent", END)
graph = g.compile()
Graphen visualisieren
from IPython.display import Image
display(Image(graph.get_graph().draw_mermaid_png()))
Dieser minimale Workflow sieht so aus:
flowchart LR
START([START]) --> AGENT[agent_node]
AGENT --> END([END])
style START fill:#90EE90
style END fill:#FFB6C1
style AGENT fill:#87CEEB
Ausführen
from langchain_core.messages import HumanMessage
initial_state = {"messages": [HumanMessage(content="Was ist LangGraph?")], "step": 0}
result = graph.invoke(initial_state)
result
Ergebnis: Ein vollständiger erster Workflow, bevor irgendein abstraktes Konzept erklärt wurde.
Grundaufbau: Workflows als State Machine
Nach einem ersten funktionsfähiges Beispiel, kann das Konzept erklärt werden:
- Ein Workflow besteht aus klar definierten Schritten (Nodes).
- Der Zustand wird in einem State gespeichert.
- Edges bestimmen die Reihenfolge.
- Reducer wie
add_messagesfügen Informationen intelligent zusammen.
flowchart TD
%% Einstiegspunkt
INVOKE([graph.invoke]) --> START
%% Hauptknoten
subgraph START_NODE [ ]
direction TB
START([START])
end
subgraph AGENT_NODE [agent_node]
direction TB
StateIn[<b>1. State-Eingang</b><br/>Aktueller Snapshot]
LLM[<b>2. Logik</b><br/>LLM / Tool-Aufruf]
Update[<b>3. State Update</b><br/>Änderungen ausgeben]
StateIn --> LLM
LLM --> Update
end
subgraph END_NODE [ ]
direction TB
END([END])
end
%% Verbindungen
START -->|erster Node| AGENT_NODE
AGENT_NODE -->|Workflow beendet| END
END --> RESULT([Finaler State])
%% Styling
style START fill:#90EE90,stroke:#333
style END fill:#FFB6C1,stroke:#333
style AGENT_NODE fill:#f9f9f9,stroke:#87CEEB,stroke-width:2px
style StateIn fill:#E1F5FE,stroke:#01579B
style LLM fill:#E1F5FE,stroke:#01579B
style Update fill:#E1F5FE,stroke:#01579B
style INVOKE fill:#eeeeee,stroke:#999,stroke-dasharray: 5 5
style RESULT fill:#eeeeee,stroke:#999,stroke-dasharray: 5 5
Kurz: Nodes sind Funktionen – Edges sind der Ablauf.
State sauber definieren (vertieft)
class ChatState(TypedDict):
messages: Annotated[list, add_messages]
step: int
# erweiterbar: approved: bool, analysis: str
Prinzipien:
- Nur speichern, was später benötigt wird.
- Typisierung unterstützt Verständnis und Fehlersuche.
- Reducer sorgen dafür, dass Listen (z. B. Nachrichten) korrekt gemergt werden.
Nodes: Bausteine des Workflows
Nodes sollen klein, fokussiert und deterministisch sein.
Ein Node ist immer eine Python-Funktion — was sich unterscheidet, ist der Inhalt:
| Node-Typ | Inhalt der Funktion | Typischer Einsatz |
|---|---|---|
| LLM-Node | direkter LLM-Aufruf | Antworten, Zusammenfassungen |
| Tool-Node | Tool-Ausführung | Suche, Berechnungen, APIs |
| Agent-Node | vollständiger Agent (create_agent) | komplexe Teilaufgaben mit eigenem Tool-Loop |
Typ 1: LLM-Node
def summarize_node(state: ChatState) -> ChatState:
text = "\n".join([m.content for m in state["messages"]])
summary = llm.invoke([{"role": "user", "content": f"Fasse zusammen: {text}"}])
return {"messages": [summary]}
Typ 2: Tool-Node
from langchain_core.tools import tool
from langchain_core.messages import AIMessage
@tool
def suche(query: str) -> str:
"""Führt eine Websuche durch."""
return f"Ergebnis für: {query}"
def tool_node(state: ChatState) -> ChatState:
result = suche.invoke({"query": state["messages"][-1].content})
return {"messages": [AIMessage(content=result)]}
Typ 3: Agent-Node
Ein Node kann intern einen vollständigen Agenten ausführen — inklusive eigenem Tool-Loop:
from langchain.agents import create_agent
research_agent = create_agent(
model=llm,
tools=[suche],
system_prompt="Du bist ein Research-Spezialist. Recherchiere gründlich.",
)
def research_node(state: ChatState) -> ChatState:
result = research_agent.invoke({"messages": state["messages"]})
return {"messages": result["messages"]}
Hinweis: Der Agent-Node ist das Muster hinter Supervisor-Architekturen (M20, M21). Der Supervisor ruft
research_node,writer_nodeetc. auf — jeder Node kapselt intern einen vollständigen Agenten.
Typische Workflows
Die folgenden Abschnitte zeigen die wichtigsten Einsteiger-Workflows: lineare Graphen, bedingtes Routing, Streaming, Sessions, Human-in-the-Loop und einfache Multi-Agent-Muster.
Edges & Conditional Routing
Nun erst wird Routing eingeführt – nachdem Entwickler Nodes und State kennen.
Lineare Edges
g.add_edge(START, "agent")
g.add_edge("agent", END)
Bedingtes Routing
def tool_node(state: ChatState):
result_message = ... # echtes Tool
return {"messages": [result_message]}
def routing_after_agent(state: ChatState) -> str:
last_msg = state["messages"][-1]
if getattr(last_msg, "tool_calls", None):
return "tools"
return END
g.add_node("tools", tool_node)
g.add_conditional_edges(
"agent",
routing_after_agent,
{"tools": "tools", END: END},
)
g.add_edge("tools", "agent")
Visualisierung des Tool-Loops:
flowchart TB
START([START]) --> AGENT[Agent Node]
AGENT --> COND{Tool Calls?}
COND -->|Yes| TOOLS[Tool Node]
COND -->|No| END([END])
TOOLS --> AGENT
style START fill:#90EE90
style END fill:#FFB6C1
style COND fill:#FFD700
style TOOLS fill:#FFA500
style AGENT fill:#87CEEB
Typische Muster
- Schlüsselwort-Trigger
- Unsicherheitsanalyse
- Routing nach Tool-Feedback
- Wiederholschleifen (Retry)
Streaming: Schritte sichtbar machen
Streaming ist ein wichtiges Werkzeug für das Verständnis.
config = {"configurable": {"thread_id": "demo"}}
for chunk in graph.stream(
initial_state,
config=config,
stream_mode="updates",
version="v2",
):
if chunk["type"] == "updates":
print(chunk["data"])
Streaming-Prozess:
sequenceDiagram
autonumber
participant User
participant Graph
participant Node1
participant Node2
User->>Graph: invoke(state)
Graph->>Node1: process
Node1-->>User: stream update 1
Graph->>Node2: process
Node2-->>User: stream update 2
Graph-->>User: final result
Streaming-Varianten:
updates: nur Änderungenvalues: vollständiger Statemessages: nur neue Nachrichtendebug: detaillierte Ausführungsinformationen
Empfehlung: updates.
Checkpointing & Sessions
Checkpointing ermöglicht:
- längerfristige Workflows
- Resume nach Unterbrechung
- stabile Interaktion
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
graph = g.compile(checkpointer=checkpointer)
config = {"configurable": {"thread_id": "session-01"}}
result1 = graph.invoke(initial_state, config)
Später:
new_input = {
"messages": [HumanMessage(content="Fahre mit der nächsten Frage fort.")],
"step": 0,
}
result2 = graph.invoke(new_input, config)
Checkpointing lädt dabei den gespeicherten Zustand der thread_id und ergänzt ihn um den neuen Input. Für Human-in-the-Loop-Unterbrechungen wird dagegen nicht ein neuer State übergeben, sondern Command(resume=...).
Session-Management mit Checkpointing:
stateDiagram-v2
[*] --> Session1: invoke(state, thread_id)
Session1 --> Checkpoint: save state
Checkpoint --> Session1: resume
Session1 --> Session2: continue later
Session2 --> [*]: complete
note right of Checkpoint
MemorySaver (Dev)
SQLite (Staging)
Postgres (Production)
end note
Hinweise:
- Optimale Einstiegsvariante: MemorySaver.
- Für produktive Systeme: SQLite/Postgres.
- Graphänderungen können Sessions invalidieren.
Human-in-the-Loop (Approval & Formulare)
Human-in-the-Loop ist ein wichtiges Konzept – aber erst an dieser Stelle sinnvoll.
Interrupt
from langgraph.types import interrupt
def approval_node(state: ChatState) -> ChatState:
decision = interrupt("Aktion ausführen? yes/no")
return {"approved": decision == "yes"}
Weiterführen
from langgraph.types import Command
result = graph.invoke(Command(resume="yes"), config)
Human-in-the-Loop Pattern:
flowchart TB
START([START]) --> NODE1[Process Data]
NODE1 --> APPROVAL[👤 Approval Node]
APPROVAL --> INTERRUPT{interrupt}
INTERRUPT -.Wait for Human.-> DECISION{Decision?}
DECISION -->|yes| EXECUTE[Execute Action]
DECISION -->|no| REJECT[Reject Action]
EXECUTE --> END([END])
REJECT --> END
style START fill:#90EE90
style END fill:#FFB6C1
style APPROVAL fill:#FFA500
style INTERRUPT fill:#FFD700
style EXECUTE fill:#87CEEB
style REJECT fill:#ff6b6b
Einsatzmöglichkeiten:
- sicherheitsrelevante Aktionen
- wichtige Entscheidungen
- mehrschrittige Formulareingaben
Multi-Agent-Workflows (Fortgeschritten)
Dieses Thema wurde bewusst ans Ende verschoben.
Agenten definieren
from langchain.agents import create_agent
research_agent = create_agent(model=llm, tools=[...], system_prompt="Research")
writer_agent = create_agent(model=llm, tools=[...], system_prompt="Writer")
Supervisor
from langgraph.types import Command
def supervisor(state: ChatState) -> Command:
task = state.get("task_type", "research")
return Command(goto=f"{task}_agent")
Multi-Agent Supervisor Pattern:
graph TB
START([User Request]) --> SUPERVISOR[Supervisor Agent]
SUPERVISOR --> COND{Task Type?}
COND -->|research| RESEARCH[Research Agent]
COND -->|writing| WRITER[Writer Agent]
COND -->|analysis| ANALYST[Analyst Agent]
RESEARCH --> REVIEW[Quality Check]
WRITER --> REVIEW
ANALYST --> REVIEW
REVIEW --> ITERCHECK{Good enough?}
ITERCHECK -->|No| SUPERVISOR
ITERCHECK -->|Yes| END([END])
style SUPERVISOR fill:#10a37f
style RESEARCH fill:#87CEEB
style WRITER fill:#FFB6C1
style ANALYST fill:#FFA500
style REVIEW fill:#FFD700
Mögliche Erweiterungen:
- iterative Qualitätsprüfungen
- mehrere Worker mit Prioritäten
- automatische oder manuelle Rollenwechsel
Best Practices
- State klein und explizit halten.
- Nodes nach fachlicher Verantwortung trennen.
- Routing als Funktion modellieren statt in Prompt-Text zu verstecken.
- Graph nach dem Kompilieren visualisieren.
- Checkpointing einsetzen, sobald Sessions wiederaufgenommen werden sollen.
- Human-in-the-Loop technisch mit Interrupts erzwingen.
Troubleshooting
Graph endet zu früh
Prüfe die Edges und Rückgabewerte der Routing-Funktion. Jeder mögliche Rückgabewert muss auf einen gültigen Zielknoten oder END zeigen.
State wird überschrieben
Nutze Reducer wie add_messages, wenn Listen über mehrere Schritte erweitert statt ersetzt werden sollen.
Human-in-the-Loop läuft nicht weiter
Setze eine stabile thread_id und verwende Command(resume=...), um nach einem Interrupt fortzufahren.
Erweiterungen / Fortgeschrittene Themen
- Checkpointing über persistente Stores
- Human-in-the-Loop mit Formularen
- Multi-Agent-Workflows
- LangSmith-Tracing für Graph-Runs
Zusammenfassung
LangGraph wird dann sinnvoll, wenn ein LLM-Workflow echten Zustand, Routing oder Unterbrechungen braucht. Der Einstieg gelingt am besten über den minimalen Graph aus State, Node und Edge; danach kommen Conditional Routing, Streaming, Checkpointing und Human-in-the-Loop hinzu.
Abgrenzung zu verwandten Dokumenten
| Dokument | Inhalt |
|---|---|
| LangChain Einsteiger | Voraussetzung: Modell-Init, Tools und Agenten mit LangChain |
| ChromaDB Einsteiger | Vektordatenbank als RAG-Tool in LangGraph-Workflows |
Version: 2.1
Stand: Mai 2026
Kurs: Generative KI. Verstehen. Anwenden. Gestalten.