欢迎大家来到企业级AI售前机器人实战系列文章: 从0到1完成一个企业级AI售前机器人的实战指南。
本篇是该系列的第四篇,核心内容是:实现用户意图分析,并且针对不同的意图执行不同的工作流
为了能够更好的让AI与用户进行沟通,我们需要先拆解在我们的业务场景中,我们的用户可能存在哪些意图。
随后我们将这些意图分发到不同的路由中执行对应的工作流,来针对性的回复用户,达到最好的对话效果。
例如:在售前场景中,我们的用户与我们的对话可以被我们拆解为以下意图:
1. 谈合同
预期场景:用户表达了非常强的购买意向
示例问题:X产品怎么购买?
、购买产品要签订什么协议?
响应方式:此时需要具体分析用户的意图,进行下单链接的推荐或者合同、协议的推送
2. 留资
预期场景:用户表达了需要换个方式沟通,或者对话过程中AI认为需要用户进行留资。
示例问题:电话联系吧
、微信聊可以么?
响应方式: 此时需要存储用户的信息 + 与访客约定回访时间。
3. 需要产品推荐
预期场景:用户需要我们为其推荐一些产品。
示例问题:你们有适合XX场景的产品么?
响应方式:此时需要给用户进行产品推荐(必要时,需要先反问收集必要信息,然后才进行产品推荐)
4. 咨询某产品细节
预期场景:用户针对某产品细节进行沟通询问
示例问题:套餐A和B的区别?
、某产品可以做到XX事么?
响应方式:根据对应的相关资料进行回复。没有资料时,将会触发留资场景。
5. 需要产品介绍
预期场景:用户需要我们介绍产品信息
示例问题:某产品怎么样?
、某产品能做到XX么?
响应方式: 对产品的基本信息、能力、规格、价格、套餐、活动价、案例等进行介绍
6. 询问其他场景
预期场景:与售前无关,但是与企业内其他工作(售后、客户经理)相关的query
示例问题:系统始终无法正确运行,怎么办?
响应方式:针对不同场景进行个性化推荐
7. 闲聊
预期场景:闲聊
示例问题:你好
、你是谁
响应方式:保持售前人设的同时进行简单的回复,避免回复不必要的问题。
本篇讲解的重点将是如何进行对应路由的设计的代码编写。
关于我
我是一个十年老程序员、React Contributor,三年前转型至AI在应用层的设计与落地。
目前转型成功,并担任多个AI项目负责人,已经完成了多款智能问答产品的上线、以及TOB产品的功能AI化升级。
本专栏将会基于我过去几年的经验,对各类AI应用落地的方案和思路积累了很多踩坑和迭代经验,进行全方位的AI产品的核心流程拆解!
我相信AI在未来将会是基础设施,而对于普通人而言,基础设施的机会不在基础设施本身,在应用层谋求发展可能是一个不错的出路。
加油!共勉!
回归正题:
用户意图的路由设置
我们将在主流程代码中将任务进行完善的拆分和封装:
为了方便大家理解,我们代码中业务逻辑删除,处理函数都放到主文件中,代码位置src/index.js
,后面的章节我们会把处理函数封装到对应的目录中:
import searchKnowledge from './knowledge/index.js'
import { Models, chatModel } from './models/index.js'
import { output_prompt, useful_prompt, analyse_prompt } from './prompts/index.js'
export default async function main({ query, history }) {
// ! 意图分析
let userAction = await handleAction({ query, history })
let actionData; // 意图返回的结果
let newQuery = query
switch (userAction) {
case '1': // 需要谈合同
actionData = await handleHeTong({ query: newQuery })
break;
case '2': // 需要留资
actionData = await handleLiuZi({ query: newQuery })
break;
case '3': // 需要产品推荐
actionData = await handleTuiJian({ query: newQuery })
break;
case '4': // 咨询某产品细节
actionData = await handleXiJie({ query: newQuery })
break;
case '5': // 需要产品介绍
actionData = await handleJieShao({ query: newQuery })
break;
case '6': // 询问其他场景
actionData = await handleOther({ query: newQuery })
break;
default: // 闲聊
actionData = await handleTalk({ query: newQuery })
break;
}
// ! 最终回复
let result = await chatModel({
message: [
{ role: 'user', content: output_prompt({ query: newQuery, data: actionData }) },
],
model: Models.db_32k_model,
stream: true
})
return result
}
async function isUseful({ data, query }) {
let result = await chatModel({
message: [
{ role: 'user', content: useful_prompt({ query, data }) },
],
model: Models.db_32k_model,
})
return result.indexOf("Y")
}
async function handleAction({ query, history }) {
let result = await chatModel({
message: [
{ role: 'user', content: analyse_prompt({ query, history }) },
],
model: Models.db_32k_model,
})
return result
}
async function handleHeTong({ query }) {
let actionData = "合同的结果"
// ! 调用谈合同知识库
let [knowledgeData] = await searchKnowledge({ query, knowledgeTag: "合同", score: 0.45, limit: 1 })
// ! 根据知识库中的匹配,
if (knowledgeData === '合同') {
// 处理合同的业务逻辑
}
if (knowledgeData === '下单') {
// 处理下单的业务逻辑
}
return actionData
}
async function handleLiuZi({ query }) {
let actionData = "留资的结果"
// ! 调用大模型进行留资对话,提示词需要做两个判断,1 用户是否提供了联系方式, 2 如果没有提供则与用户沟通联系方式。 最后与用户预约回访时间
return actionData
}
async function handleTuiJian({ query }) {
let actionData = "产品推荐的结果"
// ! 调用产品推荐知识库
knowledgeData = await searchKnowledge({ query, knowledgeTag: "产品介绍", score: 0.45 })
// ! 判断知识库与用户信息的相关性
knowledgeDataIsUseful = isUseful({ data: knowledgeData, query })
if (!knowledgeDataIsUseful) {
knowledgeData = null
}
return actionData
}
async function handleXiJie({ query }) {
let actionData = "产品细节的结果"
// ! 调用产品细节知识库
actionData = await searchKnowledge({ query, knowledgeTag: "产品介绍", score: 0.45 })
// ! 判断知识库与用户信息的相关性
knowledgeDataIsUseful = isUseful({ data: knowledgeData, query })
if (!knowledgeDataIsUseful) {
knowledgeData = null
}
return actionData
}
async function handleJieShao({ query }) {
let actionData = "产品介绍的结果"
// ! 调用产品介绍知识库
knowledgeData = await searchKnowledge({ query, knowledgeTag: "产品介绍", score: 0.45 })
// ! 判断知识库与用户信息的相关性
knowledgeDataIsUseful = isUseful({ data: knowledgeData, query })
if (!knowledgeDataIsUseful) {
knowledgeData = null
}
return actionData
}
async function handleOther({ query }) {
let actionData = "其他场景的结果"
// ! 调用大模型进行对话,提示词需要做两个判断,当前的对话是否需要售后进行回答。
return actionData
}
async function handleTalk({ query }) {
let actionData = "其他场景的结果"
// ! 调用大模型进行对话,提示词需要做两个判断,当前的对话是否需要售后进行回答。
return actionData
}
代码的解释:
首先,我们采用了意图分析的方式,在用户发起了一次对话之后,我们利用大模型进行了用户的意图分析。
得到用户的真实意图之后,根据不同的意图进行不同的处理逻辑,有调用知识库的,有调用后台接口的,也有直接大模型回复的。
不同的意图处理完成之后,最终是使用一套大模型进行统一的回复。
这里需要注意的一点是,整个代码流程中,只有最后回复的大模型是流式输出,其他的节点都不进行流式输出!
因为最终的代码响应我们是需要快速的呈现给用户响应,所以必须使用流式输出来保障最终的效率,流式输出的情况下,我们只需要考虑首包的响应时间即可,而绝大多数大模型的首包响应时间是在1秒以内。
此外,有同学可能发现了一个问题,在handleHeTong
函数里我们把发送合同模板和发送下单链接放到一个意图里,使用知识库来实现,可是这好像是两个意图呀?
这里的逻辑是:我们应该尽可能的控制意图的数量和意图的处理时间。
意图的数量太多会造成大模型的分析精度下降,而处理时间太久会造成我们产品的整体回复时间过长。
通常我们处理的方案有两种:
- 两个意图放到知识库中处理,利用知识库的语义分析和响应速度快的有点。
- 两个意图合并成一个意图,获取包含两个意图的资料后,由大模型进行回复。
再看发送合同
和发送下单链接
,这两个行为之间具有两个非常大的优势:
- 发送合同和发送下单链接需要处理的信息量非常少
- 发送合同和发送下单链接对话内容的区别足够大,易于进行语义匹配
这两点就是我们把两个意图都放到合同意图下,并使用知识库来进行匹配的原因。
本篇我们主要了解了如何实现用户意图分析的代码逻辑。有什么问题大家可以留言,看到就给大家回复。
结语
下一篇我们讲解用户意图分析体系的优化点和提示词编写逻辑:
-
提示词:讲解在流程中的哪些位置使用提示词,为什么需要提示词,提示词编写的逻辑。
-
优化一:问题拆分,解决用户一个问题询问多个问题
-
优化二:意图分提示词,每个意图都有特点的提示词要点
-
优化三:提示词安全优化,防止提示词泄露、防止破解提示词并做出响应
后续我会不断把新的内容搬到这个专练,希望这个系列能够打造成帮助大家落地AI产品时的实战手册!
大家多多点赞 + 关注,给点动力,更新的快快的!
提前订阅不迷路:售前AI机器人掘金专栏地址。
☺️你好,我是华洛,如果你对程序员转型AI产品负责人感兴趣,请给我点个赞。
你可以在这里联系我👉www.yuque.com/hualuo-fztn…
已入驻公众号【华洛AI转型纪实】,欢迎大家围观,后续会分享大量最近三年来的经验和踩过的坑。
专栏文章
# 从0到1打造企业级AI售前机器人——实战指南三:RAG工程的超级优化
# 从0到1打造企业级AI售前机器人——实战指南二:RAG工程落地之数据处理篇🧐