大家好,我是 AI 研习者轻寒。最近一直在研究 LangChain,感觉受益良多。刚好最近发现我的小猫惠充公众号有好多人在咨询一些充值相关的问题,但总是没时间去回复,所以想着做一个客服。本教程将基于 LangChain 结合 ChatGPT 实现并部署 AI 客服。 《LangChain 入门到实战教程》更多内容
你需要了解
ChatGPT
ChatGPT 是 OpenAI 开发的一种基于人工智能技术的自然语言处理模型。它可以通过对大量文本数据进行训练,自动生成高质量的回答和对话。ChatGPT 具有高效、准确、自然的特点,可以帮助人们更加高效地处理信息和交流。
ChatGPT 有很多应用场景,本文主要以简易客服场景来实现一个案例。
LangChain
LangChain是一个用于开发由语言模型驱动的应用程序的框架。
他是让应用程序不仅可以通过 API 调用语言模型,而且可以数据感知(将语言模型连接到其他数据源),Be agentic(允许语言模型与其环境交互),最终让应用程序更强大和更具差异化。
这里不过多介绍了。详见《LangChain专栏》或官方文档。
开发部署能力
- Java
- Python
- docker
- ...
功能分析
要在公众号实现一个客服,首先想到了微信的对话平台,但测试了下感觉不怎么友好,怎么也触发不了我自定义的能力,所有核心以公众号客服消息为对话方式。
- 公众号客服消息权限开通,这个需要认证过的公众号或者服务号,小猫惠充是服务号所以没问题;
- 要获取用户发来的消息,需要对接普通消息推送,该功能集成到小猫惠充的后台,使用 Java 实现;
- 要给用户发送消息,需要对接客服接口-发消息,该功能集成到小猫惠充的后台,使用 Java 实现;
- 要有客服资料库,用于给客服问答做依据,本文支持 .txt 文本文件(其他文档要支持只需更换文档加载器即可);
- 加载文档,利用 embeddings 模型把文档内容加载到矢量存储,用于相似性检索,本文采用 Chroma,使用 Python 实现(这里采用 OpenAI Embeddings 模型);
- 进行检索资料,调用 OpenAI gpt-3.5-turbo-0613 模型进行回答,使用 Python 实现;
- 部署采用 docker-compose 进行部署,并能挂载配置文件和资料库文件。
以上主要分为两个项目公众号消息收发使用 Java 实现,AI 相关逻辑基于 LangChain 使用 Python 实现。
公众号配置
在公众号后台基础配置中,我们需要进行相关配置。
在新的功能中,需要开通客服功能。
核心代码
Java 实现用户消息接受
这个 URL 就是上面微信公众号配置的服务器地址URL。
arduino
/**
* 事件接收处理接口
*
* @return
*/
@PostMapping(value = "/notifyUrl")
public String notifyUrl(WXNotifyReqVO reqVO) throws Exception {
log.info("接入成功,正在处理逻辑,reqVO:{}", JSONUtil.toJsonPrettyStr(reqVO));
// 获取HTTP请求的输入流
// 已HTTP请求输入流建立一个BufferedReader对象
BufferedReader br = new BufferedReader(new InputStreamReader(
getRequest().getInputStream(), "UTF-8"));
String buffer;
// 存放请求内容
StringBuilder xml = new StringBuilder();
while ((buffer = br.readLine()) != null) {
// 在页面中显示读取到的请求参数
xml.append(buffer);
}
WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, AppSecretEnum.XMHC.getAppId());
// 第三方收到公众号平台发送的消息
String mingwen = pc.decryptMsg(reqVO.getSignature(), reqVO.getTimestamp(), reqVO.getNonce(), xml.toString());
log.info("解密后明文: " + mingwen);
Map<String, String> params = XmlUtils.xml2Map(mingwen);
return wxOffiAccountLogic.handleNotify(params);
}
Java 实现消息接受处理,异步转发给 AI 客服
以下代码是服务端接受到用户发送的消息后,立即异步转发消息给 AI 客服。
为什么要异步?微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次,这会导致向 AI 客服发送的消息也会重复。
假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。
typescript
private ExecutorService executor = Executors.newFixedThreadPool(5);
/**
* 处理微信公众号事件通知
*
* @param params
* @return
*/
public String handleNotify(Map<String, String> params) {
log.info("WXOffiAccountLogic,handleNotify,params:{}", JSONUtil.toJsonPrettyStr(params));
String msgType = params.get("MsgType");
switch (msgType) {
case "event":
return handlerNotifyEvent(params);
case "text":
executor.submit(() -> {
// 异步处理逻辑
handlerNotifyText(params);
});
return null;
default:
return null;
}
}
private String handlerNotifyText(Map<String, String> params) {
String fromUser = params.get("FromUserName");
String content = params.get("Content");
Map<String, Object> reqParams = new HashMap<>();
reqParams.put("content", content);
String result = HttpUtil.post("https://{your ai custom service}/xmhc/kf", JSONUtil.toJsonPrettyStr(reqParams));
JSONObject response = JSONUtil.parseObj(result);
if (response.get("err_code").equals(0)) {
CustomMessageSendRequest request = new CustomMessageSendRequest();
request.setAccessToken(getAccessToken());
request.setToUser(fromUser);
request.setMessageType("text");
JSONArray dataList = response.getJSONArray("data_list");
if (dataList.size() > 0) {
request.setContent(dataList.getJSONObject(0).getStr("content"));
} else {
request.setContent("亲,请详细描述一下您的问题~");
}
wxOffiAccountApi.sendCustomMessage(request);
} else {
CustomMessageSendRequest request = new CustomMessageSendRequest();
request.setAccessToken(getAccessToken());
request.setToUser(fromUser);
request.setMessageType("text");
request.setContent("亲,请详细描述一下您的问题~");
wxOffiAccountApi.sendCustomMessage(request);
}
return null;
}
其中 https://{your ai custom service}/xmhc/kf
为 AI 客服服务的请求地址。
请求 content-type 为 application/json
请求参数格式:
css
{
"content": "充值后多久到账?"
}
响应参数格式:
css
{
"data_list": [
{
"content": "根据提供的充值须知,话费优惠充值的到账时间为0-6小时或0-72小时,具体取决于产品类型和充值时段。一般情况下,产品会在6小时内或72小时内到账。但在高峰期,可能需要96小时甚至更长的时间才能到账。少数情况下,到账时间可能延迟至120小时。如果超过规定的到账时间仍未到账,则会全额退款。"
}
],
"err_code": 0
}
AI 客服实现 app.py
ini
import os
from flask import Flask, request
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
from langchain.document_loaders import TextLoader
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import Chroma
from openai import InvalidRequestError
from utils import get_env
os.environ["OPENAI_API_KEY"] = get_env('OPENAI_API_KEY')
os.environ["OPENAI_API_BASE"] = get_env('OPENAI_API_BASE')
app = Flask(__name__)
# 获取当前脚本所在的目录
base_dir = os.path.dirname(os.path.abspath(__file__))
# 构建doc.txt文件的路径
doc_path = os.path.join(base_dir, 'static', 'doc.txt')
loader = TextLoader(doc_path)
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)
embeddings = OpenAIEmbeddings()
docsearch = Chroma.from_documents(texts, embeddings)
qa = RetrievalQA.from_chain_type(llm=ChatOpenAI(model_name='gpt-3.5-turbo-0613'), chain_type="stuff",
retriever=docsearch.as_retriever())
@app.route("/xmhc/kf", methods=['POST'])
def hello_world(): # put application's code here
# 接口请求参数
json_data = request.get_json()
try:
answer = qa.run(json_data['content'])
except InvalidRequestError:
return {
"err_code": -1,
"data_list": []
}
return {
"err_code": 0,
"data_list": [
{"content": answer}
]
}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=18880, debug=True)
相关依赖 requirements.txt
ini
Flask==2.2.3
langchain==0.0.215
python-dotenv==1.0.0
openai~=0.27.4
chromadb~=0.3.26
tiktoken~=0.4.0
SQLAlchemy~=2.0.17
安装依赖
pip install -r requirements.txt
客服资料库
只需要简单的文本即可。
AI 客服部署
我这里采用 Docker 部署。先创建一个简单 Dockerfile 用于构建镜像,Dockerfile 与上面的 app.py 和 requirements.txt 同一目录。
sql
FROM python:3.9.17
ENV GIT_SSL_NO_VERIFY=1
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
COPY . .
CMD [ "python3", "app.py" ]
在 Terminal 中执行如下命令,完成镜像构建。
bash
docker build -t xunlu-kf:1.0.0 .
docker images # 获取镜像ID cc07f3641130
我这里采用阿里云进行镜像管理。
bash
docker tag 35949b43ad7a registry.cn-hangzhou.aliyuncs.com/zwqh/xunlu-kf:1.0.0
docker push registry.cn-hangzhou.aliyuncs.com/zwqh/xunlu-kf:1.0.0
编写 docker-compose.yaml 部署脚本。
yaml
version: '3.9'
services:
chatbot:
image: registry.cn-hangzhou.aliyuncs.com/zwqh/xunlu-kf:1.0.0
volumes:
- ./app/.env:/app/.env
- ./app/static/:/app/static/
ports:
- 18880:18880
networks:
- xunlu
networks:
xunlu:
external: true
在服务器上 docker-compose.yaml 目录下,通过以下命令完成部署。
docker-compose up -d
演示成果
这里产生了两条数据就是因为没有进行异步请求。
当回答不了你的问题时,它也不会胡乱回答,如下它只会根据提供的资料进行回答。
结尾
基于 LangChain 框架,一个简单的 .txt 文本文件结合 OpenAI 即可实现一个简易客服。但这个仅限独立部署,免费的 ChatGPT Api Key 每分钟有请求限制,太频繁可能会报错。《AI客服优化篇》
理解新范式,拥抱新时代,把握新机会。
想要了解更多 AI 内容,记得关注我哦!觉得对你有用的话,记得点赞,转发给你的朋友!如果有什么问题可以私信我~ 《LangChain 入门到实战教程》更多内容