Python & AI Tutorials Logo
LangChain & LangGraph

15. Erstellen Sie Ihren ersten Graph mit LangGraph

In Teil IV haben wir Tools definiert, sie mit einem LLM verbunden und eine Agent-Schleife vollendet, die den Zyklus aus Entscheiden und Ausführen wiederholt. Die Schleife anzutreiben, Tools auszuführen, wenn das LLM sie anforderte, zu wissen, wann Schluss ist — jeden Teil dieses Ablaufs haben wir von Hand programmiert.

In diesem Kapitel bauen wir denselben Agent auf eine völlig andere Weise. Statt den Ablauf direkt zu schreiben, registrieren wir Schritte (Nodes) und Verbindungsregeln (Edges) beim LangGraph-Framework und überlassen ihm die Ausführung. Das Verhalten ist identisch mit Kapitel 14, aber die Art und Weise, wie wir es bauen, ändert sich.

Dieses Kapitel behandelt vier Kernkonzepte — StateGraph, Nodes, Edges und State — und refaktoriert dann die Agent-Schleife aus Kapitel 14 in einen LangGraph-Graph. In den folgenden Kapiteln behandelt Kapitel 16 bedingtes Routing und vorgefertigte Komponenten, und Kapitel 17 behandelt die State-Persistenz, die es einem Agent ermöglicht, dort fortzufahren, wo er unterbrochen wurde.

15.1) Warum Graphen?

15.1.1) Grenzen der bisherigen Agent-Schleife

Werfen wir noch einmal einen Blick auf die Agent-Schleife aus Kapitel 14. Nimmt man die Fehlerbehandlung und andere Details weg, sah die Kernstruktur so aus:

python
# Agent-Schleife aus Kapitel 14 — Kernstruktur (vereinfacht)
messages = [
    SystemMessage(content="You are a helpful assistant."),
    HumanMessage(content=user_input),
]
 
for step in range(max_steps):
    # Das LLM bitten, die nächste Aktion zu entscheiden
    ai_message = llm_with_tools.invoke(messages)
    messages.append(ai_message)
 
    # Wenn kein Tool-Aufruf angefordert wird, die endgültige Antwort zurückgeben
    if not ai_message.tool_calls:
        return ai_message.content
 
    # Die angeforderten Tools ausführen
    for tool_call in ai_message.tool_calls:
        selected_tool = tool_map[tool_call["name"]]
        tool_message = selected_tool.invoke(tool_call)
        messages.append(tool_message)

Dieser Code deckt nur die Grundlagen ab und sonst nichts. In einer echten Produktionsumgebung ist jedoch weit mehr erforderlich. Hier sind einige Beispiele.

  • Wiederherstellung nach Abstürzen — Wenn ein Agent bei Schritt 7 einer aus 10 Schritten bestehenden Recherche-Aufgabe abstürzt, sollte er ab Schritt 7 fortfahren können, statt von vorne zu beginnen.
  • Freigabeanfragen — Bevor ein Agent eine kritische Operation ausführt, sollte er innehalten und einen Menschen fragen können: „Ist es in Ordnung, fortzufahren?“
  • Echtzeit-Monitoring — Benutzer sollten sehen können, was der Agent gerade tut und welche Tools er aufruft.
  • Visualisierung und Debugging — Ein Diagramm, das zeigt, wie der Agent arbeitet, sollte verfügbar sein, damit man bei auftretenden Problemen nachvollziehen kann, welcher Schritt schiefgelaufen ist.

Diese Funktionen selbst zu implementieren ist nicht unmöglich, aber auch nicht einfach. Allein die Wiederherstellung nach Abstürzen erfordert Code, der den State bei jedem Schritt serialisiert, auf der Festplatte speichert, wiederherstellt und an genau der richtigen Stelle fortfährt. Am Ende könnte man mehr Infrastruktur-Code als Geschäftslogik haben.

LangGraph wurde entwickelt, um diese Funktionen auf Framework-Ebene bereitzustellen. Wiederherstellung nach Abstürzen, Freigabeanfragen, Monitoring, Visualisierung — das Framework übernimmt all das. Aber es gibt eine Voraussetzung: Sie müssen Ihren Agent in einer Struktur bauen, die das Framework verstehen kann.

Die Agent-Schleife aus Kapitel 14 verarbeitet die gesamte Logik direkt, sodass es für das Framework nichts gibt, an das es andocken könnte. Um von dem zu profitieren, was LangGraph bietet, müssen wir den Agent in einer Struktur neu aufbauen, die LangGraph versteht — einem Graph. Genau darum geht es in diesem Kapitel.

