📘 **TELUS Agriculture & Consumer Goods** 如何通过 **Haystack Agents** 转变促销交易

教程:构建带网络搜索回退的 Agentic RAG


概述

在开发使用检索增强生成 ( RAG) 的应用程序时,检索步骤起着至关重要的作用。它是大型语言模型 (LLM) 生成响应的主要信息来源。但是,如果您的数据库中缺少必要的信息,检索步骤的有效性将受到限制。在这种情况下,将agentic 行为融入其中,并将网络作为 RAG 应用程序的回退数据源可能很实用。通过在系统中实现条件路由机制,您可以完全控制数据流,从而能够设计一个在某些条件下可以利用网络作为其数据源的系统。

在本教程中,您将学习如何构建一个 agentic RAG 管道,该管道具有条件路由功能,如果答案在最初提供的文档中找不到,则会将查询定向到基于网络的 RAG 路由。

开发环境

准备 Colab 环境

安装 Haystack

使用 pip 安装 Haystack

%%bash

pip install haystack-ai

输入 API 密钥

输入本教程所需的 API 密钥。

from getpass import getpass
import os

if "OPENAI_API_KEY" not in os.environ:
    os.environ["OPENAI_API_KEY"] = getpass("Enter OpenAI API key:")
if "SERPERDEV_API_KEY" not in os.environ:
    os.environ["SERPERDEV_API_KEY"] = getpass("Enter Serper Api key: ")

填充文档存储

创建有关慕尼黑的文档,您的问题的答案将在此文档中进行初步搜索,并将其写入 InMemoryDocumentStore

from haystack.dataclasses import Document
from haystack.document_stores.in_memory import InMemoryDocumentStore

document_store = InMemoryDocumentStore()

documents = [
    Document(
        content="""Munich, the vibrant capital of Bavaria in southern Germany, exudes a perfect blend of rich cultural
                                heritage and modern urban sophistication. Nestled along the banks of the Isar River, Munich is renowned
                                for its splendid architecture, including the iconic Neues Rathaus (New Town Hall) at Marienplatz and
                                the grandeur of Nymphenburg Palace. The city is a haven for art enthusiasts, with world-class museums like the
                                Alte Pinakothek housing masterpieces by renowned artists. Munich is also famous for its lively beer gardens, where
                                locals and tourists gather to enjoy the city's famed beers and traditional Bavarian cuisine. The city's annual
                                Oktoberfest celebration, the world's largest beer festival, attracts millions of visitors from around the globe.
                                Beyond its cultural and culinary delights, Munich offers picturesque parks like the English Garden, providing a
                                serene escape within the heart of the bustling metropolis. Visitors are charmed by Munich's warm hospitality,
                                making it a must-visit destination for travelers seeking a taste of both old-world charm and contemporary allure."""
    )
]

document_store.write_documents(documents)

创建初始 RAG 管道组件

首先,您需要初始化一个 RAG 管道的组件。为此,请定义一个提示,指示 LLM 如果提供的文档没有提供足够的上下文来回答查询,则回复文本 "no_answer"。接下来,使用该提示初始化一个 ChatPromptBuilderChatPromptBuilder 接受 ChatMessage 形式的提示。LLM 回复 "no_answer" 至关重要,因为您将使用此关键字来指示查询应被定向到回退网络搜索路由。

作为 LLM,您将使用一个具有 gpt-4o-mini 模型的 OpenAIChatGenerator

提供的提示与 gpt-4o-mini 模型配合效果很好。如果您希望使用不同的 ChatGenerator,则可能需要更新提示以向您的模型提供清晰的说明。

from haystack.components.builders import ChatPromptBuilder
from haystack.dataclasses import ChatMessage
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.retrievers.in_memory import InMemoryBM25Retriever

retriever = InMemoryBM25Retriever(document_store)

prompt_template = [
    ChatMessage.from_user(
        """
Answer the following query given the documents.
If the answer is not contained within the documents reply with 'no_answer'

Documents:
{% for document in documents %}
  {{document.content}}
{% endfor %}
Query: {{query}}
"""
    )
]

prompt_builder = ChatPromptBuilder(template=prompt_template, required_variables="*")
llm = OpenAIChatGenerator(model="gpt-4o-mini")

初始化 Web-RAG 组件

初始化基于网络的 RAG 应用程序所需的组件。除了 ChatPromptBuilderOpenAIChatGenerator 之外,您还需要一个 SerperDevWebSearch 来从网络检索与查询相关的文档。

如果需要,您可以在管道的基于网络的 RAG 分支中使用不同的 ChatGenerator

