开源 AI 食谱文档

多智能体 RAG 系统 🤖🤝🤖

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

Open In Colab

多智能体 RAG 系统 🤖🤝🤖

作者: Sergio Paniego

🚨 注意:本教程是高级教程。在深入学习之前,您应该对以下食谱中讨论的概念有扎实的理解

在本笔记本中,我们将创建一个多智能体 RAG 系统,这是一个由多个智能体协作检索和生成信息的系统,结合了检索式系统生成模型的优势。

什么是多智能体 RAG 系统?🤔

一个多智能体检索增强生成(RAG)系统由多个协作执行复杂任务的智能体组成。检索智能体检索相关文档或信息,而生成智能体合成这些信息以生成有意义的输出。有一个管理器智能体(Manager Agent)负责协调系统,并根据用户输入选择最合适的智能体来执行任务。

这个食谱的原始想法来自这篇文章。您可以在那里找到更多细节。

下面,您可以找到我们将要构建的架构。

multiagent_rag_system (1).png

1. 安装依赖

首先,让我们安装依赖项

!pip install -q smolagents
!pip install markdownify duckduckgo-search spaces gradio-tools langchain langchain-community langchain-huggingface faiss-cpu --upgrade -q

让我们登录以便调用 HF 推理 API

from huggingface_hub import notebook_login

notebook_login()

2. 让我们创建多智能体 RAG 系统

在本节中,我们将创建 RAG 系统中的每个智能体。

我们将拥有 3 个由一个中心智能体管理的智能体(详情请参阅图片)

  • 🕵💬 网页搜索智能体:它将包含 DuckDuckGoSearchTool 工具和 VisitWebpageTool。正如您所见,每个智能体都可能包含一个工具列表。
  • 🕵💬 检索智能体:它将包含两个工具,用于从两个不同的知识库中检索信息。
  • 🕵💬 图像生成智能体:除了图像生成工具外,它还将包含一个提示生成器工具。

💡 除了这些智能体,中心/协调智能体还可以访问代码解释器工具来执行代码。

我们将使用 Qwen/Qwen2.5-72B-Instruct 作为每个组件的 LLM,它将通过推理 API 访问。根据智能体的不同,可以使用不同的 LLM 模型。

注意: 推理 API 根据各种标准托管模型,部署的模型可能会在没有事先通知的情况下更新或替换。在此处了解更多信息

from smolagents import InferenceClientModel

model_id = "Qwen/Qwen2.5-72B-Instruct"
model = InferenceClientModel(model_id)

让我们深入了解每个智能体的细节!

2.1 网页搜索智能体 🔍

网页搜索智能体将利用 DuckDuckGoSearchTool 在网络上搜索并收集相关信息。此工具充当搜索引擎,根据指定的关键字查询结果。

为了使搜索结果可操作,我们还需要智能体访问 DuckDuckGo 检索到的网页。这可以通过使用内置的 VisitWebpageTool 来实现。

让我们探索如何设置它并将其集成到我们的系统中!

以下代码来自原始的 让多个智能体在多智能体层次结构中协作 🤖🤝🤖 食谱,请参阅该食谱以获取更多详细信息。

2.1.1 构建我们的多工具网络智能体 🤖

现在我们已经设置了基本的搜索和网页工具,接下来让我们构建多工具网络智能体。该智能体将结合多个工具来执行更复杂的任务,利用 ToolCallingAgent 的功能。

ToolCallingAgent 特别适合网页搜索任务,因为其 JSON 动作公式只需要简单的参数,并且在单个动作的顺序链中无缝工作。这使其成为我们需要搜索网络以获取相关信息并从特定网页检索详细内容的场景的绝佳选择。相比之下,CodeAgent 动作公式更适合涉及大量或并行工具调用的场景。

通过集成多个工具,我们可以确保我们的智能体以复杂而高效的方式与网络交互。

让我们深入了解如何设置它并将其集成到我们的系统中!

from smolagents import CodeAgent, ToolCallingAgent, ManagedAgent, DuckDuckGoSearchTool, VisitWebpageTool

web_agent = ToolCallingAgent(tools=[DuckDuckGoSearchTool(), VisitWebpageTool()], model=model)

现在我们有了第一个智能体,让我们将其包装为 ManagedAgent,以便中心智能体可以使用它。

managed_web_agent = ManagedAgent(
    agent=web_agent,
    name="search_agent",
    description="Runs web searches for you. Give it your query as an argument.",
)

2.2 检索智能体 🤖🔍

