diff --git a/docs/_scripts/copy_notebooks.py b/docs/_scripts/copy_notebooks.py index 1a3af4487..402ecfc01 100644 --- a/docs/_scripts/copy_notebooks.py +++ b/docs/_scripts/copy_notebooks.py @@ -30,6 +30,7 @@ _MANUAL = { "input_output_schema.ipynb", "pass_private_state.ipynb", "memory/manage-conversation-history.ipynb", + "subgraphs-manage-state.ipynb", "memory/delete-messages.ipynb", "memory/add-summary-conversation-history.ipynb", "persistence_postgres.ipynb", diff --git a/docs/docs/how-tos/index.md b/docs/docs/how-tos/index.md index bcd1b70a6..d57333b6d 100644 --- a/docs/docs/how-tos/index.md +++ b/docs/docs/how-tos/index.md @@ -12,7 +12,6 @@ Welcome to the LangGraph how-to guides! These guides provide practical, step-by- LangGraph is known for being a highly controllable agent framework. 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) @@ -64,6 +63,11 @@ These guides show how to use different streaming modes. - [How to pass config to tools](pass-config-to-tools.ipynb) - [How to handle large numbers of tools](many-tools.ipynb) +## Subgraphs + +- [How to create subgraphs](subgraph.ipynb) +- [How to manage state in subgraphs](subgraphs-manage-state.ipynb) + ## State Management - [Use Pydantic model as state](state-model.ipynb) diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 56a9435b2..f9c8138a8 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -126,7 +126,6 @@ nav: - "How-to Guides": - "how-tos/index.md" - Controllability: - - 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 @@ -161,6 +160,9 @@ nav: - Pass graph state to tools: how-tos/pass-run-time-values-to-tools.ipynb - Pass config to tools: how-tos/pass-config-to-tools.ipynb - Handle many tools: how-tos/many-tools.ipynb + - Subgraphs: + - Create subgraphs: how-tos/subgraph.ipynb + - Manage state in subgraphs: how-tos/subgraphs-manage-state.ipynb - State Management: - Use Pydantic model as state: how-tos/state-model.ipynb - Use a context object in state: how-tos/state-context-key.ipynb diff --git a/examples/subgraphs-manage-state.ipynb b/examples/subgraphs-manage-state.ipynb new file mode 100644 index 000000000..a018e6321 --- /dev/null +++ b/examples/subgraphs-manage-state.ipynb @@ -0,0 +1,868 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# How to manage state in subgraphs\n", + "\n", + "For more complex systems, sub-graphs are a useful design principle. Sub-graphs allow you to create and manage different states in different parts of your graph. This allows you build things like [multi-agent teams](https://langchain-ai.github.io/langgraph/tutorials/multi_agent/hierarchical_agent_teams/), where each team can track its own separate state.\n", + "\n", + "In this how-to guide we will cover how to manage the persisted state in subgraphs. This will enable a lot of the human-in-the-loop interaction patterns.\n", + "\n", + "## Setup\n", + "\n", + "First we need to install the packages required" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture --no-stderr\n", + "%pip install -U langgraph" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we need to set API keys for OpenAI (the LLM we will use):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import getpass\n", + "import os\n", + "\n", + "\n", + "def _set_env(var: str):\n", + " if not os.environ.get(var):\n", + " os.environ[var] = getpass.getpass(f\"{var}: \")\n", + "\n", + "\n", + "_set_env(\"OPENAI_API_KEY\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Optionally, we can set API key for [LangSmith tracing](https://smith.langchain.com/), which will give us best-in-class observability." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n", + "_set_env(\"LANGCHAIN_API_KEY\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Define SubGraph\n", + "\n", + "First, let's set up our subgraph. For this, we will create a simple graph that can get the weather for a specific city. We will compile this graph with a [breakpoint](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/breakpoints/) before the `weather_node`:" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "from langgraph.graph import StateGraph, END, START, MessagesState\n", + "from langchain_core.tools import tool\n", + "from langchain_openai import ChatOpenAI\n", + "\n", + "\n", + "@tool\n", + "def get_weather(city: str):\n", + " \"\"\"Get the weather for a specific city\"\"\"\n", + " return f\"It's sunny in {city}!\"\n", + "\n", + "raw_model = ChatOpenAI()\n", + "model = raw_model.with_structured_output(get_weather)\n", + "\n", + "\n", + "class SubGraphState(MessagesState):\n", + " city: str\n", + "\n", + "\n", + "def model_node(state: SubGraphState):\n", + " result = model.invoke(state['messages'])\n", + " return {\"city\": result[\"city\"]}\n", + "\n", + "def weather_node(state: SubGraphState):\n", + " result = get_weather.invoke({\"city\": state['city']})\n", + " return {\"messages\": [{\"role\": \"assistant\", \"content\": result}]}\n", + "\n", + "\n", + "subgraph = StateGraph(SubGraphState)\n", + "subgraph.add_node(model_node)\n", + "subgraph.add_node(weather_node)\n", + "subgraph.add_edge(START, \"model_node\")\n", + "subgraph.add_edge(\"model_node\", \"weather_node\")\n", + "subgraph.add_edge(\"weather_node\", END)\n", + "subgraph = subgraph.compile(interrupt_before=[\"weather_node\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Define Parent Graph\n", + "\n", + "We can now setup the overall graph. This graph will first route to the subgraph if it needs to get the weather, otherwise it will route to a normal LLM." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "from typing import TypedDict, Literal\n", + "from langgraph.checkpoint.memory import MemorySaver\n", + "\n", + "\n", + "memory = MemorySaver()\n", + "\n", + "\n", + "class RouterState(MessagesState):\n", + " route: Literal[\"weather\", \"other\"]\n", + "\n", + "\n", + "class Router(TypedDict):\n", + " route: Literal[\"weather\", \"other\"]\n", + "\n", + "router_model = raw_model.with_structured_output(Router)\n", + " \n", + "def router_node(state: RouterState):\n", + " system_message = \"Classify the incoming query as either about weather or not.\"\n", + " messages = [{\"role\": \"system\", \"content\": system_message}] + state['messages']\n", + " route = router_model.invoke(messages)\n", + " return {\"route\": route['route']}\n", + "\n", + "\n", + "def normal_llm_node(state: RouterState):\n", + " response = raw_model.invoke(state['messages'])\n", + " return {\"messages\": [response]}\n", + "\n", + "\n", + "def route_after_prediction(state: RouterState) -> Literal[\"weather_graph\", \"normal_llm_node\"]:\n", + " if state['route'] == \"weather\":\n", + " return \"weather_graph\"\n", + " else:\n", + " return \"normal_llm_node\"\n", + "\n", + "\n", + "graph = StateGraph(RouterState)\n", + "graph.add_node(router_node)\n", + "graph.add_node(normal_llm_node)\n", + "graph.add_node(\"weather_graph\", subgraph)\n", + "graph.add_edge(START, \"router_node\")\n", + "graph.add_conditional_edges(\"router_node\", route_after_prediction)\n", + "graph.add_edge(\"normal_llm_node\", END)\n", + "graph.add_edge(\"weather_graph\", END)\n", + "graph = graph.compile(checkpointer=memory)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "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", + "# Setting xray to 1 will show the internal structure of the nested graph\n", + "display(Image(graph.get_graph(xray=1).draw_mermaid_png()))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's test this out with a normal query to make sure it works as intended!" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'router_node': {'route': 'other'}}\n", + "{'normal_llm_node': {'messages': [AIMessage(content='Hello! How can I assist you today?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 9, 'total_tokens': 18}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-9730e690-8cbd-4ba0-a962-3f8a4e848ef9-0', usage_metadata={'input_tokens': 9, 'output_tokens': 9, 'total_tokens': 18})]}}\n" + ] + } + ], + "source": [ + "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", + "inputs = {\"messages\": [{\"role\": \"user\", \"content\": \"hi!\"}]}\n", + "for update in graph.stream(inputs, config=config, stream_mode=\"updates\"):\n", + " print(update)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great! We didn't ask about the weather, so we got a normal response from the LLM.\n", + "\n", + "## Resuming from breakpoints\n", + "\n", + "Let's now look at what happens with breakpoints. Let's invoke it with a query that should get routed to the weather subgraph where we have the interrupt node." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'router_node': {'route': 'weather'}}\n" + ] + } + ], + "source": [ + "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", + "inputs = {\"messages\": [{\"role\": \"user\", \"content\": \"what's the weather in sf\"}]}\n", + "for update in graph.stream(inputs, config=config, stream_mode=\"updates\"):\n", + " print(update)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that the graph stream doesn't include subgraph events. If we want to stream subgraph events, we can pass `subgraphs=True` and get back subgraph events like so:" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "((), {'messages': [HumanMessage(content=\"what's the weather in sf\", id='ad42a2dc-57c5-4aae-b616-6a86ca6ee7bd')]})\n", + "((), {'messages': [HumanMessage(content=\"what's the weather in sf\", id='ad42a2dc-57c5-4aae-b616-6a86ca6ee7bd')], 'route': 'weather'})\n", + "(('weather_graph:99f49d5c-9d1a-5e00-b2fc-1f1ade30dec3',), {'messages': [HumanMessage(content=\"what's the weather in sf\", id='ad42a2dc-57c5-4aae-b616-6a86ca6ee7bd')]})\n", + "(('weather_graph:99f49d5c-9d1a-5e00-b2fc-1f1ade30dec3',), {'messages': [HumanMessage(content=\"what's the weather in sf\", id='ad42a2dc-57c5-4aae-b616-6a86ca6ee7bd')], 'city': 'San Francisco'})\n" + ] + } + ], + "source": [ + "config = {\"configurable\": {\"thread_id\": \"3\"}}\n", + "inputs = {\"messages\": [{\"role\": \"user\", \"content\": \"what's the weather in sf\"}]}\n", + "for update in graph.stream(inputs, config=config, stream_mode=\"values\", subgraphs=True):\n", + " print(update)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we get the state now, we can see that it's paused on `weather_graph`" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('weather_graph',)" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "state = graph.get_state(config)\n", + "state.next" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we look at the pending tasks for our current state, we can see that we have one task named `weather_graph`, which corresponds to the subgraph task." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(PregelTask(id='99f49d5c-9d1a-5e00-b2fc-1f1ade30dec3', name='weather_graph', error=None, interrupts=(), state={'configurable': {'thread_id': '3', 'checkpoint_ns': 'weather_graph:99f49d5c-9d1a-5e00-b2fc-1f1ade30dec3'}}),)" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "state.tasks" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However since we got the state using the config of the parent graph, we don't have access to the subgraph state. If you look at the `state` value of the `PregelTask` above you will note that it is simply the configuration of the parent graph. If we want to actually populate the subgraph state, we can pass in `subgraphs=True` to `get_state` like so:" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "PregelTask(id='99f49d5c-9d1a-5e00-b2fc-1f1ade30dec3', name='weather_graph', error=None, interrupts=(), state=StateSnapshot(values={'messages': [HumanMessage(content=\"what's the weather in sf\", id='ad42a2dc-57c5-4aae-b616-6a86ca6ee7bd')], 'city': 'San Francisco'}, next=('weather_node',), config={'configurable': {'thread_id': '3', 'checkpoint_ns': 'weather_graph:99f49d5c-9d1a-5e00-b2fc-1f1ade30dec3', 'checkpoint_id': '1ef6a48a-018f-638c-8001-a7af39dcd6ee', 'checkpoint_map': {'': '1ef6a489-fddc-6208-8001-5e02ff54dfba', 'weather_graph:99f49d5c-9d1a-5e00-b2fc-1f1ade30dec3': '1ef6a48a-018f-638c-8001-a7af39dcd6ee'}}}, metadata={'source': 'loop', 'writes': {'model_node': {'city': 'San Francisco'}}, 'step': 1, 'parents': {'': '1ef6a489-fddc-6208-8001-5e02ff54dfba'}}, created_at='2024-09-03T23:02:42.795391+00:00', parent_config={'configurable': {'thread_id': '3', 'checkpoint_ns': 'weather_graph:99f49d5c-9d1a-5e00-b2fc-1f1ade30dec3', 'checkpoint_id': '1ef6a489-fded-6936-8000-c96152586915'}}, tasks=(PregelTask(id='c153ac13-b9a5-543a-8044-3b3c852fd0bc', name='weather_node', error=None, interrupts=(), state=None),)))" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "state = graph.get_state(config, subgraphs=True)\n", + "state.tasks[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we have access to the subgraph state! If you look at the `state` value of the `PregelTask` you can see that it has all the information we need, like the next node (`weather_node`) and the current state values (e.g. `city`).\n", + "\n", + "To resume execution, we can just invoke the outer graph as normal:" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'weather_graph': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='ad42a2dc-57c5-4aae-b616-6a86ca6ee7bd'), AIMessage(content=\"It's sunny in San Francisco!\", id='07b513fa-30af-4ee4-83e4-2af8f6d133bd')]}}\n" + ] + } + ], + "source": [ + "for update in graph.stream(None, config=config, stream_mode=\"updates\"):\n", + " print(update)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Modifying state\n", + "\n", + "### Update the state of a subgraph\n", + "\n", + "What if we want to modify the state of a subgraph? We can do this similarly to how we [update the state of normal graphs](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/time-travel/), just being careful to pass in the config of the subgraph to `update_state`." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'router_node': {'route': 'weather'}}\n" + ] + } + ], + "source": [ + "config = {\"configurable\": {\"thread_id\": \"4\"}}\n", + "inputs = {\"messages\": [{\"role\": \"user\", \"content\": \"what's the weather in sf\"}]}\n", + "for update in graph.stream(inputs, config=config, stream_mode=\"updates\"):\n", + " print(update)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[HumanMessage(content=\"what's the weather in sf\", id='35e331c6-eb47-483c-a63c-585877b12f5d')]" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "state = graph.get_state(config, subgraphs=True)\n", + "state.values['messages']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to update the state of the **inner** graph, we need to pass the config for the **inner** graph, which we can get by accessing calling `state.tasks[0].state.config` - since we interrupted inside the subgraph, the state of the task is just the state of the subgraph." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'configurable': {'thread_id': '4',\n", + " 'checkpoint_ns': 'weather_graph:9e512e8e-bac5-5412-babe-fe5c12a47cc2',\n", + " 'checkpoint_id': '1ef6a424-2bb2-6ee0-8002-6a6ca5dbc91f',\n", + " 'checkpoint_map': {'': '1ef6a40d-0fca-671c-8001-3064b486db01',\n", + " 'weather_graph:9e512e8e-bac5-5412-babe-fe5c12a47cc2': '1ef6a424-2bb2-6ee0-8002-6a6ca5dbc91f'}}}" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.update_state(state.tasks[0].state.config, {\"city\": \"la\"})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now resume streaming the outer graph (which will resume the subgraph!) and check that we updated our search to use LA instead of SF." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(('weather_graph:9e512e8e-bac5-5412-babe-fe5c12a47cc2',), {'weather_node': {'messages': [{'role': 'assistant', 'content': \"It's sunny in la!\"}]}})\n", + "((), {'weather_graph': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='35e331c6-eb47-483c-a63c-585877b12f5d'), AIMessage(content=\"It's sunny in la!\", id='c3d6b224-9642-4b21-94d5-eef8dc3f2cc9')]}})\n" + ] + } + ], + "source": [ + "for update in graph.stream(None, config=config, stream_mode=\"updates\", subgraphs=True):\n", + " print(update)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Fantastic! The AI responded with \"It's sunny in LA!\" as we expected.\n", + "\n", + "### Acting as a subgraph node\n", + "\n", + "Another way we could update the state is by acting as the `weather_node` ourselves instead of editing the state before `weather_node` is ran as we did above. We can do this by passing the subgraph config and also the `as_node` argument, which allows us to update the state as if we are the node we specify. Thus by setting an interrupt before the `weather_node` and then using the update state function as the `weather_node`, the graph itself never calls `weather_node` directly but instead we decide what the output of `weather_node` should be." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "((), {'router_node': {'route': 'weather'}})\n", + "(('weather_graph:bdb185a9-ff74-58dd-ae72-34e8665a33d7',), {'model_node': {'city': 'San Francisco'}})\n", + "interrupted!\n", + "((), {'weather_graph': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='5d721f30-278e-460f-a83c-fdb101731f3e'), AIMessage(content='rainy', id='43b30e0d-6ea0-4e9c-92de-3e411e6fa21d')]}})\n", + "[HumanMessage(content=\"what's the weather in sf\", id='5d721f30-278e-460f-a83c-fdb101731f3e'), AIMessage(content='rainy', id='43b30e0d-6ea0-4e9c-92de-3e411e6fa21d')]\n" + ] + } + ], + "source": [ + "config = {\"configurable\": {\"thread_id\": \"14\"}}\n", + "inputs = {\"messages\": [{\"role\": \"user\", \"content\": \"what's the weather in sf\"}]}\n", + "for update in graph.stream(inputs, config=config, stream_mode=\"updates\", subgraphs=True):\n", + " print(update)\n", + "# Graph execution should stop before the weather node\n", + "print(\"interrupted!\")\n", + "state = graph.get_state(config, subgraphs=True)\n", + "# We update the state by passing in the message we want returned from the weather node, and make sure to use as_node\n", + "graph.update_state(state.tasks[0].state.config, {\"messages\": [{\"role\": \"assistant\", \"content\": \"rainy\"}]}, as_node=\"weather_node\")\n", + "for update in graph.stream(None, config=config, stream_mode=\"updates\", subgraphs=True):\n", + " print(update)\n", + "print(graph.get_state(config).values['messages'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Perfect! The AI responded with the message we passed in ourselves.\n", + "\n", + "### Acting as the entire subgraph\n", + "\n", + "Lastly, we could also update the graph just acting as the **entire** subgraph. This is similar to the case above but instead of acting as just the `weather_node` we are acting as the entire subgraph. This is done by passing in the normal graph config as well as the `as_node` argument, where we specify the we are acting as the entire subgraph node." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "((), {'router_node': {'route': 'weather'}})\n", + "(('weather_graph:53ab3fb1-23e8-5de0-acc6-9fb904fd4dc4',), {'model_node': {'city': 'San Francisco'}})\n", + "interrupted!\n", + "[HumanMessage(content=\"what's the weather in sf\", id='64b1b683-778b-4623-b783-4a8f81322ec8'), AIMessage(content='rainy', id='c1d1a2f3-c117-41e9-8c1f-8fb0a02a3b70')]\n" + ] + } + ], + "source": [ + "config = {\"configurable\": {\"thread_id\": \"8\"}}\n", + "inputs = {\"messages\": [{\"role\": \"user\", \"content\": \"what's the weather in sf\"}]}\n", + "for update in graph.stream(inputs, config=config, stream_mode=\"updates\", subgraphs=True):\n", + " print(update)\n", + "# Graph execution should stop before the weather node\n", + "print(\"interrupted!\")\n", + "# We update the state by passing in the message we want returned from the weather graph, making sure to use as_node\n", + "# Note that we don't need to pass in the subgraph config, since we aren't updating the state inside the subgraph\n", + "graph.update_state(config, {\"messages\": [{\"role\": \"assistant\", \"content\": \"rainy\"}]}, as_node=\"weather_graph\")\n", + "for update in graph.stream(None, config=config, stream_mode=\"updates\"):\n", + " print(update)\n", + "print(graph.get_state(config).values['messages'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Again, the AI responded with \"rainy\" as we expected.\n", + "\n", + "## Double nested subgraphs\n", + "\n", + "This same functionality continues to work no matter the level of nesting. Here is an example of doing the same things with a double nested subgraph (although any level of nesting will work). We add another router on top of our already defined graphs." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "from typing import TypedDict, Literal\n", + "from langgraph.checkpoint.memory import MemorySaver\n", + "\n", + "\n", + "memory = MemorySaver()\n", + "\n", + "\n", + "class RouterState(MessagesState):\n", + " route: Literal[\"weather\", \"other\"]\n", + "\n", + "\n", + "class Router(TypedDict):\n", + " route: Literal[\"weather\", \"other\"]\n", + "\n", + "router_model = raw_model.with_structured_output(Router)\n", + " \n", + "def router_node(state: RouterState):\n", + " system_message = \"Classify the incoming query as either about weather or not.\"\n", + " messages = [{\"role\": \"system\", \"content\": system_message}] + state['messages']\n", + " route = router_model.invoke(messages)\n", + " return {\"route\": route['route']}\n", + "\n", + "\n", + "def normal_llm_node(state: RouterState):\n", + " response = raw_model.invoke(state['messages'])\n", + " return {\"messages\": [response]}\n", + "\n", + "\n", + "def route_after_prediction(state: RouterState) -> Literal[\"weather_graph\", \"normal_llm_node\"]:\n", + " if state['route'] == \"weather\":\n", + " return \"weather_graph\"\n", + " else:\n", + " return \"normal_llm_node\"\n", + "\n", + "\n", + "graph = StateGraph(RouterState)\n", + "graph.add_node(router_node)\n", + "graph.add_node(normal_llm_node)\n", + "graph.add_node(\"weather_graph\", subgraph)\n", + "graph.add_edge(START, \"router_node\")\n", + "graph.add_conditional_edges(\"router_node\", route_after_prediction)\n", + "graph.add_edge(\"normal_llm_node\", END)\n", + "graph.add_edge(\"weather_graph\", END)\n", + "graph = graph.compile()" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "from langgraph.checkpoint.memory import MemorySaver\n", + "\n", + "memory = MemorySaver()\n", + "\n", + "class GrandfatherState(MessagesState):\n", + " to_continue: bool\n", + " \n", + "def router_node(state: GrandfatherState):\n", + " # Dummy logic that will always continue\n", + " return {\"to_continue\": True}\n", + "\n", + "def route_after_prediction(state: GrandfatherState) -> Literal[\"graph\", \"__end__\"]:\n", + " if state['to_continue']:\n", + " return \"graph\"\n", + " else:\n", + " return \"__end__\"\n", + "\n", + "grandparent_graph = StateGraph(GrandfatherState)\n", + "grandparent_graph.add_node(router_node)\n", + "grandparent_graph.add_node(\"graph\", graph)\n", + "grandparent_graph.add_edge(START, \"router_node\")\n", + "grandparent_graph.add_conditional_edges(\"router_node\", route_after_prediction)\n", + "grandparent_graph.add_edge(\"graph\", END)\n", + "grandparent_graph = grandparent_graph.compile(checkpointer=MemorySaver())" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "image/jpeg": "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fEjMjweDLiRCeABzqrqr/FJfeAACGAgobukuH7Rj2RCdEFDd0lw/aMeyIeS3+JZcX7alRslOiFvHtA79sx7ZAmhC3j2gd+2Y9sgZlndrXhn0KdsL6AAOCVLtLfbf+9uv/It09pSbu7DG21dkfKNrjj+0xjPeF0GstHkVCUel7SjVx91vTMtVuxxyMK4ozREGmnMmySXe2icrP6hs0BHXF3PyfmrvqGK/A9o47zZv1SFguLufk/NXfUMV+B7Rx3mzfqkMse8Tw+6tzOAAH1EgAAAAAAAAAAAAAIy5+5qW80e9QxJiMufualvNHvUMYNS9RV/uu2D5o7+IdG7RpLqKv912wfNHfxDo3aMp/DAAACgAAAAAAAAAAAAABBWZ2ld8+rfxTonRXKW3ZSPS61STSGqdb7ryULoyUado4pZlnW48VGPFa59NrTaU0zVERMart804zGCo2XLGAgutc749a6CXvB1rnfHrXQS94V29p8qr9P8AIujFOgILrXO+PWugl7wda53x610EveDt7T5VX6f5F0Yp0BBda53x610EveDrXO+PWugl7wdvafKq/T/IujFOgILrXO+PWugl7wda53x610EveDt7T5VX6f5F0Yp0BBda53x610EveDrXO+PWugl7wdvafKq/T/IujFOgILrXO+PWugl7wda53x610EveDt7T5VX6f5F0YtOdSh2703/4gyPqtDoAc1dS1QSzs1pp2Es2wab9kEuGdIStdWq3lX63D6hvjrXO+PWugl7wyLauNUWUz+X+TLvqnQEF1rnfHrXQS94Otc749a6CXvDe3tPlVfp/k26MU6Agutc749a6CXvB1rnfHrXQS94O3tPlVfp/kXRinQEF1rnfHrXQS94Otc749a6CXvB29p8qr9P8i6MU6Agutc749a6CXvB1rnfHrXQS94O3tPlVfp/kXRinQEF1rnfHrXQS94Otc749a6CXvB29p8qr9P8AIujFOiChu6S4ftGPZEHWud8etdBL3hkQkM/Gv11RU1nLH6paVKUTRNkWqkkkRFk/mHKZtLW0s/8AHMRE3683wzG6ZxNUROtKiFvHtA79sx7ZAmhC3j2gd+2Y9sgdMs7ta8M+hTthfQABwS1lo8lYSs0vaUaSPtR6GlqR2OKRmnEmSJc1U5m2aT7+zTlB/WNmil2lvtv/AHt1/wCRbp7Sk3d2GNtq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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Image, display\n", + "\n", + "# Setting xray to 1 will show the internal structure of the nested graph\n", + "display(Image(grandparent_graph.get_graph(xray=2).draw_mermaid_png()))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we run until the interrupt, we can now see that there are snapshots of the state of all three graphs" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "((), {'router_node': {'to_continue': True}})\n", + "(('graph:e18ecd45-5dfb-53b0-bcb7-db793924e9a8',), {'router_node': {'route': 'weather'}})\n", + "(('graph:e18ecd45-5dfb-53b0-bcb7-db793924e9a8', 'weather_graph:12bd3069-de24-5bc6-b4f1-f39527605781'), {'model_node': {'city': 'San Francisco'}})\n" + ] + } + ], + "source": [ + "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", + "inputs = {\"messages\": [{\"role\": \"user\", \"content\": \"what's the weather in sf\"}]}\n", + "for update in grandparent_graph.stream(inputs, config=config, stream_mode=\"updates\", subgraphs=True):\n", + " print(update)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Grandparent State:\n", + "{'messages': [HumanMessage(content=\"what's the weather in sf\", id='3bb28060-3d30-49a7-9f84-c90b6ada7848')], 'to_continue': True}\n", + "---------------\n", + "Parent Graph State:\n", + "{'messages': [HumanMessage(content=\"what's the weather in sf\", id='3bb28060-3d30-49a7-9f84-c90b6ada7848')], 'route': 'weather'}\n", + "---------------\n", + "Subgraph State:\n", + "{'messages': [HumanMessage(content=\"what's the weather in sf\", id='3bb28060-3d30-49a7-9f84-c90b6ada7848')], 'city': 'San Francisco'}\n" + ] + } + ], + "source": [ + "state = grandparent_graph.get_state(config, subgraphs=True)\n", + "print(\"Grandparent State:\")\n", + "print(state.values)\n", + "print(\"---------------\")\n", + "print(\"Parent Graph State:\")\n", + "print(state.tasks[0].state.values)\n", + "print(\"---------------\")\n", + "print(\"Subgraph State:\")\n", + "print(state.tasks[0].state.tasks[0].state.values)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now continue, acting as the node three levels down" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(('graph:e18ecd45-5dfb-53b0-bcb7-db793924e9a8',), {'weather_graph': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='3bb28060-3d30-49a7-9f84-c90b6ada7848'), AIMessage(content='rainy', id='be926b59-c647-4355-88fd-a429b9e2b420')]}})\n", + "((), {'graph': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='3bb28060-3d30-49a7-9f84-c90b6ada7848'), AIMessage(content='rainy', id='be926b59-c647-4355-88fd-a429b9e2b420')]}})\n", + "[HumanMessage(content=\"what's the weather in sf\", id='3bb28060-3d30-49a7-9f84-c90b6ada7848'), AIMessage(content='rainy', id='be926b59-c647-4355-88fd-a429b9e2b420')]\n" + ] + } + ], + "source": [ + "grandparent_graph_state = state\n", + "parent_graph_state = grandparent_graph_state.tasks[0].state\n", + "subgraph_state = parent_graph_state.tasks[0].state\n", + "grandparent_graph.update_state(subgraph_state.config, {\"messages\": [{\"role\": \"assistant\", \"content\": \"rainy\"}]}, as_node=\"weather_node\")\n", + "for update in grandparent_graph.stream(None, config=config, stream_mode=\"updates\", subgraphs=True):\n", + " print(update)\n", + "print(grandparent_graph.get_state(config).values['messages'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As in the cases above, we can see that the AI responds with \"rainy\" as we expect.\n", + "\n", + "We can explore the state history to see how the state of the grandparent graph was updated at each step." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "StateSnapshot(values={'messages': [HumanMessage(content=\"what's the weather in sf\", id='5ff89e4d-8255-4d23-8b55-01633c112720'), AIMessage(content='rainy', id='7c80f847-248d-4b8f-8238-633ed757b353')], 'to_continue': True}, next=(), config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef66f40-7a2c-6f9e-8002-a37a61b26709'}}, metadata={'source': 'loop', 'writes': {'graph': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='5ff89e4d-8255-4d23-8b55-01633c112720'), AIMessage(content='rainy', id='7c80f847-248d-4b8f-8238-633ed757b353')]}}, 'step': 2, 'parents': {}}, created_at='2024-08-30T17:19:35.793847+00:00', parent_config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef66f3f-f312-6338-8001-766acddc781e'}}, tasks=())\n", + "-----\n", + "StateSnapshot(values={'messages': [HumanMessage(content=\"what's the weather in sf\", id='5ff89e4d-8255-4d23-8b55-01633c112720')], 'to_continue': True}, next=('graph',), config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef66f3f-f312-6338-8001-766acddc781e'}}, metadata={'source': 'loop', 'writes': {'router_node': {'to_continue': True}}, 'step': 1, 'parents': {}}, created_at='2024-08-30T17:19:21.627097+00:00', parent_config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef66f3f-f303-61d0-8000-1945c8a74e9e'}}, tasks=(PregelTask(id='b59fe96f-fdce-5afe-aa58-bd2876a0d592', name='graph', error=None, interrupts=(), state={'configurable': {'thread_id': '2', 'checkpoint_ns': 'graph:b59fe96f-fdce-5afe-aa58-bd2876a0d592'}}),))\n", + "-----\n", + "StateSnapshot(values={'messages': [HumanMessage(content=\"what's the weather in sf\", id='5ff89e4d-8255-4d23-8b55-01633c112720')]}, next=('router_node',), config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef66f3f-f303-61d0-8000-1945c8a74e9e'}}, metadata={'source': 'loop', 'writes': None, 'step': 0, 'parents': {}}, created_at='2024-08-30T17:19:21.620923+00:00', parent_config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef66f3f-f2f9-6d6a-bfff-c8b76e5b2462'}}, tasks=(PregelTask(id='e3d4a97a-f4ca-5260-801e-e65b02907825', name='router_node', error=None, interrupts=(), state=None),))\n", + "-----\n", + "StateSnapshot(values={'messages': []}, next=('__start__',), config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef66f3f-f2f9-6d6a-bfff-c8b76e5b2462'}}, metadata={'source': 'input', 'writes': {'messages': [{'role': 'user', 'content': \"what's the weather in sf\"}]}, 'step': -1, 'parents': {}}, created_at='2024-08-30T17:19:21.617127+00:00', parent_config=None, tasks=(PregelTask(id='f0538638-b794-58fc-a406-980d2fea28a1', name='__start__', error=None, interrupts=(), state=None),))\n", + "-----\n" + ] + } + ], + "source": [ + "for state in grandparent_graph.get_state_history(config):\n", + " print(state)\n", + " print(\"-----\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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": 4 +} diff --git a/examples/time-travel.ipynb b/examples/time-travel.ipynb index dcdd035c0..2dd46e42b 100644 --- a/examples/time-travel.ipynb +++ b/examples/time-travel.ipynb @@ -46,7 +46,10 @@ "id": "af4ce0ba-7596-4e5f-8bf8-0b0bd6e62833", "metadata": {}, "outputs": [], - "source": ["%%capture --no-stderr\n%pip install --quiet -U langgraph langchain_openai"] + "source": [ + "%%capture --no-stderr\n", + "%pip install --quiet -U langgraph langchain_openai" + ] }, { "cell_type": "markdown", @@ -62,7 +65,18 @@ "id": "c903a1cf-2977-4e2d-ad7d-8b3946821d89", "metadata": {}, "outputs": [], - "source": ["import getpass\nimport os\n\n\ndef _set_env(var: str):\n if not os.environ.get(var):\n os.environ[var] = getpass.getpass(f\"{var}: \")\n\n\n_set_env(\"ANTHROPIC_API_KEY\")"] + "source": [ + "import getpass\n", + "import os\n", + "\n", + "\n", + "def _set_env(var: str):\n", + " if not os.environ.get(var):\n", + " os.environ[var] = getpass.getpass(f\"{var}: \")\n", + "\n", + "\n", + "_set_env(\"OPENAI_API_KEY\")" + ] }, { "cell_type": "markdown", @@ -78,7 +92,10 @@ "id": "95e25aec-7c9f-4a63-b143-225d0e9a79c3", "metadata": {}, "outputs": [], - "source": ["os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n_set_env(\"LANGCHAIN_API_KEY\")"] + "source": [ + "os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n", + "_set_env(\"LANGCHAIN_API_KEY\")" + ] }, { "cell_type": "markdown", @@ -96,7 +113,22 @@ "id": "f5319e01", "metadata": {}, "outputs": [], - "source": ["from typing import Annotated\n\nfrom typing_extensions import TypedDict\n\nfrom langgraph.graph.message import add_messages\n\n# `add_messages`` essentially does this\n# (with more robust handling)\n# def add_messages(left: list, right: list):\n# return left + right\n\n\nclass State(TypedDict):\n messages: Annotated[list, add_messages]"] + "source": [ + "from typing import Annotated\n", + "\n", + "from typing_extensions import TypedDict\n", + "\n", + "from langgraph.graph.message import add_messages\n", + "\n", + "# `add_messages`` essentially does this\n", + "# (with more robust handling)\n", + "# def add_messages(left: list, right: list):\n", + "# return left + right\n", + "\n", + "\n", + "class State(TypedDict):\n", + " messages: Annotated[list, add_messages]" + ] }, { "cell_type": "markdown", @@ -116,7 +148,19 @@ "id": "d7ef57dd-5d6e-4ad3-9377-a92201c1310e", "metadata": {}, "outputs": [], - "source": ["from langchain_core.tools import tool\n\n\n@tool\ndef search(query: str):\n \"\"\"Call to surf the web.\"\"\"\n # This is a placeholder for the actual implementation\n return [\"The weather is cloudy with a chance of meatballs.\"]\n\n\ntools = [search]"] + "source": [ + "from langchain_core.tools import tool\n", + "\n", + "\n", + "@tool\n", + "def search(query: str):\n", + " \"\"\"Call to surf the web.\"\"\"\n", + " # This is a placeholder for the actual implementation\n", + " return [\"The weather is cloudy with a chance of meatballs.\"]\n", + "\n", + "\n", + "tools = [search]" + ] }, { "cell_type": "markdown", @@ -133,7 +177,11 @@ "id": "5cf3331e-ccb3-41c8-aeb9-a840a94d41e7", "metadata": {}, "outputs": [], - "source": ["from langgraph.prebuilt import ToolNode\n\ntool_node = ToolNode(tools)"] + "source": [ + "from langgraph.prebuilt import ToolNode\n", + "\n", + "tool_node = ToolNode(tools)" + ] }, { "cell_type": "markdown", @@ -157,7 +205,11 @@ "id": "892b54b9-75f0-4804-9ed0-88b5e5532989", "metadata": {}, "outputs": [], - "source": ["from langchain_openai import ChatOpenAI\n\nmodel = ChatOpenAI(temperature=0)"] + "source": [ + "from langchain_openai import ChatOpenAI\n", + "\n", + "model = ChatOpenAI(temperature=0)" + ] }, { "cell_type": "markdown", @@ -175,7 +227,9 @@ "id": "cd3cbae5-d92c-4559-a4aa-44721b80d107", "metadata": {}, "outputs": [], - "source": ["model = model.bind_tools(tools)"] + "source": [ + "model = model.bind_tools(tools)" + ] }, { "cell_type": "markdown", @@ -210,7 +264,20 @@ "id": "3b541bb9-900c-40d0-964d-7b5dfee30667", "metadata": {}, "outputs": [], - "source": ["from typing import Literal\n\n\n# Define the function that determines whether to continue or not\ndef should_continue(state: State) -> Literal[\"continue\", \"end\"]:\n last_message = state[\"messages\"][-1]\n # If there is no function call, then we finish\n if not last_message.tool_calls:\n return \"end\"\n # Otherwise if there is, we continue\n else:\n return \"continue\""] + "source": [ + "from typing import Literal\n", + "\n", + "\n", + "# Define the function that determines whether to continue or not\n", + "def should_continue(state: State) -> Literal[\"continue\", \"end\"]:\n", + " last_message = state[\"messages\"][-1]\n", + " # If there is no function call, then we finish\n", + " if not last_message.tool_calls:\n", + " return \"end\"\n", + " # Otherwise if there is, we continue\n", + " else:\n", + " return \"continue\"" + ] }, { "cell_type": "markdown", @@ -228,7 +295,50 @@ "id": "812b4e70-4956-4415-8880-db48b3dcbad2", "metadata": {}, "outputs": [], - "source": ["from langgraph.graph import END, StateGraph, START\n\n# Define a new graph\nworkflow = StateGraph(State)\n\n\n# Define the two nodes we will cycle between\ndef call_model(state: State) -> State:\n return {\"messages\": model.invoke(state[\"messages\"])}\n\n\nworkflow.add_node(\"agent\", call_model)\nworkflow.add_node(\"action\", tool_node)\n\n# Set the entrypoint as `agent`\n# This means that this node is the first one called\nworkflow.add_edge(START, \"agent\")\n\n# We now add a conditional edge\nworkflow.add_conditional_edges(\n # First, we define the start node. We use `agent`.\n # This means these are the edges taken after the `agent` node is called.\n \"agent\",\n # Next, we pass in the function that will determine which node is called next.\n should_continue,\n # Finally we pass in a mapping.\n # The keys are strings, and the values are other nodes.\n # END is a special node marking that the graph should finish.\n # What will happen is we will call `should_continue`, and then the output of that\n # will be matched against the keys in this mapping.\n # Based on which one it matches, that node will then be called.\n {\n # If `tools`, then we call the tool node.\n \"continue\": \"action\",\n # Otherwise we finish.\n \"end\": END,\n },\n)\n\n# We now add a normal edge from `tools` to `agent`.\n# This means that after `tools` is called, `agent` node is called next.\nworkflow.add_edge(\"action\", \"agent\")"] + "source": [ + "from langgraph.graph import END, StateGraph, START\n", + "\n", + "# Define a new graph\n", + "workflow = StateGraph(State)\n", + "\n", + "\n", + "# Define the two nodes we will cycle between\n", + "def call_model(state: State) -> State:\n", + " return {\"messages\": model.invoke(state[\"messages\"])}\n", + "\n", + "\n", + "workflow.add_node(\"agent\", call_model)\n", + "workflow.add_node(\"action\", tool_node)\n", + "\n", + "# Set the entrypoint as `agent`\n", + "# This means that this node is the first one called\n", + "workflow.add_edge(START, \"agent\")\n", + "\n", + "# We now add a conditional edge\n", + "workflow.add_conditional_edges(\n", + " # First, we define the start node. We use `agent`.\n", + " # This means these are the edges taken after the `agent` node is called.\n", + " \"agent\",\n", + " # Next, we pass in the function that will determine which node is called next.\n", + " should_continue,\n", + " # Finally we pass in a mapping.\n", + " # The keys are strings, and the values are other nodes.\n", + " # END is a special node marking that the graph should finish.\n", + " # What will happen is we will call `should_continue`, and then the output of that\n", + " # will be matched against the keys in this mapping.\n", + " # Based on which one it matches, that node will then be called.\n", + " {\n", + " # If `tools`, then we call the tool node.\n", + " \"continue\": \"action\",\n", + " # Otherwise we finish.\n", + " \"end\": END,\n", + " },\n", + ")\n", + "\n", + "# We now add a normal edge from `tools` to `agent`.\n", + "# This means that after `tools` is called, `agent` node is called next.\n", + "workflow.add_edge(\"action\", \"agent\")" + ] }, { "cell_type": "markdown", @@ -246,7 +356,11 @@ "id": "6845ed6a-d155-4105-9160-28849877248b", "metadata": {}, "outputs": [], - "source": ["from langgraph.checkpoint.memory import MemorySaver\n\nmemory = MemorySaver()"] + "source": [ + "from langgraph.checkpoint.memory import MemorySaver\n", + "\n", + "memory = MemorySaver()" + ] }, { "cell_type": "code", @@ -254,7 +368,12 @@ "id": "79d29875-8aa8-434c-9f20-1c58346a6249", "metadata": {}, "outputs": [], - "source": ["# Finally, we compile it!\n# This compiles it into a LangChain Runnable,\n# meaning you can use it as you would any other runnable\napp = workflow.compile(checkpointer=memory)"] + "source": [ + "# Finally, we compile it!\n", + "# This compiles it into a LangChain Runnable,\n", + "# meaning you can use it as you would any other runnable\n", + "app = workflow.compile(checkpointer=memory)" + ] }, { "cell_type": "markdown", @@ -281,7 +400,15 @@ "output_type": "display_data" } ], - "source": ["from IPython.display import Image, display\n\ntry:\n display(Image(app.get_graph().draw_mermaid_png()))\nexcept Exception:\n # This requires some extra dependencies and is optional\n pass"] + "source": [ + "from IPython.display import Image, display\n", + "\n", + "try:\n", + " display(Image(app.get_graph().draw_mermaid_png()))\n", + "except Exception:\n", + " # This requires some extra dependencies and is optional\n", + " pass" + ] }, { "cell_type": "markdown", @@ -312,7 +439,14 @@ ] } ], - "source": ["from langchain_core.messages import HumanMessage\n\nconfig = {\"configurable\": {\"thread_id\": \"2\"}}\ninput_message = HumanMessage(content=\"hi! I'm bob\")\nfor event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n event[\"messages\"][-1].pretty_print()"] + "source": [ + "from langchain_core.messages import HumanMessage\n", + "\n", + "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", + "input_message = HumanMessage(content=\"hi! I'm bob\")\n", + "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", + " event[\"messages\"][-1].pretty_print()" + ] }, { "cell_type": "markdown", @@ -350,7 +484,9 @@ "output_type": "execute_result" } ], - "source": ["app.get_state(config).values"] + "source": [ + "app.get_state(config).values" + ] }, { "cell_type": "markdown", @@ -379,7 +515,9 @@ "output_type": "execute_result" } ], - "source": ["app.get_state(config).next"] + "source": [ + "app.get_state(config).next" + ] }, { "cell_type": "markdown", @@ -426,7 +564,12 @@ ] } ], - "source": ["config = {\"configurable\": {\"thread_id\": \"2\"}}\ninput_message = HumanMessage(content=\"what is the weather in sf currently\")\nfor event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n event[\"messages\"][-1].pretty_print()"] + "source": [ + "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", + "input_message = HumanMessage(content=\"what is the weather in sf currently\")\n", + "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", + " event[\"messages\"][-1].pretty_print()" + ] }, { "cell_type": "markdown", @@ -466,7 +609,9 @@ "id": "5a68afc0-606f-4294-a872-b2b563be0d69", "metadata": {}, "outputs": [], - "source": ["app_w_interrupt = workflow.compile(checkpointer=memory, interrupt_before=[\"action\"])"] + "source": [ + "app_w_interrupt = workflow.compile(checkpointer=memory, interrupt_before=[\"action\"])" + ] }, { "cell_type": "code", @@ -490,7 +635,14 @@ ] } ], - "source": ["config = {\"configurable\": {\"thread_id\": \"4\"}}\ninput_message = HumanMessage(content=\"what is the weather in sf currently\")\nfor event in app_w_interrupt.stream(\n {\"messages\": [input_message]}, config, stream_mode=\"values\"\n):\n event[\"messages\"][-1].pretty_print()"] + "source": [ + "config = {\"configurable\": {\"thread_id\": \"4\"}}\n", + "input_message = HumanMessage(content=\"what is the weather in sf currently\")\n", + "for event in app_w_interrupt.stream(\n", + " {\"messages\": [input_message]}, config, stream_mode=\"values\"\n", + "):\n", + " event[\"messages\"][-1].pretty_print()" + ] }, { "cell_type": "markdown", @@ -526,7 +678,10 @@ "output_type": "execute_result" } ], - "source": ["current_values = app_w_interrupt.get_state(config)\ncurrent_values.next"] + "source": [ + "current_values = app_w_interrupt.get_state(config)\n", + "current_values.next" + ] }, { "cell_type": "markdown", @@ -555,7 +710,9 @@ "output_type": "execute_result" } ], - "source": ["current_values.values[\"messages\"][-1].tool_calls"] + "source": [ + "current_values.values[\"messages\"][-1].tool_calls" + ] }, { "cell_type": "markdown", @@ -571,7 +728,11 @@ "id": "060e2e33-1f6a-40ef-850e-161b308986fb", "metadata": {}, "outputs": [], - "source": ["current_values.values[\"messages\"][-1].tool_calls[0][\"args\"][\n \"query\"\n] = \"weather in San Francisco today\""] + "source": [ + "current_values.values[\"messages\"][-1].tool_calls[0][\"args\"][\n", + " \"query\"\n", + "] = \"weather in San Francisco today\"" + ] }, { "cell_type": "code", @@ -591,7 +752,9 @@ "output_type": "execute_result" } ], - "source": ["app_w_interrupt.update_state(config, current_values.values)"] + "source": [ + "app_w_interrupt.update_state(config, current_values.values)" + ] }, { "cell_type": "markdown", @@ -629,7 +792,9 @@ "output_type": "execute_result" } ], - "source": ["app_w_interrupt.get_state(config).values"] + "source": [ + "app_w_interrupt.get_state(config).values" + ] }, { "cell_type": "code", @@ -648,7 +813,9 @@ "output_type": "execute_result" } ], - "source": ["app_w_interrupt.get_state(config).next"] + "source": [ + "app_w_interrupt.get_state(config).next" + ] }, { "cell_type": "markdown", @@ -679,7 +846,11 @@ ] } ], - "source": ["for event in app_w_interrupt.stream(None, config):\n for v in event.values():\n print(v)"] + "source": [ + "for event in app_w_interrupt.stream(None, config):\n", + " for v in event.values():\n", + " print(v)" + ] }, { "cell_type": "markdown", @@ -726,7 +897,13 @@ ] } ], - "source": ["for state in app_w_interrupt.get_state_history(config):\n print(state)\n print(\"--\")\n if len(state.values[\"messages\"]) == 2:\n to_replay = state"] + "source": [ + "for state in app_w_interrupt.get_state_history(config):\n", + " print(state)\n", + " print(\"--\")\n", + " if len(state.values[\"messages\"]) == 2:\n", + " to_replay = state" + ] }, { "cell_type": "markdown", @@ -754,7 +931,9 @@ "output_type": "execute_result" } ], - "source": ["to_replay.values"] + "source": [ + "to_replay.values" + ] }, { "cell_type": "code", @@ -773,7 +952,9 @@ "output_type": "execute_result" } ], - "source": ["to_replay.next"] + "source": [ + "to_replay.next" + ] }, { "cell_type": "markdown", @@ -806,7 +987,11 @@ ] } ], - "source": ["for event in app_w_interrupt.stream(None, to_replay.config):\n for v in event.values():\n print(v)"] + "source": [ + "for event in app_w_interrupt.stream(None, to_replay.config):\n", + " for v in event.values():\n", + " print(v)" + ] }, { "cell_type": "markdown", @@ -834,7 +1019,18 @@ "id": "b084f141-5800-487b-b115-d2e58421b963", "metadata": {}, "outputs": [], - "source": ["from langchain_core.messages import AIMessage\n\nbranch_config = app_w_interrupt.update_state(\n to_replay.config,\n {\n \"messages\": [\n AIMessage(content=\"All done here!\", id=to_replay.values[\"messages\"][-1].id)\n ]\n },\n)"] + "source": [ + "from langchain_core.messages import AIMessage\n", + "\n", + "branch_config = app_w_interrupt.update_state(\n", + " to_replay.config,\n", + " {\n", + " \"messages\": [\n", + " AIMessage(content=\"All done here!\", id=to_replay.values[\"messages\"][-1].id)\n", + " ]\n", + " },\n", + ")" + ] }, { "cell_type": "code", @@ -842,7 +1038,9 @@ "id": "1a7cfcd4-289e-419e-8b49-dfaef4f88641", "metadata": {}, "outputs": [], - "source": ["branch_state = app_w_interrupt.get_state(branch_config)"] + "source": [ + "branch_state = app_w_interrupt.get_state(branch_config)" + ] }, { "cell_type": "code", @@ -862,7 +1060,9 @@ "output_type": "execute_result" } ], - "source": ["branch_state.values"] + "source": [ + "branch_state.values" + ] }, { "cell_type": "code", @@ -881,7 +1081,9 @@ "output_type": "execute_result" } ], - "source": ["branch_state.next"] + "source": [ + "branch_state.next" + ] }, { "cell_type": "markdown",