百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

RAG实战篇:精准判断用户查询意图,自动选择最佳处理方案

wptr33 2025-04-11 08:27 20 浏览

在人工智能领域,理解和准确响应用户的查询是构建高效交互系统的关键。这篇文章将带你深入了解如何通过高级查询转换技术,优化大型语言模型的理解能力,使其更贴近用户的真正意图。

在《RAG实战篇:构建一个最小可行性的Rag系统》中,风叔详细介绍了Rag系统的整体实现框架,以及如何搭建一个最基本的Naive Rag。

在前面两篇文章中,风叔分别介绍了索引(Indexing)和查询转换(Query Translation)环节的优化方案。

在这篇文章中,围绕Routing(路由)环节,如下图橙色框内所示,风叔详细介绍一下面对不同的用户输入,如何让大模型更智能地路由到最佳方案。

路由的作用,是为每个Query选择最合适的处理管道,以及依据来自模型的输入或补充的元数据,来确定将启用哪些模块。比如当用户的输入问题涉及到跨文档检索、或者对于复杂文档构建了多级索引时,就需要使用路由机制。

下面,我们结合源代码,介绍一下Logical routing(基于逻辑的路由)和Sematic Routing(基于语义的路由)两种方案。

一、Logical routing(基于逻辑的路由)

基于逻辑的路由,其原理非常简单。大模型接收到问题之后,根据决策步骤,去选择正确的索引数据库,比如图数据库、向量数据库等等,如下图所示。

其使用函数调用(function calling)来产生结构化输出。

下面我们结合源代码来分析一下Logical Routing的流程:

  • 首先我们定义了三种文档,pytion、js、golang
  • 然后通过prompt告诉大模型,需要根据所涉及的编程语言,将用户问题路由到适当的数据源
  • 定义Router
# Data model
class RouteQuery(BaseModel):
    """Route a user query to the most relevant datasource."""
    datasource: Literal["python_docs", "js_docs", "golang_docs"] = 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-3.5-turbo-0125", 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.
Based on the programming language the question is referring to, route it to the relevant data source."""
prompt = ChatPromptTemplate.from_messages(
    [
        ("system", system),
        ("human", "{question}"),
    ])
# Define router 
router = prompt | structured_llm

接着给出了一个使用示例,用户提问后,路由器根据问题的内容判断出数据源为 python_docs,并返回了相应的结果。

question = """Why doesn't the following code work:
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages(["human", "speak in {language}"])
prompt.invoke("french")
"""
result = router.invoke({"question": question})
result.datasource
def choose_route(result):
    if "python_docs" in result.datasource.lower:
        ### Logic here 
        return "chain for python_docs"
    elif "js_docs" in result.datasource.lower:
        ### Logic here 
        return "chain for js_docs"
    else:
        ### Logic here 
        return "golang_docs"
from langchain_core.runnables import RunnableLambda
full_chain = router | RunnableLambda(choose_route)
full_chain.invoke({"question": question})

二、Sematicrouting(基于语义的路由)

基于语义的路由,其原理也非常简单,大模型根据query的语义相似度,去自动配置不同的prompt。

我们先定义两种不同的Prompt,一个让大模型扮演物理专家,一个让大模型扮演数学专家,并将其转为嵌入向量。

# 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}"""
embeddings = OpenAIEmbeddings
prompt_templates = [physics_template, math_template]
prompt_embeddings = embeddings.embed_documents(prompt_templates)

然后计算query embedding和prompt embedding的向量相似度

# 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"))

在上述案例中,最终的输出会使用物理专家的Prompt。

到这里,两种常用的路由策略就介绍完了。当然,我们也可以自主构建更复杂的路由策略,比如构建专门的分类器、打分器等等,这里就不详细展开了。

三、总结

在这篇文章中,风叔介绍了实现查询路由的具体方法,包括Logical routing和Semantic routing两种实现方式。

很多时候,在一些特殊的场景下,我们需要将用户的输入转化为特定的语句,比如数据库查询动作。在下一篇文章中,风叔将重点围绕Query Construction(查询构建)环节,介绍如何将用户输入转变为特定的系统执行语句。

本文由人人都是产品经理作者【风叔】,微信公众号:【风叔云】,原创/授权 发布于人人都是产品经理,未经许可,禁止转载。

题图来自 Pixabay,基于 CC0 协议。

相关推荐

「网络安全」JAVA代码审计——XXE外部实体注入

一、WEB安全部分想要了解XXE,在那之前需要了解XML的相关基础二、XML基础...

Web前端面试题目及答案汇总(web前端面试题最新)

Web前端面试题目及答案汇总来源:极客头条以下是收集一些面试中经常会遇到的经典面试题以及自己面试过程中无法解决的问题,通过对知识的整理以及经验的总结,重新巩固自身的前端基础知识,如有错误或更好的答案,...

什么是脚本文件?与可执行文件有什么不同?

今天的内容是脚本文件和可执行文件是两种不同类型的计算机文件,它们在结构和执行方式上有显著区别。脚本文件:定义与特性...

20个实用Python运维脚本(收藏级)(python 运维工具)

系统环境:支持Linux(Ubuntu/CentOS/Debian)和Windows...

2026年前每个开发者都应该学习的技能

优秀开发者...

Linux 如何每 5、10、15 或 30 分钟运行一次 Cron 作业?

在Linux系统中,Cron是一个强大的工具,用于自动化重复性任务。通过合理配置...

Shell脚本编程进阶实战:从入门到高效自动化

Shell脚本编程进阶实战:从入门到高效自动化一、参数处理进阶:打造专业级CLI工具1.高级参数解析示例...

在Bash中按分隔符拆分字符串的方法

技术背景在Bash脚本编程中,经常会遇到需要按特定分隔符拆分字符串的需求,例如处理CSV文件、解析日志等。掌握字符串拆分的方法对于数据处理和脚本自动化非常重要。...

程序员用5分钟,把一个400多MB的苹果安装包削掉了187MB

丰色发自凹非寺量子位|公众号QbitAI前些日子,一个...

如何在 Windows 上编写批处理脚本

你知道如何使用命令提示符吗?如果这样做,您可以编写一个批处理文件。在最简单的形式中,批处理文件(或批处理脚本)是双击文件时执行的几个命令的列表。批处理文件一直回到DOS,但仍然适用于现代版本的Win...

一文搞懂shell脚本(shell脚本应用实战)

一文搞懂shell脚本1、shell脚本介绍什么是shell脚本...

一文讲清ShellScript脚本编程知识

摘要:本文详尽地讲述了ShellScript的基础内容,还有它在Linux系统里的运用情况,涵盖了它的基本语法、常用的命令以及高级的功能。ShellScript可是一种简单又非常实用的编...

在Bash脚本中获取自身所在目录的方法

技术背景在使用Bash脚本时,有时需要获取脚本自身所在的目录。比如,当脚本作为另一个应用程序的启动器时,需要将工作目录更改为脚本所在的目录,以便对该目录中的文件进行操作。然而,由于脚本的调用方式多样(...

shell中如何确定脚本的位置?这篇文章告诉你

我想从同一个位置读取一些配置文件,如何确定脚本的位置?。这个问题的出现主要是由两个原因引发的:一是您希望将脚本的数据或配置进行外部化,因此需要一种方式来寻找这些外部资源;二是您的脚本需要对某些捆绑资源...

bash shell 语法(bash命令用法)

下面是**Shell(Bash)语法的常用知识点总结**,适合初学者和日常脚本编写参考。内容涵盖变量、判断、循环、函数、重定向、正则、数组等常见用法。---#Shell(Bash)语法速查总结...