mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-17 21:25:46 +02:00
76 KiB
76 KiB
In [2]:
%%capture --no-stderr
%pip install -U langgraphIn [ ]:
import getpass
import os
def _set_env(var: str):
if not os.environ.get(var):
os.environ[var] = getpass.getpass(f"{var}: ")
os.environ["LANGCHAIN_TRACING_V2"] = "true"
_set_env("LANGCHAIN_API_KEY")In [1]:
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import StateGraph
def reduce_list(left: list | None, right: list | None) -> list:
if not left:
left = []
if not right:
right = []
return left + right
class ChildState(TypedDict):
name: str
path: Annotated[list[str], reduce_list]
class ParentState(TypedDict):
name: str
path: Annotated[list[str], reduce_list]
child_builder = StateGraph(ChildState)
child_builder.add_node("child_start", lambda state: {"path": ["child_start"]})
child_builder.set_entry_point("child_start")
child_builder.add_node("child_middle", lambda state: {"path": ["child_middle"]})
child_builder.add_node("child_end", lambda state: {"path": ["child_end"]})
child_builder.add_edge("child_start", "child_middle")
child_builder.add_edge("child_middle", "child_end")
child_builder.set_finish_point("child_end")
builder = StateGraph(ParentState)
builder.add_node("grandparent", lambda state: {"path": ["grandparent"]})
builder.set_entry_point("grandparent")
builder.add_node("parent", lambda state: {"path": ["parent"]})
builder.add_node("child", child_builder.compile())
builder.add_node("sibling", lambda state: {"path": ["sibling"]})
builder.add_node("fin", lambda state: {"path": ["fin"]})
# Add connections
builder.add_edge("grandparent", "parent")
builder.add_edge("parent", "child")
builder.add_edge("parent", "sibling")
builder.add_edge("child", "fin")
builder.add_edge("sibling", "fin")
builder.set_finish_point("fin")
graph = builder.compile()In [3]:
from IPython.display import Image, display
# Setting xray to 1 will show the internal structure of the nested graph
display(Image(graph.get_graph(xray=1).draw_mermaid_png()))In [17]:
graph.invoke({"name": "test"}, debug=True)Out [17]:
[36;1m[1;3m[0:tasks][0m [1mStarting step 0 with 1 task: [0m- [32;1m[1;3m__start__[0m -> {'name': 'test'} [36;1m[1;3m[0:writes][0m [1mFinished step 0 with writes to 1 channel: [0m- [33;1m[1;3mname[0m -> 'test' [36;1m[1;3m[0:checkpoint][0m [1mState at the end of step 0: [0m{'name': 'test', 'path': []} [36;1m[1;3m[1:tasks][0m [1mStarting step 1 with 1 task: [0m- [32;1m[1;3mgrandparent[0m -> {'name': 'test', 'path': []} [36;1m[1;3m[1:writes][0m [1mFinished step 1 with writes to 1 channel: [0m- [33;1m[1;3mpath[0m -> ['grandparent'] [36;1m[1;3m[1:checkpoint][0m [1mState at the end of step 1: [0m{'name': 'test', 'path': ['grandparent']} [36;1m[1;3m[2:tasks][0m [1mStarting step 2 with 1 task: [0m- [32;1m[1;3mparent[0m -> {'name': 'test', 'path': ['grandparent']} [36;1m[1;3m[2:writes][0m [1mFinished step 2 with writes to 1 channel: [0m- [33;1m[1;3mpath[0m -> ['parent'] [36;1m[1;3m[2:checkpoint][0m [1mState at the end of step 2: [0m{'name': 'test', 'path': ['grandparent', 'parent']} [36;1m[1;3m[3:tasks][0m [1mStarting step 3 with 2 tasks: [0m- [32;1m[1;3mchild[0m -> {'name': 'test', 'path': ['grandparent', 'parent']} - [32;1m[1;3msibling[0m -> {'name': 'test', 'path': ['grandparent', 'parent']} [36;1m[1;3m[3:writes][0m [1mFinished step 3 with writes to 2 channels: [0m- [33;1m[1;3mname[0m -> 'test' - [33;1m[1;3mpath[0m -> ['grandparent', 'parent', 'child_start', 'child_middle', 'child_end'], ['sibling'] [36;1m[1;3m[3:checkpoint][0m [1mState at the end of step 3: [0m{'name': 'test', 'path': ['grandparent', 'parent', 'grandparent', 'parent', 'child_start', 'child_middle', 'child_end', 'sibling']} [36;1m[1;3m[4:tasks][0m [1mStarting step 4 with 1 task: [0m- [32;1m[1;3mfin[0m -> {'name': 'test', 'path': ['grandparent', 'parent', 'grandparent', 'parent', 'child_start', 'child_middle', 'child_end', 'sibling']} [36;1m[1;3m[4:writes][0m [1mFinished step 4 with writes to 1 channel: [0m- [33;1m[1;3mpath[0m -> ['fin'] [36;1m[1;3m[4:checkpoint][0m [1mState at the end of step 4: [0m{'name': 'test', 'path': ['grandparent', 'parent', 'grandparent', 'parent', 'child_start', 'child_middle', 'child_end', 'sibling', 'fin']}
{'name': 'test',
'path': ['grandparent',
'parent',
'grandparent',
'parent',
'child_start',
'child_middle',
'child_end',
'sibling',
'fin']}In [23]:
import uuid
def reduce_list(left: list | None, right: list | None) -> list:
"""Append the right-hand list, replacing any elements with the same id in the left-hand list."""
if not left:
left = []
if not right:
right = []
left_, right_ = [], []
for orig, new in [(left, left_), (right, right_)]:
for val in orig:
if not isinstance(val, dict):
val = {"val": val}
if "id" not in val:
val["id"] = str(uuid.uuid4())
new.append(val)
# Merge the two lists
left_idx_by_id = {val["id"]: i for i, val in enumerate(left_)}
merged = left_.copy()
for val in right_:
if (existing_idx := left_idx_by_id.get(val["id"])) is not None:
merged[existing_idx] = val
else:
merged.append(val)
return merged
class ChildState(TypedDict):
name: str
path: Annotated[list[str], reduce_list]
class ParentState(TypedDict):
name: str
path: Annotated[list[str], reduce_list]In [24]:
child_builder = StateGraph(ChildState)
child_builder.add_node("child_start", lambda state: {"path": ["child_start"]})
child_builder.set_entry_point("child_start")
child_builder.add_node("child_middle", lambda state: {"path": ["child_middle"]})
child_builder.add_node("child_end", lambda state: {"path": ["child_end"]})
child_builder.add_edge("child_start", "child_middle")
child_builder.add_edge("child_middle", "child_end")
child_builder.set_finish_point("child_end")
builder = StateGraph(ParentState)
builder.add_node("grandparent", lambda state: {"path": ["grandparent"]})
builder.set_entry_point("grandparent")
builder.add_node("parent", lambda state: {"path": ["parent"]})
builder.add_node("child", child_builder.compile())
builder.add_node("sibling", lambda state: {"path": ["sibling"]})
builder.add_node("fin", lambda state: {"path": ["fin"]})
# Add connections
builder.add_edge("grandparent", "parent")
builder.add_edge("parent", "child")
builder.add_edge("parent", "sibling")
builder.add_edge("child", "fin")
builder.add_edge("sibling", "fin")
builder.set_finish_point("fin")
graph = builder.compile()In [25]:
from IPython.display import Image, display
# Setting xray to 1 will show the internal structure of the nested graph
display(Image(graph.get_graph(xray=1).draw_mermaid_png()))In [26]:
graph.invoke({"name": "test"}, debug=True)Out [26]:
[36;1m[1;3m[0:tasks][0m [1mStarting step 0 with 1 task: [0m- [32;1m[1;3m__start__[0m -> {'name': 'test'} [36;1m[1;3m[0:writes][0m [1mFinished step 0 with writes to 1 channel: [0m- [33;1m[1;3mname[0m -> 'test' [36;1m[1;3m[0:checkpoint][0m [1mState at the end of step 0: [0m{'name': 'test', 'path': []} [36;1m[1;3m[1:tasks][0m [1mStarting step 1 with 1 task: [0m- [32;1m[1;3mgrandparent[0m -> {'name': 'test', 'path': []} [36;1m[1;3m[1:writes][0m [1mFinished step 1 with writes to 1 channel: [0m- [33;1m[1;3mpath[0m -> ['grandparent'] [36;1m[1;3m[1:checkpoint][0m [1mState at the end of step 1: [0m{'name': 'test', 'path': [{'id': '79a81f03-d16d-4d12-94a6-4ba29fc9ce49', 'val': 'grandparent'}]} [36;1m[1;3m[2:tasks][0m [1mStarting step 2 with 1 task: [0m- [32;1m[1;3mparent[0m -> {'name': 'test', 'path': [{'id': '79a81f03-d16d-4d12-94a6-4ba29fc9ce49', 'val': 'grandparent'}]} [36;1m[1;3m[2:writes][0m [1mFinished step 2 with writes to 1 channel: [0m- [33;1m[1;3mpath[0m -> ['parent'] [36;1m[1;3m[2:checkpoint][0m [1mState at the end of step 2: [0m{'name': 'test', 'path': [{'id': '79a81f03-d16d-4d12-94a6-4ba29fc9ce49', 'val': 'grandparent'}, {'id': '2a6f0263-3949-4e47-a210-57f817e6097d', 'val': 'parent'}]} [36;1m[1;3m[3:tasks][0m [1mStarting step 3 with 2 tasks: [0m- [32;1m[1;3mchild[0m -> {'name': 'test', 'path': [{'id': '79a81f03-d16d-4d12-94a6-4ba29fc9ce49', 'val': 'grandparent'}, {'id': '2a6f0263-3949-4e47-a210-57f817e6097d', 'val': 'parent'}]} - [32;1m[1;3msibling[0m -> {'name': 'test', 'path': [{'id': '79a81f03-d16d-4d12-94a6-4ba29fc9ce49', 'val': 'grandparent'}, {'id': '2a6f0263-3949-4e47-a210-57f817e6097d', 'val': 'parent'}]} [36;1m[1;3m[3:writes][0m [1mFinished step 3 with writes to 2 channels: [0m- [33;1m[1;3mname[0m -> 'test' - [33;1m[1;3mpath[0m -> [{'id': '79a81f03-d16d-4d12-94a6-4ba29fc9ce49', 'val': 'grandparent'}, {'id': '2a6f0263-3949-4e47-a210-57f817e6097d', 'val': 'parent'}, {'id': 'd1c1bab0-6e19-4846-a470-e9cc2eb85088', 'val': 'child_start'}, {'id': 'e0fcb647-1e9e-4ae4-b560-0046515d5783', 'val': 'child_middle'}, {'id': '669dd810-360f-4694-a9f3-49597f23376a', 'val': 'child_end'}], ['sibling'] [36;1m[1;3m[3:checkpoint][0m [1mState at the end of step 3: [0m{'name': 'test', 'path': [{'id': '79a81f03-d16d-4d12-94a6-4ba29fc9ce49', 'val': 'grandparent'}, {'id': '2a6f0263-3949-4e47-a210-57f817e6097d', 'val': 'parent'}, {'id': 'd1c1bab0-6e19-4846-a470-e9cc2eb85088', 'val': 'child_start'}, {'id': 'e0fcb647-1e9e-4ae4-b560-0046515d5783', 'val': 'child_middle'}, {'id': '669dd810-360f-4694-a9f3-49597f23376a', 'val': 'child_end'}, {'id': '137dbc2f-b33c-4ea4-8b04-a62215ba9718', 'val': 'sibling'}]} [36;1m[1;3m[4:tasks][0m [1mStarting step 4 with 1 task: [0m- [32;1m[1;3mfin[0m -> {'name': 'test', 'path': [{'id': '79a81f03-d16d-4d12-94a6-4ba29fc9ce49', 'val': 'grandparent'}, {'id': '2a6f0263-3949-4e47-a210-57f817e6097d', 'val': 'parent'}, {'id': 'd1c1bab0-6e19-4846-a470-e9cc2eb85088', 'val': 'child_start'}, {'id': 'e0fcb647-1e9e-4ae4-b560-0046515d5783', 'val': 'child_middle'}, {'id': '669dd810-360f-4694-a9f3-49597f23376a', 'val': 'child_end'}, {'id': '137dbc2f-b33c-4ea4-8b04-a62215ba9718', 'val': 'sibling'}]} [36;1m[1;3m[4:writes][0m [1mFinished step 4 with writes to 1 channel: [0m- [33;1m[1;3mpath[0m -> ['fin'] [36;1m[1;3m[4:checkpoint][0m [1mState at the end of step 4: [0m{'name': 'test', 'path': [{'id': '79a81f03-d16d-4d12-94a6-4ba29fc9ce49', 'val': 'grandparent'}, {'id': '2a6f0263-3949-4e47-a210-57f817e6097d', 'val': 'parent'}, {'id': 'd1c1bab0-6e19-4846-a470-e9cc2eb85088', 'val': 'child_start'}, {'id': 'e0fcb647-1e9e-4ae4-b560-0046515d5783', 'val': 'child_middle'}, {'id': '669dd810-360f-4694-a9f3-49597f23376a', 'val': 'child_end'}, {'id': '137dbc2f-b33c-4ea4-8b04-a62215ba9718', 'val': 'sibling'}, {'id': 'a4328c5f-845a-43de-b3d7-53a39208e316', 'val': 'fin'}]}
{'name': 'test',
'path': [{'val': 'grandparent', 'id': '79a81f03-d16d-4d12-94a6-4ba29fc9ce49'},
{'val': 'parent', 'id': '2a6f0263-3949-4e47-a210-57f817e6097d'},
{'val': 'child_start', 'id': 'd1c1bab0-6e19-4846-a470-e9cc2eb85088'},
{'val': 'child_middle', 'id': 'e0fcb647-1e9e-4ae4-b560-0046515d5783'},
{'val': 'child_end', 'id': '669dd810-360f-4694-a9f3-49597f23376a'},
{'val': 'sibling', 'id': '137dbc2f-b33c-4ea4-8b04-a62215ba9718'},
{'val': 'fin', 'id': 'a4328c5f-845a-43de-b3d7-53a39208e316'}]}