15.1.2) Was ist LangGraph?

LangGraph ist ein Orchestrierungs-Framework, das Agent-Workflows als Graphen definiert und ausführt. Ein Graph bedeutet hier eine Struktur, in der jeder Node (Schritt), den der Agent ausführt, durch Edges (Verbindungsregeln) verbunden ist.

In LangGraph zerlegen Sie den Workflow in unabhängige Nodes und verbinden sie mit Edges. LangGraph durchläuft dann den Graph und führt dabei jeden Node aus. So sieht die Agent-Schleife aus Kapitel 14 aus, wenn man sie als Graph darstellt:

Ja

Nein

START

LLM-Aufruf

Tool-Aufruf angefordert?

Tool-Ausführung

END

Die rechteckigen Kästchen sind Nodes, und die Pfeile sind Edges. Die Raute stellt eine bedingte Edge dar, die je nach Bedingung zu unterschiedlichen Pfaden verzweigt.

In Kapitel 14 lebte der gesamte Workflow in for-Schleifen, if-Prüfungen und anderem handgeschriebenem Code. Mit LangGraph definieren Sie, was jeder Node tut, und verdrahten die Nodes mit Edges. Kurz gesagt, Sie gehen davon über, den Workflow zu programmieren, hin dazu, ihn als Struktur zu deklarieren.

LangGraph ersetzt nichts von dem, was Sie in den Kapiteln 12–14 gelernt haben. Tool-Definitionen, bind_tools(), tool_calls, ToolMessage — all das wird weiterhin innerhalb von Nodes verwendet, genau wie zuvor.

Der nächste Abschnitt behandelt die Kernkomponenten von LangGraph — StateGraph, State, Nodes und Edges — nacheinander.

15.2) LangGraph-Komponenten: StateGraph, State, Nodes, Edges

Dieser Abschnitt geht LangGraphs vier Kernkomponenten nacheinander durch. Wir beginnen mit StateGraph — der Klasse, die State, Nodes und Edges zu einem Graph bündelt — und behandeln dann jeden der Teile (State, Nodes, Edges), die hineingehören.

15.2.1) StateGraph

StateGraph ist die Klasse, die zum Erstellen von Graphen in LangGraph verwendet wird. Sie geben den State an, den der Graph verwalten wird, fügen Nodes hinzu, verbinden sie mit Edges und kompilieren dann, um einen ausführbaren Graph zu erzeugen.

Sehen wir uns an, wie das funktioniert.

Erstellen einer StateGraph-Instanz

Rufen Sie den StateGraph-Konstruktor auf, um eine Instanz zu erstellen. Sie müssen das State-Schema (die Klasse selbst) als Parameter übergeben. Hier verwenden wir MessagesState, einen vordefinierten State, den LangGraph zur Verwaltung von Nachrichtenlisten bereitstellt. Die Details behandeln wir in 15.2.2.

python
from langgraph.graph import StateGraph, MessagesState
 
builder = StateGraph(MessagesState)

Hinzufügen von Nodes

Verwenden Sie add_node(), um einen Node zu registrieren. Ein Node ist eine Python-Funktion, die den aktuellen State entgegennimmt und die Teile zurückgibt, die sie ändern möchte. Node-Funktionen behandeln wir ausführlich in 15.2.3.

python
def say_hello(state: MessagesState):
    return {"messages": [{"role": "ai", "content": "hello world"}]}
 
builder.add_node(say_hello)    # Node-Name wird zu "say_hello"

Verbinden von Edges

Verwenden Sie add_edge(source, target), um Nodes zu verbinden. source ist der Startpunkt der Edge; target ist ihr Ziel. START und END sind spezielle Markierungen für die Ein- und Ausstiegspunkte des Graphen. Edges behandeln wir in 15.2.4.

python
from langgraph.graph import START, END
 
builder.add_edge(START, "say_hello")   # Graph startet → say_hello ausführen
builder.add_edge("say_hello", END)     # say_hello ist fertig → Graph beenden

Kompilieren und Ausführen

Der Aufruf von compile() validiert die Graph-Struktur und erzeugt ein ausführbares Objekt. Sie führen den kompilierten Graph mit invoke() aus und übergeben dabei die initialen State-Werte.

python
graph = builder.compile()
 
initial_state = {"messages": [{"role": "user", "content": "hi!"}]}
result = graph.invoke(initial_state)

