From e5672bc94445c79a01cd4793b8436cd777154d42 Mon Sep 17 00:00:00 2001 From: Eugene Yurtsev Date: Mon, 22 Jan 2024 20:28:31 -0500 Subject: [PATCH] docs: Re-write custom agent to show to write a tools agent (#15907) Shows how to write a tools agent rather than a functions agent. --- .../modules/agents/how_to/custom_agent.ipynb | 105 +++++++++++------- 1 file changed, 63 insertions(+), 42 deletions(-) diff --git a/docs/docs/modules/agents/how_to/custom_agent.ipynb b/docs/docs/modules/agents/how_to/custom_agent.ipynb index 665db61683..2bd19eba28 100644 --- a/docs/docs/modules/agents/how_to/custom_agent.ipynb +++ b/docs/docs/modules/agents/how_to/custom_agent.ipynb @@ -19,7 +19,7 @@ "\n", "This notebook goes through how to create your own custom agent.\n", "\n", - "In this example, we will use OpenAI Function Calling to create this agent.\n", + "In this example, we will use OpenAI Tool Calling to create this agent.\n", "**This is generally the most reliable way to create agents.**\n", "\n", "We will first create it WITHOUT memory, but we will then show how to add memory in.\n", @@ -61,10 +61,21 @@ }, { "cell_type": "code", - "execution_count": 5, - "id": "fbe32b5f", + "execution_count": 2, + "id": "490bab35-adbb-4b45-8d0d-232414121e97", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from langchain.agents import tool\n", "\n", @@ -75,6 +86,16 @@ " return len(word)\n", "\n", "\n", + "get_word_length.invoke(\"abc\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "c9821fb3-4449-49a0-a708-88a18d39e068", + "metadata": {}, + "outputs": [], + "source": [ "tools = [get_word_length]" ] }, @@ -91,7 +112,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 4, "id": "aa4b50ea", "metadata": {}, "outputs": [], @@ -116,22 +137,24 @@ "metadata": {}, "source": [ "## Bind tools to LLM\n", - "How does the agent know what tools it can use?\n", - "In this case we're relying on OpenAI function calling LLMs, which take functions as a separate argument and have been specifically trained to know when to invoke those functions.\n", "\n", - "To pass in our tools to the agent, we just need to format them to the [OpenAI function format](https://openai.com/blog/function-calling-and-other-api-updates) and pass them to our model. (By `bind`-ing the functions, we're making sure that they're passed in each time the model is invoked.)" + "How does the agent know what tools it can use?\n", + "\n", + "In this case we're relying on OpenAI tool calling LLMs, which take tools as a separate argument and have been specifically trained to know when to invoke those tools.\n", + "\n", + "To pass in our tools to the agent, we just need to format them to the [OpenAI tool format](https://platform.openai.com/docs/api-reference/chat/create) and pass them to our model. (By `bind`-ing the functions, we're making sure that they're passed in each time the model is invoked.)" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "id": "e82713b6", "metadata": {}, "outputs": [], "source": [ - "from langchain_community.tools.convert_to_openai import format_tool_to_openai_function\n", + "from langchain_community.tools.convert_to_openai import format_tool_to_openai_tool\n", "\n", - "llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools])" + "llm_with_tools = llm.bind(tools=[format_tool_to_openai_tool(tool) for tool in tools])" ] }, { @@ -146,30 +169,32 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "id": "925a8ca4", "metadata": {}, "outputs": [], "source": [ - "from langchain.agents.format_scratchpad import format_to_openai_function_messages\n", - "from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser\n", + "from langchain.agents.format_scratchpad.openai_tools import (\n", + " format_to_openai_tool_messages,\n", + ")\n", + "from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser\n", "\n", "agent = (\n", " {\n", " \"input\": lambda x: x[\"input\"],\n", - " \"agent_scratchpad\": lambda x: format_to_openai_function_messages(\n", + " \"agent_scratchpad\": lambda x: format_to_openai_tool_messages(\n", " x[\"intermediate_steps\"]\n", " ),\n", " }\n", " | prompt\n", " | llm_with_tools\n", - " | OpenAIFunctionsAgentOutputParser()\n", + " | OpenAIToolsAgentOutputParser()\n", ")" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "id": "9af9734e", "metadata": {}, "outputs": [], @@ -181,7 +206,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 8, "id": "653b1617", "metadata": {}, "outputs": [ @@ -193,10 +218,10 @@ "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `get_word_length` with `{'word': 'educa'}`\n", + "Invoking: `get_word_length` with `{'word': 'eudca'}`\n", "\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m5\u001b[0m\u001b[32;1m\u001b[1;3mThere are 5 letters in the word \"educa\".\u001b[0m\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m5\u001b[0m\u001b[32;1m\u001b[1;3mThere are 5 letters in the word \"eudca\".\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n" ] @@ -204,17 +229,21 @@ { "data": { "text/plain": [ - "{'input': 'How many letters in the word educa',\n", - " 'output': 'There are 5 letters in the word \"educa\".'}" + "[{'actions': [OpenAIToolAgentAction(tool='get_word_length', tool_input={'word': 'eudca'}, log=\"\\nInvoking: `get_word_length` with `{'word': 'eudca'}`\\n\\n\\n\", message_log=[AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_U9SR78eT398r9UbzID2N9LXh', 'function': {'arguments': '{\\n \"word\": \"eudca\"\\n}', 'name': 'get_word_length'}, 'type': 'function'}]})], tool_call_id='call_U9SR78eT398r9UbzID2N9LXh')],\n", + " 'messages': [AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_U9SR78eT398r9UbzID2N9LXh', 'function': {'arguments': '{\\n \"word\": \"eudca\"\\n}', 'name': 'get_word_length'}, 'type': 'function'}]})]},\n", + " {'steps': [AgentStep(action=OpenAIToolAgentAction(tool='get_word_length', tool_input={'word': 'eudca'}, log=\"\\nInvoking: `get_word_length` with `{'word': 'eudca'}`\\n\\n\\n\", message_log=[AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_U9SR78eT398r9UbzID2N9LXh', 'function': {'arguments': '{\\n \"word\": \"eudca\"\\n}', 'name': 'get_word_length'}, 'type': 'function'}]})], tool_call_id='call_U9SR78eT398r9UbzID2N9LXh'), observation=5)],\n", + " 'messages': [FunctionMessage(content='5', name='get_word_length')]},\n", + " {'output': 'There are 5 letters in the word \"eudca\".',\n", + " 'messages': [AIMessage(content='There are 5 letters in the word \"eudca\".')]}]" ] }, - "execution_count": 14, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "agent_executor.invoke({\"input\": \"How many letters in the word educa\"})" + "list(agent_executor.stream({\"input\": \"How many letters in the word eudca\"}))" ] }, { @@ -227,7 +256,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 9, "id": "60f5dc19", "metadata": {}, "outputs": [ @@ -237,7 +266,7 @@ "AIMessage(content='There are 6 letters in the word \"educa\".')" ] }, - "execution_count": 15, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -270,7 +299,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 10, "id": "169006d5", "metadata": {}, "outputs": [], @@ -301,7 +330,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 11, "id": "8c03f36c", "metadata": {}, "outputs": [], @@ -321,7 +350,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 12, "id": "5429d97f", "metadata": {}, "outputs": [], @@ -329,14 +358,14 @@ "agent = (\n", " {\n", " \"input\": lambda x: x[\"input\"],\n", - " \"agent_scratchpad\": lambda x: format_to_openai_function_messages(\n", + " \"agent_scratchpad\": lambda x: format_to_openai_tool_messages(\n", " x[\"intermediate_steps\"]\n", " ),\n", " \"chat_history\": lambda x: x[\"chat_history\"],\n", " }\n", " | prompt\n", " | llm_with_tools\n", - " | OpenAIFunctionsAgentOutputParser()\n", + " | OpenAIToolsAgentOutputParser()\n", ")\n", "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)" ] @@ -351,7 +380,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 13, "id": "9d9da346", "metadata": {}, "outputs": [ @@ -386,7 +415,7 @@ " 'output': 'No, \"educa\" is not a real word in English.'}" ] }, - "execution_count": 19, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -402,14 +431,6 @@ ")\n", "agent_executor.invoke({\"input\": \"is that a real word?\", \"chat_history\": chat_history})" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f21bcd99", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -428,7 +449,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.1" + "version": "3.11.4" }, "vscode": { "interpreter": {