掘金 人工智能 2024年07月07日
这是我见过最详细的RAG 语义路由文章,附详细代码
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

语义路由是一种智能化的查询分发技术,通过解析自然语言输入的语义信息,将查询请求路由到适当的处理组件或数据源,从而提高响应的相关性和效率。它可以根据用户的意图,将查询引导至不同的知识库、数据源或处理部件,例如,将用户的问题分发至对应的知识库,进一步提高查询的精度。

🤔 **语义路由的本质**:与传统的基于规则或模式匹配的路由系统不同,语义路由建立在自然语言之上,通过理解语义来辨认用户的意图和需求,从而将请求指向最适当的服务、数据源或相关处理部件。

🚀 **生产项目的应用场景**:语义路由在搜索助手和问答系统等实际生产项目中应用广泛,例如,根据用户搜索需求将请求派给对应的文件类型储藏处;根据问题的含义,将查询引导到合适的知识库或数据源。

💡 **不同的RAG路由**:RAG路由可以根据用户的查询,动态地选择数据源、选择不同的prompt模板,甚至将查询分发到不同的组件进行处理,例如,将简单问题交给FAQ知识库,而将复杂问题交给Agent处理。

🛠️ **RAG路由的实现**:RAG路由的实现方式多种多样,包括使用大语言模型、基于传统的NLP技术、预设标准化的话术模板,以及通过微调LLM等。

🎯 **总结**:RAG系统的路由机制根据查询语义将请求导向最适配的组件或源,核心为基于自然语言的if/else控制逻辑。查询路由在未来构建用户友好的RAG应用时会更为重要!

RAG(Retrieval-Augmented Generation)在处理某些复杂问题时的应变能力有限,并不能满足所有用户的查询需求。在实际应用中,RAG更适合作为子流程来运行,因为我们通常需要首先识别用户查询中的意图,然后才根据这个意图,将其导向不同的子流程进行处理。这在实际应用中是非常常见的,识别用户意图然后去做不同的事,这就叫做语义路由,有些地方也称之为意图识别。

文章首发公众号了,欢迎关注: AI 博物院

什么是语义路由

RAG(Retrieval-Augmented Generation)在处理某些复杂问题时,其应变能力有限,并不能满足所有用户的查询需求。在实际应用中,RAG更适合作为子流程来运行。通常,我们首先需要识别用户查询中的意图,然后基于这个意图,引导其至不同的子流程进行处理。这在实际应用中是非常常见的,这就是语义路由,有的地方也称之为意图识别。

语义路由是一种智能化的查询分发技术。通过解析自然语言输入的语义信息,该技术可以将查询请求路由到适当的处理组件或数据源,从而提高响应的相关性和效率。例如,我们可以利用语义路由将用户的问题分发至对应的知识库,进一步提高查询的精度。

语义路由的本质是什么

传统的路由系统一般基于预先设定的规则或简易的逻辑判断(比如 if/else 语句),根据关键字或模式输入,请求会被派发到相关的部分。不过,这样的方式在面对复杂自然语言查询时可能力不从心,因为它无法充分理解语境和微妙差异。

相较之下,语义路由是建立在自然语言之上来执行决策分支,这在本质上也看似一个if/else分支逻辑。然而,它并非只靠明确的关键词或模式匹配,而是通过对语义的理解,辨认用户的意图和需求,把请求指向最适当的服务、数据源或相关处理部件。

图中的组件是一个抽象的概念,它可以是数据源(比如向量库、图数据库、关系数据库等),也可以是Agent、LLM、langchain的Chain等等,甚至可以是prompt。

生产项目的应用场景

语义路由在实际生产中的应用场景比较广泛,这里我只列出常见的两个应用场景:

不同的RAG路由

这里我们介绍三种具体的的RAG路由场景:

路由到不同的数据源

用户希望互动的信息可能来源于多个地方,RAG路由能根据用户查询来自不同的数据源,如下图所示。

此处的数据源,其实也可以被理解为知识库,比如文本知识库、数据库知识库、图知识库等。

RAG系统需要处理来自各种数据源的信息,这些可能包括:

    嵌入向量存储:用于保留和查找嵌入向量,适用于快速的相似性搜索。关系型数据库:这个适合结构化数据的检索。图知识库:适合做实体关系的检索。
from typing import Literalfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_core.pydantic_v1 import BaseModel, Fieldfrom langchain_openai import ChatOpenAIclass 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 callllm = ChatOpenAI(model="gpt-4", temperature=0)structured_llm = llm.with_structured_output(RouteQuery)# Promptsystem = """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 routerrouter = 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_similarityfrom langchain_core.output_parsers import StrOutputParserfrom langchain_core.prompts import PromptTemplatefrom langchain_core.runnables import RunnableLambda, RunnablePassthroughfrom langchain_openai import ChatOpenAI, OpenAIEmbeddings# Two promptsphysics_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 promptsembeddings = OpenAIEmbeddings()prompt_templates = [physics_template, math_template]prompt_embeddings = embeddings.embed_documents(prompt_templates)# Route question to promptdef 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应用时会更为重要!

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

语义路由 RAG 自然语言处理 人工智能 知识问答
相关文章