我们多智能体系统中的第二个智能体是检索智能体。该智能体负责从不同来源收集相关信息。为了实现这一目标,它将利用两个工具,从两个独立的知识库中检索数据。

我们将重用以前在其他 RAG 食谱中使用的两个数据源,这将使检索器能够高效地收集信息以供进一步处理。

通过利用这些工具,检索智能体可以访问多样化的数据集,确保在将信息传递到系统的下一步之前全面收集相关信息。

让我们探索如何设置检索器并将其集成到我们的多智能体系统中!

2.2.1 HF 文档检索工具 📚

第一个检索工具来自 Agentic RAG:通过查询重构和自查询加速你的 RAG!🚀 食谱。

对于此检索器,我们将使用一个数据集,其中包含各种 huggingface 包的文档页面的编译,所有这些都存储为 markdown 文件。此数据集充当检索智能体搜索和检索相关文档的知识库。

为了使该数据集易于我们的智能体访问,我们将

  1. 下载数据集:我们将首先获取 markdown 文档。
  2. 嵌入数据:然后,我们将使用 FAISS 向量存储将文档转换为嵌入,以实现高效的相似性搜索。

通过这样做,检索工具可以根据搜索查询快速访问相关文档,使智能体能够提供准确详细的信息。

让我们继续设置工具来处理文档检索!

import datasets

knowledge_base = datasets.load_dataset("m-ric/huggingface_doc", split="train")
from tqdm import tqdm
from transformers import AutoTokenizer
from langchain.docstore.document import Document
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import FAISS
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_community.vectorstores.utils import DistanceStrategy

source_docs = [
    Document(page_content=doc["text"], metadata={"source": doc["source"].split("/")[1]}) for doc in knowledge_base
]

text_splitter = RecursiveCharacterTextSplitter.from_huggingface_tokenizer(
    AutoTokenizer.from_pretrained("thenlper/gte-small"),
    chunk_size=200,
    chunk_overlap=20,
    add_start_index=True,
    strip_whitespace=True,
    separators=["\n\n", "\n", ".", " ", ""],
)

# Split docs and keep only unique ones
print("Splitting documents...")
docs_processed = []
unique_texts = {}
for doc in tqdm(source_docs):
    new_docs = text_splitter.split_documents([doc])
    for new_doc in new_docs:
        if new_doc.page_content not in unique_texts:
            unique_texts[new_doc.page_content] = True
            docs_processed.append(new_doc)

print("Embedding documents...")
embedding_model = HuggingFaceEmbeddings(model_name="thenlper/gte-small")
huggingface_doc_vector_db = FAISS.from_documents(
    documents=docs_processed,
    embedding=embedding_model,
    distance_strategy=DistanceStrategy.COSINE,
)

现在我们已经将文档嵌入到 FAISS 中,接下来让我们创建 RetrieverTool。此工具将查询 FAISS 向量存储,以根据用户查询检索最相关的文档。

这将允许检索智能体在查询时访问并提供相关文档。

from smolagents import Tool
from langchain_core.vectorstores import VectorStore


class RetrieverTool(Tool):
    name = "retriever"
    description = "Using semantic similarity, retrieves some documents from the knowledge base that have the closest embeddings to the input query."
    inputs = {
        "query": {
            "type": "string",
            "description": "The query to perform. This should be semantically close to your target documents. Use the affirmative form rather than a question.",
        }
    }
    output_type = "string"

    def __init__(self, vectordb: VectorStore, **kwargs):
        super().__init__(**kwargs)
        self.vectordb = vectordb

    def forward(self, query: str) -> str:
        assert isinstance(query, str), "Your search query must be a string"

        docs = self.vectordb.similarity_search(
            query,
            k=7,
        )

        return "\nRetrieved documents:\n" + "".join(
            [f"===== Document {str(i)} =====\n" + doc.page_content for i, doc in enumerate(docs)]
        )
huggingface_doc_retriever_tool = RetrieverTool(huggingface_doc_vector_db)

2.2.2 PEFT 问题检索工具

对于第二个检索器,我们将使用 PEFT issues 作为数据源,就像在 使用 Hugging Face Zephyr 和 LangChain 对 GitHub 问题进行简单 RAG 中一样。

同样,以下代码来自该食谱,请参阅该食谱以获取更多详细信息!

from google.colab import userdata

GITHUB_ACCESS_TOKEN = userdata.get("GITHUB_PERSONAL_TOKEN")
from langchain.document_loaders import GitHubIssuesLoader

