{ "cells": [ { "cell_type": "markdown", "id": "f740d78515a7cf5f", "metadata": {}, "source": [ "# Query Plan\n", "\n", "This recipe shows how to use LLMs — in this case, Anthropic’s Claude 3.5 Sonnet — to create a query plan. Using a query plan is a great way to get more accurate results by breaking down a complex question into multiple smaller questions.\n", "\n", "
\n", "

Mirascope Concepts Used

\n", "\n", "
" ] }, { "cell_type": "markdown", "id": "3a01305b", "metadata": {}, "source": [ "## Setup\n", "\n", "Let's start by installing Mirascope and its dependencies:" ] }, { "cell_type": "code", "execution_count": null, "id": "aefb5828", "metadata": {}, "outputs": [], "source": [ "!pip install \"mirascope[anthropic]\"" ] }, { "cell_type": "code", "execution_count": null, "id": "57c0ca36", "metadata": {}, "outputs": [], "source": [ "import os\n", "\n", "os.environ[\"ANTHROPIC_API_KEY\"] = \"YOUR_API_KEY\"\n", "# Set the appropriate API key for the provider you're using" ] }, { "cell_type": "markdown", "id": "bb9583e0", "metadata": {}, "source": [ "## Create your Query\n", "\n", "To construct our Query Plan, we first need to define the individual queries that will comprise it using a Pydantic BaseModel:" ] }, { "cell_type": "code", "execution_count": 1, "id": "cb1813edef6103de", "metadata": { "ExecuteTime": { "end_time": "2024-09-30T07:53:34.826662Z", "start_time": "2024-09-30T07:53:34.753373Z" } }, "outputs": [], "source": [ "from pydantic import BaseModel, Field\n", "\n", "\n", "class Query(BaseModel):\n", " id: int = Field(..., description=\"ID of the query, this is auto-incremented\")\n", " question: str = Field(\n", " ...,\n", " description=\"The broken down question to be answered to answer the main question\",\n", " )\n", " dependencies: list[int] = Field(\n", " description=\"List of sub questions that need to be answered before asking this question\",\n", " )\n", " tools: list[str] = Field(\n", " description=\"List of tools that should be used to answer the question\"\n", " )" ] }, { "cell_type": "markdown", "id": "cc15e300e2df7595", "metadata": {}, "source": [ "\n", "Each query is assigned a unique ID, which can reference other queries for dependencies. We also provide necessary tools and the relevant portion of the broken-down question to each query.\n", "\n", "## Create our tool\n", "\n", "For the purposes of this recipe, we will define some dummy data. This tool should be replaced by web_search, a database query, or other forms of pulling data.\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "49f906a49c1e6fe2", "metadata": { "ExecuteTime": { "end_time": "2024-09-30T07:53:36.763421Z", "start_time": "2024-09-30T07:53:36.760211Z" } }, "outputs": [], "source": [ "import json\n", "\n", "\n", "def get_weather_by_year(year: int):\n", " \"\"\"Made up data to get Tokyo weather by year\"\"\"\n", " if year == 2020:\n", " data = {\n", " \"jan\": 42,\n", " \"feb\": 43,\n", " \"mar\": 49,\n", " \"apr\": 58,\n", " \"may\": 66,\n", " \"jun\": 72,\n", " \"jul\": 78,\n", " \"aug\": 81,\n", " \"sep\": 75,\n", " \"oct\": 65,\n", " \"nov\": 55,\n", " \"dec\": 47,\n", " }\n", " elif year == 2021:\n", " data = {\n", " \"jan\": 45,\n", " \"feb\": 48,\n", " \"mar\": 52,\n", " \"apr\": 60,\n", " \"may\": 68,\n", " \"jun\": 74,\n", " \"jul\": 80,\n", " \"aug\": 83,\n", " \"sep\": 77,\n", " \"oct\": 67,\n", " \"nov\": 57,\n", " \"dec\": 49,\n", " }\n", " else:\n", " data = {\n", " \"jan\": 48,\n", " \"feb\": 52,\n", " \"mar\": 56,\n", " \"apr\": 64,\n", " \"may\": 72,\n", " \"jun\": 78,\n", " \"jul\": 84,\n", " \"aug\": 87,\n", " \"sep\": 81,\n", " \"oct\": 71,\n", " \"nov\": 61,\n", " \"dec\": 53,\n", " }\n", " return json.dumps(data)" ] }, { "cell_type": "markdown", "id": "87547a5376cbe2a6", "metadata": {}, "source": [ "\n", "## Define our Query Planner\n", "\n", "Let us prompt our LLM call to create a query plan for a particular question:\n" ] }, { "cell_type": "code", "execution_count": 3, "id": "2dcf08d5387215cd", "metadata": { "ExecuteTime": { "end_time": "2024-09-30T07:53:40.869934Z", "start_time": "2024-09-30T07:53:40.016298Z" } }, "outputs": [], "source": [ "from mirascope.core import anthropic, prompt_template\n", "\n", "\n", "@anthropic.call(\n", " model=\"claude-3-5-sonnet-20240620\", response_model=list[Query], json_mode=True\n", ")\n", "@prompt_template(\n", " \"\"\"\n", " SYSTEM:\n", " You are an expert at creating a query plan for a question.\n", " You are given a question and you need to create a query plan for it.\n", " You need to create a list of queries that can be used to answer the question.\n", "\n", " You have access to the following tool:\n", " - get_weather_by_year\n", " USER:\n", " {question}\n", " \"\"\"\n", ")\n", "def create_query_plan(question: str): ..." ] }, { "cell_type": "markdown", "id": "94659f37846dcb4b", "metadata": {}, "source": [ "\n", "We set the `response_model` to the `Query` object we just defined. We also prompt the call to add tools as necessary to the individual `Query`. Now we make a call to the LLM:\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "6ed0fd75426effb1", "metadata": { "ExecuteTime": { "end_time": "2024-09-30T07:53:45.225333Z", "start_time": "2024-09-30T07:53:42.057805Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[Query(id=1, question='What was the weather like in Tokyo in 2020?', dependencies=[], tools=['get_weather_by_year']), Query(id=2, question='What was the weather like in Tokyo in 2021?', dependencies=[], tools=['get_weather_by_year']), Query(id=3, question='What was the weather like in Tokyo in 2022?', dependencies=[], tools=['get_weather_by_year']), Query(id=4, question='Compare the weather data for Tokyo from 2020 to 2022', dependencies=[1, 2, 3], tools=[])]\n" ] } ], "source": [ "query_plan = create_query_plan(\"Compare the weather in Tokyo from 2020 to 2022\")\n", "print(query_plan)" ] }, { "cell_type": "markdown", "id": "85640afd0034d8b9", "metadata": {}, "source": [ "\n", "We can see our `list[Query]` and their respective subquestions and tools needed to answer the main question. We can also see that the final question depends on the answers from the previous queries.\n", "\n", "## Executing our Query Plan\n", "\n", "Now that we have our list of queries, we can iterate on each of the subqueries to answer our main question:\n" ] }, { "cell_type": "code", "execution_count": 5, "id": "572ccc20884f6d5f", "metadata": { "ExecuteTime": { "end_time": "2024-09-30T07:53:47.568479Z", "start_time": "2024-09-30T07:53:47.564475Z" } }, "outputs": [], "source": [ "from anthropic.types import MessageParam\n", "\n", "\n", "@anthropic.call(model=\"claude-3-5-sonnet-20240620\")\n", "@prompt_template(\n", " \"\"\"\n", " MESSAGES:\n", " {history}\n", " USER:\n", " {question}\n", " \"\"\"\n", ")\n", "def run(\n", " question: str, history: list[MessageParam], tools: list[str]\n", ") -> anthropic.AnthropicDynamicConfig:\n", " tools_fn = [eval(tool) for tool in tools]\n", " return {\"tools\": tools_fn}\n", "\n", "\n", "def execute_query_plan(query_plan: list[Query]):\n", " results = {}\n", " for query in query_plan:\n", " history = []\n", " for dependency in query.dependencies:\n", " result = results[dependency]\n", " history.append({\"role\": \"user\", \"content\": result[\"question\"]})\n", " history.append({\"role\": \"assistant\", \"content\": result[\"content\"]})\n", " result = run(query.question, history, query.tools)\n", " if tool := result.tool:\n", " output = tool.call()\n", " results[query.id] = {\"question\": query.question, \"content\": output}\n", " else:\n", " return result.content\n", " return results" ] }, { "cell_type": "markdown", "id": "b09d63b38a20afc5", "metadata": {}, "source": [ "\n", "Using Mirascope’s `DynamicConfig` , we can pass in the tools from the query plan into our LLM call. We also add history to the calls that have dependencies.\n", "\n", "Now we run `execute_query_plan`:\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "71f38645849fde37", "metadata": { "ExecuteTime": { "end_time": "2024-09-30T07:54:02.760030Z", "start_time": "2024-09-30T07:53:51.340901Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Comparing the weather data for Tokyo from 2020 to 2022, we can observe the following trends:\n", "\n", "1. Overall warming trend:\n", " - There's a consistent increase in temperatures across all months from 2020 to 2022.\n", " - The average annual temperature has risen each year.\n", "\n", "2. Monthly comparisons:\n", " - January: 42°F (2020) → 45°F (2021) → 48°F (2022)\n", " - July: 78°F (2020) → 80°F (2021) → 84°F (2022)\n", " - December: 47°F (2020) → 49°F (2021) → 53°F (2022)\n", "\n", "3. Seasonal patterns:\n", " - Winters (Dec-Feb) have become milder each year.\n", " - Summers (Jun-Aug) have become hotter each year.\n", " - Spring and autumn months also show warming trends.\n", "\n", "4. Extreme temperatures:\n", " - The hottest month has consistently been August, with temperatures increasing from 81°F (2020) to 87°F (2022).\n", " - The coldest month has consistently been January, with temperatures rising from 42°F (2020) to 48°F (2022).\n", "\n", "5. Year-to-year changes:\n", " - The temperature increase from 2020 to 2021 was generally smaller than the increase from 2021 to 2022.\n", " - 2022 shows the most significant warming compared to previous years.\n", "\n", "In summary, the data indicates a clear warming trend in Tokyo from 2020 to 2022, with each year being warmer than the last across all seasons.\n" ] } ], "source": [ "result = execute_query_plan(query_plan)\n", "print(result)" ] }, { "cell_type": "markdown", "id": "e35e4e08d27b45c0", "metadata": {}, "source": [ "
\n", "

Additional Real-World Examples

\n", "\n", "
\n", "\n", "When adapting this recipe to your specific use-case, consider the following:\n", "\n", " - Agentic: Turn this example into a more flexible Agent which has access to a query plan tool.\n", " - Multiple providers: Use multiple LLM providers to verify whether the extracted information is accurate and not hallucination.\n", " - Implement Pydantic `ValidationError` and Tenacity `retry` to improve reliability and accuracy.\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.6" } }, "nbformat": 4, "nbformat_minor": 5 }