diff --git a/index.toml b/index.toml index 2e5a936c..f3bc0e0e 100644 --- a/index.toml +++ b/index.toml @@ -477,4 +477,4 @@ haystack_2 = true guide = true colab = false download = false -created_at = 2024-07-17 +created_at = 2024-07-17 \ No newline at end of file diff --git a/tutorials/36_Building_Fallbacks_with_Conditional_Routing.ipynb b/tutorials/36_Building_Fallbacks_with_Conditional_Routing.ipynb index 9e91f81c..76536338 100644 --- a/tutorials/36_Building_Fallbacks_with_Conditional_Routing.ipynb +++ b/tutorials/36_Building_Fallbacks_with_Conditional_Routing.ipynb @@ -1,551 +1,571 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "IR5wivW8THt7" - }, - "source": [ - "# Tutorial: Building Fallbacks to Websearch with Conditional Routing\n", - "\n", - "- **Level**: Intermediate\n", - "- **Time to complete**: 10 minutes\n", - "- **Components Used**: [`ConditionalRouter`](https://docs.haystack.deepset.ai/docs/conditionalrouter), [`SerperDevWebSearch`](https://docs.haystack.deepset.ai/docs/serperdevwebsearch), [`PromptBuilder`](https://docs.haystack.deepset.ai/docs/promptbuilder), [`OpenAIGenerator`](https://docs.haystack.deepset.ai/docs/openaigenerator)\n", - "- **Prerequisites**: You must have an [OpenAI API Key](https://platform.openai.com/api-keys) and a [Serper API Key](https://serper.dev/api-key) for this tutorial\n", - "- **Goal**: After completing this tutorial, you'll have learned how to create a pipeline with conditional routing that can fallback to websearch if the answer is not present in your dataset.\n", - "\n", - "> This tutorial uses Haystack 2.0. To learn more, read the [Haystack 2.0 announcement](https://haystack.deepset.ai/blog/haystack-2-release) or visit the [Haystack 2.0 Documentation](https://docs.haystack.deepset.ai/docs/intro).\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "F-a-MAMVat-o" - }, - "source": [ - "## Overview\n", - "\n", - "When developing applications using **retrieval augmented generation ([RAG](https://www.deepset.ai/blog/llms-retrieval-augmentation))**, the retrieval step plays a critical role. It serves as the primary information source for **large language models (LLMs)** to generate responses. However, if your database lacks the necessary information, the retrieval step's effectiveness is limited. In such scenarios, it may be practical to use the web as a fallback data source for your RAG application. By implementing a conditional routing mechanism in your system, you gain complete control over the data flow, enabling you to design a system that can leverage the web as its data source under some conditions.\n", - "\n", - "In this tutorial, you will learn how to create a pipeline with conditional routing that directs the query to a **web-based RAG** route if the answer is not found in the initially given documents." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "LSwNKkeKeq0f" - }, - "source": [ - "## Development Environment" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "eGJ7GmCBas4R" - }, - "source": [ - "### Prepare the Colab Environment\n", - "\n", - "- [Enable GPU Runtime in Colab](https://docs.haystack.deepset.ai/docs/enabling-gpu-acceleration)\n", - "- [Set logging level to INFO](https://docs.haystack.deepset.ai/docs/setting-the-log-level)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "FwIgIpE2XqpO" - }, - "source": [ - "### Install Haystack\n", - "\n", - "Install Haystack 2.0 with `pip`:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "uba0mntlqs_O" - }, - "outputs": [], - "source": [ - "%%bash\n", - "\n", - "pip install haystack-ai" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "WBkJ7d3hZkOJ" - }, - "source": [ - "### Enable Telemetry\n", - "\n", - "Knowing you're using this tutorial helps us decide where to invest our efforts to build a better product but you can always opt out by commenting the following line. See [Telemetry](https://docs.haystack.deepset.ai/docs/telemetry) for more details." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "HvrOixzzZmMi" - }, - "outputs": [], - "source": [ - "from haystack.telemetry import tutorial_running\n", - "\n", - "tutorial_running(36)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "QfECEAy2Jdqs" - }, - "source": [ - "### Enter API Keys\n", - "\n", - "Enter API keys required for this tutorial." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "13U7Z_k3yE-F", - "outputId": "6ec48553-12d2-4c89-ca13-fc5d34fbc625" - }, - "outputs": [], - "source": [ - "from getpass import getpass\n", - "import os\n", - "\n", - "if \"OPENAI_API_KEY\" not in os.environ:\n", - " os.environ[\"OPENAI_API_KEY\"] = getpass(\"Enter OpenAI API key:\")\n", - "if \"SERPERDEV_API_KEY\" not in os.environ:\n", - " os.environ[\"SERPERDEV_API_KEY\"] = getpass(\"Enter Serper Api key: \")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "i_AlhPv1T-4t" - }, - "source": [ - "## Creating a Document\n", - "\n", - "Create a Document about Munich, where the answer to your question will be initially searched:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "5CHbQlLMyVbg" - }, - "outputs": [], - "source": [ - "from haystack.dataclasses import Document\n", - "\n", - "documents = [\n", - " Document(\n", - " content=\"\"\"Munich, the vibrant capital of Bavaria in southern Germany, exudes a perfect blend of rich cultural\n", - " heritage and modern urban sophistication. Nestled along the banks of the Isar River, Munich is renowned\n", - " for its splendid architecture, including the iconic Neues Rathaus (New Town Hall) at Marienplatz and\n", - " the grandeur of Nymphenburg Palace. The city is a haven for art enthusiasts, with world-class museums like the\n", - " Alte Pinakothek housing masterpieces by renowned artists. Munich is also famous for its lively beer gardens, where\n", - " locals and tourists gather to enjoy the city's famed beers and traditional Bavarian cuisine. The city's annual\n", - " Oktoberfest celebration, the world's largest beer festival, attracts millions of visitors from around the globe.\n", - " Beyond its cultural and culinary delights, Munich offers picturesque parks like the English Garden, providing a\n", - " serene escape within the heart of the bustling metropolis. Visitors are charmed by Munich's warm hospitality,\n", - " making it a must-visit destination for travelers seeking a taste of both old-world charm and contemporary allure.\"\"\"\n", - " )\n", - "]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "zMNy0tjtUh_L" - }, - "source": [ - "## Creating the Initial Pipeline Components\n", - "\n", - "First, define a prompt instructing the LLM to respond with the text `\"no_answer\"` if the provided documents do not offer enough context to answer the query. Next, initialize a [PromptBuilder](https://docs.haystack.deepset.ai/docs/promptbuilder) with that prompt. It's crucial that the LLM replies with `\"no_answer\"` as you will use this keyword to indicate that the query should be directed to the fallback web search route.\n", - "\n", - "As the LLM, you will use an [OpenAIGenerator](https://docs.haystack.deepset.ai/docs/openaigenerator) with the `gpt-4o-mini` model.\n", - "\n", - "> The provided prompt works effectively with the `gpt-4o-mini` model. If you prefer to use a different [Generator](https://docs.haystack.deepset.ai/docs/generators), you may need to update the prompt to provide clear instructions to your model." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "id": "nzhn2kDfqvbs" - }, - "outputs": [], - "source": [ - "from haystack.components.builders.prompt_builder import PromptBuilder\n", - "from haystack.components.generators import OpenAIGenerator\n", - "\n", - "prompt_template = \"\"\"\n", - "Answer the following query given the documents.\n", - "If the answer is not contained within the documents reply with 'no_answer'\n", - "Query: {{query}}\n", - "Documents:\n", - "{% for document in documents %}\n", - " {{document.content}}\n", - "{% endfor %}\n", - "\"\"\"\n", - "\n", - "prompt_builder = PromptBuilder(template=prompt_template)\n", - "llm = OpenAIGenerator(model=\"gpt-4o-mini\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "LepACkkWPsBx" - }, - "source": [ - "## Initializing the Web Search Components\n", - "\n", - "Initialize the necessary components for a web-based RAG application. Along with a `PromptBuilder` and an `OpenAIGenerator`, you will need a [SerperDevWebSearch](https://docs.haystack.deepset.ai/docs/serperdevwebsearch) to retrieve relevant documents for the query from the web.\n", - "\n", - "> If desired, you can use a different [Generator](https://docs.haystack.deepset.ai/docs/generators) for the web-based RAG branch of the pipeline." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "id": "VEYchFgQPxZ_" - }, - "outputs": [], - "source": [ - "from haystack.components.builders.prompt_builder import PromptBuilder\n", - "from haystack.components.generators import OpenAIGenerator\n", - "from haystack.components.websearch.serper_dev import SerperDevWebSearch\n", - "\n", - "prompt_for_websearch = \"\"\"\n", - "Answer the following query given the documents retrieved from the web.\n", - "Your answer shoud indicate that your answer was generated from websearch.\n", - "\n", - "Query: {{query}}\n", - "Documents:\n", - "{% for document in documents %}\n", - " {{document.content}}\n", - "{% endfor %}\n", - "\"\"\"\n", - "\n", - "websearch = SerperDevWebSearch()\n", - "prompt_builder_for_websearch = PromptBuilder(template=prompt_for_websearch)\n", - "llm_for_websearch = OpenAIGenerator(model=\"gpt-4o-mini\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "vnacak_tVWqv" - }, - "source": [ - "## Creating the ConditionalRouter\n", - "\n", - "[ConditionalRouter](https://docs.haystack.deepset.ai/docs/conditionalrouter) is the component that handles data routing on specific conditions. You need to define a `condition`, an `output`, an `output_name` and an `output_type` for each route. Each route that the `ConditionalRouter` creates acts as the output of this component and can be connected to other components in the same pipeline. \n", - "\n", - "In this case, you need to define two routes:\n", - "- If the LLM replies with the `\"no_answer\"` keyword, the pipeline should perform web search. It means that you will put the original `query` in the output value to pass to the next component (in this case the next component will be the `SerperDevWebSearch`) and the output name will be `go_to_websearch`.\n", - "- Otherwise, the given documents are enough for an answer and pipeline execution ends here. Return the LLM reply in the output named `answer`." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "id": "qyE9rGcawX3F" - }, - "outputs": [], - "source": [ - "from haystack.components.routers import ConditionalRouter\n", - "\n", - "routes = [\n", - " {\n", - " \"condition\": \"{{'no_answer' in replies[0]}}\",\n", - " \"output\": \"{{query}}\",\n", - " \"output_name\": \"go_to_websearch\",\n", - " \"output_type\": str,\n", - " },\n", - " {\n", - " \"condition\": \"{{'no_answer' not in replies[0]}}\",\n", - " \"output\": \"{{replies[0]}}\",\n", - " \"output_name\": \"answer\",\n", - " \"output_type\": str,\n", - " },\n", - "]\n", - "\n", - "router = ConditionalRouter(routes)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Wdyko78oXb5a" - }, - "source": [ - "## Building the Pipeline\n", - "\n", - "Add all components to your pipeline and connect them. `go_to_websearch` output of the `router` should be connected to the `websearch` to retrieve documents from the web and also to `prompt_builder_for_websearch` to use in the prompt." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "4sCyBwc0oTVs", - "outputId": "fd2347d4-9363-45e0-e734-87e4a160f741" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from haystack import Pipeline\n", - "\n", - "pipe = Pipeline()\n", - "pipe.add_component(\"prompt_builder\", prompt_builder)\n", - "pipe.add_component(\"llm\", llm)\n", - "pipe.add_component(\"router\", router)\n", - "pipe.add_component(\"websearch\", websearch)\n", - "pipe.add_component(\"prompt_builder_for_websearch\", prompt_builder_for_websearch)\n", - "pipe.add_component(\"llm_for_websearch\", llm_for_websearch)\n", - "\n", - "pipe.connect(\"prompt_builder\", \"llm\")\n", - "pipe.connect(\"llm.replies\", \"router.replies\")\n", - "pipe.connect(\"router.go_to_websearch\", \"websearch.query\")\n", - "pipe.connect(\"router.go_to_websearch\", \"prompt_builder_for_websearch.query\")\n", - "pipe.connect(\"websearch.documents\", \"prompt_builder_for_websearch.documents\")\n", - "pipe.connect(\"prompt_builder_for_websearch\", \"llm_for_websearch\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "d0HmdbUJKJ_9" - }, - "source": [ - "### Visualize the Pipeline\n", - "\n", - "To understand how you formed this pipeline with conditional routing, use [draw()](https://docs.haystack.deepset.ai/docs/drawing-pipeline-graphs) method of the pipeline. If you're running this notebook on Google Colab, the generated file will be saved in \\\"Files\\\" section on the sidebar." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 1000 - }, - "id": "svF_SUK4rFwv", - "outputId": "60894eea-2cec-4be8-d13c-83d2c81656f4" - }, - "outputs": [], - "source": [ - "pipe.draw(\"pipe.png\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "jgk1z6GGYH6J" - }, - "source": [ - "## Running the Pipeline!\n", - "\n", - "In the `run()`, pass the query to the `prompt_builder` and the `router`. In real life applications, `documents` will be provided by a [Retriever](https://docs.haystack.deepset.ai/docs/retrievers) but to keep this example simple, you will provide the defined `documents` to the `prompt_builder`." - ] - }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "IR5wivW8THt7" + }, + "source": [ + "# Tutorial: Building Fallbacks to Websearch with Conditional Routing\n", + "\n", + "- **Level**: Intermediate\n", + "- **Time to complete**: 10 minutes\n", + "- **Components Used**: [`ConditionalRouter`](https://docs.haystack.deepset.ai/docs/conditionalrouter), [`SerperDevWebSearch`](https://docs.haystack.deepset.ai/docs/serperdevwebsearch), [`ChatPromptBuilder`](https://docs.haystack.deepset.ai/docs/chatpromptbuilder), [`OpenAIChatGenerator`](https://docs.haystack.deepset.ai/docs/openaichatgenerator)\n", + "- **Prerequisites**: You must have an [OpenAI API Key](https://platform.openai.com/api-keys) and a [Serper API Key](https://serper.dev/api-key) for this tutorial\n", + "- **Goal**: After completing this tutorial, you'll have learned how to create a pipeline with conditional routing that can fallback to websearch if the answer is not present in your dataset.\n", + "\n", + "> This tutorial uses Haystack 2.0. To learn more, read the [Haystack 2.0 announcement](https://haystack.deepset.ai/blog/haystack-2-release) or visit the [Haystack 2.0 Documentation](https://docs.haystack.deepset.ai/docs/intro).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "F-a-MAMVat-o" + }, + "source": [ + "## Overview\n", + "\n", + "When developing applications using **retrieval augmented generation ([RAG](https://www.deepset.ai/blog/llms-retrieval-augmentation))**, the retrieval step plays a critical role. It serves as the primary information source for **large language models (LLMs)** to generate responses. However, if your database lacks the necessary information, the retrieval step's effectiveness is limited. In such scenarios, it may be practical to use the web as a fallback data source for your RAG application. By implementing a conditional routing mechanism in your system, you gain complete control over the data flow, enabling you to design a system that can leverage the web as its data source under some conditions.\n", + "\n", + "In this tutorial, you will learn how to create a pipeline with conditional routing that directs the query to a **web-based RAG** route if the answer is not found in the initially given documents." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LSwNKkeKeq0f" + }, + "source": [ + "## Development Environment" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eGJ7GmCBas4R" + }, + "source": [ + "### Prepare the Colab Environment\n", + "\n", + "- [Enable GPU Runtime in Colab](https://docs.haystack.deepset.ai/docs/enabling-gpu-acceleration)\n", + "- [Set logging level to INFO](https://docs.haystack.deepset.ai/docs/setting-the-log-level)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "FwIgIpE2XqpO" + }, + "source": [ + "### Install Haystack\n", + "\n", + "Install Haystack 2.0 with `pip`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "uba0mntlqs_O" + }, + "outputs": [], + "source": [ + "%%bash\n", + "\n", + "pip install haystack-ai" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "WBkJ7d3hZkOJ" + }, + "source": [ + "### Enable Telemetry\n", + "\n", + "Knowing you're using this tutorial helps us decide where to invest our efforts to build a better product but you can always opt out by commenting the following line. See [Telemetry](https://docs.haystack.deepset.ai/docs/telemetry) for more details." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "id": "HvrOixzzZmMi" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "d_l4rYmCoVki", - "outputId": "3bd7956a-7612-4bc1-c3e5-a7a51be8981f" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Munich is in southern Germany.\n" - ] - } - ], - "source": [ - "query = \"Where is Munich?\"\n", - "\n", - "result = pipe.run({\"prompt_builder\": {\"query\": query, \"documents\": documents}, \"router\": {\"query\": query}})\n", - "\n", - "# Print the `answer` coming from the ConditionalRouter\n", - "print(result[\"router\"][\"answer\"])" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/amna.mubashar/Library/Python/3.9/lib/python/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "from haystack.telemetry import tutorial_running\n", + "\n", + "tutorial_running(36)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "QfECEAy2Jdqs" + }, + "source": [ + "### Enter API Keys\n", + "\n", + "Enter API keys required for this tutorial." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "13U7Z_k3yE-F", + "outputId": "6ec48553-12d2-4c89-ca13-fc5d34fbc625" + }, + "outputs": [], + "source": [ + "from getpass import getpass\n", + "import os\n", + "\n", + "if \"OPENAI_API_KEY\" not in os.environ:\n", + " os.environ[\"OPENAI_API_KEY\"] = getpass(\"Enter OpenAI API key:\")\n", + "if \"SERPERDEV_API_KEY\" not in os.environ:\n", + " os.environ[\"SERPERDEV_API_KEY\"] = getpass(\"Enter Serper Api key: \")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "i_AlhPv1T-4t" + }, + "source": [ + "## Creating a Document\n", + "\n", + "Create a Document about Munich, where the answer to your question will be initially searched:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "id": "5CHbQlLMyVbg" + }, + "outputs": [], + "source": [ + "from haystack.dataclasses import Document\n", + "\n", + "documents = [\n", + " Document(\n", + " content=\"\"\"Munich, the vibrant capital of Bavaria in southern Germany, exudes a perfect blend of rich cultural\n", + " heritage and modern urban sophistication. Nestled along the banks of the Isar River, Munich is renowned\n", + " for its splendid architecture, including the iconic Neues Rathaus (New Town Hall) at Marienplatz and\n", + " the grandeur of Nymphenburg Palace. The city is a haven for art enthusiasts, with world-class museums like the\n", + " Alte Pinakothek housing masterpieces by renowned artists. Munich is also famous for its lively beer gardens, where\n", + " locals and tourists gather to enjoy the city's famed beers and traditional Bavarian cuisine. The city's annual\n", + " Oktoberfest celebration, the world's largest beer festival, attracts millions of visitors from around the globe.\n", + " Beyond its cultural and culinary delights, Munich offers picturesque parks like the English Garden, providing a\n", + " serene escape within the heart of the bustling metropolis. Visitors are charmed by Munich's warm hospitality,\n", + " making it a must-visit destination for travelers seeking a taste of both old-world charm and contemporary allure.\"\"\"\n", + " )\n", + "]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zMNy0tjtUh_L" + }, + "source": [ + "## Creating the Initial Pipeline Components\n", + "\n", + "First, define a prompt instructing the LLM to respond with the text `\"no_answer\"` if the provided documents do not offer enough context to answer the query. Next, initialize a [ChatPromptBuilder](https://docs.haystack.deepset.ai/docs/chatpromptbuilder) with that prompt. `ChatPromptBuilder`accepts prompts inf the form of `ChatMessage`. It's crucial that the LLM replies with `\"no_answer\"` as you will use this keyword to indicate that the query should be directed to the fallback web search route.\n", + "\n", + "As the LLM, you will use an [OpenAIChatGenerator](https://docs.haystack.deepset.ai/docs/openaichatgenerator) with the `gpt-4o-mini` model.\n", + "\n", + "> The provided prompt works effectively with the `gpt-4o-mini` model. If you prefer to use a different [ChatGenerator](https://docs.haystack.deepset.ai/docs/generators), you may need to update the prompt to provide clear instructions to your model." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "id": "nzhn2kDfqvbs" + }, + "outputs": [], + "source": [ + "from haystack.components.builders import ChatPromptBuilder\n", + "from haystack.dataclasses import ChatMessage\n", + "from haystack.components.generators.chat import OpenAIChatGenerator\n", + "\n", + "prompt_template = [ChatMessage.from_user(\"\"\"\n", + "Answer the following query given the documents.\n", + "If the answer is not contained within the documents reply with 'no_answer'\n", + "Query: {{query}}\n", + "Documents:\n", + "{% for document in documents %}\n", + " {{document.content}}\n", + "{% endfor %}\n", + "\"\"\")]\n", + "\n", + "prompt_builder = ChatPromptBuilder(template=prompt_template)\n", + "llm = OpenAIChatGenerator(model=\"gpt-4o-mini\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LepACkkWPsBx" + }, + "source": [ + "## Initializing the Web Search Components\n", + "\n", + "Initialize the necessary components for a web-based RAG application. Along with a `ChatPromptBuilder` and an `OpenAIChatGenerator`, you will need a [SerperDevWebSearch](https://docs.haystack.deepset.ai/docs/serperdevwebsearch) to retrieve relevant documents for the query from the web.\n", + "\n", + "> If desired, you can use a different [ChatGenerator](https://docs.haystack.deepset.ai/docs/generators) for the web-based RAG branch of the pipeline." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "id": "VEYchFgQPxZ_" + }, + "outputs": [], + "source": [ + "\n", + "from haystack.components.websearch.serper_dev import SerperDevWebSearch\n", + "\n", + "prompt_for_websearch = [ChatMessage.from_user(\"\"\"\n", + "Answer the following query given the documents retrieved from the web.\n", + "Your answer shoud indicate that your answer was generated from websearch.\n", + "\n", + "Query: {{query}}\n", + "Documents:\n", + "{% for document in documents %}\n", + " {{document.content}}\n", + "{% endfor %}\n", + "\"\"\")]\n", + "\n", + "websearch = SerperDevWebSearch()\n", + "prompt_builder_for_websearch = ChatPromptBuilder(template=prompt_for_websearch)\n", + "llm_for_websearch = OpenAIChatGenerator(model=\"gpt-4o-mini\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vnacak_tVWqv" + }, + "source": [ + "## Creating the ConditionalRouter\n", + "\n", + "[ConditionalRouter](https://docs.haystack.deepset.ai/docs/conditionalrouter) is the component that handles data routing on specific conditions. You need to define a `condition`, an `output`, an `output_name` and an `output_type` for each route. Each route that the `ConditionalRouter` creates acts as the output of this component and can be connected to other components in the same pipeline. \n", + "\n", + "In this case, you need to define two routes:\n", + "- If the LLM replies with the `\"no_answer\"` keyword, the pipeline should perform web search. It means that you will put the original `query` in the output value to pass to the next component (in this case the next component will be the `SerperDevWebSearch`) and the output name will be `go_to_websearch`.\n", + "- Otherwise, the given documents are enough for an answer and pipeline execution ends here. Return the LLM reply in the output named `answer`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "qyE9rGcawX3F" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "dBN8eLSKgb16" - }, - "source": [ - "✅ The answer to this query can be found in the defined document.\n", - "\n", - "Now, try a different query that doesn't have an answer in the given document and test if the web search works as expected:" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/amna.mubashar/Library/Python/3.9/lib/python/site-packages/pypdf/_crypt_providers/_cryptography.py:32: CryptographyDeprecationWarning: ARC4 has been moved to cryptography.hazmat.decrepit.ciphers.algorithms.ARC4 and will be removed from this module in 48.0.0.\n", + " from cryptography.hazmat.primitives.ciphers.algorithms import AES, ARC4\n" + ] + } + ], + "source": [ + "from haystack.components.routers import ConditionalRouter\n", + "\n", + "routes = [\n", + " {\n", + " \"condition\": \"{{'no_answer' in replies[0].text}}\",\n", + " \"output\": \"{{query}}\",\n", + " \"output_name\": \"go_to_websearch\",\n", + " \"output_type\": str,\n", + " },\n", + " {\n", + " \"condition\": \"{{'no_answer' not in replies[0].text}}\",\n", + " \"output\": \"{{replies[0].text}}\",\n", + " \"output_name\": \"answer\",\n", + " \"output_type\": str,\n", + " },\n", + "]\n", + "\n", + "router = ConditionalRouter(routes)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Wdyko78oXb5a" + }, + "source": [ + "## Building the Pipeline\n", + "\n", + "Add all components to your pipeline and connect them. `go_to_websearch` output of the `router` should be connected to the `websearch` to retrieve documents from the web and also to `prompt_builder_for_websearch` to use in the prompt." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "4sCyBwc0oTVs", + "outputId": "fd2347d4-9363-45e0-e734-87e4a160f741" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "_v-WdlSy365M", - "outputId": "603c9346-8718-427e-d232-4cc71799a2bb" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['According to the documents retrieved from the web, the population of Munich is approximately 1.47 million as of 2019. However, the most recent estimates suggest that the population has grown to about 1.58 million as of May 31, 2022. Additionally, the current estimated population of Munich is around 1.46 million, with the urban area being much larger at 2.65 million.']\n" - ] - } - ], - "source": [ - "query = \"How many people live in Munich?\"\n", - "\n", - "result = pipe.run({\"prompt_builder\": {\"query\": query, \"documents\": documents}, \"router\": {\"query\": query}})\n", - "\n", - "# Print the `replies` generated using the web searched Documents\n", - "print(result[\"llm_for_websearch\"][\"replies\"])" + "data": { + "text/plain": [ + "\n", + "🚅 Components\n", + " - prompt_builder: ChatPromptBuilder\n", + " - llm: OpenAIChatGenerator\n", + " - router: ConditionalRouter\n", + " - websearch: SerperDevWebSearch\n", + " - prompt_builder_for_websearch: ChatPromptBuilder\n", + " - llm_for_websearch: OpenAIChatGenerator\n", + "🛤️ Connections\n", + " - prompt_builder.prompt -> llm.messages (List[ChatMessage])\n", + " - llm.replies -> router.replies (List[ChatMessage])\n", + " - router.go_to_websearch -> websearch.query (str)\n", + " - router.go_to_websearch -> prompt_builder_for_websearch.query (str)\n", + " - websearch.documents -> prompt_builder_for_websearch.documents (List[Document])\n", + " - prompt_builder_for_websearch.prompt -> llm_for_websearch.messages (List[ChatMessage])" ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from haystack import Pipeline\n", + "\n", + "pipe = Pipeline()\n", + "pipe.add_component(\"prompt_builder\", prompt_builder)\n", + "pipe.add_component(\"llm\", llm)\n", + "pipe.add_component(\"router\", router)\n", + "pipe.add_component(\"websearch\", websearch)\n", + "pipe.add_component(\"prompt_builder_for_websearch\", prompt_builder_for_websearch)\n", + "pipe.add_component(\"llm_for_websearch\", llm_for_websearch)\n", + "\n", + "pipe.connect(\"prompt_builder.prompt\", \"llm.messages\")\n", + "pipe.connect(\"llm.replies\", \"router.replies\")\n", + "pipe.connect(\"router.go_to_websearch\", \"websearch.query\")\n", + "pipe.connect(\"router.go_to_websearch\", \"prompt_builder_for_websearch.query\")\n", + "pipe.connect(\"websearch.documents\", \"prompt_builder_for_websearch.documents\")\n", + "pipe.connect(\"prompt_builder_for_websearch\", \"llm_for_websearch\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "d0HmdbUJKJ_9" + }, + "source": [ + "### Visualize the Pipeline\n", + "\n", + "To understand how you formed this pipeline with conditional routing, use [draw()](https://docs.haystack.deepset.ai/docs/drawing-pipeline-graphs) method of the pipeline. If you're running this notebook on Google Colab, the generated file will be saved in \\\"Files\\\" section on the sidebar." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 }, - { - "cell_type": "markdown", - "metadata": { - "id": "wUkuXoWnHa5c" - }, - "source": [ - "If you check the whole result, you will see that `websearch` component also provides links to Documents retrieved from the web:" - ] + "id": "svF_SUK4rFwv", + "outputId": "60894eea-2cec-4be8-d13c-83d2c81656f4" + }, + "outputs": [], + "source": [ + "pipe.draw(\"pipe.png\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jgk1z6GGYH6J" + }, + "source": [ + "## Running the Pipeline!\n", + "\n", + "In the `run()`, pass the query to the `prompt_builder` and the `router`. In real life applications, `documents` will be provided by a [Retriever](https://docs.haystack.deepset.ai/docs/retrievers) but to keep this example simple, you will provide the defined `documents` to the `prompt_builder`." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "d_l4rYmCoVki", + "outputId": "3bd7956a-7612-4bc1-c3e5-a7a51be8981f" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "_EYLZguZGznY", - "outputId": "df49a576-9961-44b4-e89d-2c5195869360" - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{'llm': {'meta': [{'model': 'gpt-4o-mini-2024-07-18',\n", - " 'index': 0,\n", - " 'finish_reason': 'stop',\n", - " 'usage': {'completion_tokens': 2,\n", - " 'prompt_tokens': 271,\n", - " 'total_tokens': 273}}]},\n", - " 'websearch': {'links': ['https://en.wikipedia.org/wiki/Munich',\n", - " 'https://worldpopulationreview.com/world-cities/munich-population',\n", - " 'https://en.wikipedia.org/wiki/Demographics_of_Munich',\n", - " 'https://www.macrotrends.net/cities/204371/munich/population',\n", - " 'https://www.britannica.com/place/Munich-Bavaria-Germany',\n", - " 'https://www.statista.com/statistics/519723/munich-population-by-age-group/',\n", - " 'https://www.citypopulation.de/en/germany/bayern/m%C3%BCnchen_stadt/09162000__m%C3%BCnchen/',\n", - " 'https://www.quora.com/How-many-people-live-in-Munich',\n", - " 'https://earth.esa.int/web/earth-watching/image-of-the-week/content/-/article/munich-germany/']},\n", - " 'llm_for_websearch': {'replies': ['According to the documents retrieved from the web, the population of Munich is approximately 1.47 million as of 2019. However, the most recent estimates suggest that the population has grown to about 1.58 million as of May 31, 2022. Additionally, the current estimated population of Munich is around 1.46 million, with the urban area being much larger at 2.65 million.'],\n", - " 'meta': [{'model': 'gpt-4o-mini-2024-07-18',\n", - " 'index': 0,\n", - " 'finish_reason': 'stop',\n", - " 'usage': {'completion_tokens': 85,\n", - " 'prompt_tokens': 436,\n", - " 'total_tokens': 521}}]}}" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "result" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Munich is located in southern Germany.\n" + ] + } + ], + "source": [ + "query = \"Where is Munich?\"\n", + "\n", + "result = pipe.run({\"prompt_builder\": {\"query\": query, \"documents\": documents}, \"router\": {\"query\": query}})\n", + "\n", + "# Print the `answer` coming from the ConditionalRouter\n", + "print(result[\"router\"][\"answer\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dBN8eLSKgb16" + }, + "source": [ + "✅ The answer to this query can be found in the defined document.\n", + "\n", + "Now, try a different query that doesn't have an answer in the given document and test if the web search works as expected:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "_v-WdlSy365M", + "outputId": "603c9346-8718-427e-d232-4cc71799a2bb" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "6nhdYK-vHpNM" - }, - "source": [ - "## What's next\n", - "\n", - "🎉 Congratulations! You've built a pipeline with conditional routing! You can now customize the condition for your specific use case and create a custom Haystack 2.0 pipeline to meet your needs.\n", - "\n", - "If you liked this tutorial, there's more to learn about Haystack 2.0:\n", - "- [Creating Your First QA Pipeline with Retrieval-Augmentation](https://haystack.deepset.ai/tutorials/27_first_rag_pipeline)\n", - "- [Model-Based Evaluation of RAG Pipelines](https://haystack.deepset.ai/tutorials/35_model_based_evaluation_of_rag_pipelines)\n", - "\n", - "To stay up to date on the latest Haystack developments, you can [sign up for our newsletter](https://landing.deepset.ai/haystack-community-updates) or [join Haystack discord community](https://discord.gg/haystack).\n", - "\n", - "Thanks for reading!" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "[ChatMessage(content='As of May 31, 2024, Munich has a population of approximately 1,594,632 residents, making it the third-largest city in Germany, after Berlin and Hamburg. The metro area population is about 1,585,000, reflecting a modest increase from the previous year. Additionally, estimates suggest that the city has consistently had over 1.5 million inhabitants in recent years. This information has been gathered from various web sources.', role=, name=None, meta={'model': 'gpt-4o-mini-2024-07-18', 'index': 0, 'finish_reason': 'stop', 'usage': {'completion_tokens': 91, 'prompt_tokens': 401, 'total_tokens': 492, 'prompt_tokens_details': {'cached_tokens': 0, 'audio_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0, 'audio_tokens': 0, 'accepted_prediction_tokens': 0, 'rejected_prediction_tokens': 0}}})]\n" + ] } - ], - "metadata": { + ], + "source": [ + "query = \"How many people live in Munich?\"\n", + "\n", + "result = pipe.run({\"prompt_builder\": {\"query\": query, \"documents\": documents}, \"router\": {\"query\": query}})\n", + "\n", + "# Print the `replies` generated using the web searched Documents\n", + "print(result[\"llm_for_websearch\"][\"replies\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wUkuXoWnHa5c" + }, + "source": [ + "If you check the whole result, you will see that `websearch` component also provides links to Documents retrieved from the web:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { "colab": { - "provenance": [] + "base_uri": "https://localhost:8080/" }, - "kernelspec": { - "display_name": "Python 3", - "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.9.6" + "id": "_EYLZguZGznY", + "outputId": "df49a576-9961-44b4-e89d-2c5195869360" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'websearch': {'links': ['https://en.wikipedia.org/wiki/Munich',\n", + " 'https://www.macrotrends.net/cities/204371/munich/population',\n", + " 'https://www.britannica.com/place/Munich-Bavaria-Germany',\n", + " 'https://en.wikipedia.org/wiki/Demographics_of_Munich',\n", + " 'https://www.statista.com/statistics/505774/munich-population/',\n", + " 'https://www.citypopulation.de/en/germany/bayern/m%C3%BCnchen_stadt/09162000__m%C3%BCnchen/',\n", + " 'https://eurocities.eu/cities/munich/',\n", + " 'https://www.coe.int/en/web/interculturalcities/munich',\n", + " 'https://www.worldometers.info/world-population/germany-population/']},\n", + " 'llm_for_websearch': {'replies': [ChatMessage(content='As of May 31, 2024, Munich has a population of approximately 1,594,632 residents, making it the third-largest city in Germany, after Berlin and Hamburg. The metro area population is about 1,585,000, reflecting a modest increase from the previous year. Additionally, estimates suggest that the city has consistently had over 1.5 million inhabitants in recent years. This information has been gathered from various web sources.', role=, name=None, meta={'model': 'gpt-4o-mini-2024-07-18', 'index': 0, 'finish_reason': 'stop', 'usage': {'completion_tokens': 91, 'prompt_tokens': 401, 'total_tokens': 492, 'prompt_tokens_details': {'cached_tokens': 0, 'audio_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0, 'audio_tokens': 0, 'accepted_prediction_tokens': 0, 'rejected_prediction_tokens': 0}}})]}}" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" } + ], + "source": [ + "result" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6nhdYK-vHpNM" + }, + "source": [ + "## What's next\n", + "\n", + "🎉 Congratulations! You've built a pipeline with conditional routing! You can now customize the condition for your specific use case and create a custom Haystack 2.0 pipeline to meet your needs.\n", + "\n", + "If you liked this tutorial, there's more to learn about Haystack 2.0:\n", + "- [Creating Your First QA Pipeline with Retrieval-Augmentation](https://haystack.deepset.ai/tutorials/27_first_rag_pipeline)\n", + "- [Model-Based Evaluation of RAG Pipelines](https://haystack.deepset.ai/tutorials/35_model_based_evaluation_of_rag_pipelines)\n", + "\n", + "To stay up to date on the latest Haystack developments, you can [sign up for our newsletter](https://landing.deepset.ai/haystack-community-updates) or [join Haystack discord community](https://discord.gg/haystack).\n", + "\n", + "Thanks for reading!" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 0 + "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.9.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 } diff --git a/tutorials/40_Building_Chat_Application_with_Function_Calling.ipynb b/tutorials/40_Building_Chat_Application_with_Function_Calling.ipynb index 1f1201bd..6bc53f86 100644 --- a/tutorials/40_Building_Chat_Application_with_Function_Calling.ipynb +++ b/tutorials/40_Building_Chat_Application_with_Function_Calling.ipynb @@ -10,7 +10,7 @@ "\n", "- **Level**: Advanced\n", "- **Time to complete**: 20 minutes\n", - "- **Components Used**: [InMemoryDocumentStore](https://docs.haystack.deepset.ai/docs/inmemorydocumentstore), [SentenceTransformersDocumentEmbedder](https://docs.haystack.deepset.ai/docs/sentencetransformersdocumentembedder), [SentenceTransformersTextEmbedder](https://docs.haystack.deepset.ai/docs/sentencetransformerstextembedder), [InMemoryEmbeddingRetriever](https://docs.haystack.deepset.ai/docs/inmemoryembeddingretriever), [PromptBuilder](https://docs.haystack.deepset.ai/docs/promptbuilder), [OpenAIGenerator](https://docs.haystack.deepset.ai/docs/openaigenerator), [OpenAIChatGenerator](https://docs.haystack.deepset.ai/docs/openaichatgenerator)\n", + "- **Components Used**: [InMemoryDocumentStore](https://docs.haystack.deepset.ai/docs/inmemorydocumentstore), [SentenceTransformersDocumentEmbedder](https://docs.haystack.deepset.ai/docs/sentencetransformersdocumentembedder), [SentenceTransformersTextEmbedder](https://docs.haystack.deepset.ai/docs/sentencetransformerstextembedder), [InMemoryEmbeddingRetriever](https://docs.haystack.deepset.ai/docs/inmemoryembeddingretriever), [ChatPromptBuilder](https://docs.haystack.deepset.ai/docs/chatpromptbuilder), [OpenAIChatGenerator](https://docs.haystack.deepset.ai/docs/openaichatgenerator)\n", "- **Prerequisites**: You must have an [OpenAI API Key](https://platform.openai.com/api-keys) and be familiar with [creating pipelines](https://docs.haystack.deepset.ai/docs/creating-pipelines)\n", "- **Goal**: After completing this tutorial, you will have learned how to build chat applications that demonstrate agent-like behavior using OpenAI's function calling feature.\n", "\n", @@ -75,11 +75,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { "id": "9V0-VuEgwt2u" }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/amna.mubashar/Library/Python/3.9/lib/python/site-packages/urllib3/__init__.py:35: NotOpenSSLWarning: urllib3 v2 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'LibreSSL 2.8.3'. See: https://github.com/urllib3/urllib3/issues/3020\n", + " warnings.warn(\n", + "/Users/amna.mubashar/Library/Python/3.9/lib/python/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], "source": [ "from haystack.telemetry import tutorial_running\n", "\n", @@ -97,7 +108,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "id": "WM-sVkYonutA" }, @@ -138,7 +149,7 @@ { "data": { "text/plain": [ - "{'replies': [ChatMessage(content='Natürliche Sprachverarbeitung (NLP) ist ein Bereich der künstlichen Intelligenz, der sich mit der Wechselwirkung zwischen Menschensprache und Maschinen befasst. Es zielt darauf ab, Computern das Verstehen, Interpretieren und Generieren menschlicher Sprache zu ermöglichen.', role=, name=None, meta={'model': 'gpt-4o-mini-2024-07-18', 'index': 0, 'finish_reason': 'stop', 'usage': {'completion_tokens': 74, 'prompt_tokens': 34, 'total_tokens': 108}})]}" + "{'replies': [ChatMessage(content='Natural Language Processing (NLP) ist ein Teilbereich der Künstlichen Intelligenz, der sich mit der Interaktion zwischen Computern und menschlicher Sprache beschäftigt. Ziel ist es, Maschinen zu ermöglichen, Text und Sprache in einer für Menschen verständlichen Weise zu verstehen, zu interpretieren und zu erzeugen.', role=, name=None, meta={'model': 'gpt-4o-mini-2024-07-18', 'index': 0, 'finish_reason': 'stop', 'usage': {'completion_tokens': 63, 'prompt_tokens': 33, 'total_tokens': 96, 'prompt_tokens_details': {'cached_tokens': 0, 'audio_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0, 'audio_tokens': 0, 'accepted_prediction_tokens': 0, 'rejected_prediction_tokens': 0}}})]}" ] }, "execution_count": 4, @@ -185,12 +196,11 @@ "name": "stdout", "output_type": "stream", "text": [ - "Natural Language Processing (NLP) ist ein Bereich der künstlichen Intelligenz, der sich mit dem Verstehen und der Verarbeitung von menschlicher Sprache durch Computer befasst." + "Natural Language Processing (NLP) ist ein Bereich der künstlichen Intelligenz, der sich mit der Interaktion zwischen Computern und Menschen in natürlicher Sprache beschäftigt. Ziel ist es, Maschinen zu befähigen, Texte und gesprochene Sprache zu verstehen, zu interpretieren und darauf zu reagieren." ] } ], "source": [ - "from haystack.dataclasses import ChatMessage\n", "from haystack.components.generators.chat import OpenAIChatGenerator\n", "from haystack.components.generators.utils import print_streaming_chunk\n", "\n", @@ -376,190 +386,11 @@ "name": "stderr", "output_type": "stream", "text": [ - "/usr/local/lib/python3.10/dist-packages/huggingface_hub/utils/_token.py:88: UserWarning: \n", - "The secret `HF_TOKEN` does not exist in your Colab secrets.\n", - "To authenticate with the Hugging Face Hub, create a token in your settings tab (https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session.\n", - "You will be able to reuse this secret in all of your notebooks.\n", - "Please note that authentication is recommended but still optional to access public models or datasets.\n", - " warnings.warn(\n" + "/Users/amna.mubashar/Library/Python/3.9/lib/python/site-packages/huggingface_hub/file_download.py:1132: FutureWarning: `resume_download` is deprecated and will be removed in version 1.0.0. Downloads always resume when possible. If you want to force a new download, use `force_download=True`.\n", + " warnings.warn(\n", + "Batches: 100%|██████████| 1/1 [00:01<00:00, 1.11s/it]\n" ] }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "041743b7cebb47458bfa61e945699655", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "modules.json: 0%| | 0.00/349 [00:00 For a step-by-step guide to create a RAG pipeline with Haystack, follow the [Creating Your First QA Pipeline with Retrieval-Augmentation](https://haystack.deepset.ai/tutorials/27_first_rag_pipeline) tutorial." ] @@ -625,18 +456,19 @@ "outputs": [ { "data": { - "image/jpeg": "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", "text/plain": [ - "" + "\n", + "🚅 Components\n", + " - embedder: SentenceTransformersTextEmbedder\n", + " - retriever: InMemoryEmbeddingRetriever\n", + " - prompt_builder: ChatPromptBuilder\n", + " - llm: OpenAIChatGenerator\n", + "🛤️ Connections\n", + " - embedder.embedding -> retriever.query_embedding (List[float])\n", + " - retriever.documents -> prompt_builder.documents (List[Document])\n", + " - prompt_builder.prompt -> llm.messages (List[ChatMessage])" ] }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [] - }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" @@ -645,10 +477,11 @@ "source": [ "from haystack.components.embedders import SentenceTransformersTextEmbedder\n", "from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever\n", - "from haystack.components.builders import PromptBuilder\n", - "from haystack.components.generators import OpenAIGenerator\n", + "from haystack.components.builders import ChatPromptBuilder\n", + "from haystack.dataclasses import ChatMessage\n", + "from haystack.components.generators.chat import OpenAIChatGenerator\n", "\n", - "template = \"\"\"\n", + "template = [ChatMessage.from_system(\"\"\"\n", "Answer the questions based on the given context.\n", "\n", "Context:\n", @@ -657,16 +490,16 @@ "{% endfor %}\n", "Question: {{ question }}\n", "Answer:\n", - "\"\"\"\n", + "\"\"\")]\n", "rag_pipe = Pipeline()\n", "rag_pipe.add_component(\"embedder\", SentenceTransformersTextEmbedder(model=\"sentence-transformers/all-MiniLM-L6-v2\"))\n", "rag_pipe.add_component(\"retriever\", InMemoryEmbeddingRetriever(document_store=document_store))\n", - "rag_pipe.add_component(\"prompt_builder\", PromptBuilder(template=template))\n", - "rag_pipe.add_component(\"llm\", OpenAIGenerator(model=\"gpt-4o-mini\"))\n", + "rag_pipe.add_component(\"prompt_builder\", ChatPromptBuilder(template=template))\n", + "rag_pipe.add_component(\"llm\", OpenAIChatGenerator(model=\"gpt-4o-mini\"))\n", "\n", "rag_pipe.connect(\"embedder.embedding\", \"retriever.query_embedding\")\n", "rag_pipe.connect(\"retriever\", \"prompt_builder.documents\")\n", - "rag_pipe.connect(\"prompt_builder\", \"llm\")" + "rag_pipe.connect(\"prompt_builder.prompt\", \"llm.messages\")" ] }, { @@ -705,29 +538,16 @@ }, "outputs": [ { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "6f4a57e2a1ea45bd98c7b93dd44f7059", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Batches: 0%| | 0/1 [00:00, name=None, meta={'model': 'gpt-4o-mini-2024-07-18', 'index': 0, 'finish_reason': 'stop', 'usage': {'completion_tokens': 5, 'prompt_tokens': 83, 'total_tokens': 88, 'prompt_tokens_details': {'cached_tokens': 0, 'audio_tokens': 0}, 'completion_tokens_details': {'reasoning_tokens': 0, 'audio_tokens': 0, 'accepted_prediction_tokens': 0, 'rejected_prediction_tokens': 0}}})]}}" ] }, "execution_count": 8, @@ -762,7 +582,7 @@ "def rag_pipeline_func(query: str):\n", " result = rag_pipe.run({\"embedder\": {\"text\": query}, \"prompt_builder\": {\"question\": query}})\n", "\n", - " return {\"reply\": result[\"llm\"][\"replies\"][0]}" + " return {\"reply\": result[\"llm\"][\"replies\"][0].content}" ] }, { @@ -926,7 +746,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 13, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -958,18 +778,11 @@ ] }, { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "910f6e07a2b843158e74a297f4934f97", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Batches: 0%| | 0/1 [00:00