• 文章
  • What is Agentic RAG? Building Agents with Qdrant
返回到 RAG & GenAI

什么是代理RAG?使用Qdrant构建代理

Kacper Łukawski

·

2024年11月22日

What is Agentic RAG? Building Agents with Qdrant

标准 检索增强生成 遵循一个可预测的线性路径:接收查询,检索相关文档,然后生成响应。在许多情况下,这可能足以解决特定问题。在最坏的情况下,你的 LLM 可能会决定不回答问题,因为上下文没有提供足够的信息。

Standard, linear RAG pipeline

另一方面,我们有智能体。这些系统被赋予更多的自由去行动,可以采取多个非线性步骤来实现某个目标。对智能体的定义并没有单一的说法,但一般来说,它是一个使用LLM并通常使用一些工具与外部世界进行通信的应用程序。LLM被用作决策者,决定接下来采取什么行动。行动可以是任何事情,但通常都是明确界定并限制在某一特定可能性集合中的。其中一个行动可能是查询向量数据库,如Qdrant,以检索相关的文档,如果上下文不足以做出决策。然而,RAG只是智能体工具箱中的一项工具。

AI Agent

代理RAG:将RAG与代理结合

由于代理的定义模糊,Agentic RAG 的概念也没有明确的定义。一般来说,它指的是代理与 RAG 的结合。这使得代理能够使用外部知识来源进行决策,主要是决定何时需要外部知识。如果一个系统打破了标准 RAG 系统的线性流程,并赋予代理采取多个步骤以实现目标的能力,我们可以将其描述为 Agentic RAG。

一个简单的路由器,选择要遵循的路径,通常被描述为代理的最简单形式。这样的系统具有多条路径,并具有描述何时采取某条路径的条件。在代理RAG的上下文中,如果上下文不足以回答,代理可以决定查询向量数据库,如果足够,则跳过查询,或者当问题涉及常识时。或者,可能有多个集合存储不同类型的信息,代理可以根据上下文决定查询哪个集合。关键因素是选择路径的决定是由LLM做出的,这是代理的核心。路由代理永远不会返回到上一步,因此它最终只是一个条件决策系统。

Routing Agent

然而,路由仅仅是开始。代理可以更加复杂,极端形式的代理可以拥有完全的行动自由。在这种情况下,代理被赋予一组工具,并可以自主决定使用哪些工具、如何使用以及使用的顺序。大型语言模型被要求规划和执行动作,代理可以采取多个步骤来实现目标,包括在需要时退回一步。这样的系统不必遵循DAG结构(有向无环图),并且可以具有帮助自我纠正过去决策的循环。以这种方式构建的代理RAG系统不仅可以查询向量数据库,还可以处理查询、总结结果,或者甚至生成新数据来回答问题。选项是无限的,但在实际中可以观察到一些常见模式。

Autonomous Agent

使用大语言模型解决信息检索问题

一般来说,在智能RAG系统中暴露的工具用于解决信息检索问题,这些问题对搜索社区来说并不陌生。LLMs改变了我们解决这些问题的方法,但问题的核心仍然是相同的。您可以考虑在智能RAG中使用什么样的工具?以下是一些示例:

  • 查询向量数据库 - 在主动 RAG 系统中最常用的工具。它允许代理根据查询检索相关文档。
  • 查询扩展 - 一种可以用于改善查询的工具。它可以用于添加同义词、纠正拼写错误,或者 甚至根据原始查询生成新查询。 Query expansion example
  • 提取过滤器 - 仅靠矢量搜索有时是不够的。在许多情况下,您可能希望根据特定参数缩小结果范围。这个提取过程可以自动识别查询中的相关条件。否则,您的用户必须手动定义这些搜索约束。 Extracting filters
  • 质量判断 - 了解给定查询结果的质量可以用来决定它们是否足够好以回答,或者代理是否应该采取其他步骤以某种方式改进它们。或者,它也可以承认未能提供良好的响应。

