diff --git a/docs/docs/how-tos/graph-api.ipynb b/docs/docs/how-tos/graph-api.ipynb index 5c0ea0e43..85aab4b7e 100644 --- a/docs/docs/how-tos/graph-api.ipynb +++ b/docs/docs/how-tos/graph-api.ipynb @@ -1785,18 +1785,19 @@ }, { "cell_type": "markdown", - "id": "205ff836-0f97-4ee8-9830-6bd8368e48c9", + "id": "48731230", "metadata": {}, "source": [ - "
Extended example: unequal length branches\n", + "### Defer node execution\n", "\n", - "The above example showed how to fan-out and fan-in when each path was only one step. But what if one path had more than one step? Let's add a node b_2 in the \"b\" branch:\n", - "
" + "Deferring node execution is useful when you want to delay the execution of a node until all other pending tasks are completed. This is particularly relevant when branches have different lengths, which is common in workflows like map-reduce flows.\n", + "\n", + "The above example showed how to fan-out and fan-in when each path was only one step. But what if one branch had more than one step? Let's add a node `\"b_2\"` in the `\"b\"` branch:" ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 26, "id": "3890af2f-fb14-4569-b48d-a91db2d3f026", "metadata": {}, "outputs": [], @@ -1844,13 +1845,14 @@ "builder.add_node(b)\n", "builder.add_node(b_2)\n", "builder.add_node(c)\n", - "builder.add_node(d)\n", + "# highlight-next-line\n", + "builder.add_node(d, defer=True)\n", "builder.add_edge(START, \"a\")\n", "builder.add_edge(\"a\", \"b\")\n", "builder.add_edge(\"a\", \"c\")\n", "builder.add_edge(\"b\", \"b_2\")\n", - "# highlight-next-line\n", - "builder.add_edge([\"b_2\", \"c\"], \"d\")\n", + "builder.add_edge(\"b_2\", \"d\")\n", + "builder.add_edge(\"c\", \"d\")\n", "builder.add_edge(\"d\", END)\n", "graph = builder.compile()" ] @@ -1912,23 +1914,10 @@ }, { "cell_type": "markdown", - "id": "903f0da5-8c2c-4a7e-96fb-0b16b4756eff", + "id": "70e67ced", "metadata": {}, "source": [ - "
\n", - "

Note

\n", - "

In the above example, nodes \"b\" and \"c\" are executed concurrently in the same [superstep](../../concepts/low_level/#graphs). What happens in the next step?

\n", - "

We use add_edge([\"b_2\", \"c\"], \"d\") here to force node \"d\" to only run when both nodes \"b_2\" and \"c\" have finished execution. If we added two separate edges,\n", - " node \"d\" would run twice: after node b2 finishes and once again after node c (in whichever order those nodes finish).

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "c1653341-3215-4ca0-b0e7-9be22f0adaa1", - "metadata": {}, - "source": [ - "
" + "In the above example, nodes `\"b\"` and `\"c\"` are executed concurrently in the same superstep. We set `defer=True` on node `d` so it will not execute until all pending tasks are finished. In this case, this means that `\"d\"` waits to execute until the entire `\"b\"` branch is finished." ] }, { diff --git a/libs/langgraph/langgraph/graph/state.py b/libs/langgraph/langgraph/graph/state.py index f6a29198b..2a2390b75 100644 --- a/libs/langgraph/langgraph/graph/state.py +++ b/libs/langgraph/langgraph/graph/state.py @@ -304,6 +304,7 @@ class StateGraph(Graph): If a string is provided, it will be used as the node name, and action will be used as the function or runnable. action: The action associated with the node. (default: None) Will be used as the node function or runnable if `node` is a string (node name). + defer: Whether to defer the execution of the node until the run is about to end. metadata: The metadata associated with the node. (default: None) input: The input schema for the node. (default: the graph's input schema) retry: The policy for retrying the node. (default: None)