Einen AI-Agenten zu bauen, der im Notebook funktioniert, dauert einen Nachmittag. Ein Modell, eine Schleife, ein paar Werkzeuge — und schon erledigt das Ding erstaunlich komplexe Aufgaben. Der Eindruck, dass das kurz vor der Produktionsreife steht, ist verständlich und fast immer falsch.
Was zwischen dem Nachmittag und dem Produktivbetrieb liegt, hat wenig mit KI zu tun. Es sind die Fragen, die jedes langlaufende verteilte System stellt: Was passiert, wenn der Prozess mitten im Ablauf stirbt? Wie greift ein Mensch ein, ohne alles neu zu starten? Woher wissen wir, dass der Agent nicht seit vier Stunden im Kreis läuft und Geld verbrennt?
LangGraph ist der Versuch, genau diese Fragen zum Kern des Frameworks zu machen, statt sie dem Anwendungscode zu überlassen. Dieser Artikel zeigt, was das konkret bedeutet, wo die Fallstricke liegen — und wann ein Graph die falsche Antwort auf eine einfachere Frage ist.
Das eigentliche Problem: Zustand
Die klassische Agentenschleife sieht ungefähr so aus:
while not fertig:
antwort = modell.aufrufen(verlauf)
if antwort.werkzeugaufruf:
ergebnis = werkzeug_ausfuehren(antwort.werkzeugaufruf)
verlauf.append(ergebnis)
else:
fertig = True
Das funktioniert — solange der Prozess lebt. Der gesamte Zustand steckt in einer lokalen Variablen. Stirbt der Prozess nach dem siebten von zehn Schritten, ist alles weg: die Zwischenergebnisse, die bereits bezahlten Modellaufrufe, der Kontext. Ein Neustart beginnt bei null.
In der Produktion ist das aus drei Gründen untragbar:
- Deployments. Ihr wollt neue Versionen ausrollen, ohne laufende Vorgänge zu töten.
- Menschliche Freigaben. Wenn ein Agent vor einer schreibenden Aktion auf Bestätigung warten soll, kann das Minuten oder Tage dauern. Solange einen Prozess offen zu halten, ist keine Architektur.
- Kosten. Ein Neustart bedeutet, dass alle bereits bezahlten Modellaufrufe noch einmal bezahlt werden.
Der Kern von LangGraph ist deshalb nicht die Graph-Notation, sondern die Erkenntnis, dass der Zustand eines Agenten außerhalb des Prozesses gehören muss.
Wie LangGraph das löst
LangGraph modelliert den Agenten als Graph: Knoten sind Funktionen, Kanten sind Übergänge, und ein explizit definiertes Zustandsobjekt fließt hindurch. Nach jedem Knoten wird der Zustand über einen Checkpointer persistiert.
from typing import Annotated, TypedDict
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
from langgraph.checkpoint.postgres import PostgresSaver
class AgentState(TypedDict):
messages: Annotated[list, add_messages]
schritte: int
kosten_cent: int
def modell_aufrufen(state: AgentState) -> dict:
antwort = llm.invoke(state["messages"])
return {
"messages": [antwort],
"schritte": state["schritte"] + 1,
"kosten_cent": state["kosten_cent"] + kosten_von(antwort),
}
def weiter_oder_ende(state: AgentState) -> str:
# Harte Abbruchbedingungen gehören in den Graphen, nicht in den Prompt.
if state["schritte"] >= 12 or state["kosten_cent"] >= 200:
return END
if not state["messages"][-1].tool_calls:
return END
return "werkzeuge"
graph = StateGraph(AgentState)
graph.add_node("modell", modell_aufrufen)
graph.add_node("werkzeuge", werkzeuge_ausfuehren)
graph.set_entry_point("modell")
graph.add_conditional_edges("modell", weiter_oder_ende)
graph.add_edge("werkzeuge", "modell")
with PostgresSaver.from_conn_string(DSN) as checkpointer:
app = graph.compile(checkpointer=checkpointer)
Drei Dinge daran sind entscheidend.
Der Zustand ist explizit und typisiert
AgentState ist ein TypedDict, das genau beschreibt, was der Agent mit sich führt. Das Annotated[list, add_messages] legt fest, wie Aktualisierungen zusammengeführt werden — hier: anhängen statt ersetzen. Diese sogenannten Reducer sind die Stelle, an der die meisten Fehler entstehen: Wer vergisst, einen Reducer anzugeben, überschreibt still den bisherigen Verlauf, und der Agent verliert bei jedem Schritt sein Gedächtnis.
Abbruchbedingungen stehen im Code, nicht im Prompt
In weiter_oder_ende stehen zwei harte Grenzen: maximal zwölf Schritte, maximal zwei Euro. Beides im Code, nicht im Systemprompt. Ein Modell, das man bittet, sparsam zu sein, ist nicht sparsam — es ist ein Modell, das gebeten wurde. Der einzige verlässliche Kostendeckel ist einer, den das Modell nicht umgehen kann.
Der Checkpointer macht den Agenten wiederanlauffähig
Mit einem persistenten Checkpointer wird nach jedem Knoten der vollständige Zustand geschrieben. Der Aufruf erfolgt gegen eine Thread-ID:
config = {"configurable": {"thread_id": f"vorgang-{vorgang.id}"}}
ergebnis = app.invoke({"messages": [eingabe], "schritte": 0, "kosten_cent": 0}, config)
Stirbt der Prozess, setzt ein erneuter Aufruf mit derselben Thread-ID am letzten Checkpoint fort. Das ist der Unterschied zwischen einem Skript und einem System.
Menschliche Freigaben ohne Dauerprozess
Der Anwendungsfall, der in der Praxis am häufigsten unterschätzt wird: Ein Agent soll vor einer schreibenden Aktion auf Bestätigung warten. LangGraph löst das über Unterbrechungen — der Graph hält vor einem definierten Knoten an, der Zustand liegt in der Datenbank, der Prozess kann beendet werden.
app = graph.compile(checkpointer=checkpointer, interrupt_before=["werkzeuge"])
# Erster Aufruf: läuft bis zur Unterbrechung und kehrt zurück.
app.invoke(eingabe, config)
# Beliebig viel später, in einem anderen Prozess, nach Klick im Frontend:
app.invoke(None, config) # setzt am Checkpoint fort
Zwischen den beiden Aufrufen können Stunden liegen, ein Deployment, ein Serverneustart. Genau das braucht man, wenn eine Freigabe durch Menschen Teil des Ablaufs ist — und genau das ist mit einer while-Schleife nicht sauber zu bauen.
Die Fallstricke, die man erst in Produktion sieht
Zustand wächst unbegrenzt
!
Der Nachrichtenverlauf wächst mit jedem Schritt. Ohne aktives Kürzen läuft man ins Kontextfenster und in exponentiell steigende Kosten
Checkpoints sammeln sich an
!
Jeder Schritt schreibt eine Zeile. Ohne Aufräumstrategie ist die Datenbank nach Monaten das größte Betriebsproblem
Werkzeuge sind nicht idempotent
!
Nach einem Wiederanlauf kann ein Knoten erneut laufen. Wer dabei zweimal eine Rechnung stellt, hat ein echtes Problem
Der dritte Punkt ist der gefährlichste, weil er in Tests nie auftritt. Jedes schreibende Werkzeug braucht einen Idempotenzschlüssel — eine ID, mit der die Zielsysteme erkennen, dass diese Aktion bereits ausgeführt wurde. Bei einem Agenten, der wiederanlaufen kann, ist das keine Feinheit, sondern Voraussetzung.
Zum Kontextwachstum: Die pragmatischste Lösung ist, den Verlauf ab einer bestimmten Länge zusammenzufassen und nur die letzten Schritte im Original zu behalten. Wichtig ist, dass diese Zusammenfassung im Zustand landet und nicht bei jedem Aufruf neu berechnet wird — sonst bezahlt man sie mehrfach.
Wann ein Graph die falsche Antwort ist
LangGraph ist ein gutes Werkzeug für einen ziemlich schmalen Problembereich. Die ehrliche Einordnung nach mehreren Projekten:
| Situation | Empfehlung |
|---|---|
| Fester Ablauf, bekannte Reihenfolge | Normale Funktionen. Kein Modell muss entscheiden, was ohnehin feststeht |
| Ein Modellaufruf, ein Ergebnis | SDK direkt aufrufen. Ein Framework fügt hier nur Abstraktion hinzu |
| Mehrere Schritte, kurz, ohne Freigaben | Eigene Schleife mit Schrittzähler. Überschaubar und vollständig verstanden |
| Langlaufend, Freigaben, Wiederanlauf nötig | LangGraph. Hier zahlt sich die Persistenz aus |
| Mehrere Agenten, die sich abstimmen | LangGraph — aber erst, wenn ein einzelner nachweislich nicht reicht |
Die häufigste Fehlentscheidung ist die letzte Zeile: Multi-Agenten-Architekturen wirken auf Folien überzeugend und sind in der Praxis schwer zu debuggen, teuer und selten besser als ein gut gebauter einzelner Agent mit klaren Werkzeugen. Wir raten konsequent dazu, mit einem zu beginnen.
Was vor dem Produktivgang fertig sein muss
Testfälle mit erwarteten Ergebnissen
Eine Sammlung realer Anfragen mit dem, was herauskommen soll. Sie läuft bei jeder Änderung an Prompt, Modell oder Werkzeugen — sonst merkt niemand, wenn eine Anpassung etwas anderes kaputt macht.
Vollständige Nachvollziehbarkeit
Jeder Modellaufruf mit Eingabe, Ausgabe, Tokenzahl und Dauer protokolliert. Ohne das ist die Frage „warum hat der Agent das getan?“ nicht beantwortbar.
Kostendeckel auf mehreren Ebenen
Pro Vorgang, pro Nutzer, pro Tag. Der teuerste Fehler in diesem Feld ist eine Endlosschleife, die niemand bemerkt.
Verhalten bei Modellausfall
Rate-Limits, Timeouts, abgekündigte Modellversionen. Ein Fallback auf ein zweites Modell und eine verständliche Fehlermeldung sind Pflicht, kein Komfort.
Aufräumstrategie für Checkpoints
Wie lange werden Zustände aufbewahrt, wann werden sie gelöscht — auch mit Blick auf Auskunfts- und Löschpflichten nach DSGVO.
Agenten, die den Produktivbetrieb überleben
Wir bauen AI-Agenten und LLM-Backends in Python — mit Persistenz, Evaluation und Kostenkontrolle von Anfang an. Als Python Agentur aus Berlin seit über 25 Jahren.
Erstgespräch vereinbaren →Fazit
Der Unterschied zwischen einem beeindruckenden Agenten-Prototyp und einem System, auf das sich Menschen verlassen, liegt fast vollständig außerhalb der KI. Es sind Zustand, Wiederanlauf, Idempotenz, Kostendeckel, Nachvollziehbarkeit und Tests — dieselben Themen, die jedes andere verteilte System auch hat.
LangGraph nimmt einem davon einen Teil ab, vor allem die Persistenz und die Unterbrechbarkeit. Es nimmt einem nicht die Entscheidung ab, ob man überhaupt einen Agenten braucht. Diese Frage ist die wichtigere, und sie wird in den meisten Projekten zu selten und zu spät gestellt.
Unsere Empfehlung: mit dem einfachsten Aufbau anfangen, der die Aufgabe lösen könnte — häufig ist das ein einzelner Modellaufruf mit gutem Kontext. Erst wenn nachweisbar ist, dass das nicht reicht, lohnt sich der Schritt zum Graphen. Andersherum baut man viel Architektur um ein Problem herum, das man noch nicht hat.