这些只是一些例子,但列表并不是详尽无遗的。例如,您的 LLM 可能会玩弄 Qdrant 搜索参数或选择不同的方法来查询它。一个例子?如果您的用户正在使用一些特定的关键字进行搜索,您可能更喜欢稀疏向量而不是密集向量,因为在这种情况下它们更有效。在这种情况下,您必须为您的代理配备工具,以决定何时使用稀疏向量以及何时使用密集向量。了解集合结构的代理可以轻松做出这样的决定。

这些工具中的每一个都可能是一个独立的代理,且多代理系统并不少见。在这种情况下,代理之间可以相互沟通,一个代理可以决定使用另一个代理来解决特定问题。代理性RAG一个相当有用的组成部分也是人类参与者,可以用来纠正代理的决策,或者引导其朝正确的方向前进。

代理在哪里使用?

代理是一个有趣的概念,但由于它们严重依赖于大型语言模型(LLMs),因此并不适用于所有问题。使用大型语言模型的成本很高,而且往往会很慢,这在许多情况下是不值得的。标准的RAG仅涉及对LLM的一次调用,响应以可预测的方式生成。另一方面,代理可以采取多个步骤,用户体验到的延迟会累计。在许多情况下,这是不可接受的。代理RAG在电子商务搜索中可能并不广泛适用,用户期望快速响应,但在客户支持中可能是可以的,用户愿意等待更长时间以获得更好的答案。

哪个框架是最好的?

有很多框架可用于构建代理,选择最佳框架并不容易。这取决于您现有的技术栈或您熟悉的工具。一些最流行的LLM库已经转向代理范式,并提供构建它们的工具。然而,还有一些工具主要用于代理开发,因此让我们专注于这些工具。

语言图

由LangChain团队开发,LangGraph似乎是已经在构建其RAG系统时使用LangChain的用户的自然扩展,并希望开始使用代理RAG。

令人惊讶的是,LangGraph 本身与大型语言模型没有任何关系。它是一个构建基于图的应用程序的框架,其中每个 节点 是工作流的一步。每个节点将应用程序的 状态 作为输入,并产生一个修改后的状态作为输出。然后,状态被传递给下一个节点,依此类推。节点之间的 可能是条件的,这使得分支成为可能。与某些基于DAG的工具(即Apache Airflow)相反,LangGraph 允许图中存在循环,这使得实现循环工作流成为可能,从而使代理能够实现自我反思和自我纠正。从理论上讲,LangGraph 可以以图形化的方式构建任何类型的应用程序,而不仅限于 LLM 代理。

LangGraph的一些优势包括:

  • 持久性 - 工作流图的状态被存储为检查点。这发生在每一个所谓的超级步骤中(这是图的一个单一顺序节点)。它允许回复工作流的某些步骤,容错,以及包括人为参与的交互。这种机制还充当了短期记忆,可以在特定工作流执行的上下文中访问。
  • 长期记忆 - LangGraph 还有一个概念,即在不同工作流运行之间共享的记忆。然而,这一机制必须由我们的节点显式处理。Qdrant 及其语义搜索能力通常用作长期记忆层
  • 多智能体支持 - 虽然在LangGraph中没有单独的多智能体系统概念,但通过构建一个包含多个智能体和某种监督者的图形,可以创建这样的架构,监督者在特定情况下做出使用哪个智能体的决策。如果一个节点可能是任何东西,那么它也可能是另一个智能体。

LangGraph的一些其他有趣功能包括可视化图形的能力、自动重试失败步骤的功能,以及包含人机交互。

一个代理型RAG的简单示例可以改善用户查询,例如通过修正拼写错误、用同义词扩展它,或甚至基于原始查询生成一个新查询。代理可以根据改进后的查询从向量数据库中检索文档,并生成响应。实施这种方法的LangGraph应用可能看起来像这样:

from typing import Sequence
from typing_extensions import TypedDict, Annotated
from langchain_core.messages import BaseMessage
from langgraph.constants import START, END
from langgraph.graph import add_messages, StateGraph


class AgentState(TypedDict):
    # The state of the agent includes at least the messages exchanged between the agent(s) 
    # and the user. It is, however, possible to include other information in the state, as 
    # it depends on the specific agent.
    messages: Annotated[Sequence[BaseMessage], add_messages]


def improve_query(state: AgentState):
    ...

def retrieve_documents(state: AgentState):
    ...

