RAG(Retrieval-Augmented Generation)在处理某些复杂问题时的应变能力有限,并不能满足所有用户的查询需求。在实际应用中,RAG更适合作为子流程来运行,因为我们通常需要首先识别用户查询中的意图,然后才根据这个意图,将其导向不同的子流程进行处理。这在实际应用中是非常常见的,识别用户意图然后去做不同的事,这就叫做语义路由,有些地方也称之为意图识别。
文章首发公众号了,欢迎关注: AI 博物院
什么是语义路由
RAG(Retrieval-Augmented Generation)在处理某些复杂问题时,其应变能力有限,并不能满足所有用户的查询需求。在实际应用中,RAG更适合作为子流程来运行。通常,我们首先需要识别用户查询中的意图,然后基于这个意图,引导其至不同的子流程进行处理。这在实际应用中是非常常见的,这就是语义路由,有的地方也称之为意图识别。
语义路由是一种智能化的查询分发技术。通过解析自然语言输入的语义信息,该技术可以将查询请求路由到适当的处理组件或数据源,从而提高响应的相关性和效率。例如,我们可以利用语义路由将用户的问题分发至对应的知识库,进一步提高查询的精度。
语义路由的本质是什么
传统的路由系统一般基于预先设定的规则或简易的逻辑判断(比如 if/else 语句),根据关键字或模式输入,请求会被派发到相关的部分。不过,这样的方式在面对复杂自然语言查询时可能力不从心,因为它无法充分理解语境和微妙差异。
相较之下,语义路由是建立在自然语言之上来执行决策分支,这在本质上也看似一个if/else分支逻辑。然而,它并非只靠明确的关键词或模式匹配,而是通过对语义的理解,辨认用户的意图和需求,把请求指向最适当的服务、数据源或相关处理部件。
图中的组件是一个抽象的概念,它可以是数据源(比如向量库、图数据库、关系数据库等),也可以是Agent、LLM、langchain的Chain等等,甚至可以是prompt。
生产项目的应用场景
语义路由在实际生产中的应用场景比较广泛,这里我只列出常见的两个应用场景:
- 搜索助手:对于一个高级的文件查询应用程序或搜索引擎,用户可能需要查找不同类型的内容,如图片、文档或录像。这时,语义路由就能派上用场——它可以理解用户的搜索需求,并把请求派给对应的文件类型储藏处。例如,如果用户输入了「找出我去年摄制的所有照片」,语义路由就会把此需求导向图像检索,而不是去搜寻文字或影片。
- 问答系统:复杂的问答系统需处理涉及多个领域的问题,或者需要不同的数据处理方式。语义路由通过解析问题的含义,能将查询引导到合适的知识库或数据源。例如,对于「量子计算是什么?」的疑问,语义路由会将其引导至科学知识库;而针对「最近的气候如何?」的问题,则会引导至天气信息服务。
不同的RAG路由
这里我们介绍三种具体的的RAG路由场景:
- 用户的query可能有不同的分析路径,如Agent、向量检索或直接交给LLM进行分析
- 用户的query可能需要根据query动态地选择数据源
- 不同的query可能对应不同的prompt模版,路由可以帮忙选择prompt
路由到不同的数据源
用户希望互动的信息可能来源于多个地方,RAG路由能根据用户查询来自不同的数据源,如下图所示。
此处的数据源,其实也可以被理解为知识库,比如文本知识库、数据库知识库、图知识库等。
RAG系统需要处理来自各种数据源的信息,这些可能包括:
- 嵌入向量存储:用于保留和查找嵌入向量,适用于快速的相似性搜索。
- 关系型数据库:这个适合结构化数据的检索。
- 图知识库:适合做实体关系的检索。
from typing import Literal
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_openai import ChatOpenAI
class RouteQuery(BaseModel):
"""Route a user query to the most relevant datasource."""
datasource: Literal["milvus", "mysql", "neo4j"] = Field(
...,
description="Given a user question choose which datasource would be most relevant for answering their question",
)
# LLM with function call
llm = ChatOpenAI(model="gpt-4", temperature=0)
structured_llm = llm.with_structured_output(RouteQuery)
# Prompt
system = """You are an expert at routing a user question to the appropriate data source.
Here is the data sources:
1. Vector library: milvus - Suitable for semantic retrieval, such as queries based on natural language descriptions.
2. Database: mysql - Suitable for structured searches, such as querying specific fields or values.
3. Graph database: neo4j - suitable for entity relationship retrieval, such as querying connections between entities and relationship networks.
Here is the examples:
```
The user input sample matches the data source:
1. ** Query ** : "I'm looking for the latest research papers on machine learning."
- ** Matching data source ** : Vector library, because this is a semantically based query.
2. ** Query ** : "Please list all AI-related books published in 2023 and their authors."
- ** Matching data source ** : Database, because the query needs to access a specific data field.
3. ** Query ** : "Show all the relationships between Elon Musk and SpaceX."
- ** Matching Data Source ** : Graph database, because the query involves relationships between entities.
```
You must infer the user's query intent from the structure of the keyword or question, route it to the relevant data source."""
prompt = ChatPromptTemplate.from_messages(
[
("system", system),
("human", "{question}"),
]
)
# Define router
router = prompt | structured_llm
# datasource='milvus'
print(router.invoke("What is the first step in the face washing process?"))
# datasource='mysql'
print(router.invoke("top 5 price of phone?"))
# datasource='neo4j'
print(router.invoke("What is the relationship between Einstein and Newton?"))
虽然上述的prompt已经能覆盖一些场景,但它们可能还存在优化空间。您完全可以按照自己项目的具体需求来定制适合的prompt。
路由到不同的组件
我们可以依据问题的特性,将其分发到不同种类的组件进行处理,例如交给Agent、或者直接让大型语言模型(LLM)来处理。
比如,在智能客服系统里,简单且常见的问题可以直接交由FAQ知识库或向量存储库进行快速回答,而一些涉及复杂操作的请求则可以导向Agent用各种工具来完成任务。针对需要深层次理解的自然语言问题,则可直接将查询交给大型语言模型(LLM)以生成详细且个性化的响应,这样可以提升系统的总体响应能力和用户满意度。
在我实际的项目开发过程中,这块场景是应该最多的,我觉得非常值得分享。为此,我计划专门撰写一篇文章,对该场景以及相关的内容进行详尽的阐述和解析。请大家期待。
路由选择不同的prompt
基于问题的不同性质,我们可以导向不同的prompt模板,如下图所示:
举例来说,在教育应用中,对于复杂数学问题的查询,我们可以将它引向详细步骤的模板,以提供分步骤解答;然而对于一般性的科学事实类问题,我们则可以选择简洁回答的模板,直接提供准确答案。
再例如,在创建社交媒体内容时,若用户询问关于品牌推广策略的问题,我们可以将其引向专业性模板,以保证内容的准确性和正式性;对于普通用户的日常互动问题,则可选用轻松有趣的模板,以增强互动体验。
这种方式让系统能够根据查询内容灵活调整响应风格和信息深度,从而提升用户体验的满意度和系统的适应性。
from langchain.utils.math import cosine_similarity
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnableLambda, RunnablePassthrough
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
# Two prompts
physics_template = """You are a very smart physics professor. \
You are great at answering questions about physics in a concise and easy to understand manner. \
When you don't know the answer to a question you admit that you don't know.
Here is a question:
{query}"""
math_template = """You are a very good mathematician. You are great at answering math questions. \
You are so good because you are able to break down hard problems into their component parts, \
answer the component parts, and then put them together to answer the broader question.
Here is a question:
{query}"""
# Embed prompts
embeddings = OpenAIEmbeddings()
prompt_templates = [physics_template, math_template]
prompt_embeddings = embeddings.embed_documents(prompt_templates)
# Route question to prompt
def prompt_router(input):
# Embed question
query_embedding = embeddings.embed_query(input["query"])
# Compute similarity
similarity = cosine_similarity([query_embedding], prompt_embeddings)[0]
most_similar = prompt_templates[similarity.argmax()]
# Chosen prompt
print("Using MATH" if most_similar == math_template else "Using PHYSICS")
return PromptTemplate.from_template(most_similar)
chain = (
{"query": RunnablePassthrough()}
| RunnableLambda(prompt_router)
| ChatOpenAI()
| StrOutputParser()
)
print(chain.invoke("What's a black hole"))
这里我们采用embedding技术,将查询和所有的prompt进行相似性匹配,以选择适当的prompt。这种方法避免了使用LLM进行意图识别,其优点在于减少了一次LLM的调用。
RAG路由的实现
RAG 路由的实现,根据不同的业务场景需求,可以有不同的实现,并没有一种标准的实现方式,以下是几种常见的实现:
- 使用大语言模型(LLM)深度解析用户输入并提取真实意图,将请求匹配到系统内预定义的响应路径,适用于需要深度语义分析的场景,如知识问答系统、多领域支持的智能客服等。
- 基于传统的NLP技术,通过建立一个分类模型对用户的查询类型进行分类,适用于查询类别明确且数据量庞大的环境。这种方式在业务场景分类明确且数据量庞大的环境中表现尤为高效,例如企业信息管理、电子商务平台等。
- 预设标准化的话术模板,根据用户查询与预设话术模板的相似性进行匹配,适合查询结构相对固定且模板库覆盖面广的场景。
- 通过微调LLM,使其更好地理解和响应特定业务领域的查询需求,以提高在特定场景中的性能。例如,微调后的 LLM 可以更好地处理金融领域的查询,在金融服务应用中实现更高的查询匹配精度。
总结
RAG系统的路由机制根据查询语义将请求导向最适配的组件或源,核心为基于自然语言的if/else控制逻辑。随着时间推进,路由相关的概念、包和库将不断增多。在构建RAG应用时,查询路由器能有效地将自然语言请求转至正确位置以满足用户需求并提升响应速度。预期查询路由在未来构建用户友好的RAG应用时会更为重要!