构建基于LLM的系统和产品的模式
“有一大类问题很容易想象和构建演示,但很难制造产品。例如,自动驾驶:在一个街区周围演示一辆汽车自动驾驶很容易,但把它变成一个产品需要十年的时间。
这篇文章是关于将大型语言模型(LLM)集成到系统和产品中的实用模式。我们将以学术研究、行业资源和从业者的专业知识为基础,并将其提炼成关键思想和实践。
有七种关键模式。它们还按照提高性能与降低成本/风险以及更接近数据与更接近用户的范围进行组织。
- 评估:衡量绩效
- RAG:添加最近的外部知识
- 微调:在特定任务中做得更好
- 缓存:减少延迟和成本
- 护栏:确保输出质量
- 防御性用户体验:优雅地预测和管理错误
- 收集用户反馈:构建我们的数据飞轮
LLM 模式:从数据到用户,从防御到进攻(见模式之间的联系)
评估:衡量绩效
评估是一组用于评估模型在任务上的表现的度量。它们包括基准数据和指标。来自 HackerNews 的评论:
EVALS 对团队的重要性是冲出热垃圾的人和那些在空间中认真构建产品的人们之间的主要区别。
为什么是 evals?
Evals 使我们能够衡量我们的系统或产品的表现如何,并检测任何回归。(系统或产品可以由多个组件组成,例如 LLM、提示模板、检索到的上下文和温度等参数。一组具有代表性的评估使我们朝着大规模测量系统变化迈出了一步。如果没有 evals,我们将盲目飞行,或者必须通过每次更改目视检查 LLM 输出。
更多关于 EVALS 的信息
语言建模领域有许多基准。一些值得注意的有:
- MMLU:一组 57 项任务,涵盖小学数学、美国历史、计算机科学、法律等。为了表现良好,模特必须具备广泛的世界知识和解决问题的能力。
- EleutherAI Eval:统一的框架,通过 200 个任务的零/少镜头设置测试模型。包含大量评估,包括 BigBench,MMLU 等。
- HELM:HELM 不是特定的任务和指标,而是通过跨领域评估 LLM 来提供对 LLM 的全面评估。指标包括准确性、校准、稳健性、公平性、偏差、毒性等。任务包括问答、信息检索、摘要、文本分类等。
- AlpacaEval:自动评估框架,用于衡量强 LLM(例如 GPT-4)更喜欢一个模型的输出而不是参考模型的频率。指标包括赢率、偏差、延迟、价格、差异等。经验证与 20k 人工注释高度一致。
我们可以将指标分为两类:上下文相关或上下文无关。
- 上下文相关:这些考虑了上下文。它们通常是为特定任务提出的;将它们重新用于其他任务将需要一些调整。
- 上下文无关:在评估生成的输出时,这些与上下文无关;他们仅将输出与提供的黄金引用进行比较。由于它们与任务无关,因此更容易应用于各种任务。
为了更好地了解这些指标(及其潜在的不足),我们将探讨一些常用的指标,如 BLEU、ROUGE、BERTScore 和 MoverScore。
BLEU(双语评估替补)是一个基于精度的指标:它计算生成的输出中也显示在参考文献中的 n 元语法数,然后将其除以输出中的单词总数。它主要用于机器翻译,由于其成本效益,它仍然是一个流行的指标。
ROUGE(用于要点评估的以召回为导向的替补):与 BLEU 相反,ROUGE 以召回为导向。它计算引用中也出现在输出中的单词数。它通常用于评估自动摘要任务。
其他变体包括:
- ROUGE-L:测量输出和参考之间最长的公共子序列 (LCS)。它考虑了句子级结构的相似性和零,并在同一序列中同时出现的最长序列 n-gram。
- ROUGE-S:这测量输出和参考之间的跳过双元组。跳过双字母是一对保持其句子顺序的单词,无论它们之间可能夹着哪些单词。
BERTScore 是一个基于嵌入的指标,它使用余弦相似性将生成的输出中的每个标记或 n 元语法与参考句子进行比较。BERTScore 有三个组件:
- 召回率:引用中的每个标记与其在生成的输出中最接近的匹配项之间的平均余弦相似性。
- 精度:生成的输出中的每个标记与其在引用中的最接近匹配项之间的平均余弦相似度。
- F1:召回率和精度的调和平均值
BERTScore 很有用,因为它可以解释同义词和释义。像 BLEU 和 ROUGE 这样更简单的指标无法做到这一点,因为它们依赖于完全匹配。BERTScore 已被证明与图像字幕和机器翻译等任务具有更好的相关性。
MoverScore 还使用上下文化嵌入来计算生成的输出和引用中标记之间的距离。但与基于令牌一对一匹配(或“硬对齐”)的 BERTScore 不同,MoverScore 允许多对一匹配(或“软对齐”)。
伯特斯科(左)与 MoverScore(右;来源)
MoverScore 支持将一个序列中语义相关的单词映射到另一个序列中的对应项。它通过解决约束优化问题来实现这一点,该问题找到将一个文本转换为另一个文本的最小工作量。这个想法是测量单词必须移动才能将一个序列转换为另一个序列的距离。
但是,使用这些常规基准和指标存在一些陷阱。
首先,这些指标与人类判断之间的相关性很差。BLEU,ROUGE 和其他人与人类评估流利程度的方式呈负相关。它们还显示出与人类充足性评分的中等至较低的相关性。特别是,BLEU 和 ROUGE 与需要创造力和多样性的任务相关性较低。
其次,这些指标通常对更广泛的任务的适应性很差。将针对一项任务提出的指标应用于另一项任务并不总是谨慎的。例如,BLEU 和 ROUGE 等完全匹配指标不适合抽象摘要或对话等任务。由于它们基于输出和引用之间的 n-gram 重叠,因此对于可能有多种响应的对话任务没有意义。输出与参考的 n 元语法重叠可能为零,但仍然是一个很好的响应。
第三,这些指标的可重复性较差。即使对于相同的指标,不同研究中也报告了很高的方差,这可能是由于人类判断收集或指标参数设置的差异。另一项针对 2,000 项研究中的 ROUGE 分数的研究发现,分数很难重现,难以比较,而且经常不正确,因为 evals 通常是使用未经测试、不正确的 ROUGE 实现进行的。
即使使用最近的基准测试(如 MMLU),根据评估实现,同一模型也可能获得明显不同的分数。Huggingface 将原始 MMLU 实现与 HELM 和 EleutherAI 实现进行了比较,发现同一示例在不同的提供程序中可能具有不同的提示。
此外,所有三个基准的评估方法都不同:
- 原始 MMLU:仅比较答案(A、B、C、D)的预测概率
- HELM:使用模型中的下一个令牌概率,并选择概率最高的令牌,即使它不是选项之一。
- EleutherAI:计算每个答案的完整答案序列(即一个字母后跟答案文本)的概率。然后,选择概率最高的答案。
因此,即使对于相同的 eval,绝对分数和模型排名也会根据评估实现而大幅波动。这意味着模型指标并不是真正可比的——即使对于相同的 eval——除非 eval 的实现与提示和标记化等微小细节相同。同样,QLoRA 的作者发现 MMLU 过于敏感,并得出结论:“不要使用/报告或信任 MMLU 分数”。
除了上面提到的传统评估之外,一个新兴的趋势是使用强大的 LLM 作为无参考指标来评估其他 LLM 的世代。这意味着我们可能不需要人类的判断或黄金参考来评估。
G-Eval 是一个框架,它应用 LLM 与筛选链(CoT)和表单填写范式来评估 LLM 输出。首先,他们向 LLM 提供任务介绍和评估标准,并要求其生成评估步骤的 CoT。然后,为了评估新闻摘要的连贯性,他们将提示、CoT、新闻文章和摘要连接起来,并要求 LLM 输出 1 到 5 之间的分数。最后,他们使用 LLM 输出令牌的概率来规范分数,并将加权求和作为最终结果。
G-Eval 概述(来源)
他们发现 GPT-4 作为评估者与人类判断具有很高的斯皮尔曼相关性 (0.514),优于以前的所有方法。它在连贯性、一致性、流畅性和相关性等方面也优于传统指标。在主题聊天中,它在自然性、连贯性、参与性和接地气等多个标准上比 ROUGE-L、BLEU-4 和 BERTScore 等传统指标做得更好。
骆马的文件采取了类似的方法。他们首先定义八个类别(写作、角色扮演、提取、推理、数学、编码、STEM 和人文/社会科学),然后为每个类别开发 10 个问题。接下来,他们从五个聊天机器人中生成答案:LLaMA,Alpaca,ChatGPT,Bard 和 Vicuna。最后,他们要求 GPT-4 根据有用性、相关性、准确性和细节对答案的质量进行评分。
总体而言,他们发现 GPT-4 不仅提供了一致的分数,还可以对这些分数给出详细的解释。在单答案评分范式下,GPT-4 与人类的一致性 (85%) 高于人类之间的一致性 (81%)。这表明 GPT-4 的判断与人类评估者密切相关。
QLoRA 还使用 LLM 来评估另一个 LLM 的输出。他们要求 GPT-4 在骆马基准测试中根据 gpt-3.5-turbo 对各种型号的性能进行评级。鉴于 gpt-3.5-turbo 和另一个型号的回应,GPT-4 被提示在 10 分中得分并解释其评级。他们还通过模型之间的直接比较来衡量性能,将任务简化为包括领带在内的三类评级方案。
为了验证自动评估,他们收集了对骆马基准的人类判断。使用 Mechanical Turk,他们招募了两个注释器与 gpt-3.5-turbo 进行比较,并招募了三个注释器进行成对比较。他们发现模型的人类和 GPT-4 排名基本一致,模型级别的 Spearman 排名相关性为 0.55。这提供了一个额外的数据点,表明基于 LLM 的自动评估可能是人类评估的具有成本效益和合理的替代方案。
如何应用评估?
构建可靠的评估应该是任何基于 LLM 的系统或产品(以及传统的机器学习系统)的起点。
不幸的是,BLEU 和 ROUGE 等经典指标对于更复杂的任务(如抽象摘要或对话)没有意义。此外,我们已经看到像 MMLU 这样的基准(以及像 ROUGE 这样的指标)对它们的实施和衡量方式很敏感。坦率地说,除非您的 LLM 系统正在为学校考试而学习,否则使用 MMLU 作为评估是没有意义的。
因此,我们可以从收集一组特定于任务的评估(即提示、上下文、预期输出作为参考)开始,而不是使用现成的基准。然后,这些评估将指导快速工程、模型选择、微调等。当我们更新系统时,我们可以运行这些评估来快速衡量改进或回归。可以将其视为评估驱动开发(EDD)。
除了评估数据集,我们还需要有用的指标。它们可帮助我们将性能变化提取为一个数字,该数字在评估运行中具有可比性。如果我们能简化问题,我们就可以选择更容易计算和解释的指标。
最简单的任务可能是分类:如果我们使用 LLM 进行类似分类的任务(例如,毒性检测,文档分类)或没有对话的抽取性 QA,我们可以依靠标准分类指标,如召回率,精度,PRAUC 等。如果我们的任务没有正确答案,但我们有参考(例如,机器翻译,抽取摘要),我们可以依靠基于匹配(BLEU,ROUGE)或语义相似性(BERTScore,MoverScore)的参考指标。
但是,这些指标可能不适用于更开放的任务,例如抽象摘要、对话等。但是收集人类的判断可能既缓慢又昂贵。因此,我们可以选择通过强大的 LLM 依靠自动评估。
相对于通常嘈杂的人类判断(由于注释者之间的不同偏见),LLM 判断往往不那么嘈杂(因为偏见更系统),但更有偏见。尽管如此,由于我们知道这些偏见,我们可以相应地减轻它们:
- 位置偏差:LLM 倾向于支持第一个位置的响应。为了缓解这种情况,我们可以在交换顺序时两次评估同一对响应。如果两个订单中都首选相同的响应,我们会将其标记为获胜;否则,这是平局。
- 冗长偏差:LLM 倾向于更长,更冗长的回答而不是更简洁的回答,即使后者更清晰,质量更高。一个可能的解决方案是确保比较响应的长度相似。
- 自我增强偏见:LLM 对自己的答案有轻微的偏见。GPT-4 以高出 10% 的胜率青睐自己,而克劳德-v1 以高出 25% 的胜率青睐自己。为了解决这个问题,不要使用相同的 LLM 进行评估任务。
另一个提示:与其要求 LLM 进行直接评估(通过给出分数),不如尝试给它一个参考并要求进行比较。这有助于减少噪音。
最后,有时最好的评估是人类评估,又名氛围检查。(不要与名称不佳的代码评估基准 HumanEval 混淆。正如 MosaicML 的 Latent Space 播客(第 34 分钟)所述:
基于氛围的评估不容小觑。...我们的一个评估就是有一堆提示,并在模型训练时观察答案,看看它们是否发生变化。老实说,我真的不相信这些评估指标中的任何一个都能捕捉到我们关心的东西。我们的提示之一是“建议一个 3 岁和一个 7 岁的孩子玩的游戏”,这对于在培训过程中看到答案如何变化更有价值。— 乔纳森·弗兰克尔
检索增强型生成:添加知识
检索增强生成 (RAG) 从基础模型外部获取相关数据,并使用此数据增强输入,从而提供更丰富的上下文以改善输出。
为什么选择RAG?
RAG 通过将模型建立在检索到的上下文上来帮助减少幻觉,从而提高真实性。此外,使检索索引保持最新比持续预训练 LLM 更便宜。这种成本效益使得 LLM 更容易通过 RAG 访问最新数据。最后,如果我们需要更新或删除数据,例如有偏见或有毒的文档,更新检索索引更直接(与微调或提示 LLM 不生成有毒输出相比)。
简而言之,RAG 应用了信息检索领域的成熟和更简单的想法来支持 LLM 的生成。在红杉最近的一项调查中,88%的受访者认为检索将是他们堆栈的关键组成部分。
更多关于 RAG
在深入研究 RAG 之前,对文本嵌入有一个基本的了解会有所帮助。(如果您熟悉该主题,请随时跳过此部分。
文本嵌入是文本数据的压缩抽象表示形式,其中任意长度的文本可以表示为固定大小的数字向量。它通常是从维基百科等文本语料库中学习的。将它们视为文本的通用编码,其中相似的项目彼此靠近,而不同的项目相距更远。
良好的嵌入是在下游任务(例如检索类似项)上表现良好的嵌入。Huggingface 的海量文本嵌入基准(MTEB)对各种模型进行分类,聚类,检索,摘要等不同任务的评分。
快速说明:虽然我们在这里主要讨论文本嵌入,但嵌入可以采用多种形式。例如,CLIP 是多模态的,将图像和文本嵌入在同一空间中,使我们能够找到与输入文本最相似的图像。我们还可以根据用户行为(例如点击、购买)或图形关系嵌入产品。
RAG 起源于开放领域的问答。早期的一篇元论文表明,通过 TF-IDF 检索相关文档并将其作为语言模型 (BERT) 的上下文提供可以提高开放域 QA 任务的性能。他们将每个任务转换为完形填空语句,并查询语言模型以查找缺少的令牌。
之后,密集通道检索(DPR)表明,使用密集嵌入(而不是稀疏向量空间,如 TF-IDF)进行文档检索可以优于 Lucene BM25 等强基线(65.2%对前 5 名精度为 42.9%)。他们还表明,更高的检索精度转化为更高的端到端 QA 准确性,突出了上游检索的重要性。
为了学习 DPR 嵌入,他们在现有的问答对上微调了两个独立的基于 BERT 的编码器。段落编码器 ( ) 将文本段落嵌入到向量中,而查询编码器 ( Ep Eq ) 将问题嵌入到向量中。然后,查询嵌入用于检索 k 与问题最相似的段落。
他们训练了编码器,使点积相似性成为一个很好的排序函数,并将损失函数优化为正通道的负对数似然。DPR 嵌入针对问题和相关段落向量之间的最大内积进行了优化。目标是学习一个向量空间,使得成对的问题及其相关段落靠近在一起。
为了进行推理,他们嵌入所有段落(通过 Ep )并在 FAISS 中离线索引它们。然后,在查询时给定一个问题,他们计算问题嵌入(通过),通过 Eq 近似最近邻检索顶部 k 段落,并将其提供给输出问题答案的语言模型(BERT)。
检索增强生成(RAG)由此得名,它强调了预训练 LLM 的缺点。这些包括无法扩展或修改记忆,无法提供对生成的输出的见解以及幻觉。
为了解决这些缺点,他们引入了 RAG(又名半参数模型)。密集矢量检索充当非参数分量,而预训练的 LLM 充当参数分量。他们重复使用 DPR 编码器来初始化检索器并构建文档索引。对于 LLM,他们使用了 BART 模型,这是一个 400M 参数 seq2seq 模型。
检索增强生成概述(来源)
在推理过程中,它们将输入与检索到的文档连接起来。然后,LLM 根据原始输入、检索到的文档和以前的 i−1 令牌生成 tokeni 。对于生成,他们提出了两种方法,这些方法在如何使用检索到的段落来生成输出方面有所不同。
在第一种方法 RAG-Sequence 中,模型使用相同的文档来生成完整的序列。因此,对于 k 检索到的文档,生成器为每个文档生成一个输出。然后,每个输出序列的概率被边缘化(将每个输出序列的概率相加 k ,并按检索每个文档的概率对其进行权衡)。最后,选择概率最高的输出序列。
另一方面,RAG-Token 可以根据不同的文档生成每个令牌。给定 k 检索到的文档,生成器在边缘化之前为每个文档的下一个输出令牌生成一个分布(聚合所有单个令牌分布)。然后对下一个令牌重复该过程。这意味着,对于每个令牌生成,它可以根据原始输入和以前生成的令牌检索一组不同的 k 相关文档。因此,文档可以具有不同的检索概率,并且对下一个生成的令牌的贡献也不同。
Fusion-in-Decoder (FiD) 还使用具有生成模型的检索来实现开放域 QA。它支持两种检索方法,BM25(具有默认参数的 Lucene)和 DPR。FiD 仅因其如何在解码器中对检索到的文档执行融合而命名。
解码器融合概述(来源)
对于每个检索到的段落,标题和段落与问题连接。这些对在编码器中独立处理。它们还会在其相应部分之前添加特殊标记,例如 question:
、 title:
和 context:
。解码器负责这些检索到的段落的串联。
因为它在编码器中独立处理段落,所以它可以扩展到大量段落,因为它一次只需要对一个上下文进行自我注意。因此,计算随着检索到的段落数呈线性增长(而不是二次增长),使其比 RAG-Token 等替代方案更具可扩展性。然后,在解码过程中,解码器联合处理编码的段落,使其能够更好地聚合多个检索到的段落的上下文。
检索增强型变压器(RETRO)采用类似的模式,它结合了冻结的 BERT 检索器,可微分编码器和分块交叉注意力以生成输出。不同的是,RETRO 在整个预训练阶段进行检索,而不仅仅是在推理期间。此外,他们根据输入块获取相关文档。这允许在生成期间进行更细粒度的重复检索,而不是每个查询只检索一次。
对于每个输入块 ( Cu ), k 检索到的 RET(Cu) 块被馈送到编码器中。输出是编码的邻居, Euj 其中 Euj=Encoder(RET(Cu)j,Hu)∈Rr×d0 .在这里,每个块编码都以 Hu (中间激活)和通过交叉注意层 Cu 激活块为条件。简而言之,检索到的块的编码取决于输入块的参与激活。 Euj 然后用于调节下一个块的生成。
复古概述(来源)
在检索过程中,RETRO 将输入序列拆分为 64 个令牌的块。然后,它会查找与上一个区块类似的文本,为当前区块提供上下文。检索索引由两个连续的标记 N 块和 F .前者是用于计算密钥的邻居块(64 个令牌),而后者是原始文档中的延续块(64 个令牌)。
检索基于 BERT 嵌入上的近 k 似-最近邻通过 L2 距离(欧几里得)。(与通常的余弦或点积相似性有趣地不同。基于 SCaNN 构建的检索索引可以在 10ms 内查询 2T 令牌数据库。
他们还演示了如何对现有基线模型进行改造。通过冻结预训练的权重并仅训练分块交叉注意力和相邻编码器参数(< 7B 模型权重的 10%),他们可以通过检索增强变压器,同时只需要 6M 训练序列(预训练序列的 3%)。RETRO 拟合模型能够超越基线模型的性能,并实现接近从头开始训练的 RETRO 的性能。
通过改造预训练模型的性能(来源)
互联网增强的 LMs 建议使用一个不起眼的“现成”搜索引擎来增强 LLM。首先,他们通过谷歌搜索检索一组相关文档。由于这些检索到的文档往往很长(平均长度为 2,056 个单词),因此他们将它们分成每段六句话的段落。最后,他们通过 TF-IDF 嵌入问题和段落,并应用余弦相似性对每个查询最相关的段落进行排名。
互联网增强型 LLM 概述(来源)
检索到的段落用于通过少数镜头提示来调节 LLM。他们采用封闭式 QA(仅提供问答对)中的常规 k -shot 提示( k=15 ),并用证据段落对其进行扩展,使得每个上下文都是证据,问答三元组。
对于生成器,他们使用了 Gopher,这是一个在 300B 令牌上训练的 280B 参数模型。对于每个问题,他们根据检索到的 50 个段落中的每一个生成了四个候选答案。最后,他们通过直接推理、RAG、噪声信道推理和专家产品 (PoE) 等多种方法估计答案概率来选择最佳答案。PoE 始终表现最佳。
RAG 也已应用于非 QA 任务,例如代码生成。虽然 CodeT5+ 可以用作独立的生成器,但当与 RAG 结合使用时,它在代码生成方面的性能明显优于类似模型。
为了评估 RAG 对代码生成的影响,他们在三个设置中评估模型:
- 基于检索:获取前 1 个代码示例作为预测
- 仅生成:仅基于解码器输出代码
- 检索增强:在通过解码器生成代码之前,将 top-1 代码示例附加到编码器输入。
用于 CodeT5+的 RAG 概述(来源)
作为一个定性的例子,他们表明检索到的代码提供了关键的上下文(例如,用于 urllib3
HTTP 请求),并指导生成过程朝着更正确的预测方向发展。相比之下,仅生成方法返回不正确的输出,仅捕获“下载”和“压缩”的概念。
如果我们没有查询通道对的相关性判断怎么办?没有它们,我们将无法训练将查询和文档嵌入同一嵌入空间中的双编码器,其中相关性由内积表示。假设文档嵌入 (HyDE) 提出了一个解决方案。
海德概况(来源)
给定一个查询,HyDE 首先提示 LLM,如 InstructGPT,以生成一个假设的文档。然后,无监督编码器(如 Contriver)将文档编码为嵌入向量。最后,计算假设文档和语料库之间的内积,并检索最相似的真实文档。
期望编码器的密集瓶颈充当有损压缩器,并且通过嵌入排除无关的、非事实的细节。这会将相关性建模问题从表示学习任务重新构建为生成任务。
如何申请 RAG
根据黑曜石-Copilot 的经验,我发现混合检索(传统的搜索索引+基于嵌入的搜索)比单独使用任何一种都更好。在那里,我用语义搜索( ) e5-small-v2
补充了经典检索(BM25 via OpenSearch)。
为什么不只基于嵌入的搜索?虽然它在许多情况下都很棒,但在某些情况下它不足,例如:
- 搜索人物或物体的名称(例如,尤金、卡普提尔 2.0)
- 搜索首字母缩略词或短语(例如,RAG、RLHF)
- 搜索 ID(例如,
gpt-3.5-turbo
titan-xlarge-v1.01
、)
但是关键字搜索也有其局限性。它仅对简单的词频进行建模,不捕获语义或相关信息。因此,它不能很好地处理同义词或超同义词(即表示概括的单词)。这就是将其与语义搜索相结合是互补的地方。
此外,使用传统的搜索索引,我们可以使用元数据来优化结果。例如,我们可以使用日期过滤器来确定较新文档的优先级或将搜索范围缩小到特定时间段。如果搜索与电子商务有关,则平均评级或类别的过滤器会有所帮助。最后,拥有元数据对于下游排名非常方便,例如优先考虑被引用较多的文档,或通过销售量来提升产品。
关于嵌入,看似流行的方法是使用 text-embedding-ada-002
.它的好处包括通过 API 易于使用,并且不必维护我们自己的嵌入基础设施或自托管嵌入模型。尽管如此,个人经验和其他人的轶事表明,有更好的检索选择。
OG 嵌入方法包括 Word2vec 和 fastText。FastText 是一个开源的轻量级库,使用户能够利用预先训练的嵌入或训练新的嵌入模型。它带有 157 种语言的预训练嵌入,即使没有 GPU,速度也非常快。这是我进行早期概念验证的首选。
另一个很好的基线是句子转换器。它使计算句子、段落甚至图像的嵌入变得简单。它基于 BERT 和 RoBERTa 等主力变压器,提供 100 多种语言版本。
最近,讲师模型已经显示出 SOTA 性能。在训练期间,这些模型将任务描述附加到文本前面。然后,在嵌入新文本时,我们只需要描述任务即可获得特定于任务的嵌入。(恕我直言,与嵌入模型的指令调整没有什么不同。
一个例子是 E5 系列模型。对于开放式 QA 和信息检索,我们只需在索引中将文档前面加上 passage:
,并在查询前面加上 query:
。如果任务是对称的(例如,语义相似性,释义检索),或者如果我们想使用嵌入作为特征(例如,分类,聚类),我们只使用 query:
前缀。
讲师模型更进一步,允许用户自定义前面的提示:“表示:”例如,“表示 domain
task_type
task_objective
要检索的维基百科文档:”。(域和任务目标是可选的)。这将提示调优的概念带入了文本嵌入领域。
最后,截至 8 月 1 日,MTEB 排行榜上排名靠前的嵌入模型是阿里巴巴达摩院的 GTE 系列模型。性能最佳的型号的大小是次优型号 e5-large-v2
的一半(0.67GB 对 1.34GB)。排在第二位的是 gte-base
模型大小仅为 0.22GB,嵌入尺寸为 768。(H/T 尼兰特。
为了大规模检索低延迟的文档,我们使用近似最近邻 (ANN)。它优化检索速度并返回近似(而不是精确) k 最相似的邻居,以一点精度损失换取大速度。
ANN 嵌入索引是让我们有效地进行 ANN 搜索的数据结构。在高级别上,它们在嵌入空间上构建分区,以便我们可以快速放大查询向量所在的特定空间。一些流行的技术包括:
- 局部敏感哈希(LSH):核心思想是创建哈希函数,以便类似的项目可能最终出现在同一个哈希桶中。只需检查相关存储桶,我们就可以有效地执行 ANN 查询。
- Facebook AI 相似性搜索 (FAISS):它使用量化和索引的组合来实现高效检索,支持 CPU 和 GPU,并且由于有效利用内存,可以处理数十亿个向量。
- 分层可导航小世界(HNSW):受“六度分离”的启发,构建了体现小世界现象的分层图结构。在这里,大多数节点都可以通过最少的跃点数从任何其他节点访问。这种结构允许 HNSW 从更广泛、更粗的近似值发起查询,并逐渐缩小较低级别的搜索范围。
- 可扩展最近邻(ScaNN):它有一个两步过程。首先,粗量化减少了搜索空间。然后,在简化的集合内完成细粒度搜索。我见过的最佳召回/延迟权衡。
在评估 ANN 指数时,需要考虑的一些因素包括:
- 回想一下:它与确切的最近邻居相比如何?
- 延迟/吞吐量:每秒可以处理多少个查询?
- 内存占用:提供索引需要多少 RAM?
- 易于添加新项目:是否可以在不重新索引所有文档的情况下添加新项目(LSH),还是需要重建索引(ScaNN)?
没有一个框架在各个方面都优于所有其他框架。因此,在基准测试之前,首先定义功能和非功能需求。就个人而言,我发现 ScaNN 在召回延迟权衡方面非常出色(请参阅此处的基准图)。
微调:在特定任务中做得更好
微调是采用预先训练的模型(已经使用大量数据进行训练)并针对特定任务进一步完善它的过程。目的是利用模型在预训练期间已经获得的知识,并将其应用于特定任务,通常涉及较小的、特定于任务的数据集。
术语“微调”使用松散,可以指几个概念,例如:
- 持续预训练:对于特定于领域的数据,在基本模型上应用相同的预训练方案(下一个令牌预测、掩码语言建模)。
- 指令微调:预训练(基础)模型根据指令输出对的示例进行微调,以遵循指令、回答问题、放弃等。
- 单任务微调:预先训练的模型针对狭窄而特定的任务(例如毒性检测或汇总)进行磨练,类似于 BERT 和 T5。
- 带有人类反馈的强化学习(RLHF):它将指令微调与强化学习相结合。它需要收集人类偏好(例如,成对比较),然后用于训练奖励模型。然后,奖励模型用于通过 RL 技术(如近端策略优化(PPO))进一步微调指示的 LLM。
在这里,我们将主要关注单任务和指令微调。
为什么要微调?
出于多种原因,微调开放式 LLM 正在成为使用第三方基于云的 LLM 的越来越可行的替代方案。
性能和控制:微调可以提高现成基础模型的性能,甚至可能超过第三方 LLM。它还提供了对 LLM 行为的更大控制,从而产生了更强大的系统或产品。总体而言,微调使我们能够构建与简单地使用第三方或开放式 LLM 区分开来的产品。
模块化:单任务微调使我们能够使用一组较小的模型,每个模型都专注于自己的任务。通过此设置,可以将系统模块化为单独的模型,用于内容审核、提取、摘要等任务。此外,鉴于每个模型只需要关注一组狭窄的任务,我们可以绕过对齐税,即在一个任务上微调模型会降低其他任务的性能。
减少依赖性:通过微调和托管我们自己的模型,我们可以减少对专有数据(例如,PII、内部文档和代码)暴露给外部 API 的法律担忧。它还绕过了第三方 LLM 带来的限制,例如速率限制,高成本或过度限制的安全过滤器。通过微调和托管我们自己的 LLM,我们可以确保数据不会离开我们的网络,并可以根据需要扩展吞吐量。
有关微调的更多信息
为什么我们需要微调基本模型?冒着过度简化的风险,基础模型主要经过优化,以根据它们所训练的语料库预测下一个单词。因此,他们天生不善于遵循指示或回答问题。当被问到问题时,他们往往会回答更多的问题。因此,我们执行指令微调,以便他们学会做出适当的反应。
然而,微调并非没有挑战。首先,我们需要大量的演示数据。例如,在 InstructGPT 论文中,他们使用 13k 指令输出样本进行监督微调,使用 33k 输出比较进行奖励建模,以及 31k 没有人类标签的提示作为 RLHF 的输入。
此外,微调伴随着对齐税 - 该过程可能导致某些关键任务的性能降低。(毕竟没有免费的午餐。同一篇 InstructGPT 论文发现,RLHF 导致公共 NLP 任务(如 SQuAD,HellaSwag 和 WMT 2015 法语到英语)的性能回归(相对于 GPT-3 基础模型)。(解决方法是使用几个较小的专用模型,这些模型擅长狭窄的任务。
微调类似于迁移学习的概念。正如维基百科中所定义的那样:“迁移学习是机器学习中的一种技术,其中从任务中学到的知识被重新用于提高相关任务的性能。几年前,迁移学习使我可以轻松地应用在 ImageNet 上训练的 ResNet 模型来对时尚产品进行分类并构建图像搜索。
ULMFit 是早期将迁移学习应用于文本的论文之一。他们建立了自我监督预训练(在未标记的数据上)然后进行微调(在标记数据上)的协议。他们使用了 AWS-LSTM,这是一种 LSTM 变体,在各个门都有辍学。
ULMFit 概述(来源)
在预训练(下一个单词预测)期间,模型在 wikitext-103 上进行训练,其中包含 28.6 个维基百科文章和 103M 个单词。然后,在目标任务微调期间,使用来自特定任务域的数据对 LM 进行微调。最后,在分类器微调期间,模型增加了两个额外的线性块,并对目标分类任务进行了微调,其中包括情感分析、问题分类和主题分类。
从那时起,预训练和微调范式推动了语言建模的长足进步。来自变压器的双向编码器表示(BERT;仅限编码器)在英语维基百科和 BooksCorpus 上进行了关于掩蔽语言建模和下一句预测的预训练。然后对特定于任务的输入和标签进行微调,以进行单句分类,句子对分类,单句标记和问答。
BERT 概述(来源)
生成预训练转换器(GPT;仅限解码器)首先通过下一个令牌预测在 BooksCorpus 上进行预训练。接下来是对文本分类、文本蕴涵、相似性和问答等任务进行单任务微调,有趣的是,他们发现将语言建模作为辅助目标有助于模型在训练期间更快地泛化和收敛。
GPT 概述(来源)
文本到文本传输转换器 (T5; 编码器-解码器) 在巨大的干净爬行语料库 (C4) 上进行预训练,这是 2019 年 4 月通用爬网的清理版本。它采用了与 BERT 相同的去噪目标,即屏蔽语言建模。然后对文本分类、抽象摘要、问答和机器翻译等任务进行微调。
T5 概述(来源)
但与 ULMFIt,BERT 和 GPT 使用不同的分类器头进行下游任务不同,T5 仅将下游任务表示为文本到文本。例如,翻译任务的输入文本可能以 Translation English to German:
Summarize:
开头,而摘要任务的输入文本可能以 或 TL;DR:
开头。前缀本质上变成了一个超参数(提示工程的第一个实例?这种设计选择使他们能够在各种下游任务中使用单个微调模型。
InstructGPT 将这种单任务微调的想法扩展到指令微调。基本模型是 GPT-3,在互联网数据上预先训练,包括通用爬行、WebText、书籍和维基百科。然后,它对所需行为(指令和输出)的演示进行监督微调。接下来,它在比较数据集上训练了一个奖励模型。最后,它通过 PPO 根据奖励模型优化了指示模型,最后一个阶段更侧重于一致性而不是特定的任务绩效。
InstructGPT 中的微调步骤概述(来源)
接下来,让我们从微调模型转向微调技术。
软提示调优将可训练张量预置到模型的输入嵌入中,实质上是创建软提示。与离散文本提示不同,软提示可以通过反向传播学习,这意味着它们可以进行微调以包含来自任意数量的标记示例的信号。
接下来是前缀调整。它不是向模型输入添加软提示,而是将可训练参数预置到所有转换器块的隐藏状态。在微调期间,LM 的原始参数保持冻结状态,同时更新前缀参数。
前缀调整概述(来源)
该论文表明,尽管只需要更新 0.1%的参数,但这实现了与完全微调相当的性能。此外,在数据有限且涉及对新主题的外推的设置中,它的表现优于完全微调。一种假设是,训练较少的参数有助于减少较小目标数据集上的过度拟合。
还有适配器技术。该方法在每个变压器块上添加两次全连接网络层,分别在注意层之后和前馈网络层之后。在 GLUE 上,只需为每个任务添加 3.6% 的参数,它就能实现完全微调性能的 0.4% 以内。
适配器概述(来源)
低秩适配 (LoRA) 是一种技术,其中适配器被设计为两个低秩矩阵的乘积.它的灵感来自 Aghajanyan 等人,该研究表明,在适应特定任务时,预先训练的语言模型具有较低的内在维度,尽管随机投影到较小的子空间中,仍然可以有效地学习。因此, LoRA 假设适应期间的权重更新也具有较低的内在等级.
LoRA 概述 (来源)
与前缀调整类似, 他们发现 LoRA 的性能优于几个基线,包括完全微调.同样, 假设是 LoRA, 由于其降低的等级, 提供隐式正则化.相比之下,更新所有权重的完全微调可能容易过度拟合。
QLoRA 建立在 LoRA 的理念之上。但是,在微调过程中,它没有使用完整的 16 位模型,而是应用 4 位量化模型。它引入了多项创新,例如 4 位 NormalFloat(用于量化模型)、双重量化(用于额外节省内存)和分页优化器(通过在 GPU 内存不足时将数据传输到 CPU RAM 来防止 OOM 错误)。
QLoRA 概述(来源)
因此,与 16 位完全微调的基线相比,QLoRA 将微调 65B 模型的平均内存需求从 > 780GB 内存降低到更易于管理的 48B,而不会降低运行时或预测性能。
(有趣的事实:在与 QLoRA 的作者蒂姆·德特默斯(Tim Dettmers)的聚会上,他打趣说,双重量化“有点愚蠢的想法,但效果很好。嘿,如果它有效,它就会起作用。
如何应用微调?
第一步是收集演示数据/标签。这些可以用于简单的任务,如文档分类、实体提取或摘要,也可以更复杂,如问答或对话。收集此数据的一些方法包括:
- 通过专家或众包人工注释器:虽然这既昂贵又缓慢,但它通常会导致更高质量的数据,并具有良好的指导方针。
- 通过用户反馈:这可以像要求用户选择描述产品的属性一样简单,用竖起或竖起大拇指对 LLM 响应进行评级(例如,ChatGPT),或者记录用户选择下载的图像(例如,Midjourney)。
- 使用宽松许可证查询较大的开放模型:通过快速工程设计,我们可能能够从更大的模型(Falcon 40B Instruct)中获取合理的演示数据,这些数据可用于微调较小的模型。
- 重用开源数据:如果你的任务可以框定为自然语言推理(NLI)任务,我们可以微调模型以使用 MNLI 数据执行 NLI。然后,我们可以继续微调内部数据的模型,将输入分类为蕴涵、中性或矛盾。
注意:某些 LLM 术语阻止用户使用其输出来开发其他模型。
- OpenAI 使用条款(第 2c 节、iii):您不得使用服务的输出来开发与 OpenAI 竞争的模型。
- LLaMA 2 社区许可协议(第 1b-v 节):您不得使用骆驼材料或骆驼材料的任何输出或结果来改进任何其他大型语言模型(不包括骆驼 2 或其衍生作品)。
下一步是定义评估指标。我们在上一节中已经讨论过这一点。
然后,选择预先训练的模型。有几个开放的 LLM 具有宽松的许可证可供选择。不包括 Llama 2(因为它没有完全商业用途),猎鹰-40B 被认为是性能最好的型号。尽管如此,鉴于它的重量,我发现微调和在生产中服务很笨拙。
相反,我倾向于使用较小的型号,如猎鹰-7B。如果我们能够更狭隘地简化和构建任务,那么 BERT(340M 参数),RoBerta(355M 参数)和 BART(406M 参数)是分类和自然语言推理任务的可靠选择。除此之外,Flan-T5(770M 和 3B 变体)是翻译、抽象摘要、标题生成等的可靠基线。
我们可能还需要更新模型架构,例如当预训练模型的架构与任务不一致时。例如,我们可能需要更新 BERT 或 T5 上的分类头以匹配我们的任务。提示: 如果任务是简单的二元分类任务,NLI 模型可以开箱即用。蕴涵映射到积极,矛盾映射到消极,而神经标签可以表示不确定性。
然后,选择一种微调方法。LoRA 和 QLoRA 是很好的起点。但是,如果您的微调更密集,例如继续对新领域知识进行预培训,您可能会发现需要完全微调。
最后,基本的超参数调优。一般来说,大多数论文都关注学习率、批量大小和时期数(参见 LoRA、QLoRA)。如果我们使用 LoRA,我们可能需要调整排名参数(尽管 QLoRA 论文发现不同的排名和 alpha 导致类似的结果)。其他超参数包括输入序列长度、损失类型(对比损失与令牌匹配)和数据比率(如预训练或演示数据的混合,或正负示例的比率等)。
缓存:减少延迟和成本
缓存是一种存储以前检索或计算的数据的技术。这样,可以更快地处理未来对相同数据的请求。在服务 LLM 世代的空间中,流行的方法是缓存以输入请求的嵌入为键的 LLM 响应。然后,对于每个新请求,如果收到语义相似的请求,我们可以提供缓存的响应。
对于一些从业者来说,这听起来像是“一场等待发生的灾难”。我倾向于同意。因此,我认为采用这种模式的关键是弄清楚如何安全地缓存,而不是仅仅依赖于语义相似性。
为什么要缓存?
缓存可以显著减少以前提供的响应的延迟。此外,通过消除一次又一次计算相同输入的响应的需要,我们可以减少 LLM 请求的数量,从而节省成本。此外,某些用例不支持秒级延迟。因此,预计算和缓存可能是为这些用例提供服务的唯一方法。
有关缓存的更多信息
缓存是一个高速存储层,用于存储访问频率更高的数据子集。这使我们能够通过缓存而不是数据的主存储(例如,搜索索引,关系数据库)更快地为这些请求提供服务。总体而言,缓存可以有效地重用以前获取或计算的数据。(有关缓存和最佳实践的更多信息。
LLM 缓存的一个例子是 GPTCache。
GPTCache 概述(来源)
收到新请求时:
- 嵌入生成器:这通过各种模型嵌入请求,例如 OpenAI
text-embedding-ada-002
,FastText,句子转换器等。 - 相似性评估器:通过向量存储计算请求的相似性,然后提供距离指标。载体存储可以是本地的(FAISS,Hnswlib)或基于云的。它还可以通过模型计算相似性。
- 缓存存储:如果请求类似,则会提取并提供缓存的响应。
- LLM:如果请求不够相似,它会被传递给 LLM,然后 LLM 生成结果。最后,提供并缓存响应以供将来使用。
Redis 也分享了一个类似的例子,提到一些团队甚至会预先计算他们预期收到的所有查询。然后,他们设置一个相似性阈值,在该阈值上,查询的相似性足以保证缓存的响应。
如何应用缓存?
我们应该从充分了解用户请求模式开始。这使我们能够深思熟虑地设计缓存,以便可靠地应用它。
首先,让我们考虑一个非 LLM 的例子。想象一下,我们正在缓存电子商务网站的产品价格。在结账时,显示(可能已过时的)缓存价格是否安全?可能不是,因为客户在结账时看到的价格应该与他们被收取的最终金额相同。缓存在这里不合适,因为我们需要确保客户的一致性。
现在,把它带回 LLM 的回应。想象一下,我们收到一个请求,要求“碟中谍 2”的摘要,该摘要在语义上与“碟中谍 3”非常相似。如果我们根据语义相似性查找缓存,我们可能会提供错误的响应。
我们还需要考虑缓存是否对使用模式有效。量化这一点的一种方法是通过缓存命中率(直接从缓存提供的请求的百分比)。如果使用模式是均匀随机的,则缓存需要频繁更新。因此,使缓存保持最新的努力可能会抵消缓存必须提供的任何好处。另一方面,如果用法遵循幂律,其中一小部分唯一请求占流量的大部分(例如,搜索查询、产品视图),那么缓存可能是一种有效的策略。
除了语义相似性之外,我们还可以根据以下内容探索缓存:
- 商品 ID:这适用于我们预先计算产品评论摘要或生成整个电影三部曲的摘要。
- 物品 ID 对:例如,当我们在两部电影之间生成比较时。虽然这似乎是,但在实践中,少数组合推动了大部分流量 O(N2) ,例如系列或类型中的流行电影之间的比较。
- 受限输入:例如电影类型、导演或主演等变量。例如,如果用户正在寻找特定导演的电影,我们可以执行结构化查询并通过 LLM 运行它,以更雄辩地构建响应。另一个示例是基于下拉选项生成代码 - 如果代码已经过验证可以正常工作,我们可以缓存它以便可靠地重用。
此外,缓存不仅必须即时进行。正如 Redis 所分享的那样,我们可以在提供 LLM 生成之前离线或异步预计算它们。通过从缓存提供服务,我们将延迟从生成(通常为秒)转移到缓存查找(毫秒)。与实时服务相比,批量预计算还有助于降低成本。
虽然这里列出的方法可能不如自然语言输入的语义缓存那么灵活,但我认为它在效率和可靠性之间提供了良好的平衡。
护栏:确保输出质量
在 LLM 的上下文中,护栏验证 LLM 的输出,确保输出不仅听起来不错,而且在语法上也是正确的,事实的,并且没有有害内容。它还包括防范对抗性输入。
为什么选择护栏?
首先,它们有助于确保模型输出足够可靠和一致,可以在生产中使用。例如,我们可能要求输出位于特定的 JSON 架构中,以便它是机器可读的,或者我们需要生成的代码才能可执行。护栏可以帮助进行此类语法验证。
其次,它们提供了额外的安全层,并保持对 LLM 输出的质量控制。例如,要验证生成的内容是否适合投放,我们可能需要检查输出是否无害,验证其事实准确性,或确保与提供的上下文保持一致。
有关护栏的更多信息
一种方法是通过提示控制模型的响应。例如,Anthropic 分享了旨在指导模型生成有用,无害和诚实(HHH)的响应的提示。他们发现,与使用 RLHF 进行微调相比,使用 HHH 提示符进行 Python 微调会带来更好的性能。
HHH 提示的示例(来源)
更常见的方法是验证输出。护栏包就是一个例子。它允许用户通过 Pydantic 风格的验证在 LLM 输出上添加结构、类型和质量要求。如果检查失败,它可以触发纠正措施,例如过滤有问题的输出或重新生成另一个响应。
大多数验证逻辑位于 中 validators.py
。看看它们是如何实现的很有趣。从广义上讲,它的验证器分为以下几类:
- 单个输出值验证:这包括确保输出 (i) 是预定义选项之一,(ii) 长度在一定范围内,(iii) 如果是数字,则在预期范围内,以及 (iv) 是一个完整的句子。
- 语法检查:这包括确保生成的 URL 有效且可访问,并且 Python 和 SQL 代码没有错误。
- 语义检查:这将验证输出是否与参考文档对齐,或者提取摘要是否与源文档紧密匹配。这些检查可以通过余弦相似性或模糊匹配技术来完成。
- 安全检查:这可确保生成的输出没有不适当的语言或翻译文本的质量很高。
Nvidia 的 NeMo-Guardrails 遵循类似的原则,但旨在指导基于 LLM 的对话系统。它不是专注于句法护栏,而是强调语义护栏。这包括确保助手避开带有政治色彩的话题,提供事实正确的信息,并可以检测越狱企图。
因此,NeMo 的方法有些不同:NeMo 没有使用更具确定性的检查,例如验证列表中是否存在值或检查代码是否存在语法错误,而是严重依赖使用另一个 LLM 来验证输出(受 SelfCheckGPT 的启发)。
在他们用于事实检查和预防幻觉的例子中,他们要求 LLM 本身检查最新的输出是否与给定的上下文一致。为了进行事实核查,根据从知识库检索到的文档,如果响应为真,则查询 LLM。为了防止幻觉,由于没有可用的知识库,他们让 LLM 生成多个替代完成作为上下文。潜在的假设是,如果 LLM 产生多个彼此不一致的完成,那么原始完成很可能是一种幻觉。
审核示例遵循类似的方法:通过 LLM 筛选响应中的有害和不道德内容。鉴于道德和有害内容的细微差别,启发式和传统的机器学习技术不足。因此,需要法学硕士来更深入地了解对话的意图和结构。
除了使用护栏来验证 LLM 的输出外,我们还可以直接引导输出以遵守特定的语法。这方面的一个例子是 Microsoft 的指南。与通过提示强加 JSON 架构的护栏不同,指南通过注入构成结构的令牌来强制实施架构。
我们可以将指南视为 LLM 交互和输出的特定于领域的语言。它的灵感来自 Handlebars,这是一种用于 Web 应用程序的流行模板语言,使用户能够执行变量插值和逻辑控制。
但是,指南通过线性执行将自己与常规模板语言区分开来。这意味着它保持生成的令牌的顺序。因此,通过插入作为结构一部分的令牌(而不是依赖 LLM 来正确生成它们),指南可以指示特定的输出格式。在他们的示例中,他们展示了如何生成始终有效的 JSON,使用多个键生成复杂的输出格式,确保 LLM 扮演正确的角色,并让代理相互交互。
他们还引入了一个称为令牌修复的概念,这是一个有用的功能,有助于避免由于标记化而发生的细微错误。简单来说,它会在提示结束之前按一个令牌回退生成,然后将第一个生成的令牌限制为具有与提示中的最后一个令牌匹配的前缀。这样就无需在制作提示时担心令牌边界。
如何应用护栏?
尽管工业中 LLM 的护栏概念仍处于萌芽状态,但我们可以考虑一些立即有用和实用的策略。
结构指导:尽可能应用指导。它提供对输出的直接控制,并提供更精确的方法来确保输出符合特定的结构或格式。
语法护栏:这些包括检查分类输出是否在一组可接受的选项内,或者数字输出是否在预期范围内。此外,如果我们生成 SQL,这些可以验证它没有语法错误,并确保查询中的所有列都与架构匹配。生成代码(例如,Python,JavaScript)也是如此。
内容安全护栏:这些护栏验证输出没有有害或不适当的内容。它可以像检查脏、顽皮、淫秽和其他坏词列表或使用亵渎检测模型一样简单。(在输出上运行审核分类器很常见。更复杂和细致的输出可以依靠 LLM 评估器。
语义/事实性护栏:这些护栏确认输出在语义上与输入相关。假设我们正在根据电影的概要生成一部电影的两句话摘要。我们可以验证生成的摘要是否在语义上与输出相似,或者让(另一个)LLM 确定摘要是否准确表示所提供的概要。
输入护栏:这些限制模型将响应的输入类型,有助于降低模型响应不适当或对抗性提示的风险,这些提示会导致生成有害内容。例如,如果您要求 Midjourney 生成 NSFW 内容,则会收到错误。这可以像与字符串列表进行比较或使用审核分类器一样简单。
Midjourney 输入护栏示例
防御性用户体验:优雅地预测和处理错误
防御性用户体验是一种设计策略,它承认在用户与机器学习或基于 LLM 的产品交互期间可能会发生不好的事情,例如不准确或幻觉。因此,目的是提前预测和管理这些错误,主要是通过指导用户行为、避免滥用和优雅地处理错误。
为什么是防御性用户体验?
机器学习和 LLM 并不完美——它们会产生不准确的输出。此外,随着时间的推移,它们对相同的输入做出不同的响应,例如搜索引擎由于个性化而显示不同的结果,或者 LLM 在更具创意,更高温度的设置上产生不同的输出。这可能违反了一致性原则,该原则主张一致的 UI 和可预测的行为。
防御性用户体验可以通过提供以下功能来帮助缓解上述情况:
- 提高可访问性:通过帮助用户了解 ML / LLM 功能的工作原理及其局限性,防御性 UX 使其更易于访问和用户友好。
- 增加信任:当用户看到该功能可以优雅地处理困难的方案并且不会产生有害的输出时,他们可能会更信任它。
- 更好的用户体验:通过设计系统和用户体验来处理模棱两可的情况和错误,防御性用户体验为更流畅、更愉快的用户体验铺平了道路。
有关防御性用户体验的更多信息
要了解有关防御性用户体验的更多信息,我们可以查看 Microsoft,Google 和 Apple 的 Human-AI 指南。
Microsoft 的《人与人工智能交互指南》基于对 168 个潜在指南的调查。这些是从内部和外部行业资源、学术文献和公共文章中收集的。在结合相似的指南、过滤过于模糊或过于具体或不特定于 AI 的指南以及一轮启发式评估后,他们将其缩小到 18 个指南。
整个用户旅程中人与 AI 交互的指南(来源)
这些准则遵循一定的风格:每个准则都是 3 - 10 个单词的简洁动作规则,以动词开头。每条规则都附有一行字,用于解决潜在的歧义。它们根据用户交互期间可能的应用进行组织:
- 最初:明确系统可以做什么(G1),明确系统可以做什么(G2)
- 在互动过程中:基于上下文的时间服务(G3),减轻社会偏见(G6)
- 错误时:支持高效解雇(G8),支持高效纠正(G9)
- 随着时间的推移:从用户行为中学习 (G13),提供全局控件 (G17)
谷歌的《人+人工智能指南》植根于谷歌产品团队和学术研究的数据和见解。与围绕用户组织的 Microsoft 指南相反,Google 将其指南组织成开发人员需要牢记的概念。
围绕产品开发过程中出现的常见问题,有 23 种模式分组,包括:
- 如何开始使用以人为本的 AI:确定 AI 是否增加了价值,尽早投资于良好的数据实践(例如,评估)
- 如何将用户引入新的 AI 功能:确保安全探索、锚定熟悉度、分阶段自动化
- 如何帮助用户建立对我的产品的信任:设定正确的期望,保持透明,在风险较低时实现更多自动化。
Apple 的机器学习人机界面指南不同于学术文献和用户研究的自下而上方法。相反,它的主要来源是从业者的知识和经验。因此,它不包括很多参考或数据点,而是专注于苹果长期以来的设计原则。这导致了一个独特的视角,将其与其他两个准则区分开来。
该文档重点介绍了如何将 Apple 的设计原则应用于注入 ML 的产品,强调 UI 的各个方面,而不是模型功能。它首先要求开发人员考虑 ML 在其应用程序中的角色,并从用户体验向后工作。这包括诸如 ML 是否为以下问题:
- 关键或补充:例如,面容 ID 在没有 ML 的情况下无法使用,但键盘仍然可以在没有快速输入的情况下工作。
- 主动或被动:Siri 建议是主动的,而自动更正是被动的。
- 动态或静态:建议是动态的,而“照片”中的对象检测只会随着每个 iOS 版本而改进。
然后,它深入研究几种模式,分为系统的输入和输出。输入侧重于显式反馈、隐式反馈、校准和更正。本部分指导 AI 产品如何请求和处理用户数据和交互的设计。输出侧重于错误、多种选择、信心、归因和限制。目的是确保模型的输出以可理解和有用的方式呈现。
这三条准则之间的差异是有见地的。谷歌更加强调训练数据和模型开发的考虑因素,这可能是由于其工程驱动的文化。Microsoft 更关注心智模型,这可能是 HCI 学术研究的产物。最后,苹果的方法围绕着提供无缝的用户体验,这一重点可能受到其文化价值观和原则的影响。
如何应用防御性用户体验?
以下是基于上述准则的一些模式。(免责声明:我不是设计师。
设定正确的期望。这一原则在所有三个准则中都是一致的:
- Microsoft:明确系统能做什么(帮助用户了解人工智能系统犯错的频率)
- 谷歌:设定正确的期望(对你的用户保持透明,了解你的人工智能产品能做什么,不能做什么)
- Apple:帮助人们建立切合实际的期望(描述营销材料或功能上下文中的局限性)
这可以像在 AI 生成的结果上方添加简短的免责声明一样简单,例如 Bard 的结果,或者在其登录页面上突出显示我们应用程序的局限性,例如 ChatGPT 如何做到这一点。
谷歌Bard结果的免责声明示例(注意: nrows
不是有效的参数。
通过对我们产品的功能和局限性保持透明,我们帮助用户校准他们对产品和输出的期望。虽然这可能会导致用户在短期内不那么信任它,但从长远来看,它有助于培养信任——用户不太可能高估我们的产品并随后面临失望。
实现高效解雇。这在 Microsoft 的准则 8 中被明确提及:支持有效关闭(使消除或忽略不需要的 AI 系统服务变得容易)。
例如,如果用户正在浏览我们的网站,并且弹出一个聊天机器人询问他们是否需要帮助,那么用户应该很容易关闭聊天机器人。这可确保聊天机器人不会妨碍,尤其是在屏幕较小的设备上。同样,GitHub Copilot 允许用户通过简单地继续输入来方便地忽略其代码建议。虽然这可能会在短期内减少人工智能功能的使用,但从长远来看,它可以防止它成为一种麻烦并可能降低客户满意度。
提供归因。这在所有三个准则中都列出:
- Microsoft:明确系统为什么这样做(使用户能够访问 AI 系统为什么会这样做的解释)
- Google:添加来自人为来源的背景信息(帮助用户根据第三方来源的意见来评估您的推荐内容)
- 苹果:考虑使用归因来帮助人们区分结果
引文正成为越来越普遍的设计元素。以 BingChat 为例。当我们进行查询时,它会在其回复中包含引用,通常来自信誉良好的来源。这不仅显示了信息的来源,而且还允许用户评估来源的质量。同样,假设我们正在使用 LLM 来解释为什么用户可能喜欢产品。除了 LLM 生成的解释外,我们还可以包括实际评论中的引用或提及产品评级。
来自专家和社区的背景也增强了用户的信任。例如,如果用户正在寻求远足路径的建议,提及相关社区强烈推荐的建议路径可能会有很长的路要走。它不仅为推荐增加了价值,而且还帮助用户通过人际关系校准信任。
通过社会证明进行归因的示例(来源)
最后,苹果的指导方针包括流行的归属,如“因为你读过非小说”,“你读过的作者的新书”。这些描述符不仅可以个性化体验,还可以提供上下文,增强用户的理解和信任。
锚定熟悉感。在向用户介绍新的 AI 产品或功能时,它有助于指导他们使用熟悉的 UX 模式和功能。这使用户更容易专注于主要任务,并开始赢得客户对我们新产品的信任。抵制通过异国情调的 UI 元素展示新的“神奇”功能的诱惑。
同样,由于 ChatGPT 的日益普及,基于聊天的功能变得越来越普遍。例如,与您的文档聊天,聊天以查询您的数据,聊天以购买杂货。但是,我质疑聊天是否适合大多数用户体验 - 相对于熟悉的点击文本和图像的 UX,它需要太多的努力。
此外,增加用户工作量会导致更难满足的更高期望。Netflix 分享说,用户对搜索等明确操作产生的推荐有更高的期望。一般来说,用户投入的努力(例如,聊天、搜索)越多,他们的期望就越高。与此形成对比的是,在推荐石板上滚动或点击产品等更省力的交互。
因此,虽然聊天提供了更大的灵活性,但它也需要更多的用户努力。此外,使用聊天框不太直观,因为它缺乏用户如何调整输出的指示符。总的来说,我认为坚持使用熟悉且受约束的 UI 会使用户更容易浏览我们的产品;聊天仅应被视为辅助或第三选项。
收集用户反馈:构建我们的数据飞轮
收集用户反馈使我们能够了解他们的偏好。特定于 LLM 产品,用户反馈有助于构建评估,微调和护栏。如果我们考虑一下,数据 - 例如用于预训练的语料库,专家制作的演示,人类对奖励建模的偏好 - 是 LLM 产品为数不多的护城河之一。因此,我们希望在设计用户体验时有意识地考虑收集用户反馈。
反馈可以是显式的,也可以是隐式的。明确反馈是用户为响应我们产品的请求而提供的信息;隐式反馈是我们从用户交互中学习的信息,不需要用户故意提供反馈。
为什么要收集用户反馈
用户反馈有助于我们的模型改进。通过了解用户喜欢、不喜欢或抱怨的内容,我们可以改进模型以更好地满足他们的需求。它还使我们能够适应个人喜好。推荐系统就是一个很好的例子。当用户与商品互动时,我们会了解他们喜欢和不喜欢什么,并随着时间的推移更好地迎合他们的口味。
此外,反馈循环有助于我们评估系统的整体性能。虽然评估可以帮助我们衡量模型/系统性能,但用户反馈提供了用户满意度和产品有效性的具体衡量标准。
如何收集用户反馈
使用户能够轻松提供反馈。这在所有三个准则中都得到了回应:
- Microsoft:鼓励精细反馈(使用户能够在与 AI 系统的定期交互期间提供反馈,表明他们的偏好)
- Google:让用户提供反馈(让用户有机会进行实时教学、反馈和纠错)
- Apple:提供你的应用可用于改进其呈现给用户的内容和体验的可操作信息
ChatGPT 就是这样一个例子。用户可以对响应表示竖起/竖起大拇指,或者在响应确实糟糕或无用时选择重新生成响应。这是对人类偏好的有用反馈,然后可用于微调 LLM。
中途是另一个很好的例子。生成图像后,用户可以生成一组新图像(负反馈),通过请求变体来调整图像(正反馈),或者放大并下载图像(强正反馈)。这使得 Midjourney 能够收集有关生成的输出的丰富比较数据。
作为 UX 的一部分收集用户反馈的示例
还要考虑隐式反馈。隐式反馈是用户与我们的产品交互时出现的信息。与我们从显式反馈中获得的特定响应不同,隐式反馈可以提供有关用户行为和偏好的广泛数据。
类似副驾驶的助手就是一个很好的例子。用户通过完全接受建议(强烈的正面反馈)、接受并进行微小的调整(正面反馈)或忽略它(中性/负面反馈)来表明建议是否有帮助。或者,他们可能会更新导致生成代码的注释,这表明初始代码生成不符合他们的需求。
聊天机器人,如 ChatGPT 和 BingChat,是另一个例子。随着时间的推移,日常使用量有何变化?如果产品具有粘性,则表明用户喜欢它。另外,平均对话多长时间?这可能很难解释:较长的对话是否因为对话引人入胜且富有成效而更好?还是更糟,因为用户花了更长的时间才能获得他们需要的东西?
机器学习中常见的其他模式
除了上述七种模式外,机器学习中还有其他模式也与 LLM 系统和产品相关。它们包括:
- 数据飞轮:持续的数据收集改进了模型并带来了更好的用户体验。这反过来又促进了更多的使用,从而提供了更多的数据来进一步评估和微调模型,从而创造了一个良性循环。
- 级联:与其将单个复杂的任务分配给 LLM,我们可以简化和分解它,这样它只需要处理它擅长的任务,例如推理或雄辩地沟通。RAG 就是一个例子。与其依靠 LLM 根据其内部知识检索和排名项目,我们可以用外部知识来增强 LLM,并专注于应用 LLM 的推理能力。
- 监控:这有助于证明人工智能系统的附加值或缺乏价值。有人分享了一个轶事,在停止使用之前,在生产中运行基于 LLM 的客户支持解决方案两周——A / B 测试表明,当使用 LLM 作为其支持团队的替代品时,损失要多 12 倍!
(详细了解机器学习代码和系统的设计模式。
另外,这是其他人说的:
关注点分离/任务分解 - 为不同的子任务提供不同的提示并将它们链接在一起有助于提高注意力和可靠性(损害延迟)。我们在指定刚性输出结构和可变响应内容时遇到了问题,因此我们拆分了任务 — Erick Enriquez
还需要的其他一些:基于角色的访问控制:谁可以访问什么;安全性:如果我使用带有 LLM 的数据库,我如何确保我有合适的保安人员 - 克里希纳
一致的输出格式:将输出设置为标准化格式,例如 JSON;工具增强:将任务卸载到更专业、经过验证、更可靠的模型 — Paul Tune
安全性:缓解缓存中毒、输入验证、缓解提示注入、训练数据来源、使用不易受攻击的代码输出、缓解旨在影响工具使用的请求的恶意输入(AI 代理)、缓解拒绝服务(压力测试 LLM),仅举几例 :) — 安德森·达拉里奥
另一个与 UX / UI 相关的:激励用户对生成的答案(隐式或显式)提供反馈。隐式可能是像副驾驶的幽灵文本样式一样,如果被 TAB 接受,这意味着积极的反馈等。— 杨文
很棒的清单。我会添加一致性检查,例如自一致性采样、任务的链接和分解,以及多个模型输出的模拟。几乎每天都应用这些。丹·怀特
护栏与构建分析工具非常相关,其中 llm 是从自然语言到编程语言的翻译 - m_voitko
结论
这是我迄今为止写过的最长的帖子。如果你还和我在一起,谢谢!我希望您发现阅读这些模式对您有所帮助,并且下面的 2x2 是有意义的。
LLM 模式跨越数据轴到用户,防御到进攻。
在构建基于 LLM 的系统和产品的旅程中,我们仍然处于早期阶段。是否有任何其他关键模式或资源?你觉得什么有用或没用?我很想听听你的经历。请伸出援手!