def generate_response(state: AgentState):
    ...

# Building a graph requires defining nodes and building the flow between them with edges.
builder = StateGraph(AgentState)

builder.add_node("improve_query", improve_query)
builder.add_node("retrieve_documents", retrieve_documents)
builder.add_node("generate_response", generate_response)

builder.add_edge(START, "improve_query")
builder.add_edge("improve_query", "retrieve_documents")
builder.add_edge("retrieve_documents", "generate_response")
builder.add_edge("generate_response", END)

# Compiling the graph performs some checks and prepares the graph for execution.
compiled_graph = builder.compile()

# Compiled graph might be invoked with the initial state to start.
compiled_graph.invoke({
    "messages": [
        ("user", "Why Qdrant is the best vector database out there?"),
    ]
})

该过程的每个节点只是执行特定操作的 Python 函数。如果需要,您可以在其中调用您选择的 LLM,但没有关于任何 AI 创建的消息的假设。 LangGraph实际上充当一个运行时,以特定顺序启动这些函数,并在它们之间传递状态。虽然LangGraph与 LangChain 生态系统集成良好,但也可以独立使用。对于寻求额外支持和功能的团队,还有一个名为 LangGraph Platform 的商业产品。该框架可用于 Python 和 JavaScript 环境,使其可以在不同的技术栈中使用。

CrewAI

CrewAI是构建代理的另一个受欢迎的选择,包括代理式RAG。它是一个高级框架,假设有一些基于LLM的代理共同合作以实现一个共同的目标。这就是CrewAI中“crew”的来源。CrewAI旨在考虑多代理系统。与LangGraph相反,开发者并不创建处理图,而是定义代理及其在团队中的角色。

CrewAI的一些关键概念包括:

  • 代理 - 一个具有特定角色和目标的单元,由LLM控制。它可以选择性地使用一些外部工具与外界沟通,但通常由我们提供给LLM的提示进行引导。
  • 过程 - 目前是顺序或层次的。它定义了任务将如何由代理执行。在顺序过程中,代理一个接一个地执行,而在层次过程中,代理由管理代理选择,管理代理负责在特定情况下决定使用哪个代理。
  • 角色和目标 - 每个代理在团队中都有一个特定角色,并且应该达到的目标。这些在我们定义代理时设定,并用于决定在特定情况下使用哪个代理。
  • 内存 - 一个广泛的内存系统由短期记忆、长期记忆、实体记忆和上下文记忆组成,后者结合了其他三者。还有用户记忆用于偏好和个性化。这就是Qdrant发挥作用的地方,因为它可能被用作长期记忆层。

CrewAI 提供了一整套集成在框架中的丰富工具。这对那些想要将 RAG 与例如代码执行或图像生成相结合的人来说可能是一个巨大优势。生态系统非常丰富,然而,携带您自己的工具并不是一件大事,因为 CrewAI 设计成可扩展的。

在CrewAI中实现的一个简单的代理RAG应用可能如下所示:

from crewai import Crew, Agent, Task
from crewai.memory.entity.entity_memory import EntityMemory
from crewai.memory.short_term.short_term_memory import ShortTermMemory
from crewai.memory.storage.rag_storage import RAGStorage

class QdrantStorage(RAGStorage):
    ...

response_generator_agent = Agent(
    role="Generate response based on the conversation",
    goal="Provide the best response, or admit when the response is not available.",
    backstory=(
        "I am a response generator agent. I generate "
        "responses based on the conversation."
    ),
    verbose=True,
)

query_reformulation_agent = Agent(
    role="Reformulate the query",
    goal="Rewrite the query to get better results. Fix typos, grammar, word choice, etc.",
    backstory=(
        "I am a query reformulation agent. I reformulate the " 
        "query to get better results."
    ),
    verbose=True,
)

task = Task(
    description="Let me know why Qdrant is the best vector database out there.",
    expected_output="3 bullet points",
    agent=response_generator_agent,
)

crew = Crew(
    agents=[response_generator_agent, query_reformulation_agent],
    tasks=[task],
    memory=True,
    entity_memory=EntityMemory(storage=QdrantStorage("entity")),
    short_term_memory=ShortTermMemory(storage=QdrantStorage("short-term")),
)
crew.kickoff()

