RAG 的召回、生成过程逻辑是不够灵活的,无法解决用户的所有问题。在实际过程中,RAG 更适合作为一个子流程。即业务中往往需要首先识别用户 query 中的意图,再进入不同的分支流程进行响应(如图:semantic routing[1])。这样总的 RAG 应用程序就是更具鲁棒性了。
意图识别也称作路由,可能作用于以下场景:
RAG,也可能进行Text2SQL,也可能进行工具调用query可能有不同的分析路径,如Agent、向量检索或直接交给LLM进行分析query动态地选择数据库query可能对应不同的prompt模版,路由可以帮忙选择prompt,比如选择小红书风格或知乎风格的写作。当然,并不是所有的场景一定需要router,我们也可以通过产品逻辑引导用户,比如对于不同的prompt,可以让用户在请求前通过交互进行选择(难免有些显得不够智能了^_^!)。
要想做得更好,我们面对的应该就是用户的原始自然语言请求,然后我们根据用户的自然语言输入做出相应的分支处理。
目前,可以考虑以下几种意图识别方法:
值得注意的是,这几个概念,比如逻辑路由,prompt 路由等,都是我自己编的~
这部分路由最容易理解,类似于我们平时写if/else语句,只不过这里可以是任意的自定义规则,如关键字、正则匹配、字符串长度等。
Haystack中,ConditionalRouter的示例就是根据query的长度返回使用哪个分支。参考链接为:https://docs.haystack.deepset.ai/docs/conditionalrouter。
关键字路由可以认为是另一类逻辑路由,通过匹配关键字与路由分支来决定子流程。当然,提取关键字的策略是多样的,也可以利用LLM进行关键字提取,那样的话就可以认为不是基于逻辑的路由了。
顾名思义,prompt router通过prompt引导LLM输出对应的分支(我就是这么取名字的)。在 LangChain 的routing 示例[2]中,用了这样的prompt:
PromptTemplate.from_template("""Giventheuserquestionbelow,classifyitaseitherbeingabout`LangChain`,`Anthropic`,or`Other`.
Donotrespondwithmorethanoneword.
<question>
{question}
</question>
Classification:"""
对于用户query,让LLM输出是属于哪个类别,这样后面再接一个RunnableLambda或者RunnableBranch去执行不同类别的子流程。这里需要注意的是,虽然prompt中规定了让LLM输出指定的三个类别,LLM是可能不听话的。因此在后面的流程判断中,需要做兜底处理。
LLM的Function Calling功能允许LLM根据用户query解析出要访问的函数和参数。通过将不同的分支描述成不同的函数或者工具,即可让LLM进入到子分支实现路由的功能。
这是一个开源项目,地址为:https://github.com/aurelio-labs/semantic-router,其原理是为每个分支提供一系列query示例,然后选择最相似的query,返回对应的分支。
fromsemantic_routerimportRoute
fromsemantic_router.layerimportRouteLayer
fromsemantic_router.encodersimportCohereEncoder,OpenAIEncoder
politics=Route(
name="politics",
utterances=[
"isn'tpoliticsthebestthingever",
"whydon'tyoutellmeaboutyourpoliticalopinions",
"don'tyoujustlovethepresident",
"they'regoingtodestroythiscountry!",
"theywillsavethecountry!",
],
)
chitchat=Route(
name="chitchat",
utterances=[
"how'stheweathertoday?",
"howarethingsgoing?",
"lovelyweathertoday",
"theweatherishorrendous",
"let'sgotothechippy",
],
)
encoder=CohereEncoder()
rl=RouteLayer(encoder=encoder,routes=[politics,chitchat])
如上述代码创建了两个分支,每个分支下有一些query示例。其原理为对于用户请求,从所有的候选集中根据embedding,选出最相似的对象,并返回对应的分支类别。根据此逻辑,自己动手实现也比较容易。
Zero-Shot Classification 是 NLP 中的一类任务,其在一组标记的示例上进行训练,然后可以对未知的类进行分类,可以认为是一种迁移学习。下述代码展示了使用bart-large-nmli进行分类:
fromtransformersimportpipeline
pipe=pipeline(model="facebook/bart-large-mnli")
pipe("Ihaveaproblemwithmyiphonethatneedstoberesolvedasap!",
candidate_labels=["urgent","noturgent","phone","tablet","computer"],
)
#output
{'sequence':'Ihaveaproblemwithmyiphonethatneedstoberesolvedasap!!','labels':['urgent','phone','computer','noturgent','tablet'],'scores':[0.504,0.479,0.013,0.003,0.002]}
Heystack 中的ZeroShotTextRouter[3]就使用了MoritzLaurer/deberta-v3-base-zeroshot-v1.1-all-33模型。
本文讨论了意图识别在增强 RAG 应用方面的重要性。通过意图识别,用户可以根据用户的自然语言输入自动选择不同的处理路径,如 RAG、Text2SQL 或工具调用。同时介绍了几种实现方法,包括基于逻辑规则、通过 LLM 提示、函数调用、语义路由和零样本分类登,帮助系统更智能地响应用户查询。
| 欢迎光临 链载Ai (https://www.lianzai.com/) | Powered by Discuz! X3.5 |