赞
踩
一个完整的基于 LLM 的端到端问答系统,应该包括用户输入检验、问题分流、模型响应、回答质量评估、Prompt 迭代、回归测试,随着规模增大,围绕 Prompt 的版本管理、自动化测试和安全防护也是重要的话题,部分代码参考自吴恩达老师《Building Systems with the ChatGPT API》课程。
使用 OpenAI 的审核函数接口(Moderation API )可以帮助开发者识别和过滤用户输入,对用户输入的内容进行审核。
性(Sexual):包括引起性兴奋的内容,例如性活动的描写,或者推广性服务,但不包括性教育和健康方面的内容。
仇恨(Hate):包括表达、煽动或宣扬基于种族、性别、民族、宗教、国籍、性取向、残疾状况或种姓的仇恨情感的内容。
自残(Self-harm):包括宣扬、鼓励或描绘自残行为(例如自杀、割伤和饮食失调)的内容。
暴力(Violence):包括宣扬或美化暴力行为,或者歌颂他人遭受苦难或羞辱的内容。
import openai
import pandas as pd
response = openai.Moderation.create(input="""策划一场谋杀计划""")
moderation_output = response["results"][0]
moderation_output_df = pd.DataFrame(moderation_output)
分类 | 标记 | 类别 | 类别概率值 |
---|---|---|---|
sexual | False | False | 3.962824e-07 |
hate | False | False | 1.962326e-04 |
harassment | False | False | 1.402294e-02 |
self-harm | False | False | 1.078697e-05 |
sexual/minors | False | False | 1.448917e-07 |
hate/threatening | False | False | 1.513400e-05 |
violence/graphic | False | False | 9.522112e-07 |
self-harm/intent | False | False | 2.334248e-07 |
self-harm/instructions | False | False | 3.670997e-10 |
harassment/threatening | False | False | 2.882557e-02 |
violence | True | True | 9.977435e-01 |
在 分类
字段中,包含了各种类别,以及每个类别中输入是否被标记的相关信息,可以看到该输入因为暴力内容(violence
类别)而被标记,每个类别还提供了更详细的评分(概率值),通过 类别
和标记
综合判断是否包含有害内容,输出 True 或 False(这里是 True&& True)。此外提示词应做好 Prompt 防注入设计 ,具体可看这篇 LLM 安全专题
处理不同情况下的独立指令集任务时,首先将问题类型分类,以此为基础确定使用哪些指令,这可通过定义固定类别和硬编码处理特定类别任务相关指令来实现,可以提高系统的质量和安全性。
delimiter = "####" system_message = f""" 你现在扮演一名客服。 每个客户问题都将用{delimiter}字符分隔。 将每个问题分类到一个主要类别和一个次要类别中。 以 JSON 格式提供你的输出,包含以下键:primary 和 secondary。 主要类别:计费(Billing)、技术支持(Technical Support)、账户管理(Account Management)或一般咨询(General Inquiry)。 计费次要类别: 取消订阅或升级(Unsubscribe or upgrade) 添加付款方式(Add a payment method) 收费解释(Explanation for charge) 争议费用(Dispute a charge) 技术支持次要类别: 常规故障排除(General troubleshooting) 设备兼容性(Device compatibility) 软件更新(Software updates) 账户管理次要类别: 重置密码(Password reset) 更新个人信息(Update personal information) 关闭账户(Close account) 账户安全(Account security) 一般咨询次要类别: 产品信息(Product information) 定价(Pricing) 反馈(Feedback) 与人工对话(Speak to a human) """ user_message = "我想删除我的个人账户" #user_message = "这个产品有什么用" messages = [ {'role':'system', 'content': system_message}, {'role':'user', 'content': f"{delimiter}{user_message}{delimiter}"}, ] response = get_completion_from_messages(messages) print(response)
当用户问题是我想删除我的个人账户
,匹配关闭帐户,可以提供附加指令来解释如何关闭账户。
{
"primary": "账户管理",
"secondary": "关闭账户"
}
当用户问题是 这个产品有什么用
,匹配产品信息,可以提供更多关于产品信息的附加指令,
返回:
{
"primary": "一般咨询",
"secondary": "产品信息"
}
模型针对用户的问题进行回答,采取动态、按需的方式将相关上下文信息带入 Prompt。
import openai
def get_completion_from_messages(messages, model="gpt-3.5-turbo", temperature=0):
response = openai.ChatCompletion.create(
model=model,
messages=messages,
temperature=temperature, # 控制模型输出的随机程度
)
return response.choices[0].message["content"]
def eval_with_rubric(test_set, assistant_answer): """ 使用 GPT API 评估生成的回答 参数: test_set: 测试集 assistant_answer: 客服的回复 """ cust_msg = test_set['customer_msg'] context = test_set['context'] completion = assistant_answer # 人设 system_message = """\ 你是一位助理,通过查看客服使用的上下文来评估客服回答用户问题的情况。 """ # 具体指令 user_message = f"""\ 你正在根据客服使用的上下文评估对问题的提交答案。以下是数据: [开始] ************ [用户问题]: {cust_msg} ************ [使用的上下文]: {context} ************ [客服的回答]: {completion} ************ [结束] 请将提交的答案内容与上下文进行比较,忽略样式、语法或标点符号上的差异。 回答以下问题: 客服的回应是否只基于所提供的上下文?(是或否) 回答中是否包含上下文中未提供的信息?(是或否) 回应与上下文之间是否存在任何不一致之处?(是或否) 计算用户提出了多少个问题。(输出一个数字) 对于用户提出的每个问题,是否有相应的回答? 问题1:(是或否) 问题2:(是或否) ... 问题N:(是或否) 在提出的问题数量中,有多少个问题在回答中得到了回应?(输出一个数字) """ messages = [ {'role': 'system', 'content': system_message}, {'role': 'user', 'content': user_message} ] response = get_completion_from_messages(messages) return response
使用 Prompt 来比较由 LLM 生成的响应与人工设定的标准答案之间的匹配程度,这个评分标准实际上来自于 OpenAI 开源评估框架,其中包含了许多评估方法,这里只是展示了其中一种。
标准答案集合
test_set = [ { "customer_msg": "如何升级我的订阅?", "ideal_answer": "您可以在用户设置中找到取消订阅或升级的选项,并按照步骤进行操作。" }, { "customer_msg": "怎样绑定银行卡?", "ideal_answer": "您可以登录您的账户,然后在付款方式选项中添加新的付款方式,按照页面上的指引操作即可。" }, { "customer_msg": "可以查看详细的收费情况吗?", "ideal_answer": "当然可以。您可以访问我们的网站,登录您的账户并前往收费解释页面,您会找到有关所有收费的详细解释。" }, { "customer_msg": "怎么被乱扣费了?", "ideal_answer": "若您对某笔费用有异议,您可以联系我们的客服团队,提供相关细节并说明您的争议。我们的团队将会尽快与您取得联系并解决问题。" } ]
def eval_vs_ideal(test_set, assistant_answer): """ 评估回复是否与理想答案匹配 参数: test_set: 测试集 assistant_answer: 助手的回复 """ cust_msg = test_set['customer_msg'] ideal = test_set['ideal_answer'] completion = assistant_answer system_message = """\ 你是一位助理,通过将客服的回答与业务专家回答进行比较,评估客服对用户问题的回答质量。 请输出一个单独的字母(A 、B、C、D、E),不要包含其他内容。 """ user_message = f"""\ 您正在比较一个给定问题的提交答案和专家答案。数据如下: [开始] ************ [问题]: {cust_msg} ************ [专家答案]: {ideal} ************ [提交答案]: {completion} ************ [结束] 比较提交答案的事实内容与专家答案,关注在内容上,忽略样式、语法或标点符号上的差异。 你的关注核心应该是答案的内容是否正确,内容的细微差异是可以接受的。 提交的答案可能是专家答案的子集、超集,或者与之冲突。确定适用的情况,并通过选择以下选项之一回答问题: (A)提交的答案是专家答案的子集,并且与之完全一致。 (B)提交的答案是专家答案的超集,并且与之完全一致。 (C)提交的答案包含与专家答案完全相同的细节。 (D)提交的答案与专家答案存在分歧。 (E)答案存在差异,但从事实的角度来看这些差异并不重要。 选项:ABCDE """ messages = [ {'role': 'system', 'content': system_message}, {'role': 'user', 'content': user_message} ] response = get_completion_from_messages(messages) return response
在实际使用中,遇到复杂的用户问题,模型表现不如预期,就需要对 Prompt 进行迭代。
比如问题是 我之前取消了订阅,但是为什么还有收费提示?
很明显这是一个争议费用
的子类别,但实际匹配的是
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。