From d7bae594f051f427673b8747eff520024086ff7c Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Wed, 15 Jan 2025 15:04:43 -0500 Subject: [PATCH 01/15] update hitl --- docs/docs/tutorials/introduction.ipynb | 763 +++++++++++++++++++------ 1 file changed, 594 insertions(+), 169 deletions(-) diff --git a/docs/docs/tutorials/introduction.ipynb b/docs/docs/tutorials/introduction.ipynb index 266c83f77..aa72c90fb 100644 --- a/docs/docs/tutorials/introduction.ipynb +++ b/docs/docs/tutorials/introduction.ipynb @@ -225,12 +225,12 @@ { "cell_type": "code", "execution_count": 7, - "id": "32e4f36e-72ce-4ade-bd7e-94880e0d456b", + "id": "9403859a-f25a-46b4-a672-46a93f8a3cba", "metadata": {}, "outputs": [ { "data": { - "image/jpeg": "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", + "image/png": "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", "text/plain": [ "" ] @@ -1171,9 +1171,11 @@ "\n", "Agents can be unreliable and may need human input to successfully accomplish tasks. Similarly, for some actions, you may want to require human approval before running to ensure that everything is running as intended.\n", "\n", - "LangGraph supports `human-in-the-loop` workflows in a number of ways. In this section, we will use LangGraph's `interrupt_before` functionality to always break the tool node.\n", + "LangGraph's [persistence](../../concepts/persistence) layer supports human-in-the-loop workflows, allowing execution to pause and resume based on user feedback. The primary interface to this functionality is the [interrupt](../../concepts/human_in_the_loop/#interrupt) function. Calling `interrupt` inside a node will pause execution. Execution can be resumed, together with new input from a human, by passing in a [Command](../../concepts/human_in_the_loop/#the-command-primitive). `interrupt` is ergonomically similar to Python's built-in `input()`, [with some caveats](../../concepts/human_in_the_loop/#interrupt). We demonstrate an example below.\n", "\n", - "First, start from our existing code. The following is copied from Part 3." + "First, start with our existing code from Part 3. We make two changes, highlighted below:\n", + "1. We add a `human_review_node` to handle the interaction with a human reviewer;\n", + "2. We use a different condition in our conditional edge that routes to the `human_review_node`, instead of directly to tools." ] }, { @@ -1183,16 +1185,18 @@ "metadata": {}, "outputs": [], "source": [ - "from typing import Annotated\n", + "from typing import Annotated, Literal\n", "\n", "from langchain_anthropic import ChatAnthropic\n", "from langchain_community.tools.tavily_search import TavilySearchResults\n", "from typing_extensions import TypedDict\n", "\n", "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.graph import StateGraph, START\n", + "from langgraph.graph import StateGraph, START, END\n", "from langgraph.graph.message import add_messages\n", - "from langgraph.prebuilt import ToolNode, tools_condition\n", + "from langgraph.prebuilt import ToolNode\n", + "# highlight-next-line\n", + "from langgraph.types import Command, interrupt\n", "\n", "memory = MemorySaver()\n", "\n", @@ -1214,14 +1218,64 @@ " return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n", "\n", "\n", - "graph_builder.add_node(\"chatbot\", chatbot)\n", + "# highlight-start\n", + "# We add a node to handle the interaction with a human reviewer\n", + "def human_review_node(state: State) -> Command[Literal[\"chatbot\", \"tools\"]]:\n", + " last_message = state[\"messages\"][-1]\n", + " tool_call = last_message.tool_calls[-1]\n", + "\n", + " # this is the value we'll be providing via Command(resume=)\n", + " human_review = interrupt(\n", + " {\n", + " \"question\": \"Is this correct?\",\n", + " # Surface tool calls for review\n", + " \"tool_call\": tool_call,\n", + " }\n", + " )\n", + "\n", + " review_action = human_review[\"action\"]\n", + " review_data = human_review.get(\"data\")\n", + "\n", + " # if approved, call the tool\n", + " if review_action == \"continue\":\n", + " return Command(goto=\"tools\")\n", + "\n", + " elif review_action == \"feedback\":\n", + " # NOTE: we're adding feedback message as a ToolMessage\n", + " # to preserve the correct order in the message history\n", + " # (AI messages with tool calls need to be followed by tool call messages)\n", + " tool_message = {\n", + " \"role\": \"tool\",\n", + " # This is our natural language feedback\n", + " \"content\": review_data,\n", + " \"name\": tool_call[\"name\"],\n", + " \"tool_call_id\": tool_call[\"id\"],\n", + " }\n", + " return Command(goto=\"chatbot\", update={\"messages\": [tool_message]})\n", + "\n", + "\n", + "# Where we used tools_condition before, here we update the condition\n", + "# to route to the human review node first, instead of tools.\n", + "def route_after_llm(state) -> Literal[END, \"human_review_node\"]:\n", + " if len(state[\"messages\"][-1].tool_calls) == 0:\n", + " return END\n", + " else:\n", + " return \"human_review_node\"\n", + "\n", + "# highlight-end\n", + "\n", + "\n", + "graph_builder.add_node(chatbot)\n", "\n", "tool_node = ToolNode(tools=[tool])\n", "graph_builder.add_node(\"tools\", tool_node)\n", + "# highlight-next-line\n", + "graph_builder.add_node(human_review_node)\n", "\n", "graph_builder.add_conditional_edges(\n", " \"chatbot\",\n", - " tools_condition,\n", + " # highlight-next-line\n", + " route_after_llm,\n", ")\n", "graph_builder.add_edge(\"tools\", \"chatbot\")\n", "graph_builder.add_edge(START, \"chatbot\")" @@ -1232,28 +1286,65 @@ "id": "813505b2-18c1-46e9-b891-20a34232808b", "metadata": {}, "source": [ - "Now, compile the graph, specifying to `interrupt_before` the `tools` node." + "------\n", + "\n", + "!!! tip \"Read more\"\n", + "\n", + " Check out [this guide](../../how-tos/human_in_the_loop/review-tool-calls/) for more detail on human review of tool calls, including how to edit tool calls directly.\n", + "\n", + "---------\n", + "\n", + "We compile the graph with a checkpointer, as before:" ] }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 5, "id": "b0883e32-1a39-4ce9-ae32-bbd66708fd84", "metadata": {}, "outputs": [], "source": [ - "graph = graph_builder.compile(\n", - " checkpointer=memory,\n", - " # This is new!\n", - " interrupt_before=[\"tools\"],\n", - " # Note: can also interrupt __after__ tools, if desired.\n", - " # interrupt_after=[\"tools\"]\n", - ")" + "graph = graph_builder.compile(checkpointer=memory)" + ] + }, + { + "cell_type": "markdown", + "id": "bc0e84db-925c-4468-b3e0-639e6b25ac3c", + "metadata": {}, + "source": [ + "Visualizing the graph, we can see that we've added a new node to mediate the interaction between the chatbot and the tools:" ] }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 34, + "id": "8b8e61b5-f3c2-4917-a8fc-928ccbcfc6ab", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Image, display\n", + "\n", + "try:\n", + " display(Image(graph.get_graph().draw_mermaid_png()))\n", + "except Exception:\n", + " # This requires some extra dependencies and is optional\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 6, "id": "9f318020-ab7e-415b-a5e2-eddec6d9f3a6", "metadata": {}, "outputs": [ @@ -1266,12 +1357,12 @@ "I'm learning LangGraph. Could you do some research on it for me?\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01R4ZFcb5hohpiVZwr88Bxhc', 'input': {'query': 'LangGraph framework for building language model applications'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01UukDzyzhEhxMgTbshetpT4', 'input': {'query': 'LangGraph programming framework'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " tavily_search_results_json (toolu_01R4ZFcb5hohpiVZwr88Bxhc)\n", - " Call ID: toolu_01R4ZFcb5hohpiVZwr88Bxhc\n", + " tavily_search_results_json (toolu_01UukDzyzhEhxMgTbshetpT4)\n", + " Call ID: toolu_01UukDzyzhEhxMgTbshetpT4\n", " Args:\n", - " query: LangGraph framework for building language model applications\n" + " query: LangGraph programming framework\n" ] } ], @@ -1297,17 +1388,17 @@ }, { "cell_type": "code", - "execution_count": 31, - "id": "9bb7af46-9b4f-4bb1-b8b9-e9ddf7dbc82c", + "execution_count": 7, + "id": "9f511371-98b6-4513-b450-9143778f12dc", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "('tools',)" + "('human_review_node',)" ] }, - "execution_count": 31, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -1322,12 +1413,12 @@ "id": "89326046-2b11-4812-8b6d-8780306ec275", "metadata": {}, "source": [ - "**Notice** that unlike last time, the \"next\" node is set to **'tools'**. We've interrupted here! Let's check the tool invocation." + "**Notice** that unlike last time, the \"next\" node is set to `human_review_node`. We've interrupted here! Let's check the tool invocation." ] }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 8, "id": "3facda0a-e6ad-4b28-b627-753ad8c90c15", "metadata": {}, "outputs": [ @@ -1335,12 +1426,12 @@ "data": { "text/plain": [ "[{'name': 'tavily_search_results_json',\n", - " 'args': {'query': 'LangGraph framework for building language model applications'},\n", - " 'id': 'toolu_01R4ZFcb5hohpiVZwr88Bxhc',\n", + " 'args': {'query': 'LangGraph programming framework'},\n", + " 'id': 'toolu_01UukDzyzhEhxMgTbshetpT4',\n", " 'type': 'tool_call'}]" ] }, - "execution_count": 32, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -1357,13 +1448,13 @@ "source": [ "This query seems reasonable. Nothing to filter here. The simplest thing the human can do is just let the graph continue executing. Let's do that below.\n", "\n", - "Next, continue the graph! Passing in `None` will just let the graph continue where it left off, without adding anything new to the state." + "To resume execution, we pass a [Command](../../concepts/human_in_the_loop/#the-command-primitive) object. Here, we specify `resume` with a dict containing the information expected by `human_review_node`. This information can be customized based on our needs." ] }, { "cell_type": "code", - "execution_count": 33, - "id": "effb95d9-b7d5-40c5-9253-253d193b23b2", + "execution_count": 9, + "id": "831d4978-b5ea-4258-b350-8e7dd2bf2b6c", "metadata": {}, "outputs": [ { @@ -1372,46 +1463,237 @@ "text": [ "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01R4ZFcb5hohpiVZwr88Bxhc', 'input': {'query': 'LangGraph framework for building language model applications'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01UukDzyzhEhxMgTbshetpT4', 'input': {'query': 'LangGraph programming framework'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " tavily_search_results_json (toolu_01R4ZFcb5hohpiVZwr88Bxhc)\n", - " Call ID: toolu_01R4ZFcb5hohpiVZwr88Bxhc\n", + " tavily_search_results_json (toolu_01UukDzyzhEhxMgTbshetpT4)\n", + " Call ID: toolu_01UukDzyzhEhxMgTbshetpT4\n", " Args:\n", - " query: LangGraph framework for building language model applications\n", + " query: LangGraph programming framework\n", "=================================\u001b[1m Tool Message \u001b[0m=================================\n", "Name: tavily_search_results_json\n", "\n", - "[{\"url\": \"https://towardsdatascience.com/from-basics-to-advanced-exploring-langgraph-e8c1cf4db787\", \"content\": \"LangChain is one of the leading frameworks for building applications powered by Lardge Language Models. With the LangChain Expression Language (LCEL), defining and executing step-by-step action sequences — also known as chains — becomes much simpler. In more technical terms, LangChain allows us to create DAGs (directed acyclic graphs). As LLM applications, particularly LLM agents, have ...\"}, {\"url\": \"https://github.com/langchain-ai/langgraph\", \"content\": \"Overview. LangGraph is a library for building stateful, multi-actor applications with LLMs, used to create agent and multi-agent workflows. Compared to other LLM frameworks, it offers these core benefits: cycles, controllability, and persistence. LangGraph allows you to define flows that involve cycles, essential for most agentic architectures ...\"}]\n", + "[{\"url\": \"https://www.langchain.com/langgraph\", \"content\": \"No. LangGraph is an orchestration framework for complex agentic systems and is more low-level and controllable than LangChain agents. LangChain provides a standard interface to interact with models and other components, useful for straight-forward chains and retrieval flows.\"}, {\"url\": \"https://academy.langchain.com/courses/intro-to-langgraph\", \"content\": \"Separate from the LangChain package, LangGraph helps developers add better precision and control into agentic workflows. Lesson 1: Motivation Lesson 2: Simple Graph Lesson 3: LangGraph Studio Lesson 4: Chain Lesson 5: Router Lesson 6: Agent Lesson 7: Agent with Memory Lesson 8: Deployment Lesson 1: State Schema Lesson 2: State Reducers Lesson 3: Multiple Schemas Lesson 1: Streaming Lesson 2: Breakpoints Lesson 3: Editing State and Human Feedback Lesson 4: Dynamic Breakpoints Lesson 1: Parallelization Lesson 2: Sub-graphs Lesson 3: Map-reduce Lesson 4: Research Assistant About this course No. LangGraph is an orchestration framework for complex agentic systems and is more low-level and controllable than LangChain agents. Deploy LangGraph agents at scale with LangGraph Cloud (available for Python).\"}]\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "Thank you for your patience. I've found some valuable information about LangGraph for you. Let me summarize the key points:\n", + "Thank you for your patience. I've researched LangGraph for you, and I'm happy to share what I've found. LangGraph is an interesting framework in the field of language AI. Here's a summary of the key points:\n", "\n", - "1. LangGraph is a library for building stateful, multi-actor applications with Large Language Models (LLMs).\n", + "1. Purpose:\n", + " LangGraph is an orchestration framework designed for complex agentic systems. It provides more low-level control and precision compared to LangChain agents.\n", "\n", - "2. It is particularly useful for creating agent and multi-agent workflows.\n", + "2. Relationship to LangChain:\n", + " - LangGraph is separate from the LangChain package but complements it.\n", + " - While LangChain provides a standard interface for interacting with models and components (useful for straightforward chains and retrieval flows), LangGraph offers more fine-grained control for complex workflows.\n", "\n", - "3. LangGraph is built on top of LangChain, which is one of the leading frameworks for building LLM-powered applications.\n", + "3. Key Features:\n", + " - Better precision and control in agentic workflows\n", + " - Allows for the creation of more complex and controllable AI systems\n", "\n", - "4. Key benefits of LangGraph compared to other LLM frameworks include:\n", - " a) Cycles: It allows you to define flows that involve cycles, which is essential for most agent architectures.\n", - " b) Controllability: Offers more control over the application flow.\n", - " c) Persistence: Provides ways to maintain state across interactions.\n", + "4. Learning Resources:\n", + " There's a course available on the LangChain Academy that covers LangGraph in depth. The course structure includes:\n", "\n", - "5. LangGraph works well with the LangChain Expression Language (LCEL), which simplifies the process of defining and executing step-by-step action sequences (chains).\n", + " - Motivation\n", + " - Simple Graph\n", + " - LangGraph Studio\n", + " - Chain\n", + " - Router\n", + " - Agent\n", + " - Agent with Memory\n", + " - Deployment\n", + " - State Schema\n", + " - State Reducers\n", + " - Multiple Schemas\n", + " - Streaming\n", + " - Breakpoints\n", + " - Editing State and Human Feedback\n", + " - Dynamic Breakpoints\n", + " - Parallelization\n", + " - Sub-graphs\n", + " - Map-reduce\n", + " - Research Assistant\n", "\n", - "6. In technical terms, LangGraph enables the creation of Directed Acyclic Graphs (DAGs) for LLM applications.\n", + "5. Deployment:\n", + " LangGraph agents can be deployed at scale using LangGraph Cloud (available for Python).\n", "\n", - "7. It's particularly useful for building more complex LLM agents and multi-agent systems.\n", + "LangGraph seems to be particularly useful when you need more control over your AI workflows, especially for complex, multi-step processes or when building sophisticated AI agents. If you're already familiar with LangChain, learning LangGraph could be a valuable next step to enhance your ability to create more advanced AI systems.\n", "\n", - "LangGraph seems to be an advanced tool that builds upon LangChain to provide more sophisticated capabilities for creating stateful and multi-actor LLM applications. It's especially valuable if you're looking to create complex agent systems or applications that require maintaining state across interactions.\n", - "\n", - "Is there any specific aspect of LangGraph you'd like to know more about? I'd be happy to dive deeper into any particular area of interest.\n" + "Is there any specific aspect of LangGraph you'd like to know more about? Or do you have any questions about how it compares to other frameworks you might be familiar with?\n" ] } ], "source": [ - "# `None` will append nothing new to the current state, letting it resume as if it had never been interrupted\n", - "events = graph.stream(None, config, stream_mode=\"values\")\n", + "human_command = Command(resume={\"action\": \"continue\"})\n", + "\n", + "events = graph.stream(human_command, config, stream_mode=\"values\")\n", + "for event in events:\n", + " if \"messages\" in event:\n", + " event[\"messages\"][-1].pretty_print()" + ] + }, + { + "cell_type": "markdown", + "id": "d789d4cf-b498-454b-a088-3ffc03e511b0", + "metadata": {}, + "source": [ + "Review this call's [LangSmith trace](https://smith.langchain.com/public/83aaec86-9dd8-406b-ab03-e66d2464b8ef/r) to see the exact work that was done in the above call. Notice that the state is loaded in the first step so that your chatbot can continue where it left off.\n", + "\n", + "Let's demonstrate another example, in which we direct the chatbot to revise its tool calls based on our feedback." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "0ebad510-01f8-4b00-8e80-1b435b0f37fa", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "Could you search the weather in San Francisco?\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "[{'text': \"Certainly! I'd be happy to search for the current weather in San Francisco for you. To get the most up-to-date and accurate information, I'll use the Tavily search engine. Let me do that for you right away.\", 'type': 'text'}, {'id': 'toolu_019rPs39MK72QMVFcnxEyFN4', 'input': {'query': 'current weather in San Francisco'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "Tool Calls:\n", + " tavily_search_results_json (toolu_019rPs39MK72QMVFcnxEyFN4)\n", + " Call ID: toolu_019rPs39MK72QMVFcnxEyFN4\n", + " Args:\n", + " query: current weather in San Francisco\n" + ] + } + ], + "source": [ + "user_input = \"Could you search the weather in San Francisco?\"\n", + "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", + "\n", + "events = graph.stream(\n", + " {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n", + ")\n", + "for event in events:\n", + " if \"messages\" in event:\n", + " event[\"messages\"][-1].pretty_print()" + ] + }, + { + "cell_type": "markdown", + "id": "ce1e485c-0ddc-4c36-a1c1-b78f6c706fa1", + "metadata": {}, + "source": [ + "This time, we will indicate that the requested action is `\"feedback\"`, and provide feedback in natural language. The chatbot will respond by generating a second, updated tool call:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "b5bbaf35-d1f2-46b3-8451-856e908fd11f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "[{'text': \"Certainly! I'd be happy to search for the current weather in San Francisco for you. To get the most up-to-date and accurate information, I'll use the Tavily search engine. Let me do that for you right away.\", 'type': 'text'}, {'id': 'toolu_019rPs39MK72QMVFcnxEyFN4', 'input': {'query': 'current weather in San Francisco'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "Tool Calls:\n", + " tavily_search_results_json (toolu_019rPs39MK72QMVFcnxEyFN4)\n", + " Call ID: toolu_019rPs39MK72QMVFcnxEyFN4\n", + " Args:\n", + " query: current weather in San Francisco\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: tavily_search_results_json\n", + "\n", + "User requested changes: use format for location.\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "[{'text': 'I apologize for the error in my previous attempt. Thank you for the clarification on the format. Let me search again using the correct format.', 'type': 'text'}, {'id': 'toolu_01AfrULohtNjWqGf8oY1FP9v', 'input': {'query': 'current weather in San Francisco, USA'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "Tool Calls:\n", + " tavily_search_results_json (toolu_01AfrULohtNjWqGf8oY1FP9v)\n", + " Call ID: toolu_01AfrULohtNjWqGf8oY1FP9v\n", + " Args:\n", + " query: current weather in San Francisco, USA\n" + ] + } + ], + "source": [ + "human_command = Command(\n", + " resume={\n", + " \"action\": \"feedback\",\n", + " \"data\": \"User requested changes: use format for location.\",\n", + " }\n", + ")\n", + "\n", + "events = graph.stream(human_command, config, stream_mode=\"values\")\n", + "for event in events:\n", + " if \"messages\" in event:\n", + " event[\"messages\"][-1].pretty_print()" + ] + }, + { + "cell_type": "markdown", + "id": "b56541f9-a5d2-49e0-9389-8d6e116c58b3", + "metadata": {}, + "source": [ + "We can now continue, as before:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "24ec8471-4438-4c89-aafa-48bb6c72eca8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "[{'text': 'I apologize for the error in my previous attempt. Thank you for the clarification on the format. Let me search again using the correct format.', 'type': 'text'}, {'id': 'toolu_01AfrULohtNjWqGf8oY1FP9v', 'input': {'query': 'current weather in San Francisco, USA'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "Tool Calls:\n", + " tavily_search_results_json (toolu_01AfrULohtNjWqGf8oY1FP9v)\n", + " Call ID: toolu_01AfrULohtNjWqGf8oY1FP9v\n", + " Args:\n", + " query: current weather in San Francisco, USA\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: tavily_search_results_json\n", + "\n", + "[{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.775, 'lon': -122.4183, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1736966001, 'localtime': '2025-01-15 10:33'}, 'current': {'last_updated_epoch': 1736965800, 'last_updated': '2025-01-15 10:30', 'temp_c': 10.6, 'temp_f': 51.1, 'is_day': 1, 'condition': {'text': 'Sunny', 'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png', 'code': 1000}, 'wind_mph': 6.3, 'wind_kph': 10.1, 'wind_degree': 51, 'wind_dir': 'NE', 'pressure_mb': 1026.0, 'pressure_in': 30.3, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 46, 'cloud': 0, 'feelslike_c': 9.3, 'feelslike_f': 48.8, 'windchill_c': 6.6, 'windchill_f': 43.9, 'heatindex_c': 8.6, 'heatindex_f': 47.5, 'dewpoint_c': 4.6, 'dewpoint_f': 40.2, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 1.3, 'gust_mph': 9.4, 'gust_kph': 15.1}}\"}, {\"url\": \"https://www.meteoprog.com/weather/Sanfrancisco/month/january/\", \"content\": \"San Francisco (United States) weather in January 2025 ☀️ Accurate weather forecast for San Francisco in January ⛅ Detailed forecast By month Current temperature \\\"near me\\\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG. ... 15 January +14 °+7° 16 January +14\"}]\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Thank you for your patience. I've successfully searched for the current weather in San Francisco, USA. Based on the search results, I can provide you with the following information about the weather in San Francisco:\n", + "\n", + "1. Current Temperature:\n", + " - 10.6°C (51.1°F)\n", + " - Feels like: 9.3°C (48.8°F)\n", + "\n", + "2. Weather Condition: Sunny\n", + "\n", + "3. Wind:\n", + " - Speed: 10.1 km/h (6.3 mph)\n", + " - Direction: Northeast (NE)\n", + "\n", + "4. Humidity: 46%\n", + "\n", + "5. Precipitation: 0 mm (0 inches)\n", + "\n", + "6. Visibility: 16 km (9 miles)\n", + "\n", + "7. Pressure: 1026.0 mb (30.3 inches)\n", + "\n", + "8. UV Index: 1.3 (relatively low)\n", + "\n", + "The data shows that it's a pleasant, sunny day in San Francisco with comfortable temperatures. The weather is clear with no cloud cover, and there's a light breeze from the northeast. The humidity is moderate, and there's no precipitation expected.\n", + "\n", + "Is there any specific aspect of the weather you'd like more information about?\n" + ] + } + ], + "source": [ + "human_command = Command(resume={\"action\": \"continue\"})\n", + "\n", + "events = graph.stream(human_command, config,stream_mode=\"values\")\n", "for event in events:\n", " if \"messages\" in event:\n", " event[\"messages\"][-1].pretty_print()" @@ -1422,7 +1704,7 @@ "id": "21e78a97-474f-4709-b51d-9d5e8323e14c", "metadata": {}, "source": [ - "Review this call's [LangSmith trace](https://smith.langchain.com/public/4d7f8757-9d3b-43b9-88b6-aeab0595bc4c/r) to see the exact work that was done in the above call. Notice that the state is loaded in the first step so that your chatbot can continue where it left off.\n", + "In the [LangSmith trace](https://smith.langchain.com/public/1e4bf84c-3e9e-41fd-a924-21395f5cd09e/r) for the above run, we can see full sequence of alternating assistant and tool messages representing the interaction with a human reviewer.\n", "\n", "**Congrats!** You've used an `interrupt` to add human-in-the-loop execution to your chatbot, allowing for human oversight and intervention when needed. This opens up the potential UIs you can create with your AI systems. Since we have already added a **checkpointer**, the graph can be paused **indefinitely** and resumed at any time as if nothing had happened.\n", "\n", @@ -1435,17 +1717,19 @@ "
\n",
     "\n",
     "```python\n",
-    "from typing import Annotated\n",
+    "from typing import Annotated, Literal\n",
     "\n",
     "from langchain_anthropic import ChatAnthropic\n",
     "from langchain_community.tools.tavily_search import TavilySearchResults\n",
-    "from langchain_core.messages import BaseMessage\n",
     "from typing_extensions import TypedDict\n",
     "\n",
     "from langgraph.checkpoint.memory import MemorySaver\n",
-    "from langgraph.graph import StateGraph\n",
+    "from langgraph.graph import StateGraph, START, END\n",
     "from langgraph.graph.message import add_messages\n",
-    "from langgraph.prebuilt import ToolNode, tools_condition\n",
+    "from langgraph.prebuilt import ToolNode\n",
+    "from langgraph.types import Command, interrupt\n",
+    "\n",
+    "memory = MemorySaver()\n",
     "\n",
     "\n",
     "class State(TypedDict):\n",
@@ -1465,26 +1749,62 @@
     "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
     "\n",
     "\n",
-    "graph_builder.add_node(\"chatbot\", chatbot)\n",
+    "# We add a node to handle the interaction with a human reviewer\n",
+    "def human_review_node(state: State) -> Command[Literal[\"chatbot\", \"tools\"]]:\n",
+    "    last_message = state[\"messages\"][-1]\n",
+    "    tool_call = last_message.tool_calls[-1]\n",
+    "\n",
+    "    # this is the value we'll be providing via Command(resume=)\n",
+    "    human_review = interrupt(\n",
+    "        {\n",
+    "            \"question\": \"Is this correct?\",\n",
+    "            # Surface tool calls for review\n",
+    "            \"tool_call\": tool_call,\n",
+    "        }\n",
+    "    )\n",
+    "\n",
+    "    review_action = human_review[\"action\"]\n",
+    "    review_data = human_review.get(\"data\")\n",
+    "\n",
+    "    # if approved, call the tool\n",
+    "    if review_action == \"continue\":\n",
+    "        return Command(goto=\"tools\")\n",
+    "\n",
+    "    elif review_action == \"feedback\":\n",
+    "        # NOTE: we're adding feedback message as a ToolMessage\n",
+    "        # to preserve the correct order in the message history\n",
+    "        # (AI messages with tool calls need to be followed by tool call messages)\n",
+    "        tool_message = {\n",
+    "            \"role\": \"tool\",\n",
+    "            # This is our natural language feedback\n",
+    "            \"content\": review_data,\n",
+    "            \"name\": tool_call[\"name\"],\n",
+    "            \"tool_call_id\": tool_call[\"id\"],\n",
+    "        }\n",
+    "        return Command(goto=\"chatbot\", update={\"messages\": [tool_message]})\n",
+    "\n",
+    "\n",
+    "# Where we used tools_condition before, here we update the condition\n",
+    "# to route to the human review node first, instead of tools.\n",
+    "def route_after_llm(state) -> Literal[END, \"human_review_node\"]:\n",
+    "    if len(state[\"messages\"][-1].tool_calls) == 0:\n",
+    "        return END\n",
+    "    else:\n",
+    "        return \"human_review_node\"\n",
+    "\n",
+    "\n",
+    "graph_builder.add_node(chatbot)\n",
     "\n",
     "tool_node = ToolNode(tools=[tool])\n",
     "graph_builder.add_node(\"tools\", tool_node)\n",
+    "graph_builder.add_node(human_review_node)\n",
     "\n",
     "graph_builder.add_conditional_edges(\n",
     "    \"chatbot\",\n",
-    "    tools_condition,\n",
+    "    route_after_llm,\n",
     ")\n",
     "graph_builder.add_edge(\"tools\", \"chatbot\")\n",
-    "graph_builder.set_entry_point(\"chatbot\")\n",
-    "\n",
-    "memory = MemorySaver()\n",
-    "graph = graph_builder.compile(\n",
-    "    checkpointer=memory,\n",
-    "    # This is new!\n",
-    "    interrupt_before=[\"tools\"],\n",
-    "    # Note: can also interrupt __after__ actions, if desired.\n",
-    "    # interrupt_after=[\"tools\"]\n",
-    ")\n",
+    "graph_builder.add_edge(START, \"chatbot\")\n",
     "```\n",
     "
\n", "" @@ -1506,21 +1826,24 @@ }, { "cell_type": "code", - "execution_count": 17, - "id": "faa345c6-38a2-42e8-9035-9cf56f7bb5b1", + "execution_count": null, + "id": "cab7f9c2-fc23-4b68-b84a-a7760b5403c9", "metadata": {}, "outputs": [], "source": [ - "from typing import Annotated\n", + "from typing import Annotated, Literal\n", "\n", "from langchain_anthropic import ChatAnthropic\n", "from langchain_community.tools.tavily_search import TavilySearchResults\n", "from typing_extensions import TypedDict\n", "\n", "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.graph import StateGraph, START\n", + "from langgraph.graph import StateGraph, START, END\n", "from langgraph.graph.message import add_messages\n", - "from langgraph.prebuilt import ToolNode, tools_condition\n", + "from langgraph.prebuilt import ToolNode\n", + "from langgraph.types import Command, interrupt\n", + "\n", + "memory = MemorySaver()\n", "\n", "\n", "class State(TypedDict):\n", @@ -1540,38 +1863,129 @@ " return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n", "\n", "\n", - "graph_builder.add_node(\"chatbot\", chatbot)\n", + "# We add a node to handle the interaction with a human reviewer\n", + "def human_review_node(state: State) -> Command[Literal[\"chatbot\", \"tools\"]]:\n", + " last_message = state[\"messages\"][-1]\n", + " tool_call = last_message.tool_calls[-1]\n", + "\n", + " # this is the value we'll be providing via Command(resume=)\n", + " human_review = interrupt(\n", + " {\n", + " \"question\": \"Is this correct?\",\n", + " # Surface tool calls for review\n", + " \"tool_call\": tool_call,\n", + " }\n", + " )\n", + "\n", + " review_action = human_review[\"action\"]\n", + " review_data = human_review.get(\"data\")\n", + "\n", + " # if approved, call the tool\n", + " if review_action == \"continue\":\n", + " return Command(goto=\"tools\")\n", + "\n", + " elif review_action == \"feedback\":\n", + " # NOTE: we're adding feedback message as a ToolMessage\n", + " # to preserve the correct order in the message history\n", + " # (AI messages with tool calls need to be followed by tool call messages)\n", + " tool_message = {\n", + " \"role\": \"tool\",\n", + " # This is our natural language feedback\n", + " \"content\": review_data,\n", + " \"name\": tool_call[\"name\"],\n", + " \"tool_call_id\": tool_call[\"id\"],\n", + " }\n", + " return Command(goto=\"chatbot\", update={\"messages\": [tool_message]})\n", + "\n", + "\n", + "# Where we used tools_condition before, here we update the condition\n", + "# to route to the human review node first, instead of tools.\n", + "def route_after_llm(state) -> Literal[END, \"human_review_node\"]:\n", + " if len(state[\"messages\"][-1].tool_calls) == 0:\n", + " return END\n", + " else:\n", + " return \"human_review_node\"\n", + "\n", + "\n", + "graph_builder.add_node(chatbot)\n", "\n", "tool_node = ToolNode(tools=[tool])\n", "graph_builder.add_node(\"tools\", tool_node)\n", + "graph_builder.add_node(human_review_node)\n", "\n", "graph_builder.add_conditional_edges(\n", " \"chatbot\",\n", - " tools_condition,\n", + " route_after_llm,\n", ")\n", "graph_builder.add_edge(\"tools\", \"chatbot\")\n", - "graph_builder.add_edge(START, \"chatbot\")\n", - "memory = MemorySaver()\n", - "graph = graph_builder.compile(\n", - " checkpointer=memory,\n", - " # This is new!\n", - " interrupt_before=[\"tools\"],\n", - " # Note: can also interrupt **after** actions, if desired.\n", - " # interrupt_after=[\"tools\"]\n", - ")\n", - "\n", + "graph_builder.add_edge(START, \"chatbot\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "64cc981c-38fd-4ea5-8be5-f077be796411", + "metadata": {}, + "outputs": [], + "source": [ + "graph = graph_builder.compile(checkpointer=memory)" + ] + }, + { + "cell_type": "markdown", + "id": "00726b4b-7661-414e-a077-5cabba597163", + "metadata": {}, + "source": [ + "We first begin a thread:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "4124bf18-302a-4593-b485-247bfd36f150", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "I'm learning LangGraph. Could you do some research on it for me?\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01NKHEFSGNmLeVGvBYDyrALi', 'input': {'query': 'LangGraph: what is it, features, and usage in AI development'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "Tool Calls:\n", + " tavily_search_results_json (toolu_01NKHEFSGNmLeVGvBYDyrALi)\n", + " Call ID: toolu_01NKHEFSGNmLeVGvBYDyrALi\n", + " Args:\n", + " query: LangGraph: what is it, features, and usage in AI development\n" + ] + } + ], + "source": [ "user_input = \"I'm learning LangGraph. Could you do some research on it for me?\"\n", "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", - "# The config is the **second positional argument** to stream() or invoke()!\n", - "events = graph.stream({\"messages\": [(\"user\", user_input)]}, config)\n", + "\n", + "events = graph.stream(\n", + " {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n", + ")\n", "for event in events:\n", " if \"messages\" in event:\n", " event[\"messages\"][-1].pretty_print()" ] }, + { + "cell_type": "markdown", + "id": "e3f5b9c1-e259-43f3-bfc6-f9a166a1da71", + "metadata": {}, + "source": [ + "Note that we can read the existing state from the `graph` object:" + ] + }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 5, "id": "a6b3bcae-dd04-49da-a4ef-e05634657faf", "metadata": {}, "outputs": [ @@ -1581,12 +1995,12 @@ "text": [ "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_018YcbFR37CG8RRXnavH5fxZ', 'input': {'query': 'LangGraph: what is it, how is it used in AI development'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01NKHEFSGNmLeVGvBYDyrALi', 'input': {'query': 'LangGraph: what is it, features, and usage in AI development'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " tavily_search_results_json (toolu_018YcbFR37CG8RRXnavH5fxZ)\n", - " Call ID: toolu_018YcbFR37CG8RRXnavH5fxZ\n", + " tavily_search_results_json (toolu_01NKHEFSGNmLeVGvBYDyrALi)\n", + " Call ID: toolu_01NKHEFSGNmLeVGvBYDyrALi\n", " Args:\n", - " query: LangGraph: what is it, how is it used in AI development\n" + " query: LangGraph: what is it, features, and usage in AI development\n" ] } ], @@ -1610,8 +2024,8 @@ }, { "cell_type": "code", - "execution_count": 36, - "id": "6a44bedc-ea91-4c22-976c-98b3d5a5e4a7", + "execution_count": 6, + "id": "f0fd4cdb-afc4-4617-b0a9-f018232d641c", "metadata": {}, "outputs": [ { @@ -1624,7 +2038,7 @@ "\n", "\n", "Last 2 messages;\n", - "[ToolMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', id='675f7618-367f-44b7-b80e-2834afb02ac5', tool_call_id='toolu_018YcbFR37CG8RRXnavH5fxZ'), AIMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', additional_kwargs={}, response_metadata={}, id='35fd5682-0c2a-4200-b192-71c59ac6d412')]\n" + "[ToolMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', id='12be5dbe-75eb-45d8-8d64-5ab0c2f8555f', tool_call_id='toolu_01NKHEFSGNmLeVGvBYDyrALi'), AIMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', additional_kwargs={}, response_metadata={}, id='0f389c32-6fdd-4ad9-bd89-671d38983a70')]\n" ] } ], @@ -1659,7 +2073,7 @@ "id": "584de971-6b10-4931-986e-cc35f7adbb3d", "metadata": {}, "source": [ - "Now the graph is complete, since we've provided the final response message! Since state updates simulate a graph step, they even generate corresponding traces. Inspect the [LangSmith trace](https://smith.langchain.com/public/6d72aeb5-3bca-4090-8684-a11d5a36b10c/r) of the `update_state` call above to see what's going on.\n", + "Now the graph is complete, since we've provided the final response message! Since state updates simulate a graph step, they even generate corresponding traces. Inspect the [LangSmith trace](https://smith.langchain.com/public/e844af02-7f45-43e2-92bc-13cd3af9b62f/r) of the `update_state` call above to see what's going on.\n", "\n", "**Notice** that our new messages are _appended_ to the messages already in the state. Remember how we defined the `State` type?\n", "\n", @@ -1675,7 +2089,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 7, "id": "d16d95c3-b465-42ac-8015-26b669d45d1f", "metadata": {}, "outputs": [ @@ -1684,10 +2098,10 @@ "text/plain": [ "{'configurable': {'thread_id': '1',\n", " 'checkpoint_ns': '',\n", - " 'checkpoint_id': '1ef7d134-3958-6412-8002-3f4b4112062f'}}" + " 'checkpoint_id': '1efd377d-87e6-6ab6-8003-7d963c60dd60'}}" ] }, - "execution_count": 19, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -1707,18 +2121,18 @@ "id": "5a1f0056-6b6f-425f-ac1a-0d4b0e9b85cc", "metadata": {}, "source": [ - "Check out the [LangSmith trace](https://smith.langchain.com/public/2e4d92ca-c17c-49e0-92e5-3962390ded30/r) for this update call at the provided link. **Notice** from the trace that the graph continues into the `tools_condition` edge. We just told the graph to treat the update `as_node=\"chatbot\"`. If we follow the diagram below and start from the `chatbot` node, we naturally end up in the `tools_condition` edge and then `__end__` since our updated message lacks tool calls." + "Check out the [LangSmith trace](https://smith.langchain.com/public/14edbcaf-a230-45e5-bda2-bd24a9f96cd1/r) for this update call at the provided link. **Notice** from the trace that the graph continues into the `route_after_llm` edge. We just told the graph to treat the update `as_node=\"chatbot\"`. If we follow the diagram below and start from the `chatbot` node, we naturally end up in the `route_after_llm` edge and then `__end__` since our updated message lacks tool calls." ] }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 8, "id": "f4009ba6-dc0b-4216-ab0c-fbb104616f73", "metadata": {}, "outputs": [ { "data": { - "image/jpeg": "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", + "image/png": "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", "text/plain": [ "" ] @@ -1747,7 +2161,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 9, "id": "d420e813-a8c7-415d-ab31-5298d42491e4", "metadata": {}, "outputs": [ @@ -1755,7 +2169,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "[ToolMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', id='675f7618-367f-44b7-b80e-2834afb02ac5', tool_call_id='toolu_018YcbFR37CG8RRXnavH5fxZ'), AIMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', additional_kwargs={}, response_metadata={}, id='35fd5682-0c2a-4200-b192-71c59ac6d412'), AIMessage(content=\"I'm an AI expert!\", additional_kwargs={}, response_metadata={}, id='288e2f74-f1cb-4082-8c3c-af4695c83117')]\n", + "[ToolMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', id='12be5dbe-75eb-45d8-8d64-5ab0c2f8555f', tool_call_id='toolu_01NKHEFSGNmLeVGvBYDyrALi'), AIMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', additional_kwargs={}, response_metadata={}, id='0f389c32-6fdd-4ad9-bd89-671d38983a70'), AIMessage(content=\"I'm an AI expert!\", additional_kwargs={}, response_metadata={}, id='8ea38275-255a-4d64-be3c-c4fcd6c6e55a')]\n", "()\n" ] } @@ -1782,8 +2196,8 @@ }, { "cell_type": "code", - "execution_count": 40, - "id": "9fc99c7e-b61d-4aec-9c62-042798185ec3", + "execution_count": 10, + "id": "b5aa8029-927d-4597-88b7-c9fadd4f6f60", "metadata": {}, "outputs": [ { @@ -1795,12 +2209,12 @@ "I'm learning LangGraph. Could you do some research on it for me?\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and accurate information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01TfAeisrpx4ddgJpoAxqrVh', 'input': {'query': 'LangGraph framework for language models'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search function to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_0135SrrAV1dhbeDtvKzUovUH', 'input': {'query': 'LangGraph python library for language models'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " tavily_search_results_json (toolu_01TfAeisrpx4ddgJpoAxqrVh)\n", - " Call ID: toolu_01TfAeisrpx4ddgJpoAxqrVh\n", + " tavily_search_results_json (toolu_0135SrrAV1dhbeDtvKzUovUH)\n", + " Call ID: toolu_0135SrrAV1dhbeDtvKzUovUH\n", " Args:\n", - " query: LangGraph framework for language models\n" + " query: LangGraph python library for language models\n" ] } ], @@ -1825,7 +2239,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 11, "id": "7215533a-b7e2-4b2d-bc1d-5122b1d06b8b", "metadata": {}, "outputs": [ @@ -1834,11 +2248,11 @@ "output_type": "stream", "text": [ "Original\n", - "Message ID run-342f3f54-356b-4cc1-b747-573f6aa31054-0\n", - "{'name': 'tavily_search_results_json', 'args': {'query': 'LangGraph framework for language models'}, 'id': 'toolu_01TfAeisrpx4ddgJpoAxqrVh', 'type': 'tool_call'}\n", + "Message ID run-c6d77fff-fb85-49df-ad84-07ed4e8a352c-0\n", + "{'name': 'tavily_search_results_json', 'args': {'query': 'LangGraph python library for language models'}, 'id': 'toolu_0135SrrAV1dhbeDtvKzUovUH', 'type': 'tool_call'}\n", "Updated\n", - "{'name': 'tavily_search_results_json', 'args': {'query': 'LangGraph human-in-the-loop workflow'}, 'id': 'toolu_01TfAeisrpx4ddgJpoAxqrVh', 'type': 'tool_call'}\n", - "Message ID run-342f3f54-356b-4cc1-b747-573f6aa31054-0\n", + "{'name': 'tavily_search_results_json', 'args': {'query': 'LangGraph human-in-the-loop workflow'}, 'id': 'toolu_0135SrrAV1dhbeDtvKzUovUH', 'type': 'tool_call'}\n", + "Message ID run-c6d77fff-fb85-49df-ad84-07ed4e8a352c-0\n", "\n", "\n", "Tool calls\n" @@ -1849,11 +2263,11 @@ "text/plain": [ "[{'name': 'tavily_search_results_json',\n", " 'args': {'query': 'LangGraph human-in-the-loop workflow'},\n", - " 'id': 'toolu_01TfAeisrpx4ddgJpoAxqrVh',\n", + " 'id': 'toolu_0135SrrAV1dhbeDtvKzUovUH',\n", " 'type': 'tool_call'}]" ] }, - "execution_count": 41, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -1891,15 +2305,15 @@ "source": [ "**Notice** that we've modified the AI's tool invocation to search for \"LangGraph human-in-the-loop workflow\" instead of the simple \"LangGraph\".\n", "\n", - "Check out the [LangSmith trace](https://smith.langchain.com/public/cd7c09a6-758d-41d4-8de1-64ab838b2338/r) to see the state update call - you can see our new message has successfully updated the previous AI message.\n", + "Check out the [LangSmith trace](https://smith.langchain.com/public/0a13df28-1509-4974-9f3a-09af34671ec9/r) to see the state update call - you can see our new message has successfully updated the previous AI message.\n", "\n", - "Resume the graph by streaming with an input of `None` and the existing config." + "Resume the graph as before, by passing the appropriate `Command`:" ] }, { "cell_type": "code", - "execution_count": 42, - "id": "03a09bfc-3d90-4e54-878f-22e3cb28a418", + "execution_count": 12, + "id": "7e9ebc73-22e8-4af2-9a36-6678873c671f", "metadata": {}, "outputs": [ { @@ -1908,49 +2322,54 @@ "text": [ "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and accurate information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01TfAeisrpx4ddgJpoAxqrVh', 'input': {'query': 'LangGraph framework for language models'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search function to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_0135SrrAV1dhbeDtvKzUovUH', 'input': {'query': 'LangGraph python library for language models'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " tavily_search_results_json (toolu_01TfAeisrpx4ddgJpoAxqrVh)\n", - " Call ID: toolu_01TfAeisrpx4ddgJpoAxqrVh\n", + " tavily_search_results_json (toolu_0135SrrAV1dhbeDtvKzUovUH)\n", + " Call ID: toolu_0135SrrAV1dhbeDtvKzUovUH\n", " Args:\n", " query: LangGraph human-in-the-loop workflow\n", "=================================\u001b[1m Tool Message \u001b[0m=================================\n", "Name: tavily_search_results_json\n", "\n", - "[{\"url\": \"https://www.youtube.com/watch?v=9BPCV5TYPmg\", \"content\": \"In this video, I'll show you how to handle persistence with LangGraph, enabling a unique Human-in-the-Loop workflow. This approach allows a human to grant an...\"}, {\"url\": \"https://medium.com/@kbdhunga/implementing-human-in-the-loop-with-langgraph-ccfde023385c\", \"content\": \"Implementing a Human-in-the-Loop (HIL) framework in LangGraph with the Streamlit app provides a robust mechanism for user engagement and decision-making. By incorporating breakpoints and ...\"}]\n", + "[{\"url\": \"https://www.youtube.com/watch?v=9BPCV5TYPmg\", \"content\": \"In this video, I'll show you how to handle persistence with LangGraph, enabling a unique Human-in-the-Loop workflow. This approach allows a human to grant an\"}, {\"url\": \"https://blog.langchain.dev/human-in-the-loop-with-opengpts-and-langgraph/\", \"content\": \"TLDR; Today we're launching two \\\"human in the loop\\\" features in OpenGPTs, Interrupt and Authorize, both powered by LangGraph. We've recently launched LangGraph, a library to help developers build multi-actor, multi-step, stateful LLM applications. That's a lot words packed into a short sentence, let's take it one at a time. Multi-actor\"}]\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "Thank you for your patience. I've found some information about LangGraph, particularly focusing on its human-in-the-loop workflow capabilities. Let me summarize what I've learned for you:\n", + "Thank you for your patience. I've found some useful information about LangGraph, particularly focusing on its human-in-the-loop workflow capabilities. Let me summarize what I've learned:\n", "\n", - "1. LangGraph Overview:\n", - " LangGraph is a framework for building stateful, multi-actor applications with Large Language Models (LLMs). It's particularly useful for creating complex, interactive AI systems.\n", + "1. What is LangGraph:\n", + " LangGraph is a library designed to help developers build complex, stateful LLM (Large Language Model) applications. It's particularly useful for creating multi-actor and multi-step processes.\n", "\n", - "2. Human-in-the-Loop (HIL) Workflow:\n", - " One of the key features of LangGraph is its support for human-in-the-loop workflows. This means that it allows for human intervention and decision-making within AI-driven processes.\n", + "2. Human-in-the-Loop Workflow:\n", + " One of the key features of LangGraph is its support for human-in-the-loop workflows. This means it allows for human intervention and interaction within AI-driven processes.\n", "\n", - "3. Persistence Handling:\n", - " LangGraph offers capabilities for handling persistence, which is crucial for maintaining state across interactions in a workflow.\n", + "3. OpenGPTs Integration:\n", + " LangGraph has been integrated with OpenGPTs, introducing two human-in-the-loop features:\n", + " a) Interrupt: This likely allows a human to pause or intervene in an ongoing AI process.\n", + " b) Authorize: This feature probably enables human approval or authorization at certain steps of the AI workflow.\n", "\n", - "4. Implementation with Streamlit:\n", - " There are examples of implementing LangGraph's human-in-the-loop functionality using Streamlit, a popular Python library for creating web apps. This combination allows for the creation of interactive user interfaces for AI applications.\n", + "4. Persistence Handling:\n", + " LangGraph includes functionality for handling persistence. This is important for maintaining state across different steps of a workflow, especially when human interaction is involved.\n", "\n", - "5. Breakpoints and User Engagement:\n", - " LangGraph allows the incorporation of breakpoints in the workflow. These breakpoints are points where the system can pause and wait for human input or decision-making, enhancing user engagement and control over the AI process.\n", + "5. Use Cases:\n", + " The human-in-the-loop capabilities make LangGraph suitable for applications where you need a blend of AI efficiency and human oversight or decision-making. This could be particularly useful in fields like content moderation, complex decision processes, or scenarios where ethical considerations are important.\n", "\n", - "6. Decision-Making Mechanism:\n", - " The human-in-the-loop framework in LangGraph provides a robust mechanism for integrating user decision-making into AI workflows. This is particularly useful in scenarios where human judgment or expertise is needed to guide or validate AI actions.\n", + "6. Developer Focus:\n", + " LangGraph seems to be targeted at developers who are looking to create more sophisticated LLM applications that go beyond simple query-response models.\n", "\n", - "7. Flexibility and Customization:\n", - " From the information available, it seems that LangGraph offers flexibility in how human-in-the-loop processes are implemented, allowing developers to customize the interaction points and the nature of human involvement based on their specific use case.\n", + "To learn more about LangGraph, you might want to:\n", + "1. Check out the official documentation or GitHub repository for LangGraph.\n", + "2. Watch tutorial videos, like the one mentioned in the search results, which demonstrates how to handle persistence with LangGraph.\n", + "3. Explore the OpenGPTs platform to see practical implementations of LangGraph's human-in-the-loop features.\n", + "4. Try building a simple application using LangGraph to get hands-on experience with its capabilities.\n", "\n", - "LangGraph appears to be a powerful tool for developers looking to create more interactive and controllable AI applications, especially those that benefit from human oversight or input at crucial stages of the process.\n", - "\n", - "Would you like me to research any specific aspect of LangGraph in more detail, or do you have any questions about what I've found so far?\n" + "Would you like me to search for more specific information about any aspect of LangGraph, such as its installation process, core components, or example use cases?\n" ] } ], "source": [ - "events = graph.stream(None, config, stream_mode=\"values\")\n", + "human_command = Command(resume={\"action\": \"continue\"})\n", + "\n", + "events = graph.stream(human_command, config, stream_mode=\"values\")\n", "for event in events:\n", " if \"messages\" in event:\n", " event[\"messages\"][-1].pretty_print()" @@ -1961,15 +2380,15 @@ "id": "090b680b-f53f-4af2-a432-45f8c5a10779", "metadata": {}, "source": [ - "Check out the [trace](https://smith.langchain.com/public/2d633326-14ad-4248-a391-2757d01851c4/r/6464f2f2-edb4-4ef3-8f48-ee4e249f2ad0) to see the tool call and later LLM response. **Notice** that now the graph queries the search engine using our updated query term - we were able to manually override the LLM's search here!\n", + "Check out the [trace](https://smith.langchain.com/public/e5b0b999-b1cd-43cf-bf75-df0b35bbe366/r/1f17ded9-6958-4682-9a0d-9d7eedbf7136) to see the tool call and later LLM response. **Notice** that now the graph queries the search engine using our updated query term - we were able to manually override the LLM's search here!\n", "\n", "All of this is reflected in the graph's checkpointed memory, meaning if we continue the conversation, it will recall all the _modified_ state." ] }, { "cell_type": "code", - "execution_count": 43, - "id": "11d5b934-6d8b-4f52-a3bc-b3daa7207e00", + "execution_count": 13, + "id": "556c71d3-48ac-43d7-833c-c3f884b330a7", "metadata": {}, "outputs": [ { @@ -1981,19 +2400,27 @@ "Remember what I'm learning about?\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "I apologize for my oversight. You're absolutely right to remind me. You mentioned that you're learning LangGraph. Thank you for bringing that back into focus. \n", + "Of course! You mentioned that you're learning LangGraph. I apologize for not explicitly referencing that in my response. You're right to bring that back into focus. \n", "\n", - "Since you're in the process of learning LangGraph, it would be helpful to know more about your current level of understanding and what specific aspects of LangGraph you're most interested in or finding challenging. This way, I can provide more targeted information or explanations that align with your learning journey.\n", + "Since you're in the process of learning LangGraph, it's important to tailor the information to your learning journey. Based on what we've found, here are some key points that might be particularly relevant for someone learning LangGraph:\n", "\n", - "Are there any particular areas of LangGraph you'd like to explore further? For example:\n", + "1. Core Concept: LangGraph is a library for building stateful, multi-step LLM applications. As you're learning it, focus on understanding how it manages state across different steps of a process.\n", "\n", - "1. Basic concepts and architecture of LangGraph\n", - "2. Setting up and getting started with LangGraph\n", - "3. Implementing specific features like the human-in-the-loop workflow\n", - "4. Best practices for using LangGraph in projects\n", - "5. Comparisons with other similar frameworks\n", + "2. Human-in-the-Loop: One of LangGraph's key features is its support for human-in-the-loop workflows. This could be an interesting area to explore in your learning, as it allows you to create AI systems that can interact with humans during execution.\n", "\n", - "Or if you have any specific questions about what you've learned so far, I'd be happy to help clarify or expand on those topics. Please let me know what would be most useful for your learning process.\n" + "3. Integration with OpenGPTs: Learning how LangGraph integrates with other tools like OpenGPTs could be valuable. The \"Interrupt\" and \"Authorize\" features might be good practical examples to study.\n", + "\n", + "4. Persistence Handling: As a learner, understanding how LangGraph handles persistence could be crucial. This relates to how the library maintains state across different steps of your AI workflows.\n", + "\n", + "5. Practical Application: The video mentioned in the search results about handling persistence with LangGraph could be a great resource for your learning. It seems to offer a practical demonstration, which is often very helpful when learning a new technology.\n", + "\n", + "To support your learning process, you might want to:\n", + "- Start with simple LangGraph projects and gradually increase complexity\n", + "- Focus on understanding the state management aspects of LangGraph\n", + "- Experiment with the human-in-the-loop features to see how they work in practice\n", + "- Look for tutorials or courses specifically designed for learning LangGraph\n", + "\n", + "Is there a particular aspect of LangGraph that you're finding challenging or especially interesting in your learning journey? Or would you like me to find more beginner-friendly resources for learning LangGraph?\n" ] } ], @@ -2018,9 +2445,7 @@ "id": "a5166e1b-96a6-4ac0-88a1-bf32a422134a", "metadata": {}, "source": [ - "**Congratulations!** You've used `interrupt_before` and `update_state` to manually modify the state as a part of a human-in-the-loop workflow. Interruptions and state modifications let you control how the agent behaves. Combined with persistent checkpointing, it means you can `pause` an action and `resume` at any point. Your user doesn't have to be available when the graph interrupts!\n", - "\n", - "The graph code for this section is identical to previous ones. The key snippets to remember are to add `.compile(..., interrupt_before=[...])` (or `interrupt_after`) if you want to explicitly pause the graph whenever it reaches a node. Then you can use `update_state` to modify the checkpoint and control how the graph should proceed." + "**Congratulations!** You've used `interrupt` and `update_state` to manually modify the state as a part of a human-in-the-loop workflow. Interruptions and state modifications let you control how the agent behaves. Combined with persistent checkpointing, it means you can `pause` an action and `resume` at any point. Your user doesn't have to be available when the graph interrupts!" ] }, { @@ -2041,7 +2466,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 14, "id": "3cf7e042-1718-4625-ae30-a9917f595449", "metadata": {}, "outputs": [], @@ -2087,7 +2512,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 15, "id": "e5192e54-6a28-42fe-a8a7-62d45d61f994", "metadata": {}, "outputs": [], @@ -2114,7 +2539,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 16, "id": "fa59b266-14e5-4c75-8b3d-54fac28e8290", "metadata": {}, "outputs": [], @@ -2148,7 +2573,7 @@ { "cell_type": "code", "execution_count": null, - "id": "3f4464d2-288b-4689-aaf0-329a55dcb85c", + "id": "3bdd9122-1dd4-4049-9626-d009e0d2ee37", "metadata": {}, "outputs": [], "source": [ @@ -3164,7 +3589,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.4" + "version": "3.10.4" } }, "nbformat": 4, From 0f458fbaffcb239b119d7ba1817663e00fcf5fee Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Wed, 15 Jan 2025 16:06:55 -0500 Subject: [PATCH 02/15] update --- docs/docs/tutorials/introduction.ipynb | 941 ++++++++++++------------- 1 file changed, 441 insertions(+), 500 deletions(-) diff --git a/docs/docs/tutorials/introduction.ipynb b/docs/docs/tutorials/introduction.ipynb index aa72c90fb..8658d90f7 100644 --- a/docs/docs/tutorials/introduction.ipynb +++ b/docs/docs/tutorials/introduction.ipynb @@ -1218,7 +1218,6 @@ " return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n", "\n", "\n", - "# highlight-start\n", "# We add a node to handle the interaction with a human reviewer\n", "def human_review_node(state: State) -> Command[Literal[\"chatbot\", \"tools\"]]:\n", " last_message = state[\"messages\"][-1]\n", @@ -1262,8 +1261,6 @@ " else:\n", " return \"human_review_node\"\n", "\n", - "# highlight-end\n", - "\n", "\n", "graph_builder.add_node(chatbot)\n", "\n", @@ -1288,7 +1285,7 @@ "source": [ "------\n", "\n", - "!!! tip \"Read more\"\n", + "!!! tip\n", "\n", " Check out [this guide](../../how-tos/human_in_the_loop/review-tool-calls/) for more detail on human review of tool calls, including how to edit tool calls directly.\n", "\n", @@ -2459,33 +2456,35 @@ "\n", "In the examples above, we involved a human deterministically: the graph __always__ interrupted whenever a tool was invoked. Suppose we wanted our chat bot to have the choice of relying on a human.\n", "\n", - "One way to do this is to create a passthrough \"human\" node, before which the graph will always stop. We will only execute this node if the LLM invokes a \"human\" tool. For our convenience, we will include an \"ask_human\" flag in our graph state that we will flip if the LLM calls this tool.\n", + "One way to do this is route to the `human_review_node` only if the LLM invokes a \"human\" tool. We will include an `ask_human` flag in our graph state that we will flip if the LLM calls this tool. This is not needed for the routing process, but conveniently indicates if a run required human assistance in the output.\n", "\n", - "Below, define this new graph, with an updated `State`" + "Below, define this new graph, with an updated `State`:" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 16, "id": "3cf7e042-1718-4625-ae30-a9917f595449", "metadata": {}, "outputs": [], "source": [ - "from typing import Annotated\n", + "from typing import Annotated, Literal\n", "\n", "from langchain_anthropic import ChatAnthropic\n", "from langchain_community.tools.tavily_search import TavilySearchResults\n", "from typing_extensions import TypedDict\n", "\n", "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.graph import StateGraph, START\n", + "from langgraph.graph import StateGraph, START, END\n", "from langgraph.graph.message import add_messages\n", - "from langgraph.prebuilt import ToolNode, tools_condition\n", + "from langgraph.prebuilt import ToolNode\n", + "from langgraph.types import Command, interrupt\n", "\n", "\n", "class State(TypedDict):\n", " messages: Annotated[list, add_messages]\n", " # This flag is new\n", + " # highlight-next-line\n", " ask_human: bool" ] }, @@ -2512,7 +2511,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 17, "id": "e5192e54-6a28-42fe-a8a7-62d45d61f994", "metadata": {}, "outputs": [], @@ -2531,16 +2530,16 @@ }, { "cell_type": "markdown", - "id": "2b19c61b-2087-463b-adf8-96dbc193f41c", + "id": "338c1bf4-8d00-49c3-9809-ecea290fa152", "metadata": {}, "source": [ - "Next, define the chatbot node. The primary modification here is flip the `ask_human` flag if we see that the chat bot has invoked the `RequestAssistance` flag." + "We include this as a new tool accessible to the model:" ] }, { "cell_type": "code", - "execution_count": 16, - "id": "fa59b266-14e5-4c75-8b3d-54fac28e8290", + "execution_count": 18, + "id": "75cf03b1-c546-4585-8d2f-4a8be296fd89", "metadata": {}, "outputs": [], "source": [ @@ -2548,18 +2547,69 @@ "tools = [tool]\n", "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n", "# We can bind the llm to a tool definition, a pydantic model, or a json schema\n", - "llm_with_tools = llm.bind_tools(tools + [RequestAssistance])\n", - "\n", - "\n", + "llm_with_tools = llm.bind_tools(tools + [RequestAssistance])" + ] + }, + { + "cell_type": "markdown", + "id": "2b19c61b-2087-463b-adf8-96dbc193f41c", + "metadata": {}, + "source": [ + "Otherwise, we just update the `human_review_node` to short-circuit and route directly to `tools` if assistance is not requested. If it is requested, we flip the new flag in the state." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "d7da1212-dc9c-4385-a0a0-c4c3bc30e633", + "metadata": {}, + "outputs": [], + "source": [ "def chatbot(state: State):\n", - " response = llm_with_tools.invoke(state[\"messages\"])\n", - " ask_human = False\n", - " if (\n", - " response.tool_calls\n", - " and response.tool_calls[0][\"name\"] == RequestAssistance.__name__\n", - " ):\n", - " ask_human = True\n", - " return {\"messages\": [response], \"ask_human\": ask_human}" + " return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n", + "\n", + "\n", + "def human_review_node(state: State) -> Command[Literal[\"chatbot\", \"tools\"]]:\n", + " last_message = state[\"messages\"][-1]\n", + " tool_call = last_message.tool_calls[-1]\n", + " \n", + " # highlight-next-line\n", + " if not tool_call[\"name\"] == RequestAssistance.__name__:\n", + " return Command(goto=\"tools\")\n", + "\n", + " human_review = interrupt(\n", + " {\n", + " \"question\": \"Is this correct?\",\n", + " \"tool_call\": tool_call,\n", + " }\n", + " )\n", + "\n", + " review_action = human_review[\"action\"]\n", + " review_data = human_review.get(\"data\")\n", + "\n", + " if review_action == \"continue\":\n", + " # highlight-next-line\n", + " return Command(goto=\"tools\", update={\"ask_human\": True})\n", + "\n", + " elif review_action == \"feedback\":\n", + " tool_message = {\n", + " \"role\": \"tool\",\n", + " \"content\": review_data,\n", + " \"name\": tool_call[\"name\"],\n", + " \"tool_call_id\": tool_call[\"id\"],\n", + " }\n", + " return Command(\n", + " goto=\"chatbot\",\n", + " # highlight-next-line\n", + " update={\"messages\": [tool_message], \"ask_human\": True},\n", + " )\n", + "\n", + "\n", + "def route_after_llm(state) -> Literal[END, \"human_review_node\"]:\n", + " if len(state[\"messages\"][-1].tool_calls) == 0:\n", + " return END\n", + " else:\n", + " return \"human_review_node\"" ] }, { @@ -2573,152 +2623,36 @@ { "cell_type": "code", "execution_count": null, - "id": "3bdd9122-1dd4-4049-9626-d009e0d2ee37", + "id": "8db38d3e-f2ff-4d9d-b267-27729be8e060", "metadata": {}, "outputs": [], "source": [ "graph_builder = StateGraph(State)\n", "\n", - "graph_builder.add_node(\"chatbot\", chatbot)\n", - "graph_builder.add_node(\"tools\", ToolNode(tools=[tool]))" - ] - }, - { - "cell_type": "markdown", - "id": "7f7a0ff3-b671-45c8-8157-ce5db411d370", - "metadata": {}, - "source": [ - "Next, create the \"human\" `node`. This `node` function is mostly a placeholder in our graph that will trigger an interrupt. If the human does __not__ manually update the state during the `interrupt`, it inserts a tool message so the LLM knows the user was requested but didn't respond. This node also unsets the `ask_human` flag so the graph knows not to revisit the node unless further requests are made." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1d70b5a4-ce50-47dc-aa43-ffb5c48c46fc", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.messages import AIMessage, ToolMessage\n", - "\n", - "\n", - "def create_response(response: str, ai_message: AIMessage):\n", - " return ToolMessage(\n", - " content=response,\n", - " tool_call_id=ai_message.tool_calls[0][\"id\"],\n", - " )\n", - "\n", - "\n", - "def human_node(state: State):\n", - " new_messages = []\n", - " if not isinstance(state[\"messages\"][-1], ToolMessage):\n", - " # Typically, the user will have updated the state during the interrupt.\n", - " # If they choose not to, we will include a placeholder ToolMessage to\n", - " # let the LLM continue.\n", - " new_messages.append(\n", - " create_response(\"No response from human.\", state[\"messages\"][-1])\n", - " )\n", - " return {\n", - " # Append the new messages\n", - " \"messages\": new_messages,\n", - " # Unset the flag\n", - " \"ask_human\": False,\n", - " }\n", - "\n", - "\n", - "graph_builder.add_node(\"human\", human_node)" - ] - }, - { - "cell_type": "markdown", - "id": "d56e5c65-f7b7-48bd-b0b5-fc8e590eca7d", - "metadata": {}, - "source": [ - "Next, define the conditional logic. The `select_next_node` will route to the `human` node if the flag is set. Otherwise, it lets the prebuilt `tools_condition` function choose the next node.\n", - "\n", - "Recall that the `tools_condition` function simply checks to see if the `chatbot` has responded with any `tool_calls` in its response message. If so, it routes to the `action` node. Otherwise, it ends the graph." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "586a0d07-8303-47f4-b3cf-3bdd043e762b", - "metadata": {}, - "outputs": [], - "source": [ - "def select_next_node(state: State):\n", - " if state[\"ask_human\"]:\n", - " return \"human\"\n", - " # Otherwise, we can route as before\n", - " return tools_condition(state)\n", + "graph_builder.add_node(chatbot)\n", "\n", + "tool_node = ToolNode(tools=[tool])\n", + "graph_builder.add_node(\"tools\", tool_node)\n", + "graph_builder.add_node(human_review_node)\n", "\n", "graph_builder.add_conditional_edges(\n", " \"chatbot\",\n", - " select_next_node,\n", - " {\"human\": \"human\", \"tools\": \"tools\", END: END},\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "66cd0bb1-b13e-477e-a08a-a7e657e2c19e", - "metadata": {}, - "source": [ - "Finally, add the simple directed edges and compile the graph. These edges instruct the graph to **always** flow from node `a`->`b` whenever `a` finishes executing." + " route_after_llm,\n", + ")\n", + "graph_builder.add_edge(\"tools\", \"chatbot\")\n", + "graph_builder.add_edge(START, \"chatbot\")" ] }, { "cell_type": "code", - "execution_count": 60, - "id": "84101737-0048-4635-9f68-45b0c508b6b6", + "execution_count": 21, + "id": "d9d77f37-63cd-4ed3-86c6-ddaac62b39e9", "metadata": {}, "outputs": [], "source": [ - "# The rest is the same\n", - "graph_builder.add_edge(\"tools\", \"chatbot\")\n", - "graph_builder.add_edge(\"human\", \"chatbot\")\n", - "graph_builder.add_edge(START, \"chatbot\")\n", "memory = MemorySaver()\n", - "graph = graph_builder.compile(\n", - " checkpointer=memory,\n", - " # We interrupt before 'human' here instead.\n", - " interrupt_before=[\"human\"],\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "7f855593-8690-4a18-9ef8-7f3ccdc335bf", - "metadata": {}, - "source": [ - "If you have the visualization dependencies installed, you can see the graph structure below:" - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "id": "b3220ae2-cba0-4447-96d1-eb0be4684e59", - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAEjAaMDASIAAhEBAxEB/8QAHQABAAMBAAMBAQAAAAAAAAAAAAUGBwQCAwgBCf/EAFgQAAEEAQIDAggICQgGBgsAAAEAAgMEBQYRBxIhEzEIFBYiQVFWlBUyNlR0k9HUFzVVYXWytNLTIzdCUnGBkbMzQ2KSlaElV3OCorEJGCQnRFNyg4XBxP/EABoBAQEAAwEBAAAAAAAAAAAAAAABAgMEBQb/xAA3EQEAAQIBCQYEBAcBAAAAAAAAAQIRAxIhMUFRUmGh0QQUM3GRwQUjgZITQ2KxFSIyQsLh8PH/2gAMAwEAAhEDEQA/AP6poiICIiAiIgIiICIiAiIgIiICIiAvxzgxpc4hrQNySegCi85mX47sK1WA28laLm14N9m9B50jz/RjbuN3fnAALnAGOZoSpkHtsZ+Q6gt7h3LabtWjI/8AlwblrQD3E8zu7dx2W6miLZVc2jmttqUfqbDxOLX5Wixw9DrLAf8AzXj5VYX8sUPeWfavFmksHGwMZhse1o6BoqsAH/JeXkrhfyPQ92Z9iy+Tx5GY8qsL+WKHvLPtTyqwv5Yoe8s+1PJXC/keh7sz7E8lcL+R6HuzPsT5PHkuY8qsL+WKHvLPtTyqwv5Yoe8s+1PJXC/keh7sz7E8lcL+R6HuzPsT5PHkZjyqwv5Yoe8s+1e2tnsZckDK+RqTvJ2DY52uJ/uBXq8lcL+R6HuzPsXqsaM0/bjMc+Cxs0ZBHLJUjcOvQ94T5PHkZkyiq401Z0z/AC+n5ZXV29ZMRPKXxPb6RC5x3id6hvyHuIG/MJ3FZODM0Irlcu7OQHzZGlr2OB2c1zT1a5pBBB6gghYVUREZVM3j/tKWdaIi1IIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiCr6V2yucz+Xfs5wsnHVz/Uih6OH9plMpJHeA3f4oVoVY0OPFTn8e7cS1srYeQRtu2YidpHrG0u2/rBHoVnXRj+JMas1vK2bks6RcmXy1LAYq7k8jZipY+lC+xYszO5WRRsaXOe4+gAAkn8y61Aa/pUMloXUNTKYqxncbPj547OLqM5prcZjcHRRjcbucN2jqOpHUd650ZdrjwtNI4LhfktYYA29QMqWqlTxc4+5XJNiQBrzzQ78nJzuDtuVxaGh27272/N8etF6c03ic5k79+nRypkbUZJhrvjMnZnZ+9cQ9q0D1uYBsQe4gr53s4jXmqOCvEjTeOxWqstpjG/BNjTcWqKHiuXlENhk1msGuDXTNY2FoY9w3cXcu79t1fuJuts5rDI6MuQ4viDitA2Y7nwlBg8ZZq5Z1tpjFdkzWATxQkGU8zeUEhvMQNkGk5Pj/AMP8RhdN5exqOF2O1GH/AATPXglnFssbzOYwRscefpsGEBxd5oBd0Vcp+E3gb3GOnoiOjlRDcxFXI177sRea50k8nKyN7DAOyYG8rjK8hoLi0lpY4LIODGhM/jrfBKpkNL5ui3Aak1O+23JVnvNRk0dl8D5JfOa4O7VgEgcWufuASQtU1TYyGi/Cfp6km0/mspg8vpeLCsuYii+22vZZdfIRMGAmNpZKDzu83zT16INwREQFV8ftiNeZGizZtfJVW5BjB6JmOEcx/sIdB0HpDj3lWhVgjx3iUxzNy3HYlzJDt03sTNLRv69qxJHo3HrC6ML+6J0W/wDOdlhZ0RFzoIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiCv5mhYx2VbncfD4xL2QguVWnzp4WkuaWejtGFztgehDnDpuCPDJ4jS/FPT3iuToY/UmIdIHOrXYGzRtkb6HMePNe3fqCAQe8BWNQmV0bistdN18MlXIEAG7SmfXmcB3BzmEF4HqduOp6LfFVNcRFerX1XTpVNvg3cKWBwbw40u0PGzgMTB1G4Ox831gf4Lv0/wM4d6TzFbLYXQ+n8Tk6xJhuU8bFFLGSC08rmtBG4JH9hKkDoiYABmp88xo9HbxO/5mMlPImx7VZ766H+Er+Hh7/KS0bVoRVfyJse1We+uh/hKp8VcfldG6ByuYx2qcwblYRmMTywlnnSsadx2Y9Dj6U/Dw9/lJaNrVF+EBwII3B7wqx5E2ParPfXQ/wk8ibHtVnvrof4Sfh4e/yktG1Xv/Vr4T/9W2lf+EQfur9Pg2cJ3Ek8N9LEnvJxMBJ/8KsHkTY9qs99dD/CX6NDueOWfUWdsM67t8bEW4P542tP+BTIw9/lJaNrvy2eq4PsKMDG2MjK3arjoSA9wHTcj+jGPS89B/aQD5adwz8TWnksvZNkbkvjFuZgPK6QgDZu/Xla1rWj8zRv1JXswunMbp6OVmPqMrmUh0su5dJKR0Be9xLnnb0uJKkljVVTEZNGj9zyERFpQREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQFnvH8gcIs/uSBtB3f9vH+cLQlnvH/f8EWf2232g+Ntt/p4/Wg0JERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQFnnhAjfhDqDqG9IOpHT/TxrQ1nnhA7fgh1Bv0G0Ho3/18aDQ0REBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQERE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D4czPsZm/raX3lPhzM+xmb+tpfeVf0TvUbkc+pfgqGExGQymbrZXJU3YuKm17a1SSRr5XPeNi95Y4tADdwACT5xJI7lb0Rc2JiTiTeSZuIiLUgiIgIiICIiAiIgIiICIiAiIgIiII7UcL7GnspFG0ukfVla1o9JLCAq1pd7ZNNYlzTu11SEg+scgV2VTtcPm9vI/GZvJYOF7i81aYgfCHHqS1ssT+Xc9dmkDck7dV24OJTFM0VTbWuqzpRcHkBkPbPN/UUvu6eQGQ9s839RS+7rffD3459C3F3ouDyAyHtnm/qKX3dPIDIe2eb+opfd0vh78c+hbi70XB5AZD2zzf1FL7unkBkPbPN/UUvu6Xw9+OfQtxd6Lg8gMh7Z5v6il93TyAyHtnm/qKX3dL4e/HPoW4u9FweQGQ9s839RS+7p5AZD2zzf1FL7ul8Pfjn0LcXei4PIDIe2eb+opfd08gMh7Z5v6il93S+Hvxz6FuLvRcHkBkPbPN/UUvu6eQGQ9s839RS+7pfD3459C3F3ouDyAyHtnm/qKX3dPIDIe2eb+opfd0vh78c+hbi70XB5AZD2zzf1FL7uvJmgbm5Eurs1Mw97ezqM36+tsAI/uPpUvh78c+hbi/eH7CL2rZQd2S5cFp2PoqVmH/wATXD+5W9cmKxVXCY+GlShEFaIENbuXEkkkuJO5c4kklxJJJJJJJXWuLGrjErmqNHTMTnERFpQREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERB//9k=", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", "\n", - "try:\n", - " display(Image(graph.get_graph().draw_mermaid_png()))\n", - "except Exception:\n", - " # This requires some extra dependencies and is optional\n", - " pass" + "graph = graph_builder.compile(checkpointer=memory)" ] }, { @@ -2728,13 +2662,106 @@ "source": [ "The chat bot can either request help from a human (chatbot->select->human), invoke the search engine tool (chatbot->select->action), or directly respond (chatbot->select->__end__). Once an action or request has been made, the graph will transition back to the `chatbot` node to continue operations.\n", "\n", - "Let's see this graph in action. We will request for expert assistance to illustrate our graph." + "Let's see this graph in action. We first ask it a question that requires no human intervention:" ] }, { "cell_type": "code", - "execution_count": 62, - "id": "c1955d79-a1e4-47d0-ba79-b45bd5752a23", + "execution_count": 22, + "id": "00a11e0c-937d-4f11-a623-bf16ee1f6d4e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "Can you search for the weather in San Francisco?\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "[{'text': \"Certainly! I'd be happy to search for the weather in San Francisco for you. To get the most up-to-date and accurate information, I'll use the search function to look this up. Let me do that for you right away.\", 'type': 'text'}, {'id': 'toolu_01QvcSUFnMXDrK4dWJ4g34P7', 'input': {'query': 'current weather in San Francisco'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "Tool Calls:\n", + " tavily_search_results_json (toolu_01QvcSUFnMXDrK4dWJ4g34P7)\n", + " Call ID: toolu_01QvcSUFnMXDrK4dWJ4g34P7\n", + " Args:\n", + " query: current weather in San Francisco\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: tavily_search_results_json\n", + "\n", + "[{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.775, 'lon': -122.4183, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1736974398, 'localtime': '2025-01-15 12:53'}, 'current': {'last_updated_epoch': 1736973900, 'last_updated': '2025-01-15 12:45', 'temp_c': 11.7, 'temp_f': 53.1, 'is_day': 1, 'condition': {'text': 'Sunny', 'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png', 'code': 1000}, 'wind_mph': 5.8, 'wind_kph': 9.4, 'wind_degree': 45, 'wind_dir': 'NE', 'pressure_mb': 1025.0, 'pressure_in': 30.27, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 41, 'cloud': 0, 'feelslike_c': 10.8, 'feelslike_f': 51.4, 'windchill_c': 9.6, 'windchill_f': 49.3, 'heatindex_c': 11.1, 'heatindex_f': 51.9, 'dewpoint_c': 6.3, 'dewpoint_f': 43.3, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 2.4, 'gust_mph': 7.7, 'gust_kph': 12.4}}\"}, {\"url\": \"https://www.yahoo.com/news/january-15-2025-san-francisco-135157305.html\", \"content\": \"January 15, 2025 San Francisco Bay Area weather forecast Search query Search the web News Finance Sports Manage your account Add or switch accounts Search the web Wildfire damage from space L.A. fires underlying causes Rent hikes amid wildfires Photos: Wildfire devastation L.A. wildfires live updates KRON San Francisco January 15, 2025 San Francisco Bay Area weather forecast KRON San Francisco Wed, January 15, 2025 at 1:51 PM UTC KRON4 Meteorologist Gayle Ong has the latest Bay Area weather outlook. https://www.kron4.com/weather/san-francisco-bay-area-weather-forecast/ Solve the daily Crossword 28,373 people played the daily Crossword recently. Can you solve it faster than others?28,373 people played the daily Crossword recently. Can you solve it faster than others? Crossword Play on Yahoo Yahoo! © 2024 Yahoo.\"}]\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Thank you for your patience. I've searched for the current weather in San Francisco, and I have the latest information for you. Here's the weather report for San Francisco:\n", + "\n", + "Date and Time: January 15, 2025, 12:45 PM local time\n", + "Temperature: 11.7°C (53.1°F)\n", + "Condition: Sunny\n", + "Wind: 5.8 mph (9.4 km/h), coming from the Northeast\n", + "Humidity: 41%\n", + "Precipitation: 0 mm (0 inches)\n", + "Visibility: 16 km (9 miles)\n", + "UV Index: 2.4 (low)\n", + "\n", + "It's a nice day in San Francisco with clear, sunny skies. The temperature is mild, typical for a winter day in the city. The wind is light, and there's no precipitation expected. It's a good day for outdoor activities, but you might want to bring a light jacket as it's not too warm.\n", + "\n", + "Is there anything specific about the weather you'd like to know more about?\n" + ] + } + ], + "source": [ + "user_input = \"Can you search for the weather in San Francisco?\"\n", + "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", + "\n", + "events = graph.stream(\n", + " {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n", + ")\n", + "for event in events:\n", + " if \"messages\" in event:\n", + " event[\"messages\"][-1].pretty_print()" + ] + }, + { + "cell_type": "markdown", + "id": "0589f4c9-5ad9-42f0-818a-7e1fcad75517", + "metadata": {}, + "source": [ + "This works as expected, and the state indicates that no human assistance was requested:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "5d6e14ce-4687-48e2-a488-dca48aa9722b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.get_state(config).values.get(\"ask_human\", False)" + ] + }, + { + "cell_type": "markdown", + "id": "a06c0ce3-dc78-40a2-8ae2-7f4429d4bf9d", + "metadata": {}, + "source": [ + "We next request for expert assistance:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "b789d334-9222-412c-83f2-0298571ce5c2", "metadata": {}, "outputs": [ { @@ -2746,19 +2773,19 @@ "I need some expert guidance for building this AI agent. Could you request assistance for me?\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"Certainly! I understand that you need expert guidance for building an AI agent. I'll use the RequestAssistance function to escalate your request to an expert who can provide you with the specialized knowledge and support you need. Let me do that for you right away.\", 'type': 'text'}, {'id': 'toolu_01Mo3N2c1byuSZwT1vyJWRia', 'input': {'request': 'The user needs expert guidance for building an AI agent. They require specialized knowledge and support in AI development and implementation.'}, 'name': 'RequestAssistance', 'type': 'tool_use'}]\n", + "[{'text': \"Certainly! I understand that you need expert guidance for building an AI agent. This is a complex topic that would benefit from specialized knowledge. I'll use the RequestAssistance function to escalate your request to an expert who can provide more in-depth support.\", 'type': 'text'}, {'id': 'toolu_01LruhQDWhxozxHJ94qDndEF', 'input': {'request': 'The user needs expert guidance for building an AI agent. They are looking for specialized knowledge and support in this area.'}, 'name': 'RequestAssistance', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " RequestAssistance (toolu_01Mo3N2c1byuSZwT1vyJWRia)\n", - " Call ID: toolu_01Mo3N2c1byuSZwT1vyJWRia\n", + " RequestAssistance (toolu_01LruhQDWhxozxHJ94qDndEF)\n", + " Call ID: toolu_01LruhQDWhxozxHJ94qDndEF\n", " Args:\n", - " request: The user needs expert guidance for building an AI agent. They require specialized knowledge and support in AI development and implementation.\n" + " request: The user needs expert guidance for building an AI agent. They are looking for specialized knowledge and support in this area.\n" ] } ], "source": [ "user_input = \"I need some expert guidance for building this AI agent. Could you request assistance for me?\"\n", - "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", - "# The config is the **second positional argument** to stream() or invoke()!\n", + "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", + "\n", "events = graph.stream(\n", " {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n", ")\n", @@ -2767,75 +2794,66 @@ " event[\"messages\"][-1].pretty_print()" ] }, - { - "cell_type": "markdown", - "id": "b3945ea4-8dbd-4e14-ae2a-34da7f05a0c1", - "metadata": {}, - "source": [ - "**Notice:** the LLM has invoked the \"`RequestAssistance`\" tool we provided it, and the interrupt has been set. Let's inspect the graph state to confirm." - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "id": "5320ba05-5696-4194-8278-5385c571264d", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "('human',)" - ] - }, - "execution_count": 63, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "snapshot = graph.get_state(config)\n", - "snapshot.next" - ] - }, { "cell_type": "markdown", "id": "ed2dd02e-f0a6-4f63-a7d6-e49ecf40db21", "metadata": {}, "source": [ - "The graph state is indeed **interrupted** before the `'human'` node. We can act as the \"expert\" in this scenario and manually update the state by adding a new ToolMessage with our input.\n", - "\n", - "Next, respond to the chatbot's request by:\n", - "1. Creating a `ToolMessage` with our response. This will be passed back to the `chatbot`.\n", - "2. Calling `update_state` to manually update the graph state." + "We can respond as before, by constructing an appropriate `Command`:" ] }, { "cell_type": "code", - "execution_count": 64, - "id": "2cbac924-61ce-4282-9b1c-77f9090ea1f5", + "execution_count": 28, + "id": "a91f333b-8c4d-44cb-ae6a-0a5e8ed4f23b", "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "{'configurable': {'thread_id': '1',\n", - " 'checkpoint_ns': '',\n", - " 'checkpoint_id': '1ef7d092-bb30-6bee-8002-015e7e1c56c0'}}" - ] - }, - "execution_count": 64, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "[{'text': \"Certainly! I understand that you need expert guidance for building an AI agent. This is a complex topic that would benefit from specialized knowledge. I'll use the RequestAssistance function to escalate your request to an expert who can provide more in-depth support.\", 'type': 'text'}, {'id': 'toolu_01LruhQDWhxozxHJ94qDndEF', 'input': {'request': 'The user needs expert guidance for building an AI agent. They are looking for specialized knowledge and support in this area.'}, 'name': 'RequestAssistance', 'type': 'tool_use'}]\n", + "Tool Calls:\n", + " RequestAssistance (toolu_01LruhQDWhxozxHJ94qDndEF)\n", + " Call ID: toolu_01LruhQDWhxozxHJ94qDndEF\n", + " Args:\n", + " request: The user needs expert guidance for building an AI agent. They are looking for specialized knowledge and support in this area.\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: RequestAssistance\n", + "\n", + "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Thank you for your patience. I've escalated your request, and an expert has provided some initial guidance. Here's what they recommend:\n", + "\n", + "The experts suggest that you look into LangGraph for building your AI agent. They mention that LangGraph is a more reliable and extensible option compared to simple autonomous agents.\n", + "\n", + "LangGraph is likely a framework or library designed specifically for creating advanced AI agents. It seems to offer benefits in terms of reliability and extensibility, which are crucial factors when developing complex AI systems.\n", + "\n", + "To follow up on this recommendation, you might want to:\n", + "\n", + "1. Research LangGraph to understand its features, capabilities, and how it compares to other agent-building frameworks.\n", + "2. Look for documentation, tutorials, or guides on how to get started with LangGraph.\n", + "3. Consider any specific requirements or goals you have for your AI agent and how LangGraph might address them.\n", + "\n", + "Do you have any specific questions about LangGraph or particular aspects of AI agent development that you'd like me to try to find more information about? I'd be happy to help you dig deeper into this topic.\n" + ] } ], "source": [ - "ai_message = snapshot.values[\"messages\"][-1]\n", "human_response = (\n", " \"We, the experts are here to help! We'd recommend you check out LangGraph to build your agent.\"\n", " \" It's much more reliable and extensible than simple autonomous agents.\"\n", ")\n", - "tool_message = create_response(human_response, ai_message)\n", - "graph.update_state(config, {\"messages\": [tool_message]})" + "\n", + "human_command = Command(resume={\"action\": \"feedback\", \"data\": human_response})\n", + "\n", + "events = graph.stream(human_command, config, stream_mode=\"values\")\n", + "for event in events:\n", + " if \"messages\" in event:\n", + " event[\"messages\"][-1].pretty_print()" ] }, { @@ -2843,87 +2861,28 @@ "id": "79492363-7fc6-4ec7-977d-9030648029bc", "metadata": {}, "source": [ - "You can inspect the state to confirm our response was added." + "You can inspect the state to it's been flagged:" ] }, { "cell_type": "code", - "execution_count": 65, - "id": "4b986c66-1c65-4da8-a404-db7e28f8364e", + "execution_count": 29, + "id": "d2c94b9d-fbbd-4131-bd49-6c95d8c3708b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[HumanMessage(content='I need some expert guidance for building this AI agent. Could you request assistance for me?', additional_kwargs={}, response_metadata={}, id='3f28f959-9ab7-489a-9c58-7ed1b49cedf3'),\n", - " AIMessage(content=[{'text': \"Certainly! I understand that you need expert guidance for building an AI agent. I'll use the RequestAssistance function to escalate your request to an expert who can provide you with the specialized knowledge and support you need. Let me do that for you right away.\", 'type': 'text'}, {'id': 'toolu_01Mo3N2c1byuSZwT1vyJWRia', 'input': {'request': 'The user needs expert guidance for building an AI agent. They require specialized knowledge and support in AI development and implementation.'}, 'name': 'RequestAssistance', 'type': 'tool_use'}], additional_kwargs={}, response_metadata={'id': 'msg_01VRnZvVbgsVRbQaQuvsziDx', 'model': 'claude-3-5-sonnet-20240620', 'stop_reason': 'tool_use', 'stop_sequence': None, 'usage': {'input_tokens': 516, 'output_tokens': 130}}, id='run-4e3f7906-5887-40d9-9267-5beefe7b3b76-0', tool_calls=[{'name': 'RequestAssistance', 'args': {'request': 'The user needs expert guidance for building an AI agent. They require specialized knowledge and support in AI development and implementation.'}, 'id': 'toolu_01Mo3N2c1byuSZwT1vyJWRia', 'type': 'tool_call'}], usage_metadata={'input_tokens': 516, 'output_tokens': 130, 'total_tokens': 646}),\n", - " ToolMessage(content=\"We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\", id='8583b899-d898-4051-9f36-f5e5d11e9a37', tool_call_id='toolu_01Mo3N2c1byuSZwT1vyJWRia')]" + "True" ] }, - "execution_count": 65, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "graph.get_state(config).values[\"messages\"]" - ] - }, - { - "cell_type": "markdown", - "id": "ea6b8616-de10-44d6-a8f0-3ac73c3c3680", - "metadata": {}, - "source": [ - "Next, **resume** the graph by invoking it with `None` as the inputs." - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "id": "6b32914d-4d60-491f-8e11-1e6867e38ffd", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "\n", - "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "\n", - "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Thank you for your patience. I've escalated your request to our expert team, and they have provided some initial guidance. Here's what they suggest:\n", - "\n", - "The experts recommend that you check out LangGraph for building your AI agent. They mention that LangGraph is a more reliable and extensible option compared to simple autonomous agents.\n", - "\n", - "LangGraph is likely a framework or tool designed specifically for creating complex AI agents. It seems to offer advantages in terms of reliability and extensibility, which are crucial factors when developing sophisticated AI systems.\n", - "\n", - "To further assist you, I can provide some additional context and next steps:\n", - "\n", - "1. Research LangGraph: Look up documentation, tutorials, and examples of LangGraph to understand its features and how it can help you build your AI agent.\n", - "\n", - "2. Compare with other options: While the experts recommend LangGraph, it might be useful to understand how it compares to other AI agent development frameworks or tools you might have been considering.\n", - "\n", - "3. Assess your requirements: Consider your specific needs for the AI agent you want to build. Think about the tasks it needs to perform, the level of complexity required, and how LangGraph's features align with these requirements.\n", - "\n", - "4. Start with a small project: If you decide to use LangGraph, consider beginning with a small, manageable project to familiarize yourself with the framework.\n", - "\n", - "5. Seek community support: Look for LangGraph user communities, forums, or discussion groups where you can ask questions and get additional support as you build your agent.\n", - "\n", - "6. Consider additional training: Depending on your current skill level, you might want to look into courses or workshops that focus on AI agent development, particularly those that cover LangGraph.\n", - "\n", - "Do you have any specific questions about LangGraph or AI agent development that you'd like me to try to answer? Or would you like me to search for more detailed information about LangGraph and its features?\n" - ] - } - ], - "source": [ - "events = graph.stream(None, config, stream_mode=\"values\")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" + "graph.get_state(config).values[\"ask_human\"]" ] }, { @@ -2933,8 +2892,6 @@ "source": [ "**Notice** that the chat bot has incorporated the updated state in its final response. Since **everything** was checkpointed, the \"expert\" human in the loop could perform the update at any time without impacting the graph's execution.\n", "\n", - "**Congratulations!** you've now added an additional node to your assistant graph to let the chat bot decide for itself whether or not it needs to interrupt execution. You did so by updating the graph `State` with a new `ask_human` field and modifying the interruption logic when compiling the graph. This lets you dynamically include a human in the loop while maintaining full **memory** every time you execute the graph.\n", - "\n", "We're almost done with the tutorial, but there is one more concept we'd like to review before finishing that connects `checkpointing` and `state updates`. \n", "\n", "This section's code is reproduced below for your reference.\n", @@ -2944,19 +2901,18 @@ "
\n",
     "\n",
     "```python\n",
-    "from typing import Annotated\n",
+    "from typing import Annotated, Literal\n",
     "\n",
     "from langchain_anthropic import ChatAnthropic\n",
     "from langchain_community.tools.tavily_search import TavilySearchResults\n",
-    "from langchain_core.messages import BaseMessage\n",
-    "# NOTE: you must use langchain-core >= 0.3 with Pydantic v2\n",
     "from pydantic import BaseModel\n",
     "from typing_extensions import TypedDict\n",
     "\n",
     "from langgraph.checkpoint.memory import MemorySaver\n",
-    "from langgraph.graph import StateGraph\n",
+    "from langgraph.graph import StateGraph, START, END\n",
     "from langgraph.graph.message import add_messages\n",
-    "from langgraph.prebuilt import ToolNode, tools_condition\n",
+    "from langgraph.prebuilt import ToolNode\n",
+    "from langgraph.types import Command, interrupt\n",
     "\n",
     "\n",
     "class State(TypedDict):\n",
@@ -2977,74 +2933,70 @@
     "tool = TavilySearchResults(max_results=2)\n",
     "tools = [tool]\n",
     "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
-    "# We can bind the llm to a tool definition, a pydantic model, or a json schema\n",
     "llm_with_tools = llm.bind_tools(tools + [RequestAssistance])\n",
     "\n",
     "\n",
     "def chatbot(state: State):\n",
-    "    response = llm_with_tools.invoke(state[\"messages\"])\n",
-    "    ask_human = False\n",
-    "    if (\n",
-    "        response.tool_calls\n",
-    "        and response.tool_calls[0][\"name\"] == RequestAssistance.__name__\n",
-    "    ):\n",
-    "        ask_human = True\n",
-    "    return {\"messages\": [response], \"ask_human\": ask_human}\n",
+    "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
+    "\n",
+    "\n",
+    "def human_review_node(state: State) -> Command[Literal[\"chatbot\", \"tools\"]]:\n",
+    "    last_message = state[\"messages\"][-1]\n",
+    "    tool_call = last_message.tool_calls[-1]\n",
+    "\n",
+    "    if not tool_call[\"name\"] == RequestAssistance.__name__:\n",
+    "        return Command(goto=\"tools\")\n",
+    "\n",
+    "    human_review = interrupt(\n",
+    "        {\n",
+    "            \"question\": \"Is this correct?\",\n",
+    "            \"tool_call\": tool_call,\n",
+    "        }\n",
+    "    )\n",
+    "\n",
+    "    review_action = human_review[\"action\"]\n",
+    "    review_data = human_review.get(\"data\")\n",
+    "\n",
+    "    if review_action == \"continue\":\n",
+    "        return Command(goto=\"tools\", update={\"ask_human\": True})\n",
+    "\n",
+    "    elif review_action == \"feedback\":\n",
+    "        tool_message = {\n",
+    "            \"role\": \"tool\",\n",
+    "            \"content\": review_data,\n",
+    "            \"name\": tool_call[\"name\"],\n",
+    "            \"tool_call_id\": tool_call[\"id\"],\n",
+    "        }\n",
+    "        return Command(\n",
+    "            goto=\"chatbot\",\n",
+    "            update={\"messages\": [tool_message], \"ask_human\": True},\n",
+    "        )\n",
+    "\n",
+    "\n",
+    "def route_after_llm(state) -> Literal[END, \"human_review_node\"]:\n",
+    "    if len(state[\"messages\"][-1].tool_calls) == 0:\n",
+    "        return END\n",
+    "    else:\n",
+    "        return \"human_review_node\"\n",
     "\n",
     "\n",
     "graph_builder = StateGraph(State)\n",
     "\n",
-    "graph_builder.add_node(\"chatbot\", chatbot)\n",
-    "graph_builder.add_node(\"tools\", ToolNode(tools=[tool]))\n",
-    "\n",
-    "\n",
-    "def create_response(response: str, ai_message: AIMessage):\n",
-    "    return ToolMessage(\n",
-    "        content=response,\n",
-    "        tool_call_id=ai_message.tool_calls[0][\"id\"],\n",
-    "    )\n",
-    "\n",
-    "\n",
-    "def human_node(state: State):\n",
-    "    new_messages = []\n",
-    "    if not isinstance(state[\"messages\"][-1], ToolMessage):\n",
-    "        # Typically, the user will have updated the state during the interrupt.\n",
-    "        # If they choose not to, we will include a placeholder ToolMessage to\n",
-    "        # let the LLM continue.\n",
-    "        new_messages.append(\n",
-    "            create_response(\"No response from human.\", state[\"messages\"][-1])\n",
-    "        )\n",
-    "    return {\n",
-    "        # Append the new messages\n",
-    "        \"messages\": new_messages,\n",
-    "        # Unset the flag\n",
-    "        \"ask_human\": False,\n",
-    "    }\n",
-    "\n",
-    "\n",
-    "graph_builder.add_node(\"human\", human_node)\n",
-    "\n",
-    "\n",
-    "def select_next_node(state: State):\n",
-    "    if state[\"ask_human\"]:\n",
-    "        return \"human\"\n",
-    "    # Otherwise, we can route as before\n",
-    "    return tools_condition(state)\n",
+    "graph_builder.add_node(chatbot)\n",
     "\n",
+    "tool_node = ToolNode(tools=[tool])\n",
+    "graph_builder.add_node(\"tools\", tool_node)\n",
+    "graph_builder.add_node(human_review_node)\n",
     "\n",
     "graph_builder.add_conditional_edges(\n",
     "    \"chatbot\",\n",
-    "    select_next_node,\n",
-    "    {\"human\": \"human\", \"tools\": \"tools\", \"__end__\": \"__end__\"},\n",
+    "    route_after_llm,\n",
     ")\n",
     "graph_builder.add_edge(\"tools\", \"chatbot\")\n",
-    "graph_builder.add_edge(\"human\", \"chatbot\")\n",
-    "graph_builder.set_entry_point(\"chatbot\")\n",
+    "graph_builder.add_edge(START, \"chatbot\")\n",
+    "\n",
     "memory = MemorySaver()\n",
-    "graph = graph_builder.compile(\n",
-    "    checkpointer=memory,\n",
-    "    interrupt_before=[\"human\"],\n",
-    ")\n",
+    "graph = graph_builder.compile(checkpointer=memory)\n",
     "```\n",
     "
\n", "" @@ -3070,25 +3022,23 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 1, "id": "bb8a02de-a21b-4ef6-a714-7d6e44435e3a", "metadata": {}, "outputs": [], "source": [ - "from typing import Annotated\n", + "from typing import Annotated, Literal\n", "\n", "from langchain_anthropic import ChatAnthropic\n", "from langchain_community.tools.tavily_search import TavilySearchResults\n", - "from langchain_core.messages import AIMessage, ToolMessage\n", - "\n", - "# NOTE: you must use langchain-core >= 0.3 with Pydantic v2\n", "from pydantic import BaseModel\n", "from typing_extensions import TypedDict\n", "\n", "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.graph import StateGraph, START\n", + "from langgraph.graph import StateGraph, START, END\n", "from langgraph.graph.message import add_messages\n", - "from langgraph.prebuilt import ToolNode, tools_condition\n", + "from langgraph.prebuilt import ToolNode\n", + "from langgraph.types import Command, interrupt\n", "\n", "\n", "class State(TypedDict):\n", @@ -3109,85 +3059,81 @@ "tool = TavilySearchResults(max_results=2)\n", "tools = [tool]\n", "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n", - "# We can bind the llm to a tool definition, a pydantic model, or a json schema\n", "llm_with_tools = llm.bind_tools(tools + [RequestAssistance])\n", "\n", "\n", "def chatbot(state: State):\n", - " response = llm_with_tools.invoke(state[\"messages\"])\n", - " ask_human = False\n", - " if (\n", - " response.tool_calls\n", - " and response.tool_calls[0][\"name\"] == RequestAssistance.__name__\n", - " ):\n", - " ask_human = True\n", - " return {\"messages\": [response], \"ask_human\": ask_human}\n", + " return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n", + "\n", + "\n", + "def human_review_node(state: State) -> Command[Literal[\"chatbot\", \"tools\"]]:\n", + " last_message = state[\"messages\"][-1]\n", + " tool_call = last_message.tool_calls[-1]\n", + "\n", + " if not tool_call[\"name\"] == RequestAssistance.__name__:\n", + " return Command(goto=\"tools\")\n", + "\n", + " human_review = interrupt(\n", + " {\n", + " \"question\": \"Is this correct?\",\n", + " \"tool_call\": tool_call,\n", + " }\n", + " )\n", + "\n", + " review_action = human_review[\"action\"]\n", + " review_data = human_review.get(\"data\")\n", + "\n", + " if review_action == \"continue\":\n", + " return Command(goto=\"tools\", update={\"ask_human\": True})\n", + "\n", + " elif review_action == \"feedback\":\n", + " tool_message = {\n", + " \"role\": \"tool\",\n", + " \"content\": review_data,\n", + " \"name\": tool_call[\"name\"],\n", + " \"tool_call_id\": tool_call[\"id\"],\n", + " }\n", + " return Command(\n", + " goto=\"chatbot\",\n", + " update={\"messages\": [tool_message], \"ask_human\": True},\n", + " )\n", + "\n", + "\n", + "def route_after_llm(state) -> Literal[END, \"human_review_node\"]:\n", + " if len(state[\"messages\"][-1].tool_calls) == 0:\n", + " return END\n", + " else:\n", + " return \"human_review_node\"\n", "\n", "\n", "graph_builder = StateGraph(State)\n", "\n", - "graph_builder.add_node(\"chatbot\", chatbot)\n", - "graph_builder.add_node(\"tools\", ToolNode(tools=[tool]))\n", - "\n", - "\n", - "def create_response(response: str, ai_message: AIMessage):\n", - " return ToolMessage(\n", - " content=response,\n", - " tool_call_id=ai_message.tool_calls[0][\"id\"],\n", - " )\n", - "\n", - "\n", - "def human_node(state: State):\n", - " new_messages = []\n", - " if not isinstance(state[\"messages\"][-1], ToolMessage):\n", - " # Typically, the user will have updated the state during the interrupt.\n", - " # If they choose not to, we will include a placeholder ToolMessage to\n", - " # let the LLM continue.\n", - " new_messages.append(\n", - " create_response(\"No response from human.\", state[\"messages\"][-1])\n", - " )\n", - " return {\n", - " # Append the new messages\n", - " \"messages\": new_messages,\n", - " # Unset the flag\n", - " \"ask_human\": False,\n", - " }\n", - "\n", - "\n", - "graph_builder.add_node(\"human\", human_node)\n", - "\n", - "\n", - "def select_next_node(state: State):\n", - " if state[\"ask_human\"]:\n", - " return \"human\"\n", - " # Otherwise, we can route as before\n", - " return tools_condition(state)\n", + "graph_builder.add_node(chatbot)\n", "\n", + "tool_node = ToolNode(tools=[tool])\n", + "graph_builder.add_node(\"tools\", tool_node)\n", + "graph_builder.add_node(human_review_node)\n", "\n", "graph_builder.add_conditional_edges(\n", " \"chatbot\",\n", - " select_next_node,\n", - " {\"human\": \"human\", \"tools\": \"tools\", END: END},\n", + " route_after_llm,\n", ")\n", "graph_builder.add_edge(\"tools\", \"chatbot\")\n", - "graph_builder.add_edge(\"human\", \"chatbot\")\n", "graph_builder.add_edge(START, \"chatbot\")\n", + "\n", "memory = MemorySaver()\n", - "graph = graph_builder.compile(\n", - " checkpointer=memory,\n", - " interrupt_before=[\"human\"],\n", - ")" + "graph = graph_builder.compile(checkpointer=memory)" ] }, { "cell_type": "code", - "execution_count": 68, - "id": "a7debb4a-2a3a-40b9-a48c-7052ec2c2726", + "execution_count": 2, + "id": "88faedd2-d12f-4084-9942-491f5ad8e6e7", "metadata": {}, "outputs": [ { "data": { - "image/jpeg": "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fp6km0/mspg8vpeLCsuYii+22vZZdfIRMGAmNpZKDzu83zT16INwREQFV8ftiNeZGizZtfJVW5BjB6JmOEcx/sIdB0HpDj3lWhVgjx3iUxzNy3HYlzJDt03sTNLRv69qxJHo3HrC6ML+6J0W/wDOdlhZ0RFzoIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiCv5mhYx2VbncfD4xL2QguVWnzp4WkuaWejtGFztgehDnDpuCPDJ4jS/FPT3iuToY/UmIdIHOrXYGzRtkb6HMePNe3fqCAQe8BWNQmV0bistdN18MlXIEAG7SmfXmcB3BzmEF4HqduOp6LfFVNcRFerX1XTpVNvg3cKWBwbw40u0PGzgMTB1G4Ox831gf4Lv0/wM4d6TzFbLYXQ+n8Tk6xJhuU8bFFLGSC08rmtBG4JH9hKkDoiYABmp88xo9HbxO/5mMlPImx7VZ766H+Er+Hh7/KS0bVoRVfyJse1We+uh/hKp8VcfldG6ByuYx2qcwblYRmMTywlnnSsadx2Y9Dj6U/Dw9/lJaNrVF+EBwII3B7wqx5E2ParPfXQ/wk8ibHtVnvrof4Sfh4e/yktG1Xv/Vr4T/9W2lf+EQfur9Pg2cJ3Ek8N9LEnvJxMBJ/8KsHkTY9qs99dD/CX6NDueOWfUWdsM67t8bEW4P542tP+BTIw9/lJaNrvy2eq4PsKMDG2MjK3arjoSA9wHTcj+jGPS89B/aQD5adwz8TWnksvZNkbkvjFuZgPK6QgDZu/Xla1rWj8zRv1JXswunMbp6OVmPqMrmUh0su5dJKR0Be9xLnnb0uJKkljVVTEZNGj9zyERFpQREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQFnvH8gcIs/uSBtB3f9vH+cLQlnvH/f8EWf2232g+Ntt/p4/Wg0JERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQFnnhAjfhDqDqG9IOpHT/TxrQ1nnhA7fgh1Bv0G0Ho3/18aDQ0REBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQERE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D4czPsZm/raX3lPhzM+xmb+tpfeVf0TvUbkc+pfgqGExGQymbrZXJU3YuKm17a1SSRr5XPeNi95Y4tADdwACT5xJI7lb0Rc2JiTiTeSZuIiLUgiIgIiICIiAiIgIiICIiAiIgIiII7UcL7GnspFG0ukfVla1o9JLCAq1pd7ZNNYlzTu11SEg+scgV2VTtcPm9vI/GZvJYOF7i81aYgfCHHqS1ssT+Xc9dmkDck7dV24OJTFM0VTbWuqzpRcHkBkPbPN/UUvu6eQGQ9s839RS+7rffD3459C3F3ouDyAyHtnm/qKX3dPIDIe2eb+opfd0vh78c+hbi70XB5AZD2zzf1FL7unkBkPbPN/UUvu6Xw9+OfQtxd6Lg8gMh7Z5v6il93TyAyHtnm/qKX3dL4e/HPoW4u9FweQGQ9s839RS+7p5AZD2zzf1FL7ul8Pfjn0LcXei4PIDIe2eb+opfd08gMh7Z5v6il93S+Hvxz6FuLvRcHkBkPbPN/UUvu6eQGQ9s839RS+7pfD3459C3F3ouDyAyHtnm/qKX3dPIDIe2eb+opfd0vh78c+hbi70XB5AZD2zzf1FL7uvJmgbm5Eurs1Mw97ezqM36+tsAI/uPpUvh78c+hbi/eH7CL2rZQd2S5cFp2PoqVmH/wATXD+5W9cmKxVXCY+GlShEFaIENbuXEkkkuJO5c4kklxJJJJJJJXWuLGrjErmqNHTMTnERFpQREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERB//9k=", + "image/png": "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", "text/plain": [ "" ] @@ -3216,7 +3162,7 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 3, "id": "69071b02-c011-4b7f-90b1-8e89e032322d", "metadata": {}, "outputs": [ @@ -3229,45 +3175,44 @@ "I'm learning LangGraph. Could you do some research on it for me?\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and accurate information, I'll use the Tavily search function to gather details about LangGraph. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_019HPZEw6v1eSLBXnwxk6MZm', 'input': {'query': 'LangGraph framework for language models'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "[{'text': \"Certainly! I'd be happy to help you research LangGraph. To provide you with the most up-to-date and accurate information, I'll use the Tavily search engine to gather some data for you. Let me do that now.\", 'type': 'text'}, {'id': 'toolu_01FuxELYf5Jn1iXcEeduiTDs', 'input': {'query': 'LangGraph framework for language models'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " tavily_search_results_json (toolu_019HPZEw6v1eSLBXnwxk6MZm)\n", - " Call ID: toolu_019HPZEw6v1eSLBXnwxk6MZm\n", + " tavily_search_results_json (toolu_01FuxELYf5Jn1iXcEeduiTDs)\n", + " Call ID: toolu_01FuxELYf5Jn1iXcEeduiTDs\n", " Args:\n", " query: LangGraph framework for language models\n", "=================================\u001b[1m Tool Message \u001b[0m=================================\n", "Name: tavily_search_results_json\n", "\n", - "[{\"url\": \"https://medium.com/@cplog/introduction-to-langgraph-a-beginners-guide-14f9be027141\", \"content\": \"LangGraph is a powerful tool for building stateful, multi-actor applications with Large Language Models (LLMs). It extends the LangChain library, allowing you to coordinate multiple chains (or ...\"}, {\"url\": \"https://towardsdatascience.com/from-basics-to-advanced-exploring-langgraph-e8c1cf4db787\", \"content\": \"LangChain is one of the leading frameworks for building applications powered by Lardge Language Models. With the LangChain Expression Language (LCEL), defining and executing step-by-step action sequences — also known as chains — becomes much simpler. In more technical terms, LangChain allows us to create DAGs (directed acyclic graphs).\"}]\n", + "[{\"url\": \"https://www.datacamp.com/tutorial/langgraph-tutorial\", \"content\": \"LangGraph provides a framework for defining, coordinating, and executing multiple LLM agents (or chains) in a structured manner. ... LangChain is a framework for including AI from large language models inside data pipelines and applications. This tutorial provides an overview of what you can do with LangChain, including the problems that\"}, {\"url\": \"https://www.langchain.com/langgraph\", \"content\": \"No. LangGraph is an orchestration framework for complex agentic systems and is more low-level and controllable than LangChain agents. LangChain provides a standard interface to interact with models and other components, useful for straight-forward chains and retrieval flows.\"}]\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", "Thank you for your patience. I've gathered some information about LangGraph for you. Let me summarize the key points:\n", "\n", - "1. What is LangGraph?\n", - " LangGraph is a powerful tool designed for building stateful, multi-actor applications using Large Language Models (LLMs). It's an extension of the LangChain library, which is already a popular framework for developing LLM-powered applications.\n", + "1. Purpose:\n", + " LangGraph is a framework designed for defining, coordinating, and executing multiple Language Model (LLM) agents or chains in a structured manner.\n", "\n", - "2. Purpose and Functionality:\n", - " - LangGraph allows developers to coordinate multiple chains or actors within a single application.\n", - " - It enhances the capabilities of LangChain by introducing more complex, stateful workflows.\n", + "2. Relation to LangChain:\n", + " While LangGraph and LangChain are related, they serve different purposes:\n", + " - LangChain is a framework for integrating AI from large language models into data pipelines and applications.\n", + " - LangGraph is more focused on orchestrating complex agentic systems.\n", "\n", - "3. Relation to LangChain:\n", - " - LangGraph builds upon LangChain, which is one of the leading frameworks for creating LLM-powered applications.\n", - " - LangChain itself uses the LangChain Expression Language (LCEL) to define and execute step-by-step action sequences, also known as chains.\n", - " - LangChain allows the creation of DAGs (Directed Acyclic Graphs), which represent the flow of operations in an application.\n", + "3. Level of Control:\n", + " LangGraph is described as more low-level and controllable compared to LangChain agents. This suggests that it offers more fine-grained control over the interaction between different components in a language model system.\n", "\n", - "4. Key Features:\n", - " - Stateful Applications: Unlike simple query-response models, LangGraph allows the creation of applications that maintain state across interactions.\n", - " - Multi-Actor Systems: It supports coordinating multiple AI \"actors\" or components within a single application, enabling more complex interactions and workflows.\n", + "4. Use Cases:\n", + " LangGraph seems particularly useful for scenarios where you need to coordinate multiple AI agents or create more complex workflows involving language models.\n", "\n", - "5. Use Cases:\n", - " While not explicitly mentioned in the search results, LangGraph is typically used for creating more sophisticated AI applications such as:\n", - " - Multi-turn conversational agents\n", - " - Complex task-planning systems\n", - " - Applications requiring memory and context management across multiple steps or actors\n", + "5. Comparison to LangChain Agents:\n", + " While LangChain provides a standard interface for interacting with models and components (useful for straightforward chains and retrieval flows), LangGraph appears to be more suited for building and managing more complex, multi-agent systems.\n", "\n", - "Learning LangGraph can be a valuable skill, especially if you're interested in developing advanced applications with LLMs that go beyond simple question-answering or text generation tasks. It allows for the creation of more dynamic, interactive, and stateful AI systems.\n", + "If you're learning LangGraph, it might be helpful to understand:\n", + "1. How to define and structure multiple agents or chains\n", + "2. The ways to coordinate these agents in a cohesive system\n", + "3. The types of complex workflows you can create with LangGraph\n", + "4. How it differs from and complements LangChain in practical applications\n", "\n", - "Is there any specific aspect of LangGraph you'd like to know more about, or do you have any questions about how it compares to or works with LangChain?\n" + "Would you like me to search for more specific information about any particular aspect of LangGraph, such as its key features, getting started guides, or specific use cases?\n" ] } ], @@ -3289,7 +3234,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 4, "id": "acbec099-e5d2-497f-929e-c548d7bcbf77", "metadata": {}, "outputs": [ @@ -3302,54 +3247,56 @@ "Ya that's helpful. Maybe I'll build an autonomous agent with it!\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"That's an excellent idea! Building an autonomous agent with LangGraph is a great way to explore its capabilities and learn about advanced AI application development. LangGraph's features make it well-suited for creating autonomous agents. Let me provide some additional insights and encouragement for your project.\", 'type': 'text'}, {'id': 'toolu_017t6BS5rNCzFWcpxRizDKjE', 'input': {'query': 'building autonomous agents with LangGraph examples and tutorials'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "[{'text': \"That's an exciting idea! Building an autonomous agent with LangGraph could be a great way to dive deep into the framework and explore its capabilities. LangGraph's focus on orchestrating complex agentic systems makes it well-suited for such a project. Let me gather some more specific information about using LangGraph for building autonomous agents.\", 'type': 'text'}, {'id': 'toolu_01TeAyyVo8fYBYApftT7yjTS', 'input': {'query': 'Building autonomous agents with LangGraph examples and tutorials'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " tavily_search_results_json (toolu_017t6BS5rNCzFWcpxRizDKjE)\n", - " Call ID: toolu_017t6BS5rNCzFWcpxRizDKjE\n", + " tavily_search_results_json (toolu_01TeAyyVo8fYBYApftT7yjTS)\n", + " Call ID: toolu_01TeAyyVo8fYBYApftT7yjTS\n", " Args:\n", - " query: building autonomous agents with LangGraph examples and tutorials\n", + " query: Building autonomous agents with LangGraph examples and tutorials\n", "=================================\u001b[1m Tool Message \u001b[0m=================================\n", "Name: tavily_search_results_json\n", "\n", - "[{\"url\": \"https://medium.com/@lucas.dahan/hands-on-langgraph-building-a-multi-agent-assistant-06aa68ed942f\", \"content\": \"Building the Graph. With our agents defined, we'll create a graph.py file to orchestrate their interactions. The basic graph structure in LangGraph is really simple, here we are going to use ...\"}, {\"url\": \"https://medium.com/@cplog/building-tool-calling-conversational-ai-with-langchain-and-langgraph-a-beginners-guide-8d6986cc589e\", \"content\": \"Introduction to AI Agent with LangChain and LangGraph: A Beginner’s Guide Two powerful tools revolutionizing this field are LangChain and LangGraph. In this guide, we’ll explore how these technologies can be combined to build a sophisticated AI assistant capable of handling complex conversations and tasks. Tool calling is a standout feature in agentic design, allowing the LLM to interact with external systems or perform specific tasks via the @tool decorator. While the Assistant class presented here is one approach, the flexibility of tool calling and LangGraph allows for a wide range of designs. With LangChain and LangGraph, you can build a powerful, flexible AI assistant capable of handling complex tasks and conversations. Tool calling significantly enhances the AI’s capabilities by enabling interaction with external systems.\"}]\n", + "[{\"url\": \"https://towardsdatascience.com/building-autonomous-multi-tool-agents-with-gemini-2-0-and-langgraph-ad3d7bd5e79d\", \"content\": \"Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph | by Youness Mansar | Jan, 2025 | Towards Data Science Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph A practical tutorial with full code examples for building and running multi-tool agents Towards Data Science LLMs are remarkable — they can memorize vast amounts of information, answer general knowledge questions, write code, generate stories, and even fix your grammar. In this tutorial, we are going to build a simple LLM agent that is equipped with four tools that it can use to answer a user’s question. This Agent will have the following specifications: Follow Published in Towards Data Science --------------------------------- Your home for data science and AI. Follow Follow Follow\"}, {\"url\": \"https://blog.futuresmart.ai/langgraph-agent-with-rag-and-nl2sql\", \"content\": \"In this blog post, we will walk you through the process of creating a custom AI agent with three powerful tools: Web Search, Retrieval-Augmented Generation (RAG), and Natural Language to SQL (NL2SQL), all integrated within the LangGraph framework. This guide is designed to provide you with a practical, step-by-step approach to building a fully functional AI agent capable of performing complex tasks such as retrieving real-time data from the web, generating responses based on retrieved information from the knowledge base, and translating natural language queries into SQL database queries. By following this tutorial, you've built an AI agent capable of performing diverse tasks such as retrieving real-time data, answering questions based on document-based knowledge, and executing SQL queries directly from natural language commands.\"}]\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "Your enthusiasm for building an autonomous agent with LangGraph is fantastic! This project will not only help you learn more about LangGraph but also give you hands-on experience with cutting-edge AI development. Here are some insights and tips to get you started:\n", + "Thank you for sharing your interest in building an autonomous agent with LangGraph! That's an excellent way to learn and apply the framework. Based on the information I've gathered, I can provide you with some insights and guidance on how to approach this project:\n", "\n", - "1. Multi-Agent Systems:\n", - " LangGraph excels at creating multi-agent systems. You could design your autonomous agent as a collection of specialized sub-agents, each handling different aspects of tasks or knowledge domains.\n", + "1. Multi-Tool Agents:\n", + " LangGraph allows you to create autonomous agents that can use multiple tools. This is particularly powerful for creating versatile agents that can handle a variety of tasks.\n", "\n", - "2. Graph Structure:\n", - " The basic graph structure in LangGraph is straightforward. You'll create a graph.py file to orchestrate the interactions between your agents or components.\n", + "2. Integration with Advanced Language Models:\n", + " There's an example of building autonomous multi-tool agents using Gemini 2.0 (Google's advanced language model) and LangGraph. This suggests that LangGraph is compatible with state-of-the-art language models, which can enhance your agent's capabilities.\n", "\n", - "3. Tool Calling:\n", - " A key feature you can incorporate is tool calling. This allows your LLM-based agent to interact with external systems or perform specific tasks. You can implement this using the @tool decorator in your code.\n", + "3. Practical Tutorial Available:\n", + " There's a practical tutorial available with full code examples for building and running multi-tool agents. This could be an excellent starting point for your project.\n", "\n", - "4. Flexibility in Design:\n", - " LangGraph offers great flexibility in designing your agent. While there are example structures like the Assistant class, you have the freedom to create a wide range of designs tailored to your specific needs.\n", + "4. Diverse Tool Integration:\n", + " You can equip your agent with various tools. For example, one tutorial mentions creating an agent with four different tools to answer user questions.\n", "\n", - "5. Complex Conversations and Tasks:\n", - " Your autonomous agent can be designed to handle sophisticated conversations and complex tasks. This is where LangGraph's stateful nature really shines, allowing your agent to maintain context over extended interactions.\n", + "5. Complex Task Handling:\n", + " LangGraph enables the creation of agents capable of performing complex tasks such as:\n", + " - Web searching for real-time data retrieval\n", + " - Implementing Retrieval-Augmented Generation (RAG) for enhanced knowledge access\n", + " - Using Natural Language to SQL (NL2SQL) for database interactions\n", "\n", - "6. Integration with LangChain:\n", - " Since LangGraph builds upon LangChain, you can leverage features from both. This combination allows for powerful, flexible AI assistants capable of managing intricate workflows.\n", + "6. Step-by-Step Guides:\n", + " There are resources available that provide step-by-step approaches to building fully functional AI agents using LangGraph.\n", "\n", - "7. External System Interaction:\n", - " Consider incorporating external APIs or databases to enhance your agent's capabilities. This could include accessing real-time data, performing calculations, or interacting with other services.\n", + "7. Versatile Applications:\n", + " Your autonomous agent could potentially handle tasks like:\n", + " - Answering questions based on retrieved information from a knowledge base\n", + " - Executing SQL queries from natural language commands\n", + " - Performing web searches and integrating the results into responses\n", "\n", - "8. Tutorial Resources:\n", - " There are tutorials available that walk through the process of building AI assistants with LangChain and LangGraph. These can be excellent starting points for your project.\n", + "To get started with your project, you might want to:\n", "\n", - "To get started, you might want to:\n", - "1. Set up your development environment with LangChain and LangGraph.\n", - "2. Define the core functionalities you want your autonomous agent to have.\n", - "3. Design the overall structure of your agent, possibly as a multi-agent system.\n", - "4. Implement basic interactions and gradually add more complex features like tool calling and state management.\n", - "5. Test your agent thoroughly with various scenarios to ensure robust performance.\n", + "1. Familiarize yourself with the LangGraph documentation and basic concepts.\n", + "2. Follow one of the available tutorials to build a simple multi-tool agent.\n", + "3. Define the specific tasks and capabilities you want your autonomous agent to have.\n", + "4. Incrementally add and test new tools and functionalities to your agent.\n", + "5. Experiment with different language models to see which works best for your use case.\n", "\n", - "Remember, building an autonomous agent is an iterative process. Start with a basic version and progressively enhance its capabilities. This approach will help you understand the intricacies of LangGraph while creating a sophisticated AI application.\n", - "\n", - "Do you have any specific ideas about what kind of tasks or domain you want your autonomous agent to specialize in? This could help guide the design and implementation process.\n" + "Would you like more information on any specific aspect of building your autonomous agent with LangGraph, such as setting up the environment, choosing tools, or handling particular types of tasks?\n" ] } ], @@ -3378,8 +3325,8 @@ }, { "cell_type": "code", - "execution_count": 71, - "id": "6c0dbed5-210d-40ad-b002-0bc52ef28fac", + "execution_count": 5, + "id": "c3e5875d-5612-41cb-8109-9a45f0282783", "metadata": {}, "outputs": [ { @@ -3392,6 +3339,8 @@ "--------------------------------------------------------------------------------\n", "Num Messages: 6 Next: ('tools',)\n", "--------------------------------------------------------------------------------\n", + "Num Messages: 6 Next: ('human_review_node',)\n", + "--------------------------------------------------------------------------------\n", "Num Messages: 5 Next: ('chatbot',)\n", "--------------------------------------------------------------------------------\n", "Num Messages: 4 Next: ('__start__',)\n", @@ -3402,6 +3351,8 @@ "--------------------------------------------------------------------------------\n", "Num Messages: 2 Next: ('tools',)\n", "--------------------------------------------------------------------------------\n", + "Num Messages: 2 Next: ('human_review_node',)\n", + "--------------------------------------------------------------------------------\n", "Num Messages: 1 Next: ('chatbot',)\n", "--------------------------------------------------------------------------------\n", "Num Messages: 0 Next: ('__start__',)\n", @@ -3431,16 +3382,16 @@ }, { "cell_type": "code", - "execution_count": 72, - "id": "de8d5521-8d71-4093-a657-4920c790802f", + "execution_count": 6, + "id": "fdcf00af-8459-4132-85cc-742199391d4f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "('tools',)\n", - "{'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef7d094-2634-687c-8006-49ddde5b2f1c'}}\n" + "('human_review_node',)\n", + "{'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1efd3840-87a4-6760-8007-bd412fc24064'}}\n" ] } ], @@ -3459,8 +3410,8 @@ }, { "cell_type": "code", - "execution_count": 73, - "id": "85f17be3-eaf6-495e-a846-49436916b4ab", + "execution_count": 7, + "id": "c5382e81-bfcd-4508-b02a-099e3d9627fd", "metadata": {}, "outputs": [ { @@ -3469,59 +3420,49 @@ "text": [ "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"That's an excellent idea! Building an autonomous agent with LangGraph is a great way to explore its capabilities and learn about advanced AI application development. LangGraph's features make it well-suited for creating autonomous agents. Let me provide some additional insights and encouragement for your project.\", 'type': 'text'}, {'id': 'toolu_017t6BS5rNCzFWcpxRizDKjE', 'input': {'query': 'building autonomous agents with LangGraph examples and tutorials'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "[{'text': \"That's an exciting idea! Building an autonomous agent with LangGraph could be a great way to dive deep into the framework and explore its capabilities. LangGraph's focus on orchestrating complex agentic systems makes it well-suited for such a project. Let me gather some more specific information about using LangGraph for building autonomous agents.\", 'type': 'text'}, {'id': 'toolu_01TeAyyVo8fYBYApftT7yjTS', 'input': {'query': 'Building autonomous agents with LangGraph examples and tutorials'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " tavily_search_results_json (toolu_017t6BS5rNCzFWcpxRizDKjE)\n", - " Call ID: toolu_017t6BS5rNCzFWcpxRizDKjE\n", + " tavily_search_results_json (toolu_01TeAyyVo8fYBYApftT7yjTS)\n", + " Call ID: toolu_01TeAyyVo8fYBYApftT7yjTS\n", " Args:\n", - " query: building autonomous agents with LangGraph examples and tutorials\n", + " query: Building autonomous agents with LangGraph examples and tutorials\n", "=================================\u001b[1m Tool Message \u001b[0m=================================\n", "Name: tavily_search_results_json\n", "\n", - "[{\"url\": \"https://blog.langchain.dev/how-to-build-the-ultimate-ai-automation-with-multi-agent-collaboration/\", \"content\": \"Learn how to create an autonomous research assistant using LangGraph, an extension of LangChain for agent and multi-agent flows. Follow the steps to define the graph state, initialize the graph, and run the agents for planning, research, review, writing and publishing.\"}, {\"url\": \"https://medium.com/@lucas.dahan/hands-on-langgraph-building-a-multi-agent-assistant-06aa68ed942f\", \"content\": \"Building the Graph. With our agents defined, we'll create a graph.py file to orchestrate their interactions. The basic graph structure in LangGraph is really simple, here we are going to use ...\"}]\n", + "[{\"url\": \"https://towardsdatascience.com/building-autonomous-multi-tool-agents-with-gemini-2-0-and-langgraph-ad3d7bd5e79d\", \"content\": \"Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph | by Youness Mansar | Jan, 2025 | Towards Data Science Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph A practical tutorial with full code examples for building and running multi-tool agents Towards Data Science LLMs are remarkable — they can memorize vast amounts of information, answer general knowledge questions, write code, generate stories, and even fix your grammar. In this tutorial, we are going to build a simple LLM agent that is equipped with four tools that it can use to answer a user’s question. This Agent will have the following specifications: Follow Published in Towards Data Science --------------------------------- Your home for data science and AI. Follow Follow Follow\"}, {\"url\": \"https://github.com/anmolaman20/Tools_and_Agents\", \"content\": \"GitHub - anmolaman20/Tools_and_Agents: This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository serves as a comprehensive guide for building AI-powered agents using Langchain and Langgraph. It provides hands-on examples, practical tutorials, and resources for developers and AI enthusiasts to master building intelligent systems and workflows. AI Agent Development: Gain insights into creating intelligent systems that think, reason, and adapt in real time. This repository is ideal for AI practitioners, developers exploring language models, or anyone interested in building intelligent systems. This repository provides resources for building AI agents using Langchain and Langgraph.\"}]\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "Great choice! Building an autonomous agent with LangGraph is an excellent way to dive deep into its capabilities. Based on the additional information I've found, here are some insights and steps to help you get started:\n", + "Great idea! Building an autonomous agent with LangGraph can be an excellent way to learn the framework and explore its capabilities. Based on the information I've found, here are some insights and resources that could help you get started:\n", "\n", - "1. LangGraph for Autonomous Agents:\n", - " LangGraph is particularly well-suited for creating autonomous agents, especially those involving multi-agent collaboration. It allows you to create complex, stateful workflows that can simulate autonomous behavior.\n", + "1. Multi-Tool Agents:\n", + " LangGraph is well-suited for building autonomous agents that can use multiple tools. This allows your agent to have a variety of capabilities and choose the appropriate tool based on the task at hand.\n", "\n", - "2. Example Project: Autonomous Research Assistant\n", - " One popular example is building an autonomous research assistant. This type of project can help you understand the core concepts of LangGraph while creating something useful.\n", + "2. Integration with Other Technologies:\n", + " There's an example of building autonomous multi-tool agents using LangGraph in combination with Gemini 2.0 (Google's large language model). This suggests that LangGraph can be integrated with various LLMs and tools to create powerful agents.\n", "\n", - "3. Key Steps in Building an Autonomous Agent:\n", - " a. Define the Graph State: This involves setting up the structure that will hold the agent's state and context.\n", - " b. Initialize the Graph: Set up the initial conditions and parameters for your agent.\n", - " c. Create Multiple Agents: For a complex system, you might create several specialized agents, each with a specific role (e.g., planning, research, review, writing).\n", - " d. Orchestrate Interactions: Use LangGraph to manage how these agents interact and collaborate.\n", + "3. Practical Tutorials:\n", + " There are tutorials available that provide full code examples for building and running multi-tool agents. These can be extremely helpful as you start your project.\n", "\n", - "4. Components of an Autonomous Agent:\n", - " - Planning Agent: Determines the overall strategy and steps.\n", - " - Research Agent: Gathers necessary information.\n", - " - Review Agent: Evaluates and refines the work.\n", - " - Writing Agent: Produces the final output.\n", - " - Publishing Agent: Handles the final distribution or application of results.\n", + "4. GitHub Resources:\n", + " There's a GitHub repository (by user anmolaman20) that provides resources for building AI agents using both LangChain and LangGraph. This could be a valuable reference as you develop your agent.\n", "\n", - "5. Implementation Tips:\n", - " - Start with a simple graph structure in LangGraph.\n", - " - Define clear roles and responsibilities for each agent or component.\n", - " - Use LangGraph's features to manage state and context across the different stages of your agent's workflow.\n", + "5. Capabilities:\n", + " The agents you can build with LangGraph can potentially memorize information, answer questions, write code, generate stories, and perform various other tasks depending on how you design them and what tools you integrate.\n", "\n", - "6. Learning Resources:\n", - " - Look for tutorials and examples specifically on building multi-agent systems with LangGraph.\n", - " - The LangChain documentation and community forums can be valuable resources, as LangGraph builds upon LangChain.\n", + "6. Real-Time Adaptation:\n", + " LangGraph seems to support building agents that can think, reason, and adapt in real-time, which is crucial for truly autonomous behavior.\n", "\n", - "7. Potential Applications:\n", - " - Autonomous research assistants\n", - " - Complex task automation systems\n", - " - Interactive storytelling agents\n", - " - Autonomous problem-solving systems\n", + "To get started with your project, you might want to:\n", "\n", - "Building an autonomous agent with LangGraph is an exciting project that will give you hands-on experience with advanced concepts in AI application development. It's a great way to learn about state management, multi-agent coordination, and complex workflow design in AI systems.\n", + "1. Set up your development environment with LangGraph and any necessary dependencies.\n", + "2. Start with a simple agent that uses one or two tools, then gradually increase complexity.\n", + "3. Explore the GitHub resources and tutorials to understand best practices and common patterns in building autonomous agents with LangGraph.\n", + "4. Consider what specific tasks or domains you want your agent to specialize in, and research appropriate tools or APIs to integrate.\n", + "5. Experiment with different LLMs to find the one that best suits your agent's needs.\n", "\n", - "As you embark on this project, remember to start small and gradually increase complexity. You might begin with a simple autonomous agent that performs a specific task, then expand its capabilities and add more agents or components as you become more comfortable with LangGraph.\n", + "Remember to consider ethical implications and potential limitations as you develop your autonomous agent. It's important to build in safeguards and ensure your agent behaves responsibly.\n", "\n", - "Do you have a specific type of autonomous agent in mind, or would you like some suggestions for beginner-friendly autonomous agent projects to start with?\n" + "Would you like more information on any specific aspect of building your autonomous agent with LangGraph, such as setting up the environment, choosing tools, or designing the agent's decision-making process?\n" ] } ], From 30311f3fb91ca86e0d01ac0861cc76f5758289f2 Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Wed, 15 Jan 2025 16:12:01 -0500 Subject: [PATCH 03/15] ruff --- docs/docs/tutorials/introduction.ipynb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/docs/tutorials/introduction.ipynb b/docs/docs/tutorials/introduction.ipynb index 8658d90f7..f20a29a9b 100644 --- a/docs/docs/tutorials/introduction.ipynb +++ b/docs/docs/tutorials/introduction.ipynb @@ -1195,6 +1195,7 @@ "from langgraph.graph import StateGraph, START, END\n", "from langgraph.graph.message import add_messages\n", "from langgraph.prebuilt import ToolNode\n", + "\n", "# highlight-next-line\n", "from langgraph.types import Command, interrupt\n", "\n", @@ -1690,7 +1691,7 @@ "source": [ "human_command = Command(resume={\"action\": \"continue\"})\n", "\n", - "events = graph.stream(human_command, config,stream_mode=\"values\")\n", + "events = graph.stream(human_command, config, stream_mode=\"values\")\n", "for event in events:\n", " if \"messages\" in event:\n", " event[\"messages\"][-1].pretty_print()" @@ -2572,7 +2573,7 @@ "def human_review_node(state: State) -> Command[Literal[\"chatbot\", \"tools\"]]:\n", " last_message = state[\"messages\"][-1]\n", " tool_call = last_message.tool_calls[-1]\n", - " \n", + "\n", " # highlight-next-line\n", " if not tool_call[\"name\"] == RequestAssistance.__name__:\n", " return Command(goto=\"tools\")\n", From 605fe4ea116fd380dddaec49e9372507514ee2ee Mon Sep 17 00:00:00 2001 From: Chester Curme Date: Thu, 16 Jan 2025 14:20:05 -0500 Subject: [PATCH 04/15] simplify hitl, condense part 5 --- docs/docs/tutorials/introduction.ipynb | 1969 ++++++------------------ 1 file changed, 436 insertions(+), 1533 deletions(-) diff --git a/docs/docs/tutorials/introduction.ipynb b/docs/docs/tutorials/introduction.ipynb index f20a29a9b..6f248e5da 100644 --- a/docs/docs/tutorials/introduction.ipynb +++ b/docs/docs/tutorials/introduction.ipynb @@ -466,6 +466,7 @@ "\n", "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n", "# Modification: tell the LLM which tools it can call\n", + "# highlight-next-line\n", "llm_with_tools = llm.bind_tools(tools)\n", "\n", "\n", @@ -864,7 +865,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 23, "id": "a06548bf-81fa-4436-b4c1-f68601fb4187", "metadata": {}, "outputs": [], @@ -1173,34 +1174,31 @@ "\n", "LangGraph's [persistence](../../concepts/persistence) layer supports human-in-the-loop workflows, allowing execution to pause and resume based on user feedback. The primary interface to this functionality is the [interrupt](../../concepts/human_in_the_loop/#interrupt) function. Calling `interrupt` inside a node will pause execution. Execution can be resumed, together with new input from a human, by passing in a [Command](../../concepts/human_in_the_loop/#the-command-primitive). `interrupt` is ergonomically similar to Python's built-in `input()`, [with some caveats](../../concepts/human_in_the_loop/#interrupt). We demonstrate an example below.\n", "\n", - "First, start with our existing code from Part 3. We make two changes, highlighted below:\n", - "1. We add a `human_review_node` to handle the interaction with a human reviewer;\n", - "2. We use a different condition in our conditional edge that routes to the `human_review_node`, instead of directly to tools." + "First, start with our existing code from Part 3. We will make one change, which is to add a simple `human_assistance` tool accessible to the chatbot. This tool uses `interrupt` to receive information from a human." ] }, { "cell_type": "code", "execution_count": null, - "id": "5a81608a-373a-4339-b1c6-65b73a92b983", + "id": "08439bb4-91e8-4abb-a57a-2511877abcb7", "metadata": {}, "outputs": [], "source": [ - "from typing import Annotated, Literal\n", + "from typing import Annotated\n", "\n", "from langchain_anthropic import ChatAnthropic\n", "from langchain_community.tools.tavily_search import TavilySearchResults\n", + "from langchain_core.tools import tool\n", "from typing_extensions import TypedDict\n", "\n", "from langgraph.checkpoint.memory import MemorySaver\n", "from langgraph.graph import StateGraph, START, END\n", "from langgraph.graph.message import add_messages\n", - "from langgraph.prebuilt import ToolNode\n", + "from langgraph.prebuilt import ToolNode, tools_condition\n", "\n", "# highlight-next-line\n", "from langgraph.types import Command, interrupt\n", "\n", - "memory = MemorySaver()\n", - "\n", "\n", "class State(TypedDict):\n", " messages: Annotated[list, add_messages]\n", @@ -1209,8 +1207,20 @@ "graph_builder = StateGraph(State)\n", "\n", "\n", + "# highlight-next-line\n", + "@tool\n", + "# highlight-next-line\n", + "def human_assistance(query: str) -> str:\n", + " # highlight-next-line\n", + " \"\"\"Request assistance from a human.\"\"\"\n", + " # highlight-next-line\n", + " human_response = interrupt({\"query\": query})\n", + " # highlight-next-line\n", + " return human_response[\"data\"]\n", + "\n", + "\n", "tool = TavilySearchResults(max_results=2)\n", - "tools = [tool]\n", + "tools = [tool, human_assistance]\n", "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n", "llm_with_tools = llm.bind_tools(tools)\n", "\n", @@ -1219,61 +1229,14 @@ " return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n", "\n", "\n", - "# We add a node to handle the interaction with a human reviewer\n", - "def human_review_node(state: State) -> Command[Literal[\"chatbot\", \"tools\"]]:\n", - " last_message = state[\"messages\"][-1]\n", - " tool_call = last_message.tool_calls[-1]\n", + "graph_builder.add_node(\"chatbot\", chatbot)\n", "\n", - " # this is the value we'll be providing via Command(resume=)\n", - " human_review = interrupt(\n", - " {\n", - " \"question\": \"Is this correct?\",\n", - " # Surface tool calls for review\n", - " \"tool_call\": tool_call,\n", - " }\n", - " )\n", - "\n", - " review_action = human_review[\"action\"]\n", - " review_data = human_review.get(\"data\")\n", - "\n", - " # if approved, call the tool\n", - " if review_action == \"continue\":\n", - " return Command(goto=\"tools\")\n", - "\n", - " elif review_action == \"feedback\":\n", - " # NOTE: we're adding feedback message as a ToolMessage\n", - " # to preserve the correct order in the message history\n", - " # (AI messages with tool calls need to be followed by tool call messages)\n", - " tool_message = {\n", - " \"role\": \"tool\",\n", - " # This is our natural language feedback\n", - " \"content\": review_data,\n", - " \"name\": tool_call[\"name\"],\n", - " \"tool_call_id\": tool_call[\"id\"],\n", - " }\n", - " return Command(goto=\"chatbot\", update={\"messages\": [tool_message]})\n", - "\n", - "\n", - "# Where we used tools_condition before, here we update the condition\n", - "# to route to the human review node first, instead of tools.\n", - "def route_after_llm(state) -> Literal[END, \"human_review_node\"]:\n", - " if len(state[\"messages\"][-1].tool_calls) == 0:\n", - " return END\n", - " else:\n", - " return \"human_review_node\"\n", - "\n", - "\n", - "graph_builder.add_node(chatbot)\n", - "\n", - "tool_node = ToolNode(tools=[tool])\n", + "tool_node = ToolNode(tools=tools)\n", "graph_builder.add_node(\"tools\", tool_node)\n", - "# highlight-next-line\n", - "graph_builder.add_node(human_review_node)\n", "\n", "graph_builder.add_conditional_edges(\n", " \"chatbot\",\n", - " # highlight-next-line\n", - " route_after_llm,\n", + " tools_condition,\n", ")\n", "graph_builder.add_edge(\"tools\", \"chatbot\")\n", "graph_builder.add_edge(START, \"chatbot\")" @@ -1281,14 +1244,14 @@ }, { "cell_type": "markdown", - "id": "813505b2-18c1-46e9-b891-20a34232808b", + "id": "cada4cd2-0316-487b-923e-0d12fa3473c2", "metadata": {}, "source": [ "------\n", "\n", "!!! tip\n", "\n", - " Check out [this guide](../../how-tos/human_in_the_loop/review-tool-calls/) for more detail on human review of tool calls, including how to edit tool calls directly.\n", + " Check out the [Human-in-the-loop section](../../how-tos/#human-in-the-loop) of the How-to Guides for more examples of Human-in-the-loop workflows, including how to [review and edit tool calls](../../how-tos/human_in_the_loop/review-tool-calls/) before they are executed.\n", "\n", "---------\n", "\n", @@ -1297,11 +1260,13 @@ }, { "cell_type": "code", - "execution_count": 5, - "id": "b0883e32-1a39-4ce9-ae32-bbd66708fd84", + "execution_count": 3, + "id": "16cc6b14-f758-4590-beb7-7b76a6841521", "metadata": {}, "outputs": [], "source": [ + "memory = MemorySaver()\n", + "\n", "graph = graph_builder.compile(checkpointer=memory)" ] }, @@ -1310,18 +1275,18 @@ "id": "bc0e84db-925c-4468-b3e0-639e6b25ac3c", "metadata": {}, "source": [ - "Visualizing the graph, we can see that we've added a new node to mediate the interaction between the chatbot and the tools:" + "Visualizing the graph, we recover the same layout as before. We have just added a tool!" ] }, { "cell_type": "code", - "execution_count": 34, - "id": "8b8e61b5-f3c2-4917-a8fc-928ccbcfc6ab", + "execution_count": 4, + "id": "22ff19af-5a5b-4ca5-82d8-6a38445c24af", "metadata": {}, "outputs": [ { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "" ] @@ -1340,9 +1305,17 @@ " pass" ] }, + { + "cell_type": "markdown", + "id": "ae4663b8-176d-445d-bd07-56938c044f98", + "metadata": {}, + "source": [ + "Let's now prompt the chatbot with a question that will engage the new `human_assistance` tool:" + ] + }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "id": "9f318020-ab7e-415b-a5e2-eddec6d9f3a6", "metadata": {}, "outputs": [ @@ -1352,22 +1325,22 @@ "text": [ "================================\u001b[1m Human Message \u001b[0m=================================\n", "\n", - "I'm learning LangGraph. Could you do some research on it for me?\n", + "I need some expert guidance for building an AI agent. Could you request assistance for me?\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01UukDzyzhEhxMgTbshetpT4', 'input': {'query': 'LangGraph programming framework'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_015tcCygn4UdBM24vg9NSycp', 'input': {'query': 'A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " tavily_search_results_json (toolu_01UukDzyzhEhxMgTbshetpT4)\n", - " Call ID: toolu_01UukDzyzhEhxMgTbshetpT4\n", + " human_assistance (toolu_015tcCygn4UdBM24vg9NSycp)\n", + " Call ID: toolu_015tcCygn4UdBM24vg9NSycp\n", " Args:\n", - " query: LangGraph programming framework\n" + " query: A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?\n" ] } ], "source": [ - "user_input = \"I'm learning LangGraph. Could you do some research on it for me?\"\n", + "user_input = \"I need some expert guidance for building an AI agent. Could you request assistance for me?\"\n", "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", - "# The config is the **second positional argument** to stream() or invoke()!\n", + "\n", "events = graph.stream(\n", " {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n", ")\n", @@ -1381,22 +1354,22 @@ "id": "39405637-13b1-40b1-a51e-6d60bf675ff1", "metadata": {}, "source": [ - "Let's inspect the graph state to confirm it worked." + "The chatbot generated a tool call, but then execution has been interrupted! Note that if we inspect the graph state, we see that it stopped at the tools node:" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "id": "9f511371-98b6-4513-b450-9143778f12dc", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "('human_review_node',)" + "('tools',)" ] }, - "execution_count": 7, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -1408,51 +1381,28 @@ }, { "cell_type": "markdown", - "id": "89326046-2b11-4812-8b6d-8780306ec275", + "id": "4574b267-b0d8-4056-aeea-6e8817e8844e", "metadata": {}, "source": [ - "**Notice** that unlike last time, the \"next\" node is set to `human_review_node`. We've interrupted here! Let's check the tool invocation." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "3facda0a-e6ad-4b28-b627-753ad8c90c15", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'name': 'tavily_search_results_json',\n", - " 'args': {'query': 'LangGraph programming framework'},\n", - " 'id': 'toolu_01UukDzyzhEhxMgTbshetpT4',\n", - " 'type': 'tool_call'}]" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "existing_message = snapshot.values[\"messages\"][-1]\n", - "existing_message.tool_calls" - ] - }, - { - "cell_type": "markdown", - "id": "a55a4c70-7226-4be0-8562-391f72bc1f2b", - "metadata": {}, - "source": [ - "This query seems reasonable. Nothing to filter here. The simplest thing the human can do is just let the graph continue executing. Let's do that below.\n", + "Let's take a closer look at the `human_assistance` tool:\n", "\n", - "To resume execution, we pass a [Command](../../concepts/human_in_the_loop/#the-command-primitive) object. Here, we specify `resume` with a dict containing the information expected by `human_review_node`. This information can be customized based on our needs." + "```python\n", + "@tool\n", + "def human_assistance(query: str) -> str:\n", + " \"\"\"Request assistance from a human.\"\"\"\n", + " human_response = interrupt({\"query\": query})\n", + " return human_response[\"data\"]\n", + "```\n", + "\n", + "Similar to Python's built-in `input()` function, calling `interrupt` inside the tool will pause execution. Progress is persisted based on our choice of [checkpointer](../../concepts/persistence/#checkpointer-libraries)-- so if we are persisting with Postgres, we can resume at any time as long as the database is alive. Here we are persisting with the in-memory checkpointer, so we can resume any time as long as our Python kernel is running.\n", + "\n", + "To resume execution, we pass a [Command](../../concepts/human_in_the_loop/#the-command-primitive) object containing data expected by the tool. The format of this data can be customized based on our needs. Here, we just need a dict with a key `\"data\"`:" ] }, { "cell_type": "code", - "execution_count": 9, - "id": "831d4978-b5ea-4258-b350-8e7dd2bf2b6c", + "execution_count": 7, + "id": "df6d81bb-e674-44ef-a46e-17b1a8d2381a", "metadata": {}, "outputs": [ { @@ -1461,235 +1411,42 @@ "text": [ "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01UukDzyzhEhxMgTbshetpT4', 'input': {'query': 'LangGraph programming framework'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_015tcCygn4UdBM24vg9NSycp', 'input': {'query': 'A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " tavily_search_results_json (toolu_01UukDzyzhEhxMgTbshetpT4)\n", - " Call ID: toolu_01UukDzyzhEhxMgTbshetpT4\n", + " human_assistance (toolu_015tcCygn4UdBM24vg9NSycp)\n", + " Call ID: toolu_015tcCygn4UdBM24vg9NSycp\n", " Args:\n", - " query: LangGraph programming framework\n", + " query: A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?\n", "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: tavily_search_results_json\n", + "Name: human_assistance\n", "\n", - "[{\"url\": \"https://www.langchain.com/langgraph\", \"content\": \"No. LangGraph is an orchestration framework for complex agentic systems and is more low-level and controllable than LangChain agents. LangChain provides a standard interface to interact with models and other components, useful for straight-forward chains and retrieval flows.\"}, {\"url\": \"https://academy.langchain.com/courses/intro-to-langgraph\", \"content\": \"Separate from the LangChain package, LangGraph helps developers add better precision and control into agentic workflows. Lesson 1: Motivation Lesson 2: Simple Graph Lesson 3: LangGraph Studio Lesson 4: Chain Lesson 5: Router Lesson 6: Agent Lesson 7: Agent with Memory Lesson 8: Deployment Lesson 1: State Schema Lesson 2: State Reducers Lesson 3: Multiple Schemas Lesson 1: Streaming Lesson 2: Breakpoints Lesson 3: Editing State and Human Feedback Lesson 4: Dynamic Breakpoints Lesson 1: Parallelization Lesson 2: Sub-graphs Lesson 3: Map-reduce Lesson 4: Research Assistant About this course No. LangGraph is an orchestration framework for complex agentic systems and is more low-level and controllable than LangChain agents. Deploy LangGraph agents at scale with LangGraph Cloud (available for Python).\"}]\n", + "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "Thank you for your patience. I've researched LangGraph for you, and I'm happy to share what I've found. LangGraph is an interesting framework in the field of language AI. Here's a summary of the key points:\n", + "Thank you for your patience. I've received a response from the expert assistance. Here's the advice they provided:\n", "\n", - "1. Purpose:\n", - " LangGraph is an orchestration framework designed for complex agentic systems. It provides more low-level control and precision compared to LangChain agents.\n", + "The experts recommend that you check out LangGraph for building your AI agent. They suggest that LangGraph is a more reliable and extensible option compared to simple autonomous agents.\n", "\n", - "2. Relationship to LangChain:\n", - " - LangGraph is separate from the LangChain package but complements it.\n", - " - While LangChain provides a standard interface for interacting with models and components (useful for straightforward chains and retrieval flows), LangGraph offers more fine-grained control for complex workflows.\n", + "LangGraph is likely a framework or library designed specifically for creating AI agents. It seems to offer advantages in terms of reliability and extensibility, which are crucial factors when developing complex AI systems.\n", "\n", - "3. Key Features:\n", - " - Better precision and control in agentic workflows\n", - " - Allows for the creation of more complex and controllable AI systems\n", + "To follow up on this recommendation, you might want to:\n", "\n", - "4. Learning Resources:\n", - " There's a course available on the LangChain Academy that covers LangGraph in depth. The course structure includes:\n", + "1. Research LangGraph: Look for its official documentation, tutorials, and any community resources.\n", + "2. Compare LangGraph with other agent-building frameworks to understand its unique benefits.\n", + "3. Check if LangGraph aligns with your specific goals and requirements for your AI agent project.\n", + "4. Look for examples or case studies of AI agents built with LangGraph to get a better idea of its capabilities.\n", "\n", - " - Motivation\n", - " - Simple Graph\n", - " - LangGraph Studio\n", - " - Chain\n", - " - Router\n", - " - Agent\n", - " - Agent with Memory\n", - " - Deployment\n", - " - State Schema\n", - " - State Reducers\n", - " - Multiple Schemas\n", - " - Streaming\n", - " - Breakpoints\n", - " - Editing State and Human Feedback\n", - " - Dynamic Breakpoints\n", - " - Parallelization\n", - " - Sub-graphs\n", - " - Map-reduce\n", - " - Research Assistant\n", - "\n", - "5. Deployment:\n", - " LangGraph agents can be deployed at scale using LangGraph Cloud (available for Python).\n", - "\n", - "LangGraph seems to be particularly useful when you need more control over your AI workflows, especially for complex, multi-step processes or when building sophisticated AI agents. If you're already familiar with LangChain, learning LangGraph could be a valuable next step to enhance your ability to create more advanced AI systems.\n", - "\n", - "Is there any specific aspect of LangGraph you'd like to know more about? Or do you have any questions about how it compares to other frameworks you might be familiar with?\n" + "Would you like me to search for more specific information about LangGraph or any other aspect of building AI agents?\n" ] } ], "source": [ - "human_command = Command(resume={\"action\": \"continue\"})\n", - "\n", - "events = graph.stream(human_command, config, stream_mode=\"values\")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "d789d4cf-b498-454b-a088-3ffc03e511b0", - "metadata": {}, - "source": [ - "Review this call's [LangSmith trace](https://smith.langchain.com/public/83aaec86-9dd8-406b-ab03-e66d2464b8ef/r) to see the exact work that was done in the above call. Notice that the state is loaded in the first step so that your chatbot can continue where it left off.\n", - "\n", - "Let's demonstrate another example, in which we direct the chatbot to revise its tool calls based on our feedback." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "0ebad510-01f8-4b00-8e80-1b435b0f37fa", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "Could you search the weather in San Francisco?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Certainly! I'd be happy to search for the current weather in San Francisco for you. To get the most up-to-date and accurate information, I'll use the Tavily search engine. Let me do that for you right away.\", 'type': 'text'}, {'id': 'toolu_019rPs39MK72QMVFcnxEyFN4', 'input': {'query': 'current weather in San Francisco'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " tavily_search_results_json (toolu_019rPs39MK72QMVFcnxEyFN4)\n", - " Call ID: toolu_019rPs39MK72QMVFcnxEyFN4\n", - " Args:\n", - " query: current weather in San Francisco\n" - ] - } - ], - "source": [ - "user_input = \"Could you search the weather in San Francisco?\"\n", - "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", - "\n", - "events = graph.stream(\n", - " {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n", - ")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "ce1e485c-0ddc-4c36-a1c1-b78f6c706fa1", - "metadata": {}, - "source": [ - "This time, we will indicate that the requested action is `\"feedback\"`, and provide feedback in natural language. The chatbot will respond by generating a second, updated tool call:" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "b5bbaf35-d1f2-46b3-8451-856e908fd11f", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Certainly! I'd be happy to search for the current weather in San Francisco for you. To get the most up-to-date and accurate information, I'll use the Tavily search engine. Let me do that for you right away.\", 'type': 'text'}, {'id': 'toolu_019rPs39MK72QMVFcnxEyFN4', 'input': {'query': 'current weather in San Francisco'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " tavily_search_results_json (toolu_019rPs39MK72QMVFcnxEyFN4)\n", - " Call ID: toolu_019rPs39MK72QMVFcnxEyFN4\n", - " Args:\n", - " query: current weather in San Francisco\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: tavily_search_results_json\n", - "\n", - "User requested changes: use format for location.\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': 'I apologize for the error in my previous attempt. Thank you for the clarification on the format. Let me search again using the correct format.', 'type': 'text'}, {'id': 'toolu_01AfrULohtNjWqGf8oY1FP9v', 'input': {'query': 'current weather in San Francisco, USA'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " tavily_search_results_json (toolu_01AfrULohtNjWqGf8oY1FP9v)\n", - " Call ID: toolu_01AfrULohtNjWqGf8oY1FP9v\n", - " Args:\n", - " query: current weather in San Francisco, USA\n" - ] - } - ], - "source": [ - "human_command = Command(\n", - " resume={\n", - " \"action\": \"feedback\",\n", - " \"data\": \"User requested changes: use format for location.\",\n", - " }\n", + "human_response = (\n", + " \"We, the experts are here to help! We'd recommend you check out LangGraph to build your agent.\"\n", + " \" It's much more reliable and extensible than simple autonomous agents.\"\n", ")\n", "\n", - "events = graph.stream(human_command, config, stream_mode=\"values\")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "b56541f9-a5d2-49e0-9389-8d6e116c58b3", - "metadata": {}, - "source": [ - "We can now continue, as before:" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "24ec8471-4438-4c89-aafa-48bb6c72eca8", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': 'I apologize for the error in my previous attempt. Thank you for the clarification on the format. Let me search again using the correct format.', 'type': 'text'}, {'id': 'toolu_01AfrULohtNjWqGf8oY1FP9v', 'input': {'query': 'current weather in San Francisco, USA'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " tavily_search_results_json (toolu_01AfrULohtNjWqGf8oY1FP9v)\n", - " Call ID: toolu_01AfrULohtNjWqGf8oY1FP9v\n", - " Args:\n", - " query: current weather in San Francisco, USA\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: tavily_search_results_json\n", - "\n", - "[{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.775, 'lon': -122.4183, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1736966001, 'localtime': '2025-01-15 10:33'}, 'current': {'last_updated_epoch': 1736965800, 'last_updated': '2025-01-15 10:30', 'temp_c': 10.6, 'temp_f': 51.1, 'is_day': 1, 'condition': {'text': 'Sunny', 'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png', 'code': 1000}, 'wind_mph': 6.3, 'wind_kph': 10.1, 'wind_degree': 51, 'wind_dir': 'NE', 'pressure_mb': 1026.0, 'pressure_in': 30.3, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 46, 'cloud': 0, 'feelslike_c': 9.3, 'feelslike_f': 48.8, 'windchill_c': 6.6, 'windchill_f': 43.9, 'heatindex_c': 8.6, 'heatindex_f': 47.5, 'dewpoint_c': 4.6, 'dewpoint_f': 40.2, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 1.3, 'gust_mph': 9.4, 'gust_kph': 15.1}}\"}, {\"url\": \"https://www.meteoprog.com/weather/Sanfrancisco/month/january/\", \"content\": \"San Francisco (United States) weather in January 2025 ☀️ Accurate weather forecast for San Francisco in January ⛅ Detailed forecast By month Current temperature \\\"near me\\\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG. ... 15 January +14 °+7° 16 January +14\"}]\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Thank you for your patience. I've successfully searched for the current weather in San Francisco, USA. Based on the search results, I can provide you with the following information about the weather in San Francisco:\n", - "\n", - "1. Current Temperature:\n", - " - 10.6°C (51.1°F)\n", - " - Feels like: 9.3°C (48.8°F)\n", - "\n", - "2. Weather Condition: Sunny\n", - "\n", - "3. Wind:\n", - " - Speed: 10.1 km/h (6.3 mph)\n", - " - Direction: Northeast (NE)\n", - "\n", - "4. Humidity: 46%\n", - "\n", - "5. Precipitation: 0 mm (0 inches)\n", - "\n", - "6. Visibility: 16 km (9 miles)\n", - "\n", - "7. Pressure: 1026.0 mb (30.3 inches)\n", - "\n", - "8. UV Index: 1.3 (relatively low)\n", - "\n", - "The data shows that it's a pleasant, sunny day in San Francisco with comfortable temperatures. The weather is clear with no cloud cover, and there's a light breeze from the northeast. The humidity is moderate, and there's no precipitation expected.\n", - "\n", - "Is there any specific aspect of the weather you'd like more information about?\n" - ] - } - ], - "source": [ - "human_command = Command(resume={\"action\": \"continue\"})\n", + "human_command = Command(resume={\"data\": human_response})\n", "\n", "events = graph.stream(human_command, config, stream_mode=\"values\")\n", "for event in events:\n", @@ -1702,33 +1459,31 @@ "id": "21e78a97-474f-4709-b51d-9d5e8323e14c", "metadata": {}, "source": [ - "In the [LangSmith trace](https://smith.langchain.com/public/1e4bf84c-3e9e-41fd-a924-21395f5cd09e/r) for the above run, we can see full sequence of alternating assistant and tool messages representing the interaction with a human reviewer.\n", + "Our input has been received and processed as a tool message. Review this call's [LangSmith trace](https://smith.langchain.com/public/9f0f87e3-56a7-4dde-9c76-b71675624e91/r) to see the exact work that was done in the above call. Notice that the state is loaded in the first step so that our chatbot can continue where it left off.\n", "\n", - "**Congrats!** You've used an `interrupt` to add human-in-the-loop execution to your chatbot, allowing for human oversight and intervention when needed. This opens up the potential UIs you can create with your AI systems. Since we have already added a **checkpointer**, the graph can be paused **indefinitely** and resumed at any time as if nothing had happened.\n", + "**Congrats!** You've used an `interrupt` to add human-in-the-loop execution to your chatbot, allowing for human oversight and intervention when needed. This opens up the potential UIs you can create with your AI systems. Since we have already added a **checkpointer**, as long as the underlying persistence layer is running, the graph can be paused **indefinitely** and resumed at any time as if nothing had happened.\n", "\n", - "Next, we'll explore how to further customize the bot's behavior using custom state updates.\n", + "Human-in-the-loop workflows enable a variety of new workflows and user experiences. Check out [this section](../../how-tos/#human-in-the-loop) of the How-to Guides for more examples of Human-in-the-loop workflows, including how to [review and edit tool calls](../../how-tos/human_in_the_loop/review-tool-calls/) before they are executed.\n", "\n", - "Below is a copy of the code you used in this section. The only difference between this and the previous parts is the addition of the `interrupt_before` argument.\n", "\n", "
\n", "Full Code\n", "
\n",
     "\n",
     "```python\n",
-    "from typing import Annotated, Literal\n",
+    "from typing import Annotated\n",
     "\n",
     "from langchain_anthropic import ChatAnthropic\n",
     "from langchain_community.tools.tavily_search import TavilySearchResults\n",
+    "from langchain_core.tools import tool\n",
     "from typing_extensions import TypedDict\n",
     "\n",
     "from langgraph.checkpoint.memory import MemorySaver\n",
     "from langgraph.graph import StateGraph, START, END\n",
     "from langgraph.graph.message import add_messages\n",
-    "from langgraph.prebuilt import ToolNode\n",
+    "from langgraph.prebuilt import ToolNode, tools_condition\n",
     "from langgraph.types import Command, interrupt\n",
     "\n",
-    "memory = MemorySaver()\n",
-    "\n",
     "\n",
     "class State(TypedDict):\n",
     "    messages: Annotated[list, add_messages]\n",
@@ -1737,8 +1492,15 @@
     "graph_builder = StateGraph(State)\n",
     "\n",
     "\n",
+    "@tool\n",
+    "def human_assistance(query: str) -> str:\n",
+    "    \"\"\"Request assistance from a human.\"\"\"\n",
+    "    human_response = interrupt({\"query\": query})\n",
+    "    return human_response[\"data\"]\n",
+    "\n",
+    "\n",
     "tool = TavilySearchResults(max_results=2)\n",
-    "tools = [tool]\n",
+    "tools = [tool, human_assistance]\n",
     "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
     "llm_with_tools = llm.bind_tools(tools)\n",
     "\n",
@@ -1747,62 +1509,20 @@
     "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
     "\n",
     "\n",
-    "# We add a node to handle the interaction with a human reviewer\n",
-    "def human_review_node(state: State) -> Command[Literal[\"chatbot\", \"tools\"]]:\n",
-    "    last_message = state[\"messages\"][-1]\n",
-    "    tool_call = last_message.tool_calls[-1]\n",
+    "graph_builder.add_node(\"chatbot\", chatbot)\n",
     "\n",
-    "    # this is the value we'll be providing via Command(resume=)\n",
-    "    human_review = interrupt(\n",
-    "        {\n",
-    "            \"question\": \"Is this correct?\",\n",
-    "            # Surface tool calls for review\n",
-    "            \"tool_call\": tool_call,\n",
-    "        }\n",
-    "    )\n",
-    "\n",
-    "    review_action = human_review[\"action\"]\n",
-    "    review_data = human_review.get(\"data\")\n",
-    "\n",
-    "    # if approved, call the tool\n",
-    "    if review_action == \"continue\":\n",
-    "        return Command(goto=\"tools\")\n",
-    "\n",
-    "    elif review_action == \"feedback\":\n",
-    "        # NOTE: we're adding feedback message as a ToolMessage\n",
-    "        # to preserve the correct order in the message history\n",
-    "        # (AI messages with tool calls need to be followed by tool call messages)\n",
-    "        tool_message = {\n",
-    "            \"role\": \"tool\",\n",
-    "            # This is our natural language feedback\n",
-    "            \"content\": review_data,\n",
-    "            \"name\": tool_call[\"name\"],\n",
-    "            \"tool_call_id\": tool_call[\"id\"],\n",
-    "        }\n",
-    "        return Command(goto=\"chatbot\", update={\"messages\": [tool_message]})\n",
-    "\n",
-    "\n",
-    "# Where we used tools_condition before, here we update the condition\n",
-    "# to route to the human review node first, instead of tools.\n",
-    "def route_after_llm(state) -> Literal[END, \"human_review_node\"]:\n",
-    "    if len(state[\"messages\"][-1].tool_calls) == 0:\n",
-    "        return END\n",
-    "    else:\n",
-    "        return \"human_review_node\"\n",
-    "\n",
-    "\n",
-    "graph_builder.add_node(chatbot)\n",
-    "\n",
-    "tool_node = ToolNode(tools=[tool])\n",
+    "tool_node = ToolNode(tools=tools)\n",
     "graph_builder.add_node(\"tools\", tool_node)\n",
-    "graph_builder.add_node(human_review_node)\n",
     "\n",
     "graph_builder.add_conditional_edges(\n",
     "    \"chatbot\",\n",
-    "    route_after_llm,\n",
+    "    tools_condition,\n",
     ")\n",
     "graph_builder.add_edge(\"tools\", \"chatbot\")\n",
     "graph_builder.add_edge(START, \"chatbot\")\n",
+    "\n",
+    "memory = MemorySaver()\n",
+    "graph = graph_builder.compile(checkpointer=memory)\n",
     "```\n",
     "
\n", "
" @@ -1810,49 +1530,121 @@ }, { "cell_type": "markdown", - "id": "6df38bc4-c177-4ccd-9ec2-83d32bf66722", + "id": "0d12578b-ff19-48b5-b1ad-67d9bf7f710e", "metadata": {}, "source": [ - "## Part 5: Manually Updating the State\n", + "## Part 5: Customizing State\n", "\n", - "In the previous section, we showed how to interrupt a graph so that a human could inspect its actions. This lets the human `read` the state, but if they want to change their agent's course, they'll need to have `write` access.\n", - "\n", - "Thankfully, LangGraph lets you **manually update state**! Updating the state lets you control the agent's trajectory by modifying its actions (even modifying the past!). This capability is particularly useful when you want to correct the agent's mistakes, explore alternative paths, or guide the agent towards a specific goal.\n", - "\n", - "We'll show how to update a checkpointed state below. As before, first, define your graph. We'll reuse the exact same graph as before." + "So far, we've relied on a simple state with one entry-- a list of messages. You can go far with this simple state, but if you want to define complex behavior without relying on the message list, you can add additional fields to the state. Here we will demonstrate a new scenario, in which the chatbot is using its search tool to find specific information, and forwarding them to a human for review. Let's have the chatbot research the birthday of an entity. We will add `name` and `birthday` keys to the state:" ] }, { "cell_type": "code", - "execution_count": null, - "id": "cab7f9c2-fc23-4b68-b84a-a7760b5403c9", + "execution_count": 2, + "id": "84627103-bcc8-4645-bd37-b93209fa09dd", "metadata": {}, "outputs": [], "source": [ - "from typing import Annotated, Literal\n", + "from typing import Annotated\n", "\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langchain_community.tools.tavily_search import TavilySearchResults\n", "from typing_extensions import TypedDict\n", "\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.graph import StateGraph, START, END\n", "from langgraph.graph.message import add_messages\n", - "from langgraph.prebuilt import ToolNode\n", - "from langgraph.types import Command, interrupt\n", - "\n", - "memory = MemorySaver()\n", "\n", "\n", "class State(TypedDict):\n", " messages: Annotated[list, add_messages]\n", + " # highlight-next-line\n", + " name: str\n", + " # highlight-next-line\n", + " birthday: str" + ] + }, + { + "cell_type": "markdown", + "id": "c0057133-3dfd-4208-a11f-9cf7c0b82587", + "metadata": {}, + "source": [ + "Adding this information to the state makes it easily accessible by other graph nodes (e.g., a downstream node that stores or processes the information), as well as the graph's persistence layer.\n", + "\n", + "Here, we will populate the state keys inside of our `human_assistance` tool. This allows a human to review the information before it is stored in the state. We will again use `Command`, this time to issue a state update from inside our tool. Read more about use cases for `Command` [here](../../concepts/low_level/#using-inside-tools)." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "c4b65504-92c7-4c82-a6ee-824885d1a8a4", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_core.messages import ToolMessage\n", + "from langchain_core.tools import InjectedToolCallId, tool\n", + "\n", + "from langgraph.types import Command, interrupt\n", "\n", "\n", - "graph_builder = StateGraph(State)\n", + "@tool\n", + "# Note that because we are generating a ToolMessage for a state update, we\n", + "# generally require the ID of the corresponding tool call. We can use\n", + "# LangChain's InjectedToolCallId to signal that this argument should not\n", + "# be revealed to the model in the tool's schema.\n", + "def human_assistance(\n", + " name: str, birthday: str, tool_call_id: Annotated[str, InjectedToolCallId]\n", + ") -> str:\n", + " \"\"\"Request assistance from a human.\"\"\"\n", + " human_response = interrupt(\n", + " {\n", + " \"question\": \"Is this correct?\",\n", + " \"name\": name,\n", + " \"birthday\": birthday,\n", + " },\n", + " )\n", + " # If the information is correct, update the state as-is.\n", + " if human_response.get(\"correct\", \"\").lower().startswith(\"y\"):\n", + " verified_name = name\n", + " verified_birthday = birthday\n", + " response = \"Correct\"\n", + " # Otherwise, receive information from the human reviewer.\n", + " else:\n", + " verified_name = human_response.get(\"name\", name)\n", + " verified_birthday = human_response.get(\"birthday\", birthday)\n", + " response = f\"Made a correction: {human_response}\"\n", + "\n", + " # This time we explicitly update the state with a ToolMessage inside\n", + " # the tool.\n", + " state_update = {\n", + " \"name\": verified_name,\n", + " \"birthday\": verified_birthday,\n", + " \"messages\": [ToolMessage(response, tool_call_id=tool_call_id)],\n", + " }\n", + " return Command(update=state_update)" + ] + }, + { + "cell_type": "markdown", + "id": "268757ca-4b72-4fc1-a482-d878dd1bc0d9", + "metadata": {}, + "source": [ + "Otherwise, the rest of our graph is the same:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "e256fa2e-6c13-42dd-a0a5-d206ee4139bf", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_anthropic import ChatAnthropic\n", + "from langchain_community.tools.tavily_search import TavilySearchResults\n", + "\n", + "from langgraph.checkpoint.memory import MemorySaver\n", + "from langgraph.graph import StateGraph, START, END\n", + "from langgraph.prebuilt import ToolNode, tools_condition\n", "\n", "\n", "tool = TavilySearchResults(max_results=2)\n", - "tools = [tool]\n", + "tools = [tool, human_assistance]\n", "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n", "llm_with_tools = llm.bind_tools(tools)\n", "\n", @@ -1861,86 +1653,35 @@ " return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n", "\n", "\n", - "# We add a node to handle the interaction with a human reviewer\n", - "def human_review_node(state: State) -> Command[Literal[\"chatbot\", \"tools\"]]:\n", - " last_message = state[\"messages\"][-1]\n", - " tool_call = last_message.tool_calls[-1]\n", + "graph_builder = StateGraph(State)\n", + "graph_builder.add_node(\"chatbot\", chatbot)\n", "\n", - " # this is the value we'll be providing via Command(resume=)\n", - " human_review = interrupt(\n", - " {\n", - " \"question\": \"Is this correct?\",\n", - " # Surface tool calls for review\n", - " \"tool_call\": tool_call,\n", - " }\n", - " )\n", - "\n", - " review_action = human_review[\"action\"]\n", - " review_data = human_review.get(\"data\")\n", - "\n", - " # if approved, call the tool\n", - " if review_action == \"continue\":\n", - " return Command(goto=\"tools\")\n", - "\n", - " elif review_action == \"feedback\":\n", - " # NOTE: we're adding feedback message as a ToolMessage\n", - " # to preserve the correct order in the message history\n", - " # (AI messages with tool calls need to be followed by tool call messages)\n", - " tool_message = {\n", - " \"role\": \"tool\",\n", - " # This is our natural language feedback\n", - " \"content\": review_data,\n", - " \"name\": tool_call[\"name\"],\n", - " \"tool_call_id\": tool_call[\"id\"],\n", - " }\n", - " return Command(goto=\"chatbot\", update={\"messages\": [tool_message]})\n", - "\n", - "\n", - "# Where we used tools_condition before, here we update the condition\n", - "# to route to the human review node first, instead of tools.\n", - "def route_after_llm(state) -> Literal[END, \"human_review_node\"]:\n", - " if len(state[\"messages\"][-1].tool_calls) == 0:\n", - " return END\n", - " else:\n", - " return \"human_review_node\"\n", - "\n", - "\n", - "graph_builder.add_node(chatbot)\n", - "\n", - "tool_node = ToolNode(tools=[tool])\n", + "tool_node = ToolNode(tools=tools)\n", "graph_builder.add_node(\"tools\", tool_node)\n", - "graph_builder.add_node(human_review_node)\n", "\n", "graph_builder.add_conditional_edges(\n", " \"chatbot\",\n", - " route_after_llm,\n", + " tools_condition,\n", ")\n", "graph_builder.add_edge(\"tools\", \"chatbot\")\n", - "graph_builder.add_edge(START, \"chatbot\")" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "64cc981c-38fd-4ea5-8be5-f077be796411", - "metadata": {}, - "outputs": [], - "source": [ + "graph_builder.add_edge(START, \"chatbot\")\n", + "\n", + "memory = MemorySaver()\n", "graph = graph_builder.compile(checkpointer=memory)" ] }, { "cell_type": "markdown", - "id": "00726b4b-7661-414e-a077-5cabba597163", + "id": "e9f77638-f957-4e1b-abcf-e9132c039be5", "metadata": {}, "source": [ - "We first begin a thread:" + "Let's prompt our application to look up the \"birthday\" of the LangGraph library. We will direct the chatbot to reach out to the `human_assistance` tool once it has the required information. Note that setting `name` and `birthday` in the arguments for the tool, we force the chatbot to generate proposals for these fields." ] }, { "cell_type": "code", - "execution_count": 4, - "id": "4124bf18-302a-4593-b485-247bfd36f150", + "execution_count": 5, + "id": "10701e49-d4b4-46db-bb30-f895fdf4411d", "metadata": {}, "outputs": [ { @@ -1949,20 +1690,36 @@ "text": [ "================================\u001b[1m Human Message \u001b[0m=================================\n", "\n", - "I'm learning LangGraph. Could you do some research on it for me?\n", + "Can you look up when LangGraph was released? When you have the answer, use the human_assistance tool for review.\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01NKHEFSGNmLeVGvBYDyrALi', 'input': {'query': 'LangGraph: what is it, features, and usage in AI development'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", + "[{'text': \"Certainly! I'll start by searching for information about LangGraph's release date using the Tavily search engine. Then, I'll use the human_assistance tool for review. Let's begin with the search.\", 'type': 'text'}, {'id': 'toolu_01APsgm3wwYXyZQcZJNb3rGJ', 'input': {'query': 'LangGraph release date'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " tavily_search_results_json (toolu_01NKHEFSGNmLeVGvBYDyrALi)\n", - " Call ID: toolu_01NKHEFSGNmLeVGvBYDyrALi\n", + " tavily_search_results_json (toolu_01APsgm3wwYXyZQcZJNb3rGJ)\n", + " Call ID: toolu_01APsgm3wwYXyZQcZJNb3rGJ\n", " Args:\n", - " query: LangGraph: what is it, features, and usage in AI development\n" + " query: LangGraph release date\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: tavily_search_results_json\n", + "\n", + "[{\"url\": \"https://blog.langchain.dev/langgraph-cloud/\", \"content\": \"We also have a new stable release of LangGraph. By LangChain 6 min read Jun 27, 2024 (Oct '24) Edit: Since the launch of LangGraph Cloud, we now have multiple deployment options alongside LangGraph Studio - which now fall under LangGraph Platform. LangGraph Cloud is synonymous with our Cloud SaaS deployment option.\"}, {\"url\": \"https://changelog.langchain.com/announcements/langgraph-cloud-deploy-at-scale-monitor-carefully-iterate-boldly\", \"content\": \"LangChain - Changelog | ☁ 🚀 LangGraph Cloud: Deploy at scale, monitor LangChain LangSmith LangGraph LangChain LangSmith LangGraph LangChain LangSmith LangGraph LangChain Changelog Sign up for our newsletter to stay up to date DATE: The LangChain Team LangGraph LangGraph Cloud ☁ 🚀 LangGraph Cloud: Deploy at scale, monitor carefully, iterate boldly DATE: June 27, 2024 AUTHOR: The LangChain Team LangGraph Cloud is now in closed beta, offering scalable, fault-tolerant deployment for LangGraph agents. LangGraph Cloud also includes a new playground-like studio for debugging agent failure modes and quick iteration: Join the waitlist today for LangGraph Cloud. And to learn more, read our blog post announcement or check out our docs. Subscribe By clicking subscribe, you accept our privacy policy and terms and conditions.\"}]\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "[{'text': 'Based on the search results, it appears that LangGraph was released before June 27, 2024. The search results mention a \"new stable release of LangGraph\" and \"LangGraph Cloud\" being announced on that date. However, the exact initial release date of LangGraph is not clearly stated in these results.\\n\\nGiven this information, I\\'ll use the human_assistance tool to review and possibly get more precise information about LangGraph\\'s initial release date.', 'type': 'text'}, {'id': 'toolu_01JtZJvDho75gcLbqcHHp4if', 'input': {'name': 'Assistant', 'birthday': '2023-01-01'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n", + "Tool Calls:\n", + " human_assistance (toolu_01JtZJvDho75gcLbqcHHp4if)\n", + " Call ID: toolu_01JtZJvDho75gcLbqcHHp4if\n", + " Args:\n", + " name: Assistant\n", + " birthday: 2023-01-01\n" ] } ], "source": [ - "user_input = \"I'm learning LangGraph. Could you do some research on it for me?\"\n", + "user_input = (\n", + " \"Can you look up when LangGraph was released? \"\n", + " \"When you have the answer, use the human_assistance tool for review.\"\n", + ")\n", "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", "\n", "events = graph.stream(\n", @@ -1975,55 +1732,16 @@ }, { "cell_type": "markdown", - "id": "e3f5b9c1-e259-43f3-bfc6-f9a166a1da71", + "id": "99dcaf45-e4d1-4597-b669-13a5330740ac", "metadata": {}, "source": [ - "Note that we can read the existing state from the `graph` object:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "a6b3bcae-dd04-49da-a4ef-e05634657faf", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01NKHEFSGNmLeVGvBYDyrALi', 'input': {'query': 'LangGraph: what is it, features, and usage in AI development'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " tavily_search_results_json (toolu_01NKHEFSGNmLeVGvBYDyrALi)\n", - " Call ID: toolu_01NKHEFSGNmLeVGvBYDyrALi\n", - " Args:\n", - " query: LangGraph: what is it, features, and usage in AI development\n" - ] - } - ], - "source": [ - "snapshot = graph.get_state(config)\n", - "existing_message = snapshot.values[\"messages\"][-1]\n", - "existing_message.pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "3bf55a26-8c12-477a-9e83-5011d36ac4ee", - "metadata": {}, - "source": [ - "So far, all of this is an _exact repeat_ of the previous section. The LLM just requested to use the search engine tool and our graph was interrupted. If we proceed as before, the tool will be called to search the web.\n", - "\n", - "But what if the user wants to intercede? What if we think the chat bot doesn't need to use the tool? \n", - "\n", - "Let's directly provide the correct response!" + "We've hit the `interrupt` in the `human_assistance` tool again. In this case, the chatbot failed to identify the correct date, so we can supply it:" ] }, { "cell_type": "code", "execution_count": 6, - "id": "f0fd4cdb-afc4-4617-b0a9-f018232d641c", + "id": "7df33d9e-cc76-4a0f-8307-01e619483b3e", "metadata": {}, "outputs": [ { @@ -2032,71 +1750,63 @@ "text": [ "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "LangGraph is a library for building stateful, multi-actor applications with LLMs.\n", + "[{'text': 'Based on the search results, it appears that LangGraph was released before June 27, 2024. The search results mention a \"new stable release of LangGraph\" and \"LangGraph Cloud\" being announced on that date. However, the exact initial release date of LangGraph is not clearly stated in these results.\\n\\nGiven this information, I\\'ll use the human_assistance tool to review and possibly get more precise information about LangGraph\\'s initial release date.', 'type': 'text'}, {'id': 'toolu_01JtZJvDho75gcLbqcHHp4if', 'input': {'name': 'Assistant', 'birthday': '2023-01-01'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n", + "Tool Calls:\n", + " human_assistance (toolu_01JtZJvDho75gcLbqcHHp4if)\n", + " Call ID: toolu_01JtZJvDho75gcLbqcHHp4if\n", + " Args:\n", + " name: Assistant\n", + " birthday: 2023-01-01\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: human_assistance\n", "\n", + "Made a correction: {'name': 'LangGraph', 'birthday': 'Jan 17, 2024'}\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "Last 2 messages;\n", - "[ToolMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', id='12be5dbe-75eb-45d8-8d64-5ab0c2f8555f', tool_call_id='toolu_01NKHEFSGNmLeVGvBYDyrALi'), AIMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', additional_kwargs={}, response_metadata={}, id='0f389c32-6fdd-4ad9-bd89-671d38983a70')]\n" + "Thank you for the human assistance. I can now provide you with the correct information about LangGraph's release date.\n", + "\n", + "LangGraph was initially released on January 17, 2024. This information comes directly from the human assistance, which provided a correction to my earlier uncertainty.\n", + "\n", + "To summarize:\n", + "- Initial search results were not clear about the exact release date of LangGraph.\n", + "- Human assistance provided the precise release date: January 17, 2024.\n", + "\n", + "This demonstrates the importance of verifying information, especially for newer technologies or products where online search results might not always provide the most up-to-date or accurate information.\n" ] } ], "source": [ - "from langchain_core.messages import AIMessage, ToolMessage\n", - "\n", - "answer = (\n", - " \"LangGraph is a library for building stateful, multi-actor applications with LLMs.\"\n", - ")\n", - "new_messages = [\n", - " # The LLM API expects some ToolMessage to match its tool call. We'll satisfy that here.\n", - " ToolMessage(content=answer, tool_call_id=existing_message.tool_calls[0][\"id\"]),\n", - " # And then directly \"put words in the LLM's mouth\" by populating its response.\n", - " AIMessage(content=answer),\n", - "]\n", - "\n", - "new_messages[-1].pretty_print()\n", - "graph.update_state(\n", - " # Which state to update\n", - " config,\n", - " # The updated values to provide. The messages in our `State` are \"append-only\", meaning this will be appended\n", - " # to the existing state. We will review how to update existing messages in the next section!\n", - " {\"messages\": new_messages},\n", + "human_command = Command(\n", + " resume={\n", + " \"name\": \"LangGraph\",\n", + " \"birthday\": \"Jan 17, 2024\",\n", + " },\n", ")\n", "\n", - "print(\"\\n\\nLast 2 messages;\")\n", - "print(graph.get_state(config).values[\"messages\"][-2:])" + "events = graph.stream(human_command, config, stream_mode=\"values\")\n", + "for event in events:\n", + " if \"messages\" in event:\n", + " event[\"messages\"][-1].pretty_print()" ] }, { "cell_type": "markdown", - "id": "584de971-6b10-4931-986e-cc35f7adbb3d", + "id": "31581965-8d7d-4378-82b2-f5c2a84a54b1", "metadata": {}, "source": [ - "Now the graph is complete, since we've provided the final response message! Since state updates simulate a graph step, they even generate corresponding traces. Inspect the [LangSmith trace](https://smith.langchain.com/public/e844af02-7f45-43e2-92bc-13cd3af9b62f/r) of the `update_state` call above to see what's going on.\n", - "\n", - "**Notice** that our new messages are _appended_ to the messages already in the state. Remember how we defined the `State` type?\n", - "\n", - "```python\n", - "class State(TypedDict):\n", - " messages: Annotated[list, add_messages]\n", - "```\n", - "\n", - "We annotated `messages` with the pre-built `add_messages` function. This instructs the graph to always append values to the existing list, rather than overwriting the list directly. The same logic is applied here, so the messages we passed to `update_state` were appended in the same way!\n", - "\n", - "The `update_state` function operates as if it were one of the nodes in your graph! By default, the update operation uses the node that was last executed, but you can manually specify it below. Let's add an update and tell the graph to treat it as if it came from the \"chatbot\"." + "Note that these fields are now reflected in the state:" ] }, { "cell_type": "code", "execution_count": 7, - "id": "d16d95c3-b465-42ac-8015-26b669d45d1f", + "id": "b9fe6275-489d-4a6f-b19f-f1000d4133a0", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'configurable': {'thread_id': '1',\n", - " 'checkpoint_ns': '',\n", - " 'checkpoint_id': '1efd377d-87e6-6ab6-8003-7d963c60dd60'}}" + "{'name': 'LangGraph', 'birthday': 'Jan 17, 2024'}" ] }, "execution_count": 7, @@ -2105,893 +1815,172 @@ } ], "source": [ - "graph.update_state(\n", - " config,\n", - " {\"messages\": [AIMessage(content=\"I'm an AI expert!\")]},\n", - " # Which node for this function to act as. It will automatically continue\n", - " # processing as if this node just ran.\n", - " as_node=\"chatbot\",\n", - ")" + "snapshot = graph.get_state(config)\n", + "\n", + "{k: v for k, v in snapshot.values.items() if k in (\"name\", \"birthday\")}" ] }, { "cell_type": "markdown", - "id": "5a1f0056-6b6f-425f-ac1a-0d4b0e9b85cc", + "id": "14593643-aa81-4b40-9c2d-9408bcaf88cb", "metadata": {}, "source": [ - "Check out the [LangSmith trace](https://smith.langchain.com/public/14edbcaf-a230-45e5-bda2-bd24a9f96cd1/r) for this update call at the provided link. **Notice** from the trace that the graph continues into the `route_after_llm` edge. We just told the graph to treat the update `as_node=\"chatbot\"`. If we follow the diagram below and start from the `chatbot` node, we naturally end up in the `route_after_llm` edge and then `__end__` since our updated message lacks tool calls." + "This makes them easily accessible to downstream nodes (e.g., a node that further processes or stores the information)." + ] + }, + { + "cell_type": "markdown", + "id": "238c359a-24ca-4fbf-8f6c-28a347fee2f2", + "metadata": {}, + "source": [ + "### Manually updating state\n", + "\n", + "LangGraph gives a high degree of control over the application state. For instance, at any point (including when interrupted), we can manually override a key using `graph.update_state`:" ] }, { "cell_type": "code", "execution_count": 8, - "id": "f4009ba6-dc0b-4216-ab0c-fbb104616f73", + "id": "b206e600-91f0-4f46-9587-ab00c05899de", "metadata": {}, "outputs": [ { "data": { - "image/png": "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", "text/plain": [ - "" + "{'configurable': {'thread_id': '1',\n", + " 'checkpoint_ns': '',\n", + " 'checkpoint_id': '1efd4395-61ae-6f14-8006-fb093210b222'}}" ] }, + "execution_count": 8, "metadata": {}, - "output_type": "display_data" + "output_type": "execute_result" } ], "source": [ - "from IPython.display import Image, display\n", - "\n", - "try:\n", - " display(Image(graph.get_graph().draw_mermaid_png()))\n", - "except Exception:\n", - " # This requires some extra dependencies and is optional\n", - " pass" + "graph.update_state(config, {\"name\": \"LangGraph (library)\"})" ] }, { "cell_type": "markdown", - "id": "96cd4ffa-8fb2-4bd6-bef9-564cbfe7e3ab", + "id": "3dfb8268-8c5a-4022-9189-6edd231436ae", "metadata": {}, "source": [ - "Inspect the current state as before to confirm the checkpoint reflects our manual updates." + "If we call `graph.get_state`, we can see the new value is reflected:" ] }, { "cell_type": "code", "execution_count": 9, - "id": "d420e813-a8c7-415d-ab31-5298d42491e4", + "id": "10adcb89-55ab-4076-bc81-4488eff9e6b3", "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ToolMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', id='12be5dbe-75eb-45d8-8d64-5ab0c2f8555f', tool_call_id='toolu_01NKHEFSGNmLeVGvBYDyrALi'), AIMessage(content='LangGraph is a library for building stateful, multi-actor applications with LLMs.', additional_kwargs={}, response_metadata={}, id='0f389c32-6fdd-4ad9-bd89-671d38983a70'), AIMessage(content=\"I'm an AI expert!\", additional_kwargs={}, response_metadata={}, id='8ea38275-255a-4d64-be3c-c4fcd6c6e55a')]\n", - "()\n" - ] + "data": { + "text/plain": [ + "{'name': 'LangGraph (library)', 'birthday': 'Jan 17, 2024'}" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ "snapshot = graph.get_state(config)\n", - "print(snapshot.values[\"messages\"][-3:])\n", - "print(snapshot.next)" + "\n", + "{k: v for k, v in snapshot.values.items() if k in (\"name\", \"birthday\")}" ] }, { "cell_type": "markdown", - "id": "380222f4-65fa-4962-afe6-6a715fadb2de", + "id": "ab34ef46-a836-4dbd-b1ae-56c5e8dc75af", "metadata": {}, "source": [ - "**Notice**: that we've continued to add AI messages to the state. Since we are acting as the `chatbot` and responding with an AIMessage that doesn't contain `tool_calls`, the graph knows that it has entered a finished state (`next` is empty).\n", + "Manual state updates will even [generate a trace](https://smith.langchain.com/public/7ebb7827-378d-49fe-9f6c-5df0e90086c8/r) in LangSmith. If desired, they can also be used to control human-in-the-loop workflows, as described in [this guide](how-tos/human_in_the_loop/edit-graph-state/). Use of the `interrupt` function is generally recommended instead, as it allows data to be transmitted in a human-in-the-loop interaction independently of state updates.\n", "\n", - "#### What if you want to **overwrite** existing messages? \n", - "\n", - "The [`add_messages`](https://langchain-ai.github.io/langgraph/reference/graphs/?h=add+messages#add_messages) function we used to annotate our graph's `State` above controls how updates are made to the `messages` key. This function looks at any message IDs in the new `messages` list. If the ID matches a message in the existing state, [`add_messages`](https://langchain-ai.github.io/langgraph/reference/graphs/?h=add+messages#add_messages) overwrites the existing message with the new content. \n", - "\n", - "As an example, let's update the tool invocation to make sure we get good results from our search engine! First, start a new thread:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "b5aa8029-927d-4597-88b7-c9fadd4f6f60", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "I'm learning LangGraph. Could you do some research on it for me?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search function to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_0135SrrAV1dhbeDtvKzUovUH', 'input': {'query': 'LangGraph python library for language models'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " tavily_search_results_json (toolu_0135SrrAV1dhbeDtvKzUovUH)\n", - " Call ID: toolu_0135SrrAV1dhbeDtvKzUovUH\n", - " Args:\n", - " query: LangGraph python library for language models\n" - ] - } - ], - "source": [ - "user_input = \"I'm learning LangGraph. Could you do some research on it for me?\"\n", - "config = {\"configurable\": {\"thread_id\": \"2\"}} # we'll use thread_id = 2 here\n", - "events = graph.stream(\n", - " {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n", - ")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "8b019fc6-7826-4291-9178-6cecb5d7b3d0", - "metadata": {}, - "source": [ - "**Next,** let's update the tool invocation for our agent. Maybe we want to search for human-in-the-loop workflows in particular." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "7215533a-b7e2-4b2d-bc1d-5122b1d06b8b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Original\n", - "Message ID run-c6d77fff-fb85-49df-ad84-07ed4e8a352c-0\n", - "{'name': 'tavily_search_results_json', 'args': {'query': 'LangGraph python library for language models'}, 'id': 'toolu_0135SrrAV1dhbeDtvKzUovUH', 'type': 'tool_call'}\n", - "Updated\n", - "{'name': 'tavily_search_results_json', 'args': {'query': 'LangGraph human-in-the-loop workflow'}, 'id': 'toolu_0135SrrAV1dhbeDtvKzUovUH', 'type': 'tool_call'}\n", - "Message ID run-c6d77fff-fb85-49df-ad84-07ed4e8a352c-0\n", - "\n", - "\n", - "Tool calls\n" - ] - }, - { - "data": { - "text/plain": [ - "[{'name': 'tavily_search_results_json',\n", - " 'args': {'query': 'LangGraph human-in-the-loop workflow'},\n", - " 'id': 'toolu_0135SrrAV1dhbeDtvKzUovUH',\n", - " 'type': 'tool_call'}]" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from langchain_core.messages import AIMessage\n", - "\n", - "snapshot = graph.get_state(config)\n", - "existing_message = snapshot.values[\"messages\"][-1]\n", - "print(\"Original\")\n", - "print(\"Message ID\", existing_message.id)\n", - "print(existing_message.tool_calls[0])\n", - "new_tool_call = existing_message.tool_calls[0].copy()\n", - "new_tool_call[\"args\"][\"query\"] = \"LangGraph human-in-the-loop workflow\"\n", - "new_message = AIMessage(\n", - " content=existing_message.content,\n", - " tool_calls=[new_tool_call],\n", - " # Important! The ID is how LangGraph knows to REPLACE the message in the state rather than APPEND this messages\n", - " id=existing_message.id,\n", - ")\n", - "\n", - "print(\"Updated\")\n", - "print(new_message.tool_calls[0])\n", - "print(\"Message ID\", new_message.id)\n", - "graph.update_state(config, {\"messages\": [new_message]})\n", - "\n", - "print(\"\\n\\nTool calls\")\n", - "graph.get_state(config).values[\"messages\"][-1].tool_calls" - ] - }, - { - "cell_type": "markdown", - "id": "680f0ebd-ebce-4de6-8a9b-37d3d4ef0234", - "metadata": {}, - "source": [ - "**Notice** that we've modified the AI's tool invocation to search for \"LangGraph human-in-the-loop workflow\" instead of the simple \"LangGraph\".\n", - "\n", - "Check out the [LangSmith trace](https://smith.langchain.com/public/0a13df28-1509-4974-9f3a-09af34671ec9/r) to see the state update call - you can see our new message has successfully updated the previous AI message.\n", - "\n", - "Resume the graph as before, by passing the appropriate `Command`:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "7e9ebc73-22e8-4af2-9a36-6678873c671f", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and comprehensive information, I'll use the Tavily search function to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_0135SrrAV1dhbeDtvKzUovUH', 'input': {'query': 'LangGraph python library for language models'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " tavily_search_results_json (toolu_0135SrrAV1dhbeDtvKzUovUH)\n", - " Call ID: toolu_0135SrrAV1dhbeDtvKzUovUH\n", - " Args:\n", - " query: LangGraph human-in-the-loop workflow\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: tavily_search_results_json\n", - "\n", - "[{\"url\": \"https://www.youtube.com/watch?v=9BPCV5TYPmg\", \"content\": \"In this video, I'll show you how to handle persistence with LangGraph, enabling a unique Human-in-the-Loop workflow. This approach allows a human to grant an\"}, {\"url\": \"https://blog.langchain.dev/human-in-the-loop-with-opengpts-and-langgraph/\", \"content\": \"TLDR; Today we're launching two \\\"human in the loop\\\" features in OpenGPTs, Interrupt and Authorize, both powered by LangGraph. We've recently launched LangGraph, a library to help developers build multi-actor, multi-step, stateful LLM applications. That's a lot words packed into a short sentence, let's take it one at a time. Multi-actor\"}]\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Thank you for your patience. I've found some useful information about LangGraph, particularly focusing on its human-in-the-loop workflow capabilities. Let me summarize what I've learned:\n", - "\n", - "1. What is LangGraph:\n", - " LangGraph is a library designed to help developers build complex, stateful LLM (Large Language Model) applications. It's particularly useful for creating multi-actor and multi-step processes.\n", - "\n", - "2. Human-in-the-Loop Workflow:\n", - " One of the key features of LangGraph is its support for human-in-the-loop workflows. This means it allows for human intervention and interaction within AI-driven processes.\n", - "\n", - "3. OpenGPTs Integration:\n", - " LangGraph has been integrated with OpenGPTs, introducing two human-in-the-loop features:\n", - " a) Interrupt: This likely allows a human to pause or intervene in an ongoing AI process.\n", - " b) Authorize: This feature probably enables human approval or authorization at certain steps of the AI workflow.\n", - "\n", - "4. Persistence Handling:\n", - " LangGraph includes functionality for handling persistence. This is important for maintaining state across different steps of a workflow, especially when human interaction is involved.\n", - "\n", - "5. Use Cases:\n", - " The human-in-the-loop capabilities make LangGraph suitable for applications where you need a blend of AI efficiency and human oversight or decision-making. This could be particularly useful in fields like content moderation, complex decision processes, or scenarios where ethical considerations are important.\n", - "\n", - "6. Developer Focus:\n", - " LangGraph seems to be targeted at developers who are looking to create more sophisticated LLM applications that go beyond simple query-response models.\n", - "\n", - "To learn more about LangGraph, you might want to:\n", - "1. Check out the official documentation or GitHub repository for LangGraph.\n", - "2. Watch tutorial videos, like the one mentioned in the search results, which demonstrates how to handle persistence with LangGraph.\n", - "3. Explore the OpenGPTs platform to see practical implementations of LangGraph's human-in-the-loop features.\n", - "4. Try building a simple application using LangGraph to get hands-on experience with its capabilities.\n", - "\n", - "Would you like me to search for more specific information about any aspect of LangGraph, such as its installation process, core components, or example use cases?\n" - ] - } - ], - "source": [ - "human_command = Command(resume={\"action\": \"continue\"})\n", - "\n", - "events = graph.stream(human_command, config, stream_mode=\"values\")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "090b680b-f53f-4af2-a432-45f8c5a10779", - "metadata": {}, - "source": [ - "Check out the [trace](https://smith.langchain.com/public/e5b0b999-b1cd-43cf-bf75-df0b35bbe366/r/1f17ded9-6958-4682-9a0d-9d7eedbf7136) to see the tool call and later LLM response. **Notice** that now the graph queries the search engine using our updated query term - we were able to manually override the LLM's search here!\n", - "\n", - "All of this is reflected in the graph's checkpointed memory, meaning if we continue the conversation, it will recall all the _modified_ state." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "556c71d3-48ac-43d7-833c-c3f884b330a7", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "Remember what I'm learning about?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Of course! You mentioned that you're learning LangGraph. I apologize for not explicitly referencing that in my response. You're right to bring that back into focus. \n", - "\n", - "Since you're in the process of learning LangGraph, it's important to tailor the information to your learning journey. Based on what we've found, here are some key points that might be particularly relevant for someone learning LangGraph:\n", - "\n", - "1. Core Concept: LangGraph is a library for building stateful, multi-step LLM applications. As you're learning it, focus on understanding how it manages state across different steps of a process.\n", - "\n", - "2. Human-in-the-Loop: One of LangGraph's key features is its support for human-in-the-loop workflows. This could be an interesting area to explore in your learning, as it allows you to create AI systems that can interact with humans during execution.\n", - "\n", - "3. Integration with OpenGPTs: Learning how LangGraph integrates with other tools like OpenGPTs could be valuable. The \"Interrupt\" and \"Authorize\" features might be good practical examples to study.\n", - "\n", - "4. Persistence Handling: As a learner, understanding how LangGraph handles persistence could be crucial. This relates to how the library maintains state across different steps of your AI workflows.\n", - "\n", - "5. Practical Application: The video mentioned in the search results about handling persistence with LangGraph could be a great resource for your learning. It seems to offer a practical demonstration, which is often very helpful when learning a new technology.\n", - "\n", - "To support your learning process, you might want to:\n", - "- Start with simple LangGraph projects and gradually increase complexity\n", - "- Focus on understanding the state management aspects of LangGraph\n", - "- Experiment with the human-in-the-loop features to see how they work in practice\n", - "- Look for tutorials or courses specifically designed for learning LangGraph\n", - "\n", - "Is there a particular aspect of LangGraph that you're finding challenging or especially interesting in your learning journey? Or would you like me to find more beginner-friendly resources for learning LangGraph?\n" - ] - } - ], - "source": [ - "events = graph.stream(\n", - " {\n", - " \"messages\": (\n", - " \"user\",\n", - " \"Remember what I'm learning about?\",\n", - " )\n", - " },\n", - " config,\n", - " stream_mode=\"values\",\n", - ")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "a5166e1b-96a6-4ac0-88a1-bf32a422134a", - "metadata": {}, - "source": [ - "**Congratulations!** You've used `interrupt` and `update_state` to manually modify the state as a part of a human-in-the-loop workflow. Interruptions and state modifications let you control how the agent behaves. Combined with persistent checkpointing, it means you can `pause` an action and `resume` at any point. Your user doesn't have to be available when the graph interrupts!" - ] - }, - { - "cell_type": "markdown", - "id": "d88d4c9e-65c8-4093-a6c2-c261475f7c07", - "metadata": {}, - "source": [ - "## Part 6: Customizing State\n", - "\n", - "So far, we've relied on a simple state (it's just a list of messages!). You can go far with this simple state, but if you want to define complex behavior without relying on the message list, you can add additional fields to the state. In this section, we will extend our chat bot with a new node to illustrate this.\n", - "\n", - "In the examples above, we involved a human deterministically: the graph __always__ interrupted whenever a tool was invoked. Suppose we wanted our chat bot to have the choice of relying on a human.\n", - "\n", - "One way to do this is route to the `human_review_node` only if the LLM invokes a \"human\" tool. We will include an `ask_human` flag in our graph state that we will flip if the LLM calls this tool. This is not needed for the routing process, but conveniently indicates if a run required human assistance in the output.\n", - "\n", - "Below, define this new graph, with an updated `State`:" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "3cf7e042-1718-4625-ae30-a9917f595449", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Annotated, Literal\n", - "\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langchain_community.tools.tavily_search import TavilySearchResults\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.graph import StateGraph, START, END\n", - "from langgraph.graph.message import add_messages\n", - "from langgraph.prebuilt import ToolNode\n", - "from langgraph.types import Command, interrupt\n", - "\n", - "\n", - "class State(TypedDict):\n", - " messages: Annotated[list, add_messages]\n", - " # This flag is new\n", - " # highlight-next-line\n", - " ask_human: bool" - ] - }, - { - "cell_type": "markdown", - "id": "e87f2cb8-c066-4b54-acc4-e8c7399c5f3d", - "metadata": {}, - "source": [ - "Next, define a schema to show the model to let it decide to request assistance." - ] - }, - { - "cell_type": "markdown", - "id": "7bd3d704-5bee-4872-8d12-992bc970c158", - "metadata": {}, - "source": [ - "
\n", - "

Using Pydantic with LangChain

\n", - "

\n", - " This notebook uses Pydantic v2 BaseModel, which requires langchain-core >= 0.3. Using langchain-core < 0.3 will result in errors due to mixing of Pydantic v1 and v2 BaseModels.\n", - "

\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "e5192e54-6a28-42fe-a8a7-62d45d61f994", - "metadata": {}, - "outputs": [], - "source": [ - "from pydantic import BaseModel\n", - "\n", - "\n", - "class RequestAssistance(BaseModel):\n", - " \"\"\"Escalate the conversation to an expert. Use this if you are unable to assist directly or if the user requires support beyond your permissions.\n", - "\n", - " To use this function, relay the user's 'request' so the expert can provide the right guidance.\n", - " \"\"\"\n", - "\n", - " request: str" - ] - }, - { - "cell_type": "markdown", - "id": "338c1bf4-8d00-49c3-9809-ecea290fa152", - "metadata": {}, - "source": [ - "We include this as a new tool accessible to the model:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "75cf03b1-c546-4585-8d2f-4a8be296fd89", - "metadata": {}, - "outputs": [], - "source": [ - "tool = TavilySearchResults(max_results=2)\n", - "tools = [tool]\n", - "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n", - "# We can bind the llm to a tool definition, a pydantic model, or a json schema\n", - "llm_with_tools = llm.bind_tools(tools + [RequestAssistance])" - ] - }, - { - "cell_type": "markdown", - "id": "2b19c61b-2087-463b-adf8-96dbc193f41c", - "metadata": {}, - "source": [ - "Otherwise, we just update the `human_review_node` to short-circuit and route directly to `tools` if assistance is not requested. If it is requested, we flip the new flag in the state." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "d7da1212-dc9c-4385-a0a0-c4c3bc30e633", - "metadata": {}, - "outputs": [], - "source": [ - "def chatbot(state: State):\n", - " return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n", - "\n", - "\n", - "def human_review_node(state: State) -> Command[Literal[\"chatbot\", \"tools\"]]:\n", - " last_message = state[\"messages\"][-1]\n", - " tool_call = last_message.tool_calls[-1]\n", - "\n", - " # highlight-next-line\n", - " if not tool_call[\"name\"] == RequestAssistance.__name__:\n", - " return Command(goto=\"tools\")\n", - "\n", - " human_review = interrupt(\n", - " {\n", - " \"question\": \"Is this correct?\",\n", - " \"tool_call\": tool_call,\n", - " }\n", - " )\n", - "\n", - " review_action = human_review[\"action\"]\n", - " review_data = human_review.get(\"data\")\n", - "\n", - " if review_action == \"continue\":\n", - " # highlight-next-line\n", - " return Command(goto=\"tools\", update={\"ask_human\": True})\n", - "\n", - " elif review_action == \"feedback\":\n", - " tool_message = {\n", - " \"role\": \"tool\",\n", - " \"content\": review_data,\n", - " \"name\": tool_call[\"name\"],\n", - " \"tool_call_id\": tool_call[\"id\"],\n", - " }\n", - " return Command(\n", - " goto=\"chatbot\",\n", - " # highlight-next-line\n", - " update={\"messages\": [tool_message], \"ask_human\": True},\n", - " )\n", - "\n", - "\n", - "def route_after_llm(state) -> Literal[END, \"human_review_node\"]:\n", - " if len(state[\"messages\"][-1].tool_calls) == 0:\n", - " return END\n", - " else:\n", - " return \"human_review_node\"" - ] - }, - { - "cell_type": "markdown", - "id": "04ca0f57-2519-49c2-9499-888b5a884897", - "metadata": {}, - "source": [ - "Next, create the graph builder and add the chatbot and tools nodes to the graph, same as before." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8db38d3e-f2ff-4d9d-b267-27729be8e060", - "metadata": {}, - "outputs": [], - "source": [ - "graph_builder = StateGraph(State)\n", - "\n", - "graph_builder.add_node(chatbot)\n", - "\n", - "tool_node = ToolNode(tools=[tool])\n", - "graph_builder.add_node(\"tools\", tool_node)\n", - "graph_builder.add_node(human_review_node)\n", - "\n", - "graph_builder.add_conditional_edges(\n", - " \"chatbot\",\n", - " route_after_llm,\n", - ")\n", - "graph_builder.add_edge(\"tools\", \"chatbot\")\n", - "graph_builder.add_edge(START, \"chatbot\")" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "d9d77f37-63cd-4ed3-86c6-ddaac62b39e9", - "metadata": {}, - "outputs": [], - "source": [ - "memory = MemorySaver()\n", - "\n", - "graph = graph_builder.compile(checkpointer=memory)" - ] - }, - { - "cell_type": "markdown", - "id": "a3b73851-810e-4466-89d8-37fba87e8494", - "metadata": {}, - "source": [ - "The chat bot can either request help from a human (chatbot->select->human), invoke the search engine tool (chatbot->select->action), or directly respond (chatbot->select->__end__). Once an action or request has been made, the graph will transition back to the `chatbot` node to continue operations.\n", - "\n", - "Let's see this graph in action. We first ask it a question that requires no human intervention:" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "00a11e0c-937d-4f11-a623-bf16ee1f6d4e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "Can you search for the weather in San Francisco?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Certainly! I'd be happy to search for the weather in San Francisco for you. To get the most up-to-date and accurate information, I'll use the search function to look this up. Let me do that for you right away.\", 'type': 'text'}, {'id': 'toolu_01QvcSUFnMXDrK4dWJ4g34P7', 'input': {'query': 'current weather in San Francisco'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " tavily_search_results_json (toolu_01QvcSUFnMXDrK4dWJ4g34P7)\n", - " Call ID: toolu_01QvcSUFnMXDrK4dWJ4g34P7\n", - " Args:\n", - " query: current weather in San Francisco\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: tavily_search_results_json\n", - "\n", - "[{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.775, 'lon': -122.4183, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1736974398, 'localtime': '2025-01-15 12:53'}, 'current': {'last_updated_epoch': 1736973900, 'last_updated': '2025-01-15 12:45', 'temp_c': 11.7, 'temp_f': 53.1, 'is_day': 1, 'condition': {'text': 'Sunny', 'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png', 'code': 1000}, 'wind_mph': 5.8, 'wind_kph': 9.4, 'wind_degree': 45, 'wind_dir': 'NE', 'pressure_mb': 1025.0, 'pressure_in': 30.27, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 41, 'cloud': 0, 'feelslike_c': 10.8, 'feelslike_f': 51.4, 'windchill_c': 9.6, 'windchill_f': 49.3, 'heatindex_c': 11.1, 'heatindex_f': 51.9, 'dewpoint_c': 6.3, 'dewpoint_f': 43.3, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 2.4, 'gust_mph': 7.7, 'gust_kph': 12.4}}\"}, {\"url\": \"https://www.yahoo.com/news/january-15-2025-san-francisco-135157305.html\", \"content\": \"January 15, 2025 San Francisco Bay Area weather forecast Search query Search the web News Finance Sports Manage your account Add or switch accounts Search the web Wildfire damage from space L.A. fires underlying causes Rent hikes amid wildfires Photos: Wildfire devastation L.A. wildfires live updates KRON San Francisco January 15, 2025 San Francisco Bay Area weather forecast KRON San Francisco Wed, January 15, 2025 at 1:51 PM UTC KRON4 Meteorologist Gayle Ong has the latest Bay Area weather outlook. https://www.kron4.com/weather/san-francisco-bay-area-weather-forecast/ Solve the daily Crossword 28,373 people played the daily Crossword recently. Can you solve it faster than others?28,373 people played the daily Crossword recently. Can you solve it faster than others? Crossword Play on Yahoo Yahoo! © 2024 Yahoo.\"}]\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Thank you for your patience. I've searched for the current weather in San Francisco, and I have the latest information for you. Here's the weather report for San Francisco:\n", - "\n", - "Date and Time: January 15, 2025, 12:45 PM local time\n", - "Temperature: 11.7°C (53.1°F)\n", - "Condition: Sunny\n", - "Wind: 5.8 mph (9.4 km/h), coming from the Northeast\n", - "Humidity: 41%\n", - "Precipitation: 0 mm (0 inches)\n", - "Visibility: 16 km (9 miles)\n", - "UV Index: 2.4 (low)\n", - "\n", - "It's a nice day in San Francisco with clear, sunny skies. The temperature is mild, typical for a winter day in the city. The wind is light, and there's no precipitation expected. It's a good day for outdoor activities, but you might want to bring a light jacket as it's not too warm.\n", - "\n", - "Is there anything specific about the weather you'd like to know more about?\n" - ] - } - ], - "source": [ - "user_input = \"Can you search for the weather in San Francisco?\"\n", - "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", - "\n", - "events = graph.stream(\n", - " {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n", - ")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "0589f4c9-5ad9-42f0-818a-7e1fcad75517", - "metadata": {}, - "source": [ - "This works as expected, and the state indicates that no human assistance was requested:" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "5d6e14ce-4687-48e2-a488-dca48aa9722b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.get_state(config).values.get(\"ask_human\", False)" - ] - }, - { - "cell_type": "markdown", - "id": "a06c0ce3-dc78-40a2-8ae2-7f4429d4bf9d", - "metadata": {}, - "source": [ - "We next request for expert assistance:" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "b789d334-9222-412c-83f2-0298571ce5c2", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "I need some expert guidance for building this AI agent. Could you request assistance for me?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Certainly! I understand that you need expert guidance for building an AI agent. This is a complex topic that would benefit from specialized knowledge. I'll use the RequestAssistance function to escalate your request to an expert who can provide more in-depth support.\", 'type': 'text'}, {'id': 'toolu_01LruhQDWhxozxHJ94qDndEF', 'input': {'request': 'The user needs expert guidance for building an AI agent. They are looking for specialized knowledge and support in this area.'}, 'name': 'RequestAssistance', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " RequestAssistance (toolu_01LruhQDWhxozxHJ94qDndEF)\n", - " Call ID: toolu_01LruhQDWhxozxHJ94qDndEF\n", - " Args:\n", - " request: The user needs expert guidance for building an AI agent. They are looking for specialized knowledge and support in this area.\n" - ] - } - ], - "source": [ - "user_input = \"I need some expert guidance for building this AI agent. Could you request assistance for me?\"\n", - "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", - "\n", - "events = graph.stream(\n", - " {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n", - ")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "ed2dd02e-f0a6-4f63-a7d6-e49ecf40db21", - "metadata": {}, - "source": [ - "We can respond as before, by constructing an appropriate `Command`:" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "a91f333b-8c4d-44cb-ae6a-0a5e8ed4f23b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Certainly! I understand that you need expert guidance for building an AI agent. This is a complex topic that would benefit from specialized knowledge. I'll use the RequestAssistance function to escalate your request to an expert who can provide more in-depth support.\", 'type': 'text'}, {'id': 'toolu_01LruhQDWhxozxHJ94qDndEF', 'input': {'request': 'The user needs expert guidance for building an AI agent. They are looking for specialized knowledge and support in this area.'}, 'name': 'RequestAssistance', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " RequestAssistance (toolu_01LruhQDWhxozxHJ94qDndEF)\n", - " Call ID: toolu_01LruhQDWhxozxHJ94qDndEF\n", - " Args:\n", - " request: The user needs expert guidance for building an AI agent. They are looking for specialized knowledge and support in this area.\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: RequestAssistance\n", - "\n", - "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Thank you for your patience. I've escalated your request, and an expert has provided some initial guidance. Here's what they recommend:\n", - "\n", - "The experts suggest that you look into LangGraph for building your AI agent. They mention that LangGraph is a more reliable and extensible option compared to simple autonomous agents.\n", - "\n", - "LangGraph is likely a framework or library designed specifically for creating advanced AI agents. It seems to offer benefits in terms of reliability and extensibility, which are crucial factors when developing complex AI systems.\n", - "\n", - "To follow up on this recommendation, you might want to:\n", - "\n", - "1. Research LangGraph to understand its features, capabilities, and how it compares to other agent-building frameworks.\n", - "2. Look for documentation, tutorials, or guides on how to get started with LangGraph.\n", - "3. Consider any specific requirements or goals you have for your AI agent and how LangGraph might address them.\n", - "\n", - "Do you have any specific questions about LangGraph or particular aspects of AI agent development that you'd like me to try to find more information about? I'd be happy to help you dig deeper into this topic.\n" - ] - } - ], - "source": [ - "human_response = (\n", - " \"We, the experts are here to help! We'd recommend you check out LangGraph to build your agent.\"\n", - " \" It's much more reliable and extensible than simple autonomous agents.\"\n", - ")\n", - "\n", - "human_command = Command(resume={\"action\": \"feedback\", \"data\": human_response})\n", - "\n", - "events = graph.stream(human_command, config, stream_mode=\"values\")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "79492363-7fc6-4ec7-977d-9030648029bc", - "metadata": {}, - "source": [ - "You can inspect the state to it's been flagged:" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "d2c94b9d-fbbd-4131-bd49-6c95d8c3708b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.get_state(config).values[\"ask_human\"]" - ] - }, - { - "cell_type": "markdown", - "id": "48e0559b-d653-4dab-8928-b001004d14cb", - "metadata": {}, - "source": [ - "**Notice** that the chat bot has incorporated the updated state in its final response. Since **everything** was checkpointed, the \"expert\" human in the loop could perform the update at any time without impacting the graph's execution.\n", + "**Congratulations!** You've added custom keys to the state to facilitate a more complex workflow, and learned how to generate state updates from inside tools.\n", "\n", "We're almost done with the tutorial, but there is one more concept we'd like to review before finishing that connects `checkpointing` and `state updates`. \n", "\n", "This section's code is reproduced below for your reference.\n", "\n", + "\n", "
\n", "Full Code\n", "
\n",
     "\n",
     "```python\n",
-    "from typing import Annotated, Literal\n",
+    "from typing import Annotated\n",
     "\n",
     "from langchain_anthropic import ChatAnthropic\n",
     "from langchain_community.tools.tavily_search import TavilySearchResults\n",
-    "from pydantic import BaseModel\n",
+    "from langchain_core.messages import ToolMessage\n",
+    "from langchain_core.tools import InjectedToolCallId, tool\n",
     "from typing_extensions import TypedDict\n",
     "\n",
     "from langgraph.checkpoint.memory import MemorySaver\n",
     "from langgraph.graph import StateGraph, START, END\n",
     "from langgraph.graph.message import add_messages\n",
-    "from langgraph.prebuilt import ToolNode\n",
+    "from langgraph.prebuilt import ToolNode, tools_condition\n",
     "from langgraph.types import Command, interrupt\n",
     "\n",
     "\n",
+    "\n",
     "class State(TypedDict):\n",
     "    messages: Annotated[list, add_messages]\n",
-    "    # This flag is new\n",
-    "    ask_human: bool\n",
+    "    name: str\n",
+    "    birthday: str\n",
     "\n",
     "\n",
-    "class RequestAssistance(BaseModel):\n",
-    "    \"\"\"Escalate the conversation to an expert. Use this if you are unable to assist directly or if the user requires support beyond your permissions.\n",
+    "@tool\n",
+    "def human_assistance(\n",
+    "    name: str, birthday: str, tool_call_id: Annotated[str, InjectedToolCallId]\n",
+    ") -> str:\n",
+    "    \"\"\"Request assistance from a human.\"\"\"\n",
+    "    human_response = interrupt(\n",
+    "        {\n",
+    "            \"question\": \"Is this correct?\",\n",
+    "            \"name\": name,\n",
+    "            \"birthday\": birthday,\n",
+    "        },\n",
+    "    )\n",
+    "    if human_response.get(\"correct\", \"\").lower().startswith(\"y\"):\n",
+    "        verified_name = name\n",
+    "        verified_birthday = birthday\n",
+    "        response = \"Correct\"\n",
+    "    else:\n",
+    "        verified_name = human_response.get(\"name\", name)\n",
+    "        verified_birthday = human_response.get(\"birthday\", birthday)\n",
+    "        response = f\"Made a correction: {human_response}\"\n",
     "\n",
-    "    To use this function, relay the user's 'request' so the expert can provide the right guidance.\n",
-    "    \"\"\"\n",
-    "\n",
-    "    request: str\n",
+    "    state_update = {\n",
+    "        \"name\": verified_name,\n",
+    "        \"birthday\": verified_birthday,\n",
+    "        \"messages\": [ToolMessage(response, tool_call_id=tool_call_id)],\n",
+    "    }\n",
+    "    return Command(update=state_update)\n",
     "\n",
     "\n",
     "tool = TavilySearchResults(max_results=2)\n",
-    "tools = [tool]\n",
+    "tools = [tool, human_assistance]\n",
     "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
-    "llm_with_tools = llm.bind_tools(tools + [RequestAssistance])\n",
+    "llm_with_tools = llm.bind_tools(tools)\n",
     "\n",
     "\n",
     "def chatbot(state: State):\n",
     "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
     "\n",
     "\n",
-    "def human_review_node(state: State) -> Command[Literal[\"chatbot\", \"tools\"]]:\n",
-    "    last_message = state[\"messages\"][-1]\n",
-    "    tool_call = last_message.tool_calls[-1]\n",
-    "\n",
-    "    if not tool_call[\"name\"] == RequestAssistance.__name__:\n",
-    "        return Command(goto=\"tools\")\n",
-    "\n",
-    "    human_review = interrupt(\n",
-    "        {\n",
-    "            \"question\": \"Is this correct?\",\n",
-    "            \"tool_call\": tool_call,\n",
-    "        }\n",
-    "    )\n",
-    "\n",
-    "    review_action = human_review[\"action\"]\n",
-    "    review_data = human_review.get(\"data\")\n",
-    "\n",
-    "    if review_action == \"continue\":\n",
-    "        return Command(goto=\"tools\", update={\"ask_human\": True})\n",
-    "\n",
-    "    elif review_action == \"feedback\":\n",
-    "        tool_message = {\n",
-    "            \"role\": \"tool\",\n",
-    "            \"content\": review_data,\n",
-    "            \"name\": tool_call[\"name\"],\n",
-    "            \"tool_call_id\": tool_call[\"id\"],\n",
-    "        }\n",
-    "        return Command(\n",
-    "            goto=\"chatbot\",\n",
-    "            update={\"messages\": [tool_message], \"ask_human\": True},\n",
-    "        )\n",
-    "\n",
-    "\n",
-    "def route_after_llm(state) -> Literal[END, \"human_review_node\"]:\n",
-    "    if len(state[\"messages\"][-1].tool_calls) == 0:\n",
-    "        return END\n",
-    "    else:\n",
-    "        return \"human_review_node\"\n",
-    "\n",
-    "\n",
     "graph_builder = StateGraph(State)\n",
+    "graph_builder.add_node(\"chatbot\", chatbot)\n",
     "\n",
-    "graph_builder.add_node(chatbot)\n",
-    "\n",
-    "tool_node = ToolNode(tools=[tool])\n",
+    "tool_node = ToolNode(tools=tools)\n",
     "graph_builder.add_node(\"tools\", tool_node)\n",
-    "graph_builder.add_node(human_review_node)\n",
     "\n",
     "graph_builder.add_conditional_edges(\n",
     "    \"chatbot\",\n",
-    "    route_after_llm,\n",
+    "    tools_condition,\n",
     ")\n",
     "graph_builder.add_edge(\"tools\", \"chatbot\")\n",
     "graph_builder.add_edge(START, \"chatbot\")\n",
@@ -3010,7 +1999,7 @@
    "source": [
     "## Part 7: Time Travel\n",
     "\n",
-    "In a typical chat bot workflow, the user interacts with the bot 1 or more times to accomplish a task. In the previous sections, we saw how to add memory and a human-in-the-loop to be able to checkpoint our graph state and manually override the state to control future responses.\n",
+    "In a typical chat bot workflow, the user interacts with the bot 1 or more times to accomplish a task. In the previous sections, we saw how to add memory and a human-in-the-loop to be able to checkpoint our graph state and control future responses.\n",
     "\n",
     "But what if you want to let your user start from a previous response and \"branch off\" to explore a separate outcome? Or what if you want users to be able to \"rewind\" your assistant's work to fix some mistakes or try a different strategy (common in applications like autonomous software engineers)?\n",
     "\n",
@@ -3018,106 +2007,54 @@
     "\n",
     "In this section, you will \"rewind\" your graph by fetching a checkpoint using the graph's `get_state_history` method. You can then resume execution at this previous point in time.\n",
     "\n",
-    "First, recall our chatbot graph. We don't need to make **any** changes from before:"
+    "For this, let's use the simple chatbot with tools from [Part 3](#part-3-adding-memory-to-the-chatbot):"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": 10,
    "id": "bb8a02de-a21b-4ef6-a714-7d6e44435e3a",
    "metadata": {},
    "outputs": [],
    "source": [
-    "from typing import Annotated, Literal\n",
+    "from typing import Annotated\n",
     "\n",
     "from langchain_anthropic import ChatAnthropic\n",
     "from langchain_community.tools.tavily_search import TavilySearchResults\n",
-    "from pydantic import BaseModel\n",
+    "from langchain_core.messages import BaseMessage\n",
     "from typing_extensions import TypedDict\n",
     "\n",
     "from langgraph.checkpoint.memory import MemorySaver\n",
     "from langgraph.graph import StateGraph, START, END\n",
     "from langgraph.graph.message import add_messages\n",
-    "from langgraph.prebuilt import ToolNode\n",
-    "from langgraph.types import Command, interrupt\n",
+    "from langgraph.prebuilt import ToolNode, tools_condition\n",
     "\n",
     "\n",
     "class State(TypedDict):\n",
     "    messages: Annotated[list, add_messages]\n",
-    "    # This flag is new\n",
-    "    ask_human: bool\n",
     "\n",
     "\n",
-    "class RequestAssistance(BaseModel):\n",
-    "    \"\"\"Escalate the conversation to an expert. Use this if you are unable to assist directly or if the user requires support beyond your permissions.\n",
-    "\n",
-    "    To use this function, relay the user's 'request' so the expert can provide the right guidance.\n",
-    "    \"\"\"\n",
-    "\n",
-    "    request: str\n",
+    "graph_builder = StateGraph(State)\n",
     "\n",
     "\n",
     "tool = TavilySearchResults(max_results=2)\n",
     "tools = [tool]\n",
     "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
-    "llm_with_tools = llm.bind_tools(tools + [RequestAssistance])\n",
+    "llm_with_tools = llm.bind_tools(tools)\n",
     "\n",
     "\n",
     "def chatbot(state: State):\n",
     "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
     "\n",
     "\n",
-    "def human_review_node(state: State) -> Command[Literal[\"chatbot\", \"tools\"]]:\n",
-    "    last_message = state[\"messages\"][-1]\n",
-    "    tool_call = last_message.tool_calls[-1]\n",
-    "\n",
-    "    if not tool_call[\"name\"] == RequestAssistance.__name__:\n",
-    "        return Command(goto=\"tools\")\n",
-    "\n",
-    "    human_review = interrupt(\n",
-    "        {\n",
-    "            \"question\": \"Is this correct?\",\n",
-    "            \"tool_call\": tool_call,\n",
-    "        }\n",
-    "    )\n",
-    "\n",
-    "    review_action = human_review[\"action\"]\n",
-    "    review_data = human_review.get(\"data\")\n",
-    "\n",
-    "    if review_action == \"continue\":\n",
-    "        return Command(goto=\"tools\", update={\"ask_human\": True})\n",
-    "\n",
-    "    elif review_action == \"feedback\":\n",
-    "        tool_message = {\n",
-    "            \"role\": \"tool\",\n",
-    "            \"content\": review_data,\n",
-    "            \"name\": tool_call[\"name\"],\n",
-    "            \"tool_call_id\": tool_call[\"id\"],\n",
-    "        }\n",
-    "        return Command(\n",
-    "            goto=\"chatbot\",\n",
-    "            update={\"messages\": [tool_message], \"ask_human\": True},\n",
-    "        )\n",
-    "\n",
-    "\n",
-    "def route_after_llm(state) -> Literal[END, \"human_review_node\"]:\n",
-    "    if len(state[\"messages\"][-1].tool_calls) == 0:\n",
-    "        return END\n",
-    "    else:\n",
-    "        return \"human_review_node\"\n",
-    "\n",
-    "\n",
-    "graph_builder = StateGraph(State)\n",
-    "\n",
-    "graph_builder.add_node(chatbot)\n",
+    "graph_builder.add_node(\"chatbot\", chatbot)\n",
     "\n",
     "tool_node = ToolNode(tools=[tool])\n",
     "graph_builder.add_node(\"tools\", tool_node)\n",
-    "graph_builder.add_node(human_review_node)\n",
     "\n",
     "graph_builder.add_conditional_edges(\n",
     "    \"chatbot\",\n",
-    "    route_after_llm,\n",
+    "    tools_condition,\n",
     ")\n",
     "graph_builder.add_edge(\"tools\", \"chatbot\")\n",
     "graph_builder.add_edge(START, \"chatbot\")\n",
@@ -3126,33 +2063,6 @@
     "graph = graph_builder.compile(checkpointer=memory)"
    ]
   },
-  {
-   "cell_type": "code",
-   "execution_count": 2,
-   "id": "88faedd2-d12f-4084-9942-491f5ad8e6e7",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "image/png": "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",
-      "text/plain": [
-       ""
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    }
-   ],
-   "source": [
-    "from IPython.display import Image, display\n",
-    "\n",
-    "try:\n",
-    "    display(Image(graph.get_graph().draw_mermaid_png()))\n",
-    "except Exception:\n",
-    "    # This requires some extra dependencies and is optional\n",
-    "    pass"
-   ]
-  },
   {
    "cell_type": "markdown",
    "id": "5414c482-215e-4cc0-9eef-4a8722d2f468",
@@ -3163,7 +2073,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 11,
    "id": "69071b02-c011-4b7f-90b1-8e89e032322d",
    "metadata": {},
    "outputs": [
@@ -3176,44 +2086,48 @@
       "I'm learning LangGraph. Could you do some research on it for me?\n",
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "[{'text': \"Certainly! I'd be happy to help you research LangGraph. To provide you with the most up-to-date and accurate information, I'll use the Tavily search engine to gather some data for you. Let me do that now.\", 'type': 'text'}, {'id': 'toolu_01FuxELYf5Jn1iXcEeduiTDs', 'input': {'query': 'LangGraph framework for language models'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n",
+      "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and accurate information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01BscbfJJB9EWJFqGrN6E54e', 'input': {'query': 'LangGraph latest information and features'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n",
       "Tool Calls:\n",
-      "  tavily_search_results_json (toolu_01FuxELYf5Jn1iXcEeduiTDs)\n",
-      " Call ID: toolu_01FuxELYf5Jn1iXcEeduiTDs\n",
+      "  tavily_search_results_json (toolu_01BscbfJJB9EWJFqGrN6E54e)\n",
+      " Call ID: toolu_01BscbfJJB9EWJFqGrN6E54e\n",
       "  Args:\n",
-      "    query: LangGraph framework for language models\n",
+      "    query: LangGraph latest information and features\n",
       "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
       "Name: tavily_search_results_json\n",
       "\n",
-      "[{\"url\": \"https://www.datacamp.com/tutorial/langgraph-tutorial\", \"content\": \"LangGraph provides a framework for defining, coordinating, and executing multiple LLM agents (or chains) in a structured manner. ... LangChain is a framework for including AI from large language models inside data pipelines and applications. This tutorial provides an overview of what you can do with LangChain, including the problems that\"}, {\"url\": \"https://www.langchain.com/langgraph\", \"content\": \"No. LangGraph is an orchestration framework for complex agentic systems and is more low-level and controllable than LangChain agents. LangChain provides a standard interface to interact with models and other components, useful for straight-forward chains and retrieval flows.\"}]\n",
+      "[{\"url\": \"https://blockchain.news/news/langchain-new-features-upcoming-events-update\", \"content\": \"LangChain, a leading platform in the AI development space, has released its latest updates, showcasing new use cases and enhancements across its ecosystem. According to the LangChain Blog, the updates cover advancements in LangGraph Cloud, LangSmith's self-improving evaluators, and revamped documentation for LangGraph.\"}, {\"url\": \"https://blog.langchain.dev/langgraph-platform-announce/\", \"content\": \"With these learnings under our belt, we decided to couple some of our latest offerings under LangGraph Platform. LangGraph Platform today includes LangGraph Server, LangGraph Studio, plus the CLI and SDK. ... we added features in LangGraph Server to deliver on a few key value areas. Below, we'll focus on these aspects of LangGraph Platform.\"}]\n",
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "Thank you for your patience. I've gathered some information about LangGraph for you. Let me summarize the key points:\n",
+      "Thank you for your patience. I've found some recent information about LangGraph for you. Let me summarize the key points:\n",
       "\n",
-      "1. Purpose:\n",
-      "   LangGraph is a framework designed for defining, coordinating, and executing multiple Language Model (LLM) agents or chains in a structured manner.\n",
+      "1. LangGraph is part of the LangChain ecosystem, which is a leading platform in AI development.\n",
       "\n",
-      "2. Relation to LangChain:\n",
-      "   While LangGraph and LangChain are related, they serve different purposes:\n",
-      "   - LangChain is a framework for integrating AI from large language models into data pipelines and applications.\n",
-      "   - LangGraph is more focused on orchestrating complex agentic systems.\n",
+      "2. Recent updates and features of LangGraph include:\n",
       "\n",
-      "3. Level of Control:\n",
-      "   LangGraph is described as more low-level and controllable compared to LangChain agents. This suggests that it offers more fine-grained control over the interaction between different components in a language model system.\n",
+      "   a. LangGraph Cloud: This seems to be a cloud-based version of LangGraph, though specific details weren't provided in the search results.\n",
       "\n",
-      "4. Use Cases:\n",
-      "   LangGraph seems particularly useful for scenarios where you need to coordinate multiple AI agents or create more complex workflows involving language models.\n",
+      "   b. LangGraph Platform: This is a newly introduced concept that combines several offerings:\n",
+      "      - LangGraph Server\n",
+      "      - LangGraph Studio\n",
+      "      - CLI (Command Line Interface)\n",
+      "      - SDK (Software Development Kit)\n",
       "\n",
-      "5. Comparison to LangChain Agents:\n",
-      "   While LangChain provides a standard interface for interacting with models and components (useful for straightforward chains and retrieval flows), LangGraph appears to be more suited for building and managing more complex, multi-agent systems.\n",
+      "3. LangGraph Server: This component has received new features to enhance its value proposition, though the specific features weren't detailed in the search results.\n",
       "\n",
-      "If you're learning LangGraph, it might be helpful to understand:\n",
-      "1. How to define and structure multiple agents or chains\n",
-      "2. The ways to coordinate these agents in a cohesive system\n",
-      "3. The types of complex workflows you can create with LangGraph\n",
-      "4. How it differs from and complements LangChain in practical applications\n",
+      "4. LangGraph Studio: This appears to be a new tool in the LangGraph ecosystem, likely providing a graphical interface for working with LangGraph.\n",
       "\n",
-      "Would you like me to search for more specific information about any particular aspect of LangGraph, such as its key features, getting started guides, or specific use cases?\n"
+      "5. Documentation: The LangGraph documentation has been revamped, which should make it easier for learners like yourself to understand and use the tool.\n",
+      "\n",
+      "6. Integration with LangSmith: While not directly part of LangGraph, LangSmith (another tool in the LangChain ecosystem) now features self-improving evaluators, which might be relevant if you're using LangGraph as part of a larger LangChain project.\n",
+      "\n",
+      "As you're learning LangGraph, it would be beneficial to:\n",
+      "\n",
+      "1. Check out the official LangChain documentation, especially the newly revamped LangGraph sections.\n",
+      "2. Explore the different components of the LangGraph Platform (Server, Studio, CLI, and SDK) to see which best fits your learning needs.\n",
+      "3. Keep an eye on LangGraph Cloud developments, as cloud-based solutions often provide an easier starting point for learners.\n",
+      "4. Consider how LangGraph fits into the broader LangChain ecosystem, especially its interaction with tools like LangSmith.\n",
+      "\n",
+      "Is there any specific aspect of LangGraph you'd like to know more about? I'd be happy to do a more focused search on particular features or use cases.\n"
      ]
     }
    ],
@@ -3235,7 +2149,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 12,
    "id": "acbec099-e5d2-497f-929e-c548d7bcbf77",
    "metadata": {},
    "outputs": [
@@ -3248,56 +2162,47 @@
       "Ya that's helpful. Maybe I'll build an autonomous agent with it!\n",
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "[{'text': \"That's an exciting idea! Building an autonomous agent with LangGraph could be a great way to dive deep into the framework and explore its capabilities. LangGraph's focus on orchestrating complex agentic systems makes it well-suited for such a project. Let me gather some more specific information about using LangGraph for building autonomous agents.\", 'type': 'text'}, {'id': 'toolu_01TeAyyVo8fYBYApftT7yjTS', 'input': {'query': 'Building autonomous agents with LangGraph examples and tutorials'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n",
+      "[{'text': \"That's an exciting idea! Building an autonomous agent with LangGraph is indeed a great application of this technology. LangGraph is particularly well-suited for creating complex, multi-step AI workflows, which is perfect for autonomous agents. Let me gather some more specific information about using LangGraph for building autonomous agents.\", 'type': 'text'}, {'id': 'toolu_01QWNHhUaeeWcGXvA4eHT7Zo', 'input': {'query': 'Building autonomous agents with LangGraph examples and tutorials'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n",
       "Tool Calls:\n",
-      "  tavily_search_results_json (toolu_01TeAyyVo8fYBYApftT7yjTS)\n",
-      " Call ID: toolu_01TeAyyVo8fYBYApftT7yjTS\n",
+      "  tavily_search_results_json (toolu_01QWNHhUaeeWcGXvA4eHT7Zo)\n",
+      " Call ID: toolu_01QWNHhUaeeWcGXvA4eHT7Zo\n",
       "  Args:\n",
       "    query: Building autonomous agents with LangGraph examples and tutorials\n",
       "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
       "Name: tavily_search_results_json\n",
       "\n",
-      "[{\"url\": \"https://towardsdatascience.com/building-autonomous-multi-tool-agents-with-gemini-2-0-and-langgraph-ad3d7bd5e79d\", \"content\": \"Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph | by Youness Mansar | Jan, 2025 | Towards Data Science Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph A practical tutorial with full code examples for building and running multi-tool agents Towards Data Science LLMs are remarkable — they can memorize vast amounts of information, answer general knowledge questions, write code, generate stories, and even fix your grammar. In this tutorial, we are going to build a simple LLM agent that is equipped with four tools that it can use to answer a user’s question. This Agent will have the following specifications: Follow Published in Towards Data Science --------------------------------- Your home for data science and AI. Follow Follow Follow\"}, {\"url\": \"https://blog.futuresmart.ai/langgraph-agent-with-rag-and-nl2sql\", \"content\": \"In this blog post, we will walk you through the process of creating a custom AI agent with three powerful tools: Web Search, Retrieval-Augmented Generation (RAG), and Natural Language to SQL (NL2SQL), all integrated within the LangGraph framework. This guide is designed to provide you with a practical, step-by-step approach to building a fully functional AI agent capable of performing complex tasks such as retrieving real-time data from the web, generating responses based on retrieved information from the knowledge base, and translating natural language queries into SQL database queries. By following this tutorial, you've built an AI agent capable of performing diverse tasks such as retrieving real-time data, answering questions based on document-based knowledge, and executing SQL queries directly from natural language commands.\"}]\n",
+      "[{\"url\": \"https://towardsdatascience.com/building-autonomous-multi-tool-agents-with-gemini-2-0-and-langgraph-ad3d7bd5e79d\", \"content\": \"Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph | by Youness Mansar | Jan, 2025 | Towards Data Science Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph A practical tutorial with full code examples for building and running multi-tool agents Towards Data Science LLMs are remarkable — they can memorize vast amounts of information, answer general knowledge questions, write code, generate stories, and even fix your grammar. In this tutorial, we are going to build a simple LLM agent that is equipped with four tools that it can use to answer a user’s question. This Agent will have the following specifications: Follow Published in Towards Data Science --------------------------------- Your home for data science and AI. Follow Follow Follow\"}, {\"url\": \"https://github.com/anmolaman20/Tools_and_Agents\", \"content\": \"GitHub - anmolaman20/Tools_and_Agents: This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository serves as a comprehensive guide for building AI-powered agents using Langchain and Langgraph. It provides hands-on examples, practical tutorials, and resources for developers and AI enthusiasts to master building intelligent systems and workflows. AI Agent Development: Gain insights into creating intelligent systems that think, reason, and adapt in real time. This repository is ideal for AI practitioners, developers exploring language models, or anyone interested in building intelligent systems. This repository provides resources for building AI agents using Langchain and Langgraph.\"}]\n",
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "Thank you for sharing your interest in building an autonomous agent with LangGraph! That's an excellent way to learn and apply the framework. Based on the information I've gathered, I can provide you with some insights and guidance on how to approach this project:\n",
+      "Great idea! Building an autonomous agent with LangGraph is definitely an exciting project. Based on the latest information I've found, here are some insights and tips for building autonomous agents with LangGraph:\n",
       "\n",
-      "1. Multi-Tool Agents:\n",
-      "   LangGraph allows you to create autonomous agents that can use multiple tools. This is particularly powerful for creating versatile agents that can handle a variety of tasks.\n",
+      "1. Multi-Tool Agents: LangGraph is particularly well-suited for creating autonomous agents that can use multiple tools. This allows your agent to have a diverse set of capabilities and choose the right tool for each task.\n",
       "\n",
-      "2. Integration with Advanced Language Models:\n",
-      "   There's an example of building autonomous multi-tool agents using Gemini 2.0 (Google's advanced language model) and LangGraph. This suggests that LangGraph is compatible with state-of-the-art language models, which can enhance your agent's capabilities.\n",
+      "2. Integration with Large Language Models (LLMs): You can combine LangGraph with powerful LLMs like Gemini 2.0 to create more intelligent and capable agents. The LLM can serve as the \"brain\" of your agent, making decisions and generating responses.\n",
       "\n",
-      "3. Practical Tutorial Available:\n",
-      "   There's a practical tutorial available with full code examples for building and running multi-tool agents. This could be an excellent starting point for your project.\n",
+      "3. Workflow Management: LangGraph excels at managing complex, multi-step AI workflows. This is crucial for autonomous agents that need to break down tasks into smaller steps and execute them in the right order.\n",
       "\n",
-      "4. Diverse Tool Integration:\n",
-      "   You can equip your agent with various tools. For example, one tutorial mentions creating an agent with four different tools to answer user questions.\n",
+      "4. Practical Tutorials Available: There are tutorials available that provide full code examples for building and running multi-tool agents. These can be incredibly helpful as you start your project.\n",
       "\n",
-      "5. Complex Task Handling:\n",
-      "   LangGraph enables the creation of agents capable of performing complex tasks such as:\n",
-      "   - Web searching for real-time data retrieval\n",
-      "   - Implementing Retrieval-Augmented Generation (RAG) for enhanced knowledge access\n",
-      "   - Using Natural Language to SQL (NL2SQL) for database interactions\n",
+      "5. Langchain Integration: LangGraph is often used in conjunction with Langchain. This combination provides a powerful framework for building AI agents, offering features like memory management, tool integration, and prompt management.\n",
       "\n",
-      "6. Step-by-Step Guides:\n",
-      "   There are resources available that provide step-by-step approaches to building fully functional AI agents using LangGraph.\n",
+      "6. GitHub Resources: There are repositories available (like the one by anmolaman20) that provide comprehensive resources for building AI agents using Langchain and LangGraph. These can be valuable references as you develop your agent.\n",
       "\n",
-      "7. Versatile Applications:\n",
-      "   Your autonomous agent could potentially handle tasks like:\n",
-      "   - Answering questions based on retrieved information from a knowledge base\n",
-      "   - Executing SQL queries from natural language commands\n",
-      "   - Performing web searches and integrating the results into responses\n",
+      "7. Real-time Adaptation: LangGraph allows you to create agents that can think, reason, and adapt in real-time, which is crucial for truly autonomous behavior.\n",
       "\n",
-      "To get started with your project, you might want to:\n",
+      "8. Customization: You can equip your agent with specific tools tailored to your use case. For example, you might include tools for web searching, data analysis, or interacting with specific APIs.\n",
       "\n",
-      "1. Familiarize yourself with the LangGraph documentation and basic concepts.\n",
-      "2. Follow one of the available tutorials to build a simple multi-tool agent.\n",
-      "3. Define the specific tasks and capabilities you want your autonomous agent to have.\n",
-      "4. Incrementally add and test new tools and functionalities to your agent.\n",
-      "5. Experiment with different language models to see which works best for your use case.\n",
+      "To get started with your autonomous agent project:\n",
       "\n",
-      "Would you like more information on any specific aspect of building your autonomous agent with LangGraph, such as setting up the environment, choosing tools, or handling particular types of tasks?\n"
+      "1. Familiarize yourself with LangGraph's documentation and basic concepts.\n",
+      "2. Look into tutorials that specifically deal with building autonomous agents, like the one mentioned from Towards Data Science.\n",
+      "3. Decide on the specific capabilities you want your agent to have and identify the tools it will need.\n",
+      "4. Start with a simple agent and gradually add complexity as you become more comfortable with the framework.\n",
+      "5. Experiment with different LLMs to find the one that works best for your use case.\n",
+      "6. Pay attention to how you structure the agent's decision-making process and workflow.\n",
+      "7. Don't forget to implement proper error handling and safety measures, especially if your agent will be interacting with external systems or making important decisions.\n",
+      "\n",
+      "Building an autonomous agent is an iterative process, so be prepared to refine and improve your agent over time. Good luck with your project! If you need any more specific information as you progress, feel free to ask.\n"
      ]
     }
    ],
@@ -3326,8 +2231,8 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
-   "id": "c3e5875d-5612-41cb-8109-9a45f0282783",
+   "execution_count": 13,
+   "id": "40953570-66bd-45b9-9469-1d018230d88a",
    "metadata": {},
    "outputs": [
     {
@@ -3340,8 +2245,6 @@
       "--------------------------------------------------------------------------------\n",
       "Num Messages:  6 Next:  ('tools',)\n",
       "--------------------------------------------------------------------------------\n",
-      "Num Messages:  6 Next:  ('human_review_node',)\n",
-      "--------------------------------------------------------------------------------\n",
       "Num Messages:  5 Next:  ('chatbot',)\n",
       "--------------------------------------------------------------------------------\n",
       "Num Messages:  4 Next:  ('__start__',)\n",
@@ -3352,8 +2255,6 @@
       "--------------------------------------------------------------------------------\n",
       "Num Messages:  2 Next:  ('tools',)\n",
       "--------------------------------------------------------------------------------\n",
-      "Num Messages:  2 Next:  ('human_review_node',)\n",
-      "--------------------------------------------------------------------------------\n",
       "Num Messages:  1 Next:  ('chatbot',)\n",
       "--------------------------------------------------------------------------------\n",
       "Num Messages:  0 Next:  ('__start__',)\n",
@@ -3383,7 +2284,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 14,
    "id": "fdcf00af-8459-4132-85cc-742199391d4f",
    "metadata": {},
    "outputs": [
@@ -3391,8 +2292,8 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "('human_review_node',)\n",
-      "{'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1efd3840-87a4-6760-8007-bd412fc24064'}}\n"
+      "('tools',)\n",
+      "{'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1efd43e3-0c1f-6c4e-8006-891877d65740'}}\n"
      ]
     }
    ],
@@ -3411,7 +2312,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 15,
    "id": "c5382e81-bfcd-4508-b02a-099e3d9627fd",
    "metadata": {},
    "outputs": [
@@ -3421,10 +2322,10 @@
      "text": [
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "[{'text': \"That's an exciting idea! Building an autonomous agent with LangGraph could be a great way to dive deep into the framework and explore its capabilities. LangGraph's focus on orchestrating complex agentic systems makes it well-suited for such a project. Let me gather some more specific information about using LangGraph for building autonomous agents.\", 'type': 'text'}, {'id': 'toolu_01TeAyyVo8fYBYApftT7yjTS', 'input': {'query': 'Building autonomous agents with LangGraph examples and tutorials'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n",
+      "[{'text': \"That's an exciting idea! Building an autonomous agent with LangGraph is indeed a great application of this technology. LangGraph is particularly well-suited for creating complex, multi-step AI workflows, which is perfect for autonomous agents. Let me gather some more specific information about using LangGraph for building autonomous agents.\", 'type': 'text'}, {'id': 'toolu_01QWNHhUaeeWcGXvA4eHT7Zo', 'input': {'query': 'Building autonomous agents with LangGraph examples and tutorials'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n",
       "Tool Calls:\n",
-      "  tavily_search_results_json (toolu_01TeAyyVo8fYBYApftT7yjTS)\n",
-      " Call ID: toolu_01TeAyyVo8fYBYApftT7yjTS\n",
+      "  tavily_search_results_json (toolu_01QWNHhUaeeWcGXvA4eHT7Zo)\n",
+      " Call ID: toolu_01QWNHhUaeeWcGXvA4eHT7Zo\n",
       "  Args:\n",
       "    query: Building autonomous agents with LangGraph examples and tutorials\n",
       "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
@@ -3433,37 +2334,39 @@
       "[{\"url\": \"https://towardsdatascience.com/building-autonomous-multi-tool-agents-with-gemini-2-0-and-langgraph-ad3d7bd5e79d\", \"content\": \"Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph | by Youness Mansar | Jan, 2025 | Towards Data Science Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph A practical tutorial with full code examples for building and running multi-tool agents Towards Data Science LLMs are remarkable — they can memorize vast amounts of information, answer general knowledge questions, write code, generate stories, and even fix your grammar. In this tutorial, we are going to build a simple LLM agent that is equipped with four tools that it can use to answer a user’s question. This Agent will have the following specifications: Follow Published in Towards Data Science --------------------------------- Your home for data science and AI. Follow Follow Follow\"}, {\"url\": \"https://github.com/anmolaman20/Tools_and_Agents\", \"content\": \"GitHub - anmolaman20/Tools_and_Agents: This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository serves as a comprehensive guide for building AI-powered agents using Langchain and Langgraph. It provides hands-on examples, practical tutorials, and resources for developers and AI enthusiasts to master building intelligent systems and workflows. AI Agent Development: Gain insights into creating intelligent systems that think, reason, and adapt in real time. This repository is ideal for AI practitioners, developers exploring language models, or anyone interested in building intelligent systems. This repository provides resources for building AI agents using Langchain and Langgraph.\"}]\n",
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "Great idea! Building an autonomous agent with LangGraph can be an excellent way to learn the framework and explore its capabilities. Based on the information I've found, here are some insights and resources that could help you get started:\n",
+      "Great idea! Building an autonomous agent with LangGraph is indeed an excellent way to apply and deepen your understanding of the technology. Based on the search results, I can provide you with some insights and resources to help you get started:\n",
       "\n",
       "1. Multi-Tool Agents:\n",
       "   LangGraph is well-suited for building autonomous agents that can use multiple tools. This allows your agent to have a variety of capabilities and choose the appropriate tool based on the task at hand.\n",
       "\n",
-      "2. Integration with Other Technologies:\n",
-      "   There's an example of building autonomous multi-tool agents using LangGraph in combination with Gemini 2.0 (Google's large language model). This suggests that LangGraph can be integrated with various LLMs and tools to create powerful agents.\n",
+      "2. Integration with Large Language Models (LLMs):\n",
+      "   There's a tutorial that specifically mentions using Gemini 2.0 (Google's LLM) with LangGraph to build autonomous agents. This suggests that LangGraph can be integrated with various LLMs, giving you flexibility in choosing the language model that best fits your needs.\n",
       "\n",
       "3. Practical Tutorials:\n",
-      "   There are tutorials available that provide full code examples for building and running multi-tool agents. These can be extremely helpful as you start your project.\n",
+      "   There are tutorials available that provide full code examples for building and running multi-tool agents. These can be invaluable as you start your project, giving you a concrete starting point and demonstrating best practices.\n",
       "\n",
       "4. GitHub Resources:\n",
-      "   There's a GitHub repository (by user anmolaman20) that provides resources for building AI agents using both LangChain and LangGraph. This could be a valuable reference as you develop your agent.\n",
+      "   There's a GitHub repository (github.com/anmolaman20/Tools_and_Agents) that provides resources for building AI agents using both Langchain and Langgraph. This could be a great resource for code examples, tutorials, and understanding how LangGraph fits into the broader LangChain ecosystem.\n",
       "\n",
-      "5. Capabilities:\n",
-      "   The agents you can build with LangGraph can potentially memorize information, answer questions, write code, generate stories, and perform various other tasks depending on how you design them and what tools you integrate.\n",
+      "5. Real-Time Adaptation:\n",
+      "   The resources mention creating intelligent systems that can think, reason, and adapt in real-time. This is a key feature of advanced autonomous agents and something you can aim for in your project.\n",
       "\n",
-      "6. Real-Time Adaptation:\n",
-      "   LangGraph seems to support building agents that can think, reason, and adapt in real-time, which is crucial for truly autonomous behavior.\n",
+      "6. Diverse Applications:\n",
+      "   The materials suggest that these techniques can be applied to various tasks, from answering questions to potentially more complex decision-making processes.\n",
       "\n",
-      "To get started with your project, you might want to:\n",
+      "To get started with your autonomous agent project using LangGraph, you might want to:\n",
       "\n",
-      "1. Set up your development environment with LangGraph and any necessary dependencies.\n",
-      "2. Start with a simple agent that uses one or two tools, then gradually increase complexity.\n",
-      "3. Explore the GitHub resources and tutorials to understand best practices and common patterns in building autonomous agents with LangGraph.\n",
-      "4. Consider what specific tasks or domains you want your agent to specialize in, and research appropriate tools or APIs to integrate.\n",
-      "5. Experiment with different LLMs to find the one that best suits your agent's needs.\n",
+      "1. Review the tutorials mentioned, especially those with full code examples.\n",
+      "2. Explore the GitHub repository for hands-on examples and resources.\n",
+      "3. Decide on the specific tasks or capabilities you want your agent to have.\n",
+      "4. Choose an LLM to integrate with LangGraph (like GPT, Gemini, or others).\n",
+      "5. Start with a simple agent that uses one or two tools, then gradually expand its capabilities.\n",
+      "6. Implement decision-making logic to help your agent choose between different tools or actions.\n",
+      "7. Test your agent thoroughly with various inputs and scenarios to ensure robust performance.\n",
       "\n",
-      "Remember to consider ethical implications and potential limitations as you develop your autonomous agent. It's important to build in safeguards and ensure your agent behaves responsibly.\n",
+      "Remember, building an autonomous agent is an iterative process. Start simple and gradually increase complexity as you become more comfortable with LangGraph and its capabilities.\n",
       "\n",
-      "Would you like more information on any specific aspect of building your autonomous agent with LangGraph, such as setting up the environment, choosing tools, or designing the agent's decision-making process?\n"
+      "Would you like more information on any specific aspect of building your autonomous agent with LangGraph?\n"
      ]
     }
    ],

From d978cb039291f779459754edfa1f6edb45026437 Mon Sep 17 00:00:00 2001
From: Chester Curme 
Date: Thu, 16 Jan 2025 14:21:40 -0500
Subject: [PATCH 05/15] part 7 -> part 6

---
 docs/docs/tutorials/introduction.ipynb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/docs/tutorials/introduction.ipynb b/docs/docs/tutorials/introduction.ipynb
index 6f248e5da..9c474eaa8 100644
--- a/docs/docs/tutorials/introduction.ipynb
+++ b/docs/docs/tutorials/introduction.ipynb
@@ -1997,7 +1997,7 @@
    "id": "05283db2-2f26-4800-8eda-78a4468a3d8f",
    "metadata": {},
    "source": [
-    "## Part 7: Time Travel\n",
+    "## Part 6: Time Travel\n",
     "\n",
     "In a typical chat bot workflow, the user interacts with the bot 1 or more times to accomplish a task. In the previous sections, we saw how to add memory and a human-in-the-loop to be able to checkpoint our graph state and control future responses.\n",
     "\n",

From 93854ed7217ca576624b8045baacfcb2f164b50e Mon Sep 17 00:00:00 2001
From: Chester Curme 
Date: Thu, 16 Jan 2025 15:12:53 -0500
Subject: [PATCH 06/15] fix link

---
 docs/docs/tutorials/introduction.ipynb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/docs/tutorials/introduction.ipynb b/docs/docs/tutorials/introduction.ipynb
index 9c474eaa8..cc14e5cb4 100644
--- a/docs/docs/tutorials/introduction.ipynb
+++ b/docs/docs/tutorials/introduction.ipynb
@@ -1897,7 +1897,7 @@
    "id": "ab34ef46-a836-4dbd-b1ae-56c5e8dc75af",
    "metadata": {},
    "source": [
-    "Manual state updates will even [generate a trace](https://smith.langchain.com/public/7ebb7827-378d-49fe-9f6c-5df0e90086c8/r) in LangSmith. If desired, they can also be used to control human-in-the-loop workflows, as described in [this guide](how-tos/human_in_the_loop/edit-graph-state/). Use of the `interrupt` function is generally recommended instead, as it allows data to be transmitted in a human-in-the-loop interaction independently of state updates.\n",
+    "Manual state updates will even [generate a trace](https://smith.langchain.com/public/7ebb7827-378d-49fe-9f6c-5df0e90086c8/r) in LangSmith. If desired, they can also be used to control human-in-the-loop workflows, as described in [this guide](../../how-tos/human_in_the_loop/edit-graph-state/). Use of the `interrupt` function is generally recommended instead, as it allows data to be transmitted in a human-in-the-loop interaction independently of state updates.\n",
     "\n",
     "**Congratulations!** You've added custom keys to the state to facilitate a more complex workflow, and learned how to generate state updates from inside tools.\n",
     "\n",

From cc397b16295aaa3556e9ff8470a1ec4f3910ad60 Mon Sep 17 00:00:00 2001
From: Chester Curme 
Date: Thu, 16 Jan 2025 16:22:31 -0500
Subject: [PATCH 07/15] update cassettes

---
 ...troduction_03a09bfc-3d90-4e54-878f-22e3cb28a418.msgpack.zlib | 2 +-
 ...troduction_051dc374-67cc-4371-9dd1-221e07593148.msgpack.zlib | 2 +-
 ...troduction_11d5b934-6d8b-4f52-a3bc-b3daa7207e00.msgpack.zlib | 2 +-
 ...troduction_32e4f36e-72ce-4ade-bd7e-94880e0d456b.msgpack.zlib | 1 -
 ...troduction_35c8978e-c07d-4dd0-a97b-0ce3a723eea5.msgpack.zlib | 2 +-
 ...troduction_4527cf9a-b191-4bde-858a-e33a74a48c55.msgpack.zlib | 2 +-
 ...troduction_69071b02-c011-4b7f-90b1-8e89e032322d.msgpack.zlib | 2 +-
 ...troduction_6a385b06-8d34-4a2d-aded-1cf4bb0ca590.msgpack.zlib | 2 +-
 ...troduction_6b32914d-4d60-491f-8e11-1e6867e38ffd.msgpack.zlib | 2 +-
 ...troduction_761d15fb-d5e2-4d50-a630-126d77e77294.msgpack.zlib | 1 -
 ...troduction_85f17be3-eaf6-495e-a846-49436916b4ab.msgpack.zlib | 1 -
 ...troduction_8b49509c-9d97-457c-a76a-c495fb30ccbc.msgpack.zlib | 1 -
 ...troduction_9f318020-ab7e-415b-a5e2-eddec6d9f3a6.msgpack.zlib | 2 +-
 ...troduction_9fc99c7e-b61d-4aec-9c62-042798185ec3.msgpack.zlib | 2 +-
 ...troduction_a7debb4a-2a3a-40b9-a48c-7052ec2c2726.msgpack.zlib | 1 -
 ...troduction_acbec099-e5d2-497f-929e-c548d7bcbf77.msgpack.zlib | 2 +-
 ...troduction_b3220ae2-cba0-4447-96d1-eb0be4684e59.msgpack.zlib | 1 -
 ...troduction_c1955d79-a1e4-47d0-ba79-b45bd5752a23.msgpack.zlib | 2 +-
 ...troduction_dba1b168-f8e0-496d-9bd6-37198fb4776e.msgpack.zlib | 2 +-
 ...troduction_effb95d9-b7d5-40c5-9253-253d193b23b2.msgpack.zlib | 2 +-
 ...troduction_f4009ba6-dc0b-4216-ab0c-fbb104616f73.msgpack.zlib | 1 -
 ...troduction_f5447778-53d7-47f3-801b-f47bcf2185a0.msgpack.zlib | 2 +-
 ...troduction_faa345c6-38a2-42e8-9035-9cf56f7bb5b1.msgpack.zlib | 2 +-
 23 files changed, 16 insertions(+), 23 deletions(-)
 delete mode 100644 docs/cassettes/introduction_32e4f36e-72ce-4ade-bd7e-94880e0d456b.msgpack.zlib
 delete mode 100644 docs/cassettes/introduction_761d15fb-d5e2-4d50-a630-126d77e77294.msgpack.zlib
 delete mode 100644 docs/cassettes/introduction_85f17be3-eaf6-495e-a846-49436916b4ab.msgpack.zlib
 delete mode 100644 docs/cassettes/introduction_8b49509c-9d97-457c-a76a-c495fb30ccbc.msgpack.zlib
 delete mode 100644 docs/cassettes/introduction_a7debb4a-2a3a-40b9-a48c-7052ec2c2726.msgpack.zlib
 delete mode 100644 docs/cassettes/introduction_b3220ae2-cba0-4447-96d1-eb0be4684e59.msgpack.zlib
 delete mode 100644 docs/cassettes/introduction_f4009ba6-dc0b-4216-ab0c-fbb104616f73.msgpack.zlib

diff --git a/docs/cassettes/introduction_03a09bfc-3d90-4e54-878f-22e3cb28a418.msgpack.zlib b/docs/cassettes/introduction_03a09bfc-3d90-4e54-878f-22e3cb28a418.msgpack.zlib
index e07f27bf3..812c19ffb 100644
--- a/docs/cassettes/introduction_03a09bfc-3d90-4e54-878f-22e3cb28a418.msgpack.zlib
+++ b/docs/cassettes/introduction_03a09bfc-3d90-4e54-878f-22e3cb28a418.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_051dc374-67cc-4371-9dd1-221e07593148.msgpack.zlib b/docs/cassettes/introduction_051dc374-67cc-4371-9dd1-221e07593148.msgpack.zlib
index bf029661f..a59deb3aa 100644
--- a/docs/cassettes/introduction_051dc374-67cc-4371-9dd1-221e07593148.msgpack.zlib
+++ b/docs/cassettes/introduction_051dc374-67cc-4371-9dd1-221e07593148.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+eNrtWQlUFFfWVjFxzCBGEzQRl7JdcOluuhsaaOIGreCCAgIia1t0Peiyq6vaqmqaRcZE3I1Lm5ioGbcBwfQYFDUyY8DBBR3jFp1MhLgkcTnuY4bEMS7R/77qbkDF6JyTnJM5fzgcTlW9e9+9767ffcwsy0G8QHNs6000KyKeNIrwIrwzs4xH02xIEGeVWpBo4qiS2Jj4hGIbT9f3M4miVQgLCCCttJJkRRPPWWmj0shZAnLUARYkCGQ2EkoyOSrvyzadCmQWMtcgcmbECrIwQq3SBMkJmYcKvqQWyHiOQfAkswmIl8GqkQNVWBF/SjKRIkFxRB5nI8wsZyfITM4mEtEkmx3Fk1bTcFlhOt6PoxCD6Y0MaaOQIlChVQgcyyJRoQGJqmCNCm8schzjlsmSFkmmSObQTJ5BQCRvNBl4JNgYUTBMBWbMQCHByNNWbBNMHE646AjEZtMsIjhYsdD5iCKyOJ4AC1h5ZIKD0jlITpBGo40nRfzEUoTI2wQRCN0SlESigLJsjMRoBx7phCwCCpEDBsGOeEJyAHaH+9SwHw92IVAO/IUtxrBW+CqYOBtDEZmIID3qASOfp8QHoDGJQTCakIWEExTIrOAtxIu0ZPsCmUQpPT121OY7YZUYjjMTNqtkxTyrZDpB5Gk2W1ZYCN9wtNA8orBx3ZumNyPlMqciowik6YVlJkRSEHNLSkycIDoqnoiizWA4ZBUViDVyFAhwfJSdT1vlBIWyGDCn04j9KoWpw2lGyKogGbB3qYvLsYW0WhnaSOL1AOzGTe5oUmBdnlx24qBTQCyyoqMy3KNHQGweBD1LqJSBQUrNllyFIJI0y0DUKhgIPUepVVr/pPmClTSaYR+FO6EcpS7m8uY0nODYMJ40xsQ/siW2tGMDyVuCg7Y1/87bWIgv5CjTxz4pzr3YJC5QqVYrQyoe2VjIY42ODVkkI6CKRiM3sjghNwIVqmCFSl3usRIDoS2aHMVajW4jxKoVog8VlcKWok2YWQIeQYf/XuZO3z/FjPN482yrriUjwTuO6gSTTU6og4mxJEvA/lpCow5ThYZpA4mo8Qmb9G4xCS06oyKBh9DPAoeM8ji/zGiysWZEOfUtur1e1nQsnGwM5KOocNcucBZ+dZQEqVSq+v4/SclDgtAsllgSqNPpnrEvWAaJju34fGA8hTo4wX1KdUrLcqQ8VLjKoFurUqwV6DXomfRNunl4+j8Hz1M0DEyp92+JGwrMEypuCJWkDX42fZOKbh7/5+F5uopES+yPmc8lqO9PUDY3nIua+Enqp+rjdHteQVOOKng2qNQTc+0kq57GB0VlZweSI7X0SJK2xRfn0KTDqVaqiWyOy2bQZn2kQk9C+VXESynkKBuZPCF8/Bj9psmKiVwmB7GUQELMsRyLSuMRD6npcBoZzkZBseNRKbBPDE92bNepAtVqbRAKCVWrdCqtShEBNcSTTI3JUoIrpdR53yp1Vefa1kt6LfxdK+nHi4rbzX4+wvtH30Ndle8MSt75iaySH+h7sZXY9eUIR8j5M7NWv/2P12MqyeUzosYkrjtH1d8ceq9+mNFcsU/Z01k1ub9u149190/c2DrgRP7tWi74VIwpdu4a/y4HRreLLAo/nbDutVMbL/h2yMmsJ+d/XEzpClYrtg04uy1r4fRpKzd30XXbVDu4oLbh3p2/fthwvu9a/Xx7m8Klc7/QeC/7+vOpXgknBy7VLK1ceje637b4L+9Wz1q83bfj9ndKrOMeWHts5LxPV/E+Q7a94Dsvej07JaD1dtJa0t1XPvhjZUaNYrDoPWmE34mVwaN31hy/bxt4zvlq2ZlLRePznA3nTuXYdqYaqgvu3+/NUEK6/OyMMz2Orytjvziuvzbn6sERvqH9yyruvl4bs3r62lcPBZ719/F674cDw9PO1AyLPeDfPqr7gV4vFo81vFA65u6eY94jd8VcN+8/4X/Ju/RO3MU7dOQGnupVUXU46UWz06/8as13V5zvv33/9Y7R/5kRvexBat62nge+Ass/fOjVylpuXaRv06rV05FVdXNg5cIlEqpytWIXoGrtVSCDZYMZ5UnoJYfJU4gJI7Uh4fETzaNQhG1aTHJoLqUdN05EufFBqvHmCSG4Z3v6vKwRORHhY4gsHlCQnePNmATjNDc6AUKN3IMBDBT0VRPmJakckjVCk5eAhZEBpGWgOJxiEqjCDR/ltvjZQ+0CNvBVaknNFnjSbmiCfY+v0hY3WJQWGiHEHGcibt7hUvPe4WrJjTU6QKMMhN/N4S40MaplNFHqWnYUDwoY9JQWU+5Js2h3a9Rodc/oY/9N55z9FLHPEOEpFhswEs19XMcSKBbaZzRkLW7IjxSLL9sWNSLCpwaKLItjGM5usFkNjfhUFsbaGEYu87jX9ebxGkSArDGwAHqLtIjxfjMJCgnQ600QMiDAxgOUl3mSwW63KzHmMuJVKR/wWzbmA9rGmGnazV8gshiUS2cyqElvQrBZrRwvCgRFY/iDCMwJgwfQcnYBNBDAAMAhIUE5YQFtaYX7xUTDYASZAPZn5ICx4dyAvUgGuDC057lMwPZMHmGCN8BdgPHBg2AZo1yaCUAZQjAiluRpDlC7Uqkk0pod3kQKAN5hAoB8gSnBAnuTrrmAs/HY+BTgfYaz4gXA/HAEl8Bmh8PEmTaawQFO4IjDo0XjIYwiLDeLH4Gw06KJiI4eL0jCRQl0cbwFhg8TjFh2BBMGydhgG7CwYOR48JZKGRqiClaFasGXzXMVu7pQ3pJTcwRCzyM7HACeYqyIhad4O6DcMCIJTCnFlZS6RGTjQWDQ0Js4TkDDn4gDLg8xZKbwaAQocgSFEYSQNH6CyYaFJwELUZBu9ykazRTwSLxIcrC9RBMieDrbJGKFJJZmljVC0sBkxUHMwJTGWDCDZD2BIywkmyeNgNKElkPSoB+DlE3DqdxtANcE2NwEBPR2EMwj2DpL0sACwxBh5aw2aPtN8gU5gQA9ABGAYizbxtIQfUQWgqoCOQVhTYuumZGiMQ3W3oajmxSQ0EwVAgozYkBNkcihBRvEZz7ezhOeIimYBUlLCwQKXsHzJhR+xFIwh8G0CNFEmvECLRI0hdwRigPWiDWhCKyulEvK5kETEqIODNFpAluKGldZkOqkAY8ysjC1Uhtc+DNdPbQz/vJXD3KiaQdSECDnQalHt8H1DuVKGyZwBEzfOWA9aU8pjDyXBJLtbVaAogoKv9IsTkgpXR+XKyfG+DNM412Be1DH3sBxhJuagF0HQyCDIwCJhAXhc4j4PJgMhCubz/GSftJZGr9wHGMAk2Cq57sokWaPR24UntZA8G0BTXmk2ABJJ08KtieEhI/OjR/PJ3KJUWrNuMmZQJj+iH2f9FDqYwq7dHrMi6kFabiQpMFz2vP0lDTgT/Ns4OL63+osaf8rvSVNirkWvPMzVPoWvPhbvf+l6j04Mt1zu4qrhuG50huXAcGAeJ5rnAcg43+7zP3tMve3y9yf+TK3RB2qU/+Mt7m6MJXq/8VtrvbXfZuL/fArv811qfjruc2V9GnhNjfJZLHb4/KzklPso+MTY+MiQwWrnvplb3ODg3SkRv1f3ea2jW26zZ3+3inWT+c9xzB7xQfX2xj7zO0Z+9WG+p7efS+P+rK6Xt4mZe/KuI8cCY6t57sU3n5Be74ucmH1S39aP6Dh4fC4B3H1pSkJXvYll7raN09KCvhbVZe7396y1H0b/92cgLPpibZ+n4zuNupwXVxi0sDQ9BFZh2ZmOHd2i9CXpyTsJ1lTjrZAd/7roQevN9xvqL3z50PfOcujv43IcNYOH/6fMbPXiAV3tm08K4v32l30fdvoFdEd54e+8U2396Z8po8mjX4z0/++5eMTRbcso70WdOhp9d1ao7j7L/2euoCe94tmPOgo98r/S0bEB9Z1ltFm0zzLpQ/fCu47GV3rdu2Nmqyis7FePoXvV/QZcKP1/subBkb9u/uwibKakRvqtDeIF6/NnpG6r7b72Tfytw6O+vYPM+6ee7ntestANbH93ha940Rxq0uv6TvP6dDfT1O0YOXMoi9mK05OqZ6W/GfDkNxWK3ZX31rdp2ZxVfQ4e/381T02T9/+bgIyf3bj9vHK6IxNyiE/HNKdntU7LH9mgT7j2Jwll/3K/HdPPPrDuvVtR5PLk0/75C/qPXrW0a2TvS77qeL7r9Go685F6f343j4XUPncjCPfZMRuPOJTviRoeBfm3Ih+fh2Hdr6+L3qN5p+qt2/4tb+y71NHcWp0j+VeC87br4bu7VVZab+f/eHV2u4PdvzxeP3NPpaQ16ah1b7jqt6MWUNsn/vSsdcmd74zIX/S90y4fq/d+XnW2FHHnL9rWLVwgldk7JxuCy74NezvfOwbgXs9JeLg/Ck1WnrCvBX7Vl1X/bUHpVxFP5QP9OtgGaEd+O67wRlHExv+5rNs76WX/5jffqhm07yqlKnL0uO8NvaklYv2qW99aNRa/xWWGVfxe2fO4Vdf6Ra3ZULtjl2x6lNzLnQ74hv/w9jI/VczFlWRW7vfNx32vzKwB3uk/Qvv9d4esWvePHqW6t0OJw85fvTq6n20vD3b2XKrmPs6vu+M6ln3FKWkz83PLo/6/N5hsWr8J3H39nzRa8hHt+uum5Mdg6zn5nbUHOlyZpdufdSxh4vGTFm8cdCyqjV7u/b/S/ikw8PqOtxZxka8da24mypyzz7nngVTxh09EnqqsFPBhqgPOhceCl7d0M4r/7rp+49Pv3/5cvJYZWKXtfooJz90x7+nr62s9qktLO7TSbx8ZJBhTYpZvvNE2kri1NKSpIo1ncKmTe63evpbiS/VxQ5qHTI0pSPV5uZk00byVGrg4rx5vZ3taoLYDrunHZ8iq3z7jiHrzcGBX4tXl/SXpxZOO7qq0/refdssphjzkYfVI/J10R1fGR5RevtiZFBfU4+Tn839aNXylTVjO/Qe33fwg/i4PkfbdTfPW7y0fff23m3NvXYUdzy0LdJyU71fYyztmnBK6btwR5mqe+KQzX94kJok7z2sf4TPrpSECx9EHTyY9I92ypiZ66d+s02wLT90883aJZ/eXXExbs+qIUkLT3blrn667sqV430H1feK6XP09levkN9dq1x6Mfdi7Z2Lx9Y+bO36d8SP2W8MKIZS8n9Kdz8B
\ No newline at end of file
diff --git a/docs/cassettes/introduction_11d5b934-6d8b-4f52-a3bc-b3daa7207e00.msgpack.zlib b/docs/cassettes/introduction_11d5b934-6d8b-4f52-a3bc-b3daa7207e00.msgpack.zlib
index ce72040c7..3825eadaa 100644
--- a/docs/cassettes/introduction_11d5b934-6d8b-4f52-a3bc-b3daa7207e00.msgpack.zlib
+++ b/docs/cassettes/introduction_11d5b934-6d8b-4f52-a3bc-b3daa7207e00.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_32e4f36e-72ce-4ade-bd7e-94880e0d456b.msgpack.zlib b/docs/cassettes/introduction_32e4f36e-72ce-4ade-bd7e-94880e0d456b.msgpack.zlib
deleted file mode 100644
index af25c9ceb..000000000
--- a/docs/cassettes/introduction_32e4f36e-72ce-4ade-bd7e-94880e0d456b.msgpack.zlib
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_35c8978e-c07d-4dd0-a97b-0ce3a723eea5.msgpack.zlib b/docs/cassettes/introduction_35c8978e-c07d-4dd0-a97b-0ce3a723eea5.msgpack.zlib
index b16138d3b..b5ba5e1d5 100644
--- a/docs/cassettes/introduction_35c8978e-c07d-4dd0-a97b-0ce3a723eea5.msgpack.zlib
+++ b/docs/cassettes/introduction_35c8978e-c07d-4dd0-a97b-0ce3a723eea5.msgpack.zlib
@@ -1 +1 @@
-eNqFVU1vGzcQRYCe+isGuhgItKtIUSxFl8J1nNStHKew+oEGhUCRs1rWXHJDcr1SDR/iftz1F2rXLoz049Rb7j30F+TXdLjSWm7qIoAuS868efPmDXV6eYTWSaPvvJLao2Xc04dbnF5afFGg899fZOhTI86f7R+MzgorX6fe527QarFcxp4dSTWPuclaDpnl6fnEiPmbO+8fN+h6fIjzxgAa/kjNo9lQW53lbHtPou0nn/KPX2ybZ/vD7Muv9h9/3t9rNKFBFW2V8UXK/IYDBhvaCNwAqWHI9PSJZXn6QYjM2Gxs0RXKO4rv0Mmy/lhg7tMAwcQR0xxFiJaaq0LgWJiMSR0ynn9Nxzi79biOZtqVaOk0YcrhjQvLyjE3JJf2t9zKjE3R1RcnlykyQRr/ePWZQxttTSlr8Wc+J1F1tBLZtTrxffr9vsU58Y92NDdC6uni1+m3Mm+CwEQxjxfL68XZ3dbdq22jNVbTWlwdIuYRU/IIf9te8oqGqKc+XZx1Njdf1WejeY6LP1ieK8lZyGx944z+hXTMaeb43YXzzBfu9Jyq499/XWboHPXy0/4ndRM//E/ZiwO0ZKTFz3oq9ewdBd/meN5uP7h//ogaXLwepUUTOptwgDl07nW60O4Nup1BpwdP9kaVuV4SS0vavHnv5XFtmHf5pZEYpUw5LvJxpXeweGOgC6WajXrKy696eGSExrW/nh83vPQKqdA1KowKb6xkagChOOy6dUVgWsBHpgRvgIYOuz5wKKwigHp7yrKMBfOMsyyv9sev8FqKYKYBJqqPKPnabo3dG601ARlPIfQMFnMiTDEkA4UM94AFqzUrMj5FQEGdAbNYfVHJrNCrsQBPGY1VOZigLxF1CCHiFYKLYZRKByR7wX1B+SyI6SAxFriitatKZExTOJsohNLYwySENKFMkRIqlhUY5GgpLyO4HLlMJAfP3KGrIHLmHFGUOkQsiZGChrjYFRVgDjSiQBHDAZkVV2UzuoxhXyOYZC3PRiBNwKbwkCAL3AmdfgGItA01eAghnDiOSWbHjaUx34sfPuz3Nze7XXLBzWUPJjlpru3w2JoMPmROcheobq3enAHszHJlgk3XbP5jAW9KZoULLnBcIiVWRkgIM5pUmJE3Uf2ORVhDRmuHYJ+3edIVk16/9y+XkPuQFrJ5w5STkBt2ZFJoGgcJxYSQQWWmyA46PC006yGGTRLS8cK54IMsvgFC6nFLUqII/dK7JElzPudhwRVUpAijinUB1EnnQ6lgueUSBk1QVRNzA3hK1nVr7wL9/xQEtPobqlzByc4T8pCsfEDGJlut3EAGTKiZKjaGLeUMXS2dRSA7Tx8tVyNj9tAtd4DwiA3OkBch6+2Zd9vdB7eNfPkaVK/k2MuMwttxr3fyDx4LpLQ=
\ No newline at end of file
+eNqFVMluG0cQjYGc8hWFucgyONyilZdEtgXGkSUZkYLEsAOiOVOc6bCnu90LpYmgQ5Tlzl+IFCkQnOXkmy855ZAv8NekekaUiFiGAR44tdd7r+vkYoLGciXvvOTSoWGJow87Pbkw+MKjdT+eF+hylZ492d3bP/WGv86d07bXajHNm45NuCibiSpaFplJ8rOhSss3dz46isg9GGMZ9SByE1HGbv/h8urG3hfjTbzvX+w+XTtMl7e2HB7uLbW3xzurUQMi6miqjK9y5hYsMFiQKsUF4BIeM5n1DdP5JyGyYIcDg9YLZym+S5a6/yBF7fJQgqUTJhNMQzSXifApDlJVMC5DxrNvyIyHt5pn0UzaAzRkHTFhcc5h2MEgUQSXdLd4ecEytDPH8UWOLCWMf7780qKJNzLKmr7SJYEq4yuQbavb/Jh+f24kCc0fb8pEpVxm09+z77huQIojwRye1+7p6b3WvcsHSkqs2JpejhF1zASf4B8P6rnixygzl09PuysrL2e2/VLj9C+mteAJC5mtb62SvxGOmjjHH86tY87bkzPqjv/+c1GgtbTLL7tbsyV+ekfb97Q430NDOpv+KjMuD/8/41mn3V06e0gLTl/v574BnRX4nEnotrvL0O302mu95Q70t/crcX1PUxrC5s2HHxzNBPM+vUQjJYQ6GHg9qPAOEo960gvRiGYs118z8kgI0bW+nh1FjjuB1Oi6KvSFInRMCTH0ufvMD+FJldqIvBEUOXsmgjKSnPQVM97MuMv9sMlVZc5CoRYpKbBqW2FCgRMULSpyra9ohzayf7+CR3M7NSDsSQsbBFdqwlqIEmpRwcjL+hXDXVvKBJQBFv4swkGOISFHGHFjHWhleYhkgiplvqCGwG0VEKRAqmYyhbtK10GiXGzUTqTx0nelM3gexh/x7Dk9vrAIbU+MwawO1F5v2FAgaGYY3RhSF83rk5yGpRIuNyS5AU8Xm7DHCy6YAadgB92BMuOvG1AqDyxNwzwWr+CgAAYVquBt6BiGpaBBcEN9yHoErk2UITbbzfXuarvdXl0hsuffdNDCceOG9UfSGZX6CtXQ5JqHHmzAfSRRSzSkv77n1CeGbUy5L96SQlGZq2v5aaKFylp8rnDsVHytipjFw6u6Ns5C2bizNFofYru72lnqvC2QHuzcKIK2HnouwgmBoVDJ2IIaBcTMzehN2GQEdoWMQU1ip2oB+Zl8Kt0QVYX2rnrKpAnUTXhKwNNB4nIOdY1mpEwBVmPCRzwBx+zYNmDGpzYqoWMS5uGS6jWgYGP6mudibX15bX1l/TYq6sdYHamB4wWFd5prS8f/AWTydLU=
\ No newline at end of file
diff --git a/docs/cassettes/introduction_4527cf9a-b191-4bde-858a-e33a74a48c55.msgpack.zlib b/docs/cassettes/introduction_4527cf9a-b191-4bde-858a-e33a74a48c55.msgpack.zlib
index 77236e6e0..0b03a29fa 100644
--- a/docs/cassettes/introduction_4527cf9a-b191-4bde-858a-e33a74a48c55.msgpack.zlib
+++ b/docs/cassettes/introduction_4527cf9a-b191-4bde-858a-e33a74a48c55.msgpack.zlib
@@ -1 +1 @@
-eNqFVW9sE2UY3wDF6AAzVDAQeFNAxey6u/6lMzhHGThwbmxFRhHr27u37W3Xe4+798bKNoEN5ANEOBI1AxLUde2sk20ZSIIo0YWgqIRvMP+LigMHMaLTDyC+17UwZMF+aO7e5/f8+z2/572WZD1SNRHLuV2iTJAKeUJfNKMlqaJ1OtLIlkQUkQgW4pUV1b52XRUH5kUIUbSiwkKoiFYok4iKFZG38jhaWM8VRpGmwTDS4kEsxL4cl9toicKGAMF1SNYsRYBjbY4CYMmi6MmaRouKJUSfLLqGVAu18piWIhPzqApFUTSIVBCNARlGUbGlea3pjwUkmXZegrqAGDvjZDQsy4gwNpqBddlYMxDBWMrkMJ1NBwLrRSkW0BBU+UhARZouES1QS51NBwFpvCoqJgcmuASM4ACSw6KMAKaWqLgBCSCEVUA7VlQUoY2J9agAQJ7XVUjMJ1kARNU1QoGZDFawUkMhXUo7rqc+IIZ1ICOKIJg6aOtpj2nCTfoBDGKdABpPpTwAVE//aYgyWaGnWgTrkgCCCMBsedRRjVnNBkQTEtD4CIpC2kGjRaHTQSoR01w3WtLI9NN/Wh0dySxJwrgO6EqaxZiSpk4jqiiHLc3N9MxUh6giwSQ3E3TtKCgO1iKeUOja5mQEQYFqbGc8gjVi9N6mmm5KHFIIg2QeCzSB8W54g6gUAAGFJEpnijfnmpalkapDSGGgRPlOjHgZPVBRJJGHpr3QHGNXRj2MWcvt5pQpMoZqTybG4ZJsHYWVMSpyGbBWu8Nq62lgNAJFWaIqZSRIS0ooafv7ow0K5OtoHCazQEZixPnAaAzWjI5yyFdU3xLSZNrogGrU5egbfa7qMtUXMpLeytvTZYw309mtHGf19N4SWIvJvNERgpKGem+QfMMlRXfDzrAuhuUOZFmSqLRJxGh3cvZOqlWFqg+1JmhIomstcToR9Pknycy6vlWxPDvNb3Py44vpdIwPfBG9ANhcoBopwNw9wLmLHLYihwMsLfd1eTNpfGMOo9enUumH6EBKs8NP8hFdrkNCyjvm2AcsN9syl02i+0iYzF1Fh2W+GnEHy7IDj9wRqdIFEWUzY9zu8Xj+Jy5lBhHjoNkfw3oYm8s30qXT4R8AY3mOXHiZehJmPbSiuXdA3qwniwZ3RI9dj8PhT2WKZkTBOEqfAyxXukzw+u3yqvCKpaFlVT6dq4HPrQ4famB4CesCQ+itj5i0IBqIMQA4OxdyQWi3u0ICcghuZBOcdneQ44Is60L2Be31IjRSnJUDYYzDEur2LmG8kF45THVaNkZy8epnS8rLvF01TBUOYsqfD1KeZSyjRDVSqRyNVDo1XXAVJah7Vclq4+AC3uNkBac7CN0uJ3IjpnRVVU9WQDcEEjdvh/TXZXNi5EY6nls7e/s9OenfeJ/xhfzVU3lbAlu/nzdtoHJmMkLmNw1+tPDuhYceywuVLt87tPvk7r1+59XLW7+effDRfHv/lPG/7eg9Mblv0rbh4SvnLwv9Fz67f//6/bOcxcX7Zn380Iw/YufmHQ/Rb0qNgxnXVqrln7i7b3hfT/+uzuGjR9Z80/1M6dlVe+v7ot9F/RLbuWA7/9efVydebPKf6m7vX3g6Xrbt79YZDanJjYMr5ZlLNvCgDT6+4r7FntpPf1px12DZO/1dhzZVnncO5T394uFtx67tue6ZOq36zQltfa89/EqpvZOd8KrbOrz913vnXpzzurMpzi564JdFP9TuqV7XysMZZ3rcNWpeoq15h21T+cxz3MsdZ8unzP+QFV54Y3OV33d63JzkhSMbdz7ZUldxZeLRprrTzye90Pbg0K6O4gam5dikH8+czJ/+xNvznTXdGy+cmo5SLynNkBt671K01X8tcOmfaz//PjUn5/r18TmD2DgxnJuT8y/YbDsP
\ No newline at end of file
+eNqNVXtsU1UY35hEEFCJRGYi4djMjbHdro+tozMC3cYQCDLWQjZgLrf3nrWX3d5zuffcbt3YHwyYARPJxRDQSFTWtaSOPXRIohBwETFKwkMlTOShAYnEAAoENcH53a5lg41H/2hOz/l+3+P3/b6vLdEgVlSBSKkdgkSxwnIUfqh6S1TBazSs0g2RAKZ+wofLl7g9bZoi9L/sp1RWi/LyWFkwsxL1K0QWODNHAnlBa14Aqyrrw2rYS/jQT2NSm0wBtqGGkjosqaYiZLXY8nORKWkFNyubTAoRMZxMmooVE7xyBFKRqHFVgQM44MUKCoSQxAbwHFNztYEnPBaNd05kNR4zdqaAUYkkYcrYIILFYbMYjighYiKGATYAlA0KYqhGxazC+WsUrGoiVWtWA9gA8FjlFEE2ODCMXWjQDmHJJ0gYEXgJCI2YR7VEQVCxrGA/FCYEcS5iOU5TWGqcJB5RRVMpGCYimNEyFddqYhxYDxgUIhqSMFhQAgC1HmqME27Qj1gv0SgCfwrwgHAQvsHFAkmGW9VPNJFHXozYZHoAVEJmowDBMKlROT8OsFBBk0mG7mCFCnGum0xxy/jpvlKHezJSEgmpQ5ocZzEkx6lTqSJIPlNzM9wZ6hAUzBvkJpxWDzMl3tWYo2Ba3Rz1Y5YHjW0J+4lK9Z4RqukC4rBMGSxxhIcA+h5foyDnIh7XikBnjDP6GpelHqvDWGZYEfiODKL0blaWRYFjjfc8o40dCfUwRi4jn2OGyBjQnkT1fa5kHnnlIRC5hCxme77Z1t3AqJQVJBFUyogspBSR4+9fDH+QWa4O/DCJAdIjg+DO4TZE1dsXs9wS9z0uDab1dlYJOPI/HX6vaBLoC+vRkvKR4RKPQ+HsZqvVXNhzj2M1JHF6ey0rqrjnLsl3ITGYDTtjcTAWa2eSJRGkTf16W4HVvhu0KoP68PoIuKSa2hKGjuCj30QT47pryaJkN8+lTA2XQnf0Ax6/lousDrSQlRD4L0A2a5HFWWTJR/MXezpKEmE8ozajx6OA9GuhIfOSzY9yfk2qw3ysZNS295uGyjKGTYR5pExiV0GzjJ96ON9isfRnPtRSgQERJCNi2O50Oh/hF5jBVO816gPyGKvDk6jSvmL0OPE5ZAbXXiKriJEV5DXzkfZDuSUxmY+BeXCGWaOhYcGMSLF9VjxazqPth1JMYLIeB/OAFPNX9KPR4PfRNxgo4yGWw4kbtEYPtX4gZbFE5xmB1/fDucZiLQ+UlCl2Ul66pqHMV6nVl2lUcEltQYHVY1azFfkI8Ym4q6SMKWFh/TLu+Ajp0dKq112LF5R0VDIVxEtASx4WNCcRCUfcWIHR1GOcSDQelp2CIwCvcFXpvU6L3WotcDq9nLfQaXEUMMWwQ5LDdHdYwsamjP/TrosMbufDqcHpb41LiX/SeN215fu5EzcObL40YXvvwkVTw6vKXblXdk5AUya9EH0Xe5884y7w3Lm2e1115ZpPbp67cTnrn5Zs7/q2aWca1YGP9h2bXjjtSOh2MOf25Tf/ZAfG59wM7Vq5+Wif3l28be1zLVW2Z/6o/GWGbnOcvlRu2vNG59XlmUcvfhw4cPbHrs8Klp8e/0oPd+PSX+O0ovOntp+4kNqXUfX271nLru+Z9SJ66qCc3rcJXZ/4TubSyrm+J5emC1N2uhp3tM+Q04VJTesPdc855D58ZXz7xZesGVfnHbmwIL1x2+TMdvdWb+Hfm354/rtT12fTtIzgyeOMcOND6XhOf3drfYWy/2xrttsyJvo+Gz6oHXri6eNjW59t29p/rffb0vd8r02cHb7sO3/hVt3G32x7F365ocf16+nGpV/PaT2xpfjnyY5VSmd37jHBvKNh5rnP12Y5xOCtSJ+Zpu3debKYfJB1ZX5N9lcDr2b/16Xc/rfxztiUlIGBtJSTm2ahwjEpKf8Dn2qrXg==
\ No newline at end of file
diff --git a/docs/cassettes/introduction_69071b02-c011-4b7f-90b1-8e89e032322d.msgpack.zlib b/docs/cassettes/introduction_69071b02-c011-4b7f-90b1-8e89e032322d.msgpack.zlib
index d72c229bc..c1f763bd1 100644
--- a/docs/cassettes/introduction_69071b02-c011-4b7f-90b1-8e89e032322d.msgpack.zlib
+++ b/docs/cassettes/introduction_69071b02-c011-4b7f-90b1-8e89e032322d.msgpack.zlib
@@ -1 +1 @@
-eNrtWQdUFFf3R7EECxp7NH6Oa8HCbF9gseCKNAFBxIKiOMzMsiOzM+sUYEFAQTFHjWYxxppEpSmigvIp9oImokmsiTVqlBhL1C/ms2v8vze7C6gkMf/zlXO+o8cjw3v33Xvf7953m1lFSSTHUyzToIRiBJLDcAH8wi/MKuLIqSLJCzMLzaRgYon8yIhR0XkiR53tZRIEC++rUGAWSo4xgoljLRQux1mzIkmlMJM8jyWQfH48S1jPue5Ok5mxlDiBTSQZXuaLqJRqrScic1KBlQlpMo6lSfAlE3mSk4FdnAWqMAJcCvEwIzSJcQzFJCBhGJMQxGEWkxzxZ0WaQKysiBAswrNmEuFIHtDhJoRlEEpAjCyHmEk/WfpEKI4lSBqyw2lMJEhUg+pQnmUYUkDVQCGll1oJ5QosSztUYjCzpJKAJVG0Nc7OOg7IEGmBj5sCDsMDBMnjHGWBkEFiA+JQgWQSKIZEWLBjplJJQtIGAGThSBPAgUoiPREMx0UOE+AXQyACJ/ICIHRIkCOjedIo0tLBZHBGuipDAgqBBQf4ZJJDJPtAayFYPCsKCODHAdgQMgn8C1iEMBawypskqOJJBHOqBw5yVjm8AAVJ4njcRJoxcIM0mQUYk+QESjJNmkyilL5euWpdTlAlmmUTEdEioWi1SNDxAgeMJktPB2vQmSiOJCC4DqYT65Cy8VNIXJBIa6GPsjuggecpXsAYnKwH8QAex2gAIiKYSAAwA50Zg5t2mBAyBd5GQhOQUDxCGSUkMY5ERAaLp0mJUBKBEEBDXKCtCMAc0EGW0CMRh/I8wosWC8sJAEsry0jexyGAv5ni4Qvi5bFMLBPNwkN2YUaRkZ6TJ2BBY9Yajh484uF4Xh7AeaV1u6YIDpQGNkiiCPudOCrBJCAJIkVABN7IZg7O0vef2sJJXK81JqYXmUiMAJguyDexvGAre+3JbwRuTFoElGRwlgAibOsTUimLJ0KQRmiXYhy+MgkEW3EiSVpQjAbeX2g/ZSvFLBaawiWLKeCjKnE8fRTq8vp2MUQPBYGDEWxbDU49FJFWEKEYRCnXaOXq0hQUuAvF0CDEoDSIGLZCi7S/o+6GBcMTAR/UEf1shfbDG+rSsLytIBzDI0a9xBL6va0A48xe2s111zmRAa+dtBX5R74uzrFZK04jV6nk+rKXGPNWBrcVGDGaJ8tqQK45UgwilQZVeqFK1QYnSjQINILJlqfX+awBDmoBTkhmFwKWgshn5QOLkF8dKnLE2tURoU5rXnRpkz8MWMe2K9okeiJqL2QUaUFgJERU3r5aja9ajwSFR5f4O8RE12uMsmgOBCIjMEiA0/hFuElkEkmi2L9es5+V1V4Lhj4aREcBdbggMBb81ZavVSqVZ3v/ISUHXJ+CKcGWr9Hr9X/CF2YGwVYO74cq9ajaK9p+S512/FmkvpP2bOXQpxDqAzTq+QeUtfo4qZE/pK5fH7V+fLFDaZQibDvBd5xSFZDIDWe8UkOHR0ZpsGR1kskyKnXq0L+noDjNigQqgJRNopJDpAi2swiAQ+dNqEhVPOmNE4TGB9MbcQzHCDVmxEjv+LwkCrMVq+QqJIFlE2hyo38g6o+BYIKOktzGVjQsZoQhPMS/ZBwaxcazAL9oDODMsAxZOIrkgDvaiiXR4IFzZCE4HmWIsZX74HqdkvTS45g+XqWLj0cDxkaVOh2oxkHyYXSQSoMZhfaYdLDBum5z33GR/rhG50aw55UtDu5p9mWoIqm1x5HfHnl5Bpzu7pqz/pZ75WSlFz5gUcjY1bnbDLufTk4O2LEQyV1wt6jpp6XrlV/KTx0c+DSjYufz8p3j0QdHkv0eLD7/9xcPFsl6m/yPXm03e4gOz5r0/biVrc9N7pnjljS+rPL90KCyK8LSDSdWyugb8btTBmVuXoJnFcwp63Rtz4iI0A9fzLt349AvPdLyxlz4R7MNin5n1NpTD12XZP20t/pIE6+e9xcV7Z7xaWon7TeXA1cZXRM7+bZsUhYRfnLOvBn5WVE7LvKVbc65+vcfcL9rzLrcvfdn8a1dI8518S1npmcO3tHnRx/tstNEy7Q1Z9aIDUzrjn9mMJZi2fNXRZXm/OzWYtgCzUCPowtGiwEt8Jmj7lwd1OHXnysXf/5LxY70FMWRo7F3vW+VXNigCYtcs1xoO+6Xd8akuB+P6fPAQF7oma79KiKl29lWS67OnT5QnBad6f2uPtc3apAxuqx5yuAXI5RLHsxK6Jz8vKmPruGloE9yVYuvx2ZNfeLy+MbxcuUu3G3Jxk2jszrfJtEjFz87mtnAxeXFC1eXNku6zZjc0MXl98vCXXWrQnvVJJWE9kLBXg02aJcmA9txiaRVqq2SaCuaEsZwjNmC+YdTJOdjHIkPn+rPRkaEmceNjwgc4xMOM56zCpHVFICIkQNVQjLLJUoVEgzzIohxiFTo8fAMrDodxRQ4qfZ0lixxBEg8JsgMI5JgTiXsORWnQWEYR7DwIUs1IMyIZEq9y05qex0GVqWYXWeDw5LjaovYV3cps6P0lTZqcmxO8WiY3QxSdttiz1k1QUyhlmvA340Ge7oNqD/dFtq3bXn9FP1+JwZvcL7JMEfuUHt7/Umg/yupZdbviHWGjgJYGaf8icBXdcxXKTVef5yxNCqYsV6KLOcatagpYN/cc2RGlqbZ5DjREldTX8t8GZGmPWVOe9t/c5oRuISsxtNA6yBQAmxnZCGMwLGEiDvL0RoVfBEDMpQEODBSKRgkwmIPRcJJghLNQAORA72KzPmezNKy9JaG4BaaTVBQdRiDnCIVOQmQMYqh8Q6+PAprRhJVaY36eFKp9lZpVYB1jVPWAQQUqhhiYcHNYMMBeyAJmXiRoqGLIdDmsBfxRMzgjhQKWkSwXcdmPJJMCSZwPw7gGOYENFwCFOkTFhbO9wXNCOhLUoBsgpfqWkjmbwKPCqGpeA7jrKANgrhDgbBAB3jhLMsBBWB1Lwm2gGIdh0cAU6CAXA6qYRmPsxwAWykHeU+l06qAKeq+PWipdM9am9TeOloEt6Aw2hcZa8IEJISvtY/UkAWzyVAJ2DiECH6vWSU5OVlOYAJIrGaLZBvBwU9Raw3n0su4w2YWMdm5w06hRixAwAmGBCjA5mWkSJzlraBLNHtK8HAkhOYNrCMKFE2lQmRpyUSv+HyNiQIlz4dtogCebbwVhT+B1cAVAfSssdYlAAlldthDADWC0wHqAggaGhrYBvTiPAKNBNszGJx4yEkCCMjhgBeLHAiO0jUQM8YAvcwAKXtXXOMC4B6vWNtHq9GrNPWZ2/4cpYAVB4tuma9artan/4smGu98/V+faMAm2SkAc3THwstSYBgCzw1S+IPWELYY1u5IiIc0BzAB75Ca9hoBdaIjEAJ0kCOgj00gBckDzaD1A709DDUEtJLdMnWGGQjFgHNmzN7rhnjQtKMHJpFoqRJwDh6cDTEUnoCBfQ5kLqAd7Rxh1MEjDEgHIBCwPcYEp2IIwybL604ZpGtKkNSsgAgWB+RDqjcb40gd9UvzjjfOF7ChpginWBHU64bwsWKycUyqntEMJxOmhA1T4fHDVDLQTNe12+uOMeGVG9iVfMV5JqTFwkAUC75j/w0ZIhaIi3XKswv5X8gTsZKD1IPcX4ni9WHzNpb/P2M5sMhE58QVvtW4N3pD8K3xcSTHsTVFN3hWbwe8bwe8bwe8bwe8/8MD3ny1Wqf5l054tcq3E97//IRXq6xvwqsaO0yvChoRyiYQw5MTx3mnBo6NTA38/QmvD07ojUZvDNfrdJhKoyd1Gp3aS+eDGQlSr9X8eye8Pt5qTOf1lya8jcprJ7zCmPPzz3u1fr5oxqQTDTeVnqWzohUNtm/THmqC5pYbjqMdekwh3i0MnqUpP93y3t2DkZ+gPZZ7VOYGf3ZkRY90lJ5w6uDeWzvmfpmpe3je8vyb2LNxcVWXni5OyxjcQjF300fPg5+0U11dNmfTB/tuNCa2eF4v6DO3e3n1nO1K91Gh6zzWFfV3v7iwRK6Qb5R/NnFSOxLL6ngv6tSLaZ96t99++sfHRfLB9697l7Zy2976vvf+D+KruhRfvp2HGjrmsjMqh0xO73hlenx2U3pomwrDnoy2U382pLa7PLjn6aH+xxZ22VE9Yofv/uvr4yo7ZXe/1owJnoxc1rbodDuz0Ym2tKkVXjqpYvf9rb9Nbfy5iB8pypt0IXX6wapPGqya63NMfqBl+YGk22u/DvKu2j4mgjSskm9rk1N9YMOx4A+mX71eUjWzU9KY1Ip9FYU7rft1+9LaL/2haPnyh8/4xuyP77qmrkzrfrSf/3U1PdHyfd79y3Rb1Z3+AZkx+7r1nT9j7TdLxjY/dT32jKq8vFfHwDkt2uyd2XrCrZGmLL1vw7zz6j7jD341edAS5bz5dwxuydsjxDN+ru+r5uiqMCEtOGxzq95t5syZGjigS8cboZtsk4fcarzeb3iT6xM6Hbs6XhGjaHc8rHmX3K622d8ldQ24l4s1jpjkczIzat+Ac5WJQ0NsKSdc+i9p9KiP6r1dIxXRIWE3r41/UdKZmNKebmFK/dbjgO6JNfrjipuZXot2f9p03qYo64MO0zxWLWs22Jh0d9F7LasLcrauDt26pVfOjLAFF+/tjdlW4Jk6rPP5kKrswN5Nrs1qfdOl/5bZC7zbxx4dcf7y4oYmxr3D0VaP7i+YvWrFteDPq3z8869aViwtWLP4JHdrY79HC9022BISMx5af2m984lLk6VDCsoMV4nHH/c+mac1aA8EVTfZ1cRvbYLvYV9a2/2K8sEnAbqVDypSlg2c6HWk+bYNd3rl3T6+9c5H2e2bf5gwUz2rqP00xFuv+KHd/idPcyKDdrfqv3RvWofOh/ueWLqifZPsHl7fxZR9nK3Pjrk+4W8DfvSMeO+MxrzV/1I64t53WUx1xKCAhvMa5fYcNnd+g62mrl7zR+SWLDT3fbjpn6p8cc8a9bqf/M5MbLq/l0U9CFHIWrXcpNv8aNGVy71yjrmtbTBhTkxPzcj7OYE/6Md2do9UjPk648FMfv6CU36Nv+11eO0/OpZ+fHTy6V173XdNn+k79lni+yWbT4YOaVtZvb1tQVW/5ZWNBjFVfm2GdHQ7n762Z0RgwoedTnQaOG4t53ppZmnVD5GtrAV5nKzrvupf3Ssr/LdaxwnThiQFT/ti4+FFD29m5Jt03m1n3fVMMdHDLUn+0zf7FbhPvIcGpH+/9djs77OMd/ArAf6fT3r/Wd7g3YePrThX/NuWfT0bW2+Gbw8iD20+vv67YysW37jsPSYjtOWwzq4T3KZubJazYfMXqwdcUreq/OmZfmWWMdW17/pvbvbv9XB/8BdJ360YnRK4uemp5fpNcx+7vXvOsiL72YXFw6atqXgWsOnI4NyMbdVY7+dJM9yvzr1yfg+5r80XO4IP7esoGnbvWtgufWrFvn/2ulEUMfJpdWxM/rPHozPRkm4LL4Sc+ein1RkZ1tEdulfdO/ftr3G70592s/9Xx9/CT1RedHNx+T9w3qPo
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_6a385b06-8d34-4a2d-aded-1cf4bb0ca590.msgpack.zlib b/docs/cassettes/introduction_6a385b06-8d34-4a2d-aded-1cf4bb0ca590.msgpack.zlib
index e82d60c13..b3391947d 100644
--- a/docs/cassettes/introduction_6a385b06-8d34-4a2d-aded-1cf4bb0ca590.msgpack.zlib
+++ b/docs/cassettes/introduction_6a385b06-8d34-4a2d-aded-1cf4bb0ca590.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+eNqNVGtQE1cUjtIqdrRVBx+ldNgGRUE3yZIECYOjiAqIEUrCIFQH191LsmSzu+yDisiU4gOVae2WGbWtMh0NCRMRBHVEa9W2Sp3WiqUgE1+1oz9qtVMfBRRk7E0IggUf++vuPa/vfN85t9RVAHiBYpkRNRQjAh4nRPgjyKUuHuRLQBA3OO1AtLKkIy3VZN4r8ZRnulUUOSFWrcY5SoUzopVnOYpQEaxdXYCp7UAQcAsQHKtZstBTXqS042tyRNYGGEEZi2CaKN1sRNnvBG8+KFLyLA3gSSkJgFdCK8FCJIzovcq04iJCskghKyE2hv0QwVezkogsxRlLIo9z1nnK4pXefCwJaK8/QeMSCVAtqkcFlmGAiEbBiproKI2y2GUFOAmb3eawsoIo1w+BX4cTBOBEFDAES1KMRd5vWUtxsxES5NK4CNyEN6OPH9ltA4BDcZoqAM6+KPkAznE0ReBeuzoPVq/x94GKhRwYanZ720UhC4woH4nvx6FOK4RsM4hGpdWpog6sQQURpxga8oXSsGnZyfns3ww2cDhhg3lQv5Kysy+4drAPK8hVRpxINT2TEucJq1yF8/Zo3cHB97zEiJQdyK6EtKHl/MaBcloVhqnm1D+TWChkCLkqF6cFUP+U5KchbqiKFtVEoxqstp8lGjAW0SrvxbSGah4IHJxCsN4JU4qSUOqAioBzZ13+wdmTmtKv5jXFFMdCqI78rdkqzUawaGQJziAwvx6JwmI1MbE6A5JoNNck+MuYhxWj3szjjJALBVnUL76LsEqMDZDuhGFl9ygH2uJhfZqyUyLqXxoolvdXdug0Go0n/IWePLBD1rwVHVqDwfCSvJAZIMqHvP1B8lAs2uzvck728HUohpPgCPoW0I/K6UUFcUW+1H8AW39M+CvEPAehIdszY7houNBDIFbF+KrNern/AER/zIxXiXk+RGS48P/R11do2gs8BxPX54280Pu5eNx+5VGKlI/Dc44GyyjgMskMyUQlGoFFmyLp03n78ry9BRQuuzEVhlhY1kKDuoTFaAJOWAFq8q2Q7FqYtSzemJxQsxxNZ1ezcJbMOJw5hmWA0wR4uJqym6BZiYSPHQ+cMDw9Pks+ZNBoMUyvxfS5JKEjAEAXwDekf5meLovD+1L6nvyP4cry8OrMiO7Q8kCF7wsQ042pVzTje2eF5TSSvzagSb9MyihpTUndX+1uo+OSnTHa2rnnGxY97vopa3xaawVoftDTEBpS1H4s4q3LHZ6Ox67Hl1bkrDzf2dH5VfG8k7277l4PtpQlTVpkuDG/Nj85Ye6pXYZ3th5tMv4V0XhRGlHuaitrexS5L9CTd/DauhU59MXa/N1b5Z22j+LiKoKvtt/+ueWYeuYPGd/HjLTMDzyesvPN6xEPkJvfBS1+Y0LBxvVltLV1h8I0pmlWSNJYTdOpd4P3kTO/ACUlUUEhgZMrHgUxd6apQ0ZFrgqOL6q+tCOsQbF19Nj4rrfXGi9MX7AvriK8dJlr6p8nCt//3Xbs9pR/K+3r6jonRobv9phGmcYl3h/zetmSExfQlu1pUaEBd852LhxZ2VPZ8nmd81xa8a2gjO0r9b3b7t5WLvsju0tnylNor5RkGrCp+eF3d1Vrv+5J2pIcG7tple36qNiaxhntn4VJV4TRlWMN5KndkwNquw9XbDk9+WhebWvd/Vbdgj0lTdqNAYF/73jYdvCT18aE9XCKL/XnDm+ujHjYjTxprki9eqO5CfzWaNyQdebwp6fZ/dPyU9cvPZky7mZ2xHs6Jv/mpdE/Tiy3G/9JarA1q4Lb8TktnQ/PR14+UtLxIG5Cd5cW7dzE9N66d08NRX7yJEChLg7dmRmgUPwHSE1ojw==
\ No newline at end of file
diff --git a/docs/cassettes/introduction_6b32914d-4d60-491f-8e11-1e6867e38ffd.msgpack.zlib b/docs/cassettes/introduction_6b32914d-4d60-491f-8e11-1e6867e38ffd.msgpack.zlib
index bd56de369..5800f50a6 100644
--- a/docs/cassettes/introduction_6b32914d-4d60-491f-8e11-1e6867e38ffd.msgpack.zlib
+++ b/docs/cassettes/introduction_6b32914d-4d60-491f-8e11-1e6867e38ffd.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_761d15fb-d5e2-4d50-a630-126d77e77294.msgpack.zlib b/docs/cassettes/introduction_761d15fb-d5e2-4d50-a630-126d77e77294.msgpack.zlib
deleted file mode 100644
index f7c4715e0..000000000
--- a/docs/cassettes/introduction_761d15fb-d5e2-4d50-a630-126d77e77294.msgpack.zlib
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_85f17be3-eaf6-495e-a846-49436916b4ab.msgpack.zlib b/docs/cassettes/introduction_85f17be3-eaf6-495e-a846-49436916b4ab.msgpack.zlib
deleted file mode 100644
index eddce2856..000000000
--- a/docs/cassettes/introduction_85f17be3-eaf6-495e-a846-49436916b4ab.msgpack.zlib
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_8b49509c-9d97-457c-a76a-c495fb30ccbc.msgpack.zlib b/docs/cassettes/introduction_8b49509c-9d97-457c-a76a-c495fb30ccbc.msgpack.zlib
deleted file mode 100644
index 9aaf68fcf..000000000
--- a/docs/cassettes/introduction_8b49509c-9d97-457c-a76a-c495fb30ccbc.msgpack.zlib
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_9f318020-ab7e-415b-a5e2-eddec6d9f3a6.msgpack.zlib b/docs/cassettes/introduction_9f318020-ab7e-415b-a5e2-eddec6d9f3a6.msgpack.zlib
index 3168d8dfb..4907c4150 100644
--- a/docs/cassettes/introduction_9f318020-ab7e-415b-a5e2-eddec6d9f3a6.msgpack.zlib
+++ b/docs/cassettes/introduction_9f318020-ab7e-415b-a5e2-eddec6d9f3a6.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_9fc99c7e-b61d-4aec-9c62-042798185ec3.msgpack.zlib b/docs/cassettes/introduction_9fc99c7e-b61d-4aec-9c62-042798185ec3.msgpack.zlib
index 4d5579ac3..d153781b5 100644
--- a/docs/cassettes/introduction_9fc99c7e-b61d-4aec-9c62-042798185ec3.msgpack.zlib
+++ b/docs/cassettes/introduction_9fc99c7e-b61d-4aec-9c62-042798185ec3.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_a7debb4a-2a3a-40b9-a48c-7052ec2c2726.msgpack.zlib b/docs/cassettes/introduction_a7debb4a-2a3a-40b9-a48c-7052ec2c2726.msgpack.zlib
deleted file mode 100644
index 5e60e16a2..000000000
--- a/docs/cassettes/introduction_a7debb4a-2a3a-40b9-a48c-7052ec2c2726.msgpack.zlib
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_acbec099-e5d2-497f-929e-c548d7bcbf77.msgpack.zlib b/docs/cassettes/introduction_acbec099-e5d2-497f-929e-c548d7bcbf77.msgpack.zlib
index 650645947..c2c31aa6a 100644
--- a/docs/cassettes/introduction_acbec099-e5d2-497f-929e-c548d7bcbf77.msgpack.zlib
+++ b/docs/cassettes/introduction_acbec099-e5d2-497f-929e-c548d7bcbf77.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_b3220ae2-cba0-4447-96d1-eb0be4684e59.msgpack.zlib b/docs/cassettes/introduction_b3220ae2-cba0-4447-96d1-eb0be4684e59.msgpack.zlib
deleted file mode 100644
index b3c569af2..000000000
--- a/docs/cassettes/introduction_b3220ae2-cba0-4447-96d1-eb0be4684e59.msgpack.zlib
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_c1955d79-a1e4-47d0-ba79-b45bd5752a23.msgpack.zlib b/docs/cassettes/introduction_c1955d79-a1e4-47d0-ba79-b45bd5752a23.msgpack.zlib
index 355265ba8..3648a8428 100644
--- a/docs/cassettes/introduction_c1955d79-a1e4-47d0-ba79-b45bd5752a23.msgpack.zlib
+++ b/docs/cassettes/introduction_c1955d79-a1e4-47d0-ba79-b45bd5752a23.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_dba1b168-f8e0-496d-9bd6-37198fb4776e.msgpack.zlib b/docs/cassettes/introduction_dba1b168-f8e0-496d-9bd6-37198fb4776e.msgpack.zlib
index 83f61afb3..3859f4c05 100644
--- a/docs/cassettes/introduction_dba1b168-f8e0-496d-9bd6-37198fb4776e.msgpack.zlib
+++ b/docs/cassettes/introduction_dba1b168-f8e0-496d-9bd6-37198fb4776e.msgpack.zlib
@@ -1 +1 @@
-eNqFVW1sU1UYHiOgIEKCLM4Y3aEZRHG363fX+TkKAuIYbBUcMJrTe09773Z7z+Wec8vKMoQBMQ4U7vSHRlQ+Sod1wKbAQpA5CaiJDIzRuElAJWoiiJKAHwHHPLdrYciC/dGcnvd5v573eU+bWmNIIxJWRrRJCkUa5Cn7QYymVg0t1xGh65JRREUsJOZXVAV26JrUN0WkVCWlxcVQlaxQoaKGVYm38jhaHLMXRxEhMIJIIoSF+Le5YxssUVgfpLgOKcRSCuw2h6sIWLIodrOkwaJhGbGTRSdIszArj1kpCjWvZkuAikhDk0F5HCgwioBEwCJJlq2WxhozEBaQbAJ5GeoC4pycmyNYURDlHCyVzeOwmREpxnImmRnEdKAwJsnxIEFQ48WghoguUxKsZc6mg4AIr0mqSYYJLgODOICUiKQggJklKq1EAghjDbDWVQ2JrEMphooA5Hldg9Q8KQKgmk4oA2YyWMFzBIV1Oe24gvmAONaBghiCYuZAViANpJk35wBgCOsUsHgaIwSgGPtmIeYoKrslItZlAYQQgNnymKMWt5oNSCYkSHgRRSHroMGisjEhjUpp0hssaWT69J9Wh0YyS5IxrgO6mmYxrqapI1STlIilsZHdmTKRNCSY5GaC1gyB4lAt4imD1jS2iggKTGybEiIm1Oi4RT57GXFIpRxSeCywBMbuyEpJLQICCsuMzhRvzjWtTyNVh5DKQZnxnRz0MtqhqsoSD017sTnGtoyMOLOWW80pU20cE6FCjc6ybB3F8+NM7QqwWZ0uq6O9niMUSorM5MrJkJWUVNP2Q0MNKuTrWBwus0lGctB5z1AMJsbOcshXVN0U0mTa2Am1qMf1wdB7TVeYvpDR6p9/a7qM8UY6p9Vut/o6bgpM4gpv7AxDmaCO6yRfd0mx3XByNg9ns+/JsiQzaVPR2OF2OHYxrapMfWhtkoWkOmlKsImg45+1ZvZ2e8Xc7DTP5ExMzGDTMQ4HRL0IODygCqnA3D1g95a6HKUuO5hVHmjzZ9IEhh1GR0Bj0g+zgczMDr+VF3WlDgkp/7Bj77PcaMtcNpntI+UyjxYblvnTSLhsNlvf1NsiNbYgkmJmTDh9Pt//xGXMIGrsM/vjbD7O4QkMdul2Le4Dw3kOvnyZepJmPayiwtsgb9STRYPbooevx2VfnMoUzUmC8SE7B232RbOn1wo+tz43stDjD1SXxGqXi0pofz3Hy1gXOMqef8SlBVFPjT5gF9wer73EyYe9kIeOEp+T95TwYcHj5p3Q63PuiEnQSNmtdhDBOCKjvf6nOT9kTw5XlZaN0Tqjel5Z+Rx/2/NcJQ5hxl8AMp4VrKBkFdKYHI1UOjVbcA0lmXtlWbWxr4T3uW2Cy+GFNrcbeRE3c1Fle1ZA1wWSMF+H9N/MmuTgi3RsRG3Bhjtz0p+RzxpldfeXjVs/0JzaUHy+XX910p8tVc13H540/XRl84LI/kNVJ59500jusV/7HXnHXC6sv3KmIbfGdqD3e7F/26oB6cqV6oLOGQV/VfRf/PunU9carl4d88jlS0edx8JfORe+7u7JfWMmmfjp2FlRH1w7eYEU74eNnZ48GMTneqKNH73bcWTr2aJXejZ9vmTXpe/6ujaO7tzScuSJ5OXxsS7H5vz8pVCIldQdXLP7bbC5e/yyc5G8pUtKn+w+0X3HiXGFkfaX/L+GVj/01s/GY6njF6c5C7/mX3uwtGdr/ON37jq1sXdiyRcFq1afrl035WTe6Hn3bNk+4Sm1mfNP/eW+fSO/eXj0e92TkkeFcQ+QJuulUOGjuf1fniUvTyAXzudt+3HXsWUHvPX91dsOznvxuDCtF8xtuNgyKnjvJyfXT7F5KitT7UUDojUfTVulPv5+vqfzj5r1i/954UJX17KBETk5AwMjc3pPj/rhN3b+F+M8Qc0=
\ No newline at end of file
+eNqNVVtsFFUY3oJBbUxECxKUyGGjbQKd7cxuW9uGqKUtBUtLaRe1NVhmZ047w87OmZ45s3RpatJiMaIBRhNBDQ/S7S5Z29JKpQ8olweDWEiEgKQQ+wJEQ3wgRjQRDP6z3aWFlss+bM6e833/5fsv2xUPY2qqRM/oU3WGqSgx+GHaXXGKWy1ssvdjIcwUIkdr19b7eyyqjr2sMGaYJXl5oqF6RJ0plBiq5JFIKC8s5IWwaYot2IwGiBy5OCuz3R0S25oYCWLddJcggffm5yJ3GgU377S7KdEwnNyWiakbXiUCoejMuVqlIqZgipeg6gjSxRBGqoneUjXN4+7Y4BgiMtYcoKSJlow5H1fAmUTXMeO84Iov9PKORUaIlnLmGHEITAyrWqTJxCKVlCaKTUtjZtMmIDsEGZsSVQ1HDAdciiZwCOstqo4RgZeQugXLqJlQBKkbFCuQoRrGuUiUJIuKzDnpMmLUMhkAUx48aL2Jmy0tSdwMHBQhFtIxIBgBgrkZU5RU3qkDEgPEYgjsURAE4TB8g4nVugG3pkIsTUYBjMR0eECkEY+TgOpAmkxJwSERMmh3G1AmTJmaFL3dnUQmT/ekOtWSE5JGSBBZRlLFiJGUzmRU1VvcHR1w57SJSrHsiJsyumEKlAQ2YYkBdENHXMGiDM22M6oQk9lD09rnAAiHDcZhXSIyOLD7W7aoRi6ScbMGciYkp67J/rQTQYwNTtRA79gEyx4UDUNTJdF5z3PK2JdqI86JZfpzwuk2DppQZ/ZIaTqOvNoIdLuOeI8v3+MdbONMJqq6Bu3KaSKEFDOS74enPhiiFAQ7XGqS7NgEeWAqhph2b7Uora2/y6SjtN0r0lBh/sGp99TSob+wHS+rne4u9TjpzucRBM8rQ3cZNiO6ZPc2i5qJh+6IfIeSgNnwcXwhxwsDaZU0aG2m2D0FXu9+6FUDug9vjYFJZpldUagIPvVjPDW3+9ZWpas57loQLYfq2N/7FSsXCYXoDVFHYL8AeYUSvriE96LKan9fWcqNf8ZiDPkptH4zFKQiXfy4pFh6EMuJshnLPuaeTMsZNg3mkXGppQXFcn7a0Xye58eyH4ikMCCq7niM+oqLix9iF5TBzB528gPxOKHQn8qSb5zZT3IOuYn9l4oq5kQFcS19KH4ytjQn+xE494nQ2ziWMxMbFsy0EHuLkt6WPRw/GWKKk/MonPuHiGai3yPfhKOXHoCcKtwEGj0Qfd94EqnKc6psfwfnJl5YUxGqa9xcU0lCtaFaucBPK9e1NazpCauinRA8AmohpEXDB8pWcmUirF+uPjlCdry8oaa0enVZ39tcHQkQ6CW/CD2nEx3H6jGF0bQTkkYsGZYdxTGg15U22MPFvE8QCoqKeMknF/OFBdwK2CHpYbozLFFnUyb/cjtjE9v5h4zliz96wpX8zJZ3lVbNFuZ23/6paPe7Yfzroa+vnC3L6698prz8s10fh7QvNF/Wpd6/jo4OZG6Pd/5zJPL0+MK9Fd3t48PnT28K37x1pHXn6Mjh9guLdlsHz8Ufz639d8ec7XtubBs8Nu8/pDSf2Ld1Y+dN5WTPisvWIX/NaOSk8Ngn3wxcazh/bv5zSmBuZte1q7eylrLnx0/0GBXjlW10vOl4Y/ZTxxfO+nAw59nfpSPb1i/vOpPxy/X1r+1HZ669lxGcM1bn/vmrD2pyWrPb974e+O2Uqya3beSFrH7p08+XxOxX5UCrcH3PyPnFw8dGg525Q8EsdUfG/LrB/ivzrl/aWCJnbqvt/qOjM7Jo1d4z3Z6qZa2VnetOJyKdK7/kvs22X9xy8Wj5jcs5Z/8+uuDgrTdjp6/++aTLdfv2bFfFhX7zcIbL9T+lrJEt
\ No newline at end of file
diff --git a/docs/cassettes/introduction_effb95d9-b7d5-40c5-9253-253d193b23b2.msgpack.zlib b/docs/cassettes/introduction_effb95d9-b7d5-40c5-9253-253d193b23b2.msgpack.zlib
index c83f512d7..8556e6463 100644
--- a/docs/cassettes/introduction_effb95d9-b7d5-40c5-9253-253d193b23b2.msgpack.zlib
+++ b/docs/cassettes/introduction_effb95d9-b7d5-40c5-9253-253d193b23b2.msgpack.zlib
@@ -1 +1 @@
-eNrtWHtcE3e2x0dXq7W66q3WlnWMokAzIQnhEUq7hQhKCwXlpTw2DpNfksHJzDgzIQks3hUf3PVBG9Tt3lt1a0FwqYL4WqpWqbduZdv6lhXqtvrxVam9t1d3sVp3vec3SXgotb2f2z/XD34+M/M77/M95/xOKupLkCgxPDdoG8PJSKRoGV6k6op6ES1yIkleVudAsp231GakZ2bVOEXmPbssC1JcRAQlMBqZKmFYj4bmHRESokTaXlvEWzydgyLKVHBsXog8qjhCJZewHtKdyomcQ6BMaQwSY61z6JcXmfiM9FTHvLz05JzYNJWaUIFGUeFIpTjbLJES7HGEy07JBCMRjKwm7LzL90g4JWRRExRngReJYCkZTCUsqASxvOBAnCxhcQ7KbRaR5GThNY7QwxefkWYLEmQ71kNZSiiORhZMzXA067Qgs4V3UAyHOfIL4TNyD/g5QE1xkguJ8NVKsRLqcyBSLjPNQ0w5eYBTxkHZkBQ4KK+3I8oCiVjRkC0hkUywAZd3r+CByHOkPxNShF4TCX9NCTQN9pNJHM1bGM7m3W4rZQQ1eG/FcajzHXtrwiPCG0w8xyElpd6GhQgJJMUyJajR5LOLTEWcTbZ7ayK1kdsC37I8AvLuoASBZWgKc0YUSzy3FeIoADDQ0jpJpmSnVFEL2tHHR+sdSJLAl7fTXwk4sfw71NZlIhHQ5t3C2RjO/T0KH7SxVqfTRdfOBAe972XZnWpCH01kIoHQa/UGQhcTZ9DHGYzErLQsBYFLwEoRYtM5tKAsgKofBVQqK8+yvMvsFMxKUnCxqOI4J8uqVQEo+N4CGQa0qHpAmF+mkhmZRX2tIUgCP5vsAC9Q4BRZOA0Umcvl0rBwSuNTpc7wmw3zAW0PvvpIA1cowipSDuTixYWElReJIifDYqQQOHXI6mTVhAPsYUiodjimMNokwsXIdiI1NU0iZBwdmuIIO8SCRQSoFVjkJiQacZTI8JISIxoiQRXxIoj08dqdDgiBhui1xcTyTovPIoB1CUMjxR4oP5b3YIOwHIkGdMBzL1sfLEhqn2xKcUImGY7IlJ0WhlcECSIv87JHAHaM/yKnzaY8KmLtFEaABsIk0bwIIddqjEajIVYfHQkZ6VudOGHl6t7UJIu8g0ikJIaGWPBEgr9JxBFJbjBc7GfsQxmTeRclWiQLJVMSzSBgVNJmBZlkkSKTlHky0HhIFBBJ9iSWRLG0jrYaLEUxsTGPyjIAkWQxPPvkW8kdb7VCHRLIDXwSVB5BOyWZdzCSElOCF/yhpTCWsTse3ok9VYACUUU0IyHW4ysTfMYhZNEQmdC9ENHPCCUrBMiUeQHU9iJZDTU0Q4K0Uw4WOgQIw/PFhtFiwY+8UmOI5iWPJCMHIJJaiC2BMkSU5MHWYNdEACf4wUClwaHM82wAfA5oRxi3GmI278KUavAdiYigfP8pQLTy7rNXoOzA5AT3ihDBOAA5JZDRB8Chj9ZrBwSHr4aVBmiWGQfQ6zQxxvLvnpIdIX3HJMXJdpEXGFqBQokuwt80Jd+4HFZfpswqmV+IlAmjg6aG55efCs+cMpXIY3ASKuhSIp5XvcNFlTLDAdGiRK4fNDWESXEYJ9DCExLvQAR4oYxAnDIINS4iB/q5qlxN9CqgJAniDTb314J7FyAKU5iQKEOOWc8UImWGElE71KyStB4FvTDBSsAGDZHFEzYk4zQRDh5aq1PApWDBDSSQUxHZ/ZBlOOBzKIBVgxaWxe1Z4c1SLh2EXw/C0wQpeOF5jH9ApVOALgSawGFwXCkJvxEEx7s02C/oGoqzikuK+z1fAGRm0IWpOMrh+6aoNPuvD/52bsZzyndzEJw4LmU/6gWmHEu2BCxymrW6XC5HZNwzadoZ+XKJ/Ioj2ZPMc6mq8sJ+6XsYH/kPOOez/wEM5ZcV4E5WAM8FP2T8FAB/QUCAj+ufQ+i7hlCBArEBAvwjT4vvT8o/Z8b/d2ZALguVDuLvE+YfVKS4mCUzEkW+Z1mAusWbhAPu0SyWQLMUrAZkJBlFSvgCLZP4cquFmRRQ558EP6wrWZBEi4ySNkyc8EDDxAl1MKUQWQzifr0Xkgzm47D7UCyLAAUg9GvQELCkQAErjBAvrifdOAO+WzDRczsmoDydUMlOUYTQExB1JQEpuGdCfQTCSwXMU1qopqetmiXajhyU0l0hAQJMHkaZiL3NtuxBV/tK6hkMTqFv2/etB6py3GTxDGdEhLOY7xda2IeULyqGXQZIC3vWtNdq7TC/vM0PzfYmyreboYF3swZ64MXIx/XwErTNX8mkPOCO1IBbPal0Tu8fEgJ2RGQoayOh1UQaNPodblJSZjUUlNI0vHW+tXJ/3wOBoheCHNL/Y4C3zsfc2JeGl7xb0ig6PbOfSBxp7xZKdEQbdvX9Ljo5fFHy1psyHlbnP+xVF6nR6TTG5n6CJQ9He7coldLcE+QelgaojUhSG01qdY2BKLGBVdEYZfy/LKyfBY199GYZFYs3y+/ZWJuzRMA+NNHezbyetju5hcjyHQtxh6rXL1xtLBSk3LPuk8qrt9ag1Wo7pj+SUkT4twmssTYSrrHfIxdf0WTvbuwfqTWS+ugs7GVkXJQhr4MYiNN3L/XbU4ftAYumPYKy154ANfFI6oHswVHPa/AbTTIW7wF4hv6a5Zo9T0iSZxvlWJTFuUv5WanU3LQ9bpLGc56URYpGpIIIt+ztIGJiaYNFTyFUpNWimCiLLjLaGmWI0VqtRdFFlKGopoShvA06jY6w8byNRU2mZNJEQc8hMxXYeOtnzn81IS3FtG0eOZcv4iF+WRTEmYNJEvhBo0FRDRUuojpgn5sw37s7ljZGaS0xtNESY4UBrSeTcufuCACoByC1uD30+8XiyGPPTF41PEj5N2R1zqfcp8lj/r4+zFwdtO4/Yl9d2RUiaByrwyNSOuPPLNd1BlfnR7h+u3GzPeTooQm79v1RW/HixOq2v7y7Qbq6+mDO+7mrGt7ovvs/a0e6FjffO9d0fu2W/MWll/6cfvx++c3c7Nx9Tx991Tt8b9bZ7Kv20RnT/q3oVENjaff4d5KuqKo2WdNtx62Hw7zHjv3sdxt/vnhxd0vDcx+mhDF7vvn2yxe3ntpeGDF5VRddef0n0fGJ/9nxYuSy2nUp4xMrQuq6b6823R53YOaU0Rteen7wlI8bl6bqk9dP0rxPVUy5FecOv1j3VvDw20OnRG0oO9P6uHCk5mc17WOyFoyvnqT1HL0cGubOy7y8ub5WXxkS9teh76S6hyS8f2td91lN46nsUn1lenD4UGPy4kXrn/z8q8cS1zbX//rWKHf1iek3Q44WP3Gy8kxFaHgUvW3z5JoVT8ddeeJc3k+1K4PnF3G/vzyxOcRte2J4fIHm87YaY0HXkLCLu9/6YIiQ+eShLm3tpDpNy5Olh6eNuXFjpu7YE19F11THXHj3rbKWoZfnRb995vj2k7uMB660dT5evPXO/sLOyC+LF623fh0+rmH9Vy2TVX9pr3xqUOWUn+SGesnM9qWFpe8t/6xx4+EdZOKCrtBx35wwrFvz++D45IOXJi460r7ysdJVbR+uvUFUjb3aOrjYgu7Gr0g9Qc9eOSU4NDQxdN972SP/KqafcCW9MfE3e7f+y8b/agwuPrf37JoXputubDp2cXRnK78szlot3gsJKa54ecmXn2yfW71julATevviRzk749etHtlSU3/0tHpS3ow/hWdTq+NTnh58ZfvBBUcvV2Scb7XMulGouim9cm/JjtemDS4Lm9dOhpUFqy/QE4aWHth8+IXNrLrlyvHpSftGzW3JuRr6vPrukszN9W3n7780L7Jl3vKJu5fJdZP2mcP36ytafzV/6TNTr7boznakvFl3P+FmVd6FKHTixOmnli2aGLvwcfG1r5/6+pru1/unsi0t8SPOCM8NWjG7zDMpJl/IO1UlPl13y6ie88m1X/zuXJr3sPd6rnfWv7LPTDk5NNET/Oz6vPhR3pikTW1LY1fn15wbFrucP/jGrmOJFaPj7rau2t+2Lazzb0uIKxltBktO+5o11lGbcuhPf9MUwlfeqfQ0ndplLLAkhjVrynYV76yakHs9c4Jq43n0JpeZ39naOu7K4Huc0FV2b7KFzTftfL3xyFTh28qy48NHVH34BZU0Zu/18ubItcIo/esj04QLKbrfLvuo7kTVZeFgRNWuNUz3rZduP/PhgVub9r186bhj6QJNZ1n6YbrEYjBHR68YrU84f+jFjleiN5fbn18+fRp/1jV+2JBEj22C6XJqyHMxacKgqe6Smux3pSrZ9sX0vJSMisrThk+m1rV3XHr30j9s3zbtOfPayqB/50fMiQu/9qv9Xo1pQor65pg5jqYRHwimr70zPv7Fhajww8MmhBo7m56d0uXYPbJpzKmPT78VnHF9wbX6/dnZ+z7fM8s4/oNV42+v2RD+t5kbgqdHRL46TD3qzu0zmYd2hsXMP998PPWnUds+GXuySWe8eeRA16Vka35428kdf9gxpFqK3WkbN7/b+nrNOxvHxlJznz+5YHJR67MH15lD54dGu375VE7o+49v23px57X2nMoZk/Z+dOeEaU77lht7NkXPGlRTfvq/g8gtd8k5fxLWuis+Gzvee2jrwb9n5r4dX/DmXmP2qpXVh9p19cW3E7+4ZV+Xs8rwx3m59J3Clm/ylhtWl27/pSml4UjE8WNdK2e9UN59496f+c//MSQo6P79IUHd11LTXSOCgv4XTCOo8w==
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_f4009ba6-dc0b-4216-ab0c-fbb104616f73.msgpack.zlib b/docs/cassettes/introduction_f4009ba6-dc0b-4216-ab0c-fbb104616f73.msgpack.zlib
deleted file mode 100644
index e629869fc..000000000
--- a/docs/cassettes/introduction_f4009ba6-dc0b-4216-ab0c-fbb104616f73.msgpack.zlib
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_f5447778-53d7-47f3-801b-f47bcf2185a0.msgpack.zlib b/docs/cassettes/introduction_f5447778-53d7-47f3-801b-f47bcf2185a0.msgpack.zlib
index e208dd31d..9e0098b4a 100644
--- a/docs/cassettes/introduction_f5447778-53d7-47f3-801b-f47bcf2185a0.msgpack.zlib
+++ b/docs/cassettes/introduction_f5447778-53d7-47f3-801b-f47bcf2185a0.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+eNqNVl1sU1Uc3xgxOkGRB4iK26HKRnS3u223QRcNbgPZWCZj68Qhyzy993S99Paeyz3nbnTLoo4FNSOOa0gGD6hhXUvqGCwSUdiegIDEaPwKTuMe1MQQH5QHHxTj/N/blg02PvrQnJ7z+/0/fv+PtC/ZSQymUC13VNE4MbDE4Qez+pIG2W0SxvsTUcLDVI43bm0ODJuGMrUmzLnOKktLsa64scbDBtUVyS3RaGmnpzRKGMMdhMWDVI79sOiPHlcU72nnNEI05qpEHtFbVoJcWRTcvNLjMqhK4OQyGTFc8CpRCEXj9lWtgniYGGQ1aoghDUcJUhjarqiq29VbgmapmDGFcYjmVj5RVeoQVqM6XsyQpkgEcYqihHAUo6Yb1dIuJGEN1aG0EfsWEDKObUB1LO0eYS2GdGxwRTJVbMAzpGwDi2WkKhHHoqwwyWQMUcNBO+rZWjr2wriTbLg55AWybSJREg0SA0XTyQKjzVaLykS13yUVmzIRfEK5wKimES54QU+xwivahjilakZRm2wTOO5U1Fg7I9iQwu0GYabKWfsuINsEmTDJUHQ7ShtchdI4RLQORSOIwktU6SYyCkFOUF/dIGEoo9JJShCWJNPA3D5pMuKGyTgAMx7cqIWRkKk6xC7gOBpoBBAgFNZYF+Q4KxAOUpMjsGeADoh0wjeYqNN0uGVhaqoyCkIJsuEB0Yi57QQUG9LOpDCJYsigx6VDLxKoktNZPS4H6ZxuSXWuJTskldIIMnVHxZjuSMe4oWgdrl6omcueBcUgsi1uxmjbHCgN7iISB2hbbzJMsAwTNRgPU8at8XkzcgKEIzoXiCZRGRxYxzu6Fb0EySSkgpwpya6rM4RWKkKILmAV9E6kWdZJrOuqImH7vdQu42imewQ7lvnPKbvJBJg0jVunq7JxlDbGYKQ1JLp9ZW7vyT0CTI6iqTCTgoohpITuvJ+d+6BjKQJ2hMy6sBJp8thcDGXWSAOWtjbfZNJW2hrBRrSi7KO594apQX8RK1nTON9d5nHWnc/t8bjXjd9kmMU0yRoJYZWR8Rsi36CkYDZ8glghiJ6xrEoqtDYPW8Pryj3HoFd16D6yNwEmucn64lAR8vmlZGY5Hd1an63mdM7K+EaojjUZCJslyFOBtsDCAPvlyOupFP2Vog9tbgiM1mTcBBYsxnjAgNYPQUE2ZYuflMKmFiFyqmbBsk+5ZtOyh02FeeRCZjNDseyfVrxMFMWpojsiDRgQRbM9xn1+v/8udkEZwq1Tdn4gnuCpCGSy9O5Y2I8zh0J6yWeiSthRQVxP3xU/G1uWU3QPnNtHWLwQGxbMvBBH1jvenrk7fjbEDKf4Xji3CdG3YwotRL9FvrSjp+6AnCtcGo3uiL6tZKlM5QVFtibg3C56vHhjbWssTCJdPLa9uoVGtfWtwU3DnQq2Uh63B3VQ2qGSEzUvCDUY1q/Q7IyQldzY+mJVQ13N6MtCEw1S6KUAhp7TqEYSzcSA0bRSkkpNGZadQRJAb6pqtU75RZ/HU+73eUPSOr9YUS5Uww7JDtONYYnbm9L5X/FGIr2dL+QWFw7cn+N88uTBhvrz4rJ9M1sODQwFzvx0Juwu+PZcwYqHBwrXNgW9Z5c2FJcf/oBcfW3I7V773n3Tv8XaD+WtfzD/n1P08oW2yclPu6fHVgy+cwbHzk49O/H9kuV7Vukfi2smNx9Ytvf9vCPv1o++XVVdWNLd+OrEFysGyO5t8ef7dwZIy9CHqcUPFC170nPsyjnl4LXIWOFg3/Uj4uqL/U2jm84XXO/aH1ziz//6uS3Xfp3YsPL3pz658Fb1N5eOD0/W5j12moU6vxz9c6zmq6OF55O/vKSf7J7Yd7Wh+mex7BEzf3H+AfWcf/m/r/cXPvoZWnt5uv7SxTe/y1219PDjDz3RtKjlytDy/RVCRdHR0Mpjf0cOFhds+3GmRP7vSOCvst68nJyZmbycrp1XpYHcnJz/AaIMyJ0=
\ No newline at end of file
diff --git a/docs/cassettes/introduction_faa345c6-38a2-42e8-9035-9cf56f7bb5b1.msgpack.zlib b/docs/cassettes/introduction_faa345c6-38a2-42e8-9035-9cf56f7bb5b1.msgpack.zlib
index 18913ce2b..967cd660a 100644
--- a/docs/cassettes/introduction_faa345c6-38a2-42e8-9035-9cf56f7bb5b1.msgpack.zlib
+++ b/docs/cassettes/introduction_faa345c6-38a2-42e8-9035-9cf56f7bb5b1.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+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
\ No newline at end of file

From e7aaf21121fe7f3d9405745de90aa09a2d2b5122 Mon Sep 17 00:00:00 2001
From: Chester Curme 
Date: Fri, 17 Jan 2025 10:02:18 -0500
Subject: [PATCH 08/15] update

---
 docs/docs/tutorials/introduction.ipynb | 1 +
 1 file changed, 1 insertion(+)

diff --git a/docs/docs/tutorials/introduction.ipynb b/docs/docs/tutorials/introduction.ipynb
index cc14e5cb4..b978af138 100644
--- a/docs/docs/tutorials/introduction.ipynb
+++ b/docs/docs/tutorials/introduction.ipynb
@@ -1617,6 +1617,7 @@
     "        \"birthday\": verified_birthday,\n",
     "        \"messages\": [ToolMessage(response, tool_call_id=tool_call_id)],\n",
     "    }\n",
+    "    # We return a Command object in the tool to update our state.\n",
     "    return Command(update=state_update)"
    ]
   },

From 784b6afa11cdc324f7a3d62cbb5cef1e6ecdf307 Mon Sep 17 00:00:00 2001
From: Chester Curme 
Date: Fri, 17 Jan 2025 10:15:06 -0500
Subject: [PATCH 09/15] disable parallel tool use

---
 docs/docs/tutorials/introduction.ipynb | 85 ++++++++++++++++----------
 1 file changed, 54 insertions(+), 31 deletions(-)

diff --git a/docs/docs/tutorials/introduction.ipynb b/docs/docs/tutorials/introduction.ipynb
index b978af138..dc80a1d50 100644
--- a/docs/docs/tutorials/introduction.ipynb
+++ b/docs/docs/tutorials/introduction.ipynb
@@ -1180,7 +1180,7 @@
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "08439bb4-91e8-4abb-a57a-2511877abcb7",
+   "id": "da81116c-73f6-410a-858a-3a362dc16dd3",
    "metadata": {},
    "outputs": [],
    "source": [
@@ -1222,7 +1222,13 @@
     "tool = TavilySearchResults(max_results=2)\n",
     "tools = [tool, human_assistance]\n",
     "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
-    "llm_with_tools = llm.bind_tools(tools)\n",
+    "llm_with_tools = llm.bind_tools(\n",
+    "    tools,\n",
+    "    # Because we will be interrupting during tool execution,\n",
+    "    # we disable parallel tool calling to avoid repeating any\n",
+    "    # tool invocations when we resume.\n",
+    "    tool_choice={\"type\": \"any\", \"disable_parallel_tool_use\": True},\n",
+    ")\n",
     "\n",
     "\n",
     "def chatbot(state: State):\n",
@@ -1260,7 +1266,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 2,
    "id": "16cc6b14-f758-4590-beb7-7b76a6841521",
    "metadata": {},
    "outputs": [],
@@ -1280,7 +1286,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 3,
    "id": "22ff19af-5a5b-4ca5-82d8-6a38445c24af",
    "metadata": {},
    "outputs": [
@@ -1315,7 +1321,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 4,
    "id": "9f318020-ab7e-415b-a5e2-eddec6d9f3a6",
    "metadata": {},
    "outputs": [
@@ -1328,12 +1334,12 @@
       "I need some expert guidance for building an AI agent. Could you request assistance for me?\n",
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_015tcCygn4UdBM24vg9NSycp', 'input': {'query': 'A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
+      "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. I'll use the human assistance function to ask for this guidance. Let me do that for you right away.\", 'type': 'text'}, {'id': 'toolu_01XufxDDxm3tXvuuX9h7C7v2', 'input': {'query': 'A user is seeking expert guidance for building an AI agent. Could you provide some key points or steps to consider when developing an AI agent?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
       "Tool Calls:\n",
-      "  human_assistance (toolu_015tcCygn4UdBM24vg9NSycp)\n",
-      " Call ID: toolu_015tcCygn4UdBM24vg9NSycp\n",
+      "  human_assistance (toolu_01XufxDDxm3tXvuuX9h7C7v2)\n",
+      " Call ID: toolu_01XufxDDxm3tXvuuX9h7C7v2\n",
       "  Args:\n",
-      "    query: A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?\n"
+      "    query: A user is seeking expert guidance for building an AI agent. Could you provide some key points or steps to consider when developing an AI agent?\n"
      ]
     }
    ],
@@ -1359,7 +1365,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 5,
    "id": "9f511371-98b6-4513-b450-9143778f12dc",
    "metadata": {},
    "outputs": [
@@ -1369,7 +1375,7 @@
        "('tools',)"
       ]
      },
-     "execution_count": 6,
+     "execution_count": 5,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -1401,7 +1407,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 6,
    "id": "df6d81bb-e674-44ef-a46e-17b1a8d2381a",
    "metadata": {},
    "outputs": [
@@ -1411,32 +1417,40 @@
      "text": [
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_015tcCygn4UdBM24vg9NSycp', 'input': {'query': 'A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
+      "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. I'll use the human assistance function to ask for this guidance. Let me do that for you right away.\", 'type': 'text'}, {'id': 'toolu_01XufxDDxm3tXvuuX9h7C7v2', 'input': {'query': 'A user is seeking expert guidance for building an AI agent. Could you provide some key points or steps to consider when developing an AI agent?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
       "Tool Calls:\n",
-      "  human_assistance (toolu_015tcCygn4UdBM24vg9NSycp)\n",
-      " Call ID: toolu_015tcCygn4UdBM24vg9NSycp\n",
+      "  human_assistance (toolu_01XufxDDxm3tXvuuX9h7C7v2)\n",
+      " Call ID: toolu_01XufxDDxm3tXvuuX9h7C7v2\n",
       "  Args:\n",
-      "    query: A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?\n",
+      "    query: A user is seeking expert guidance for building an AI agent. Could you provide some key points or steps to consider when developing an AI agent?\n",
       "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
       "Name: human_assistance\n",
       "\n",
       "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\n",
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "Thank you for your patience. I've received a response from the expert assistance. Here's the advice they provided:\n",
+      "Thank you for your patience. I've received some expert advice regarding building an AI agent. Here's the guidance provided:\n",
       "\n",
-      "The experts recommend that you check out LangGraph for building your AI agent. They suggest that LangGraph is a more reliable and extensible option compared to simple autonomous agents.\n",
+      "The experts recommend looking into LangGraph for building your AI agent. They suggest that LangGraph is a more reliable and extensible option compared to simple autonomous agents.\n",
       "\n",
-      "LangGraph is likely a framework or library designed specifically for creating AI agents. It seems to offer advantages in terms of reliability and extensibility, which are crucial factors when developing complex AI systems.\n",
+      "LangGraph is a framework designed to help developers create more complex and capable AI agents. Here are a few key points about LangGraph:\n",
       "\n",
-      "To follow up on this recommendation, you might want to:\n",
+      "1. Reliability: LangGraph is noted for being more reliable than simpler agent architectures, which can be crucial for developing robust AI systems.\n",
       "\n",
-      "1. Research LangGraph: Look for its official documentation, tutorials, and any community resources.\n",
-      "2. Compare LangGraph with other agent-building frameworks to understand its unique benefits.\n",
-      "3. Check if LangGraph aligns with your specific goals and requirements for your AI agent project.\n",
-      "4. Look for examples or case studies of AI agents built with LangGraph to get a better idea of its capabilities.\n",
+      "2. Extensibility: The framework offers greater flexibility and extensibility, allowing you to create more sophisticated and adaptable AI agents.\n",
       "\n",
-      "Would you like me to search for more specific information about LangGraph or any other aspect of building AI agents?\n"
+      "3. Advanced Capabilities: LangGraph likely provides tools and structures for creating agents with more complex behaviors and decision-making processes.\n",
+      "\n",
+      "4. Structured Development: Using a framework like LangGraph can provide a more organized approach to building AI agents, potentially simplifying the development process.\n",
+      "\n",
+      "To get started with LangGraph, you might want to:\n",
+      "\n",
+      "1. Research LangGraph documentation and tutorials.\n",
+      "2. Understand the core concepts and components of the framework.\n",
+      "3. Set up your development environment to work with LangGraph.\n",
+      "4. Start with simple projects to familiarize yourself with its features before moving on to more complex agent designs.\n",
+      "\n",
+      "Would you like more specific information about LangGraph or any particular aspect of building AI agents? I'd be happy to request further assistance or search for more detailed information if needed.\n"
      ]
     }
    ],
@@ -1502,7 +1516,10 @@
     "tool = TavilySearchResults(max_results=2)\n",
     "tools = [tool, human_assistance]\n",
     "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
-    "llm_with_tools = llm.bind_tools(tools)\n",
+    "llm_with_tools = llm.bind_tools(\n",
+    "    tools,\n",
+    "    tool_choice={\"type\": \"any\", \"disable_parallel_tool_use\": True},\n",
+    ")\n",
     "\n",
     "\n",
     "def chatbot(state: State):\n",
@@ -1540,7 +1557,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 7,
    "id": "84627103-bcc8-4645-bd37-b93209fa09dd",
    "metadata": {},
    "outputs": [],
@@ -1572,7 +1589,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 8,
    "id": "c4b65504-92c7-4c82-a6ee-824885d1a8a4",
    "metadata": {},
    "outputs": [],
@@ -1631,7 +1648,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 9,
    "id": "e256fa2e-6c13-42dd-a0a5-d206ee4139bf",
    "metadata": {},
    "outputs": [],
@@ -1647,7 +1664,10 @@
     "tool = TavilySearchResults(max_results=2)\n",
     "tools = [tool, human_assistance]\n",
     "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
-    "llm_with_tools = llm.bind_tools(tools)\n",
+    "llm_with_tools = llm.bind_tools(\n",
+    "    tools,\n",
+    "    tool_choice={\"type\": \"any\", \"disable_parallel_tool_use\": True},\n",
+    ")\n",
     "\n",
     "\n",
     "def chatbot(state: State):\n",
@@ -1966,7 +1986,10 @@
     "tool = TavilySearchResults(max_results=2)\n",
     "tools = [tool, human_assistance]\n",
     "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
-    "llm_with_tools = llm.bind_tools(tools)\n",
+    "llm_with_tools = llm.bind_tools(\n",
+    "    tools,\n",
+    "    tool_choice={\"type\": \"any\", \"disable_parallel_tool_use\": True},\n",
+    ")\n",
     "\n",
     "\n",
     "def chatbot(state: State):\n",

From 4c02a4c501e79ff0d5a159f37c04e8bbb7cbb3a3 Mon Sep 17 00:00:00 2001
From: Chester Curme 
Date: Fri, 17 Jan 2025 10:19:17 -0500
Subject: [PATCH 10/15] Revert "disable parallel tool use"

This reverts commit 784b6afa11cdc324f7a3d62cbb5cef1e6ecdf307.
---
 docs/docs/tutorials/introduction.ipynb | 85 ++++++++++----------------
 1 file changed, 31 insertions(+), 54 deletions(-)

diff --git a/docs/docs/tutorials/introduction.ipynb b/docs/docs/tutorials/introduction.ipynb
index dc80a1d50..b978af138 100644
--- a/docs/docs/tutorials/introduction.ipynb
+++ b/docs/docs/tutorials/introduction.ipynb
@@ -1180,7 +1180,7 @@
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "da81116c-73f6-410a-858a-3a362dc16dd3",
+   "id": "08439bb4-91e8-4abb-a57a-2511877abcb7",
    "metadata": {},
    "outputs": [],
    "source": [
@@ -1222,13 +1222,7 @@
     "tool = TavilySearchResults(max_results=2)\n",
     "tools = [tool, human_assistance]\n",
     "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
-    "llm_with_tools = llm.bind_tools(\n",
-    "    tools,\n",
-    "    # Because we will be interrupting during tool execution,\n",
-    "    # we disable parallel tool calling to avoid repeating any\n",
-    "    # tool invocations when we resume.\n",
-    "    tool_choice={\"type\": \"any\", \"disable_parallel_tool_use\": True},\n",
-    ")\n",
+    "llm_with_tools = llm.bind_tools(tools)\n",
     "\n",
     "\n",
     "def chatbot(state: State):\n",
@@ -1266,7 +1260,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 3,
    "id": "16cc6b14-f758-4590-beb7-7b76a6841521",
    "metadata": {},
    "outputs": [],
@@ -1286,7 +1280,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 4,
    "id": "22ff19af-5a5b-4ca5-82d8-6a38445c24af",
    "metadata": {},
    "outputs": [
@@ -1321,7 +1315,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 5,
    "id": "9f318020-ab7e-415b-a5e2-eddec6d9f3a6",
    "metadata": {},
    "outputs": [
@@ -1334,12 +1328,12 @@
       "I need some expert guidance for building an AI agent. Could you request assistance for me?\n",
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. I'll use the human assistance function to ask for this guidance. Let me do that for you right away.\", 'type': 'text'}, {'id': 'toolu_01XufxDDxm3tXvuuX9h7C7v2', 'input': {'query': 'A user is seeking expert guidance for building an AI agent. Could you provide some key points or steps to consider when developing an AI agent?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
+      "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_015tcCygn4UdBM24vg9NSycp', 'input': {'query': 'A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
       "Tool Calls:\n",
-      "  human_assistance (toolu_01XufxDDxm3tXvuuX9h7C7v2)\n",
-      " Call ID: toolu_01XufxDDxm3tXvuuX9h7C7v2\n",
+      "  human_assistance (toolu_015tcCygn4UdBM24vg9NSycp)\n",
+      " Call ID: toolu_015tcCygn4UdBM24vg9NSycp\n",
       "  Args:\n",
-      "    query: A user is seeking expert guidance for building an AI agent. Could you provide some key points or steps to consider when developing an AI agent?\n"
+      "    query: A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?\n"
      ]
     }
    ],
@@ -1365,7 +1359,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 6,
    "id": "9f511371-98b6-4513-b450-9143778f12dc",
    "metadata": {},
    "outputs": [
@@ -1375,7 +1369,7 @@
        "('tools',)"
       ]
      },
-     "execution_count": 5,
+     "execution_count": 6,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -1407,7 +1401,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 7,
    "id": "df6d81bb-e674-44ef-a46e-17b1a8d2381a",
    "metadata": {},
    "outputs": [
@@ -1417,40 +1411,32 @@
      "text": [
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. I'll use the human assistance function to ask for this guidance. Let me do that for you right away.\", 'type': 'text'}, {'id': 'toolu_01XufxDDxm3tXvuuX9h7C7v2', 'input': {'query': 'A user is seeking expert guidance for building an AI agent. Could you provide some key points or steps to consider when developing an AI agent?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
+      "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_015tcCygn4UdBM24vg9NSycp', 'input': {'query': 'A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
       "Tool Calls:\n",
-      "  human_assistance (toolu_01XufxDDxm3tXvuuX9h7C7v2)\n",
-      " Call ID: toolu_01XufxDDxm3tXvuuX9h7C7v2\n",
+      "  human_assistance (toolu_015tcCygn4UdBM24vg9NSycp)\n",
+      " Call ID: toolu_015tcCygn4UdBM24vg9NSycp\n",
       "  Args:\n",
-      "    query: A user is seeking expert guidance for building an AI agent. Could you provide some key points or steps to consider when developing an AI agent?\n",
+      "    query: A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?\n",
       "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
       "Name: human_assistance\n",
       "\n",
       "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\n",
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "Thank you for your patience. I've received some expert advice regarding building an AI agent. Here's the guidance provided:\n",
+      "Thank you for your patience. I've received a response from the expert assistance. Here's the advice they provided:\n",
       "\n",
-      "The experts recommend looking into LangGraph for building your AI agent. They suggest that LangGraph is a more reliable and extensible option compared to simple autonomous agents.\n",
+      "The experts recommend that you check out LangGraph for building your AI agent. They suggest that LangGraph is a more reliable and extensible option compared to simple autonomous agents.\n",
       "\n",
-      "LangGraph is a framework designed to help developers create more complex and capable AI agents. Here are a few key points about LangGraph:\n",
+      "LangGraph is likely a framework or library designed specifically for creating AI agents. It seems to offer advantages in terms of reliability and extensibility, which are crucial factors when developing complex AI systems.\n",
       "\n",
-      "1. Reliability: LangGraph is noted for being more reliable than simpler agent architectures, which can be crucial for developing robust AI systems.\n",
+      "To follow up on this recommendation, you might want to:\n",
       "\n",
-      "2. Extensibility: The framework offers greater flexibility and extensibility, allowing you to create more sophisticated and adaptable AI agents.\n",
+      "1. Research LangGraph: Look for its official documentation, tutorials, and any community resources.\n",
+      "2. Compare LangGraph with other agent-building frameworks to understand its unique benefits.\n",
+      "3. Check if LangGraph aligns with your specific goals and requirements for your AI agent project.\n",
+      "4. Look for examples or case studies of AI agents built with LangGraph to get a better idea of its capabilities.\n",
       "\n",
-      "3. Advanced Capabilities: LangGraph likely provides tools and structures for creating agents with more complex behaviors and decision-making processes.\n",
-      "\n",
-      "4. Structured Development: Using a framework like LangGraph can provide a more organized approach to building AI agents, potentially simplifying the development process.\n",
-      "\n",
-      "To get started with LangGraph, you might want to:\n",
-      "\n",
-      "1. Research LangGraph documentation and tutorials.\n",
-      "2. Understand the core concepts and components of the framework.\n",
-      "3. Set up your development environment to work with LangGraph.\n",
-      "4. Start with simple projects to familiarize yourself with its features before moving on to more complex agent designs.\n",
-      "\n",
-      "Would you like more specific information about LangGraph or any particular aspect of building AI agents? I'd be happy to request further assistance or search for more detailed information if needed.\n"
+      "Would you like me to search for more specific information about LangGraph or any other aspect of building AI agents?\n"
      ]
     }
    ],
@@ -1516,10 +1502,7 @@
     "tool = TavilySearchResults(max_results=2)\n",
     "tools = [tool, human_assistance]\n",
     "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
-    "llm_with_tools = llm.bind_tools(\n",
-    "    tools,\n",
-    "    tool_choice={\"type\": \"any\", \"disable_parallel_tool_use\": True},\n",
-    ")\n",
+    "llm_with_tools = llm.bind_tools(tools)\n",
     "\n",
     "\n",
     "def chatbot(state: State):\n",
@@ -1557,7 +1540,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 2,
    "id": "84627103-bcc8-4645-bd37-b93209fa09dd",
    "metadata": {},
    "outputs": [],
@@ -1589,7 +1572,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 3,
    "id": "c4b65504-92c7-4c82-a6ee-824885d1a8a4",
    "metadata": {},
    "outputs": [],
@@ -1648,7 +1631,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 4,
    "id": "e256fa2e-6c13-42dd-a0a5-d206ee4139bf",
    "metadata": {},
    "outputs": [],
@@ -1664,10 +1647,7 @@
     "tool = TavilySearchResults(max_results=2)\n",
     "tools = [tool, human_assistance]\n",
     "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
-    "llm_with_tools = llm.bind_tools(\n",
-    "    tools,\n",
-    "    tool_choice={\"type\": \"any\", \"disable_parallel_tool_use\": True},\n",
-    ")\n",
+    "llm_with_tools = llm.bind_tools(tools)\n",
     "\n",
     "\n",
     "def chatbot(state: State):\n",
@@ -1986,10 +1966,7 @@
     "tool = TavilySearchResults(max_results=2)\n",
     "tools = [tool, human_assistance]\n",
     "llm = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
-    "llm_with_tools = llm.bind_tools(\n",
-    "    tools,\n",
-    "    tool_choice={\"type\": \"any\", \"disable_parallel_tool_use\": True},\n",
-    ")\n",
+    "llm_with_tools = llm.bind_tools(tools)\n",
     "\n",
     "\n",
     "def chatbot(state: State):\n",

From 18c6637e6c2bb820b57208b3f9a02e0c64feb1d4 Mon Sep 17 00:00:00 2001
From: Chester Curme 
Date: Fri, 17 Jan 2025 10:34:21 -0500
Subject: [PATCH 11/15] use message dicts instead of tuples

---
 docs/docs/tutorials/introduction.ipynb | 33 ++++++++++++++++++--------
 1 file changed, 23 insertions(+), 10 deletions(-)

diff --git a/docs/docs/tutorials/introduction.ipynb b/docs/docs/tutorials/introduction.ipynb
index b978af138..8e40e8b66 100644
--- a/docs/docs/tutorials/introduction.ipynb
+++ b/docs/docs/tutorials/introduction.ipynb
@@ -276,7 +276,7 @@
    ],
    "source": [
     "def stream_graph_updates(user_input: str):\n",
-    "    for event in graph.stream({\"messages\": [(\"user\", user_input)]}):\n",
+    "    for event in graph.stream({\"messages\": [{\"role\": \"user\", \"content\": user_input}]}):\n",
     "        for value in event.values():\n",
     "            print(\"Assistant:\", value[\"messages\"][-1].content)\n",
     "\n",
@@ -958,7 +958,7 @@
     "\n",
     "# The config is the **second positional argument** to stream() or invoke()!\n",
     "events = graph.stream(\n",
-    "    {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n",
+    "    {\"messages\": [{\"role\": \"user\", \"content\": user_input}]}, config, stream_mode=\"values\"\n",
     ")\n",
     "for event in events:\n",
     "    event[\"messages\"][-1].pretty_print()"
@@ -998,7 +998,7 @@
     "\n",
     "# The config is the **second positional argument** to stream() or invoke()!\n",
     "events = graph.stream(\n",
-    "    {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n",
+    "    {\"messages\": [{\"role\": \"user\", \"content\": user_input}]}, config, stream_mode=\"values\"\n",
     ")\n",
     "for event in events:\n",
     "    event[\"messages\"][-1].pretty_print()"
@@ -1036,7 +1036,8 @@
    "source": [
     "# The only difference is we change the `thread_id` here to \"2\" instead of \"1\"\n",
     "events = graph.stream(\n",
-    "    {\"messages\": [(\"user\", user_input)]},\n",
+    "    {\"messages\": [{\"role\": \"user\", \"content\": user_input}]},\n",
+    "    # highlight-next-line\n",
     "    {\"configurable\": {\"thread_id\": \"2\"}},\n",
     "    stream_mode=\"values\",\n",
     ")\n",
@@ -1342,7 +1343,7 @@
     "config = {\"configurable\": {\"thread_id\": \"1\"}}\n",
     "\n",
     "events = graph.stream(\n",
-    "    {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n",
+    "    {\"messages\": [{\"role\": \"user\", \"content\": user_input}]}, config, stream_mode=\"values\"\n",
     ")\n",
     "for event in events:\n",
     "    if \"messages\" in event:\n",
@@ -1724,7 +1725,7 @@
     "config = {\"configurable\": {\"thread_id\": \"1\"}}\n",
     "\n",
     "events = graph.stream(\n",
-    "    {\"messages\": [(\"user\", user_input)]}, config, stream_mode=\"values\"\n",
+    "    {\"messages\": [{\"role\": \"user\", \"content\": user_input}]}, config, stream_mode=\"values\"\n",
     ")\n",
     "for event in events:\n",
     "    if \"messages\" in event:\n",
@@ -2137,8 +2138,14 @@
     "events = graph.stream(\n",
     "    {\n",
     "        \"messages\": [\n",
-    "            (\"user\", \"I'm learning LangGraph. Could you do some research on it for me?\")\n",
-    "        ]\n",
+    "            {\n",
+    "                \"role\": \"user\",\n",
+    "                \"content\": (\n",
+    "                    \"I'm learning LangGraph. \"\n",
+    "                    \"Could you do some research on it for me?\"\n",
+    "                ),\n",
+    "            },\n",
+    "        ],\n",
     "    },\n",
     "    config,\n",
     "    stream_mode=\"values\",\n",
@@ -2211,8 +2218,14 @@
     "events = graph.stream(\n",
     "    {\n",
     "        \"messages\": [\n",
-    "            (\"user\", \"Ya that's helpful. Maybe I'll build an autonomous agent with it!\")\n",
-    "        ]\n",
+    "            {\n",
+    "                \"role\": \"user\",\n",
+    "                \"content\": (\n",
+    "                    \"Ya that's helpful. Maybe I'll \"\n",
+    "                    \"build an autonomous agent with it!\"\n",
+    "                ),\n",
+    "            },\n",
+    "        ],\n",
     "    },\n",
     "    config,\n",
     "    stream_mode=\"values\",\n",

From 02ea5238971335f8dc01cd55dac674d5663c71a8 Mon Sep 17 00:00:00 2001
From: Chester Curme 
Date: Fri, 17 Jan 2025 11:02:25 -0500
Subject: [PATCH 12/15] udpate

---
 docs/docs/tutorials/introduction.ipynb | 90 +++++++++++++++-----------
 1 file changed, 51 insertions(+), 39 deletions(-)

diff --git a/docs/docs/tutorials/introduction.ipynb b/docs/docs/tutorials/introduction.ipynb
index 8e40e8b66..cf6c15ca0 100644
--- a/docs/docs/tutorials/introduction.ipynb
+++ b/docs/docs/tutorials/introduction.ipynb
@@ -1227,7 +1227,12 @@
     "\n",
     "\n",
     "def chatbot(state: State):\n",
-    "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
+    "    message = llm_with_tools.invoke(state[\"messages\"])\n",
+    "    # Because we will be interrupting during tool execution,\n",
+    "    # we disable parallel tool calling to avoid repeating any\n",
+    "    # tool invocations when we resume.\n",
+    "    assert(len(message.tool_calls) <= 1)\n",
+    "    return {\"messages\": [message]}\n",
     "\n",
     "\n",
     "graph_builder.add_node(\"chatbot\", chatbot)\n",
@@ -1261,7 +1266,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 3,
+   "execution_count": 2,
    "id": "16cc6b14-f758-4590-beb7-7b76a6841521",
    "metadata": {},
    "outputs": [],
@@ -1281,7 +1286,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 3,
    "id": "22ff19af-5a5b-4ca5-82d8-6a38445c24af",
    "metadata": {},
    "outputs": [
@@ -1316,7 +1321,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 4,
    "id": "9f318020-ab7e-415b-a5e2-eddec6d9f3a6",
    "metadata": {},
    "outputs": [
@@ -1329,12 +1334,12 @@
       "I need some expert guidance for building an AI agent. Could you request assistance for me?\n",
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_015tcCygn4UdBM24vg9NSycp', 'input': {'query': 'A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
+      "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01ABUqneqnuHNuo1vhfDFQCW', 'input': {'query': 'A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
       "Tool Calls:\n",
-      "  human_assistance (toolu_015tcCygn4UdBM24vg9NSycp)\n",
-      " Call ID: toolu_015tcCygn4UdBM24vg9NSycp\n",
+      "  human_assistance (toolu_01ABUqneqnuHNuo1vhfDFQCW)\n",
+      " Call ID: toolu_01ABUqneqnuHNuo1vhfDFQCW\n",
       "  Args:\n",
-      "    query: A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?\n"
+      "    query: A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic?\n"
      ]
     }
    ],
@@ -1360,7 +1365,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 5,
    "id": "9f511371-98b6-4513-b450-9143778f12dc",
    "metadata": {},
    "outputs": [
@@ -1370,7 +1375,7 @@
        "('tools',)"
       ]
      },
-     "execution_count": 6,
+     "execution_count": 5,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -1402,7 +1407,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 6,
    "id": "df6d81bb-e674-44ef-a46e-17b1a8d2381a",
    "metadata": {},
    "outputs": [
@@ -1412,32 +1417,37 @@
      "text": [
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_015tcCygn4UdBM24vg9NSycp', 'input': {'query': 'A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
+      "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01ABUqneqnuHNuo1vhfDFQCW', 'input': {'query': 'A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
       "Tool Calls:\n",
-      "  human_assistance (toolu_015tcCygn4UdBM24vg9NSycp)\n",
-      " Call ID: toolu_015tcCygn4UdBM24vg9NSycp\n",
+      "  human_assistance (toolu_01ABUqneqnuHNuo1vhfDFQCW)\n",
+      " Call ID: toolu_01ABUqneqnuHNuo1vhfDFQCW\n",
       "  Args:\n",
-      "    query: A user is seeking expert guidance for building an AI agent. Can you provide some professional advice or resources on this topic?\n",
+      "    query: A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic?\n",
       "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
       "Name: human_assistance\n",
       "\n",
       "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\n",
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "Thank you for your patience. I've received a response from the expert assistance. Here's the advice they provided:\n",
+      "Thank you for your patience. I've received some expert advice regarding your request for guidance on building an AI agent. Here's what the experts have suggested:\n",
       "\n",
-      "The experts recommend that you check out LangGraph for building your AI agent. They suggest that LangGraph is a more reliable and extensible option compared to simple autonomous agents.\n",
+      "The experts recommend that you look into LangGraph for building your AI agent. They mention that LangGraph is a more reliable and extensible option compared to simple autonomous agents.\n",
       "\n",
-      "LangGraph is likely a framework or library designed specifically for creating AI agents. It seems to offer advantages in terms of reliability and extensibility, which are crucial factors when developing complex AI systems.\n",
+      "LangGraph is likely a framework or library designed specifically for creating AI agents with advanced capabilities. Here are a few points to consider based on this recommendation:\n",
       "\n",
-      "To follow up on this recommendation, you might want to:\n",
+      "1. Reliability: The experts emphasize that LangGraph is more reliable than simpler autonomous agent approaches. This could mean it has better stability, error handling, or consistent performance.\n",
       "\n",
-      "1. Research LangGraph: Look for its official documentation, tutorials, and any community resources.\n",
-      "2. Compare LangGraph with other agent-building frameworks to understand its unique benefits.\n",
-      "3. Check if LangGraph aligns with your specific goals and requirements for your AI agent project.\n",
-      "4. Look for examples or case studies of AI agents built with LangGraph to get a better idea of its capabilities.\n",
+      "2. Extensibility: LangGraph is described as more extensible, which suggests that it probably offers a flexible architecture that allows you to easily add new features or modify existing ones as your agent's requirements evolve.\n",
       "\n",
-      "Would you like me to search for more specific information about LangGraph or any other aspect of building AI agents?\n"
+      "3. Advanced capabilities: Given that it's recommended over \"simple autonomous agents,\" LangGraph likely provides more sophisticated tools and techniques for building complex AI agents.\n",
+      "\n",
+      "To get started with LangGraph, you might want to:\n",
+      "\n",
+      "1. Search for the official LangGraph documentation or website to learn more about its features and how to use it.\n",
+      "2. Look for tutorials or guides specifically focused on building AI agents with LangGraph.\n",
+      "3. Check if there are any community forums or discussion groups where you can ask questions and get support from other developers using LangGraph.\n",
+      "\n",
+      "If you'd like more specific information about LangGraph or have any questions about this recommendation, please feel free to ask, and I can request further assistance from the experts.\n"
      ]
     }
    ],
@@ -1652,7 +1662,9 @@
     "\n",
     "\n",
     "def chatbot(state: State):\n",
-    "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
+    "    message = llm_with_tools.invoke(state[\"messages\"])\n",
+    "    assert(len(message.tool_calls) <= 1)\n",
+    "    return {\"messages\": [message]}\n",
     "\n",
     "\n",
     "graph_builder = StateGraph(State)\n",
@@ -1695,10 +1707,10 @@
       "Can you look up when LangGraph was released? When you have the answer, use the human_assistance tool for review.\n",
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "[{'text': \"Certainly! I'll start by searching for information about LangGraph's release date using the Tavily search engine. Then, I'll use the human_assistance tool for review. Let's begin with the search.\", 'type': 'text'}, {'id': 'toolu_01APsgm3wwYXyZQcZJNb3rGJ', 'input': {'query': 'LangGraph release date'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n",
+      "[{'text': \"Certainly! I'll start by searching for information about LangGraph's release date using the Tavily search function. Then, I'll use the human_assistance tool for review.\", 'type': 'text'}, {'id': 'toolu_01JoXQPgTVJXiuma8xMVwqAi', 'input': {'query': 'LangGraph release date'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n",
       "Tool Calls:\n",
-      "  tavily_search_results_json (toolu_01APsgm3wwYXyZQcZJNb3rGJ)\n",
-      " Call ID: toolu_01APsgm3wwYXyZQcZJNb3rGJ\n",
+      "  tavily_search_results_json (toolu_01JoXQPgTVJXiuma8xMVwqAi)\n",
+      " Call ID: toolu_01JoXQPgTVJXiuma8xMVwqAi\n",
       "  Args:\n",
       "    query: LangGraph release date\n",
       "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
@@ -1707,10 +1719,10 @@
       "[{\"url\": \"https://blog.langchain.dev/langgraph-cloud/\", \"content\": \"We also have a new stable release of LangGraph. By LangChain 6 min read Jun 27, 2024 (Oct '24) Edit: Since the launch of LangGraph Cloud, we now have multiple deployment options alongside LangGraph Studio - which now fall under LangGraph Platform. LangGraph Cloud is synonymous with our Cloud SaaS deployment option.\"}, {\"url\": \"https://changelog.langchain.com/announcements/langgraph-cloud-deploy-at-scale-monitor-carefully-iterate-boldly\", \"content\": \"LangChain - Changelog | ☁ 🚀 LangGraph Cloud: Deploy at scale, monitor LangChain LangSmith LangGraph LangChain LangSmith LangGraph LangChain LangSmith LangGraph LangChain Changelog Sign up for our newsletter to stay up to date DATE: The LangChain Team LangGraph LangGraph Cloud ☁ 🚀 LangGraph Cloud: Deploy at scale, monitor carefully, iterate boldly DATE: June 27, 2024 AUTHOR: The LangChain Team LangGraph Cloud is now in closed beta, offering scalable, fault-tolerant deployment for LangGraph agents. LangGraph Cloud also includes a new playground-like studio for debugging agent failure modes and quick iteration: Join the waitlist today for LangGraph Cloud. And to learn more, read our blog post announcement or check out our docs. Subscribe By clicking subscribe, you accept our privacy policy and terms and conditions.\"}]\n",
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "[{'text': 'Based on the search results, it appears that LangGraph was released before June 27, 2024. The search results mention a \"new stable release of LangGraph\" and \"LangGraph Cloud\" being announced on that date. However, the exact initial release date of LangGraph is not clearly stated in these results.\\n\\nGiven this information, I\\'ll use the human_assistance tool to review and possibly get more precise information about LangGraph\\'s initial release date.', 'type': 'text'}, {'id': 'toolu_01JtZJvDho75gcLbqcHHp4if', 'input': {'name': 'Assistant', 'birthday': '2023-01-01'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
+      "[{'text': \"Based on the search results, it appears that LangGraph was already in existence before June 27, 2024, when LangGraph Cloud was announced. However, the search results don't provide a specific release date for the original LangGraph. \\n\\nGiven this information, I'll use the human_assistance tool to review and potentially provide more accurate information about LangGraph's initial release date.\", 'type': 'text'}, {'id': 'toolu_01JDQAV7nPqMkHHhNs3j3XoN', 'input': {'name': 'Assistant', 'birthday': '2023-01-01'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
       "Tool Calls:\n",
-      "  human_assistance (toolu_01JtZJvDho75gcLbqcHHp4if)\n",
-      " Call ID: toolu_01JtZJvDho75gcLbqcHHp4if\n",
+      "  human_assistance (toolu_01JDQAV7nPqMkHHhNs3j3XoN)\n",
+      " Call ID: toolu_01JDQAV7nPqMkHHhNs3j3XoN\n",
       "  Args:\n",
       "    name: Assistant\n",
       "    birthday: 2023-01-01\n"
@@ -1752,10 +1764,10 @@
      "text": [
       "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
       "\n",
-      "[{'text': 'Based on the search results, it appears that LangGraph was released before June 27, 2024. The search results mention a \"new stable release of LangGraph\" and \"LangGraph Cloud\" being announced on that date. However, the exact initial release date of LangGraph is not clearly stated in these results.\\n\\nGiven this information, I\\'ll use the human_assistance tool to review and possibly get more precise information about LangGraph\\'s initial release date.', 'type': 'text'}, {'id': 'toolu_01JtZJvDho75gcLbqcHHp4if', 'input': {'name': 'Assistant', 'birthday': '2023-01-01'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
+      "[{'text': \"Based on the search results, it appears that LangGraph was already in existence before June 27, 2024, when LangGraph Cloud was announced. However, the search results don't provide a specific release date for the original LangGraph. \\n\\nGiven this information, I'll use the human_assistance tool to review and potentially provide more accurate information about LangGraph's initial release date.\", 'type': 'text'}, {'id': 'toolu_01JDQAV7nPqMkHHhNs3j3XoN', 'input': {'name': 'Assistant', 'birthday': '2023-01-01'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n",
       "Tool Calls:\n",
-      "  human_assistance (toolu_01JtZJvDho75gcLbqcHHp4if)\n",
-      " Call ID: toolu_01JtZJvDho75gcLbqcHHp4if\n",
+      "  human_assistance (toolu_01JDQAV7nPqMkHHhNs3j3XoN)\n",
+      " Call ID: toolu_01JDQAV7nPqMkHHhNs3j3XoN\n",
       "  Args:\n",
       "    name: Assistant\n",
       "    birthday: 2023-01-01\n",
@@ -1767,13 +1779,13 @@
       "\n",
       "Thank you for the human assistance. I can now provide you with the correct information about LangGraph's release date.\n",
       "\n",
-      "LangGraph was initially released on January 17, 2024. This information comes directly from the human assistance, which provided a correction to my earlier uncertainty.\n",
+      "LangGraph was initially released on January 17, 2024. This information comes from the human assistance correction, which is more accurate than the search results I initially found.\n",
       "\n",
       "To summarize:\n",
-      "- Initial search results were not clear about the exact release date of LangGraph.\n",
-      "- Human assistance provided the precise release date: January 17, 2024.\n",
+      "1. LangGraph's original release date: January 17, 2024\n",
+      "2. LangGraph Cloud announcement: June 27, 2024\n",
       "\n",
-      "This demonstrates the importance of verifying information, especially for newer technologies or products where online search results might not always provide the most up-to-date or accurate information.\n"
+      "It's worth noting that LangGraph had been in development and use for some time before the LangGraph Cloud announcement, but the official initial release of LangGraph itself was on January 17, 2024.\n"
      ]
     }
    ],
@@ -1851,7 +1863,7 @@
       "text/plain": [
        "{'configurable': {'thread_id': '1',\n",
        "  'checkpoint_ns': '',\n",
-       "  'checkpoint_id': '1efd4395-61ae-6f14-8006-fb093210b222'}}"
+       "  'checkpoint_id': '1efd4ec5-cf69-6352-8006-9278f1730162'}}"
       ]
      },
      "execution_count": 8,

From a54689affdba0f7d8d5b84965854afd7d49dce95 Mon Sep 17 00:00:00 2001
From: Chester Curme 
Date: Fri, 17 Jan 2025 11:02:58 -0500
Subject: [PATCH 13/15] ruff

---
 docs/docs/tutorials/introduction.ipynb | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/docs/docs/tutorials/introduction.ipynb b/docs/docs/tutorials/introduction.ipynb
index cf6c15ca0..10c9ef4b2 100644
--- a/docs/docs/tutorials/introduction.ipynb
+++ b/docs/docs/tutorials/introduction.ipynb
@@ -958,7 +958,9 @@
     "\n",
     "# The config is the **second positional argument** to stream() or invoke()!\n",
     "events = graph.stream(\n",
-    "    {\"messages\": [{\"role\": \"user\", \"content\": user_input}]}, config, stream_mode=\"values\"\n",
+    "    {\"messages\": [{\"role\": \"user\", \"content\": user_input}]},\n",
+    "    config,\n",
+    "    stream_mode=\"values\",\n",
     ")\n",
     "for event in events:\n",
     "    event[\"messages\"][-1].pretty_print()"
@@ -998,7 +1000,9 @@
     "\n",
     "# The config is the **second positional argument** to stream() or invoke()!\n",
     "events = graph.stream(\n",
-    "    {\"messages\": [{\"role\": \"user\", \"content\": user_input}]}, config, stream_mode=\"values\"\n",
+    "    {\"messages\": [{\"role\": \"user\", \"content\": user_input}]},\n",
+    "    config,\n",
+    "    stream_mode=\"values\",\n",
     ")\n",
     "for event in events:\n",
     "    event[\"messages\"][-1].pretty_print()"
@@ -1231,7 +1235,7 @@
     "    # Because we will be interrupting during tool execution,\n",
     "    # we disable parallel tool calling to avoid repeating any\n",
     "    # tool invocations when we resume.\n",
-    "    assert(len(message.tool_calls) <= 1)\n",
+    "    assert len(message.tool_calls) <= 1\n",
     "    return {\"messages\": [message]}\n",
     "\n",
     "\n",
@@ -1348,7 +1352,9 @@
     "config = {\"configurable\": {\"thread_id\": \"1\"}}\n",
     "\n",
     "events = graph.stream(\n",
-    "    {\"messages\": [{\"role\": \"user\", \"content\": user_input}]}, config, stream_mode=\"values\"\n",
+    "    {\"messages\": [{\"role\": \"user\", \"content\": user_input}]},\n",
+    "    config,\n",
+    "    stream_mode=\"values\",\n",
     ")\n",
     "for event in events:\n",
     "    if \"messages\" in event:\n",
@@ -1663,7 +1669,7 @@
     "\n",
     "def chatbot(state: State):\n",
     "    message = llm_with_tools.invoke(state[\"messages\"])\n",
-    "    assert(len(message.tool_calls) <= 1)\n",
+    "    assert len(message.tool_calls) <= 1\n",
     "    return {\"messages\": [message]}\n",
     "\n",
     "\n",
@@ -1737,7 +1743,9 @@
     "config = {\"configurable\": {\"thread_id\": \"1\"}}\n",
     "\n",
     "events = graph.stream(\n",
-    "    {\"messages\": [{\"role\": \"user\", \"content\": user_input}]}, config, stream_mode=\"values\"\n",
+    "    {\"messages\": [{\"role\": \"user\", \"content\": user_input}]},\n",
+    "    config,\n",
+    "    stream_mode=\"values\",\n",
     ")\n",
     "for event in events:\n",
     "    if \"messages\" in event:\n",

From 5e3aa495d94494375334dc4a2576dbb8a7b8095e Mon Sep 17 00:00:00 2001
From: Chester Curme 
Date: Fri, 17 Jan 2025 11:05:55 -0500
Subject: [PATCH 14/15] update

---
 docs/docs/tutorials/introduction.ipynb | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/docs/docs/tutorials/introduction.ipynb b/docs/docs/tutorials/introduction.ipynb
index 10c9ef4b2..0168af968 100644
--- a/docs/docs/tutorials/introduction.ipynb
+++ b/docs/docs/tutorials/introduction.ipynb
@@ -1523,7 +1523,9 @@
     "\n",
     "\n",
     "def chatbot(state: State):\n",
-    "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
+    "    message = llm_with_tools.invoke(state[\"messages\"])\n",
+    "    assert(len(message.tool_calls) <= 1)\n",
+    "    return {\"messages\": [message]}\n",
     "\n",
     "\n",
     "graph_builder.add_node(\"chatbot\", chatbot)\n",
@@ -1991,7 +1993,9 @@
     "\n",
     "\n",
     "def chatbot(state: State):\n",
-    "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
+    "    message = llm_with_tools.invoke(state[\"messages\"])\n",
+    "    assert(len(message.tool_calls) <= 1)\n",
+    "    return {\"messages\": [message]}\n",
     "\n",
     "\n",
     "graph_builder = StateGraph(State)\n",

From f8033a20c183b32705c67f4823cf29b7034561bc Mon Sep 17 00:00:00 2001
From: Chester Curme 
Date: Fri, 17 Jan 2025 11:15:33 -0500
Subject: [PATCH 15/15] update cassettes

---
 ...troduction_03a09bfc-3d90-4e54-878f-22e3cb28a418.msgpack.zlib | 1 -
 ...troduction_051dc374-67cc-4371-9dd1-221e07593148.msgpack.zlib | 2 +-
 ...troduction_10701e49-d4b4-46db-bb30-f895fdf4411d.msgpack.zlib | 1 +
 ...troduction_11d5b934-6d8b-4f52-a3bc-b3daa7207e00.msgpack.zlib | 1 -
 ...troduction_35c8978e-c07d-4dd0-a97b-0ce3a723eea5.msgpack.zlib | 2 +-
 ...troduction_4527cf9a-b191-4bde-858a-e33a74a48c55.msgpack.zlib | 2 +-
 ...troduction_69071b02-c011-4b7f-90b1-8e89e032322d.msgpack.zlib | 2 +-
 ...troduction_6a385b06-8d34-4a2d-aded-1cf4bb0ca590.msgpack.zlib | 2 +-
 ...troduction_6b32914d-4d60-491f-8e11-1e6867e38ffd.msgpack.zlib | 1 -
 ...troduction_7df33d9e-cc76-4a0f-8307-01e619483b3e.msgpack.zlib | 1 +
 ...troduction_9f318020-ab7e-415b-a5e2-eddec6d9f3a6.msgpack.zlib | 2 +-
 ...troduction_9fc99c7e-b61d-4aec-9c62-042798185ec3.msgpack.zlib | 1 -
 ...troduction_acbec099-e5d2-497f-929e-c548d7bcbf77.msgpack.zlib | 2 +-
 ...troduction_c1955d79-a1e4-47d0-ba79-b45bd5752a23.msgpack.zlib | 1 -
 ...troduction_c5382e81-bfcd-4508-b02a-099e3d9627fd.msgpack.zlib | 1 +
 ...troduction_dba1b168-f8e0-496d-9bd6-37198fb4776e.msgpack.zlib | 2 +-
 ...troduction_df6d81bb-e674-44ef-a46e-17b1a8d2381a.msgpack.zlib | 1 +
 ...troduction_effb95d9-b7d5-40c5-9253-253d193b23b2.msgpack.zlib | 1 -
 ...troduction_f5447778-53d7-47f3-801b-f47bcf2185a0.msgpack.zlib | 2 +-
 ...troduction_faa345c6-38a2-42e8-9035-9cf56f7bb5b1.msgpack.zlib | 1 -
 20 files changed, 13 insertions(+), 16 deletions(-)
 delete mode 100644 docs/cassettes/introduction_03a09bfc-3d90-4e54-878f-22e3cb28a418.msgpack.zlib
 create mode 100644 docs/cassettes/introduction_10701e49-d4b4-46db-bb30-f895fdf4411d.msgpack.zlib
 delete mode 100644 docs/cassettes/introduction_11d5b934-6d8b-4f52-a3bc-b3daa7207e00.msgpack.zlib
 delete mode 100644 docs/cassettes/introduction_6b32914d-4d60-491f-8e11-1e6867e38ffd.msgpack.zlib
 create mode 100644 docs/cassettes/introduction_7df33d9e-cc76-4a0f-8307-01e619483b3e.msgpack.zlib
 delete mode 100644 docs/cassettes/introduction_9fc99c7e-b61d-4aec-9c62-042798185ec3.msgpack.zlib
 delete mode 100644 docs/cassettes/introduction_c1955d79-a1e4-47d0-ba79-b45bd5752a23.msgpack.zlib
 create mode 100644 docs/cassettes/introduction_c5382e81-bfcd-4508-b02a-099e3d9627fd.msgpack.zlib
 create mode 100644 docs/cassettes/introduction_df6d81bb-e674-44ef-a46e-17b1a8d2381a.msgpack.zlib
 delete mode 100644 docs/cassettes/introduction_effb95d9-b7d5-40c5-9253-253d193b23b2.msgpack.zlib
 delete mode 100644 docs/cassettes/introduction_faa345c6-38a2-42e8-9035-9cf56f7bb5b1.msgpack.zlib

diff --git a/docs/cassettes/introduction_03a09bfc-3d90-4e54-878f-22e3cb28a418.msgpack.zlib b/docs/cassettes/introduction_03a09bfc-3d90-4e54-878f-22e3cb28a418.msgpack.zlib
deleted file mode 100644
index 812c19ffb..000000000
--- a/docs/cassettes/introduction_03a09bfc-3d90-4e54-878f-22e3cb28a418.msgpack.zlib
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_051dc374-67cc-4371-9dd1-221e07593148.msgpack.zlib b/docs/cassettes/introduction_051dc374-67cc-4371-9dd1-221e07593148.msgpack.zlib
index a59deb3aa..626117679 100644
--- a/docs/cassettes/introduction_051dc374-67cc-4371-9dd1-221e07593148.msgpack.zlib
+++ b/docs/cassettes/introduction_051dc374-67cc-4371-9dd1-221e07593148.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_10701e49-d4b4-46db-bb30-f895fdf4411d.msgpack.zlib b/docs/cassettes/introduction_10701e49-d4b4-46db-bb30-f895fdf4411d.msgpack.zlib
new file mode 100644
index 000000000..b23b8c0e7
--- /dev/null
+++ b/docs/cassettes/introduction_10701e49-d4b4-46db-bb30-f895fdf4411d.msgpack.zlib
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_11d5b934-6d8b-4f52-a3bc-b3daa7207e00.msgpack.zlib b/docs/cassettes/introduction_11d5b934-6d8b-4f52-a3bc-b3daa7207e00.msgpack.zlib
deleted file mode 100644
index 3825eadaa..000000000
--- a/docs/cassettes/introduction_11d5b934-6d8b-4f52-a3bc-b3daa7207e00.msgpack.zlib
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_35c8978e-c07d-4dd0-a97b-0ce3a723eea5.msgpack.zlib b/docs/cassettes/introduction_35c8978e-c07d-4dd0-a97b-0ce3a723eea5.msgpack.zlib
index b5ba5e1d5..79b725f3b 100644
--- a/docs/cassettes/introduction_35c8978e-c07d-4dd0-a97b-0ce3a723eea5.msgpack.zlib
+++ b/docs/cassettes/introduction_35c8978e-c07d-4dd0-a97b-0ce3a723eea5.msgpack.zlib
@@ -1 +1 @@
-eNqFVMluG0cQjYGc8hWFucgyONyilZdEtgXGkSUZkYLEsAOiOVOc6bCnu90LpYmgQ5Tlzl+IFCkQnOXkmy855ZAv8NekekaUiFiGAR44tdd7r+vkYoLGciXvvOTSoWGJow87Pbkw+MKjdT+eF+hylZ492d3bP/WGv86d07bXajHNm45NuCibiSpaFplJ8rOhSss3dz46isg9GGMZ9SByE1HGbv/h8urG3hfjTbzvX+w+XTtMl7e2HB7uLbW3xzurUQMi6miqjK9y5hYsMFiQKsUF4BIeM5n1DdP5JyGyYIcDg9YLZym+S5a6/yBF7fJQgqUTJhNMQzSXifApDlJVMC5DxrNvyIyHt5pn0UzaAzRkHTFhcc5h2MEgUQSXdLd4ecEytDPH8UWOLCWMf7780qKJNzLKmr7SJYEq4yuQbavb/Jh+f24kCc0fb8pEpVxm09+z77huQIojwRye1+7p6b3WvcsHSkqs2JpejhF1zASf4B8P6rnixygzl09PuysrL2e2/VLj9C+mteAJC5mtb62SvxGOmjjHH86tY87bkzPqjv/+c1GgtbTLL7tbsyV+ekfb97Q430NDOpv+KjMuD/8/41mn3V06e0gLTl/v574BnRX4nEnotrvL0O302mu95Q70t/crcX1PUxrC5s2HHxzNBPM+vUQjJYQ6GHg9qPAOEo960gvRiGYs118z8kgI0bW+nh1FjjuB1Oi6KvSFInRMCTH0ufvMD+FJldqIvBEUOXsmgjKSnPQVM97MuMv9sMlVZc5CoRYpKbBqW2FCgRMULSpyra9ohzayf7+CR3M7NSDsSQsbBFdqwlqIEmpRwcjL+hXDXVvKBJQBFv4swkGOISFHGHFjHWhleYhkgiplvqCGwG0VEKRAqmYyhbtK10GiXGzUTqTx0nelM3gexh/x7Dk9vrAIbU+MwawO1F5v2FAgaGYY3RhSF83rk5yGpRIuNyS5AU8Xm7DHCy6YAadgB92BMuOvG1AqDyxNwzwWr+CgAAYVquBt6BiGpaBBcEN9yHoErk2UITbbzfXuarvdXl0hsuffdNDCceOG9UfSGZX6CtXQ5JqHHmzAfSRRSzSkv77n1CeGbUy5L96SQlGZq2v5aaKFylp8rnDsVHytipjFw6u6Ns5C2bizNFofYru72lnqvC2QHuzcKIK2HnouwgmBoVDJ2IIaBcTMzehN2GQEdoWMQU1ip2oB+Zl8Kt0QVYX2rnrKpAnUTXhKwNNB4nIOdY1mpEwBVmPCRzwBx+zYNmDGpzYqoWMS5uGS6jWgYGP6mudibX15bX1l/TYq6sdYHamB4wWFd5prS8f/AWTydLU=
\ No newline at end of file
+eNqFVMtOHEcUjaWs/BVXvcFY3fMKzMBsEmwT4mDACkSJZUejmu473eWpripXVQ+0EYuQx35+IRCIkPNYeedNVlnkC/w1udVDwyjGsjSL6fu+55y6x+cTNJYreesVlw4Nix192OnxucEXBVr341mOLlPJ6eOd3b2TwvA3mXPa9ptNpnnDsQkXZSNWedMiM3F2OlRJ+fbW7cOA3IMxlkEfAjcRZeT2Hiz31na/Gq/jveLFzpOVg2R5c9Phwe5Sa2u83QtCCKijqTK+yZhbsMBgQaoEF4BLeMRkumGYzj71kTk7GBi0hXCW4jtkmfUfJKhd5kuwZMJkjImP5jIWRYKDROWMS5/x9Dsy48GN5jqaSbuPhqwjJizOOQzbH8SK4JLuBi/PWYq2dhydZ8gSwvjni68tmmgtpazpa10SqDK6BNk2O41P6PfnWhzT/NG6jFXCZTr9PX3JdQgJjgRzeDZzT0/uNu9e3FdSYsXW9GKMqCMm+AT/uD+bK3qEMnXZ9KTT7b6qbXulxulfTGvBY+Yzm8+tkr8Rjpo4xx/OrGOusMen1B3//ec8R2tpl192NuslfnpP2w+0ONtFQzqb/ipTLg9OH9Au0zefGx5CuwdfMgmdVmcZ2t1+u9Nf7sLG1t7/9zhttzpLlbi+pykNYfP2448Oa8F8SC/BSAmh9geFHlR4e4kHfVkIEQY1y7OvmjwSQnClr6eHgeNOIDW6qgobQhE6poQINrj7ohjC4yo1DAojKLJ+JoIy4oz0FTHeSLnLimGDq8qc+kJNUpJn1Tb9hAInKJpU5EpfwTZtZP9+DQ/ndgrB70kLGwRXasJaiBJmooJRIWevGO7YUsagDDD/ZxH2M/QJGcKIG+tAK8t9JBNUKS1yagjcVgFeCqRqJhO4o/QsSJSL4cyJNF7yvnQGz/z4I54+o8fnF6HtiTGo68DMWxg2FAiaGUY3htRF8xZxRsNSCZcZktyAJ4sN2OU5F8yAU7CNbl+Z8bchlKoAliR+HouXcFAAgwpVKKzv6IeloIF3w+yQ9QlcGytDbLYaq51eq9XqdYns+TfttXAUXrP+UDqjkqJC1Te54qEPa3APSdQSDelvo+DUJ4ItTHiRvyOFvDJX1/KzWAuVNvlc4cip6EoVEYuGl3VtlPqyUXtptDrEVqfXXmq/K5A+bF8rgrYeFlz4EwJDoeKxBTXyiJnr0RuwzgjsChmDmsRO1TzytXwq3RBVuS5c9ZRJE6gb8ISAp4PE5RzqGs1ImRysxpiPeAyO2bENoeZTGxXTMfHzcEn1QsjZmL7muVhZXV5Z7a7eRMXsMVZHauB4TuHtRrd79B/qa3Sq
\ No newline at end of file
diff --git a/docs/cassettes/introduction_4527cf9a-b191-4bde-858a-e33a74a48c55.msgpack.zlib b/docs/cassettes/introduction_4527cf9a-b191-4bde-858a-e33a74a48c55.msgpack.zlib
index 0b03a29fa..b9bea8edb 100644
--- a/docs/cassettes/introduction_4527cf9a-b191-4bde-858a-e33a74a48c55.msgpack.zlib
+++ b/docs/cassettes/introduction_4527cf9a-b191-4bde-858a-e33a74a48c55.msgpack.zlib
@@ -1 +1 @@
-eNqNVXtsU1UY35hEEFCJRGYi4djMjbHdro+tozMC3cYQCDLWQjZgLrf3nrWX3d5zuffcbt3YHwyYARPJxRDQSFTWtaSOPXRIohBwETFKwkMlTOShAYnEAAoENcH53a5lg41H/2hOz/l+3+P3/b6vLdEgVlSBSKkdgkSxwnIUfqh6S1TBazSs0g2RAKZ+wofLl7g9bZoi9L/sp1RWi/LyWFkwsxL1K0QWODNHAnlBa14Aqyrrw2rYS/jQT2NSm0wBtqGGkjosqaYiZLXY8nORKWkFNyubTAoRMZxMmooVE7xyBFKRqHFVgQM44MUKCoSQxAbwHFNztYEnPBaNd05kNR4zdqaAUYkkYcrYIILFYbMYjighYiKGATYAlA0KYqhGxazC+WsUrGoiVWtWA9gA8FjlFEE2ODCMXWjQDmHJJ0gYEXgJCI2YR7VEQVCxrGA/FCYEcS5iOU5TWGqcJB5RRVMpGCYimNEyFddqYhxYDxgUIhqSMFhQAgC1HmqME27Qj1gv0SgCfwrwgHAQvsHFAkmGW9VPNJFHXozYZHoAVEJmowDBMKlROT8OsFBBk0mG7mCFCnGum0xxy/jpvlKHezJSEgmpQ5ocZzEkx6lTqSJIPlNzM9wZ6hAUzBvkJpxWDzMl3tWYo2Ba3Rz1Y5YHjW0J+4lK9Z4RqukC4rBMGSxxhIcA+h5foyDnIh7XikBnjDP6GpelHqvDWGZYEfiODKL0blaWRYFjjfc8o40dCfUwRi4jn2OGyBjQnkT1fa5kHnnlIRC5hCxme77Z1t3AqJQVJBFUyogspBSR4+9fDH+QWa4O/DCJAdIjg+DO4TZE1dsXs9wS9z0uDab1dlYJOPI/HX6vaBLoC+vRkvKR4RKPQ+HsZqvVXNhzj2M1JHF6ey0rqrjnLsl3ITGYDTtjcTAWa2eSJRGkTf16W4HVvhu0KoP68PoIuKSa2hKGjuCj30QT47pryaJkN8+lTA2XQnf0Ax6/lousDrSQlRD4L0A2a5HFWWTJR/MXezpKEmE8ozajx6OA9GuhIfOSzY9yfk2qw3ysZNS295uGyjKGTYR5pExiV0GzjJ96ON9isfRnPtRSgQERJCNi2O50Oh/hF5jBVO816gPyGKvDk6jSvmL0OPE5ZAbXXiKriJEV5DXzkfZDuSUxmY+BeXCGWaOhYcGMSLF9VjxazqPth1JMYLIeB/OAFPNX9KPR4PfRNxgo4yGWw4kbtEYPtX4gZbFE5xmB1/fDucZiLQ+UlCl2Ul66pqHMV6nVl2lUcEltQYHVY1azFfkI8Ym4q6SMKWFh/TLu+Ajp0dKq112LF5R0VDIVxEtASx4WNCcRCUfcWIHR1GOcSDQelp2CIwCvcFXpvU6L3WotcDq9nLfQaXEUMMWwQ5LDdHdYwsamjP/TrosMbufDqcHpb41LiX/SeN215fu5EzcObL40YXvvwkVTw6vKXblXdk5AUya9EH0Xe5884y7w3Lm2e1115ZpPbp67cTnrn5Zs7/q2aWca1YGP9h2bXjjtSOh2MOf25Tf/ZAfG59wM7Vq5+Wif3l28be1zLVW2Z/6o/GWGbnOcvlRu2vNG59XlmUcvfhw4cPbHrs8Klp8e/0oPd+PSX+O0ovOntp+4kNqXUfX271nLru+Z9SJ66qCc3rcJXZ/4TubSyrm+J5emC1N2uhp3tM+Q04VJTesPdc855D58ZXz7xZesGVfnHbmwIL1x2+TMdvdWb+Hfm354/rtT12fTtIzgyeOMcOND6XhOf3drfYWy/2xrttsyJvo+Gz6oHXri6eNjW59t29p/rffb0vd8r02cHb7sO3/hVt3G32x7F365ocf16+nGpV/PaT2xpfjnyY5VSmd37jHBvKNh5rnP12Y5xOCtSJ+Zpu3debKYfJB1ZX5N9lcDr2b/16Xc/rfxztiUlIGBtJSTm2ahwjEpKf8Dn2qrXg==
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_69071b02-c011-4b7f-90b1-8e89e032322d.msgpack.zlib b/docs/cassettes/introduction_69071b02-c011-4b7f-90b1-8e89e032322d.msgpack.zlib
index c1f763bd1..a69fc1008 100644
--- a/docs/cassettes/introduction_69071b02-c011-4b7f-90b1-8e89e032322d.msgpack.zlib
+++ b/docs/cassettes/introduction_69071b02-c011-4b7f-90b1-8e89e032322d.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_6a385b06-8d34-4a2d-aded-1cf4bb0ca590.msgpack.zlib b/docs/cassettes/introduction_6a385b06-8d34-4a2d-aded-1cf4bb0ca590.msgpack.zlib
index b3391947d..0049ee903 100644
--- a/docs/cassettes/introduction_6a385b06-8d34-4a2d-aded-1cf4bb0ca590.msgpack.zlib
+++ b/docs/cassettes/introduction_6a385b06-8d34-4a2d-aded-1cf4bb0ca590.msgpack.zlib
@@ -1 +1 @@
-eNqNVGtQE1cUjtIqdrRVBx+ldNgGRUE3yZIECYOjiAqIEUrCIFQH191LsmSzu+yDisiU4gOVae2WGbWtMh0NCRMRBHVEa9W2Sp3WiqUgE1+1oz9qtVMfBRRk7E0IggUf++vuPa/vfN85t9RVAHiBYpkRNRQjAh4nRPgjyKUuHuRLQBA3OO1AtLKkIy3VZN4r8ZRnulUUOSFWrcY5SoUzopVnOYpQEaxdXYCp7UAQcAsQHKtZstBTXqS042tyRNYGGEEZi2CaKN1sRNnvBG8+KFLyLA3gSSkJgFdCK8FCJIzovcq04iJCskghKyE2hv0QwVezkogsxRlLIo9z1nnK4pXefCwJaK8/QeMSCVAtqkcFlmGAiEbBiproKI2y2GUFOAmb3eawsoIo1w+BX4cTBOBEFDAES1KMRd5vWUtxsxES5NK4CNyEN6OPH9ltA4BDcZoqAM6+KPkAznE0ReBeuzoPVq/x94GKhRwYanZ720UhC4woH4nvx6FOK4RsM4hGpdWpog6sQQURpxga8oXSsGnZyfns3ww2cDhhg3lQv5Kysy+4drAPK8hVRpxINT2TEucJq1yF8/Zo3cHB97zEiJQdyK6EtKHl/MaBcloVhqnm1D+TWChkCLkqF6cFUP+U5KchbqiKFtVEoxqstp8lGjAW0SrvxbSGah4IHJxCsN4JU4qSUOqAioBzZ13+wdmTmtKv5jXFFMdCqI78rdkqzUawaGQJziAwvx6JwmI1MbE6A5JoNNck+MuYhxWj3szjjJALBVnUL76LsEqMDZDuhGFl9ygH2uJhfZqyUyLqXxoolvdXdug0Go0n/IWePLBD1rwVHVqDwfCSvJAZIMqHvP1B8lAs2uzvck728HUohpPgCPoW0I/K6UUFcUW+1H8AW39M+CvEPAehIdszY7houNBDIFbF+KrNern/AER/zIxXiXk+RGS48P/R11do2gs8BxPX54280Pu5eNx+5VGKlI/Dc44GyyjgMskMyUQlGoFFmyLp03n78ry9BRQuuzEVhlhY1kKDuoTFaAJOWAFq8q2Q7FqYtSzemJxQsxxNZ1ezcJbMOJw5hmWA0wR4uJqym6BZiYSPHQ+cMDw9Pks+ZNBoMUyvxfS5JKEjAEAXwDekf5meLovD+1L6nvyP4cry8OrMiO7Q8kCF7wsQ042pVzTje2eF5TSSvzagSb9MyihpTUndX+1uo+OSnTHa2rnnGxY97vopa3xaawVoftDTEBpS1H4s4q3LHZ6Ox67Hl1bkrDzf2dH5VfG8k7277l4PtpQlTVpkuDG/Nj85Ye6pXYZ3th5tMv4V0XhRGlHuaitrexS5L9CTd/DauhU59MXa/N1b5Z22j+LiKoKvtt/+ueWYeuYPGd/HjLTMDzyesvPN6xEPkJvfBS1+Y0LBxvVltLV1h8I0pmlWSNJYTdOpd4P3kTO/ACUlUUEhgZMrHgUxd6apQ0ZFrgqOL6q+tCOsQbF19Nj4rrfXGi9MX7AvriK8dJlr6p8nCt//3Xbs9pR/K+3r6jonRobv9phGmcYl3h/zetmSExfQlu1pUaEBd852LhxZ2VPZ8nmd81xa8a2gjO0r9b3b7t5WLvsju0tnylNor5RkGrCp+eF3d1Vrv+5J2pIcG7tple36qNiaxhntn4VJV4TRlWMN5KndkwNquw9XbDk9+WhebWvd/Vbdgj0lTdqNAYF/73jYdvCT18aE9XCKL/XnDm+ujHjYjTxprki9eqO5CfzWaNyQdebwp6fZ/dPyU9cvPZky7mZ2xHs6Jv/mpdE/Tiy3G/9JarA1q4Lb8TktnQ/PR14+UtLxIG5Cd5cW7dzE9N66d08NRX7yJEChLg7dmRmgUPwHSE1ojw==
\ No newline at end of file
+eNqNVHlQE1cYB4MW6hGL0/HoOOykIo64SZYckFSpKZfcVDJYoIwum0eyZLMbdzeEQ0djFa3isR7Voq1UQ2IjhyhTtdoOg7XUY1orU5EKtlOpjow4o/UYj5a+QBAsqN2/3r7v+n2/3/e9Ve4iwHIkQ/vXkDQPWJzg4Q8nrHKzYKkNcPxqlwXwJsbgzEjP1O+3sWR7qInnrZxWJsOtpBSneRPLWElCSjAWWREmswCOw42Ac+YzhpL2DWUSC168mGfMgOYkWgSTRyjnIJIBJ3iTWyZhGQrAk8TGAVYCrQQDkdC892qRCecRA4OUMDbETDN2BM9nbDySgtPGBBa3mt6VLM/z5mMMgPL6ExRuMwBUgapQjqFpwKMRsKJcHSGXLHebAG6AzW52mhiOFxqGwa/HCQJYeRTQBGMgaaNQaywlrXMQAyigcB54CG/GPn4EjxkAK4pTZBFw9UcJh3CrlSIJ3GuXFcLqNb4+UL7ECoabPd52UcgCzQtHdQM4ZBklkG0akUsVSmnEoWKU43GSpiBfKAWbFlzWPvuJoQYrTphhHtSnpODqD64b6sNwQnUqTqRnPpcSZwmTUI2zFrXyyNB71kbzpAUI7piM4eV8xsFyCimGSSMbnkvMldCEUF2AUxxoeEbysxAPVEWBytWoHKsbYIkCtJE3CfsxheYACzgrnELwkQum5G3cKidUBJz/we0bnH3pyQNqXvWb7IyF6gjfxLPkHASLRJJwGoH5VQim1mIRWpUSSUjV18T4yuhHFKNBz+I0VwAFiRsQ302YbLQZGDwxI8reLhlsi4X1KdJC8qhvaaBY3l/BqZTL5e0zX+rJAgtkzVvRqdBoNK/IC5kBvNDo7Q+Sh2KRel+XWM7IdUjaaoMj2LeAPlQuLyqIa/Yr/QexDcTM/B8xL0CozGkPGykaLvQwiNVRfdXCX+0/CNEXE/Z/Yl4MERkp/D/09Rea8RLPocT1eyMv9X4hHo9PeZQ0CCfhebEci7NH0QsKyOR43SKOL15qz4hlGA7sLyJxwYNJMcTIMEYK1MfEozE4YQJoZt8KCe7Y7DRdamJMzQfoQiafgbOkx+HM0QwNXJmAhaspeAiKsRngY8cCFwxfqMsWGjVyRSSOYWolUAElQWjQ9+AbMrBMz5bF6X0p+558B1xZFl6dHiUP2RDo1/eJDFtTmSvyceW9r3+RLEvb0pjreHSp51D1ZTxkbe2U8pWCafe6lNLgHc5Zj397TYOup8N0kkfdJYnRURPqbMTtowfv71jWe/xJaVkXY2+531m2IulmS89G857OdP2RWcZbZ1RSska8S2GMwdqOvS+Ka9OGNATkfIhelR5evwWVLtrJZLXtDG+Lqs+fcf3XxeKf9sW7c6JDap9UXFyREjW+aerEbzuuVI0S7EGt8wLOdowdLV/j+CPgRDM2X63sTlrdEHtt9IMZY6JShXnTDhpmfVq9dt3FybeCCi6dXL0xryv71PzRKWEXJsxuXuuf7RfatP1ekyNiV+H5C+SovYG13dNVPScOtMw1Hp4Seu+G2G5IkDia8hK+vNtBLRlzLiOU36PvtgTJPhFaHosrjoUtETWf396dXCWK++z61wvc10/fDd+trvI/p7vm+Mf2juLH8ZUSnbqyYKuiNTj6pjBh+7SmSk1rtHiyeqJeOm7M3IkBEV0L/LVp7eWeJPfHwduKSwuVuaJsnHtj5XfmxDdPibseqgpFjqLpZd8H6pZPTaSKMhzBj0qWnbmcoLWfzKqoHH+2UZ4XoKzsqXoY+svYZDc51/x72gb/3PJNF5L2HbFtnnQ76jD2Z3XZ085jlNYyCc9aWvt2UG54Ykcm0rp3IXo8K6liY/hf3UfFm8Dsr1Sd2wxtdfVv3fhZ3Divfs3ZB7bmbs3ngad6MfRBEv337Tt3ZHA0entFfoXGp64dIj+/fwEX/nZF
\ No newline at end of file
diff --git a/docs/cassettes/introduction_6b32914d-4d60-491f-8e11-1e6867e38ffd.msgpack.zlib b/docs/cassettes/introduction_6b32914d-4d60-491f-8e11-1e6867e38ffd.msgpack.zlib
deleted file mode 100644
index 5800f50a6..000000000
--- a/docs/cassettes/introduction_6b32914d-4d60-491f-8e11-1e6867e38ffd.msgpack.zlib
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_7df33d9e-cc76-4a0f-8307-01e619483b3e.msgpack.zlib b/docs/cassettes/introduction_7df33d9e-cc76-4a0f-8307-01e619483b3e.msgpack.zlib
new file mode 100644
index 000000000..3f3c5747f
--- /dev/null
+++ b/docs/cassettes/introduction_7df33d9e-cc76-4a0f-8307-01e619483b3e.msgpack.zlib
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_9f318020-ab7e-415b-a5e2-eddec6d9f3a6.msgpack.zlib b/docs/cassettes/introduction_9f318020-ab7e-415b-a5e2-eddec6d9f3a6.msgpack.zlib
index 4907c4150..f14d5edc4 100644
--- a/docs/cassettes/introduction_9f318020-ab7e-415b-a5e2-eddec6d9f3a6.msgpack.zlib
+++ b/docs/cassettes/introduction_9f318020-ab7e-415b-a5e2-eddec6d9f3a6.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_9fc99c7e-b61d-4aec-9c62-042798185ec3.msgpack.zlib b/docs/cassettes/introduction_9fc99c7e-b61d-4aec-9c62-042798185ec3.msgpack.zlib
deleted file mode 100644
index d153781b5..000000000
--- a/docs/cassettes/introduction_9fc99c7e-b61d-4aec-9c62-042798185ec3.msgpack.zlib
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_acbec099-e5d2-497f-929e-c548d7bcbf77.msgpack.zlib b/docs/cassettes/introduction_acbec099-e5d2-497f-929e-c548d7bcbf77.msgpack.zlib
index c2c31aa6a..00a9173f4 100644
--- a/docs/cassettes/introduction_acbec099-e5d2-497f-929e-c548d7bcbf77.msgpack.zlib
+++ b/docs/cassettes/introduction_acbec099-e5d2-497f-929e-c548d7bcbf77.msgpack.zlib
@@ -1 +1 @@
-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
\ No newline at end of file
+eNrtWwl4FEW+D6CAIiCIcmMRIQmQmcxkciNgEq6EBEISVo7EsaenZqZJT/fQRw4CooCyIAJBBA/ukOBGTjmUc0EOFREFXVSUQxAv1EV4giDC+1d198wkBNG37H6+b8OnkExX1f++ftUzcXkhlmROFOqt4AQFSwyrwC/ysxOXS3iMimVlcqUXKx7RuSxrSE5uuSpxn3T1KIpPToqKYnycmREUjyT6ONbMit6oQmuUF8sy48byMofoLDlyT/vSUC9TbFfEAizIoUnIaomOiUShxir4ZFRpqCTyGH4KVWUshcJTVgRWBIV8lBbuRTxmJIET3CiDEdwDJMbnMaNUUeWdqERUkVNEsujFSMIyrGM9SBQQpyCXKCEv7hM6PhIFCDCyzMkK8FydCrCg4GJKLxVLCsMJfElnlBbuRA6MPIzPV4IUMUDAzwYlAjyYUa6I3FhBigcjrygrSPWZFNHkZBSMGMGJQDc+CXtABVwhRpwA+7wMUXQkUOF5BILTvblMIceXIJ0OFtycgAlpXhQLYAEnw8FmlAGUQGAQXPEwisEEEsQiM5FLKfFRYalIVHz/J6LI24EWWSUwXu0zStKukbSDjCqvyPbRsiiQVZzgU4leSkPBGaQSsiEgvU8S3RLj9RLT8JxDYmDBeLLJaRBT7RZr3OBY2yCc+HChWihm9R05ckBc9lCuX+j4/GqWud70o2rwrbFWwz1GleaFqhKfBz/nhRp+6SsBxxQldxQwOBqzShQPLLsJy1F5sD/POEDblac6E2wY/nYmsvRnJ/k5PiFPdWGLK8jl8tToOMaKUlSOd1KR4ZEKTozgf0GRESMjSkQ2Vo7qPHhIbr98lAHWIxuIoYiV03OQHnR9UA7GxmcS9onUW/TfnSIrm81oCKwt5HCROcjvwBEYQ+X0WIfBFHi3gl0qH4m8oC3OBPEMj8GFeY6lHiejIk4BH87IlCOJ3zmJf7ESpq5KBKEs6Jvp70WiVODixSKZRJ3Xx0jaHhHYlMg5yAVOgMkqOBEiT3S5QDoiBXg1K0oYokjALk6RkxBbwvIYlhELgOl5xsHxnFISSYn6iFJksAyLzXnUc2sxrhc7OdVLs81DAiczktsswF+q4AyY2cSYdOWYiGIUkyhAOPpMostE1rAeiHCTyxnrcjqdDktcTEwtbuGSRC/yn2h2a3r3+kRJQTlEydQSkSgnNzk7NxL1G9wXodr2mPVUZ+xlnE67kf3QDU6KrL4qCXkZgRxBjWs4GTWTfjYxjxk5OVaxFzI8pO2IUaXhxv7wJJSclqn9EqHL2Cs8gxMKsDNN0HwJIsUFK8A/GB4JWCHWJO7k4xmFJCvNU4inMaiQkTislICdkU+VfKJMDMoJLK8SD0zKgz8C/at7d6sZDQ4cRjj2R0+qKAhYKzZJ3bsHbTKeaH7KgpNgxq1Sp+Ehf0Pe1Og5VVkB7w/mXNb9SCQiciCJF/4VJdmsn5wucgKoT1R9MkQbiKZ5MiRPCbk4DAUFBKRlEAqfTB5BCqa2E0C5MqtSOprqcbGP/EP36gozyCQrQN+JCjlJUYEJsgz8jXg3lCZcSJOFB6oEUIcPDEOYgxVnq1Pc/1VxkDnyaRnUi539d5UjUrZkO5YkUYLVLlAJrlGhbtA7hKYwssYPSdt65dbLKFR3xDICUXUh58S0SlPj0IYlqA1AjENUleD+pkaur6XUIieWObegh6XjplXJjAaCeRCkb8ppAQYXALNCVgblCRCpWVowJ1Wn7Q98WiP+UImBtIzpYZSfTNGJeRlFkMrTzYzSlHAZQTFROFblGQm6HqAEp1JaTjA2D10l8f2b1CTCfDSpTCBXir/O3LxQBYT01ysJarEXSgNk30KwM8mdoBuEkAml0roFquEKMLAqYdgiEfYUkWpTr2NBtZRUOo6lcUHaaoU0fmBFFkIOUjohcp0gGqXqlTEJDSHsEVJeIqJeOJEIXQGlTDZT9TiwB1o5oAd5uYYTGGdnBQpsEspR3SAgtWgNCYgOSBOs1xuGlURZRsHjARFL1pKHZgHIV9kkL5APPJyPnEIUnEoqbbBDgZdAhNAMAa01Lc40dEQfYZt4GQ8uSDXszzL+g0iS0ozpE33Eaaq1QEay9Lc3lLEYMxoEnk78QRSILpJQLkhrbNTKFhhEBo+TIOdoVRqsryVNrOUslyroGVfXZKBuJ6H+ZNIgBdofHEaJBhXSNBccG4YtaLWnh0PB9zuW0ZA5wY8FLVAdGA4WjDKAaZomYUsUdp33BPcNUPb9jGvjkMFkcNtA9cVp2UtrWIjaYs0ouZDhAl5YPR9pj3hMsguDskpgQIQsx7AF5FQ6lJC05yA5DhQChYgkdchi4BkR2moa/Np6Y43UjZKOM6O/aN2xZiuJZFXs9fsMeECApt5HU9UwKB0Yy2Elzqf4H4CS/KxH6skXQ2ogViINt8xB8uJ0M0PHrZLKx/hVhhlWU0i8GewMdYx4q6aHHEVSWUWVcHWPwl6fh5G5sZh2wHSyAx609lE2tlBhYEJhBFioJTetw/NHdHAQ62mDRiojF2i8aukjOCgpn2ku4nLhoLTrp+ZIWoC8nNsDeYe4ODABqoem1AGeJzhBZeD5tIpAEtVad8g3LPZp3qb5tsYpUVPkdWJpbYQH+Od03lwMsB4Uk1RXNRzGb4cS4h1Zad3Ar8l0D9ZmkFsUnaQNZekgDFHhNBxGsxL5hZD39xcO0D4Leicn42LG64PETVXzsB8y4CHYtHQq+zDLuWD99cWYEUrAvX2koaruRLIKFZ6RqZiKNvdTLYKTUznJCCRRDZIa64JqQFRTA4moBeoYwdDQgcjwYN4HpdCMMpkSUAKFCGiBB6YQoyqiIHpF8EW9hGhEO0PfQ5AVUmbJcZC/ILOZbKZYk0waQ8UUbYmOscRFW4zuSEdffh8SAEmSRhYoiCxOrgFSiPDEC86s9wrBeAc4BcuqJOI09wBz0RZOp2BGwwKFvwj2aGAG1hIhI8hFkPApFKWZmBoHzpOI7FpTCN0EwSmQ7An4jc4ehS3MfijDLrMe7GUoogFhBa2lwlEUKgBwlNYUNfgkPxij+oKhFnBBiJrQ8QT9ILgZB60HUa5+aH7QUtFBIAlYmj9+uQczJOhmLiNNbdna6/C01aA4CD4TFGyRhGXZSvdYzhdJqgOpjlWsfxQoqyrA2GdieNB3pbarbE1Q2YkiZlyhO5uJ8HL94yrik1p/VfZassFHlB6sFrMtxhy9ptgkU3wM8hGdpcsqffT5luAHemCb9CRcVqltXhW8RpTLKjIZdkhOtSOJpssqGMkbF7Mu+HNJhbnEi8uWp2ZdT05/GCBnM1ut5vi11Q6WSwS2rII29mv9SvZvqYLYsJkscSaLdZWhJR5cW/GULYtJSLS+DM4KDYSMJ1WSLKjKE5eBSfD+t5brtXTpkEGGOY+FtF7WF8xTtq2/xEUiazzUJQEBgVhkjUuy2pJi4tCAzNwVqTqd3FqtsTZXAt+H1s/Uz7D+ctajkpGnKrVWu38SGpCLRBsPAamYdBgXrEV+BWksFssnYb+5UsKkAyQUl9kSExNvci6BRZWy9UQ+0J7JGp+rSxkzsnY6NBBNGiKsc1VJuAK+ut90fYA3Y0/Y79hzAw7jRn4SXttuyDDXsViRQKn1uPn6AIv6nvDfs+fGLKLattdQn0aoy2+sDFacthr95uob8lOlW97EOcu2ws8wU6ePdqRyY/p6BLG/22odkeuKZTNzs8qh5SurspqtpIa7ebw6tb8pFfopbMqhIVS2vO+IwcmZaakrhpuyRejrZFMuAz4nQKNemYMliM2yKpgHVCdkOwlXwvbs5BFl6xMttngmOs7qdMTExTitCaYUSCJGMPmDZRlJlfQS4olKLT3vqXf8/qcbh9A/DeD/a9fysvPFTy13XenRwX7hZKu0I6teOn7hoHdH9OKv6ys7LG2m9/04Hb/d4m8H+s+61vutnXErhtTfc+rH4i9aLNjTrpR76fRoWf6l8HhvvvkvV5R//nzhB/Pm5m17fMidmOhoMbptj4yD85q3HLO0Vase35XjmbHthnxy7qQ0ZtusNvXPOLbl2U32lfOGL5manBhxuM+MCQOfezO7d59YoeehefVv8zqyfXO/uX3rOwdGtR65OGRO7FMfvxn5kKnRk/bBPT/O8vTp2i7JYi1t0tM8vFPT0j6TPPWfOfFCdsj3bbZ+2jX9nqw1O06dYB2+7o96Fi84P7jjO7fzw5e422SPk+YmO9576HCSap3VqPXuDQv27Q/d5B2R3j/9lRm/huTsf//ViRFdcenhqgXPpmxyl7currqa2KJcfLXVhK8q5iTEv/OPC++cuvjo38cfLbq46PyZgtLzV5krCY4nn7i8acbC+YvaMemVBS0HXej+7iOOiAzmrWk/tWj+wgeTY3+4+uKl/WklQteZHzZf+N4p7vDzHUp2fvCN+8mlYzwtc7hzi84ldh73Voe72I6vXrz3y0v8t6dGZJb/WDbp0W2bx8nDlnT+YAy7b/tR8fRXe8q7Wx9/u3VFWOWj+07Pm7u4jceTN6oJtWKDkNVrHjjyQf2QkBtfWm0LvrPSGh0KIWu1XburqmcqDYXHdujaaDtUyJeYlNy+sfHJOdkF/XCKOmbIiIRiZ+ygQQouzomxZBYMjidNgP9mxI/B1GzR/ICIMUMZfanWD6lkBIHCRA4jl2V6YwRHRkca7YfdCSXdQ3EoAk6w0F/QnoaOr3anSIKb9nOk18DFtX5srNZ6KgPmCnogMUX2QENa8ynn1W/sNHTMKHdPVQ0jfUMy7Rs2at2AvzpERZtt8N/qZK2R6Vd7I1OpPS4r7x7V/QbFbZUR4BlaVS63Waw3qaB/pGY/eQOyNyFhpKkK0gQX36TqJ5CqX1OOZdHRiZZqaepI43P+ZvQWuFSoS+RhoLSrPru/iQ5NElSejww1HEH7zbAv+Eqo3wXJLRynkJkl1I9AJwd4yaSYXC4MEyg5iK0B2Au1BkWbLZQdP5fAjirBdOK/zVHEIkZyyk4GBluWozc/JCwNsU0BsU0a/EfmFq1HlU2ElMlNSZmiTRYTkDIF3QE5bc54hzMWxydCrAQGrVshBxpHRuYRoiqAJ8GUJsiMBJ+BxSM1k49DuZpkCHyCQTmabOhWkE5GPjrxswzvt7O2BYYoHhEXDzhDNWiYnAO9MgUFAto0/KlWhsnMTiFj0j5IBRTzOfn4HIJTlFCMx4thjiYgRiEjw8wMEunQVLVLbn2KA0IUZCsQxCIeO2FA97tkJCqSOAKbAvuR+kKF3HhRdEYbHMmwh1xcsQaqUTyckcjsp12NG8qAozSY2y3qCK0+OyOZI1qhULA2OlOoCraSkc3nMwZ4FzmeDsj6Ag3Oopf0/omUIb9LJx9/QfYLQcANOCxZn8rBGB6mUMd0aBBSgFBHHDQ0kKCH5AnKUh08J3swQTdqN4XpZn+IP0rIQ64WKIZONutBRdWXnGY2qFX7B4JDJlhPaJLFnGAlEEE8JIDgUkDyw/jIQCYIOGOurvOkINeukZ4odBtuqKW/AcFflwqKiorMbqyMxT6aAhgd6peDrnUNC1cL5/6cwPB8CbU6MdFI7IMRHXKHgiWv5p/BuDwjBNse3Bp7HQT+90m4kCPxCCeTqZAJIErE0FD0WAI0BFOjJtaPJaoPgrkDFFSCIdfGj1adKMhBCZCUzxHU9mH9ZB0DZvwoG6FDzyRRAaf6L4hBKVB/tNsZegft5MilAeFBgHjSLvolRIAePZR08B6l9ZXJTWOxcp1AgdssOxWdBgSs8nCsRxOKrCDKZnnwMYVGgiadWd9n3BBEdENaO+ZH8AIaJUA/LtTBSHKiBthU03MQGE5VYeeEQhhT4FgD3jb40pAPOaDQkiDRq0tOPkER5NKHcdo5GnY1ApViQN20rIkVVRI0kWtYmcptdBpmlDowOSu3Xzayod8MkqB0HhQumZpzZBDklsKLQagj+G1ymu5Y/nuswA1K8CUJkUA27tCwdtti3EqJJAMWa5ca8ANHQfzqN1GgseBrvuD3DbS3KTjBcOMAFmwOziLxNmucNTa2tiyi9RZUWXYC2oQmWc1xseNv0etmHTvXvW5W97pZ3etmda+b1b1uVve6Wd1bU3Wvm9W9blb3ulnd62Z1r5vVvW5W97pZ3etmda+b1b1uduteN/tjUEeuRozAmZiA6k7MdA60mTekFMgErN9K0J0VsxhimCxitJeyKGamBEWG3vzxRO/Uvxifll4g/PyghtEq0Q4JshmnaDMJmJn4rWZiWS9dxORAiqiL2vU6U1DIREcB/hPYyL98O3g9fJI7qGC44MzJHO3JHqgmxDrjUx8u7l/874RP/kNXgLXM3HUXgf/aRWCeGm2xxtTdBep3gVQdif/vrwNvCIX9gQu6WoKt7pruT3FNZzjpf+FNnSF63WXdzUCrGzQBtYNWdV86qPvSQd2XDm71lw7iY2Ljb+mXDmLj/yu+dJDwZ//SQWz8n/5LB4TFP9OXDoCfWr50MLjfwP5jHxZ9o21js0eoxWMHDM0d6U34937pIJ5NdLjwH/rSwe1q4EsH4/5yUOiwqcWV5w5s/bihq9FsftG4X1ru7j2f2VH/B6n+xC7NJj/yatHcFlN6ueKLKtpcvbj47RFc1wdKWq5PjXtl8yvTrhy+/fjKLWl7X1p3fubD536Y+c1F3/hLV8+djL98SZr0z89KPioa2+fZlaEtOvztzJb9Bx97qAxNS9uy/aWPc747vODp4Q+ufGT1sVWTc0Lz8+fnb0385ZuTK870fDOtG/fa1a9eY4dW9Pz0kWsrttit3aY1vBhebE/5n87PPH7Hmojwha83PjEw7fO7lUaLrM/cbzvQs7Hjla8PDJ3+k+3YpOif14Sf7WvDjdPaKgPu3hXGbm+U0Sn93JxnnpiyuL7cf/lO5rb5X7XpMPpElwZbB3RuPv/IY7ktn5y1cf7yzUundMT199/2xj3JA1vuXZDeK2VfwuwPUxpyA8Y8VWq2zJ4Y4er696uzty87X29V+odrNrtmnG3NdjsTdceJyWF732r0t0+f24lTKg7fXe/okom7buvXOOyVmAH18Yyf8jKkxfz9tnGmJovrrSpKXlFqczVd1Xf/j51cvbOOzW086sD3rdrvWvjq4qcG9slIbfiAz7pj+bKYL488i1MWrb6v5YSvsg8+ie+od7lX2IBOoZVrTwzM6trl7l2mnQNeTLnTZ53fa9EGqYHH+1bTHU3qDTEPPLH+xbMbp+5NTTG1PXWq3sxTG7s2c382uU1MFnt27OOFu+8fHbLa8vnAe7qO7z0ltMvjliN9Xsm8t9EB2aXceyw3/i9rB67c/ek9a96sDG/9dHi9oQcausfM2xF3/rbe/GtzMt+Z2ivteNjFvsqw/C572/X+9VDE1rYnpoUduHj288lHz7dIOGD7qHPfwafSuw2xbPD+I2zmo0v+yhREV0261OjdJpMGxHZq3SO1cmplU/y87ftJabvHjFzG3vfyKlv3UUr3XpGnokfknv/kxam25Gem9TS59n7BVEbOtzx1bdbqjOPNshacW/Ltsx80eLO1NSX0XGyIp/2hSU32dw73tF5319ke7sU95385cHzsR84L48+2bswUbnlp2uuHR1dEc83Whz+RUXbh+YWTU9qXcyciDh7+/M6rywdUnD653jn67ASueFHELzsuFba/FPLz4k3bS5Z2bxD97guTs2O/Keerzt2WsOvQ4bA2506d7/WiNc2z8visTn8d/f7bS4+FrRgkX1x4Zs303KYvN7x8+bGN+6df3FBy+OqUA95BVVN2vVO14M6rYcM7jr307bCC8pOmt4cekw92+nL/jN0P3tdKmbdp+paxX6ccK3Yemm3KHtJufpprcMq9Z2MX9ecLhn9/Zv6l41+szzwyZmqnjXz2YyhzXYcHLuW03NNmiC2hZIfSfOpd5fldFrrSF84uSJSsO6Z0XDcrP21RH/uvM3dIYdKz46czy75o/MghS7Ne4658P/anzfb6a1Y3yNhhq3jO9/aMkPLswS8zQ1Y/9eLIp/kVrTO/De/eZ3KbMwvWzOnzvquF0rxZOd4u/bCzfGm/tn2//DR61On4VLl1R7WRNKegfcfWz3Quu3It4pG9ibnvPRY9b0RlpwZfRbSYnnymIp89PaKq7xvz526KuiQ5Nixp9+0R4XT4brVR6f7Yydvv2/eEs9vQLcOixu3bkC5lxkzIr7q4Yd6Mpt8t+Hzs7BOxiRfiLh88cs/MlpZX5x95o8y67/3o10avuHPtEymzHn1u5pUVzzVpue7nuc2QbdOaps1and64s5PtsiOuweaXZkbN/aDn/vpvxGzr7F49q2u/5Sb3nsxl7oue07+8due7ccMmHDY1HzCza/GZ6WOi95y/8GHnYS9sP3bvml3buC9+bFHvwuvrmvZ58LOUid26XLt7b9S4niPbxl048Yt88Vf7+PB95zPDWg0+urn8C3H/90fPJX9dYH1TOZPr+G5Ltr3ijJj/7sz2p0elH1r53oTt4z4qanZ0hvCZNOizB/OlwisL7/h15vHXv/4mSjy+cMK1q3b9q0ANlx7oEd0kJOR/AblmdAs=
\ No newline at end of file
diff --git a/docs/cassettes/introduction_c1955d79-a1e4-47d0-ba79-b45bd5752a23.msgpack.zlib b/docs/cassettes/introduction_c1955d79-a1e4-47d0-ba79-b45bd5752a23.msgpack.zlib
deleted file mode 100644
index 3648a8428..000000000
--- a/docs/cassettes/introduction_c1955d79-a1e4-47d0-ba79-b45bd5752a23.msgpack.zlib
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_c5382e81-bfcd-4508-b02a-099e3d9627fd.msgpack.zlib b/docs/cassettes/introduction_c5382e81-bfcd-4508-b02a-099e3d9627fd.msgpack.zlib
new file mode 100644
index 000000000..e8bc8459f
--- /dev/null
+++ b/docs/cassettes/introduction_c5382e81-bfcd-4508-b02a-099e3d9627fd.msgpack.zlib
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_dba1b168-f8e0-496d-9bd6-37198fb4776e.msgpack.zlib b/docs/cassettes/introduction_dba1b168-f8e0-496d-9bd6-37198fb4776e.msgpack.zlib
index 3859f4c05..aa5ff8b76 100644
--- a/docs/cassettes/introduction_dba1b168-f8e0-496d-9bd6-37198fb4776e.msgpack.zlib
+++ b/docs/cassettes/introduction_dba1b168-f8e0-496d-9bd6-37198fb4776e.msgpack.zlib
@@ -1 +1 @@
-eNqNVVtsFFUY3oJBbUxECxKUyGGjbQKd7cxuW9uGqKUtBUtLaRe1NVhmZ047w87OmZ45s3RpatJiMaIBRhNBDQ/S7S5Z29JKpQ8olweDWEiEgKQQ+wJEQ3wgRjQRDP6z3aWFlss+bM6e833/5fsv2xUPY2qqRM/oU3WGqSgx+GHaXXGKWy1ssvdjIcwUIkdr19b7eyyqjr2sMGaYJXl5oqF6RJ0plBiq5JFIKC8s5IWwaYot2IwGiBy5OCuz3R0S25oYCWLddJcggffm5yJ3GgU377S7KdEwnNyWiakbXiUCoejMuVqlIqZgipeg6gjSxRBGqoneUjXN4+7Y4BgiMtYcoKSJlow5H1fAmUTXMeO84Iov9PKORUaIlnLmGHEITAyrWqTJxCKVlCaKTUtjZtMmIDsEGZsSVQ1HDAdciiZwCOstqo4RgZeQugXLqJlQBKkbFCuQoRrGuUiUJIuKzDnpMmLUMhkAUx48aL2Jmy0tSdwMHBQhFtIxIBgBgrkZU5RU3qkDEgPEYgjsURAE4TB8g4nVugG3pkIsTUYBjMR0eECkEY+TgOpAmkxJwSERMmh3G1AmTJmaFL3dnUQmT/ekOtWSE5JGSBBZRlLFiJGUzmRU1VvcHR1w57SJSrHsiJsyumEKlAQ2YYkBdENHXMGiDM22M6oQk9lD09rnAAiHDcZhXSIyOLD7W7aoRi6ScbMGciYkp67J/rQTQYwNTtRA79gEyx4UDUNTJdF5z3PK2JdqI86JZfpzwuk2DppQZ/ZIaTqOvNoIdLuOeI8v3+MdbONMJqq6Bu3KaSKEFDOS74enPhiiFAQ7XGqS7NgEeWAqhph2b7Uora2/y6SjtN0r0lBh/sGp99TSob+wHS+rne4u9TjpzucRBM8rQ3cZNiO6ZPc2i5qJh+6IfIeSgNnwcXwhxwsDaZU0aG2m2D0FXu9+6FUDug9vjYFJZpldUagIPvVjPDW3+9ZWpas57loQLYfq2N/7FSsXCYXoDVFHYL8AeYUSvriE96LKan9fWcqNf8ZiDPkptH4zFKQiXfy4pFh6EMuJshnLPuaeTMsZNg3mkXGppQXFcn7a0Xye58eyH4ikMCCq7niM+oqLix9iF5TBzB528gPxOKHQn8qSb5zZT3IOuYn9l4oq5kQFcS19KH4ytjQn+xE494nQ2ziWMxMbFsy0EHuLkt6WPRw/GWKKk/MonPuHiGai3yPfhKOXHoCcKtwEGj0Qfd94EqnKc6psfwfnJl5YUxGqa9xcU0lCtaFaucBPK9e1NazpCauinRA8AmohpEXDB8pWcmUirF+uPjlCdry8oaa0enVZ39tcHQkQ6CW/CD2nEx3H6jGF0bQTkkYsGZYdxTGg15U22MPFvE8QCoqKeMknF/OFBdwK2CHpYbozLFFnUyb/cjtjE9v5h4zliz96wpX8zJZ3lVbNFuZ23/6paPe7Yfzroa+vnC3L6698prz8s10fh7QvNF/Wpd6/jo4OZG6Pd/5zJPL0+MK9Fd3t48PnT28K37x1pHXn6Mjh9guLdlsHz8Ufz639d8ec7XtubBs8Nu8/pDSf2Ld1Y+dN5WTPisvWIX/NaOSk8Ngn3wxcazh/bv5zSmBuZte1q7eylrLnx0/0GBXjlW10vOl4Y/ZTxxfO+nAw59nfpSPb1i/vOpPxy/X1r+1HZ669lxGcM1bn/vmrD2pyWrPb974e+O2Uqya3beSFrH7p08+XxOxX5UCrcH3PyPnFw8dGg525Q8EsdUfG/LrB/ivzrl/aWCJnbqvt/qOjM7Jo1d4z3Z6qZa2VnetOJyKdK7/kvs22X9xy8Wj5jcs5Z/8+uuDgrTdjp6/++aTLdfv2bFfFhX7zcIbL9T+lrJEt
\ No newline at end of file
+eNqNVWtsU1UcH8NXiAnxgy5+UA+NY4nudn1s6zbFZJbXgDFYS9yArZ7de9ZeenvP9dxzB2UOZQxDxKE3YlCCBlnXYi2wBWQQID7QiAkmk0DiCALxEUgMxn0AAjGZ/3vXssHGo0mbe8/5/f6P3//RzlQbYbpM1SkZWeWEYZHDi252phh5wyA670rGCI9QKbGkLhDsMZg8VBjhXNOrSkqwJjuxyiOMarLoFGmspM1dEiO6jsNET7RQKX42f1q7I4bXhDiNElV3VCG3y1NajBw5FJysaHcwqhB4chg6YQ64FSmEonLraL6MeIQwMgPVxpGKYwTJOnpNVhSno6PJMkQlolhAUcGGRASvUCboVFUJFzzgylXucVkWOaVK1pllxCJw3CYr8ZBOMBMjIUZ0Q+F6aBWQLYJEdJHJmiWGBa5GozhE1LCsEkThJiavJRJqpQxB6hojEchQbiPFCIuiwTC3nlQJcWboHIBZD060TCethmITVwMHxamBVAIIToGgryYM2cpbdUC4hRocgT0GgiDSBr9gokbV4FSPUEORUAtBOBceEFncaSUgW5CQLkZIDEMG7Q4NykQYl23R2x020n66I9XxlqyQFEqjyNBsFeOaLZ3OmayGHR0dcGa1icyIZImbNdo0DkpbVhGRA7SpIxUhWIJmez8RoTo3+ye0zz4QjmhcIKpIJXBg7gmvlbViJJFWBeRMi1Zd7f4001FCNAEroHdylGX2YU1TZBFb9yVWGTPZNhKsWCZep61uE6AJVW4OVOfiKFkSh25XkcvpLXV6+tYIOseyqkC7CgqGkJKafX9k/IWGxSjYEbKTZCZHyXvHY6hu9tZisS5wm0lLabMXs1h56f7x58xQob+ImfIvmegueznmzut0u52+/tsM63FVNHtbsaKT/lsi36KkYTa8gqtccLn35lRSoLV5xOwp83h2Q69q0H1kQxJMckPvTEBFyMkTqezc7qpbmKvm+byCxGyojnlsLpOLkduHFmAVgf0y5C6vcnurXBVoXm0w48+6CU5ajP4gg9ZvhYLMyRU/JUYMNUqktH/Ssg85xtKyhk2BeeRCdmlBsaxXM1HqcrmGZt4TyWBAZNXymPBWVlbexy4oQ7h5wMoPxBPcvmA2S9/yyf3YcyiM7r9sVEkrKojrhfvix2LLcWY+AOcuEVYsHyqajA0LZkKIvRW2txfvjx8LMcspehDO3UNEk9HvkG/U0fP3QI4XbhSN7om+azzpbOUFWTKPwnPI5a5c2lK2tDocqG2pX1NqyKuXRcvilaynTcZm2u10ozClYYXs888V/BjWrxCwR8hMzW5cXF1b4880CPW0hUIvBTH0nEpVkgwQBqNppkWFGhIsO0aSQK+vbjQPVLq8Puz2iWUVEi4VRVF4FXZIbphuDUvC2pT2X+765Oh2/mFK6XObH8uzP1PhOzIifVAbza9+/J2RBds3b/sq8/ePuKT56uCzXfWfbyUf1/z2rXtI9ezeNHIss2fwVOBi/PzR9Stdj2SGdx5J7lCmf1hQFVNWPOMvuhIYaHx5oOvhs4d7ZsxJq763m0/l7VgV1JWGi9X5hZlfirZN7U79caNh4yfKyo/OZFYGC5+6vLH71751R84t7F58/Gbs9KFdWx9qFhdM7zto5s+rez3/UceG/X/Oa/jpiaNiw/HrN9Z31miXCjNPZno/+2Z46OyJlwa3vPnfpnXzu/MTh74+c6VxC5rVtfuVL53DN5t3bue1dYs39s/9fbDhn6ff6joVnnmtq+zS1mknB0KnC947R6KLrn3/7tXMjoLLn9IvhmdVbv7u5wuz49dnHf73Qs3BC9Lypn0hW5qpeX8t2vNBckpe3v9NnJOl
\ No newline at end of file
diff --git a/docs/cassettes/introduction_df6d81bb-e674-44ef-a46e-17b1a8d2381a.msgpack.zlib b/docs/cassettes/introduction_df6d81bb-e674-44ef-a46e-17b1a8d2381a.msgpack.zlib
new file mode 100644
index 000000000..c88c4d311
--- /dev/null
+++ b/docs/cassettes/introduction_df6d81bb-e674-44ef-a46e-17b1a8d2381a.msgpack.zlib
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_effb95d9-b7d5-40c5-9253-253d193b23b2.msgpack.zlib b/docs/cassettes/introduction_effb95d9-b7d5-40c5-9253-253d193b23b2.msgpack.zlib
deleted file mode 100644
index 8556e6463..000000000
--- a/docs/cassettes/introduction_effb95d9-b7d5-40c5-9253-253d193b23b2.msgpack.zlib
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_f5447778-53d7-47f3-801b-f47bcf2185a0.msgpack.zlib b/docs/cassettes/introduction_f5447778-53d7-47f3-801b-f47bcf2185a0.msgpack.zlib
index 9e0098b4a..870503059 100644
--- a/docs/cassettes/introduction_f5447778-53d7-47f3-801b-f47bcf2185a0.msgpack.zlib
+++ b/docs/cassettes/introduction_f5447778-53d7-47f3-801b-f47bcf2185a0.msgpack.zlib
@@ -1 +1 @@
-eNqNVl1sU1Uc3xgxOkGRB4iK26HKRnS3u223QRcNbgPZWCZj68Qhyzy993S99Paeyz3nbnTLoo4FNSOOa0gGD6hhXUvqGCwSUdiegIDEaPwKTuMe1MQQH5QHHxTj/N/blg02PvrQnJ7z+/0/fv+PtC/ZSQymUC13VNE4MbDE4Qez+pIG2W0SxvsTUcLDVI43bm0ODJuGMrUmzLnOKktLsa64scbDBtUVyS3RaGmnpzRKGMMdhMWDVI79sOiPHlcU72nnNEI05qpEHtFbVoJcWRTcvNLjMqhK4OQyGTFc8CpRCEXj9lWtgniYGGQ1aoghDUcJUhjarqiq29VbgmapmDGFcYjmVj5RVeoQVqM6XsyQpkgEcYqihHAUo6Yb1dIuJGEN1aG0EfsWEDKObUB1LO0eYS2GdGxwRTJVbMAzpGwDi2WkKhHHoqwwyWQMUcNBO+rZWjr2wriTbLg55AWybSJREg0SA0XTyQKjzVaLykS13yUVmzIRfEK5wKimES54QU+xwivahjilakZRm2wTOO5U1Fg7I9iQwu0GYabKWfsuINsEmTDJUHQ7ShtchdI4RLQORSOIwktU6SYyCkFOUF/dIGEoo9JJShCWJNPA3D5pMuKGyTgAMx7cqIWRkKk6xC7gOBpoBBAgFNZYF+Q4KxAOUpMjsGeADoh0wjeYqNN0uGVhaqoyCkIJsuEB0Yi57QQUG9LOpDCJYsigx6VDLxKoktNZPS4H6ZxuSXWuJTskldIIMnVHxZjuSMe4oWgdrl6omcueBcUgsi1uxmjbHCgN7iISB2hbbzJMsAwTNRgPU8at8XkzcgKEIzoXiCZRGRxYxzu6Fb0EySSkgpwpya6rM4RWKkKILmAV9E6kWdZJrOuqImH7vdQu42imewQ7lvnPKbvJBJg0jVunq7JxlDbGYKQ1JLp9ZW7vyT0CTI6iqTCTgoohpITuvJ+d+6BjKQJ2hMy6sBJp8thcDGXWSAOWtjbfZNJW2hrBRrSi7KO594apQX8RK1nTON9d5nHWnc/t8bjXjd9kmMU0yRoJYZWR8Rsi36CkYDZ8glghiJ6xrEoqtDYPW8Pryj3HoFd16D6yNwEmucn64lAR8vmlZGY5Hd1an63mdM7K+EaojjUZCJslyFOBtsDCAPvlyOupFP2Vog9tbgiM1mTcBBYsxnjAgNYPQUE2ZYuflMKmFiFyqmbBsk+5ZtOyh02FeeRCZjNDseyfVrxMFMWpojsiDRgQRbM9xn1+v/8udkEZwq1Tdn4gnuCpCGSy9O5Y2I8zh0J6yWeiSthRQVxP3xU/G1uWU3QPnNtHWLwQGxbMvBBH1jvenrk7fjbEDKf4Xji3CdG3YwotRL9FvrSjp+6AnCtcGo3uiL6tZKlM5QVFtibg3C56vHhjbWssTCJdPLa9uoVGtfWtwU3DnQq2Uh63B3VQ2qGSEzUvCDUY1q/Q7IyQldzY+mJVQ13N6MtCEw1S6KUAhp7TqEYSzcSA0bRSkkpNGZadQRJAb6pqtU75RZ/HU+73eUPSOr9YUS5Uww7JDtONYYnbm9L5X/FGIr2dL+QWFw7cn+N88uTBhvrz4rJ9M1sODQwFzvx0Juwu+PZcwYqHBwrXNgW9Z5c2FJcf/oBcfW3I7V773n3Tv8XaD+WtfzD/n1P08oW2yclPu6fHVgy+cwbHzk49O/H9kuV7Vukfi2smNx9Ytvf9vCPv1o++XVVdWNLd+OrEFysGyO5t8ef7dwZIy9CHqcUPFC170nPsyjnl4LXIWOFg3/Uj4uqL/U2jm84XXO/aH1ziz//6uS3Xfp3YsPL3pz658Fb1N5eOD0/W5j12moU6vxz9c6zmq6OF55O/vKSf7J7Yd7Wh+mex7BEzf3H+AfWcf/m/r/cXPvoZWnt5uv7SxTe/y1219PDjDz3RtKjlytDy/RVCRdHR0Mpjf0cOFhds+3GmRP7vSOCvst68nJyZmbycrp1XpYHcnJz/AaIMyJ0=
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/docs/cassettes/introduction_faa345c6-38a2-42e8-9035-9cf56f7bb5b1.msgpack.zlib b/docs/cassettes/introduction_faa345c6-38a2-42e8-9035-9cf56f7bb5b1.msgpack.zlib
deleted file mode 100644
index 967cd660a..000000000
--- a/docs/cassettes/introduction_faa345c6-38a2-42e8-9035-9cf56f7bb5b1.msgpack.zlib
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file