Fügen wir nun alles zusammen und bauen einen einfachen Graph:

python
from langgraph.graph import StateGraph, MessagesState, START, END
 
def say_hello(state: MessagesState):
    return {"messages": [{"role": "ai", "content": "hello world"}]}
 
builder = StateGraph(MessagesState)
 
builder.add_node(say_hello)
builder.add_edge(START, "say_hello")
builder.add_edge("say_hello", END)
 
graph = builder.compile()
 
initial_state = {"messages": [{"role": "user", "content": "hi!"}]}
result = graph.invoke(initial_state)
print(result["messages"][-1].content)

Ausgabe:

hello world

Wenn Sie invoke() aufrufen, läuft der Graph in der Reihenfolge STARTsay_helloEND. say_hello gab ein Dictionary mit messages als Schlüssel zurück, und dieser Wert wurde an die messages-Liste in MessagesState angehängt. Wie das funktioniert, vertiefen wir in 15.2.2. Das Ergebnis ist, dass das Herausziehen des Inhalts der letzten Nachricht uns "hello world" liefert.

15.2.2) State: Daten, die durch den Graph fließen

State sind die Daten, die jeder Node im Graph gemeinsam nutzt. Wenn ein Node läuft, empfängt er den aktuellen State, erledigt seine Arbeit und gibt nur die Teile zurück, die er ändern möchte. LangGraph führt diese Änderungen wieder in den State zusammen und übergibt die aktualisierte Version an den nächsten Node.

State definieren

Sie definieren State, indem Sie von TypedDict erben. Wählen Sie die Felder und Typen, die zu dem passen, was Ihr Agent verfolgen muss. Hier ist ein einfaches Beispiel:

python
from typing_extensions import TypedDict
 
class AgentState(TypedDict):
    messages: list       # Nachrichtenliste
    llm_calls: int       # Anzahl der LLM-Aufrufe

Von hier aus übergeben Sie AgentState beim Erstellen eines StateGraph und verwenden es als Typ-Hinweis für Ihre Node-Funktionen.

Reducer

Wenn ein Node einen Wert zurückgibt, wird das entsprechende State-Feld aktualisiert. Das Standardverhalten ist Überschreiben — wenn ein Node {"llm_calls": 3} zurückgibt, wird llm_calls einfach zu 3, egal was es vorher war.

Aber einige Felder müssen angehängt und nicht überschrieben werden. Was passiert, wenn messages überschrieben wird? Jedes Mal, wenn ein Node eine neue Nachricht zurückgibt, verschwindet der gesamte Gesprächsverlauf. Für messages ist Anhängen das richtige Verhalten.

LangGraph ermöglicht es Ihnen, pro Feld eine andere Aktualisierungsstrategie über eine Reducer-Funktion festzulegen. Sie geben den Reducer als zweites Argument in Annotated an:

python
from typing_extensions import TypedDict, Annotated
from langgraph.graph.message import add_messages
 
class AgentState(TypedDict):
    messages: Annotated[list, add_messages]   # Reducer: anhängen
    llm_calls: int                            # kein Reducer: überschreiben

add_messages ist ein von LangGraph bereitgestellter Reducer. Statt die Liste zu ersetzen, hängt er neue Nachrichten an das bereits Vorhandene an. Da dieser Reducer auf dem Feld messages gesetzt ist, wird jeder Wert, den ein Node für messages zurückgibt, angehängt. llm_calls hat keinen Reducer, sodass zurückgegebene Werte einfach überschreiben, was zuvor da war.

Genau deshalb wurde die Nachricht, die say_hello in 15.2.1 zurückgab, an messages angehängt, statt sie zu ersetzen — der Reducer hat das übernommen.

MessagesState

LangGraph wird mit einem vordefinierten State namens MessagesState ausgeliefert. So sieht er unter der Haube aus:

python
class MessagesState(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]

Dieselbe Struktur, die wir gerade behandelt haben — ein messages-Feld mit dem bereits verdrahteten add_messages-Reducer.

Wenn Sie zusätzliche Felder benötigen, erben Sie einfach davon:

python
from langgraph.graph import MessagesState
 
class AgentState(MessagesState):
    llm_calls: int  # standardmäßiges Überschreiben-Verhalten

15.2.3) Nodes: Funktionen, die den State aktualisieren

Ein Node ist eine Python-Funktion, die eine einzelne, bestimmte Aufgabe innerhalb des Graphen ausführt.