免责声明:QdrantStorage 不是 CrewAI 框架的一部分,但它是来自 Qdrant 文档中关于 如何将 Qdrant 与 CrewAI 集成 的内容。

尽管这不是技术上的优势,但CrewAI有着优秀的文档。该框架可用于Python,并且很容易上手。CrewAI还提供了商业版,CrewAI Enterprise,提供了一个用于大规模构建和部署代理的平台。

自动生成

AutoGen 强调多代理架构作为一个基本设计原则。该框架要求在任何系统中至少有两个代理,才能真正称之为应用代理 - 通常助手和用户代理交换消息以实现共同目标。还支持超过两个代理的顺序聊天,以及小组聊天和内部对话的嵌套聊天。然而,AutoGen 不假设代理之间存在结构化状态,聊天对话是它们之间唯一的沟通方式。

在这个框架中有许多有趣的概念,其中一些甚至非常独特:

  • 工具/函数 - 代理可以用来与外部世界通信的外部组件。它们被定义为Python可调用对象,可以用于我们希望代理执行的任何外部交互。类型注解用于定义工具的输入和输出,并且支持Pydantic模型以处理更复杂的类型 схемы。目前,AutoGen 仅支持与OpenAI兼容的工具调用API。
  • 代码执行器 - 内置的代码执行器包括本地命令、Docker命令和Jupyter。代理可以编写 并运行代码,因此理论上代理可以完成在Python中可以完成的任何操作。其他框架没有将代码生成和执行做得如此显著。代码执行作为AutoGen中的第一公民是一个 有趣的概念。

每个 AutoGen 代理至少使用一个组件:人机协作、代码执行器、工具执行器或 LLM。 一个简单的代理 RAG,基于两个代理的对话,可以从向量数据库中检索文档,或改进查询,可能看起来像这样:

from os import environ

from autogen import ConversableAgent
from autogen.agentchat.contrib.retrieve_user_proxy_agent import RetrieveUserProxyAgent
from qdrant_client import QdrantClient

client = QdrantClient(...)

response_generator_agent = ConversableAgent(
    name="response_generator_agent",
    system_message=(
        "You answer user questions based solely on the provided context. You ask to retrieve relevant documents for "
        "your query, or reformulate the query, if it is incorrect in some way."
    ),
    description="A response generator agent that can answer your queries.",
    llm_config={"config_list": [{"model": "gpt-4", "api_key": environ.get("OPENAI_API_KEY")}]},
    human_input_mode="NEVER",
)

user_proxy = RetrieveUserProxyAgent(
    name="retrieval_user",
    llm_config={"config_list": [{"model": "gpt-4", "api_key": environ.get("OPENAI_API_KEY")}]},
    human_input_mode="NEVER",
    retrieve_config={
        "task": "qa",
        "chunk_token_size": 2000,
        "vector_db": "qdrant",
        "db_config": {"client": client},
        "get_or_create": True,
        "overwrite": True,
    },
)

result = user_proxy.initiate_chat(
    response_generator_agent,
    message=user_proxy.message_generator,
    problem="Why Qdrant is the best vector database out there?",
    max_turns=10,
)

对于那些刚接触代理开发的人,AutoGen提供了AutoGen Studio,这是一个用于原型设计代理的低代码接口。虽然不适合用于生产,但它显著降低了实验代理架构的入门门槛。

AutoGen Studio

值得注意的是,AutoGen 当前正在进行重大更新,开发中的版本 0.4.x 相比于稳定的 0.2.x 版本引入了实质性的 API 变更。虽然该框架目前具有的内置持久性和状态管理功能有限,但这些功能可能会在未来的版本中得到改进。

开放AI群体

与本文中描述的其他框架不同,OpenAI Swarm 是一个教育项目,它还没有准备好用于生产环境。不过,值得一提的是,它相当轻量级,易于上手。OpenAI Swarm 是一个实验性框架,旨在通过直接交接而不是复杂的编排模式来协调多智能体工作流程。

