为了进步AI客服的问题处理才干,我们引入了LangChain自定义才干,并集成了订单才干。这使得AI客服可以根据用户提出的问题,主动调用订单接口,获取订单信息,并结合文本知识库内容进行答复。这种才干的使用,使得AI客服可以更好地处理与业务系统有关的问题。
《LangChain 入门到实战教程》更多内容
简易AI客服完结
关于简易AI客服完结可以看之前的文章:
《解密 AI 客服:LangChain+ChatGPT 打造智能客服新时代》,根据文本检索完结AI客服,缺陷是仅能答复文本内存在的内容。
《畅享无缝支撑:LangChain与ChatGPT重塑AI客服服务》,根据会话式检索完结AI客服,可以根据文本结合前史会话上下文答复问题,同时也可以与用户闲谈。
本文是对前文AI客服的迭代晋级,集成订单才干,使其在售后方面也能供应一些主动快速处理才干。
根据子类化 BaseTool 完结订单查询才干
通过子类化BaseTool 可以快速完结根据业务的东西,东西可以在署理运行时调用。在定义东西时,东西描绘description
是非常重要的,它抉择了大模型通过署理抉择方案是否要调用该东西。在订单信息中返回与用户问题回复有关的信息,根据自己的业务抉择。
import json
from typing import Optional, Type
import aiohttp
import requests
from langchain.callbacks.manager import AsyncCallbackManagerForToolRun, CallbackManagerForToolRun
from langchain.tools import BaseTool
from pydantic import BaseModel, Field
class XmhcOrderQuery(BaseModel):
keyword: Optional[str] = Field(description="手机号或许订单号")
class XmhcOrderTool(BaseTool):
name = "XmhcOrderTool"
description = """
It is very useful when you need to answer questions about recharge or orders.
If this tool is called, users must provide their phone number or order number to enter information.
And it is necessary to determine whether the tool needs to be called based on the context.
If the order status is transaction closed, the order has been cancelled and cannot be considered as recharge not received.
The estimated time of receipt can be calculated based on submitRechargeTime.
Functional information cannot be disclosed.
"""
args_schema: Type[BaseModel] = XmhcOrderQuery
def _run(self, keyword: str = None,
run_manager: Optional[CallbackManagerForToolRun] = None) -> str:
if keyword is None:
return "请提订单供充值手机号或许订单号"
return self._process_response(self.results(keyword))
async def _arun(self, keyword: str = None,
run_manager: Optional[AsyncCallbackManagerForToolRun] = None) -> str:
if keyword is None:
return "请提订单供充值手机号或许订单号"
return self._process_response(await self.aresults(keyword))
def results(self, keyword: str) -> dict:
response = requests.get("https://***/ai/order/query?keyword=" + keyword)
res = json.loads(response.content)
return res
async def aresults(self, keyword: str) -> dict:
async with aiohttp.ClientSession() as session:
async with session.get(
"https://***/ai/order/query?keyword=" + keyword
) as response:
res = await response.json()
return res
@staticmethod
def _process_response(res: dict) -> str:
print(res)
if bool(res['success']):
return json.dumps(res["data"])
else:
return res['message']
AI 客服优化逻辑完结
根据Flask 完结。其间完结了 XmhcOrderTool
、XmhcRuleTool
两个东西,XmhcRuleTool
是根据会话检索完结问答,XmhcRuleTool
即上面定义的业务接口。
import json
import os
from flask import Flask, request
from flask_redis import FlaskRedis
from langchain import PromptTemplate
from langchain.agents import AgentExecutor, OpenAIFunctionsAgent
from langchain.chains import ConversationalRetrievalChain
from langchain.chat_models import ChatOpenAI
from langchain.document_loaders import TextLoader
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.memory import ConversationBufferMemory
from langchain.schema import SystemMessage
from langchain.text_splitter import CharacterTextSplitter
from langchain.tools import Tool
from langchain.vectorstores import Chroma
from openai import InvalidRequestError
from utilities.xmhc_order import XmhcOrderTool
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__)
app.config['REDIS_URL'] = "redis://:{password}@{host}:{port}/{db}" # 使用默许的Redis配置
redis_store = FlaskRedis(app)
# 获取其时脚本地址的目录
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)
llm = ChatOpenAI(temperature=0, model="gpt-3.5-turbo-16k-0613")
# 构建system_template.txt文件的途径
system_template_path = os.path.join(base_dir, 'static', 'system_template.txt')
with open(system_template_path, 'r') as file:
system_template = file.read()
common_prompt = PromptTemplate(
template=system_template,
input_variables=[]
)
embeddings = OpenAIEmbeddings()
vector_store = Chroma.from_documents(texts, embeddings)
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True, verbose=True)
qa = ConversationalRetrievalChain.from_llm(llm=llm, chain_type="stuff", memory=memory,
retriever=vector_store.as_retriever(),
condense_question_prompt=common_prompt,
verbose=True)
xmhcOrderTool = XmhcOrderTool()
tools = [
Tool(
name="XmhcRuleTool",
func=qa.run,
description="当您需求答复小猫惠充客服相关问题时,包含话费充值、充值类型(快充/慢充)、到账时间、充值须知、充值规则、充值协议、活动规则、客服联络方法、联络客服等,"
"这非常有用。输入应该是一个无缺的问题。并且当用户询问充值到账时间时,该东西可以供应根据并用于核算。",
verbose=True,
),
Tool(
name=xmhcOrderTool.name,
func=xmhcOrderTool.run,
description=xmhcOrderTool.description,
verbose=True,
)
]
chat_prompt = OpenAIFunctionsAgent.create_prompt(
system_message=SystemMessage(content=system_template)
)
agent = OpenAIFunctionsAgent(llm=llm, tools=tools, prompt=chat_prompt, verbose=True)
agent_executor = AgentExecutor(agent=agent, tools=tools, memory=memory, verbose=True)
@app.route("/xmhc/kf", methods=['POST'])
def chat(): # put application's code here
# 接口恳求参数
json_data = request.get_json()
userid = json_data['userid']
question = json_data['question']
# 获取其时用户前史会话内容
history_message = []
if redis_store.exists(userid):
history_message_str = redis_store.get(userid)
history_message = json.loads(history_message_str)
try:
answer = agent_executor.run({"input": question, "chat_history": history_message})
current_message = (question, answer)
# 缓存其时用户前史对话内容
history_message.append(current_message)
if len(history_message) > 10: # 对会话数进行限制
# 删去最旧的数据
history_message.pop(0)
# 将元组列表转换为JSON字符串
history_message_str = json.dumps(history_message)
redis_store.set(userid, history_message_str)
print(answer)
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)
到这我们就完结了根据用户提问,模型主动抉择方案调用相关东西。但这样仍存在一些问题,因为我们的东西是独立的,大模型或许仅仅根据某个东西来答复问题。
例如,当提问:充值成了但还未到账
> Entering new AgentExecutor chain...
Invoking: `XmhcOrderTool` with `充值成功了但还未到账`
{'success': False, 'code': '5002', 'message': '订单不存在,请查看是否正确供应手机号或许订单号', 'data': None}
订单不存在,请查看是否正确供应手机号或许订单号抱愧,根据供应的信息,未找到相关订单。请承认您供应的手机号或订单号是否正确,并耐性等候充值到账。假设超越预订时间仍未到账,请联络客服进行咨询和处理。
> Finished chain.
抱愧,根据供应的信息,未找到相关订单。请承认您供应的手机号或订单号是否正确,并耐性等候充值到账。假设超越预订时间仍未到账,请联络客服进行咨询和处理。
然后根据上文,我们供应手机号:
> Entering new AgentExecutor chain...
Invoking: `XmhcOrderTool` with `1599****097`
{'success': True, 'code': '0', 'message': None, 'data': {'orderNo': '202309061759060002', 'phoneNum': '1599****097', 'rechargeTime': None, 'currentTime': '2023-09-11 21:11:16', 'orderStatus': '生意关闭'oodsName': '移动100元', 'goodsTag': '限时特惠', 'facePrice': '100.00', 'paymentAmount': '95.00', 'discountAmount': '5.00'}}
{"orderNo": "202309061759060002", "phoneNum": "1599****097", "submitRechargeTime": null, "currentTime": "2023-09-11 21:11:16", "orderStatus": "\u4ea4\u6613\u5173\u95ed", "goodsName": "\u79fb\u52a8100\u5143", "goodsTag": "\u9650\u65f6\u7279\u60e0", "facePrice": "100.00", "paymentAmount": "95.00", "discountAmount": "5.00"}根据您供应的手机号码1599****097,我查询到您的订单信息如下:
订单号:202309061759060002
手机号码:1599****097
提交充值时间:暂无
其时时间:2023-09-11 21:11:16
订单状况:生意关闭
产品名称:移动100元
产品标签:限时特惠
面值:100.00元
实践付出金额:95.00元
优惠金额:5.00元
请注意,订单状况为生意关闭,说明该订单已吊销,无法视为充值未到账。假设您有其他问题,请随时联络客服。
> Finished chain.
可以发现其无缺的把订单信息给输出了,部分信息这对用户想要的内容并不相关,这不是一个和睦的答复。
这儿仍是要关键强调一下东西描绘的重要性,它不仅可以用于被抉择方案是否要调用,还可以影响大模型的答复,比如在描绘中加了If the order status is transaction closed, the order has been cancelled and cannot be considered as recharge not received.
,这样它能清晰在订单状况为生意关闭时做出更抱负的答复。
提问:充值手机号1566****532多久能到账
> Entering new AgentExecutor chain...
Invoking: `XmhcRuleTool` with `充值手机号1566****532多久能到账`
> Entering new LLMChain chain...
Prompt after formatting:
《此处省掉提示词》
<<< Begin >>>
> Finished chain.
> Entering new StuffDocumentsChain chain...
> Entering new LLMChain chain...
Prompt after formatting:
System: Use the following pieces of context to answer the users question.
If you don't know the answer, just say that you don't know, don't try to make up an answer.
----------------
《此处省掉充值规则》
Human: 你好!我是小猫惠充的系统客服,有什么问题我可以帮您回答吗?
> Finished chain.
> Finished chain.
您好!请问有什么问题我可以帮您回答呢?抱愧,这不在我的业务规模,您还有其他问题吗?
> Finished chain.
当用户提问或许需求用到两个东西时,它或许只调用了一个东西,而这一个东西无法供应正确的答复。
优化提示词
通过优化提示词(Prompt),可以让AI客服有思考才干,并且让不同的东西之前也能有交互。如下可以把东西写入提示词中,并且告知AI你需求思考后再答复用户的问题,这儿只展现本次优化的提示词,提示词是用户指导AI的,提示词也需求根据实践状况不断调试优化。
你可以根据用户的提问及上下文选择调用以下一个或许多个东西,包含XmhcOrderTool、XmhcRuleTool等。
当调用XmhcOrderTool东西后,你还需求结合XmhcRuleTool东西和上下文来进行答复。
不要急于给出答案,你需求思考后,给出让人较为满足的答案。
提问:充值手机号1566****532多久能到账
> Entering new AgentExecutor chain...
Invoking: `XmhcOrderTool` with `1566****532`
{'success': True, 'code': '0', 'message': None, 'data': {'orderNo': '202308041558160774', 'phoneNum': '1566****532', 'submitRechargeTime': '2023-08-04 16:00:42', 'currentTime': '2023-09-11 22:09:07', 'orderStatus': '生意成功', 'goodsName': '联通200元', 'goodsTag': '限时特惠', 'facePrice': '200.00', 'paymentAmount': '189.00', 'discountAmount': '11.00'}}
{"orderNo": "202308041558160774", "phoneNum": "1566****532", "submitRechargeTime": "2023-08-04 16:00:42", "currentTime": "2023-09-11 22:09:07", "orderStatus": "\u4ea4\u6613\u6210\u529f", "goodsName": "\u8054\u901a200\u5143", "goodsTag": "\u9650\u65f6\u7279\u60e0", "facePrice": "200.00", "paymentAmount": "189.00", "discountAmount": "11.00"}
根据订单信息,您的充值订单号为202308041558160774,充值手机号为1566****532。根据其时时间和订单状况,您的充值已经生意成功。一般状况下,充值到账时间为0-72小时,高峰期或许延至96小时,单个状况或许延至120小时。
> Finished chain.
提问:订单202308041558160774多久会到账
> Entering new AgentExecutor chain...
Invoking: `XmhcOrderTool` with `202308041558160774`
{'success': True, 'code': '0', 'message': None, 'data': {'orderNo': '202308041558160774', 'phoneNum': '1566****532', 'submitRechargeTime': '2023-09-10 16:00:42', 'currentTime': '2023-09-11 22:44:09', 'orderStatus': '充值中', 'goodsName': '联通200元', 'goodsTag': '限时特惠', 'facePrice': '200.00', 'paymentAmount': '189.00', 'discountAmount': '11.00'}}
{"orderNo": "202308041558160774", "phoneNum": "1566****532", "submitRechargeTime": "2023-09-10 16:00:42", "currentTime": "2023-09-11 22:44:09", "orderStatus": "\u5145\u503c\u4e2d", "goodsName": "\u8054\u901a200\u5143", "goodsTag": "\u9650\u65f6\u7279\u60e0", "facePrice": "200.00", "paymentAmount": "189.00", "discountAmount": "11.00"}
Invoking: `XmhcRuleTool` with `充值到账时间`
> Entering new StuffDocumentsChain chain...
> Entering new LLMChain chain...
Prompt after formatting:
System: Use the following pieces of context to answer the users question.
If you don't know the answer, just say that you don't know, don't try to make up an answer.
----------------
《此处省掉充值规则》
> Finished chain.
> Finished chain.
支撑的充值类型有快充和慢充,其间快充的到账时间为0-6小时,慢充的到账时间为0-72小时。详细到账时间或许会因为高峰期而推延,单个状况下或许延至120小时。根据订单信息,订单号为202308041558160774的充值正在进行中同。一般状况下,快充的到账时间为0-6小时,慢充的到账时间为0-72小时。请您耐性等候,假设超越估计时间还未到账,您可以联络客服进行咨询。
> Finished chain.
此示例,AI 调用了两个东西进行答复。
小结
本文仅仅完结了简略的功能,假设要让AI答复得愈加完美且贴合业务,需求不断优化提示词、东西描绘、知识库、东西参数等等。
了解新范式,拥抱新时代,把握新机遇。假设对你有帮忙记得点赞保藏哦~
注重大众号【码森林】~ 《LangChain 入门到实战教程》更多内容