python
def say_hello(state: MessagesState):
    return {"messages": [{"role": "ai", "content": "hello world"}]}

Zwei Dinge, die Sie beim Schreiben von Node-Funktionen wissen sollten:

Regel 1: Sie empfängt den aktuellen State als Argument. LangGraph übergibt das aktuelle State-Objekt, wenn es den Node ausführt.

Regel 2: Sie gibt nur die Teile zurück, die sie ändern möchte, nicht den vollständigen State. Nodes ändern den State nicht direkt. Geben Sie einfach die Felder zurück, die Sie aktualisieren möchten, und LangGraph führt sie gemäß den Reducer-Regeln jedes Feldes in den bestehenden State zusammen.

Verwenden Sie add_node(), um einen Node zum StateGraph hinzuzufügen:

python
builder.add_node(say_hello)          # Funktionsname "say_hello" wird zum Node-Namen
builder.add_node("my_node", my_func) # Sie können den Namen auch explizit angeben

15.2.4) Edges: Regeln, die Nodes verbinden

Eine Edge bestimmt: „Was läuft als Nächstes, nachdem dieser Node fertig ist?“ Es gibt zwei Typen.

Normale Edges

Eine normale Edge verdrahtet einen festen „Gehe-zu“-Übergang zwischen zwei Nodes. Verwenden Sie add_edge(source, target)source ist der Start-Node, target ist das Ziel.

python
builder.add_edge(START, "say_hello")       # wenn der Graph startet, say_hello ausführen
builder.add_edge("say_hello", "llm_call")  # nach say_hello, llm_call ausführen
builder.add_edge("llm_call", END)          # nach llm_call, den Graph beenden

Bedingte Edges

Eine bedingte Edge wählt zur Laufzeit den nächsten Node basierend auf dem aktuellen State aus. Verwenden Sie add_conditional_edges(source, routing_function)source ist der Start-Node, und routing_function ist eine Funktion, die den aktuellen State entgegennimmt und den Namen des nächsten Nodes zurückgibt:

python
from langgraph.graph import END
 
def should_continue(state: AgentState):
    last_message = state["messages"][-1]
    if last_message.tool_calls:
        return "tool_node"   # Tool-Aufruf angefordert → zu tool_node gehen
    return END               # kein Tool-Aufruf → beenden
 
builder.add_conditional_edges("llm_call", should_continue)

add_conditional_edges("llm_call", should_continue) teilt LangGraph mit: „wenn llm_call fertig ist, rufe should_continue auf, um zu entscheiden, was als Nächstes läuft.“ should_continue leitet zu "tool_node" weiter, wenn die letzte Nachricht tool_calls enthält, oder zu END, wenn nicht. In der Praxis bedeutet das, dass der Graph zum Tool-Ausführungs-Node weiterläuft, wenn das LLM einen Tool-Aufruf anfordert, und beendet wird, wenn nicht.

Nachdem wir nun alle vier Komponenten behandelt haben, verwendet der nächste Abschnitt sie, um die Agent-Schleife aus Kapitel 14 in einen LangGraph-Graph zu refaktorieren.

15.3) Refaktorieren der Agent-Schleife in einen Graph

Bauen wir die Agent-Schleife aus Kapitel 14 mit LangGraph neu auf. Das Verhalten ist identisch mit Kapitel 14 — das LLM entscheidet, Tools werden basierend auf den Anforderungen des LLM ausgeführt, und der Zyklus wiederholt sich bis zur Fertigstellung. Das Einzige, was sich ändert, ist, wie wir diesen Ablauf strukturieren.

So wird der fertige Graph aussehen:

Ja

Nein

START

llm_call

Tool-Aufruf angefordert?

tool_node

END

Der Graph pendelt zwischen llm_call und tool_node, bis das LLM keine Tool-Aufrufe mehr anfordert, woraufhin er zu END austritt. Bauen wir ihn Schritt für Schritt auf.

15.3.1) State definieren

Wir erben von MessagesState aus 15.2.2, um den State des Agents zu definieren. Das messages-Feld wird von MessagesState geerbt, und wir fügen ein llm_calls-Feld hinzu, um die Anzahl der LLM-Aufrufe zu verfolgen.

python
from langgraph.graph import MessagesState
 
class AgentState(MessagesState):
    llm_calls: int    # Anzahl der LLM-Aufrufe (überschreiben)

Die messages-Liste sammelt Benutzereingaben (HumanMessage), LLM-Antworten (AIMessage) und Tool-Ausführungsergebnisse (ToolMessage) der Reihe nach an.

