From 6a07147a749cadef6119c66e55eb42717f1e4158 Mon Sep 17 00:00:00 2001 From: bracesproul Date: Mon, 19 Aug 2024 13:17:32 -0700 Subject: [PATCH] finished porting --- .../base.ipynb | 416 ++++++++---------- 1 file changed, 179 insertions(+), 237 deletions(-) diff --git a/examples/chat_agent_executor_with_function_calling/base.ipynb b/examples/chat_agent_executor_with_function_calling/base.ipynb index 9a448e2b0..e40e5d8fb 100644 --- a/examples/chat_agent_executor_with_function_calling/base.ipynb +++ b/examples/chat_agent_executor_with_function_calling/base.ipynb @@ -61,65 +61,25 @@ "source": [ "## Set up the tools\n", "\n", - "We will first define the tools we want to use. For this simple example, we will\n", - "use a built-in search tool via Tavily. However, it is really easy to create your\n", - "own tools - see documentation\n", - "[here](https://js.langchain.com/docs/modules/agents/tools/dynamic) on how to do\n", - "that." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "c60720fd", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[Module: null prototype] { default: {} }" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import \"dotenv/config\";" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "d7ef57dd-5d6e-4ad3-9377-a92201c1310e", - "metadata": {}, - "outputs": [], - "source": [ - "import { TavilySearchResults } from \"@langchain/community/tools/tavily_search\";\n", + "We will first define the tools we want to use. For this simple example, we will use a built-in search tool via Tavily. However, it is really easy to create your own tools - see documentation [here](https://js.langchain.com/docs/how_to/custom_tools/) on how to do that.\n", "\n", - "const tools = [new TavilySearchResults({ maxResults: 1 })];" - ] - }, - { - "cell_type": "markdown", - "id": "01885785-b71a-44d1-b1d6-7b5b14d53b58", - "metadata": {}, - "source": [ - "We can now wrap these tools in a simple ToolExecutor. This is a real simple\n", - "class that takes in a ToolInvocation and calls that tool, returning the output.\n", + "After defining our tools, we can wrap them in a simple `ToolExecutor`. This is a real simple\n", + "class that takes in a `ToolInvocation` and calls that tool, returning the output.\n", "\n", "A ToolInvocation is any type with `tool` and `toolInput` attribute." ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "5cf3331e-ccb3-41c8-aeb9-a840a94d41e7", "metadata": {}, "outputs": [], "source": [ "import { ToolExecutor } from \"@langchain/langgraph/prebuilt\";\n", + "import { TavilySearchResults } from \"@langchain/community/tools/tavily_search\";\n", + "\n", + "const tools = [new TavilySearchResults({ maxResults: 1 })];\n", "\n", "const toolExecutor = new ToolExecutor({\n", " tools,\n", @@ -147,7 +107,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "id": "892b54b9-75f0-4804-9ed0-88b5e5532989", "metadata": {}, "outputs": [], @@ -174,7 +134,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "id": "cd3cbae5-d92c-4559-a4aa-44721b80d107", "metadata": {}, "outputs": [], @@ -204,29 +164,15 @@ "object you construct the graph with.\n", "\n", "For this example, the state we will track will just be a list of messages. We\n", - "want each node to just add messages to that list. To do this, we define our state via the `Annotation` function, with a single attribute `messages` that is a list of `BaseMessage`s. The value of our attribute `messages` is another `Annotation` which has two sub-attributes: `reducer` and `default`. The `reducer` key must be a factory that returns a function that takes the current value of the attribute and the new value to add, and returns the new value of the attribute.\n", - "\n", - "The `default` key must be a factory that returns the default value for that\n", - "attribute (this key is optional)." + "want each node to just add messages to that list. To do this, we define our state via the `Annotation` function, with a single attribute `messages` that is a list of `BaseMessage`s. The value of our attribute `messages` is another `Annotation` which has two sub-attributes: `reducer` and `default`. The `reducer` key must be a factory that returns a function that takes the current value of the attribute and the new value to add, and returns the new value of the attribute." ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 11, "id": "ea793afa-2eab-4901-910d-6eed90cd6564", "metadata": {}, - "outputs": [ - { - "ename": "TypeError", - "evalue": "Cannot read properties of undefined (reading 'Root')", - "output_type": "error", - "traceback": [ - "Stack trace:", - "TypeError: Cannot read properties of undefined (reading 'Root')", - " at :3:31" - ] - } - ], + "outputs": [], "source": [ "import { BaseMessage } from \"@langchain/core/messages\";\n", "import { Annotation } from \"@langchain/langgraph\";\n", @@ -234,7 +180,6 @@ "const AgentState = Annotation.Root({\n", " messages: Annotation({\n", " reducer: (x, y) => x.concat(y),\n", - " default: () => [],\n", " })\n", "})" ] @@ -272,7 +217,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "id": "3b541bb9-900c-40d0-964d-7b5dfee30667", "metadata": {}, "outputs": [], @@ -353,7 +298,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "813ae66c-3b58-4283-a02a-36da72a2ab90", "metadata": {}, "outputs": [], @@ -361,40 +306,36 @@ "import { END, START, StateGraph } from \"@langchain/langgraph\";\n", "\n", "// Define a new graph\n", - "const workflow = new StateGraph(AgentState);\n", - "\n", - "// Define the two nodes we will cycle between\n", - "workflow.addNode(\"agent\", callModel);\n", - "workflow.addNode(\"action\", callTool);\n", - "\n", - "// Set the entrypoint as `agent`\n", - "// This means that this node is the first one called\n", - "workflow.addEdge(START, \"agent\");\n", - "\n", - "// We now add a conditional edge\n", - "workflow.addConditionalEdges(\n", - " // First, we define the start node. We use `agent`.\n", - " // This means these are the edges taken after the `agent` node is called.\n", - " \"agent\",\n", - " // Next, we pass in the function that will determine which node is called next.\n", - " shouldContinue,\n", - " // Finally we pass in a mapping.\n", - " // The keys are strings, and the values are other nodes.\n", - " // END is a special node marking that the graph should finish.\n", - " // What will happen is we will call `should_continue`, and then the output of that\n", - " // will be matched against the keys in this mapping.\n", - " // Based on which one it matches, that node will then be called.\n", - " {\n", - " // If `tools`, then we call the tool node.\n", - " continue: \"action\",\n", - " // Otherwise we finish.\n", - " end: END,\n", - " },\n", - ");\n", - "\n", - "// We now add a normal edge from `tools` to `agent`.\n", - "// This means that after `tools` is called, `agent` node is called next.\n", - "workflow.addEdge(\"action\", \"agent\");\n", + "const workflow = new StateGraph(AgentState)\n", + " // Define the two nodes we will cycle between\n", + " .addNode(\"agent\", callModel)\n", + " .addNode(\"action\", callTool)\n", + " // Set the entrypoint as `agent`\n", + " // This means that this node is the first one called\n", + " .addEdge(START, \"agent\")\n", + " // We now add a conditional edge\n", + " .addConditionalEdges(\n", + " // First, we define the start node. We use `agent`.\n", + " // This means these are the edges taken after the `agent` node is called.\n", + " \"agent\",\n", + " // Next, we pass in the function that will determine which node is called next.\n", + " shouldContinue,\n", + " // Finally we pass in a mapping.\n", + " // The keys are strings, and the values are other nodes.\n", + " // END is a special node marking that the graph should finish.\n", + " // What will happen is we will call `should_continue`, and then the output of that\n", + " // will be matched against the keys in this mapping.\n", + " // Based on which one it matches, that node will then be called.\n", + " {\n", + " // If `tools`, then we call the tool node.\n", + " continue: \"action\",\n", + " // Otherwise we finish.\n", + " end: END,\n", + " },\n", + " )\n", + " // We now add a normal edge from `tools` to `agent`.\n", + " // This means that after `tools` is called, `agent` node is called next.\n", + " .addEdge(\"action\", \"agent\");\n", "\n", "// Finally, we compile it!\n", "// This compiles it into a LangChain Runnable,\n", @@ -416,66 +357,83 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "8edb04b9-40b6-46f1-a7a8-4b2d8aba7752", "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "{\n", - " messages: [\n", - " HumanMessage {\n", - " lc_serializable: \u001b[33mtrue\u001b[39m,\n", - " lc_kwargs: { content: \u001b[32m\"what is the weather in sf\"\u001b[39m, additional_kwargs: {} },\n", - " lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"messages\"\u001b[39m ],\n", - " content: \u001b[32m\"what is the weather in sf\"\u001b[39m,\n", - " name: \u001b[90mundefined\u001b[39m,\n", - " additional_kwargs: {}\n", - " },\n", - " AIMessageChunk {\n", - " lc_serializable: \u001b[33mtrue\u001b[39m,\n", - " lc_kwargs: { content: \u001b[32m\"\"\u001b[39m, additional_kwargs: { function_call: \u001b[36m[Object]\u001b[39m } },\n", - " lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"messages\"\u001b[39m ],\n", - " content: \u001b[32m\"\"\u001b[39m,\n", - " name: \u001b[90mundefined\u001b[39m,\n", - " additional_kwargs: {\n", - " function_call: {\n", - " name: \u001b[32m\"tavily_search_results_json\"\u001b[39m,\n", - " arguments: \u001b[32m'{\"input\":\"weather in San Francisco\"}'\u001b[39m\n", - " }\n", - " }\n", - " },\n", - " FunctionMessage {\n", - " lc_serializable: \u001b[33mtrue\u001b[39m,\n", - " lc_kwargs: {\n", - " content: \u001b[32m\"[]\"\u001b[39m,\n", - " name: \u001b[32m\"tavily_search_results_json\"\u001b[39m,\n", - " additional_kwargs: {}\n", - " },\n", - " lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"messages\"\u001b[39m ],\n", - " content: \u001b[32m\"[]\"\u001b[39m,\n", - " name: \u001b[32m\"tavily_search_results_json\"\u001b[39m,\n", - " additional_kwargs: {}\n", - " },\n", - " AIMessageChunk {\n", - " lc_serializable: \u001b[33mtrue\u001b[39m,\n", - " lc_kwargs: {\n", - " content: \u001b[32m\"I'm sorry, but I couldn't find the current weather in San Francisco. You may want to check a reliabl\"\u001b[39m... 61 more characters,\n", - " additional_kwargs: {}\n", - " },\n", - " lc_namespace: [ \u001b[32m\"langchain_core\"\u001b[39m, \u001b[32m\"messages\"\u001b[39m ],\n", - " content: \u001b[32m\"I'm sorry, but I couldn't find the current weather in San Francisco. You may want to check a reliabl\"\u001b[39m... 61 more characters,\n", - " name: \u001b[90mundefined\u001b[39m,\n", - " additional_kwargs: {}\n", - " }\n", - " ]\n", - "}" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " messages: [\n", + " HumanMessage {\n", + " \"content\": \"what is the weather in sf\",\n", + " \"additional_kwargs\": {},\n", + " \"response_metadata\": {}\n", + " },\n", + " AIMessageChunk {\n", + " \"id\": \"chatcmpl-9y3695OyrZqhRmcbVkioOxXzjXp32\",\n", + " \"content\": \"\",\n", + " \"additional_kwargs\": {\n", + " \"function_call\": {\n", + " \"name\": \"tavily_search_results_json\",\n", + " \"arguments\": \"{\\\"input\\\":\\\"weather in San Francisco\\\"}\"\n", + " }\n", + " },\n", + " \"response_metadata\": {\n", + " \"estimatedTokenUsage\": {\n", + " \"promptTokens\": 80,\n", + " \"completionTokens\": 21,\n", + " \"totalTokens\": 101\n", + " },\n", + " \"prompt\": 0,\n", + " \"completion\": 0,\n", + " \"finish_reason\": \"function_call\",\n", + " \"system_fingerprint\": null\n", + " },\n", + " \"tool_calls\": [],\n", + " \"tool_call_chunks\": [],\n", + " \"invalid_tool_calls\": [],\n", + " \"usage_metadata\": {\n", + " \"input_tokens\": 79,\n", + " \"output_tokens\": 21,\n", + " \"total_tokens\": 100\n", + " }\n", + " },\n", + " FunctionMessage {\n", + " \"content\": \"[{\\\"title\\\":\\\"Weather in San Francisco\\\",\\\"url\\\":\\\"https://www.weatherapi.com/\\\",\\\"content\\\":\\\"{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.78, 'lon': -122.42, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1724098493, 'localtime': '2024-08-19 13:14'}, 'current': {'last_updated_epoch': 1724097600, 'last_updated': '2024-08-19 13:00', 'temp_c': 21.1, 'temp_f': 70.0, 'is_day': 1, 'condition': {'text': 'Sunny', 'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png', 'code': 1000}, 'wind_mph': 9.4, 'wind_kph': 15.1, 'wind_degree': 250, 'wind_dir': 'WSW', 'pressure_mb': 1019.0, 'pressure_in': 30.08, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 64, 'cloud': 0, 'feelslike_c': 21.1, 'feelslike_f': 70.0, 'windchill_c': 17.7, 'windchill_f': 63.8, 'heatindex_c': 17.7, 'heatindex_f': 63.8, 'dewpoint_c': 10.7, 'dewpoint_f': 51.2, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 5.0, 'gust_mph': 13.2, 'gust_kph': 21.2}}\\\",\\\"score\\\":0.9991679,\\\"raw_content\\\":null}]\",\n", + " \"name\": \"tavily_search_results_json\",\n", + " \"additional_kwargs\": {},\n", + " \"response_metadata\": {}\n", + " },\n", + " AIMessageChunk {\n", + " \"id\": \"chatcmpl-9y36FtclcqetcawFZmYH7rDvajQ7A\",\n", + " \"content\": \"The current weather in San Francisco is sunny with a temperature of 70.0°F (21.1°C). The wind is blowing at 15.1 kph from the WSW direction. The humidity is at 64%, and there is no precipitation.\",\n", + " \"additional_kwargs\": {},\n", + " \"response_metadata\": {\n", + " \"estimatedTokenUsage\": {\n", + " \"promptTokens\": 536,\n", + " \"completionTokens\": 53,\n", + " \"totalTokens\": 589\n", + " },\n", + " \"prompt\": 0,\n", + " \"completion\": 0,\n", + " \"finish_reason\": \"stop\",\n", + " \"system_fingerprint\": null\n", + " },\n", + " \"tool_calls\": [],\n", + " \"tool_call_chunks\": [],\n", + " \"invalid_tool_calls\": [],\n", + " \"usage_metadata\": {\n", + " \"input_tokens\": 538,\n", + " \"output_tokens\": 54,\n", + " \"total_tokens\": 592\n", + " }\n", + " }\n", + " ]\n", + "}\n" + ] } ], "source": [ @@ -508,7 +466,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "f544977e-31f7-41f0-88c4-ec9c27b8cecb", "metadata": {}, "outputs": [ @@ -520,12 +478,33 @@ " agent: {\n", " messages: [\n", " AIMessageChunk {\n", - " lc_serializable: true,\n", - " lc_kwargs: { content: \"\", additional_kwargs: [Object] },\n", - " lc_namespace: [ \"langchain_core\", \"messages\" ],\n", - " content: \"\",\n", - " name: undefined,\n", - " additional_kwargs: { function_call: [Object] }\n", + " \"id\": \"chatcmpl-9y36G4P6hDihhZkOCW5T5bJWWNl0Z\",\n", + " \"content\": \"\",\n", + " \"additional_kwargs\": {\n", + " \"function_call\": {\n", + " \"name\": \"tavily_search_results_json\",\n", + " \"arguments\": \"{\\\"input\\\":\\\"weather in San Francisco\\\"}\"\n", + " }\n", + " },\n", + " \"response_metadata\": {\n", + " \"estimatedTokenUsage\": {\n", + " \"promptTokens\": 80,\n", + " \"completionTokens\": 21,\n", + " \"totalTokens\": 101\n", + " },\n", + " \"prompt\": 0,\n", + " \"completion\": 0,\n", + " \"finish_reason\": \"function_call\",\n", + " \"system_fingerprint\": null\n", + " },\n", + " \"tool_calls\": [],\n", + " \"tool_call_chunks\": [],\n", + " \"invalid_tool_calls\": [],\n", + " \"usage_metadata\": {\n", + " \"input_tokens\": 79,\n", + " \"output_tokens\": 21,\n", + " \"total_tokens\": 100\n", + " }\n", " }\n", " ]\n", " }\n", @@ -536,16 +515,10 @@ " action: {\n", " messages: [\n", " FunctionMessage {\n", - " lc_serializable: true,\n", - " lc_kwargs: {\n", - " content: \"[]\",\n", - " name: \"tavily_search_results_json\",\n", - " additional_kwargs: {}\n", - " },\n", - " lc_namespace: [ \"langchain_core\", \"messages\" ],\n", - " content: \"[]\",\n", - " name: \"tavily_search_results_json\",\n", - " additional_kwargs: {}\n", + " \"content\": \"[{\\\"title\\\":\\\"Weather in San Francisco\\\",\\\"url\\\":\\\"https://www.weatherapi.com/\\\",\\\"content\\\":\\\"{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.78, 'lon': -122.42, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1724098493, 'localtime': '2024-08-19 13:14'}, 'current': {'last_updated_epoch': 1724097600, 'last_updated': '2024-08-19 13:00', 'temp_c': 21.1, 'temp_f': 70.0, 'is_day': 1, 'condition': {'text': 'Sunny', 'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png', 'code': 1000}, 'wind_mph': 9.4, 'wind_kph': 15.1, 'wind_degree': 250, 'wind_dir': 'WSW', 'pressure_mb': 1019.0, 'pressure_in': 30.08, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 64, 'cloud': 0, 'feelslike_c': 21.1, 'feelslike_f': 70.0, 'windchill_c': 17.7, 'windchill_f': 63.8, 'heatindex_c': 17.7, 'heatindex_f': 63.8, 'dewpoint_c': 10.7, 'dewpoint_f': 51.2, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 5.0, 'gust_mph': 13.2, 'gust_kph': 21.2}}\\\",\\\"score\\\":0.9991846,\\\"raw_content\\\":null}]\",\n", + " \"name\": \"tavily_search_results_json\",\n", + " \"additional_kwargs\": {},\n", + " \"response_metadata\": {}\n", " }\n", " ]\n", " }\n", @@ -556,62 +529,28 @@ " agent: {\n", " messages: [\n", " AIMessageChunk {\n", - " lc_serializable: true,\n", - " lc_kwargs: {\n", - " content: \"I couldn't find the current weather in San Francisco. You may want to check a reliable weather websi\"... 46 more characters,\n", - " additional_kwargs: {}\n", - " },\n", - " lc_namespace: [ \"langchain_core\", \"messages\" ],\n", - " content: \"I couldn't find the current weather in San Francisco. You may want to check a reliable weather websi\"... 46 more characters,\n", - " name: undefined,\n", - " additional_kwargs: {}\n", - " }\n", - " ]\n", - " }\n", - "}\n", - "-----\n", - "\n", - "output {\n", - " __end__: {\n", - " messages: [\n", - " HumanMessage {\n", - " lc_serializable: true,\n", - " lc_kwargs: { content: \"what is the weather in sf\", additional_kwargs: {} },\n", - " lc_namespace: [ \"langchain_core\", \"messages\" ],\n", - " content: \"what is the weather in sf\",\n", - " name: undefined,\n", - " additional_kwargs: {}\n", - " },\n", - " AIMessageChunk {\n", - " lc_serializable: true,\n", - " lc_kwargs: { content: \"\", additional_kwargs: [Object] },\n", - " lc_namespace: [ \"langchain_core\", \"messages\" ],\n", - " content: \"\",\n", - " name: undefined,\n", - " additional_kwargs: { function_call: [Object] }\n", - " },\n", - " FunctionMessage {\n", - " lc_serializable: true,\n", - " lc_kwargs: {\n", - " content: \"[]\",\n", - " name: \"tavily_search_results_json\",\n", - " additional_kwargs: {}\n", - " },\n", - " lc_namespace: [ \"langchain_core\", \"messages\" ],\n", - " content: \"[]\",\n", - " name: \"tavily_search_results_json\",\n", - " additional_kwargs: {}\n", - " },\n", - " AIMessageChunk {\n", - " lc_serializable: true,\n", - " lc_kwargs: {\n", - " content: \"I couldn't find the current weather in San Francisco. You may want to check a reliable weather websi\"... 46 more characters,\n", - " additional_kwargs: {}\n", + " \"id\": \"chatcmpl-9y36KCh1ZZbMNXVbLxTzz8jZb4t4T\",\n", + " \"content\": \"The current weather in San Francisco is sunny with a temperature of 70.0°F (21.1°C). The wind is blowing at 15.1 kph from the WSW direction. The humidity is at 64% and there is no precipitation.\",\n", + " \"additional_kwargs\": {},\n", + " \"response_metadata\": {\n", + " \"estimatedTokenUsage\": {\n", + " \"promptTokens\": 536,\n", + " \"completionTokens\": 53,\n", + " \"totalTokens\": 589\n", + " },\n", + " \"prompt\": 0,\n", + " \"completion\": 0,\n", + " \"finish_reason\": \"stop\",\n", + " \"system_fingerprint\": null\n", " },\n", - " lc_namespace: [ \"langchain_core\", \"messages\" ],\n", - " content: \"I couldn't find the current weather in San Francisco. You may want to check a reliable weather websi\"... 46 more characters,\n", - " name: undefined,\n", - " additional_kwargs: {}\n", + " \"tool_calls\": [],\n", + " \"tool_call_chunks\": [],\n", + " \"invalid_tool_calls\": [],\n", + " \"usage_metadata\": {\n", + " \"input_tokens\": 538,\n", + " \"output_tokens\": 54,\n", + " \"total_tokens\": 592\n", + " }\n", " }\n", " ]\n", " }\n", @@ -634,17 +573,20 @@ ], "metadata": { "kernelspec": { - "display_name": "Deno", + "display_name": "TypeScript", "language": "typescript", - "name": "deno" + "name": "tslab" }, "language_info": { + "codemirror_mode": { + "mode": "typescript", + "name": "javascript", + "typescript": true + }, "file_extension": ".ts", - "mimetype": "text/x.typescript", + "mimetype": "text/typescript", "name": "typescript", - "nb_converter": "script", - "pygments_lexer": "typescript", - "version": "5.3.3" + "version": "3.7.2" } }, "nbformat": 4,