diff --git a/docs/docs/tutorials/functional_api/functional_api_test.ipynb b/docs/docs/tutorials/functional_api/react_functional_api.ipynb similarity index 84% rename from docs/docs/tutorials/functional_api/functional_api_test.ipynb rename to docs/docs/tutorials/functional_api/react_functional_api.ipynb index d2f7fba73..468bb18e7 100644 --- a/docs/docs/tutorials/functional_api/functional_api_test.ipynb +++ b/docs/docs/tutorials/functional_api/react_functional_api.ipynb @@ -28,7 +28,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -49,7 +49,7 @@ }, { "cell_type": "code", - "execution_count": 90, + "execution_count": 26, "metadata": {}, "outputs": [], "source": [ @@ -96,7 +96,7 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -108,10 +108,10 @@ "Add 3 and 4.\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"I'll help you add those numbers using the `add` function.\", 'type': 'text'}, {'id': 'toolu_01Lr23DbYsJvGSuzwQdXqDvH', 'input': {'a': 3, 'b': 4}, 'name': 'add', 'type': 'tool_use'}]\n", + "[{'text': \"I'll help you add 3 and 4 using the `add` function.\", 'type': 'text'}, {'id': 'toolu_01Js4XXxB1oMDqZKz6VkxpnQ', 'input': {'a': 3, 'b': 4}, 'name': 'add', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " add (toolu_01Lr23DbYsJvGSuzwQdXqDvH)\n", - " Call ID: toolu_01Lr23DbYsJvGSuzwQdXqDvH\n", + " add (toolu_01Js4XXxB1oMDqZKz6VkxpnQ)\n", + " Call ID: toolu_01Js4XXxB1oMDqZKz6VkxpnQ\n", " Args:\n", " a: 3\n", " b: 4\n", @@ -181,7 +181,8 @@ "source": [ "### Agent with short-term memory (within a thread)\n", "\n", - "* LangGraph persistence layer \n", + "* LangGraph persistence layer\n", + "* Allows you to resume any conversation with the agent\n", "\n", "`@entrypoint` \n", "* Decorator indicates the start of a workflow / agent \n", @@ -206,7 +207,7 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -233,9 +234,9 @@ " tool = tools_by_name[tool_call[\"name\"]]\n", " return tool.invoke(tool_call)\n", "\n", - "checkpointer = MemorySaver()\n", + "checkpointer = MemorySaver() # New\n", "@entrypoint(checkpointer=checkpointer) # New \n", - "def agent(messages: list[BaseMessage], previous: list[BaseMessage]): # New \n", + "def agent(messages: list[BaseMessage], previous: list[BaseMessage]): # previous (state associated with the previous ckpt)\n", " \"\"\" Tool calling agent \"\"\"\n", "\n", " # Add previous messages from short-term memory to the current messages\n", @@ -264,7 +265,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -276,10 +277,10 @@ "Add 3 and 4.\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"I'll help you add 3 and 4 using the `add` function.\", 'type': 'text'}, {'id': 'toolu_013z1syyD8SvfDKdysUSwyeq', 'input': {'a': 3, 'b': 4}, 'name': 'add', 'type': 'tool_use'}]\n", + "[{'text': \"I'll help you add 3 and 4 using the `add` function.\", 'type': 'text'}, {'id': 'toolu_016nz34fiRCrz2pcipHGRbEc', 'input': {'a': 3, 'b': 4}, 'name': 'add', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " add (toolu_013z1syyD8SvfDKdysUSwyeq)\n", - " Call ID: toolu_013z1syyD8SvfDKdysUSwyeq\n", + " add (toolu_016nz34fiRCrz2pcipHGRbEc)\n", + " Call ID: toolu_016nz34fiRCrz2pcipHGRbEc\n", " Args:\n", " a: 3\n", " b: 4\n", @@ -308,7 +309,7 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -320,10 +321,10 @@ "Add 3 and 4.\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"I'll help you add 3 and 4 using the `add` function.\", 'type': 'text'}, {'id': 'toolu_013z1syyD8SvfDKdysUSwyeq', 'input': {'a': 3, 'b': 4}, 'name': 'add', 'type': 'tool_use'}]\n", + "[{'text': \"I'll help you add 3 and 4 using the `add` function.\", 'type': 'text'}, {'id': 'toolu_016nz34fiRCrz2pcipHGRbEc', 'input': {'a': 3, 'b': 4}, 'name': 'add', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " add (toolu_013z1syyD8SvfDKdysUSwyeq)\n", - " Call ID: toolu_013z1syyD8SvfDKdysUSwyeq\n", + " add (toolu_016nz34fiRCrz2pcipHGRbEc)\n", + " Call ID: toolu_016nz34fiRCrz2pcipHGRbEc\n", " Args:\n", " a: 3\n", " b: 4\n", @@ -346,7 +347,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -358,10 +359,10 @@ "Add 3 and 4.\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"I'll help you add 3 and 4 using the `add` function.\", 'type': 'text'}, {'id': 'toolu_013z1syyD8SvfDKdysUSwyeq', 'input': {'a': 3, 'b': 4}, 'name': 'add', 'type': 'tool_use'}]\n", + "[{'text': \"I'll help you add 3 and 4 using the `add` function.\", 'type': 'text'}, {'id': 'toolu_016nz34fiRCrz2pcipHGRbEc', 'input': {'a': 3, 'b': 4}, 'name': 'add', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " add (toolu_013z1syyD8SvfDKdysUSwyeq)\n", - " Call ID: toolu_013z1syyD8SvfDKdysUSwyeq\n", + " add (toolu_016nz34fiRCrz2pcipHGRbEc)\n", + " Call ID: toolu_016nz34fiRCrz2pcipHGRbEc\n", " Args:\n", " a: 3\n", " b: 4\n", @@ -377,10 +378,10 @@ "Take the result and multiply it by 2.\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"I'll multiply the previous result (7) by 2 using the `multiply` function.\", 'type': 'text'}, {'id': 'toolu_01RhScbTXybkGxYG6RA1tQpM', 'input': {'a': 7, 'b': 2}, 'name': 'multiply', 'type': 'tool_use'}]\n", + "[{'text': \"I'll take the previous result (7) and multiply it by 2 using the `multiply` function.\", 'type': 'text'}, {'id': 'toolu_01Mqx3AB6Xiiz3gZcQHrxnPB', 'input': {'a': 7, 'b': 2}, 'name': 'multiply', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " multiply (toolu_01RhScbTXybkGxYG6RA1tQpM)\n", - " Call ID: toolu_01RhScbTXybkGxYG6RA1tQpM\n", + " multiply (toolu_01Mqx3AB6Xiiz3gZcQHrxnPB)\n", + " Call ID: toolu_01Mqx3AB6Xiiz3gZcQHrxnPB\n", " Args:\n", " a: 7\n", " b: 2\n", @@ -390,7 +391,7 @@ "14\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "The result of multiplying 7 by 2 is 14.\n" + "7 multiplied by 2 equals 14.\n" ] } ], @@ -407,6 +408,7 @@ "source": [ "### Agent with HITL\n", "\n", + "* Very useful for [approval](https://www.anthropic.com/research/building-effective-agents) in agents.\n", "* Add interrupt to the workflow to allow for HITL.\n", "* Re-executes from the start of the entrypoint.\n", "* Output of each `@task` is cached / saved as a checkpoint." @@ -414,7 +416,7 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 37, "metadata": {}, "outputs": [], "source": [ @@ -423,7 +425,7 @@ "@task\n", "def call_llm(messages: list[BaseMessage]):\n", " \"\"\"LLM decides whether to call a tool or not\"\"\"\n", - " print(\"Calling LLM or using cached LLM output!\")\n", + " print(\"Calling LLM!\")\n", " return llm_with_tools.invoke(\n", " [\n", " SystemMessage(\n", @@ -436,7 +438,7 @@ "@task\n", "def call_tool(tool_call: ToolCall):\n", " \"\"\"Performs the tool call\"\"\"\n", - " print(\"Calling tool or using cached tool output!\")\n", + " print(\"Calling tool!\")\n", " # Interrupt the workflow to get a review from a human.\n", " is_approved = interrupt({ # New \n", " # Any json-serializable payload provided to interrupt as argument.\n", @@ -457,7 +459,8 @@ "@entrypoint(checkpointer=MemorySaver()) \n", "def agent(messages: list[BaseMessage], previous: list[BaseMessage]): \n", " \"\"\" Tool calling agent \"\"\"\n", - "\n", + " print(\"Executing agent!\")\n", + " \n", " # Add previous messages from short-term memory to the current messages\n", " if previous is not None:\n", " messages = add_messages(previous, messages)\n", @@ -482,16 +485,17 @@ }, { "cell_type": "code", - "execution_count": 76, + "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Calling LLM or using cached LLM output!\n", - "Calling tool or using cached tool output!\n", - "{'tool_call': {'name': 'add', 'args': {'a': 3, 'b': 4}, 'id': 'toolu_017uJdvp4SfEyPLVWamxBjGT', 'type': 'tool_call'}, 'action': 'Please approve/reject the tool call'}\n" + "Executing agent!\n", + "Calling LLM!\n", + "Calling tool!\n", + "{'tool_call': {'name': 'add', 'args': {'a': 3, 'b': 4}, 'id': 'toolu_01GGBdQZJ11bZGyHuvRkuRrh', 'type': 'tool_call'}, 'action': 'Please approve/reject the tool call'}\n" ] } ], @@ -510,15 +514,16 @@ }, { "cell_type": "code", - "execution_count": 77, + "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Calling tool or using cached tool output!\n", - "Calling LLM or using cached LLM output!\n", + "Executing agent!\n", + "Calling tool!\n", + "Calling LLM!\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", "The sum of 3 and 4 is 7.\n" @@ -532,18 +537,35 @@ " item['agent'][-1].pretty_print()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Initial Execution Flow:\n", + "* `call_llm` runs first and is cached\n", + "* `call_tool` starts but hits the interrupt\n", + "* Execution pauses waiting for human input\n", + "\n", + "After Resume:\n", + "* `call_tool` continues from where it left off (since it didn't complete)\n", + "* The tool executes if approved\n", + "* `call_llm` runs again with the tool results\n", + "* Final response is generated" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Time travel\n", "\n", - "* It can be useful to add time travel to the workflow.\n" + "* It can be useful to add time travel to the workflow.\n", + "* This allows you to rewind to specific checkpoint, modify the workflow, and re-run it. \n" ] }, { "cell_type": "code", - "execution_count": 108, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -593,7 +615,7 @@ }, { "cell_type": "code", - "execution_count": 109, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -605,10 +627,10 @@ "Add 3 and 4.\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"I'll help you add 3 and 4 using the `add` function.\", 'type': 'text'}, {'id': 'toolu_015EBCekAyhHGVExDSCbSppi', 'input': {'a': 3, 'b': 4}, 'name': 'add', 'type': 'tool_use'}]\n", + "[{'text': \"I'll help you add 3 and 4 using the `add` function.\", 'type': 'text'}, {'id': 'toolu_0144yacRC2U5UkwEfEzBdzm2', 'input': {'a': 3, 'b': 4}, 'name': 'add', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " add (toolu_015EBCekAyhHGVExDSCbSppi)\n", - " Call ID: toolu_015EBCekAyhHGVExDSCbSppi\n", + " add (toolu_0144yacRC2U5UkwEfEzBdzm2)\n", + " Call ID: toolu_0144yacRC2U5UkwEfEzBdzm2\n", " Args:\n", " a: 3\n", " b: 4\n", @@ -637,7 +659,7 @@ }, { "cell_type": "code", - "execution_count": 110, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -646,7 +668,7 @@ "text": [ "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "The result of multiplying 7 by 2 is 14.\n" + "7 multiplied by 2 equals 14.\n" ] } ], @@ -659,18 +681,18 @@ }, { "cell_type": "code", - "execution_count": 111, + "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'configurable': {'thread_id': 'ac13180b-31f0-4ff5-8d71-0354addc0a59',\n", + "{'configurable': {'thread_id': 'c0336c2c-1a97-4b6d-826c-21c33eb47ccb',\n", " 'checkpoint_ns': '',\n", - " 'checkpoint_id': '1efddb89-50bb-6c16-8001-4b2a0f971b4e'}}" + " 'checkpoint_id': '1efddbc1-103d-66d4-8001-48133c20ef14'}}" ] }, - "execution_count": 111, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -683,7 +705,7 @@ }, { "cell_type": "code", - "execution_count": 112, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -695,10 +717,10 @@ "Add 3 and 4.\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "[{'text': \"I'll help you add 3 and 4 using the `add` function.\", 'type': 'text'}, {'id': 'toolu_015EBCekAyhHGVExDSCbSppi', 'input': {'a': 3, 'b': 4}, 'name': 'add', 'type': 'tool_use'}]\n", + "[{'text': \"I'll help you add 3 and 4 using the `add` function.\", 'type': 'text'}, {'id': 'toolu_0144yacRC2U5UkwEfEzBdzm2', 'input': {'a': 3, 'b': 4}, 'name': 'add', 'type': 'tool_use'}]\n", "Tool Calls:\n", - " add (toolu_015EBCekAyhHGVExDSCbSppi)\n", - " Call ID: toolu_015EBCekAyhHGVExDSCbSppi\n", + " add (toolu_0144yacRC2U5UkwEfEzBdzm2)\n", + " Call ID: toolu_0144yacRC2U5UkwEfEzBdzm2\n", " Args:\n", " a: 3\n", " b: 4\n", @@ -721,7 +743,7 @@ }, { "cell_type": "code", - "execution_count": 113, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -730,63 +752,17 @@ "text": [ "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "The result of multiplying 7 by 2 is 14.\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The result of multiplying 7 by 2 is 14.\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The result of multiplying 7 by 2 is 14.\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The result of multiplying 7 by 2 is 14.\n" + "7 multiplied by 3 equals 21.\n" ] } ], "source": [ "# Re-run the workflow from the fork\n", - "for chunk in agent.stream([HumanMessage(content=\"Take the result and multiply it by 3.\")], to_fork_from, stream_mode=\"updates\"):\n", + "for item in agent.stream([HumanMessage(content=\"Take the result and multiply it by 3.\")], to_fork_from, stream_mode=\"updates\"):\n", " if 'agent' in item:\n", " item['agent'][-1].pretty_print()" ] }, - { - "cell_type": "code", - "execution_count": 114, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "Add 3 and 4.\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"I'll help you add 3 and 4 using the `add` function.\", 'type': 'text'}, {'id': 'toolu_015EBCekAyhHGVExDSCbSppi', 'input': {'a': 3, 'b': 4}, 'name': 'add', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " add (toolu_015EBCekAyhHGVExDSCbSppi)\n", - " Call ID: toolu_015EBCekAyhHGVExDSCbSppi\n", - " Args:\n", - " a: 3\n", - " b: 4\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: add\n", - "\n", - "7\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The sum of 3 and 4 is 7.\n" - ] - } - ], - "source": [ - "agent_state = agent.get_state(to_fork_from)\n", - "for m in agent_state.values:\n", - " m.pretty_print()" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -799,7 +775,7 @@ }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 48, "metadata": {}, "outputs": [], "source": [ @@ -833,7 +809,7 @@ "\n", " # BaseStore is a LangGraph persistence layer\n", " store.put(\n", - " (\"memories\"),\n", + " (\"memories\",\"lance\"),\n", " key=str(mem_id),\n", " value={\"content\": content},\n", " )\n", @@ -847,7 +823,7 @@ }, { "cell_type": "code", - "execution_count": 83, + "execution_count": 50, "metadata": {}, "outputs": [], "source": [ @@ -905,7 +881,7 @@ " # New \n", " # Retrieve the most recent memories for context\n", " memories = store.search( \n", - " (\"memories\"),\n", + " (\"memories\",\"lance\"),\n", " limit=10,\n", " )\n", "\n", @@ -939,14 +915,14 @@ }, { "cell_type": "code", - "execution_count": 84, + "execution_count": 51, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{'tool_call': {'name': 'upsert_memory', 'args': {'content': \"User's name is Lance.\"}, 'id': 'toolu_01Ppw9sRsBnkpmfUPmeHZVyR', 'type': 'tool_call'}, 'action': 'Please approve/reject the tool call'}\n" + "{'tool_call': {'name': 'upsert_memory', 'args': {'content': \"User's name is Lance.\"}, 'id': 'toolu_01Y1J6BnLWejpoQfF72GWP9L', 'type': 'tool_call'}, 'action': 'Please approve/reject the tool call'}\n" ] } ], @@ -965,9 +941,20 @@ }, { "cell_type": "code", - "execution_count": 86, + "execution_count": 52, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tool call approved, Memory Added!\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Nice to meet you Lance! Is there anything else you'd like me to help you with?\n" + ] + } + ], "source": [ "for item in agent.stream(Command(resume=True), config, stream_mode=\"updates\"):\n", " if 'agent' in item:\n", @@ -976,10 +963,23 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 55, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "data": { + "text/plain": [ + "[Item(namespace=['memories', 'lance'], key='20544090-a509-46ac-85f2-04b3f54db0d2', value={'content': \"User's name is Lance.\"}, created_at='2025-01-28T21:41:25.959474+00:00', updated_at='2025-01-28T21:41:25.959475+00:00', score=None)]" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "in_memory_store.search((\"memories\",\"lance\"))" + ] }, { "cell_type": "code", @@ -987,6 +987,24 @@ "metadata": {}, "outputs": [], "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Overview\n", + "\n", + "- Vanilla agent\n", + "- Added short-term memory (w/ tracing)\n", + "- Added short-term memory + HITL (w/ tracing)\n", + "- Added short-term memory + HITL + time travel (w/ tracing)\n", + "- Added short-term memory + HITL + long-term memory (w/ tracing)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] } ], "metadata": {