在这种设置下,代理只是在聊天中交换消息,选择性地调用一些Python函数与外部服务进行通信,或者将对话交给另一个代理,如果另一个代理似乎更适合回答问题的话。每个代理都有特定的角色,由我们必须定义的指令来定义。我们必须决定特定代理将使用哪个LLM,以及它可以调用的一组函数。例如,检索代理可以使用向量数据库来检索文档,并将结果返回给下一个代理。这意味着必须有一个代表它执行语义搜索的函数,但模型将决定查询应该是什么样子。

这里是一个类似的代理RAG应用程序,在OpenAI Swarm中实现的样子:

from swarm import Swarm, Agent

client = Swarm()

def retrieve_documents(query: str) -> list[str]:
    """
    Retrieve documents based on the query.
    """
    ...

def transfer_to_query_improve_agent():
    return query_improve_agent

query_improve_agent = Agent(
    name="Query Improve Agent",
    instructions=(
        "You are a search expert that takes user queries and improves them to get better results. You fix typos and "
        "extend queries with synonyms, if needed. You never ask the user for more information."
    ),
)

response_generation_agent = Agent(
    name="Response Generation Agent",
    instructions=(
        "You take the whole conversation and generate a final response based on the chat history. "
        "If you don't have enough information, you can retrieve the documents from the knowledge base or "
        "reformulate the query by transferring to other agent. You never ask the user for more information. "
        "You have to always be the last participant of each conversation."
    ),
    functions=[retrieve_documents, transfer_to_query_improve_agent],
)

response = client.run(
    agent=response_generation_agent,
    messages=[
        {
            "role": "user",
            "content": "Why Qdrant is the best vector database out there?"
        }
    ],
)

尽管我们没有明确定义处理的图,但代理仍然可以决定将处理移交给另一个代理。没有状态的概念,因此一切都依赖于不同组件之间交换的消息。

OpenAI Swarm 不专注于与外部工具的集成,如果您想将语义搜索与 Qdrant 集成,您需要完全自己实现。显然,该库与 OpenAI 模型紧密耦合,而使用其他一些模型也是可能的,但需要一些额外的工作,例如设置代理以调整与 OpenAI API 的接口。

赢家是?

为您的代理RAG系统选择最佳框架取决于您现有的技术栈、团队专长以及项目的具体要求。所有描述的工具都是强有力的竞争者,并且它们正在快速发展。值得关注它们,因为它们很可能会随着时间的推移而发展和改进。最终,您应该能够用其中任何一个工具构建相同的流程,但其中一些可能更适合您希望您的代理与之交互的特定工具生态系统。

然而,在选择代理RAG系统的框架时,有一些重要因素需要考虑:

  • 人机协作 - 尽管我们旨在构建自主代理,但包括人类的反馈通常很重要,因此我们的代理不能执行恶意行为。
  • 可观察性 - 调试系统的难易程度,以及理解内部发生情况的难易程度。尤其重要,因为我们正在处理大量的LLM提示。

然而,选择合适的工具包取决于您的项目状态和具体需求。如果您想将您的代理与多个外部工具集成,CrewAI 可能是最佳选择,因为开箱即用的集成数量最多。然而,LangGraph 与 LangChain 集成得很好,因此如果您对该生态系统熟悉,它可能更适合您。

所有框架在构建代理方面都有不同的方法,因此值得尝试所有框架以查看哪一个最符合您的需求。LangGraph 和 CrewAI 更加成熟,具有更多功能,而 AutoGen 和 OpenAI Swarm 更加轻量且实验性更强。然而, 现有的框架都无法解决所有上述的信息检索问题,因此您仍然需要构建自己的工具来填补空白。

使用Qdrant构建自主RAG

无论您选择哪个框架,Qdrant都是构建自主RAG系统的极佳工具。请查看我们的集成以选择最适合您用例和偏好的选项。使用Qdrant的最简单方法是使用我们的托管服务Qdrant Cloud。可以免费获得1GB的集群,因此您可以在几分钟内开始构建您的自主RAG系统。

进一步阅读

查看Qdrant如何与以下内容集成:

这个页面有用吗?

感谢您的反馈!🙏

我们很遗憾听到这个消息。 😔 你可以 编辑 这个页面在 GitHub上,或者 create 一个 GitHub 问题。