在 RAG 驱动的应用中的路由

张开发
2026/4/14 10:39:53 15 分钟阅读

分享文章

在 RAG 驱动的应用中的路由
原文towardsdatascience.com/routing-in-rag-driven-applications-a685460a7220?sourcecollection_archive---------1-----------------------#2024-05-09根据查询意图引导应用流程https://medium.com/ssmaameri?sourcepost_page---byline--a685460a7220--------------------------------https://towardsdatascience.com/?sourcepost_page---byline--a685460a7220-------------------------------- Sami Maameri·发表于 Towards Data Science ·9 分钟阅读·2024 年 5 月 9 日–根据用户查询的意图在 RAG 应用中路由控制流可以帮助我们创建更有用和强大的基于检索增强生成RAG的应用。我们希望用户能够交互的数据可能来自多个不同的来源例如报告、文档、图像、数据库以及第三方系统。对于基于业务的 RAG 应用我们可能还希望让用户能够交互来自业务各个领域的信息例如来自销售、订单和会计系统的信息。由于数据来源的多样性信息的存储方式以及我们希望与其交互的方式也可能是多样的。有些数据可能存储在向量存储中有些存储在 SQL 数据库中还有些数据我们可能需要通过 API 调用来访问因为它位于第三方系统中。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/34159eb96b878359e44851c2335541d4.pngRAG 系统根据查询意图路由到不同的数据源对于相同的数据可能会设置不同的向量存储以优化不同的查询类型。例如可以为回答总结类问题设置一个向量存储为回答特定、定向类问题设置另一个向量存储。我们可能还希望根据问题的类型路由到不同的组件类型。例如我们可能希望将查询传递给一个代理、向量存储或者直接传递给一个 LLM 进行处理这一切都取决于问题的性质。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/e171242fbcc3f09ba6c6fd62dd48e126.png根据用户查询路由到不同的组件类型我们甚至可能希望根据问题的不同定制提示模板。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/61f627b15df4c09e6ffcf469dcbd9b42.png根据用户查询通过不同的提示模板进行路由总的来说我们有许多理由希望在应用程序中改变和引导用户查询的流程。我们的应用程序试图满足的用例越多我们就越有可能在整个应用程序中存在路由需求。路由器本质上只是我们可以用来引导查询控制流的 If/Else 语句。然而令它们有趣的是它们需要基于自然语言输入做出决策。因此我们正在寻找一个基于自然语言描述的离散输出。由于许多路由逻辑是基于使用大语言模型LLM或机器学习算法这些算法本质上是非确定性的我们无法保证路由器总是能够 100%做出正确的选择。此外我们也不太可能预测所有进入路由器的不同查询变体。然而通过使用最佳实践和一些测试我们应该能够利用路由器帮助创建更强大的 RAG 应用程序。自然语言路由器在这里我们将探索一些我发现的自然语言路由器它们是由一些不同的 RAG 和 LLM 框架和库实现的。LLM 补全路由器LLM 函数调用路由器语义路由器零-shot 分类路由器语言分类路由器下面的图表描述了这些路由器并提供了它们可以找到的框架/包。该图还包括逻辑路由器我将其定义为基于离散逻辑工作的路由器例如字符串长度、文件名、整数值等条件。换句话说它们不依赖于理解自然语言查询的意图。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/78163855bb31bbb8345e6d141e77a57b.png不同类型的自然语言路由器让我们更详细地探讨一下这些路由器LLM 路由器这些利用 LLM 的决策能力根据用户的查询选择路由。LLM 补全路由器这些使用 LLM 的补全调用要求 LLM 从你传递给其提示的单词选项列表中返回一个最能描述查询的单词。然后这个单词可以作为 If/Else 条件的一部分来控制应用程序的流程。这就是LlamaIndex 的 LLM 选择路由器的工作原理。这也是LangChain文档中给出的一个路由器示例。让我们看看一个代码示例基于 LangChain 文档中提供的示例来更清楚地说明这一点。正如你所见在 LangChain 内部编写这样的代码是非常直接的。fromlangchain_anthropicimportChatAnthropicfromlangchain_core.output_parsersimportStrOutputParserfromlangchain_core.promptsimportPromptTemplate# Set up the LLM Chain to return a single word based on the query,# and based on a list of words we provide to it in the prompt templatellm_completion_select_route_chain(PromptTemplate.from_template( Given the user question below, classify it as either being about LangChain, Anthropic, or Other. Do not respond with more than one word. question {question} /question Classification:)|ChatAnthropic(model_nameclaude-3-haiku)|StrOutputParser())# We setup an IF/Else condition to route the query to the correct chain# based on the LLM completion call abovedefroute_to_chain(route_name):ifanthropicroute_name.lower():returnanthropic_chaineliflangchainroute_name.lower():returnlangchain_chainelse:returngeneral_chain...# Later on in the application, we can use the response from the LLM# completion chain to control (i.e route) the flow of the application# to the correct chain via the route_to_chain method we createdroute_namellm_completion_select_route_chain.invoke(user_query)chainroute_to_chain(route_name)chain.invoke(user_query)LLM 函数调用路由器这利用了 LLM 的函数调用能力来选择要遍历的路由。不同的路由被设置为 LLM 函数调用中的函数并附有适当的描述。然后基于传递给 LLM 的查询LLM 能够返回正确的函数即路由供我们使用。这就是LlamaIndex中PyDantic Router的工作方式。这也是大多数 Agent 在选择正确工具时所采用的方式。它们利用 LLM 的函数调用功能来根据用户的查询选择适合的工具。语义路由器这种路由器类型利用嵌入和相似度搜索来选择最佳的路径进行遍历。每个路由都有一组关联的示例查询这些查询会被嵌入并存储为向量。传入的查询也会被嵌入并与来自路由器的其他示例查询进行相似度搜索。与查询最接近的路由将被选中。实际上有一个名为semantic-router的 Python 包可以做到这一点。让我们看一下其中的一些实现细节以便更好地理解整个过程的工作原理。这些示例直接来自该库的 GitHub 页面。让我们设置两条路由一条用于关于政治的问题另一条用于一般闲聊类型的问题。我们为每条路由分配一组可能会被问到的问题这些问题通常用于触发该路由。这些示例查询称为话语。这些话语将被嵌入以便我们可以用于与用户查询的相似度搜索。fromsemantic_routerimportRoute# we could use this as a guide for our chatbot to avoid political# conversationspoliticsRoute(namepolitics,utterances[isnt politics the best thing ever,why dont you tell me about your political opinions,dont you just love the president,theyre going to destroy this country!,they will save the country!,],)# this could be used as an indicator to our chatbot to switch to a more# conversational promptchitchatRoute(namechitchat,utterances[hows the weather today?,how are things going?,lovely weather today,the weather is horrendous,lets go to the chippy,],)# we place both of our decisions together into single listroutes[politics,chitchat]我们指定 OpenAI 作为编码器尽管任何嵌入库都可以使用。接下来我们使用路由器和编码器创建我们的路由层。encoderOpenAIEncoder()fromsemantic_router.layerimportRouteLayer route_layerRouteLayer(encoderencoder,routesroutes)然后当我们将查询应用于路由器层时它会返回应使用的查询路由。route_layer(dont you love politics?).name# - politics所以再总结一下这个语义路由器利用嵌入和相似度搜索通过用户的查询选择最佳的路径进行遍历。由于只需要处理一个索引查询相较于其他类型需要调用 LLM 的路由器这种路由器的速度应该更快。零-shot 分类路由器“Zero-shot 文本分类是自然语言处理中的一项任务其中模型在一组标记示例上进行训练但随后能够对来自先前未见类别的新示例进行分类”。这些路由器利用零-shot 分类模型为文本分配标签标签来自你传入路由器的预定义标签集。示例Haystack 中的ZeroShotTextRouter它利用了来自 Hugging Face 的 Zero Shot 分类模型。查看源代码看看魔法发生的地方。语言分类路由器这种类型的路由器能够识别查询所使用的语言并基于此进行路由。如果您的应用需要某种多语言解析能力这会非常有用。示例来自 Haystack 的TextClassificationRouter。 它利用 langdetect Python 库来检测文本的语言而 langdetect 库本身使用了朴素贝叶斯算法来检测语言。关键词路由器这篇来自 LlamaIndex 联合创始人 Jerry Liu 的文章讨论了 RAG 应用程序中的路由问题其中提出了一个关键词路由器它通过匹配查询与路由列表之间的关键词来选择路由除此之外还提到了其他几种方案。这个关键词路由器也可以通过 LLM 来识别关键词或者通过其他关键词匹配库来实现。我还没有找到任何实现这种路由器类型的包。逻辑路由器这些使用逻辑检查来处理变量例如字符串长度、文件名和数值比较以决定如何路由查询。它们与编程中常见的 If/Else 条件非常相似。换句话说它们并不需要理解自然语言查询的意图而是基于现有的离散变量来做出选择。示例来自 Haystack 的ConditionalRouter和FileTypeRouter。智能体与路由器初看之下路由器和智能体之间确实有很多相似之处可能很难区分它们的不同。这些相似之处的存在是因为智能体实际上在其流程中执行了路由操作。它们使用路由机制来选择正确的工具以完成任务。它们通常利用函数调用来选择正确的工具就像上面描述的LLM 函数调用路由器一样。然而路由器通常比智能体简单得多通常只有一个“简单”的任务就是将任务路由到正确的地方而不涉及与该任务相关的任何逻辑或处理。另一方面代理通常负责处理逻辑包括管理它们所能访问的工具所完成的工作。结论我们在这里介绍了当前在不同的 RAG 和 LLM 框架及包中找到的一些不同的自然语言路由器。关于路由的概念、包和库随着时间的推移肯定会增加。在构建 RAG 应用程序时你会发现在某个时候路由功能确实变得必要以便构建一个对用户有用的应用程序。路由器是这些基本构建块它们允许你将自然语言请求路由到应用程序的正确位置以便尽可能最好地满足用户的查询。希望这对你有帮助请订阅以便在我发布新文章时收到通知除非另有说明所有图片均由作者提供。第一张图片中使用的图标来自SyafriStudiDimitry Miroliubovand以及Free Icons PNG

更多文章