From 84cb3ea15142a58e4c721db66b6e44827fb63106 Mon Sep 17 00:00:00 2001 From: Isaac Francisco <78627776+isahers1@users.noreply.github.com> Date: Tue, 27 Aug 2024 21:06:09 -0700 Subject: [PATCH] [docs]: recursion limit info (#1501) * draft * vadym comments * spelling * final nits * final nits --- docs/_scripts/copy_notebooks.py | 1 + docs/docs/concepts/low_level.md | 12 ++- docs/docs/how-tos/index.md | 2 +- docs/mkdocs.yml | 1 + examples/recursion-limit.ipynb | 172 ++++++++++++++++++++++++++++++++ 5 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 examples/recursion-limit.ipynb diff --git a/docs/_scripts/copy_notebooks.py b/docs/_scripts/copy_notebooks.py index 41970fa21..9cc2e8a76 100644 --- a/docs/_scripts/copy_notebooks.py +++ b/docs/_scripts/copy_notebooks.py @@ -38,6 +38,7 @@ _MANUAL = { "visualization.ipynb", "state-model.ipynb", "subgraph.ipynb", + "recursion-limit.ipynb", "force-calling-a-tool-first.ipynb", "pass-run-time-values-to-tools.ipynb", "tool-calling.ipynb", diff --git a/docs/docs/concepts/low_level.md b/docs/docs/concepts/low_level.md index e4a6778cd..9338e0ee8 100644 --- a/docs/docs/concepts/low_level.md +++ b/docs/docs/concepts/low_level.md @@ -401,7 +401,17 @@ def node_a(state, config): ... ``` -See [this guide](../how-tos/configuration.ipynb) for a full breakdown on configuration +See [this guide](../how-tos/configuration.ipynb) for a full breakdown on configuration. + +### Recursion Limit + +The recursion limit sets the maximum number of [super-steps](#graphs) the graph can execute during a single execution. Once the limit is reached, LangGraph will raise `GraphRecursionError`. By default this value is set to 25 steps. The recursion limit can be set on any graph at runtime, and is passed to `.invoke`/`.stream` via the config dictionary. Importantly, `recursion_limit` is a standalone `config` key and should not be passed inside the `configurable` key as all other user-defined configuration. See the example below: + +```python +graph.invoke(inputs, config={"recursion_limit": 5, "configurable":{"llm": "anthropic"}}) +``` + +Read [this how-to] to learn more about how the recursion limit works. ## Breakpoints diff --git a/docs/docs/how-tos/index.md b/docs/docs/how-tos/index.md index ac32c1ad2..bcd1b70a6 100644 --- a/docs/docs/how-tos/index.md +++ b/docs/docs/how-tos/index.md @@ -15,7 +15,7 @@ These how-to guides show how to achieve that controllability. - [How to create subgraphs](subgraph.ipynb) - [How to create branches for parallel execution](branching.ipynb) - [How to create map-reduce branches for parallel execution](map-reduce.ipynb) - +- [How to control graph recursion limit](recursion-limit.ipynb) ## Persistence diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index ec1f9faab..20b357da8 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -129,6 +129,7 @@ nav: - Create subgraphs: how-tos/subgraph.ipynb - Create branches for parallel execution: how-tos/branching.ipynb - Create map-reduce branches for parallel execution: how-tos/map-reduce.ipynb + - Control graph recursion limit: how-tos/recursion-limit.ipynb - Persistence: - Add persistence ("memory"): how-tos/persistence.ipynb - Manage conversation history: how-tos/memory/manage-conversation-history.ipynb diff --git a/examples/recursion-limit.ipynb b/examples/recursion-limit.ipynb new file mode 100644 index 000000000..0021baa8b --- /dev/null +++ b/examples/recursion-limit.ipynb @@ -0,0 +1,172 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# How to control graph recursion limit\n", + "\n", + "You can set the graph recursion limit when invoking or streaming the graph. The recursion limit sets the number of supersteps that the graph is allowed to execute before it raises an error. Read more about the concept of recursion limits [here](https://langchain-ai.github.io/langgraph/concepts/low_level/#recursion-limit). Let's see an example of this in a simple graph with parallel branches to better understand exactly how the recursion limit works.\n", + "\n", + "## Define our graph" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import operator\n", + "from typing import Annotated, Any\n", + "\n", + "from typing_extensions import TypedDict\n", + "\n", + "from langgraph.graph import StateGraph, START, END\n", + "\n", + "\n", + "class State(TypedDict):\n", + " # The operator.add reducer fn makes this append-only\n", + " aggregate: Annotated[list, operator.add]\n", + "\n", + "\n", + "class ReturnNodeValue:\n", + " def __init__(self, node_secret: str):\n", + " self._value = node_secret\n", + "\n", + " def __call__(self, state: State) -> Any:\n", + " print(f\"Adding {self._value} to {state['aggregate']}\")\n", + " return {\"aggregate\": [self._value]}\n", + "\n", + "\n", + "builder = StateGraph(State)\n", + "builder.add_node(\"a\", ReturnNodeValue(\"I'm A\"))\n", + "builder.add_edge(START, \"a\")\n", + "builder.add_node(\"b\", ReturnNodeValue(\"I'm B\"))\n", + "builder.add_node(\"c\", ReturnNodeValue(\"I'm C\"))\n", + "builder.add_node(\"d\", ReturnNodeValue(\"I'm D\"))\n", + "builder.add_edge(\"a\", \"b\")\n", + "builder.add_edge(\"a\", \"c\")\n", + "builder.add_edge(\"b\", \"d\")\n", + "builder.add_edge(\"c\", \"d\")\n", + "builder.add_edge(\"d\", END)\n", + "graph = builder.compile()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "image/jpeg": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Image, display\n", + "\n", + "display(Image(graph.get_graph().draw_mermaid_png()))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we can see, our graph will execute nodes `b` and `c` in parallel (i.e. in a single super-step), which means that if we run this graph it should take exactly 3 steps. We can set the recursion limit to 3 first to check that it raises an error (the recursion limit is inclusive, so if the limit is 3 the graph will raise an error when it reaches step 3) as expected: " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Adding I'm A to []\n", + "Adding I'm B to [\"I'm A\"]\n", + "Adding I'm C to [\"I'm A\"]\n", + "Adding I'm D to [\"I'm A\", \"I'm B\", \"I'm C\"]\n", + "Recursion Error\n" + ] + } + ], + "source": [ + "from langgraph.errors import GraphRecursionError\n", + "\n", + "try:\n", + " graph.invoke({\"aggregate\": []},{\"recursion_limit\":3})\n", + "except GraphRecursionError:\n", + " print(\"Recursion Error\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Success! The graph raised an error as expected - now let's test setting the recursion limit to 4 and ensure that the graph succeeds in this case:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Adding I'm A to []\n", + "Adding I'm B to [\"I'm A\"]\n", + "Adding I'm C to [\"I'm A\"]\n", + "Adding I'm D to [\"I'm A\", \"I'm B\", \"I'm C\"]\n" + ] + } + ], + "source": [ + "try:\n", + " graph.invoke({\"aggregate\": []},{\"recursion_limit\":4})\n", + "except GraphRecursionError:\n", + " print(\"Recursion Error\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Perfect, just as we expected the graph runs successfully in this case. \n", + "\n", + "Setting the correct graph recursion limit is important for avoiding graph runs stuck in long-running loops and thus helps minimize unnecessary costs" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}