智能体课程文档

构建 Agentic RAG 系统

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

Ask a Question Open In Colab

构建 Agentic RAG 系统

你可以跟随这个 notebook 中的代码,并使用 Google Colab 运行它。

检索增强生成(Retrieval Augmented Generation, RAG)系统结合了数据检索和生成模型的能力,以提供具有上下文感知能力的响应。例如,用户的查询被传递给搜索引擎,检索到的结果与查询一起提供给模型。然后,模型根据查询和检索到的信息生成响应。

Agentic RAG(Agentic Retrieval-Augmented Generation)通过 将自主 Agent 与动态知识检索相结合,扩展了传统的 RAG 系统。

传统 RAG 系统使用 LLM 根据检索到的数据回答查询,而 Agentic RAG 则 能够智能地控制检索和生成过程,从而提高效率和准确性。

传统 RAG 系统面临一些关键限制,例如 依赖于单次检索步骤,并专注于与用户查询的直接语义相似性,这可能会忽略相关信息。

Agentic RAG 通过允许 Agent 自主制定搜索查询、评估检索结果并执行多个检索步骤来解决这些问题,从而获得更具针对性和更全面的输出。

使用 DuckDuckGo 进行基本检索

让我们构建一个能使用 DuckDuckGo 搜索网络的简单 Agent。这个 Agent 将检索信息并综合响应以回答查询。借助 Agentic RAG,Alfred 的 Agent 可以:

  • 搜索最新的超级英雄派对趋势
  • 筛选结果以包含奢华元素
  • 将信息整合成一个完整的计划

以下是 Alfred 的 Agent 实现这一目标的方式:

from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel

# Initialize the search tool
search_tool = DuckDuckGoSearchTool()

# Initialize the model
model = InferenceClientModel()

agent = CodeAgent(
    model=model,
    tools=[search_tool],
)

# Example usage
response = agent.run(
    "Search for luxury superhero-themed party ideas, including decorations, entertainment, and catering."
)
print(response)

Agent 遵循以下流程:

  1. 分析请求: Alfred 的 Agent 识别出查询的关键要素——奢华的超级英雄主题派对策划,重点关注装饰、娱乐和餐饮。
  2. 执行检索: Agent 利用 DuckDuckGo 搜索最相关和最新的信息,确保其符合 Alfred 对奢华活动的精确偏好。
  3. 综合信息: 收集结果后,Agent 将它们处理成一个连贯、可操作的计划,供 Alfred 使用,涵盖派对的各个方面。
  4. 存储以备将来参考: Agent 存储检索到的信息,以便在规划未来活动时轻松访问,从而优化后续任务的效率。

自定义知识库工具

对于专业任务,自定义知识库可能非常宝贵。让我们创建一个工具,用于查询技术文档或专业知识的向量数据库。通过语义搜索,Agent 可以找到最符合 Alfred 需求的信息。

向量数据库存储由机器学习模型创建的文本或其他数据的数值表示(嵌入)。它通过识别高维空间中的相似含义来实现语义搜索。

这种方法将预定义知识与语义搜索相结合,为活动策划提供具有上下文感知的解决方案。通过访问专业知识,Alfred 可以完善派对的每一个细节。

在此示例中,我们将创建一个从自定义知识库中检索派对策划创意的工具。我们将使用 BM25 检索器来搜索知识库并返回最佳结果,并使用 RecursiveCharacterTextSplitter 将文档分割成更小的块,以实现更高效的搜索。

from langchain.docstore.document import Document
from langchain.text_splitter import RecursiveCharacterTextSplitter
from smolagents import Tool
from langchain_community.retrievers import BM25Retriever
from smolagents import CodeAgent, InferenceClientModel

class PartyPlanningRetrieverTool(Tool):
    name = "party_planning_retriever"
    description = "Uses semantic search to retrieve relevant party planning ideas for Alfred’s superhero-themed party at Wayne Manor."
    inputs = {
        "query": {
            "type": "string",
            "description": "The query to perform. This should be a query related to party planning or superhero themes.",
        }
    }
    output_type = "string"

    def __init__(self, docs, **kwargs):
        super().__init__(**kwargs)
        self.retriever = BM25Retriever.from_documents(
            docs, k=5  # Retrieve the top 5 documents
        )

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

        docs = self.retriever.invoke(
            query,
        )
        return "\nRetrieved ideas:\n" + "".join(
            [
                f"\n\n===== Idea {str(i)} =====\n" + doc.page_content
                for i, doc in enumerate(docs)
            ]
        )

# Simulate a knowledge base about party planning
party_ideas = [
    {"text": "A superhero-themed masquerade ball with luxury decor, including gold accents and velvet curtains.", "source": "Party Ideas 1"},
    {"text": "Hire a professional DJ who can play themed music for superheroes like Batman and Wonder Woman.", "source": "Entertainment Ideas"},
    {"text": "For catering, serve dishes named after superheroes, like 'The Hulk's Green Smoothie' and 'Iron Man's Power Steak.'", "source": "Catering Ideas"},
    {"text": "Decorate with iconic superhero logos and projections of Gotham and other superhero cities around the venue.", "source": "Decoration Ideas"},
    {"text": "Interactive experiences with VR where guests can engage in superhero simulations or compete in themed games.", "source": "Entertainment Ideas"}
]

source_docs = [
    Document(page_content=doc["text"], metadata={"source": doc["source"]})
    for doc in party_ideas
]

# Split the documents into smaller chunks for more efficient search
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
    add_start_index=True,
    strip_whitespace=True,
    separators=["\n\n", "\n", ".", " ", ""],
)
docs_processed = text_splitter.split_documents(source_docs)

# Create the retriever tool
party_planning_retriever = PartyPlanningRetrieverTool(docs_processed)

# Initialize the agent
agent = CodeAgent(tools=[party_planning_retriever], model=InferenceClientModel())

# Example usage
response = agent.run(
    "Find ideas for a luxury superhero-themed party, including entertainment, catering, and decoration options."
)

print(response)

这个增强后的 Agent 可以:

  1. 首先检查文档以获取相关信息
  2. 结合知识库中的见解
  3. 在内存中保持对话上下文

增强的检索能力

在构建 Agentic RAG 系统时,Agent 可以采用复杂的策略,例如:

  1. 查询重构 (Query Reformulation): Agent 不使用原始用户查询,而是可以构建优化的搜索词,以更好地匹配目标文档。
  2. 查询分解 (Query Decomposition): 如果用户查询包含多个需要查询的信息点,可以将其分解为多个查询,而不是直接使用。
  3. 查询扩展 (Query Expansion): 与查询重构有些类似,但会多次进行,将查询用多种措辞表达,然后全部进行查询。
  4. 重排序 (Reranking): 使用交叉编码器 (Cross-Encoders) 在检索到的文档和搜索查询之间分配更全面和语义化的相关性分数。
  5. 多步检索 (Multi-Step Retrieval): Agent 可以执行多次搜索,利用初始结果为后续查询提供信息。
  6. 来源整合 (Source Integration): 信息可以从多个来源(如网络搜索和本地文档)进行整合。
  7. 结果验证 (Result Validation): 在将检索到的内容包含到响应中之前,可以分析其相关性和准确性。

高效的 Agentic RAG 系统需要仔细考虑几个关键方面。Agent 应根据查询类型和上下文在可用工具之间进行选择。记忆系统有助于维护对话历史并避免重复检索。备用策略确保即使主要检索方法失败,系统仍能提供价值。此外,实施验证步骤有助于确保检索信息的准确性和相关性。

资源

< > 在 GitHub 上更新