loader = GitHubIssuesLoader(repo="huggingface/peft", access_token=GITHUB_ACCESS_TOKEN, include_prs=False, state="all")
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=30)
chunked_docs = splitter.split_documents(docs)
peft_issues_vector_db = FAISS.from_documents(chunked_docs, embedding=embedding_model)

现在让我们使用相同的 RetrieverTool 生成第二个检索工具。

peft_issues_retriever_tool = RetrieverTool(peft_issues_vector_db)

2.2.3 构建检索智能体

现在我们已经创建了两个检索工具,是时候构建检索智能体了。该智能体将管理这两个工具,并根据用户查询检索相关信息。

我们将使用 ManagedAgent 集成这些工具并将智能体传递给中心智能体进行协调。

retriever_agent = ToolCallingAgent(
    tools=[huggingface_doc_retriever_tool, peft_issues_retriever_tool], model=model, max_iterations=4, verbose=2
)
managed_retriever_agent = ManagedAgent(
    agent=retriever_agent,
    name="retriever_agent",
    description="Retrieves documents from the knowledge base for you that are close to the input query. Give it your query as an argument. The knowledge base includes Hugging Face documentation and PEFT issues.",
)

2.3 图像生成智能体 🎨

我们系统中的第三个智能体是图像生成智能体。该智能体将有两个工具:一个用于优化用户查询,另一个用于根据查询生成图像。在这种情况下,我们将使用 CodeAgent 而不是 ReactAgent,因为这些动作可以一次性执行。

您可以在 智能体,超强升级 - 多智能体、外部工具等 文档中找到有关图像生成智能体的更多详细信息。

让我们深入了解这些工具如何协同工作以根据用户输入生成图像!

from transformers import load_tool, CodeAgent

prompt_generator_tool = Tool.from_space(
    "sergiopaniego/Promptist", name="generator_tool", description="Optimizes user input into model-preferred prompts"
)
image_generation_tool = load_tool("m-ric/text-to-image", trust_remote_code=True)
image_generation_agent = CodeAgent(tools=[prompt_generator_tool, image_generation_tool], model=model)

🖼 同样,我们使用 ManagedAgent 来告知中心智能体它可以管理它。此外,我们还包含了一个 additional_prompting 参数,以确保智能体返回生成的图像,而不仅仅是文本描述。

managed_image_generation_agent = ManagedAgent(
    agent=image_generation_agent,
    name="image_generation_agent",
    description="Generates images from text prompts. Give it your prompt as an argument.",
    additional_prompting="\n\nYour final answer MUST BE only the generated image location.",
)

3. 让我们添加通用智能体管理器来协调系统

中心智能体管理器将协调智能体之间的任务。它将

  • 接收用户输入并决定哪个智能体(网页搜索、检索、图像生成)处理它。
  • 根据用户的查询将任务委托给相应的智能体。
  • 收集并合成来自智能体的结果。
  • 将最终输出返回给用户。

我们将所有开发的智能体作为 managed_agents 包含在内,并在 additional_authorized_imports 下添加代码执行器所需的任何导入。

manager_agent = CodeAgent(
    tools=[],
    model=model,
    managed_agents=[managed_web_agent, managed_retriever_agent, managed_image_generation_agent],
    additional_authorized_imports=["time", "datetime", "PIL"],
)

现在一切都已设置好,让我们测试多智能体 RAG 系统的性能!

为此,我们将提供一些示例查询,并观察系统如何在智能体之间委派任务、处理信息并返回最终结果。

这将帮助我们了解智能体协同工作的效率和效果,并在必要时确定优化领域。

让我们继续运行一些测试!

3.1 尝试触发搜索智能体的示例

manager_agent.run("How many years ago was Stripe founded?")

3.2 尝试触发图像生成智能体的示例

result = manager_agent.run(
    "Improve this prompt, then generate an image of it.", prompt="A rabbit wearing a space suit"
)
>>> from IPython.display import Image, display

>>> display(Image(filename=result))

3.3 尝试触发 HF 文档知识库的检索智能体的示例

manager_agent.run("How can I push a model to the Hub?")

3.4 尝试触发 PEFT 问题知识库的检索智能体的示例

manager_agent.run("How do you combine multiple adapters in peft?")

🏁 最终想法

我们成功构建了一个多智能体 RAG 系统,它集成了网页搜索、文档检索和图像生成智能体,所有这些都由一个中心智能体管理器协调。这种架构实现了无缝的任务委派、高效的处理以及处理各种用户查询的灵活性。

🔍 探索更多

< > 在 GitHub 上更新