diff --git a/docs/docs/how_to/migrate_agent.ipynb b/docs/docs/how_to/migrate_agent.ipynb index c517f415c0..2ed479d5b0 100644 --- a/docs/docs/how_to/migrate_agent.ipynb +++ b/docs/docs/how_to/migrate_agent.ipynb @@ -8,8 +8,23 @@ "# How to migrate from legacy LangChain agents to LangGraph\n", "\n", "Here we focus on how to move from legacy LangChain agents to LangGraph agents.\n", - "LangChain agents (the AgentExecutor in particular) have multiple configuration parameters.\n", - "In this notebook we will show how those parameters map to the LangGraph `chat_agent_executor`." + "LangChain agents (the [AgentExecutor](https://api.python.langchain.com/en/latest/agents/langchain.agents.agent.AgentExecutor.html#langchain.agents.agent.AgentExecutor) in particular) have multiple configuration parameters.\n", + "In this notebook we will show how those parameters map to the LangGraph [react agent executor](https://langchain-ai.github.io/langgraph/reference/prebuilt/#create_react_agent).\n", + "\n", + "#### Prerequisites\n", + "\n", + "This how-to guide uses OpenAI as the LLM. Install the dependencies to run." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "662fac50", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture --no-stderr\n", + "%pip install -U langchain-openai langchain langgraph" ] }, { @@ -24,7 +39,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 6, "id": "1e425fea-2796-4b99-bee6-9a6ffe73f756", "metadata": {}, "outputs": [], @@ -32,7 +47,7 @@ "from langchain_core.tools import tool\n", "from langchain_openai import ChatOpenAI\n", "\n", - "model = ChatOpenAI()\n", + "model = ChatOpenAI(model=\"gpt-4o\")\n", "\n", "\n", "@tool\n", @@ -52,12 +67,12 @@ "id": "af002033-fe51-4d14-b47c-3e9b483c8395", "metadata": {}, "source": [ - "For AgentExecutor, we define a prompt with a placeholder for the agent's scratchpad. The agent can be invoked as follows:" + "For the LangChain [AgentExecutor](https://api.python.langchain.com/en/latest/agents/langchain.agents.agent.AgentExecutor.html#langchain.agents.agent.AgentExecutor), we define a prompt with a placeholder for the agent's scratchpad. The agent can be invoked as follows:" ] }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 15, "id": "03ea357c-9c36-4464-b2cc-27bd150e1554", "metadata": {}, "outputs": [ @@ -68,20 +83,21 @@ " 'output': 'The value of `magic_function(3)` is 5.'}" ] }, - "execution_count": 21, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from langchain.agents import AgentExecutor, create_tool_calling_agent\n", - "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", + "from langchain_core.prompts import ChatPromptTemplate\n", "\n", "prompt = ChatPromptTemplate.from_messages(\n", " [\n", " (\"system\", \"You are a helpful assistant\"),\n", " (\"human\", \"{input}\"),\n", - " MessagesPlaceholder(\"agent_scratchpad\"),\n", + " # Placeholders fill up a **list** of messages\n", + " (\"placeholder\", \"{agent_scratchpad}\"),\n", " ]\n", ")\n", "\n", @@ -97,13 +113,13 @@ "id": "94205f3b-fd2b-4fd7-af69-0a3fc313dc88", "metadata": {}, "source": [ - "LangGraph's `chat_agent_executor` manages a state that is defined by a list of messages. It will continue to process the list until there are no tool calls in the agent's output. To kick it off, we input a list of messages. The output will contain the entire state of the graph-- in this case, the conversation history.\n", + "LangGraph's [react agent executor](https://langchain-ai.github.io/langgraph/reference/prebuilt/#create_react_agent) manages a state that is defined by a list of messages. It will continue to process the list until there are no tool calls in the agent's output. To kick it off, we input a list of messages. The output will contain the entire state of the graph-- in this case, the conversation history.\n", "\n" ] }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 16, "id": "53a3737a-d167-4255-89bf-20ac37f89a3e", "metadata": {}, "outputs": [ @@ -111,18 +127,18 @@ "data": { "text/plain": [ "{'input': 'what is the value of magic_function(3)?',\n", - " 'output': 'The value of the magic function with input 3 is 5.'}" + " 'output': 'The value of `magic_function(3)` is 5.'}" ] }, - "execution_count": 22, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from langgraph.prebuilt import chat_agent_executor\n", + "from langgraph.prebuilt import create_react_agent\n", "\n", - "app = chat_agent_executor.create_tool_calling_executor(model, tools)\n", + "app = create_react_agent(model, tools)\n", "\n", "\n", "messages = app.invoke({\"messages\": [(\"human\", query)]})\n", @@ -134,7 +150,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 17, "id": "74ecebe3-512e-409c-a661-bdd5b0a2b782", "metadata": {}, "outputs": [ @@ -142,10 +158,10 @@ "data": { "text/plain": [ "{'input': 'Pardon?',\n", - " 'output': 'The value of the magic function with input 3 is 5.'}" + " 'output': 'The result of applying the `magic_function` to the input `3` is `5`.'}" ] }, - "execution_count": 23, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -171,7 +187,7 @@ "\n", "With legacy LangChain agents you have to pass in a prompt template. You can use this to control the agent.\n", "\n", - "With LangGraph `chat_agent_executor`, by default there is no prompt. You can achieve similar control over the agent in a few ways:\n", + "With LangGraph [react agent executor](https://langchain-ai.github.io/langgraph/reference/prebuilt/#create_react_agent), by default there is no prompt. You can achieve similar control over the agent in a few ways:\n", "\n", "1. Pass in a system message as input\n", "2. Initialize the agent with a system message\n", @@ -184,7 +200,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 18, "id": "a9a11ccd-75e2-4c11-844d-a34870b0ff91", "metadata": {}, "outputs": [ @@ -195,7 +211,7 @@ " 'output': 'El valor de `magic_function(3)` es 5.'}" ] }, - "execution_count": 24, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -205,7 +221,8 @@ " [\n", " (\"system\", \"You are a helpful assistant. Respond only in Spanish.\"),\n", " (\"human\", \"{input}\"),\n", - " MessagesPlaceholder(\"agent_scratchpad\"),\n", + " # Placeholders fill up a **list** of messages\n", + " (\"placeholder\", \"{agent_scratchpad}\"),\n", " ]\n", ")\n", "\n", @@ -221,44 +238,27 @@ "id": "bd5f5500-5ae4-4000-a9fd-8c5a2cc6404d", "metadata": {}, "source": [ - "Now, let's pass a custom system message to `chat_agent_executor`. This can either be a string or a LangChain SystemMessage." + "Now, let's pass a custom system message to [react agent executor](https://langchain-ai.github.io/langgraph/reference/prebuilt/#create_react_agent). This can either be a string or a LangChain SystemMessage." ] }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 14, "id": "a9486805-676a-4d19-a5c4-08b41b172989", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'input': 'what is the value of magic_function(3)?',\n", - " 'output': 'El valor de magic_function(3) es 5.'}" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from langchain_core.messages import SystemMessage\n", + "from langgraph.prebuilt import create_react_agent\n", "\n", - "system_message = \"Respond only in Spanish\"\n", + "system_message = \"You are a helpful assistant. Respond only in Spanish.\"\n", "# This could also be a SystemMessage object\n", - "# system_message = SystemMessage(content=\"Respond only in Spanish\")\n", + "# system_message = SystemMessage(content=\"You are a helpful assistant. Respond only in Spanish.\")\n", "\n", - "app = chat_agent_executor.create_tool_calling_executor(\n", - " model, tools, messages_modifier=system_message\n", - ")\n", + "app = create_react_agent(model, tools, messages_modifier=system_message)\n", "\n", "\n", - "messages = app.invoke({\"messages\": [(\"human\", query)]})\n", - "{\n", - " \"input\": query,\n", - " \"output\": messages[\"messages\"][-1].content,\n", - "}" + "messages = app.invoke({\"messages\": [(\"user\", query)]})" ] }, { @@ -272,7 +272,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 21, "id": "d369ab45-0c82-45f4-9d3e-8efb8dd47e2c", "metadata": {}, "outputs": [ @@ -280,24 +280,35 @@ "data": { "text/plain": [ "{'input': 'what is the value of magic_function(3)?',\n", - " 'output': 'El valor de magic_function(3) es 5.'}" + " 'output': 'El valor de magic_function(3) es 5. ¡Pandamonium!'}" ] }, - "execution_count": 27, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "def _modify_messages(messages):\n", - " return [SystemMessage(content=\"Respond only in spanish\")] + messages\n", + "from langchain_core.messages import AnyMessage\n", + "from langgraph.prebuilt import create_react_agent\n", "\n", - "\n", - "app = chat_agent_executor.create_tool_calling_executor(\n", - " model, tools, messages_modifier=_modify_messages\n", + "prompt = ChatPromptTemplate.from_messages(\n", + " [\n", + " (\"system\", \"You are a helpful assistant. Respond only in Spanish.\"),\n", + " (\"placeholder\", \"{messages}\"),\n", + " ]\n", ")\n", "\n", "\n", + "def _modify_messages(messages: list[AnyMessage]):\n", + " return prompt.invoke({\"messages\": messages}).to_messages() + [\n", + " (\"user\", \"Also say 'Pandamonium!' after the answer.\")\n", + " ]\n", + "\n", + "\n", + "app = create_react_agent(model, tools, messages_modifier=_modify_messages)\n", + "\n", + "\n", "messages = app.invoke({\"messages\": [(\"human\", query)]})\n", "{\n", " \"input\": query,\n", @@ -317,7 +328,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 22, "id": "4eff44bc-a620-4c8a-97b1-268692a842bb", "metadata": {}, "outputs": [ @@ -325,7 +336,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "[(ToolAgentAction(tool='magic_function', tool_input={'input': 3}, log=\"\\nInvoking: `magic_function` with `{'input': 3}`\\n\\n\\n\", message_log=[AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_qckwqZI7p2LGYhMnQI5r6qsL', 'function': {'arguments': '{\"input\":3}', 'name': 'magic_function'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls'}, id='run-0602a2dd-c4d9-4050-b851-3e2b838c6773', tool_calls=[{'name': 'magic_function', 'args': {'input': 3}, 'id': 'call_qckwqZI7p2LGYhMnQI5r6qsL'}], tool_call_chunks=[{'name': 'magic_function', 'args': '{\"input\":3}', 'id': 'call_qckwqZI7p2LGYhMnQI5r6qsL', 'index': 0}])], tool_call_id='call_qckwqZI7p2LGYhMnQI5r6qsL'), 5)]\n" + "[(ToolAgentAction(tool='magic_function', tool_input={'input': 3}, log=\"\\nInvoking: `magic_function` with `{'input': 3}`\\n\\n\\n\", message_log=[AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_lIjE9voYOCFAVoUXSDPQ5bFI', 'function': {'arguments': '{\"input\":3}', 'name': 'magic_function'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls'}, id='run-7a23003a-ab50-4d7c-b14b-86129d1cacfe', tool_calls=[{'name': 'magic_function', 'args': {'input': 3}, 'id': 'call_lIjE9voYOCFAVoUXSDPQ5bFI'}], tool_call_chunks=[{'name': 'magic_function', 'args': '{\"input\":3}', 'id': 'call_lIjE9voYOCFAVoUXSDPQ5bFI', 'index': 0}])], tool_call_id='call_lIjE9voYOCFAVoUXSDPQ5bFI'), 5)]\n" ] } ], @@ -340,34 +351,33 @@ "id": "594f7567-302f-4fa8-85bb-025ac8322162", "metadata": {}, "source": [ - "By default the `chat_agent_executor` in LangGraph appends all messages to the central state. Therefore, it is easy to see any intermediate steps by just looking at the full state." + "By default the [react agent executor](https://langchain-ai.github.io/langgraph/reference/prebuilt/#create_react_agent) in LangGraph appends all messages to the central state. Therefore, it is easy to see any intermediate steps by just looking at the full state." ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 23, "id": "4f4364ea-dffe-4d25-bdce-ef7d0020b880", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'messages': [HumanMessage(content='what is the value of magic_function(3)?', id='408451ee-d65b-498b-abf1-788aaadfbeff'),\n", - " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_eF7WussX7KgpGdoJFj6cWTxR', 'function': {'arguments': '{\"input\":3}', 'name': 'magic_function'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 65, 'total_tokens': 79}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_3b956da36b', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-a07e5d11-9319-4e27-85fb-253b75c5d7c3-0', tool_calls=[{'name': 'magic_function', 'args': {'input': 3}, 'id': 'call_eF7WussX7KgpGdoJFj6cWTxR'}]),\n", - " ToolMessage(content='5', name='magic_function', id='35045a27-a301-474b-b321-5f93da671fb1', tool_call_id='call_eF7WussX7KgpGdoJFj6cWTxR'),\n", - " AIMessage(content='The value of magic_function(3) is 5.', response_metadata={'token_usage': {'completion_tokens': 13, 'prompt_tokens': 88, 'total_tokens': 101}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_3b956da36b', 'finish_reason': 'stop', 'logprobs': None}, id='run-18a36a26-2477-4fc6-be51-7a675a6e10e8-0')]}" + "{'messages': [HumanMessage(content='what is the value of magic_function(3)?', id='8c252eb2-9496-4ad0-b3ae-9ecb2f6c406e'),\n", + " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_xmBLOw2pRqB1aRTTiwqEEftW', 'function': {'arguments': '{\"input\":3}', 'name': 'magic_function'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 64, 'total_tokens': 78}, 'model_name': 'gpt-4o', 'system_fingerprint': 'fp_729ea513f7', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-2393b69c-7c52-4771-8bec-aca0e097fcc1-0', tool_calls=[{'name': 'magic_function', 'args': {'input': 3}, 'id': 'call_xmBLOw2pRqB1aRTTiwqEEftW'}]),\n", + " ToolMessage(content='5', name='magic_function', id='bec0d0f9-bbaf-49fb-b0cb-46a658658f87', tool_call_id='call_xmBLOw2pRqB1aRTTiwqEEftW'),\n", + " AIMessage(content='The value of `magic_function(3)` is 5.', response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 87, 'total_tokens': 101}, 'model_name': 'gpt-4o', 'system_fingerprint': 'fp_729ea513f7', 'finish_reason': 'stop', 'logprobs': None}, id='run-5904d36f-b2a4-4f55-b431-12c82992c92c-0')]}" ] }, - "execution_count": 6, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from langgraph.prebuilt import chat_agent_executor\n", - "\n", - "app = chat_agent_executor.create_tool_calling_executor(model, tools)\n", + "from langgraph.prebuilt import create_react_agent\n", "\n", + "app = create_react_agent(model, tools=tools)\n", "\n", "messages = app.invoke({\"messages\": [(\"human\", query)]})\n", "\n", @@ -390,7 +400,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 24, "id": "16f189a7-fc78-4cb5-aa16-a94ca06401a6", "metadata": {}, "outputs": [], @@ -406,7 +416,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 26, "id": "c96aefd7-6f6e-4670-aca6-1ac3d4e7871f", "metadata": {}, "outputs": [ @@ -421,15 +431,7 @@ "Invoking: `magic_function` with `{'input': '3'}`\n", "\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3mSorry, there was an error. Please try again.\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `magic_function` with `{'input': '3'}`\n", - "responded: I encountered an error while trying to determine the value of the magic function for the input \"3\". Let me try again.\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3mSorry, there was an error. Please try again.\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `magic_function` with `{'input': '3'}`\n", - "responded: I apologize for the inconvenience. It seems there is still an error in calculating the value of the magic function for the input \"3\". Let me attempt to resolve the issue by trying a different approach.\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3mSorry, there was an error. Please try again.\u001b[0m\u001b[32;1m\u001b[1;3m\u001b[0m\n", + "\u001b[0m\u001b[36;1m\u001b[1;3mSorry, there was an error. Please try again.\u001b[0m\u001b[32;1m\u001b[1;3mParece que hubo un error al intentar obtener el valor de `magic_function(3)`. ¿Te gustaría que lo intente de nuevo?\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] @@ -438,15 +440,24 @@ "data": { "text/plain": [ "{'input': 'what is the value of magic_function(3)?',\n", - " 'output': 'Agent stopped due to max iterations.'}" + " 'output': 'Parece que hubo un error al intentar obtener el valor de `magic_function(3)`. ¿Te gustaría que lo intente de nuevo?'}" ] }, - "execution_count": 8, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "prompt = ChatPromptTemplate.from_messages(\n", + " [\n", + " (\"system\", \"You are a helpful assistant. Respond only in Spanish.\"),\n", + " (\"human\", \"{input}\"),\n", + " # Placeholders fill up a **list** of messages\n", + " (\"placeholder\", \"{agent_scratchpad}\"),\n", + " ]\n", + ")\n", + "\n", "agent = create_tool_calling_agent(model, tools, prompt)\n", "agent_executor = AgentExecutor(\n", " agent=agent,\n", @@ -460,7 +471,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 29, "id": "b974a91f-6ae8-4644-83d9-73666258a6db", "metadata": {}, "outputs": [ @@ -468,35 +479,33 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_VkrswGIkIUKJQyVF0AvMaU3p', 'function': {'arguments': '{\"input\":\"3\"}', 'name': 'magic_function'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 65, 'total_tokens': 79}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_3b956da36b', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-2dd5504b-9386-4b35-aed1-a2a267f883fd-0', tool_calls=[{'name': 'magic_function', 'args': {'input': '3'}, 'id': 'call_VkrswGIkIUKJQyVF0AvMaU3p'}])]}}\n", - "------\n", - "{'action': {'messages': [ToolMessage(content='Sorry, there was an error. Please try again.', name='magic_function', id='85d7e845-f4ef-40a6-828d-c48c93b02b97', tool_call_id='call_VkrswGIkIUKJQyVF0AvMaU3p')]}}\n", - "------\n", - "{'agent': {'messages': [AIMessage(content='It seems there was an error when trying to calculate the value of the magic function for the input 3. Let me try again.', additional_kwargs={'tool_calls': [{'id': 'call_i5ZWsDhQvzgKs2bCroMB4JSL', 'function': {'arguments': '{\"input\":\"3\"}', 'name': 'magic_function'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 42, 'prompt_tokens': 98, 'total_tokens': 140}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_3b956da36b', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-6224c33b-0d3a-4925-9050-cb2a844dfe62-0', tool_calls=[{'name': 'magic_function', 'args': {'input': '3'}, 'id': 'call_i5ZWsDhQvzgKs2bCroMB4JSL'}])]}}\n", - "------\n", - "{'action': {'messages': [ToolMessage(content='Sorry, there was an error. Please try again.', name='magic_function', id='f846363c-b143-402c-949d-40d84b19d979', tool_call_id='call_i5ZWsDhQvzgKs2bCroMB4JSL')]}}\n", - "------\n", - "{'agent': {'messages': [AIMessage(content='Unfortunately, there seems to be an issue with calculating the value of the magic function for the input 3. Let me attempt to resolve this issue by using a different approach.', additional_kwargs={'tool_calls': [{'id': 'call_I26nZWbe4iVnagUh4GVePwig', 'function': {'arguments': '{\"input\": \"3\"}', 'name': 'magic_function'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 65, 'prompt_tokens': 162, 'total_tokens': 227}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_3b956da36b', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-0512509d-201e-4fbb-ac96-fdd68400810a-0', tool_calls=[{'name': 'magic_function', 'args': {'input': '3'}, 'id': 'call_I26nZWbe4iVnagUh4GVePwig'}])]}}\n", - "------\n", - "{'action': {'messages': [ToolMessage(content='Sorry, there was an error. Please try again.', name='magic_function', id='fb19299f-de26-4659-9507-4bf4fb53bff4', tool_call_id='call_I26nZWbe4iVnagUh4GVePwig')]}}\n", - "------\n", + "('human', 'what is the value of magic_function(3)?')\n", + "content='' additional_kwargs={'tool_calls': [{'id': 'call_9fMkSAUGRa2BsADwF32ct1m1', 'function': {'arguments': '{\"input\":\"3\"}', 'name': 'magic_function'}, 'type': 'function'}]} response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 64, 'total_tokens': 78}, 'model_name': 'gpt-4o', 'system_fingerprint': 'fp_729ea513f7', 'finish_reason': 'tool_calls', 'logprobs': None} id='run-79084bff-6e10-49bb-b7f0-f613ebcc68ac-0' tool_calls=[{'name': 'magic_function', 'args': {'input': '3'}, 'id': 'call_9fMkSAUGRa2BsADwF32ct1m1'}]\n", + "content='Sorry, there was an error. Please try again.' name='magic_function' id='06f997fd-5309-4d56-afa3-2fe8cbf0d04f' tool_call_id='call_9fMkSAUGRa2BsADwF32ct1m1'\n", + "content='' additional_kwargs={'tool_calls': [{'id': 'call_Fg92zoL8oS5q6im2jR1INRvH', 'function': {'arguments': '{\"input\":\"3\"}', 'name': 'magic_function'}, 'type': 'function'}]} response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 97, 'total_tokens': 111}, 'model_name': 'gpt-4o', 'system_fingerprint': 'fp_729ea513f7', 'finish_reason': 'tool_calls', 'logprobs': None} id='run-fc2e201f-6330-4330-8c4e-1a66e85c1ffa-0' tool_calls=[{'name': 'magic_function', 'args': {'input': '3'}, 'id': 'call_Fg92zoL8oS5q6im2jR1INRvH'}]\n", + "content='Sorry, there was an error. Please try again.' name='magic_function' id='a931dd6e-2ed7-42ea-a58c-5ffb4041d7c9' tool_call_id='call_Fg92zoL8oS5q6im2jR1INRvH'\n", + "content='It seems there is an issue with processing the request for the value of `magic_function(3)`. Let me try a different approach.' additional_kwargs={'tool_calls': [{'id': 'call_lbYBMptprZ6HMqNiTvoqhmwP', 'function': {'arguments': '{\"input\":\"3\"}', 'name': 'magic_function'}, 'type': 'function'}]} response_metadata={'token_usage': {'completion_tokens': 43, 'prompt_tokens': 130, 'total_tokens': 173}, 'model_name': 'gpt-4o', 'system_fingerprint': 'fp_729ea513f7', 'finish_reason': 'tool_calls', 'logprobs': None} id='run-2e0baab0-c4c1-42e8-b49d-a2704ae977c0-0' tool_calls=[{'name': 'magic_function', 'args': {'input': '3'}, 'id': 'call_lbYBMptprZ6HMqNiTvoqhmwP'}]\n", + "content='Sorry, there was an error. Please try again.' name='magic_function' id='9957435a-5de3-4662-b23c-abfa31e71208' tool_call_id='call_lbYBMptprZ6HMqNiTvoqhmwP'\n", + "content='It appears that the `magic_function` is currently experiencing issues when attempting to process the input \"3\". Unfortunately, I can\\'t provide the value of `magic_function(3)` at this moment.\\n\\nIf you have any other questions or need assistance with something else, please let me know!' response_metadata={'token_usage': {'completion_tokens': 58, 'prompt_tokens': 195, 'total_tokens': 253}, 'model_name': 'gpt-4o', 'system_fingerprint': 'fp_729ea513f7', 'finish_reason': 'stop', 'logprobs': None} id='run-bb68d7ca-da76-43ad-80ab-23737a70c391-0'\n", "{'input': 'what is the value of magic_function(3)?', 'output': 'Agent stopped due to max iterations.'}\n" ] } ], "source": [ - "from langgraph.pregel import GraphRecursionError\n", + "from langgraph.errors import GraphRecursionError\n", + "from langgraph.prebuilt import create_react_agent\n", "\n", "RECURSION_LIMIT = 2 * 3 + 1\n", "\n", - "app = chat_agent_executor.create_tool_calling_executor(model, tools)\n", + "app = create_react_agent(model, tools=tools)\n", "\n", "try:\n", " for chunk in app.stream(\n", - " {\"messages\": [(\"human\", query)]}, {\"recursion_limit\": RECURSION_LIMIT}\n", + " {\"messages\": [(\"human\", query)]},\n", + " {\"recursion_limit\": RECURSION_LIMIT},\n", + " stream_mode=\"values\",\n", " ):\n", - " print(chunk)\n", - " print(\"------\")\n", + " print(chunk[\"messages\"][-1])\n", "except GraphRecursionError:\n", " print({\"input\": query, \"output\": \"Agent stopped due to max iterations.\"})" ] @@ -513,7 +522,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 30, "id": "4b8498fc-a7af-4164-a401-d8714f082306", "metadata": {}, "outputs": [ @@ -540,7 +549,7 @@ " 'output': 'Agent stopped due to max iterations.'}" ] }, - "execution_count": 17, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -569,9 +578,19 @@ "agent_executor.invoke({\"input\": query})" ] }, + { + "cell_type": "markdown", + "id": "d02eb025", + "metadata": {}, + "source": [ + "With LangGraph's react agent, you can control timeouts on two levels. \n", + "\n", + "You can set a `step_timeout` to bound each **step**:" + ] + }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 31, "id": "a2b29113-e6be-4f91-aa4c-5c63dea3e423", "metadata": {}, "outputs": [ @@ -579,14 +598,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_lp2tuTmBpulORJr4FJp9za4E', 'function': {'arguments': '{\"input\":\"3\"}', 'name': 'magic_function'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 65, 'total_tokens': 79}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_3b956da36b', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-4070a5d8-c2ea-46f3-a3a2-dfcd2ebdadc2-0', tool_calls=[{'name': 'magic_function', 'args': {'input': '3'}, 'id': 'call_lp2tuTmBpulORJr4FJp9za4E'}])]}}\n", + "{'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_GlXWTlJ0jQc2B8jQuDVFzmnc', 'function': {'arguments': '{\"input\":\"3\"}', 'name': 'magic_function'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 64, 'total_tokens': 78}, 'model_name': 'gpt-4o', 'system_fingerprint': 'fp_729ea513f7', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-38a0459b-a363-4181-b7a3-f25cb5c5d728-0', tool_calls=[{'name': 'magic_function', 'args': {'input': '3'}, 'id': 'call_GlXWTlJ0jQc2B8jQuDVFzmnc'}])]}}\n", "------\n", "{'input': 'what is the value of magic_function(3)?', 'output': 'Agent stopped due to max iterations.'}\n" ] } ], "source": [ - "app = chat_agent_executor.create_tool_calling_executor(model, tools)\n", + "from langgraph.prebuilt import create_react_agent\n", + "\n", + "app = create_react_agent(model, tools=tools)\n", "# Set the max timeout for each step here\n", "app.step_timeout = 2\n", "\n", @@ -598,13 +619,52 @@ " print({\"input\": query, \"output\": \"Agent stopped due to max iterations.\"})" ] }, + { + "cell_type": "markdown", + "id": "32a9db70", + "metadata": {}, + "source": [ + "The other way to set a max timeout is just via python's stdlib [asyncio](https://docs.python.org/3/library/asyncio.html)." + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 34, "id": "e9eb55f4-a321-4bac-b52d-9e43b411cf92", "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_cR1oJuYcNrOmcaaIRRvh5dSr', 'function': {'arguments': '{\"input\":\"3\"}', 'name': 'magic_function'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 64, 'total_tokens': 78}, 'model_name': 'gpt-4o', 'system_fingerprint': 'fp_729ea513f7', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-1c03c5d6-4883-4ccd-aa78-53dbafa99622-0', tool_calls=[{'name': 'magic_function', 'args': {'input': '3'}, 'id': 'call_cR1oJuYcNrOmcaaIRRvh5dSr'}])]}}\n", + "------\n", + "{'action': {'messages': [ToolMessage(content='Sorry, there was an error. Please try again.', name='magic_function', id='596baf13-de35-4a4f-8b78-475b387a1f40', tool_call_id='call_cR1oJuYcNrOmcaaIRRvh5dSr')]}}\n", + "------\n", + "{'input': 'what is the value of magic_function(3)?', 'output': 'Task Cancelled.'}\n" + ] + } + ], + "source": [ + "import asyncio\n", + "\n", + "from langgraph.prebuilt import create_react_agent\n", + "\n", + "app = create_react_agent(model, tools=tools)\n", + "\n", + "\n", + "async def stream(app, inputs):\n", + " async for chunk in app.astream({\"messages\": [(\"human\", query)]}):\n", + " print(chunk)\n", + " print(\"------\")\n", + "\n", + "\n", + "try:\n", + " task = asyncio.create_task(stream(app, {\"messages\": [(\"human\", query)]}))\n", + " await asyncio.wait_for(task, timeout=3)\n", + "except TimeoutError:\n", + " print(\"Task Cancelled.\")" + ] } ], "metadata": { @@ -623,7 +683,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.1" + "version": "3.11.2" } }, "nbformat": 4,