1.背景介绍
概述
随着人工智能(AI)技术的不断发展,在许多行业中,都面临着如何快速、高效地为组织提供更好的客服服务的挑战。而面对客户各种各样的问题,以往我们都是采用人工的方式来解决这些问题,并以此进行售后服务。但是,随着自动化程度的提升以及智能客服机器人的普及,一些企业也试图采用基于机器学习的客服系统来替代人工客服,甚至还将其作为核心竞争力。基于深度学习和强化学习的方法可以提高系统的响应速度,减少等待时间,帮助企业更好地满足用户需求。 但是,由于复杂的业务逻辑,很多企业仍然需要人工智能工程师或机器学习专家的参与才能实现自动化。在这种情况下,基于机器学习的客服系统仍然具有很大的局限性。因此,如何更好地利用自动化工具和知识库构建一个专业的客服系统成为企业的难题。在本文中,我们将展示基于Rasa NLU和GPT-2技术框架的客户服务机器人(CSM),用于快速准确地处理用户的咨询请求,并帮助企业实现自动化服务。
动机
虽然现阶段人工智能技术已经取得了巨大的进步,但是对于大部分企业来说,拥有专门的人才团队来运维、部署和维护AI系统则是很困难的事情。同时,许多企业都会面临着如何快速、高效地为客户服务的问题。而面对客户各种各样的问题,以往我们都是采用人工的方式来解决这些问题,并以此进行售后服务。例如,企业可能会通过电话、邮箱或者通过线上平台向客户发送FAQ(常见问题解答)。但这样的方式效率低下,耗时长。同时,用户反馈不及时,会造成不良影响。 为了解决这个问题,许多企业开始探索基于机器学习和自然语言处理的新型客服系统。基于机器学习的客服系统可以用计算机来分析用户的语言并作出相应的回复,而且不必依赖人类的反馈。另外,除了利用客服人员的技能之外,还可以用大数据等技术收集用户的意见和评价,通过机器学习模型分析并预测用户的喜好,并改善产品或服务。 但是,目前大部分的客服系统仍然存在着以下三个主要缺点:
-
依赖场景:传统的客服系统基于人工规则,在特定领域内能够较为准确地回应用户的咨询。但是当遇到新的业务类型,比如说医疗健康、金融等诸如此类的时候,人工客服就束手无策了。除非有专门的工程师或机器学习专家开发适合该领域的客服系统,否则客服工作量极大,效率很低。
-
无法满足个性化:许多用户根据自己的需求、心情、习惯等方面有不同的客服技能。如果没有针对每个用户的定制化客服系统,那么将会出现非常多的重复服务。而如果每个用户都要输入相同的信息,那又可能陷入“信息茧房”——用户对同一个问题反复提问,客服只能重复发问。
-
缓慢且低效率:许多客服系统仅仅用来响应某些固定类型的咨询请求,用户的咨询越多,客服系统的负担就越重。而且,用户通常需要等待几分钟甚至十几分钟的时间才会收到回复。这样做既不符合用户的正常交互习惯,也耗费了许多企业的宝贵资源。 综合以上三个缺点,使得很多企业望而却步。他们希望找到一种更加精准的客服模式,让用户更快、更有效地得到解答,并改善用户体验。同时,也期待能够为企业提供自动化服务,节省人力物力,提升企业竞争力。
需求与目标
功能需求
- 提供客服服务:能够为用户提供快速、准确的客服服务,支持语音、文本、视频、图像等多种形式的咨询方式;
- 知识管理:能够建立客服知识库,包括常见问题、故障排查方法、解决方案等,通过AI算法进行自动问答和答案推荐;
- 会话跟踪:能够记录用户的历史会话,帮助企业识别热门话题、解决用户疑问;
- 持续学习:能够持续地学习和更新知识库,为用户提供最新的咨询建议;
- 用户画像:能够从用户的多种行为习惯、偏好等特征中挖掘出用户个性,改善客服服务。
性能需求
- 快速响应:客服系统的响应速度必须足够快,响应用户的关键词和查询必须在1秒内返回结果;
- 可靠性:客服系统必须具备良好的可靠性,保证每一次的咨询请求能够得到及时的响应;
- 技术成熟:客服系统必须能够兼容最新技术,能够处理海量的用户咨询请求;
- 可扩展性:客服系统的处理能力必须足够强大,能够在不间断服务的情况下持续为客户提供帮助。
研究方案与设计
1. AI解决方案
(1)Chatbot平台选型
目前,比较流行的开源聊天机器人平台有rasa,Botfuel,Dialogflow等。rasa是一个开源的机器学习聊天助手框架,它支持多个聊天引擎,如Facebook Messenger、Slack、Telegram等。rasa的训练集可以使用自然语言处理(NLP)工具进行标注,对话的训练过程也可以自动化。rasa的框架支持Python、JavaScript等主流编程语言,并且可以轻松地部署到云端。rasa还有丰富的第三方插件,可以提供如天气、股票等实用的功能。rasa同时也提供了一个基于Web界面管理聊天机器人的平台,可以直观地监控和管理聊天机器人的运行状态。 选择rasa作为我们的Chatbot平台,主要原因如下:
- 开源免费:rasa是开源项目,完全免费、无授权费,可以部署到私有服务器或者云平台;
- 支持丰富的接口:rasa提供了Facebook Messenger、Slack、Telegram、Wechat等接口,可以方便地与各大聊天平台连接;
- 社区活跃:rasa有成百上千的开发者和用户群,可靠的文档、支持、帮助中心;
- 功能强大:rasa可以实现复杂的对话管理、用户画像和会话跟踪、语音识别等功能。
(2)知识库建设
rasa支持了包括RegexExtractor(正则表达式抽取器)、RegexInterpreter(正则表达式解释器)、MitieEntityExtractor(MITIE实体识别器)等多种抽取器。为了建立知识库,我们可以将不同类型的问题划分到不同的intent(意图)中,然后训练rasa对这些意图的回答。rasa还支持自定义实体,可以通过配置实体识别器、正则表达式等进行匹配。
(3)业务规则管理
在现有的聊天机器人技术中,有些功能模块无法实现,比如判断用户是否满意、积分兑换商品等。这时候,我们就可以利用rasa的API来调用其他服务,或者用外部脚本进行一些规则校验。
2. GPT-2语言模型技术
(1)概述
GPT-2(Generative Pre-trained Transformer 2) 是 OpenAI 的一个最新研究成果,是在语言模型训练过程中借鉴了 transformer 模型的架构,利用 BERT(Bidirectional Encoder Representations from Transformers) 方法预训练生成模型。它的最大特点就是利用 Transformer 模型能够在不了解词汇之间相互关联的结构特性,而不需要手工构建语法和词法分析器,从而在一定程度上解决了 NLP 中的 “知其然,而不知其所以然” 问题。 OpenAI 在 GitHub 上提供了 GPT-2 的 TensorFlow 版本的代码实现,具体使用方法如下:
-
安装环境
pip install tensorflow==2.0.0 pip install transformers==2.9.1 git clone https://github.com/openai/gpt-2.git cd gpt-2 -
下载模型
export MODEL_DIR=models curl -o $MODEL_DIR/model.tar.gz https://storage.googleapis.com/gpt-2/releases/download/v1.0/checkpoint.tar.gz tar xf $MODEL_DIR/model.tar.gz -C $MODEL_DIR将下载的模型解压到 models 文件夹下。
-
生成文本示例
import openai # replace with your own API key openai.api_key = "YOUR_API_KEY" response = openai.Completion.create( engine="text-davinci-001", prompt="I want to book a hotel in Beijing for the weekend.", max_tokens=100 ) print(response["choices"][0]["text"])上面的代码即调用了 OpenAI 的 GPT-2 模型完成了一个文本生成任务,输入了用户的提示语句 "I want to book a hotel in Beijing for the weekend." ,输出了由 GPT-2 生成的一些句子,这里只打印了第一条结果。模型的参数设置为 text-davinci-001 。其中 API_KEY 需要自己去申请。
(2)Rasa Agent结合GPT-2模型
Rasa Agent 是 Rasa 框架的一个内部组件,它负责对用户输入的语句进行理解,然后按照指定的策略做出相应的回应。如果需要实现对话系统中的槽值填充任务,则需要结合 GPT-2 模型进行问答生成。本节将介绍如何结合 GPT-2 模型来实现问答生成。
(2.1)初始化Agent
首先,创建一个名为 chatbot 的新 agent:
from rasa_sdk import Agent
agent = Agent('chatbot')
(2.2)注册槽填充槽
然后,创建一个槽位 "name":
from rasa_sdk.forms import FormAction
class BookHotelForm(FormAction):
def name(self):
return 'book_hotel'
@staticmethod
def required_slots(tracker):
return ["name"]
def slot_mappings(self):
return {
"name": self.from_text()
}
(2.3)注册槽填充槽后端
设置槽位后端,该后端将处理槽位的设置请求:
from typing import Dict, Text, Any
import requests
class BookHotelForm(FormAction):
@classmethod
def load_settings(cls,
path: Text,
action_endpoint: Optional[EndpointConfig] = None
) -> "FormPolicy":
try:
cls._load_nlu_interpreter(path)
cls.apikey = os.getenv("OPENAI_API_KEY")
except Exception as e:
logging.error("Failed to create form policy. Error: {}".format(e))
@staticmethod
def required_slots(tracker: Tracker) -> List[Text]:
return ['city']
@staticmethod
def _load_nlu_interpreter(path):
model_dir = Path(path).parent / "models/"
nlu_model = Interpreter.load(str(model_dir))
return nlu_model
@action.register("utter_ask_city")
def ask_city(dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
dispatcher.utter_message("Where do you want to stay?")
return []
@action.register("utter_city")
def utter_city(city: Text, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
dispatcher.utter_template("utter_selected_city", tracker, city=city)
return []
(2.4)定义槽填充动作
创建槽位的动作,该动作将处理槽位值的设置请求:
@action.register("action_book_hotel")
class ActionBookHotel(Action):
"""
Simple example of a custom action which utters slots values passed as input
and queries an external API (in this case, OpenAI's Codex) to generate natural language responses.
This demonstrates how to use a pre-trained Language Model like GPT-2 to generate responses based on user inputs.
"""
def name(self):
return "action_book_hotel"
async def run(
self,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: Dict[Text, Any],
) -> List[Dict[Text, Any]]:
slot_values = await self.get_slot_values(dispatcher, tracker, domain)
if not all([slot == value for slot, value in slot_values.items()]):
dispatcher.utter_message("Please fill out all required fields.")
return [AllSlotsReset()]
query = f"{slot_values['name']} hotel in {slot_values['city']} for the weekend"
api_url = "https://api.openai.com/v1/engines/davinci-codex/completions"
headers = {"Authorization": f"Bearer {self.apikey}"}
data = {'prompt': query,
'max_tokens': 100,
}
response = requests.post(api_url, headers=headers, json=data)
generated_text = response.json()["choices"][0]["text"].strip().capitalize()
dispatcher.utter_message(generated_text)
return []