15.3.2) Nodes bauen

Richten wir zunächst die Tools und das Modell aus Kapitel 14 ein:

python
from langchain_openai import ChatOpenAI
from langchain_core.messages import ToolMessage
from langchain.tools import tool
 
@tool
def get_weather(city: str) -> str:
    """Ruft das aktuelle Wetter für eine Stadt ab."""
    fake_data = {"Tokyo": "18°C, cloudy", "Cairo": "31°C, sunny"}
    return fake_data.get(city, f"No weather data for {city}.")
 
@tool
def calculate(expression: str) -> str:
    """Berechnet einen einfachen arithmetischen Ausdruck. Beispiel: '3 * 21'."""
    return str(eval(expression))  # Warnung: eval() ist ein Sicherheitsrisiko. Nicht in der Produktion verwenden.
 
tools = [get_weather, calculate]
tool_map = {t.name: t for t in tools}
 
llm = ChatOpenAI(model="gpt-5-mini")
model_with_tools = llm.bind_tools(tools)

Schreiben wir nun die beiden Node-Funktionen.

llm_call-Node — Ruft das LLM auf und gibt die Antwort zurück:

python
def llm_call(state: AgentState):
    """Ruft das LLM auf und gibt die Antwort zurück."""
    response = model_with_tools.invoke(state["messages"])
    return {
        "messages": [response],
        "llm_calls": state.get("llm_calls", 0) + 1,
    }

model_with_tools.invoke() ruft das LLM auf, und die Antwort wird unter dem Schlüssel messages im Rückgabe-Dictionary verpackt. Der Reducer hängt sie an die bestehenden messages in AgentState an. llm_calls gibt den aktuellen Zählerstand plus 1 zurück und überschreibt den vorherigen Wert.

tool_node-Node — Führt die vom LLM angeforderten Tools aus und gibt die Ergebnisse zurück:

python
def tool_node(state: AgentState):
    """Führt die vom LLM angeforderten Tools aus."""
    last_message = state["messages"][-1]
    results = []
    for tool_call in last_message.tool_calls:
        selected_tool = tool_map[tool_call["name"]]
        tool_message = selected_tool.invoke(tool_call)
        results.append(tool_message)
    return {"messages": results}

Da tool_node immer direkt nach llm_call läuft, ist die letzte Nachricht in messages garantiert die AIMessage, die das LLM gerade erzeugt hat. Das tool_calls-Feld dieser Nachricht enthält die Tool-Aufrufe, die das LLM angefordert hat. Der Node führt jedes Tool aus, sammelt die Ergebnisse in results und gibt sie unter dem Schlüssel messages zurück — der Reducer kümmert sich darum, sie an die bestehende Liste anzuhängen.

15.3.3) Bedingte Edge

Sobald llm_call fertig ist, benötigen wir eine bedingte Edge, um zu entscheiden, ob tool_node ausgeführt oder der Graph beendet werden soll. Dies folgt demselben Muster aus 15.2.4:

python
from typing import Literal
from langgraph.graph import END
 
def should_continue(state: AgentState) -> Literal["tool_node", "__end__"]:
    """Entscheidet, ob Tools ausgeführt oder der Graph beendet werden soll."""
    last_message = state["messages"][-1]
    if last_message.tool_calls:
        return "tool_node"
    return END

Wenn last_message.tool_calls vorhanden ist, fordert das LLM einen Tool-Aufruf an, also leiten wir zu tool_node weiter. Andernfalls leiten wir zu END weiter und der Graph wird beendet.

Der Rückgabetyp-Hinweis Literal["tool_node", "__end__"] deklariert die möglichen Ziele, die diese Funktion zurückgeben kann. LangGraph benötigt diesen Hinweis, um die Pfade bedingter Edges in Graph-Visualisierungen korrekt zu zeichnen. Er hat keine Auswirkung auf das Laufzeitverhalten.

"__end__" ist der zugrunde liegende String-Wert von END. Da Literal nur String-Literale akzeptiert, schreiben wir "__end__" statt END.

15.3.4) Zusammensetzen und Ausführen des Graphen

Zeit, alles zu verdrahten. Setzen wir den State, die Nodes und die bedingte Edge zu einem StateGraph zusammen und kompilieren:

python
from langgraph.graph import StateGraph, START, END
 
builder = StateGraph(AgentState)
 
builder.add_node("llm_call", llm_call)
builder.add_node("tool_node", tool_node)
 
