在检索增强生成(RAG)应用程序中,根据用户查询的意图对控制流进行路由,能够显著提升系统的响应质量与效率。我们希望用户交互的数据来源广泛,包括报告、文档、图像、数据库及第三方系统。对于企业级 RAG 应用,用户可能需要与销售、订单、会计等不同业务领域的信息交互。
由于数据源的多样性,信息的存储方式及交互方式也各不相同。部分数据存储在向量数据库中,部分存在于 SQL 关系型数据库,还有些需要通过 API 调用访问位于第三方系统中的数据。此外,针对相同但不同的数据类型,也可以配置不同的向量存储设置以优化特定查询类型。例如,一个向量存储专门用于回答摘要类问题,另一个则针对具体的定向事实查询进行优化。
根据问题性质,我们可能还需要将查询路由到不同的组件类型。例如,将查询传递给 Agent、VectorStore 或直接传递给 LLM 进行处理。甚至可以根据提出的问题自定义提示模板,以适应不同场景的需求。
路由器本质上类似于 If/Else 语句,用于指导查询的控制流。但其特殊性在于,它需要根据自然语言输入做出决定,即基于自然语言描述产生离散输出。由于许多路由逻辑依赖于 LLM 或机器学习算法,这些算法具有不确定性,因此无法保证路由器始终 100% 做出正确选择。然而,通过最佳实践和测试,我们可以利用路由器构建更强大的 RAG 应用。
自然语言路由器类型
目前主流的 RAG 和 LLM 框架实现了多种自然语言路由器:
- LLM 完成路由器:利用 LLM 的文本补全能力。
- LLM 函数调用路由器:利用 LLM 的工具调用能力。
- 语义路由器:基于嵌入向量和相似度搜索。
- 零样本分类路由器:基于预定义标签的分类模型。
- 语言分类路由器:识别查询语言并路由。
- 关键字路由器:基于关键词匹配。
- 逻辑路由器:基于字符串长度、文件名等离散变量。
下图展示了不同类型的自然语言路由器及其对应的框架支持。逻辑路由器不依赖理解自然语言意图,而是基于现有离散变量做出选择,例如 Haystack 中的 ConditionalRouter。
LLM 路由器详解
LLM 完成路由器
这类路由器使用 LLM 的完成调用,要求 LLM 从提示词提供的单词选项列表中返回最能描述查询的单个单词。该单词随后用作 If/Else 条件的一部分来控制应用流程。
以下是一个基于 LangChain 的实现示例。在 LangChain 中编写此类代码相对简单:
from langchain_anthropic import ChatAnthropic
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
# 设置 LLM 链根据查询返回单个单词
llm_completion_select_route_chain = (
PromptTemplate.from_template("""
给定下面的用户问题,将其分类为
有关 `LangChain`、`Anthropic` 或 `Other` 的问题。
请勿使用多个单词进行回答。
<question>
{question}
</question>
Classification:""")
| ChatAnthropic(model_name="claude-3-haiku")
| StrOutputParser()
)
# 设置 IF/Else 条件将查询路由到正确的链
def route_to_chain(route_name):
if "anthropic" == route_name.lower():
anthropic_chain
== route_name.lower():
langchain_chain
:
generic_chain
route_name = llm_completion_select_route_chain.invoke(user_query)
chain = route_to_chain(route_name)
result = chain.invoke(user_query)