from haystack.components.websearch.serper_dev import SerperDevWebSearch

prompt_for_websearch = [
    ChatMessage.from_user(
        """
Answer the following query given the documents retrieved from the web.
Your answer should indicate that your answer was generated from websearch.

Documents:
{% for document in documents %}
  {{document.content}}
{% endfor %}

Query: {{query}}
"""
    )
]

websearch = SerperDevWebSearch()
prompt_builder_for_websearch = ChatPromptBuilder(template=prompt_for_websearch, required_variables="*")
llm_for_websearch = OpenAIChatGenerator(model="gpt-4o-mini")

创建 ConditionalRouter

ConditionalRouter 是实现 agentic 行为并根据特定条件处理数据路由的关键组件。您需要为每个路由定义一个 condition、一个 output、一个 output_name 和一个 output_typeConditionalRouter 创建的每个路由都充当该组件的输出,并且可以连接到同一管道中的其他组件。

在这种情况下,您需要定义两个路由

  • 如果 LLM 回复 "no_answer" 关键字,管道应执行网络搜索。这意味着您将原始 query 放入输出值以传递给下一个组件(在本例中,下一个组件将是 SerperDevWebSearch),并且输出名称将是 go_to_websearch
  • 否则,提供的文档足以给出答案,管道执行在此结束。以名为 answer 的输出返回 LLM 的回复。
from haystack.components.routers import ConditionalRouter

routes = [
    {
        "condition": "{{'no_answer' in replies[0].text}}",
        "output": "{{query}}",
        "output_name": "go_to_websearch",
        "output_type": str,
    },
    {
        "condition": "{{'no_answer' not in replies[0].text}}",
        "output": "{{replies[0].text}}",
        "output_name": "answer",
        "output_type": str,
    },
]

router = ConditionalRouter(routes)

构建 Agentic RAG 管道

将所有组件添加到管道并连接它们。routergo_to_websearch 输出应连接到 websearch 以从网络检索文档,也连接到 prompt_builder_for_websearch 以在提示中使用。

from haystack import Pipeline

agentic_rag_pipe = Pipeline()
agentic_rag_pipe.add_component("retriever", retriever)
agentic_rag_pipe.add_component("prompt_builder", prompt_builder)
agentic_rag_pipe.add_component("llm", llm)
agentic_rag_pipe.add_component("router", router)
agentic_rag_pipe.add_component("websearch", websearch)
agentic_rag_pipe.add_component("prompt_builder_for_websearch", prompt_builder_for_websearch)
agentic_rag_pipe.add_component("llm_for_websearch", llm_for_websearch)

agentic_rag_pipe.connect("retriever", "prompt_builder.documents")
agentic_rag_pipe.connect("prompt_builder.prompt", "llm.messages")
agentic_rag_pipe.connect("llm.replies", "router.replies")
agentic_rag_pipe.connect("router.go_to_websearch", "websearch.query")
agentic_rag_pipe.connect("router.go_to_websearch", "prompt_builder_for_websearch.query")
agentic_rag_pipe.connect("websearch.documents", "prompt_builder_for_websearch.documents")
agentic_rag_pipe.connect("prompt_builder_for_websearch", "llm_for_websearch")

可视化管道

为了理解您如何通过条件路由构建此管道,请使用管道的 show() 方法。

# agentic_rag_pipe.show()

运行管道!

run() 中,将查询传递给 retrieverprompt_builderrouter

query = "Where is Munich?"

result = agentic_rag_pipe.run(
    {"retriever": {"query": query}, "prompt_builder": {"query": query}, "router": {"query": query}}
)

# Print the `answer` coming from the ConditionalRouter
print(result["router"]["answer"])

✅ 此查询的答案可以在定义的文档中找到。

现在,尝试一个在给定文档中没有答案的不同查询,并测试网络搜索是否按预期工作

query = "How many people live in Munich?"

result = agentic_rag_pipe.run(
    {"retriever": {"query": query}, "prompt_builder": {"query": query}, "router": {"query": query}}
)

# Print the `replies` generated using the web searched Documents
print(result["llm_for_websearch"]["replies"][0].text)

如果您检查整个结果,您会发现 websearch 组件还提供了从网络检索到的文档链接

result

下一步

🎉 恭喜!您已经构建了一个带条件路由的 agentic RAG 管道!您现在可以根据特定用例自定义条件,并创建自定义 Haystack 管道以满足您的需求。

如果您喜欢本教程,还有更多关于 Haystack 的内容可以学习。

要随时了解最新的 Haystack 发展,您可以 订阅我们的时事通讯加入 Haystack discord 社区

感谢阅读!