diff --git a/README.md b/README.md index 96f70c7db..1a9be5d3c 100644 --- a/README.md +++ b/README.md @@ -454,18 +454,6 @@ We also have a lot of examples highlighting how to slightly modify the base chat - [Force calling a tool first](https://github.com/langchain-ai/langgraph/blob/main/examples/agent_executor/force-calling-a-tool-first.ipynb): How to always call a specific tool first - [Managing agent steps](https://github.com/langchain-ai/langgraph/blob/main/examples/agent_executor/managing-agent-steps.ipynb): How to more explicitly manage intermediate steps that an agent takes -### Multi-agent Examples - -- [Multi-agent collaboration](https://github.com/langchain-ai/langgraph/blob/main/examples/multi_agent/multi-agent-collaboration.ipynb): how to create two agents that work together to accomplish a task -- [Multi-agent with supervisor](https://github.com/langchain-ai/langgraph/blob/main/examples/multi_agent/agent_supervisor.ipynb): how to orchestrate individual agents by using an LLM as a "supervisor" to distribute work -- [Hierarchical agent teams](https://github.com/langchain-ai/langgraph/blob/main/examples/multi_agent/hierarchical_agent_teams.ipynb): how to orchestrate "teams" of agents as nested graphs that can collaborate to solve a problem - -### Chatbot Evaluation via Simulation - -It can often be tough to evaluation chat bots in multi-turn situations. One way to do this is with simulations. - -- [Chat bot evaluation as multi-agent simulation](https://github.com/langchain-ai/langgraph/blob/main/examples/chatbot-simulation-evaluation/agent-simulation-evaluation.ipynb): How to simulate a dialogue between a "virtual user" and your chat bot - ### Async If you are running LangGraph in async workflows, you may want to create the nodes to be async by default. @@ -486,6 +474,32 @@ For a walkthrough on how to do that, see [this documentation](https://github.com LangGraph comes with built-in support for human-in-the-loop workflows. This is useful when you want to have a human review the current state before proceeding to a particular node. For a walkthrough on how to do that, see [this documentation](https://github.com/langchain-ai/langgraph/blob/main/examples/human-in-the-loop.ipynb) + +### Planning Agent Examples + +The following notebooks implement agent architectures prototypical of the "plan-and-execute" style, where an LLM planner decomposes a user request into a program, an executor executes the program, and an LLM synthesizes a response (and/or dynamically replans) based on the program outputs. + +- [Plan-and-execute](https://github.com/langchain-ai/langgraph/blob/main/examples/plan-and-execute/plan-and-execute.ipynb): a simple agent with a **planner** that generates a multi-step task list, an **executor** that invokes the tools in the plan, and a **replanner** that responds or generates an updated plan. Based on the [Plan-and-solve](https://arxiv.org/abs/2305.04091) paper by Wang, et. al. +- [Reasoning without Observation](https://github.com/langchain-ai/langgraph/blob/main/examples/rewoo/rewoo.ipynb): planner generates a task list whose observations are saved as **variables**. Variables can be used in subsequent tasks to reduce the need for further re-planning. Based on the [ReWOO](https://arxiv.org/abs/2305.18323) paper by Xu, et. al. +- [LLMCompiler](https://github.com/langchain-ai/langgraph/blob/main/examples/llm-compiler/LLMCompiler.ipynb): planner generates a **DAG** of tasks with variable responses. Tasks are **streamed** and executed eagerly to minimize tool execution runtime. Based on the [paper](https://arxiv.org/abs/2312.04511) by Kim, et. al. + + +### Multi-agent Examples + +- [Multi-agent collaboration](https://github.com/langchain-ai/langgraph/blob/main/examples/multi_agent/multi-agent-collaboration.ipynb): how to create two agents that work together to accomplish a task +- [Multi-agent with supervisor](https://github.com/langchain-ai/langgraph/blob/main/examples/multi_agent/agent_supervisor.ipynb): how to orchestrate individual agents by using an LLM as a "supervisor" to distribute work +- [Hierarchical agent teams](https://github.com/langchain-ai/langgraph/blob/main/examples/multi_agent/hierarchical_agent_teams.ipynb): how to orchestrate "teams" of agents as nested graphs that can collaborate to solve a problem + +### Chatbot Evaluation via Simulation + +It can often be tough to evaluation chat bots in multi-turn situations. One way to do this is with simulations. + +- [Chat bot evaluation as multi-agent simulation](https://github.com/langchain-ai/langgraph/blob/main/examples/chatbot-simulation-evaluation/agent-simulation-evaluation.ipynb): how to simulate a dialogue between a "virtual user" and your chat bot + +### Multimodal Examples + +- [WebVoyager](https://github.com/langchain-ai/langgraph/blob/main/examples/web-navigation/web_voyager.ipynb): vision-enabled web browsing agent that uses [Set-of-marks](https://som-gpt4v.github.io/) prompting to navigate a web browser and execute tasks + ## Documentation There are only a few new APIs to use. diff --git a/examples/llm-compiler/LLMCompiler.ipynb b/examples/llm-compiler/LLMCompiler.ipynb index ba4fb12a2..3aedf4aea 100644 --- a/examples/llm-compiler/LLMCompiler.ipynb +++ b/examples/llm-compiler/LLMCompiler.ipynb @@ -9,13 +9,14 @@ "\n", "This notebook shows how to implement [LLMCompiler, by Kim, et. al](https://arxiv.org/abs/2312.04511) in LangGraph.\n", "\n", - "LLMCompiler is an agent architecture intented on speeding up the latency of agentic tasks via fast, parallel tool execution. It has 3 main components:\n", + "![LLMCompiler Graph](./img/llm-compiler.png)\n", "\n", - "1. Planner: generate a DAG of tasks.\n", - "2. Task Fetching Unit: schedules and executes the tasks\n", + "LLMCompiler is an agent architecture designed to speed up the execution of agentic tasks by eagerly-executed tasks within a DAG. It has 3 main components:\n", + "\n", + "1. Planner: stream a DAG of tasks.\n", + "2. Task Fetching Unit: schedules and executes the tasks as soon as they are executable\n", "3. Joiner: Responds to the user or triggers a second plan\n", "\n", - "![diagram](./img/diagram.png)\n", "\n", "This notebook walks through each component and shows how to wire them together using LangGraph. \n", "\n", @@ -299,7 +300,10 @@ "}\n", "```\n", "\n", - "The basic idea is to begin executing tools as soon as their dependencies are met. This is done through multi-threading." + "\n", + "The basic idea is to begin executing tools as soon as their dependencies are met. This is done through multi-threading. We will combine the task fetching unit and exector below:\n", + "\n", + "![diagram](./img/diagram.png)" ] }, { diff --git a/examples/llm-compiler/img/llm-compiler.png b/examples/llm-compiler/img/llm-compiler.png new file mode 100644 index 000000000..3c9ec7a57 Binary files /dev/null and b/examples/llm-compiler/img/llm-compiler.png differ diff --git a/examples/plan-and-execute/img/plan-and-execute.png b/examples/plan-and-execute/img/plan-and-execute.png new file mode 100644 index 000000000..829f2aee8 Binary files /dev/null and b/examples/plan-and-execute/img/plan-and-execute.png differ diff --git a/examples/plan-and-execute/plan-and-execute.ipynb b/examples/plan-and-execute/plan-and-execute.ipynb index d191a20c5..05fe873de 100644 --- a/examples/plan-and-execute/plan-and-execute.ipynb +++ b/examples/plan-and-execute/plan-and-execute.ipynb @@ -12,6 +12,10 @@ "The core idea is to first come up with a multi-step plan, and then go through that plan one item at a time.\n", "After accomplishing a particular task, you can then revisit the plan and modify as appropriate.\n", "\n", + "\n", + "![plan-and-execute diagram](./img/plan-and-execute.png)\n", + "\n", + "\n", "This compares to a typical [ReAct](https://arxiv.org/abs/2210.03629) style agent where you think one step at a time.\n", "The advantages of this \"plan-and-execute\" style agent are:\n", "\n", @@ -454,12 +458,14 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "8c20341e-267d-4ba0-9a0b-dad055a76b1d", + "cell_type": "markdown", + "id": "8bf585a9-0f1e-4910-bd00-65e7bb05b6e6", "metadata": {}, - "outputs": [], - "source": [] + "source": [ + "## Conclusion\n", + "\n", + "Congrats on making a plan-and-execute agent! One known limitations of the above design is that each task is still executed in sequence, meaning embarassingly parallel operations all add to the total execution time. You could improve on this by having each task represented as a DAG (similar to LLMCompiler), rather than a regular list." + ] }, { "cell_type": "code", @@ -486,7 +492,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.1" + "version": "3.11.2" } }, "nbformat": 4, diff --git a/examples/rewoo/img/rewoo-paper-workflow.png b/examples/rewoo/img/rewoo-paper-workflow.png new file mode 100644 index 000000000..cdfc7261f Binary files /dev/null and b/examples/rewoo/img/rewoo-paper-workflow.png differ diff --git a/examples/rewoo/img/rewoo.png b/examples/rewoo/img/rewoo.png new file mode 100644 index 000000000..48af25d57 Binary files /dev/null and b/examples/rewoo/img/rewoo.png differ diff --git a/examples/rewoo/rewoo.ipynb b/examples/rewoo/rewoo.ipynb new file mode 100644 index 000000000..5e90bb7fd --- /dev/null +++ b/examples/rewoo/rewoo.ipynb @@ -0,0 +1,484 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "1c161710-fc66-426f-8c96-28440b9c9626", + "metadata": {}, + "source": [ + "# Reasoning without Observation\n", + "\n", + "In [ReWOO](https://arxiv.org/abs/2305.18323), Xu, et. al, propose an agent that combines a multi-step planner and variable substitution for effective tool use. It was designed to improve on the ReACT-style agent architecture in the following ways:\n", + "\n", + "1. Reduce token consumption and execution time by generating the full chain of tools used in a single pass. (_ReACT-style agent architecture requires many LLM calls with redundant prefixes (since the system prompt and previous steps are provided to the LLM for each reasoning step_)\n", + "2. Simplify the fine-tuning process. Since the planning data doesn't depend on the outputs of the tool, models can be fine-tuned without actually invoking the tools (in theory).\n", + "\n", + "\n", + "![ReWoo Diagram](./img/rewoo.png)\n", + "\n", + "ReWOO is made of 3 modules:\n", + "\n", + "1. 🧠**Planner**: Generate the plan in the following format:\n", + "```text\n", + "Plan: \n", + "#E1 = Tool[argument for tool]\n", + "Plan: \n", + "#E2 = Tool[argument for tool with #E1 variable substitution]\n", + "...\n", + "```\n", + "3. **Worker**: executes the tool with the provided arguments.\n", + "4. 🧠**Solver**: generates the answer for the initial task based on the tool observations.\n", + "\n", + "The modules with a 🧠 emoji depend on an LLM call. Notice that we avoid redundant calls to the planner LLM by using variable substitution.\n", + "\n", + "In this example, each module is represented by a LangGraph node. Let's get started!\n", + "\n", + "## 0. Prerequisites\n", + "\n", + "For this example, we will provide the agent with a Tavily search engine tool. You can get an API key [here](https://app.tavily.com/sign-in) or replace with a free tool option (e.g., [duck duck go search](https://python.langchain.com/docs/integrations/tools/ddg)).\n", + "\n", + "To see the full langsmith trace, you can s" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "7f52bded-9d23-4826-8bfc-20b0d3a51182", + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install -U langgraph langchain_community langchain_openai tavily-python" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "4215f9fb-71ff-4d88-8484-f73174db5592", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import getpass\n", + "\n", + "\n", + "def _set_if_undefined(var: str):\n", + " if not os.environ.get(var):\n", + " os.environ[var] = getpass.getpass(f\"{var}=\")\n", + "\n", + "\n", + "os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n", + "os.environ[\"LANGCHAIN_PROJECT\"] = \"ReWOO\"\n", + "_set_if_undefined(\"TAVILY_API_KEY\")\n", + "_set_if_undefined(\"LANGCHAIN_API_KEY\")\n", + "_set_if_undefined(\"OPENAI_API_KEY\")" + ] + }, + { + "cell_type": "markdown", + "id": "55239a14-a14d-4117-adb5-07199e1e5e16", + "metadata": {}, + "source": [ + "**Graph State**: In LangGraph, every node updates a shared graph state. The state is the input to any node whenever it is invoked.\n", + "\n", + "Below, we will define a state dict to contain the task, plan, steps, and other variables." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9a92c875-c20b-4b7e-9d88-61c62382f8e2", + "metadata": {}, + "outputs": [], + "source": [ + "from typing import TypedDict, List\n", + "\n", + "\n", + "class ReWOO(TypedDict):\n", + " task: str\n", + " plan_string: str\n", + " steps: List\n", + " results: dict\n", + " result: str" + ] + }, + { + "cell_type": "markdown", + "id": "997f9181-41c0-4c44-937d-94bd3946a929", + "metadata": {}, + "source": [ + "## 1. Planner\n", + "\n", + "The planner prompts an LLM to generate a plan in the form of a task list. The arguments to each task are strings that may contain special variables (`#E{0-9}+`) that are used for variable subtitution from other task results.\n", + "\n", + "\n", + "![ReWOO workflow](./img/rewoo-paper-workflow.png)\n", + "\n", + "Our example agent will have two tools: \n", + "1. Google - a search engine (in this case Tavily)\n", + "2. LLM - an LLM call to reason about previous outputs.\n", + "\n", + "The LLM tool receives less of the prompt context and so can be more token-efficient than the ReACT paradigm." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c8836921-c89e-42b6-8c71-27aeaeac5368", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_openai import ChatOpenAI\n", + "\n", + "model = ChatOpenAI(temperature=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "7e7faa92-30a1-4942-b3c7-acd3a7bfccbc", + "metadata": {}, + "outputs": [], + "source": [ + "prompt = \"\"\"For the following task, make plans that can solve the problem step by step. For each plan, indicate \\\n", + "which external tool together with tool input to retrieve evidence. You can store the evidence into a \\\n", + "variable #E that can be called by later tools. (Plan, #E1, Plan, #E2, Plan, ...)\n", + "\n", + "Tools can be one of the following:\n", + "(1) Google[input]: Worker that searches results from Google. Useful when you need to find short\n", + "and succinct answers about a specific topic. The input should be a search query.\n", + "(2) LLM[input]: A pretrained LLM like yourself. Useful when you need to act with general\n", + "world knowledge and common sense. Prioritize it when you are confident in solving the problem\n", + "yourself. Input can be any instruction.\n", + "\n", + "For example,\n", + "Task: Thomas, Toby, and Rebecca worked a total of 157 hours in one week. Thomas worked x\n", + "hours. Toby worked 10 hours less than twice what Thomas worked, and Rebecca worked 8 hours\n", + "less than Toby. How many hours did Rebecca work?\n", + "Plan: Given Thomas worked x hours, translate the problem into algebraic expressions and solve\n", + "with Wolfram Alpha. #E1 = WolframAlpha[Solve x + (2x − 10) + ((2x − 10) − 8) = 157]\n", + "Plan: Find out the number of hours Thomas worked. #E2 = LLM[What is x, given #E1]\n", + "Plan: Calculate the number of hours Rebecca worked. #E3 = Calculator[(2 ∗ #E2 − 10) − 8]\n", + "\n", + "Begin! \n", + "Describe your plans with rich details. Each Plan should be followed by only one #E.\n", + "\n", + "Task: {task}\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "72b4ab0f-7215-4f4b-9407-0ebad8b13b92", + "metadata": {}, + "outputs": [], + "source": [ + "task = \"what is the hometown of the 2024 australian open winner\"" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "56ecb45b-ea76-4303-a4f3-51406fe8312a", + "metadata": {}, + "outputs": [], + "source": [ + "result = model.invoke(prompt.format(task=task))" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "8a733caa-d75b-422c-93aa-6ad913c995f3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Plan: Use Google to search for the 2024 Australian Open winner.\n", + "#E1 = Google[2024 Australian Open winner]\n", + "\n", + "Plan: Retrieve the name of the 2024 Australian Open winner from the search results.\n", + "#E2 = LLM[What is the name of the 2024 Australian Open winner, given #E1]\n", + "\n", + "Plan: Use Google to search for the hometown of the 2024 Australian Open winner.\n", + "#E3 = Google[hometown of 2024 Australian Open winner, given #E2]\n", + "\n", + "Plan: Retrieve the hometown of the 2024 Australian Open winner from the search results.\n", + "#E4 = LLM[What is the hometown of the 2024 Australian Open winner, given #E3]\n" + ] + } + ], + "source": [ + "print(result.content)" + ] + }, + { + "cell_type": "markdown", + "id": "37166985-5bec-4615-bd40-54d16fd7b4ea", + "metadata": {}, + "source": [ + "#### Planner Node\n", + "\n", + "To connect the planner to our graph, we will create a `get_plan` node that accepts the `ReWOO` state and returns with a state update for the\n", + "`steps` and `plan_string` fields." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "f9f042b6-90d8-430f-abf3-04ad2bb047c7", + "metadata": {}, + "outputs": [], + "source": [ + "import re\n", + "from langchain_core.prompts import ChatPromptTemplate\n", + "\n", + "# Regex to match expressions of the form E#... = ...[...]\n", + "regex_pattern = r\"Plan:\\s*(.+)\\s*(#E\\d+)\\s*=\\s*(\\w+)\\s*\\[([^\\]]+)\\]\"\n", + "prompt_template = ChatPromptTemplate.from_messages([(\"user\", prompt)])\n", + "planner = prompt_template | model\n", + "\n", + "\n", + "def get_plan(state: ReWOO):\n", + " task = state[\"task\"]\n", + " result = planner.invoke({\"task\": task})\n", + " # Find all matches in the sample text\n", + " matches = re.findall(regex_pattern, result.content)\n", + " return {\"steps\": matches, \"plan_string\": result.content}" + ] + }, + { + "cell_type": "markdown", + "id": "0d97942f-27d3-4761-b6cc-6614dbb90c77", + "metadata": {}, + "source": [ + "## 2. Executor\n", + "\n", + "The executor receives the plan and executes the tools in sequence.\n", + "\n", + "Below, instantiate the search engine and define the toole execution node." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "3412cfc4-6796-4295-aea4-7eeb304e10bd", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_community.tools.tavily_search import TavilySearchResults\n", + "\n", + "search = TavilySearchResults()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "aa96fbac-28bc-4afe-ae35-ddb3383d1147", + "metadata": {}, + "outputs": [], + "source": [ + "def _get_current_task(state: ReWOO):\n", + " if state[\"results\"] is None:\n", + " return 1\n", + " if len(state[\"results\"]) == len(state[\"steps\"]):\n", + " return None\n", + " else:\n", + " return len(state[\"results\"]) + 1\n", + "\n", + "\n", + "def tool_execution(state: ReWOO):\n", + " \"\"\"Worker node that executes the tools of a given plan.\"\"\"\n", + " _step = _get_current_task(state)\n", + " _, step_name, tool, tool_input = state[\"steps\"][_step - 1]\n", + " _results = state[\"results\"] or {}\n", + " for k, v in _results.items():\n", + " tool_input = tool_input.replace(k, v)\n", + " if tool == \"Google\":\n", + " result = search.invoke(tool_input)\n", + " elif tool == \"LLM\":\n", + " result = model.invoke(tool_input)\n", + " else:\n", + " raise ValueError\n", + " _results[step_name] = str(result)\n", + " return {\"results\": _results}" + ] + }, + { + "cell_type": "markdown", + "id": "28e20b31-d721-470d-94d2-db0c177fae75", + "metadata": {}, + "source": [ + "## 3. Solver\n", + "\n", + "The solver receives the full plan and generates the final response based on the responses of the tool calls from the worker." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "0a4d9851-8590-42be-8c53-9969ebff85f4", + "metadata": {}, + "outputs": [], + "source": [ + "solve_prompt = \"\"\"Solve the following task or problem. To solve the problem, we have made step-by-step Plan and \\\n", + "retrieved corresponding Evidence to each Plan. Use them with caution since long evidence might \\\n", + "contain irrelevant information.\n", + "\n", + "{plan}\n", + "\n", + "Now solve the question or task according to provided Evidence above. Respond with the answer\n", + "directly with no extra words.\n", + "\n", + "Task: {task}\n", + "Response:\"\"\"\n", + "\n", + "\n", + "def solve(state: ReWOO):\n", + " plan = \"\"\n", + " for _plan, step_name, tool, tool_input in state[\"steps\"]:\n", + " _results = state[\"results\"] or {}\n", + " for k, v in _results.items():\n", + " tool_input = tool_input.replace(k, v)\n", + " plan += f\"Plan: {_plan}\\n{step_name} = {tool}[{tool_input}]\"\n", + " prompt = solve_prompt.format(plan=plan, task=state[\"task\"])\n", + " result = model.invoke(prompt)\n", + " return {\"result\": result.content}" + ] + }, + { + "cell_type": "markdown", + "id": "8ce26c3f-6ced-4a91-a9f2-d0bc235e4010", + "metadata": {}, + "source": [ + "## 4. Define Graph\n", + "\n", + "Our graph defines the workflow. Each of the planner, tool executor, and solver modules are added as nodes." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "73b235d7-fa83-4e84-9f2e-2908f16deb26", + "metadata": {}, + "outputs": [], + "source": [ + "def _route(state):\n", + " _step = _get_current_task(state)\n", + " if _step is None:\n", + " # We have executed all tasks\n", + " return \"solve\"\n", + " else:\n", + " # We are still executing tasks, loop back to the \"tool\" node\n", + " return \"tool\"" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "cf173aa1-ce31-4dca-8111-30c91e209652", + "metadata": {}, + "outputs": [], + "source": [ + "from langgraph.graph import StateGraph, END\n", + "\n", + "graph = StateGraph(ReWOO)\n", + "graph.add_node(\"plan\", get_plan)\n", + "graph.add_node(\"tool\", tool_execution)\n", + "graph.add_node(\"solve\", solve)\n", + "graph.add_edge(\"plan\", \"tool\")\n", + "graph.add_edge(\"solve\", END)\n", + "graph.add_conditional_edges(\"tool\", _route)\n", + "graph.set_entry_point(\"plan\")\n", + "\n", + "app = graph.compile()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "badaca52-5d55-433f-8770-1bd50c10bf7f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'plan': {'steps': [('Use Google to search for the 2024 Australian Open winner.', '#E1', 'Google', '2024 Australian Open winner'), ('Retrieve the name of the 2024 Australian Open winner from the search results.', '#E2', 'LLM', 'What is the name of the 2024 Australian Open winner, given #E1'), ('Use Google to search for the hometown of the 2024 Australian Open winner.', '#E3', 'Google', 'hometown of 2024 Australian Open winner, given #E2'), ('Retrieve the hometown of the 2024 Australian Open winner from the search results.', '#E4', 'LLM', 'What is the hometown of the 2024 Australian Open winner, given #E3')], 'plan_string': 'Plan: Use Google to search for the 2024 Australian Open winner.\\n#E1 = Google[2024 Australian Open winner]\\n\\nPlan: Retrieve the name of the 2024 Australian Open winner from the search results.\\n#E2 = LLM[What is the name of the 2024 Australian Open winner, given #E1]\\n\\nPlan: Use Google to search for the hometown of the 2024 Australian Open winner.\\n#E3 = Google[hometown of 2024 Australian Open winner, given #E2]\\n\\nPlan: Retrieve the hometown of the 2024 Australian Open winner from the search results.\\n#E4 = LLM[What is the hometown of the 2024 Australian Open winner, given #E3]'}}\n", + "---\n", + "{'tool': {'results': {'#E1': '[{\\'url\\': \\'https://www.cbssports.com/tennis/news/australian-open-2024-jannik-sinner-aryna-sabalenka-crowned-as-grand-slam-singles-champions-at-melbourne-park/\\', \\'content\\': \\'2024 Australian Open odds, Sinner vs. Medvedev picks Sabalenka defeats Zheng to win 2024 Australian Open Australian Open 2024: Jannik Sinner, Aryna Sabalenka crowned as Grand Slam singles champions at Melbourne Park 2024 Australian Open odds, Sabalenka vs. Zheng picks 2024 Australian Open odds, Medvedev vs. Zverev picks Sinner, Sabalenka win Australian Open singles titles Sinner makes epic comeback to win Australian OpenJan 28, 2024 — Jan 28, 2024Australian Open 2024: Jannik Sinner, Aryna Sabalenka crowned as Grand Slam singles champions at Melbourne Park ... Watch Now: Jannik Sinner came\\\\xa0...\\'}, {\\'url\\': \\'https://en.wikipedia.org/wiki/2024_Australian_Open\\', \\'content\\': \"Contents 2024 Australian Open The 2024 Australian Open was a Grand Slam level tennis tournament held at Melbourne Park, from 14–28 January 2024.[1] The Australian Open total prize money for 2024 increased by 13.07% year on year to a tournament record A$86,500,000. In the tournament\\'s 119-year history, this was the first Australian Open Tennis Championships to be held on an openingNovak Djokovic was the defending men\\'s singles champion. ... He was defeated in the semifinals by Jannik Sinner, who went on to beat Daniil Medvedev in a five-set\\\\xa0...\"}, {\\'url\\': \\'https://en.wikipedia.org/wiki/2024_Australian_Open_%E2%80%93_Men%27s_singles\\', \\'content\\': \"Contents 2024 Australian Open – Men\\'s singles The entry list was released by Tennis Australia based on the ATP rankings for the week of 4 December 2023.[15] matches, tying the Open Era record set at the 1983 US Open.[14] feature any of the Big Three members.[4] It was the second time Medvedev lost the Australian Open final after winningJannik Sinner defeated Daniil Medvedev in the final, 3–6, 3–6, 6–4, 6–4, 6–3, to win the men\\'s singles tennis title at the 2024 Australian Open.\"}]'}}}\n", + "---\n", + "{'tool': {'results': {'#E1': '[{\\'url\\': \\'https://www.cbssports.com/tennis/news/australian-open-2024-jannik-sinner-aryna-sabalenka-crowned-as-grand-slam-singles-champions-at-melbourne-park/\\', \\'content\\': \\'2024 Australian Open odds, Sinner vs. Medvedev picks Sabalenka defeats Zheng to win 2024 Australian Open Australian Open 2024: Jannik Sinner, Aryna Sabalenka crowned as Grand Slam singles champions at Melbourne Park 2024 Australian Open odds, Sabalenka vs. Zheng picks 2024 Australian Open odds, Medvedev vs. Zverev picks Sinner, Sabalenka win Australian Open singles titles Sinner makes epic comeback to win Australian OpenJan 28, 2024 — Jan 28, 2024Australian Open 2024: Jannik Sinner, Aryna Sabalenka crowned as Grand Slam singles champions at Melbourne Park ... Watch Now: Jannik Sinner came\\\\xa0...\\'}, {\\'url\\': \\'https://en.wikipedia.org/wiki/2024_Australian_Open\\', \\'content\\': \"Contents 2024 Australian Open The 2024 Australian Open was a Grand Slam level tennis tournament held at Melbourne Park, from 14–28 January 2024.[1] The Australian Open total prize money for 2024 increased by 13.07% year on year to a tournament record A$86,500,000. In the tournament\\'s 119-year history, this was the first Australian Open Tennis Championships to be held on an openingNovak Djokovic was the defending men\\'s singles champion. ... He was defeated in the semifinals by Jannik Sinner, who went on to beat Daniil Medvedev in a five-set\\\\xa0...\"}, {\\'url\\': \\'https://en.wikipedia.org/wiki/2024_Australian_Open_%E2%80%93_Men%27s_singles\\', \\'content\\': \"Contents 2024 Australian Open – Men\\'s singles The entry list was released by Tennis Australia based on the ATP rankings for the week of 4 December 2023.[15] matches, tying the Open Era record set at the 1983 US Open.[14] feature any of the Big Three members.[4] It was the second time Medvedev lost the Australian Open final after winningJannik Sinner defeated Daniil Medvedev in the final, 3–6, 3–6, 6–4, 6–4, 6–3, to win the men\\'s singles tennis title at the 2024 Australian Open.\"}]', '#E2': \"content='The name of the 2024 Australian Open winner is Jannik Sinner.'\"}}}\n", + "---\n", + "{'tool': {'results': {'#E1': '[{\\'url\\': \\'https://www.cbssports.com/tennis/news/australian-open-2024-jannik-sinner-aryna-sabalenka-crowned-as-grand-slam-singles-champions-at-melbourne-park/\\', \\'content\\': \\'2024 Australian Open odds, Sinner vs. Medvedev picks Sabalenka defeats Zheng to win 2024 Australian Open Australian Open 2024: Jannik Sinner, Aryna Sabalenka crowned as Grand Slam singles champions at Melbourne Park 2024 Australian Open odds, Sabalenka vs. Zheng picks 2024 Australian Open odds, Medvedev vs. Zverev picks Sinner, Sabalenka win Australian Open singles titles Sinner makes epic comeback to win Australian OpenJan 28, 2024 — Jan 28, 2024Australian Open 2024: Jannik Sinner, Aryna Sabalenka crowned as Grand Slam singles champions at Melbourne Park ... Watch Now: Jannik Sinner came\\\\xa0...\\'}, {\\'url\\': \\'https://en.wikipedia.org/wiki/2024_Australian_Open\\', \\'content\\': \"Contents 2024 Australian Open The 2024 Australian Open was a Grand Slam level tennis tournament held at Melbourne Park, from 14–28 January 2024.[1] The Australian Open total prize money for 2024 increased by 13.07% year on year to a tournament record A$86,500,000. In the tournament\\'s 119-year history, this was the first Australian Open Tennis Championships to be held on an openingNovak Djokovic was the defending men\\'s singles champion. ... He was defeated in the semifinals by Jannik Sinner, who went on to beat Daniil Medvedev in a five-set\\\\xa0...\"}, {\\'url\\': \\'https://en.wikipedia.org/wiki/2024_Australian_Open_%E2%80%93_Men%27s_singles\\', \\'content\\': \"Contents 2024 Australian Open – Men\\'s singles The entry list was released by Tennis Australia based on the ATP rankings for the week of 4 December 2023.[15] matches, tying the Open Era record set at the 1983 US Open.[14] feature any of the Big Three members.[4] It was the second time Medvedev lost the Australian Open final after winningJannik Sinner defeated Daniil Medvedev in the final, 3–6, 3–6, 6–4, 6–4, 6–3, to win the men\\'s singles tennis title at the 2024 Australian Open.\"}]', '#E2': \"content='The name of the 2024 Australian Open winner is Jannik Sinner.'\", '#E3': '[{\\'url\\': \\'https://www.tennis.com/news/articles/soccer-mad-italy-is-now-obsessed-with-tennis-player-jannik-sinner-after-his-australian-open-title\\', \\'content\\': \"Soccer-mad Italy is now obsessed with tennis player Jannik Sinner after his Australian Open title Play & Win Advertising Soccer-mad Italy is now obsessed with tennis player Jannik Sinner after his Australian Open title \\'Grandissimo\\': Italian Premier Giorgia Meloni welcomes home Australian Open champion Jannik Sinner First of many? Jannik Sinner\\'s five-set comeback sinks Daniil Medvedev in Australian Open finalJan 28, 2024 — Jan 28, 2024In Sinner\\'s tiny hometown of Sesto (population 1,860) near the Austrian border, about 70 people gathered inside the two-court indoor tennis\\\\xa0...\"}, {\\'url\\': \\'https://apnews.com/article/jannik-sinner-italy-australian-open-03573689c4c58c2851d1006e26546ac9\\', \\'content\\': \"Soccer-mad Italy is now obsessed with tennis player Jannik Sinner after his Australian Open title Jannik Sinner, left, of Italy gestures as he holds the Norman Brookes Challenge Cup after defeating Daniil Medvedev, Jannik Sinner, left, of Italy gestures as he holds the Norman Brookes Challenge Cup after defeating Daniil Medvedev, Jannik Sinner, left, of Italy gestures as he holds the Norman Brookes Challenge Cup after defeating Daniil Medvedev,Jan 28, 2024 — Jan 28, 2024Soccer-mad Italy has a new obsession. Jannik Sinner\\'s Australian Open performance on the tennis court has captured the country\\'s attention.\"}, {\\'url\\': \\'https://en.wikipedia.org/wiki/Jannik_Sinner\\', \\'content\\': \\'Sinner is a major champion, having won the 2024 Australian Open.[3] He has won a further ten ATP Tour singles titles, At the 2024 Australian Open, Sinner defeated world No. 1 Novak Djokovic in the semifinals to reach his first major Early in the year Sinner made the second round of the 2020 Australian Open, recording his first Grand Slam main draw a match since Janko Tipsarević in London in 2011.[59][60] Sinner played Daniil Medvedev next in the round robin stage,Since making his professional debut in 2018, Sinner has won 11 ATP Tour singles titles, including a Grand Slam at the 2024 Australian Open and a Masters 1000 at\\\\xa0...\\'}, {\\'url\\': \\'https://ausopen.com/players/italy/jannik-sinner\\', \\'content\\': \"Jannik Sinner weathered an early onslaught to reel in Daniil Medvedev, growing in potency to win the Australian Open the Australian Open 2024 final – his first Grand Slam singles title. Jannik Sinner will contest his first Grand Slam final after scuttling Novak Djokovic’s bid for a record-extending 11th Jannick Sinner has form and fitness on his side ahead of his meeting with Andrey Rublev.Jannik Sinner Press Conference | Australian Open 2024 Final. 15:02 · Player & Career Overview. Career Wins 73% · Men\\'s Singles. Final • Rod Laver Arena · Comeback\\\\xa0...\"}]'}}}\n", + "---\n", + "{'tool': {'results': {'#E1': '[{\\'url\\': \\'https://www.cbssports.com/tennis/news/australian-open-2024-jannik-sinner-aryna-sabalenka-crowned-as-grand-slam-singles-champions-at-melbourne-park/\\', \\'content\\': \\'2024 Australian Open odds, Sinner vs. Medvedev picks Sabalenka defeats Zheng to win 2024 Australian Open Australian Open 2024: Jannik Sinner, Aryna Sabalenka crowned as Grand Slam singles champions at Melbourne Park 2024 Australian Open odds, Sabalenka vs. Zheng picks 2024 Australian Open odds, Medvedev vs. Zverev picks Sinner, Sabalenka win Australian Open singles titles Sinner makes epic comeback to win Australian OpenJan 28, 2024 — Jan 28, 2024Australian Open 2024: Jannik Sinner, Aryna Sabalenka crowned as Grand Slam singles champions at Melbourne Park ... Watch Now: Jannik Sinner came\\\\xa0...\\'}, {\\'url\\': \\'https://en.wikipedia.org/wiki/2024_Australian_Open\\', \\'content\\': \"Contents 2024 Australian Open The 2024 Australian Open was a Grand Slam level tennis tournament held at Melbourne Park, from 14–28 January 2024.[1] The Australian Open total prize money for 2024 increased by 13.07% year on year to a tournament record A$86,500,000. In the tournament\\'s 119-year history, this was the first Australian Open Tennis Championships to be held on an openingNovak Djokovic was the defending men\\'s singles champion. ... He was defeated in the semifinals by Jannik Sinner, who went on to beat Daniil Medvedev in a five-set\\\\xa0...\"}, {\\'url\\': \\'https://en.wikipedia.org/wiki/2024_Australian_Open_%E2%80%93_Men%27s_singles\\', \\'content\\': \"Contents 2024 Australian Open – Men\\'s singles The entry list was released by Tennis Australia based on the ATP rankings for the week of 4 December 2023.[15] matches, tying the Open Era record set at the 1983 US Open.[14] feature any of the Big Three members.[4] It was the second time Medvedev lost the Australian Open final after winningJannik Sinner defeated Daniil Medvedev in the final, 3–6, 3–6, 6–4, 6–4, 6–3, to win the men\\'s singles tennis title at the 2024 Australian Open.\"}]', '#E2': \"content='The name of the 2024 Australian Open winner is Jannik Sinner.'\", '#E3': '[{\\'url\\': \\'https://www.tennis.com/news/articles/soccer-mad-italy-is-now-obsessed-with-tennis-player-jannik-sinner-after-his-australian-open-title\\', \\'content\\': \"Soccer-mad Italy is now obsessed with tennis player Jannik Sinner after his Australian Open title Play & Win Advertising Soccer-mad Italy is now obsessed with tennis player Jannik Sinner after his Australian Open title \\'Grandissimo\\': Italian Premier Giorgia Meloni welcomes home Australian Open champion Jannik Sinner First of many? Jannik Sinner\\'s five-set comeback sinks Daniil Medvedev in Australian Open finalJan 28, 2024 — Jan 28, 2024In Sinner\\'s tiny hometown of Sesto (population 1,860) near the Austrian border, about 70 people gathered inside the two-court indoor tennis\\\\xa0...\"}, {\\'url\\': \\'https://apnews.com/article/jannik-sinner-italy-australian-open-03573689c4c58c2851d1006e26546ac9\\', \\'content\\': \"Soccer-mad Italy is now obsessed with tennis player Jannik Sinner after his Australian Open title Jannik Sinner, left, of Italy gestures as he holds the Norman Brookes Challenge Cup after defeating Daniil Medvedev, Jannik Sinner, left, of Italy gestures as he holds the Norman Brookes Challenge Cup after defeating Daniil Medvedev, Jannik Sinner, left, of Italy gestures as he holds the Norman Brookes Challenge Cup after defeating Daniil Medvedev,Jan 28, 2024 — Jan 28, 2024Soccer-mad Italy has a new obsession. Jannik Sinner\\'s Australian Open performance on the tennis court has captured the country\\'s attention.\"}, {\\'url\\': \\'https://en.wikipedia.org/wiki/Jannik_Sinner\\', \\'content\\': \\'Sinner is a major champion, having won the 2024 Australian Open.[3] He has won a further ten ATP Tour singles titles, At the 2024 Australian Open, Sinner defeated world No. 1 Novak Djokovic in the semifinals to reach his first major Early in the year Sinner made the second round of the 2020 Australian Open, recording his first Grand Slam main draw a match since Janko Tipsarević in London in 2011.[59][60] Sinner played Daniil Medvedev next in the round robin stage,Since making his professional debut in 2018, Sinner has won 11 ATP Tour singles titles, including a Grand Slam at the 2024 Australian Open and a Masters 1000 at\\\\xa0...\\'}, {\\'url\\': \\'https://ausopen.com/players/italy/jannik-sinner\\', \\'content\\': \"Jannik Sinner weathered an early onslaught to reel in Daniil Medvedev, growing in potency to win the Australian Open the Australian Open 2024 final – his first Grand Slam singles title. Jannik Sinner will contest his first Grand Slam final after scuttling Novak Djokovic’s bid for a record-extending 11th Jannick Sinner has form and fitness on his side ahead of his meeting with Andrey Rublev.Jannik Sinner Press Conference | Australian Open 2024 Final. 15:02 · Player & Career Overview. Career Wins 73% · Men\\'s Singles. Final • Rod Laver Arena · Comeback\\\\xa0...\"}]', '#E4': \"content='The hometown of the 2024 Australian Open winner, Jannik Sinner, is Sesto, a small town near the Austrian border in Italy.'\"}}}\n", + "---\n", + "{'solve': {'result': 'The hometown of the 2024 Australian Open winner, Jannik Sinner, is Sesto, Italy.'}}\n", + "---\n", + "{'__end__': {'task': 'what is the hometown of the 2024 australian open winner', 'plan_string': 'Plan: Use Google to search for the 2024 Australian Open winner.\\n#E1 = Google[2024 Australian Open winner]\\n\\nPlan: Retrieve the name of the 2024 Australian Open winner from the search results.\\n#E2 = LLM[What is the name of the 2024 Australian Open winner, given #E1]\\n\\nPlan: Use Google to search for the hometown of the 2024 Australian Open winner.\\n#E3 = Google[hometown of 2024 Australian Open winner, given #E2]\\n\\nPlan: Retrieve the hometown of the 2024 Australian Open winner from the search results.\\n#E4 = LLM[What is the hometown of the 2024 Australian Open winner, given #E3]', 'steps': [('Use Google to search for the 2024 Australian Open winner.', '#E1', 'Google', '2024 Australian Open winner'), ('Retrieve the name of the 2024 Australian Open winner from the search results.', '#E2', 'LLM', 'What is the name of the 2024 Australian Open winner, given #E1'), ('Use Google to search for the hometown of the 2024 Australian Open winner.', '#E3', 'Google', 'hometown of 2024 Australian Open winner, given #E2'), ('Retrieve the hometown of the 2024 Australian Open winner from the search results.', '#E4', 'LLM', 'What is the hometown of the 2024 Australian Open winner, given #E3')], 'results': {'#E1': '[{\\'url\\': \\'https://www.cbssports.com/tennis/news/australian-open-2024-jannik-sinner-aryna-sabalenka-crowned-as-grand-slam-singles-champions-at-melbourne-park/\\', \\'content\\': \\'2024 Australian Open odds, Sinner vs. Medvedev picks Sabalenka defeats Zheng to win 2024 Australian Open Australian Open 2024: Jannik Sinner, Aryna Sabalenka crowned as Grand Slam singles champions at Melbourne Park 2024 Australian Open odds, Sabalenka vs. Zheng picks 2024 Australian Open odds, Medvedev vs. Zverev picks Sinner, Sabalenka win Australian Open singles titles Sinner makes epic comeback to win Australian OpenJan 28, 2024 — Jan 28, 2024Australian Open 2024: Jannik Sinner, Aryna Sabalenka crowned as Grand Slam singles champions at Melbourne Park ... Watch Now: Jannik Sinner came\\\\xa0...\\'}, {\\'url\\': \\'https://en.wikipedia.org/wiki/2024_Australian_Open\\', \\'content\\': \"Contents 2024 Australian Open The 2024 Australian Open was a Grand Slam level tennis tournament held at Melbourne Park, from 14–28 January 2024.[1] The Australian Open total prize money for 2024 increased by 13.07% year on year to a tournament record A$86,500,000. In the tournament\\'s 119-year history, this was the first Australian Open Tennis Championships to be held on an openingNovak Djokovic was the defending men\\'s singles champion. ... He was defeated in the semifinals by Jannik Sinner, who went on to beat Daniil Medvedev in a five-set\\\\xa0...\"}, {\\'url\\': \\'https://en.wikipedia.org/wiki/2024_Australian_Open_%E2%80%93_Men%27s_singles\\', \\'content\\': \"Contents 2024 Australian Open – Men\\'s singles The entry list was released by Tennis Australia based on the ATP rankings for the week of 4 December 2023.[15] matches, tying the Open Era record set at the 1983 US Open.[14] feature any of the Big Three members.[4] It was the second time Medvedev lost the Australian Open final after winningJannik Sinner defeated Daniil Medvedev in the final, 3–6, 3–6, 6–4, 6–4, 6–3, to win the men\\'s singles tennis title at the 2024 Australian Open.\"}]', '#E2': \"content='The name of the 2024 Australian Open winner is Jannik Sinner.'\", '#E3': '[{\\'url\\': \\'https://www.tennis.com/news/articles/soccer-mad-italy-is-now-obsessed-with-tennis-player-jannik-sinner-after-his-australian-open-title\\', \\'content\\': \"Soccer-mad Italy is now obsessed with tennis player Jannik Sinner after his Australian Open title Play & Win Advertising Soccer-mad Italy is now obsessed with tennis player Jannik Sinner after his Australian Open title \\'Grandissimo\\': Italian Premier Giorgia Meloni welcomes home Australian Open champion Jannik Sinner First of many? Jannik Sinner\\'s five-set comeback sinks Daniil Medvedev in Australian Open finalJan 28, 2024 — Jan 28, 2024In Sinner\\'s tiny hometown of Sesto (population 1,860) near the Austrian border, about 70 people gathered inside the two-court indoor tennis\\\\xa0...\"}, {\\'url\\': \\'https://apnews.com/article/jannik-sinner-italy-australian-open-03573689c4c58c2851d1006e26546ac9\\', \\'content\\': \"Soccer-mad Italy is now obsessed with tennis player Jannik Sinner after his Australian Open title Jannik Sinner, left, of Italy gestures as he holds the Norman Brookes Challenge Cup after defeating Daniil Medvedev, Jannik Sinner, left, of Italy gestures as he holds the Norman Brookes Challenge Cup after defeating Daniil Medvedev, Jannik Sinner, left, of Italy gestures as he holds the Norman Brookes Challenge Cup after defeating Daniil Medvedev,Jan 28, 2024 — Jan 28, 2024Soccer-mad Italy has a new obsession. Jannik Sinner\\'s Australian Open performance on the tennis court has captured the country\\'s attention.\"}, {\\'url\\': \\'https://en.wikipedia.org/wiki/Jannik_Sinner\\', \\'content\\': \\'Sinner is a major champion, having won the 2024 Australian Open.[3] He has won a further ten ATP Tour singles titles, At the 2024 Australian Open, Sinner defeated world No. 1 Novak Djokovic in the semifinals to reach his first major Early in the year Sinner made the second round of the 2020 Australian Open, recording his first Grand Slam main draw a match since Janko Tipsarević in London in 2011.[59][60] Sinner played Daniil Medvedev next in the round robin stage,Since making his professional debut in 2018, Sinner has won 11 ATP Tour singles titles, including a Grand Slam at the 2024 Australian Open and a Masters 1000 at\\\\xa0...\\'}, {\\'url\\': \\'https://ausopen.com/players/italy/jannik-sinner\\', \\'content\\': \"Jannik Sinner weathered an early onslaught to reel in Daniil Medvedev, growing in potency to win the Australian Open the Australian Open 2024 final – his first Grand Slam singles title. Jannik Sinner will contest his first Grand Slam final after scuttling Novak Djokovic’s bid for a record-extending 11th Jannick Sinner has form and fitness on his side ahead of his meeting with Andrey Rublev.Jannik Sinner Press Conference | Australian Open 2024 Final. 15:02 · Player & Career Overview. Career Wins 73% · Men\\'s Singles. Final • Rod Laver Arena · Comeback\\\\xa0...\"}]', '#E4': \"content='The hometown of the 2024 Australian Open winner, Jannik Sinner, is Sesto, a small town near the Austrian border in Italy.'\"}, 'result': 'The hometown of the 2024 Australian Open winner, Jannik Sinner, is Sesto, Italy.'}}\n", + "---\n" + ] + } + ], + "source": [ + "for s in app.stream({\"task\": task}):\n", + " print(s)\n", + " print(\"---\")" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "70e5aa0f-4d8b-4f65-817a-1c4ebf07d07a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The hometown of the 2024 Australian Open winner, Jannik Sinner, is Sesto, Italy.\n" + ] + } + ], + "source": [ + "# Print out the final result\n", + "print(s[END][\"result\"])" + ] + }, + { + "cell_type": "markdown", + "id": "842954d7-0de0-4876-be63-46b4e14157b0", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "Congratulations on implementing ReWOO! Before you leave, I'll leave you with a couple limitations of the current implementation from the paper:\n", + "\n", + "1. If little context of the environment is available, the planner will be ineffective in its tool use. This can typically be ameliorated through few-shot prompting and/or fine-tuning.\n", + "2. The tasks are still executed in sequence, meaning the total execution time is impacted by _every_ tool call, not just he longest-running in a given step." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}