AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


RAG中,根据查询意图驱动的Router逻辑分析
发布日期:2024-05-17 07:07:29 浏览次数: 2282 来源:颠覆式创新



导读

在很多RAG系统中(包括传统的搜索引擎),均需要根据用户的输入首先分析用户的查询意图,以便执行不同的分支获取最优答案, 本文详细介绍RAG中的查询意图驱动Router逻辑。通过本文你能够了解:

  1. RAG中的Router分类

  2. 具体代码


根据查询意图引导应用程序流程

根据用户查询的意图来控制 RAG 应用程序的流程,可以帮助我们创建更有用和更加强大的检索增强生成(RAG)应用程序。

我们希望用户能够与数据进行交互,这些数据可能来自各种各样的来源。

例如报告、文档、图片、数据库和第三方系统。

对于基于业务的 RAG 应用程序,我们可能希望用户能够与业务的各个领域的信息进行交互,例如销售、订购和会计系统的信息。


由于数据来源的多样性,信息的存储方式以及我们希望与之交互的方式也可能是多样的。

一些数据可能存储在向量存储中,一些存储在 SQL 数据库中,还有一些可能需要通过 API 调用来访问,因为它们位于第三方系统中。   

同样,对于相同的数据,也可能设置了不同的向量存储,针对不同的查询类型进行优化。

例如,一个向量存储可以用于回答摘要类型的问题,另一个用于回答具体的、定向的问题。


我们可能还希望根据问题的性质,路由到不同的组件类型

例如,根据问题的性质,我们可能希望将查询传递给Agent、向量存储,或者直接传递给 LLM 进行处理。    

甚至可能根据所提出的问题定制提示模板。

   

总的来说,有很多原因我们希望改变并引导用户查询通过应用程序的流程。

我们的应用程序尝试满足的用例越多,我们就越有可能在整个应用程序中有更多的路由要求。


路由器(Router)本质上只是我们可以使用的 If/Else 语句,用于引导查询的控制流程。


但有趣的是,它们需要根据自然语言输入做出决策

因此,我们正在寻找基于自然语言描述的离散路径输出。


由于很多路由逻辑是基于 LLM 或机器学习算法的使用,这些算法是非确定性的,我们无法保证路由器总是能够100%地做出正确的选择。再加上我们不太可能能够预测所有进入路由器的不同查询变体。

然而,通过使用最佳实践和一些测试,我们应该能够利用路由器来帮助创建更强大的 RAG 应用程序。


自然语言Router

我们将在这里探讨一些我发现的由一些不同的 RAG 和 LLM 框架和库实现的自然语言路由器。

  1. LLM 完成路由器

  2. LLM 函数调用路由器

  3. 语义路由器

  4. zero-shot 分类路由器

  5. 语言分类路由器


下面的图表描述了这些路由器,以及它们所在的框架/包。

该图表还包括逻辑路由器,我定义为基于离散逻辑工作的路由器

例如根据字符串长度、文件名、整数值等条件。换句话说,它们不是基于必须理解自然语言查询意图的。    


LLM 路由器

利用LLM的决策能力根据用户的查询选择路由。    

LLM 完成路由器

这些使用 LLM 完成调用,要求 LLM 传递的prompt选项列表中返回最佳描述查询的单词。

然后,可以将此单词用作 If/Else 条件的一部分,以控制应用程序流程。

这就是 LlamaIndex 中的 LLM 选择器路由器 的工作原理。这也是 LangChain 文档中路由器的示例。

