随着聊天机器人在不同行业越来越受欢迎,保持准确和有趣的交互对于成功的用户体验至关重要。然而,聊天机器人经常胡说八道,随着时间的推移,它们的回答变得不那么相关和可理解。用户可能会觉得这很烦人,也可能会降低聊天机器人的效率。
一个简单直接的方法可以用来阻止ChatGPT胡说八道,保持聊天机器人的焦点。我们将在这篇文章中研究这种方法,并展示它是如何使用ChatGPT工作的,ChatGPT是一种高度健壮的大型语言模型(LLM),最近在不同的专业领域得到了广泛的普及。本文将只讨论实际实现,因为已经有几篇文章介绍了ChatGPT的技术方面。
GPT-3与ChatGPT
为了清楚起见,ChatGPT与GPT-3并不完全相同,尽管它使用GPT-3模型作为其主干。ChatGPT的训练策略更进一步,融合了监督学习和强化学习的概念。特别是,OpenAI使用了来自人类反馈的强化学习(RLHF),它利用人类AI训练器提供反馈,用于提高模型的性能。这种方法本质上允许模型对正确的反应进行“奖励”,对错误的反应进行“惩罚”,就像我们训练宠物或教育孩子一样。
强化学习中使用人工输入来教导AI模型哪些行为是首选的,哪些是应该避免的。从这个反馈中,模型修改它的行为,努力最大化奖励和减少惩罚。这个过程使模型能够通过从错误中学习,随着时间的推移改善与人的互动。虽然这项技术在纸面上看起来很简单,但在实践中很难成功实施。
用ChatGPT模型构建聊天机器人
现在,继续我们的实现,我们将依赖上一篇关于微调GPT-3模型的文章中实现的一些函数。与使用GPT-3构建聊天机器人不同,我们将使用ChatGPT模型,在OpenAI的模型页面上简称为gpt-3.5-turbo。
为了使用模型运行推理,我们将使用以下函数:
def generate_response_chatgpt(input_text):
prompt = [{"role": "system",
"content": "You are DSA, a large language model for answering data structure and algorithm questions. "
"Answer as concisely as possible. Limit your response to 60 words. \nKnowledge cutoff: "
"2023-03-01\nCurrent date: 2023-03-02"},
{"role": "user", "content": "who are you"},
{"role": "assistant", "content": "I am DSA, my purpose is to answer your questions on data structure "
"and algorithms"},
{"role": "user", "content": "{}".format(input_text)}]
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=prompt
)
return completion.choices[0].message.content.strip()
从代码中可以看出,提示样式与text-davinci-003(GPT-3)有些不同。我们现在有了使用聊天标记语言(ChatML)的能力,它支持解析JSON作为输入聊天消息,而不是以前API中的非结构化文本。
另外,我们实现了一个flask API来服务于模型:
@app.route("/chat_openai", methods=['POST'])
def get_bot_response_chatgpt():
if request.method == 'POST':
output_text = []
try:
user_text = request.get_json()["text"]
output_text = generate_response_chatgpt(user_text)
return jsonify({"error": None,
"message": str(output_text),
"status": 200}), 200
except Exception as error:
return jsonify({"error": True,
"message": "Can't to process the input questions",
"status": 400}), 400
else:
return jsonify(success=False), 405
通过调用API,我们对上面实现的函数进行了一些测试:
初步问题及回应:
input: {
"text": "tell me about linked list"
}
DSA:{
"message": "A linked list is a linear data structure consisting
of a sequence of nodes, where each node contains a data element
and a pointer to the next node in the sequence. Unlike an array,
a linked list does not have a fixed size and can dynamically grow
or shrink. Linked lists are efficient in terms of insertion and
deletion operations but accessing an element at a particular index
requires traversing the list from the beginning."
}
跟进问题及回应:
input: {
"text": "how can we use it"
}
DSA: {
"message": "You can use DSA to ask questions and receive concise answers
on topics related to data structures and algorithms. You might
use that information to improve your coding skills, prepare
for technical interviews, or better understand how to approach
programming problems in general."
}
很明显,该模型无法将后续问题与前一个问题联系起来,这在聊天机器人中被简单地称为对话漂移。
让ChatGPT停止乱说话
我们将利用新的ChatML功能来管理聊天机器人对话中的漂移。
为了解决这个问题,我们使用了一个简单的会话概念,并将后续会话附加到旧会话中,同时使用会话来管理模型何时应该继续对话或启动新对话。具体实现如下:
def generate_response_chatgpt_no_drift(input_text, interview_history):
prompt = [{"role": "system",
"content": "You are DSA, a large language model for answering data structure and algorithm questions. "
"Answer as concisely as possible. Limit your response to 60 words. \nKnowledge cutoff: "
"2023-03-01\nCurrent date: 2023-03-02"},
{"role": "user", "content": "who are you"},
{"role": "assistant", "content": "I am DSA, my purpose is to answer your questions on data structure "
"and algorithms"},
{"role": "user", "content": "{}".format(input_text)}]
if interview_history is not []:
for interview in interview_history:
prompt.append({"role": "assistant", "content": "{}".format(interview["question"])})
prompt.append({"role": "user", "content": "{}".format(interview["answer"])})
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=prompt
)
return completion.choices[0].message.content.strip()
我们将它的flask API实现为:
session = {"session_id": ""}
interview_history = []
@app.route("/chat_openai_no_drift", methods=['POST'])
def get_bot_response_chatgpt_no_drift():
if request.method == 'POST':
output_text = []
try:
user_text = request.get_json()["text"]
session_id = request.get_json()["session_id"]
print(session_id)
print(session["session_id"])
if session_id == session["session_id"]:
output_text = generate_response_chatgpt_no_drift(user_text, interview_history)
interview = {
"question": user_text,
"answer": output_text
}
interview_history.append(interview)
else:
session["session_id"] = session_id
interview_history2 = []
output_text = generate_response_chatgpt_no_drift(user_text, interview_history2)
interview = {
"question": user_text,
"answer": output_text
}
interview_history2.append(interview)
return jsonify({"message": str(output_text),
"error": None,
"status": 200}), 200
except Exception as error:
logging.error([error])
return jsonify({"error": True,
"message": "Can't to process the input questions",
"status": 400}), 400
else:
return jsonify({"error": "Not Allowed",
"status": 405}), 405
现在,让我们通过添加所需的session_id再次测试模型:
初步问题及回应:
input: {
"text": "tell me about linked list",
"session_id": "KJN=87aGNq"
}
DSA: {
"message": "A linked list is a linear data structure that consists of a
sequence of elements, each of which stores a reference
(or pointer) to an object and a reference to the next element
in the sequence. The elements are not necessarily stored in
contiguous memory locations, and so linked lists can grow or
shrink dynamically at runtime. Common operations performed on
linked lists include insertion, deletion, traversal, and search.",
}
跟进问题及回应:
input: {
"text": "how can we use it ",
"session_id": "KJN=87aGNq"
}
DSA: {
"message": "We can use linked lists to implement various data structures
such as Stacks, Queues, Hash tables and Graphs. Linked lists
are also used in applications like train route databases,
music playlists, and text editors. They can also be used to
implement dynamic memory allocation, where memory is allocated
and deallocated during program execution as needed.
Furthermore, linked lists are fundamental for understanding
algorithm complexities and improving problem-solving abilities.",
}
我们现在可以注意到,只要session_id没有更改,对话就从初始对话继续进行。然而,值得注意的是,该模型中可接受的令牌的最大数量是4096,因此,一旦超过这个数量,我们就会遇到一些错误,在这种情况下,必须更改session_id以启动新的会话。