builder.add_edge(START, "llm_call")                         # Start → llm_call
builder.add_conditional_edges("llm_call", should_continue)  # llm_call → tool_node oder END
builder.add_edge("tool_node", "llm_call")                   # tool_node → llm_call (Schleife)
 
agent = builder.compile()

Die Edge von tool_node zurück zu llm_call erzeugt eine Schleife. Die Ausführung durchläuft weiter Zyklen, bis das LLM mit einer endgültigen Antwort reagiert, statt einen weiteren Tool-Aufruf anzufordern, woraufhin die Schleife beendet wird.

Führen wir ihn aus:

python
from langchain_core.messages import HumanMessage
 
result = agent.invoke({
    "messages": [HumanMessage(content="Get the temperature in Cairo, then multiply the number by 3.")],
    "llm_calls": 0,
})
 
print(result["messages"][-1].content)
print(f"\nTotal LLM calls: {result['llm_calls']}")

Ausgabe:

Current temperature in Cairo: 31°C. Multiplied by 3 = 93.
 
Total LLM calls: 3

Der Agent rief get_weather("Cairo") auf, sah das Ergebnis, rief calculate("31 * 3") auf und erzeugte die endgültige Antwort — dasselbe Ergebnis, das wir in Kapitel 14 erhalten haben.

Die Betrachtung des vollständigen Nachrichtenverlaufs zeigt jeden Schritt, der der Reihe nach in messages aufgezeichnet wurde:

python
for message in result["messages"]:
    message.pretty_print()

Ausgabe:

================================ Human Message =================================
Get the temperature in Cairo, then multiply the number by 3.
================================== Ai Message ==================================
Tool Calls:
  get_weather (call_DiL9WF)
  Args:
    city: Cairo
================================= Tool Message =================================
Name: get_weather
31°C, sunny
================================== Ai Message ==================================
Tool Calls:
  calculate (call_wa6RqWST)
  Args:
    expression: 31 * 3
================================= Tool Message =================================
Name: calculate
93
================================== Ai Message ==================================
Current temperature in Cairo: 31°C. Multiplied by 3 = 93.

15.3.5) Graph-Visualisierung

In einem Jupyter-Notebook rendert agent.get_graph().draw_mermaid_png() die Graph-Struktur direkt in der Zellenausgabe als Bild.

python
from IPython.display import Image, display
 
display(Image(agent.get_graph().draw_mermaid_png()))

In einer Terminal-Umgebung speichern Sie sie stattdessen als PNG-Datei.

python
agent.get_graph().draw_mermaid_png(output_file_path="agent_graph.png")

Erzeugtes Bild:

__start__

llm_call

tool_node

__end__

Durchgezogene Linien sind normale Edges und gepunktete Linien sind bedingte Edges. Dieses Diagramm wird automatisch aus dem Code generiert.

15.3.6) Rekursionslimit

Genau wie wir in Kapitel 14 max_steps verwendet haben, um uns vor Endlosschleifen zu schützen, verfügt LangGraph über ein eingebautes Sicherheitsnetz. Jedes Mal, wenn ein Node während der Graph-Ausführung läuft, wird ein interner Zähler um eins erhöht. Wenn dieser Zähler das konfigurierte Limit überschreitet, löst LangGraph einen GraphRecursionError aus.

Um zu sehen, wie die Zählung funktioniert, betrachten Sie den vorherigen Lauf. Der Aufruf sowohl von get_weather als auch von calculate besuchte die Nodes in dieser Reihenfolge:

llm_call(1) → tool_node(2) → llm_call(3) → tool_node(4) → llm_call(5) → END

Das sind insgesamt 5 Node-Besuche. Wenn Sie recursion_limit auf 3 setzen, greift das Limit beim 3. Besuch und der Lauf wird abgebrochen:

python
from langgraph.errors import GraphRecursionError
 
try:
    result = agent.invoke(
        {"messages": [HumanMessage(content="Get the temperature in Cairo, then multiply the number by 3.")],
         "llm_calls": 0},
        config={"recursion_limit": 3},
    )
except GraphRecursionError:
    print("Agent hit the recursion limit — stopping execution.")

Ausgabe:

Agent hit the recursion limit — stopping execution.

Legen Sie das Limit fest, indem Sie config={"recursion_limit": number} an invoke() übergeben. Der richtige Wert hängt von Ihrem Anwendungsfall und der Komplexität Ihres Graphen ab. Beginnen Sie mit einem großzügigen Wert und passen Sie ihn durch Tests an.