让我们看一个代码示例,基于 LangChain 文档中提供的示例,以使这一点更加清晰。正如您所看到的,在 LangChain 中自己编写其中之一是非常简单的。



    from langchain_anthropic import ChatAnthropicfrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import PromptTemplate

    设置LLM链以根据查询返回单个单词


      llm_completion_select_route_chain = (PromptTemplate.from_template("""根据我们在提示模板中提供的单词列表,对下面的用户问题进行分类。
      不要用超过一个词来回答。
      {question}
      分类:""" )| ChatAnthropic(model_name="claude-3-haiku")| StrOutputParser())

      我们设置了一个IF/Else条件,将查询路由到正确的链路

      基于上面的LLM完成调用


        def route_to_chain(route_name):
        if "anthropic" == route_name.lower(): return anthropic_chain
        elif "langchain" == route_name.lower(): return langchain_chain
        else: return general_chain

        应用程序后期,我们可以使用LLM的响应

        完成链用于控制(即路由)应用程序的流程

        通过我们创建的 route_to_chain 方法将正确的链路路由

          route_name = llm_completion_select_route_chain.invoke(user_query)chain = route_to_chain(route_name)chain.invoke(user_query)

          LLM 功能调用路由

          这利用了LLM的函数调用能力来选择遍历的路线。不同的路线被设置为LLM函数调用中具有适当描述的函数。然后,基于传递给LLM的查询,它能够返回正确的函数(即路线),供我们采取。

          这就是 Pydantic Router 在 LlamaIndex 内部的工作原理。这也是大多数代理人工作的方式,也是选择要使用的正确工具的方式。他们利用LLM的函数调用能力来根据用户的查询选择适当的工具。


          语义路由器

          这种路由器类型利用嵌入和相似性搜索来选择最佳的遍历路线。

          每条路线都有一组与之关联的示例查询,这些查询会被嵌入并存储为向量。传入的查询也会被嵌入,然后与路由器中的其他示例查询进行相似性搜索。选择与最接近匹配的查询相关的路线。

          事实上,有一个名为semantic-router的Python包就是这样做的。让我们看一些实现细节,以更好地了解整个工作原理。这些示例直接来自该库的 GitHub 页面。    

          让我们设置两条路线,一条用于关于政治的问题,另一条用于一般的闲聊类型问题。对于每条路线,我们分配一个可能会被问到的问题列表,以触发该路线。这些示例查询被称为话语。这些话语将被嵌入,以便我们可以将它们用于与用户查询的相似性搜索。


            from semantic_router import Route# 我们可以将这作为我们的聊天机器人的指南,避免政治话题# 对话政治= Route(name="politics",utterances=["政治难道不是最好的东西吗","为什么不告诉我你的政治观点","你难道不喜欢总统吗","他们将毁掉这个国家!","他们将拯救这个国家!",],)# 这可以作为指示我们的聊天机器人切换到更多...# 闲聊提示chitchat = Route(name="chitchat",utterances=["今天天气怎么样?","最近怎么样?","今天天气真好","天气太可怕了","我们去吃炸鱼薯条吧",],)# 我们将我们的两个决策放在一个列表中routes = [politics, chitchat]

            我们将OpenAI分配为编码器,尽管任何嵌入库都可以使用。接下来,我们使用路由器和编码器创建我们的路由层。   


              encoder = OpenAIEncoder()from semantic_router.layer import RouteLayerroute_layer = RouteLayer(encoder=encoder, routes=routes)

              然后,当我们对路由器层应用我们的查询时,它会返回应该用于查询的路由


                route_layer("你不喜欢政治吗?").nameOutput:


                # -> '政治'


                ## zero-shot 分类路由器

                         
                             
                ["zero-shot 文本分类](https://huggingface.co/tasks/zero-shot-classification) 是自然语言处理中的一项任务,模型在一组标记示例上进行训练,然后能够对以前未见过的类别的新示例进行分类"。这些路由器利用零-shot分类模型,将标签分配给文本片段,从您传递给路由器的预定义标签集中选择。              
                             
                **示例:** Haystack 中的 [ZeroShotTextRouter](https://docs.haystack.deepset.ai/reference/routers-api#module-zero_shot_text_router),利用了 Hugging Face 的零-shot分类模型。查看 [源代码](https://github.com/deepset-ai/haystack/blob/main/haystack/components/routers/zero_shot_text_router.py#L130) 以了解神奇发生的地方。              
                             

                语言分类路由器              
                             


                这种类型的路由器能够识别查询所使用的语言,并根据此进行路由。如果您的应用程序需要某种多语言解析能力,这将非常有用。             
                             
                **示例:** [Haystack 的 TextClassificationRouter](https://docs.haystack.deepset.ai/reference/routers-api#module-text_language_router)。[它利用 langdetect python 库](https://github.com/deepset-ai/haystack/blob/main/haystack/components/routers/text_language_router.py#L90) 来检测文本的语言,该库本身使用 [朴素贝叶斯](https://www.slideshare.net/shuyo/language-detection-library-for-java) 算法来检测语言。              
                             

                关键词路由器              
                             

                这篇来自 LlamaIndex 的联合创始人 Jerry Liu 的[文章](https://betterprogramming.pub/unifying-llm-powered-qa-techniques-with-routing-abstractions-438e2499a0d0)讨论了 RAG 应用程序内部的路由,其中提出了一种关键词路由器,该路由器尝试通过匹配查询和路由列表之间的关键词来选择路由。              
                             
                这个关键词路由器可以由 LLM 来识别关键词,或者通过其他关键词匹配库来实现。我还没有找到任何实现这种路由器类型的软件包。             
                             

                逻辑路由器              
                             

                这些使用逻辑检查对变量进行操作,比如字符串长度、文件名和值比较,以处理如何路由查询。它们与编程中使用的典型的 If/Else 条件非常相似。                           

                换句话说,它们不是基于理解自然语言查询的意图,而是可以根据现有的离散变量做出选择。             
                             
                **示例:** [ConditionalRouter](https://docs.haystack.deepset.ai/docs/conditionalrouter) 和 [FileTypeRouter](https://docs.haystack.deepset.ai/docs/filetyperouter) 来自 HayStack。              
                             

                Agent vs 路由器              
                             


                乍一看,Agent和Router之间确实有很多相似之处,可能很难区分它们的不同之处。             
                             
                这种相似之处存在是因为代理实际上在其流程中执行路由。它们使用路由机制来选择正确的工具来完成任务。它们经常利用函数调用来选择正确的工具,就像上面描述的 "
                LLM 函数调用路由器" 一样。              
                             
                路由器比代理简单得多,通常只是将任务路由到正确的位置,而不进行与该任务相关的任何逻辑或处理。             
                             
                另一方面,Agent通常负责处理逻辑,包括管理其可以访问的工具所完成的工作。   
                         
                             

                结论             

                             
                我们在这里介绍了目前在不同的RAG和LLM框架和包中找到的几种不同的自然语言路由器。             
                             
                随着时间的推移,围绕路由的概念、包和库肯定会增加。在构建RAG应用程序时,您会发现,在某个时候,路由能力确实变得必要,以便构建对用户有用的应用程序。             
                             
                路由器是这些基本构建模块,它们允许您将自然语言请求路由到您的应用程序的正确位置,以便尽可能最好地满足用户的查询。 
                           
                             


                53AI,企业落地应用大模型首选服务商

                产品:大模型应用平台+智能体定制开发+落地咨询服务

                承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业

                联系我们

                售前咨询
                186 6662 7370
                预约演示
                185 8882 0121

                微信扫码

                与创始人交个朋友

                回到顶部

                 
                扫码咨询