万字经验 | 使用大模型(LLMs)构建产品一年后,我们有些经验想告诉你

大语言模型(LLMs)的时代充满了让人兴奋的机遇。在过去的一年里,LLMs的性能已经“足够好”以至于可以用于现实世界的应用,预计会在2025年前带动大约2000亿美元的人工智能投资。LLMs也广泛使得所有人,而不只是机器学习工程师和科学家,都能够将人工智能带入他们的产品中。虽然构建AI产品的门槛已经降低,但要创造出一个体验优秀的产品仍然是一个艰巨的挑战。

在过去一年中,Eugene Yan、Bryan Bischof 、Charles Frye 等一直在LLMs之上构建他们的应用程序。他们写这篇文章的目标是,以自己的经验为基础,创建一个关于围绕LLMs构建成功产品的实用指南,并列出实际成功的例子,分享一些建议和教训,供任何构建LLMs产品的人参考。

原文:

https://www.oreilly.com/radar/what-we-learned-from-a-year-of-building-with-llms-part-i/

01.提示工程(Prompting)

我们建议在开发新应用时从提示工程(Prompting)开始。人们很容易低估或者低估它的重要性。正确的提示技巧,若使用得当的情况下,可以让我们取得很大的进展,所以它往往被低估;但是,即使是基于提示的应用程序也需要围绕提示进行大量工程开发才能很好地工作,因此其重要性也容易被高估。

1. 重视从基本的提示技巧中获得最大收益

有几种提示技巧在不同模型和任务中都能有助于提升性能:

n-shot 提示与上下文学习

利用n-shot 提示进行上下文中学习的思路是提供给LLM一些示例,这些示例展示了任务要求,并使输出符合我们的期望。一些建议:

  • 如果 n 过低,模型可能会过度依赖这些特定示例,影响其泛化能力。一般来说,n 应该不小于 5,甚至可以达到几十个。
  • 示例应能代表预期输入的分布。如果您正在构建一个电影摘要生成器,请包含不同类型的样本,比例大致与实际情况相符。
  • 不一定要提供完整的输入输出对。在很多情况下,仅提供期望输出的示例就足够了。
  • 如果您使用支持工具的大语言模型,您的 n-shot 示例也应包括您希望智能体使用的工具。

思维链(CoT)提示

在思维链(CoT)提示中,我们鼓励LLM在返回最终答案之前解释其思考过程。可以将其视为为LLM提供一个草稿本,这样它就不必全部在记忆中完成。最初的方法是简单地在指示中添加“lets think step by step(让我们一步一步思考)”这句话。然而,我们发现使链式思维更具体,通过添加一两句额外的说明,可以显著降低幻觉率。

当要求大语言模型总结会议记录时,我们可以明确步骤,例如:

首先,在草稿本上列出关键决策、后续事项及相关责任人。

然后,检查草稿本中的细节与会议记录事实上是否一致。

最后,将关键点综合成一份简洁的摘要。

最近,人们开始怀疑这种技术是否像人们认为的那样强大。此外,关于在使用思维链时推理过程中究竟发生了什么,存在相当大的争议。无论如何,尝试这种技术是值得的。

提供相关资源

提供相关资源是一种扩展模型知识库、减少幻觉并增加用户信任的强有力机制。通常通过检索增强生成(RAG)实现,为模型提供它可以直接在回应中使用的文本片段是一种基本技巧。提供相关资源时,仅仅包括这些资源是不够的;别忘了告诉模型优先使用这些资源,直接提及它们,有时还要提及当资源不足时的情况。这些有助于让智能体的响应基于一组资源。

结构化你的输入和输出

结构化输入和输出可以帮助模型更好地理解输入,并返回能够可靠集成到下游系统中的输出。为您的输入添加序列化格式可以为模型提供更多关于上下文中tokens之间关系的线索,为特定tokens提供额外的元数据(如类型),或将请求与模型训练数据中的类似示例联系起来。

例如,互联网上许多关于编写SQL的问题都是通过指定SQL模式开始的。因此,你可能期望有效的Text-to-SQL提示应包括结构化的模式定义。

结构化输出具有类似的目的,但它也简化了与系统下游组件的集成。Instructor和Outlines适合用于结构化输出。(如果你正在导入LLM API SDK,使用Instructor;如果您正在导入 Huggingface 进行自托管模型,请使用Outlines)。结构化输入清晰地表达任务,并且类似于训练数据的格式,增加了获得更好输出的可能性。

使用结构化输入时,请注意每个大语言模型都有自己的偏好。Claude偏好xml,而GPT偏好Markdown和JSON。使用XML,你甚至可以通过提供一个 response标签来预填Claude的响应,就像这样。

万字经验 | 使用大模型(LLMs)构建产品一年后,我们有些经验想告诉你

2. 编写短而精的提示词,专注做好一件事

在软件开发中,有一个常见的反模式叫“万能对象”,即一个类或函数承担了所有的功能。提示词也有类似的问题。

提示通常开始很简单:几句指令,几个例子,就可以开始使用了。但是当我们试图提高性能和处理更多边缘情况时,复杂性就会悄然而至。更多指令、多步推理、几十个例子。在我们意识到之前,最初简单的提示现在已经变成了一个2000个token的复合体。更糟的是,它在更常见和直接的输入上性能还下降了!GoDaddy 把这个作为他们在使用大语言模型时的首要经验。

就像我们努力保持系统和代码的简约一样,我们的提示也应该如此。我们不应该拥有一个用于会议记录的全能型提示,我们可以将其分解为步骤:

  1. 将关键决策、行动项目和责任人提取成结构化格式
  2. 检查提取的详情与原始记录的一致性
  3. 从结构化的细节生成简洁的摘要

因此,我们将单一的提示分解成了多个简单、专注且易于理解的提示。通过分解,我们可以分别迭代和评估每个提示词的效果。

3. 精心设计你的上下文信息

重新思考你的需求,然后反思实际需要向agent发送多少上下文。像米开朗琪罗那样,不是不断堆砌石料——而是剔除多余的材料,直到雕塑显现出来。检索增强生成(RAG)是一个流行的方法,用来汇集所有可能相关的信息块,但是你如何提取必要的内容呢?

我们发现,将最终发送给模型的提示词——包括所有的上下文构建、元提示词和 RAG 结果——放在一张空白页上阅读,确实有助于重新思考上下文。通过这种方法,我们发现了冗余、自相矛盾的语言和糟糕的格式。

另一个关键的优化是你的上下文结构。如果你的文档袋(bag-of-docs)表示法对人类不友好,不要假设它对agent有用。仔细考虑你如何构建上下文,强调其各部分之间的关系,并尽可能简化提取过程。

02.检索增强生成(RAG)

除了提示工程之外,还有一种有效的方法是在提示中提供知识。这种方法将使LLMs锚定在提供的上下文上,用于上下文学习,这被称为检索增强生成(RAG)。实践中发现,RAG在提供知识和改善输出方面有效,而且与微调相比需要的努力和成本更少。RAG的好坏取决于检索文档的相关性、信息密度和详细程度。

1. RAG输出质量取决于检索文档的质量,而文档的质量又可以从几个因素考虑

第一个也是最明显的衡量指标是文档的相关性。相关性通常通过排名指标进行量化,例如平均倒数排名(MRR)或归一化折扣累计增益(NDCG)。MRR评估系统在排名列表中将首个相关结果置于何处的能力,而NDCG则考虑所有结果的相关性及其位置。这些指标衡量系统将相关文档排在更高位置、不相关文档排在更低位置的。例如,如果我们检索用户评论来生成电影评论摘要,我们希望将特定电影的评论排名更高,同时排除与其他电影有关的评论。

与传统推荐系统类似,检索到的项目排名将对 LLM 在下游任务中的表现产生重大影响。为了衡量这种影响,可以运行一个基于 RAG 的任务,但将检索到的项目顺序打乱,然后观察 RAG 输出的表现如何。

其次,我们还想考虑信息密度。如果两份文档同样相关,我们应该更偏好那些更简洁且不必要细节较少的文档。回到我们的电影示例,从广义上讲,我们可能会认为电影剧本和所有用户评论都相关。然而,高评价的评论和编辑评论可能在信息上更为密集。

最后,考虑文档提供的细节水平。想象我们正在构建一个 RAG 系统,从自然语言生成 SQL 查询。我们可以简单地提供表结构和列名作为上下文,但如果包括列描述和一些代表性值,额外的细节将帮助 LLM 更好地理解表的语义,从而生成更正确的 SQL。

2. 不要忘记关键词搜索:将其用于基准和混合搜索

鉴于基于嵌入(Embedding)的RAG如此普遍,很容易让人忘记或忽视信息检索领域几十年的研究和解决方案。

尽管嵌入式搜索无疑是一个强大的工具,但它们并非万能。首先,虽然它们擅长捕捉高层次的语义相似性,但它们可能在处理更具体的基于关键词的查询时遇到困难,就像用户搜索名称(例如,Ilya)、缩写(例如,RAG)或ID(例如,claude-3-sonnet)时。基于关键词的搜索,如BM25,专门为此设计。而且,经过多年的基于关键词的搜索,用户很可能已经将其视为理所当然,并且如果他们希望检索的文档没有被返回,可能会感到沮丧。

向量嵌入并不是搜索的万能解决方案。事实上,在使用语义相似搜索进行重新排序之前的步骤才是最关键和费力的。要真正实现比 BM25 或全文搜索更好的效果是非常困难的。

— Aravind Srinivas, CEO Perplexity.ai

几个月来我们一直向客户和合作伙伴反复强调:使用简单的嵌入进行相似检索会产生非常杂乱的结果,还不如从关键词搜索开始。

— Beyang Liu, CTO Sourcegraph

其次,使用关键词搜索检索到文档的原因更直观——我们可以查看与查询匹配的关键词。相比之下,基于嵌入的检索解释性较差。最后,得益于像Lucene和OpenSearch这样经过数十年优化和实战检验的系统,关键词搜索通常在计算上更高效。

在大多数情况下,混合使用效果最佳:对于明显的匹配使用关键词匹配,对于同义词、上位词、拼写错误以及多模态(例如,图片和文本)使用嵌入。Shortwave分享了他们如何构建他们的RAG流水线,包括查询重写、关键词 嵌入检索和排名。

在大多数情况下,混合搜索是最有效的:关键词匹配用于明显的匹配,而嵌入用于同义词、上位词和拼写错误,以及多模态(如图像和文本)。Shortwave 分享了他们如何构建 RAG 管道,包括查询重写、关键词 嵌入检索和排序。

3. 对于新知识首选RAG,而不是微调

RAG和微调都可以用来将新信息纳入大语言模型并提高特定任务上的性能。那么,我们应该首先尝试哪个?

最近的研究表明RAG可能更具优势。一项研究将RAG与无监督微调(又称持续预训练)进行了比较,评估了它们在MMLU的一个子集和当前事件上的表现。他们发现RAG在训练过程中遇到的知识以及完全新的知识方面,持续地优于微调。在另一篇论文中,他们将RAG与在农业数据集上的监督微调进行了比较。同样,RAG带来的性能提升大于微调,尤其是对GPT-4(参见该论文的表20)。

除了性能提升,RAG还带来了几个实际优势。首先,与持续预训练或微调相比,保持检索索引更新更容易——也更便宜!其次,如果我们的检索索引含有包含有害或有偏见内容的问题文档,我们可以轻松地删除或修改这些问题文档。

此外,RAG中的R提供了更细致的控制,以便我们检索文档。例如,如果我们为多个组织托管RAG系统,通过划分检索索引,我们可以确保每个组织只能从它们自己的索引中检索文档。这确保我们不会无意中将一个组织的信息暴露给另一个组织。

4. 长上下文窗口不会让RAG失去作用

Gemini 1.5提供了多达1000万个tokens的上下文窗口,一些人开始质疑RAG的未来。

我认为 Sora 对 Gemini 1.5 的宣传大大夸大了。一个 1000 万 tokens 的上下文窗口实际上使大多数现有的 RAG 框架变得不必要——你只需将你的数据放入上下文中,像往常一样与模型对话。想象一下,这对那些大部分工程努力都集中在 RAG 上的初创公司/智能体/LangChain 项目会产生怎样的影响 😅 简单一句话:这个 1000 万的上下文杀死了 RAG。干得好,Gemini。

— Yao Fu

虽然长上下文将会对用例如分析多份文件等应用中是一个变革,但关于RAG即将过时的传言被大大夸张了。

首先,即使有一个1000万tokens的上下文窗口,我们仍然需要一种方法来选择信息来喂给模型。其次,除了狭义的“大海捞针”评估之外,我们还没看到有力的数据证明模型能有效地推理如此大的上下文。因此,如果没有好的检索和排序,我们有可能用干扰信息使模型不堪重负,或者甚至可能用完全不相关的信息填满上下文窗口。

最后,是成本问题。Transformer的推理成本与上下文长度呈二次方(或在空间和时间上呈线性)增长。仅仅因为存在一个模型在回答每个问题之前能读取你组织的整个Google Drive内容,并不意味着这是个好主意。考虑到我们如何使用RAM的类比:即使存在运行数十TB RAM的计算实例,我们还是会从磁盘进行读写。

所以,不要急着把你的RAG扔掉。即使上下文窗口的大小增长,这种模式仍然会很有用。

03.调整和优化工作流程

提示工程只是开始。为了最大限度地利用它们,我们需要思考超越单个提示的范围,并拥抱工作流程。例如,我们如何将一个单一复杂任务分解为多个更简单的任务?微调或缓存在提高性能和减少延迟/成本时何时有帮助?在本节中,我们将分享经过验证的策略和现实世界的例子,以帮助您优化和构建可靠的大语言模型工作流程。

1. 逐步、多回合的流程可以提升效果

我们已经知道,将一大段提示词分解为若干个小段提示词可以取得更好的效果。一个例子是 AlphaCodium:他们从单个提示切换到多步骤工作流程,将GPT-4在CodeContests上的准确率(pass@5)从19%提高到44%。

这个工作流包括:

反思问题

  1. 在公共测试中进行推理
  2. 生成可能的解决方案
  3. 对可能的解决方案进行排序
  4. 生成模拟测试
  5. 在公共和模拟测试中迭代解决方案

具有明确目标的小任务非常适合作为agent或流程提示。虽然不是每个智能体提示都需要结构化输出,但结构化输出有助于与协调智能体与环境互动的系统进行接口对接。

下面是一些值得尝试的事情

制定尽可能详细的计划步骤。可以考虑从预定义的计划中进行选择 (参考 https://youtu.be/hGXhFa3gzBs?si=gNEGYzux6TuB1del)

将原始用户提示转化为智能体提示,但要注意,这个过程可能会有信息损失!

将智能体行为设计成线性链、DAG 和状态机的形式;不同的依赖关系和逻辑关系适用于不同的任务规模。能否通过不同的任务架构来优化性能?

计划验证;在你的计划中包含如何评估其他智能体响应的指导,以确保最终组合效果良好。

通过固定的上游状态进行提示工程——确保你的智能体提示能够应对可能发生的各种情况。

2. 优先考虑确定性工作流

虽然AI agent可以动态地响应用户请求和环境,但它们的非确定性特征使得部署它们成为一大挑战。agent采取的每一步都有失败的可能性,而且从错误中恢复的可能性很小。因此,随着步骤数量的增加,agent成功完成多步骤任务的可能性呈指数级下降。结果是,构建agent的团队发现很难部署可靠的agent。

一种有效的方法是拥有能产生确定性计划的agent系统,然后以结构化、可复制的方式执行这些计划。在第一步,给定一个高级目标或提示,agent生成一个计划。然后,计划被确定性地执行。这使每一步都更可预测和可靠。

好处包括:

  1. 生成的计划可以作为少样本示例,用于提示或微调智能体。
  2. 确定性执行使系统更加可靠,便于测试和调试,且可以精确定位失败步骤。
  3. 生成的计划可以表示为有向无环图 (DAG),比起静态提示更容易理解和适应新情况。

最成功的agent构建者可能是那些管理初级工程师经验丰富的人,因为生成计划的过程类似于我们如何指导和管理初级人员。我们给初级人员明确的目标和具体的计划,而不是模糊的开放式指导,我们也应该对我们的agent做同样的事情。

最终,可靠、有效的agent的关键可能在于采用更加结构化、确定性的方法,以及收集数据来精炼提示和微调模型。如果没有这个,虽然智能体在某些情况下表现出色,但整体表现可能会让用户失望,导致用户流失

3. 调节temperature参数获得更多样性的输出

假设你的需求是关注LLM输出的多样性。例如,你正在设计一个 LLM 流程,根据用户之前购买的产品列表推荐新产品。当你多次运行提示时,可能会发现结果推荐过于相似,因此你可能会考虑增加 LLM 请求中的温度参数。

简而言之,增加温度参数使LLM响应更加多样化。在采样时,下一个tokens的概率分布变得更加平坦,这意味着通常较不可能的tokens被更频繁地选择。尽管如此,当增加温度时,你可能会注意到一些与输出多样性相关的失败模式。例如,目录中一些非常适合的产品可能从未被 LLM 推荐,而某些产品因为在训练时被认为非常适合而频繁出现。如果温度过高,输出可能会包含不存在的产品或一些无意义的内容。

换句话说,增加温度并不保证LLM会从你期望的概率分布(例如,均匀随机)中抽样输出。尽管如此,我们还有其他方法来增加输出的多样性。最简单的方法是调整提示中的内容。例如,如果提示模板包括一个项目列表,比如历史购买,每次将这些项目插入提示时随机排序,可以使差异显著。

此外,保留最近输出的简短列表可以帮助防止冗余。在我们推荐产品的例子中,通过指示LLM避免建议来自这个最近列表的项目,或者拒绝和重新抽样与最近建议类似的输出,我们可以进一步多样化响应。另一种有效的策略是变化提示中使用的措辞。例如,加入短语如“选择一个用户会经常使用并喜欢的项目”或“选择一个用户可能会推荐给朋友的产品”可以转移焦点,从而影响推荐产品的多样性。

4. 缓存被低估了

缓存可以节省成本,并消除了生成延迟。此外,如果一个响应之前已经过安全审查,我们可以提供这些经过审核的响应,减少提供有害或不当内容的风险。

缓存的一种直接方法是为被处理的项目使用唯一ID,比如我们在总结新闻文章或产品评论时。当一个请求进来时,我们可以检查缓存中是否已经存在一个摘要。如果是,我们可以立即返回它;如果不是,我们生成它,进行安全审查,提供它,然后将它存储在缓存中以供未来的请求使用。

对于更开放式的查询,我们可以借鉴搜索领域的技术,搜索也利用缓存来处理开放式输入。如自动完成和拼写纠正等功能也有助于规范用户输入,从而提高缓存命中率。

5. 何时需要进行微调

我们可能有一些任务,即使是设计最巧妙的提示也难以胜任。例如,即使在进行了大量的提示工程之后,我们的系统可能仍然离返回可靠、高质量输出有一段距离。如果是这样,那么可能需要针对您的特定任务对模型进行微调。

成功的例子包括:

  1. Honeycomb 的自然语言查询助手:最初,“编程指南”与 n-shot 样例一起提供给提示以进行上下文理解。虽然这效果尚可,但微调模型后,在特定领域语言的语法和规则上输出更好。
  2. ReChat 的 Lucy:LLM 需要以一种非常特定的格式生成响应,该格式结合了结构化和非结构化数据,以便前端正确呈现。微调对于让它一致运行至关重要。

尽管微调可以有效,但它伴随着显著的成本增加。我们不得不标注微调数据、微调和评估模型,最终自行托管它们。因此,考虑较高的前期成本是否值得。如果提示让你走了90%的路,那么微调可能不值得投资。然而,如果我们确实决定进行微调,为了降低收集人工注释数据的成本,我们可以生成并在合成数据上进行微调,或者利用开源数据引导。

04.评估与监控

评估大语言模型 (LLMs) 是一个复杂的过程。LLM的输入和输出都是任意文本,我们给它们设置的任务也多种多样。尽管如此,严密而深思熟虑的评估是至关重要的——OpenAI的技术领导在评估方面投入了大量工作并非无效。

评估 LLM 应用的方式多种多样:有些人认为它像单元测试,有些人觉得它更类似于可观察性,还有人认为它就是数据科学的一部分。我们发现这些观点各有其价值。在接下来的部分中,我们将分享一些我们在构建评估和监控管道方面的重要经验教训。

1. 从真实输入/输出样本创建几个断言(Assertion)的单元测试

创建单元测试,包括来自生产的输入和输出样本,基于至少三个标准对输出设定期望。尽管三个标准可能看起来是任意的,但这是一个实际开始的数字;更少可能表明您的任务定义不够充分或太开放,就像一个通用聊天机器人。无论是编辑提示、通过RAG添加新上下文还是其他修改,这些单元测试或断言应该被任何对管道的改动所触发。

这篇文章有一个基于断言测试(断言是在编程中用来检验程序的某个条件是否为真的一种语句。如果断言的条件为真,程序可以继续执行;如果条件为假,则程序会抛出错误或异常,通常会中断执行。在单元测试中,断言用来确保代码的某个具体行为或输出符合预期。)的实际用例示例。

可以考虑从指定包含或排除在所有响应中的短语或观点的断言开始。还要考虑检查以确保单词、项目或句子的数量在一个范围内。对于其他类型的生成,断言可能看起来不同。执行评估是评估代码生成的强大方法,在其中您运行生成的代码并确定运行时状态对于用户请求来说是足够的。

例如,如果用户请求一个名为foo的新功能;那么在执行agent生成的代码之后,foo应该是可调用的!“执行 – 评估方法”的一个挑战是,agent的代码经常会使运行时状态与目标代码略有不同。将断言“放宽”到任何可行答案都会满足的最弱假设是有效的。

最后,按照客户预期的方式使用您的产品(即“自用”,dogfooding)可以提供关于实际数据故障模式的测试。这种方法不仅有助于识别潜在的弱点,而且还提供了一个有用的生产样本来源,这些样本可以转换成评估。

2. LLM-as-Judge有用,但不是灵丹妙药

有些人对于使用强大的LLM来评估其他LLM的输出(LLM-as-Judge)抱有怀疑。(我们中的一些人最初也是巨大的怀疑者。)然而,当执行得当时,LLM-as-Judge与人类判断有相当的相关性,并且至少可以帮助构建关于新提示或技术可能如何表现的先验。特别是,当进行成对比较(例如,对照组与处理组)时,LLM-as-Judge通常能判断出正确的方向,尽管胜/败的幅度可能会有噪声。

以下是一些建议,以充分利用LLM-as-Judge:

  1. 使用成对比较:不要让大语言模型在 Likert 量表上对单个输出进行评分,而是给它呈现两个选项并让它选择较好的一个。这往往能带来更稳定的结果
  2. 控制位置偏差:选项的呈现顺序会影响大语言模型的决策。为了减少这种偏差,每次成对比较时都交换选项的顺序进行两次。只要确保在交换后将胜利归因于正确的选项即可。
  3. 允许平局:在某些情况下,两种选项可能同样好。因此,允许大语言模型宣告平局,以避免其不得不随意选择一个优胜者。
  4. 使用 Chain-of-Thought 方法:在给出最终选择前,要求大语言模型解释其决策过程,这可以提高评估的可靠性。一个额外的好处是,你可以使用一个较弱但更快的大语言模型,仍能达到类似的结果。因为这一部分通常是在批处理模式下进行的,Chain-of-Thought 增加的延迟并不是问题
  5. 控制回复长度:大语言模型倾向于偏向较长的回复。为了减少这种偏差,确保回复的长度相似。

LLM-as-Judge 的一个特别有用的应用是检查新的提示策略是否会出现退步。如果您已经有了一系列生产结果,有时您可以用新的提示策略重新运行这些生产示例,并使用LLM-as-Judge来快速评估新策略可能遇到的问题。

这有一个简单但有效的方法 ,以迭代LLM-as-Judge,我们记录大模型的回复、评判的解释 (即 CoT) 和最终结果。然后与其他人一起检查这些记录,以确定改进的领域。经过三次迭代,人类与大语言模型的判断一致性从 68% 提高到了 94%!

万字经验 | 使用大模型(LLMs)构建产品一年后,我们有些经验想告诉你

LLM-as-Judge并非万能,在一些微妙的语言方面,即使是最强大的模型也无法可靠评估。此外,我们发现传统的分类器和奖励模型可以比LLM-as-Judge实现更高的准确性,而且成本更低,延迟更短。对于代码生成,LLM-as-Judge可能比执行评估等更直接的评估策略更弱。

3. 用于评估生成的“实习生测试”

在评估生成时,我们喜欢使用以下的“实习生测试”:如果你将完全相同的输入,包括上下文,交给一个相关专业的普通大学生作为任务,他们能否成功完成?需要多长时间?

如果答案是否定的,因为LLM缺乏所需的知识,考虑方法来丰富上下文。

如果答案是否定的,我们简单地无法改善上下文来解决它,那么我们可能遇到了对当代LLM来说过于艰难的任务。

如果答案是肯定的,但需要一段时间,我们可以尝试减少任务的复杂性。它能分解吗?是否有任务的某些方面可以更加模板化?

如果答案是肯定的,而且很快就能完成,那么就需要深入分析数据。模型做错了什么?我们能找到失败的模式吗?可以尝试在模型响应前后让它解释自己的思路,以帮助我们理解模型的工作原理

4. 过分强调某些评估可能会降低整体性能

“当一个衡量标准变成目标时,它就不再是一个好的衡量标准。”

— 古德哈特法则

这方面的一个例子是“针堆中的针 (NIAH)”评估。最初的评估是为了量化随着上下文规模的增加,模型的召回率及其受针的位置影响的程度。然而,这一评估被过分强调,以至于在 Gemini 1.5 的报告中成为图 1 的内容。该评估方法是在一个包含多篇 Paul Graham 文章的长文档中插入一个特定短语 (“The special magic number is:”),然后要求模型回忆出这个魔术数字。

虽然有些模型实现了接近完美的召回,但值得怀疑的是NIAH是否真正反映了应用中所需的推理和召回能力。考虑一个更实际的场景:给定一个小时长会议的文字记录,LLM能否总结关键决策和下一步行动,并正确将每个项目归属于相关人士?这一任务更加现实,不仅需要死记硬背,还需要解析复杂讨论、识别关键信息并进行综合总结的能力。

这是一个 实际应用中 NIAH 评估 的例子。使用 医生与患者视频通话的记录,大模型被询问关于患者药物的信息。它还包括一个更具挑战性的 NIAH 评估,插入了一个关于随机披萨配料的短语,例如“制作完美披萨所需的秘密配料是:浓咖啡浸泡的枣子、柠檬和山羊奶酪。”在药物任务上的召回率约为 80%,而在披萨任务上的召回率约为 30%。

万字经验 | 使用大模型(LLMs)构建产品一年后,我们有些经验想告诉你

此外,过分强调NIAH评估可能会导致大模型在提取和总结任务上的性能降低。由于这些大模型被微调到关注每一句话,它们可能开始将不相关的细节和分散注意力的内容当作重要内容,因此在最终输出中包含它们(实际上不应该包含)!

这种情况也可能适用于其他评估和使用场景。例如,在生成摘要时,过分强调事实一致性可能导致摘要内容不够具体 (因此不太可能在事实上一致) 并且可能不够相关。反之,过分强调写作风格和文采可能导致语言更加华丽,但同时可能引入事实上的不一致。

5. 将标注任务简化为二元判断或者成对比较

开放式反馈或用 李克特量表 对模型输出进行评分,认知负担较大。结果,收集的数据更加嘈杂——由于人类评分员之间的变异性——因此不太有用。一种更有效的方法是简化任务,减少标注者的认知负担。工作良好的两项任务是二元分类成对比较

在二元分类中,要求标注者对模型的输出做出简单的是或否的判断。他们可能会被询问生成的摘要是否与源文档在事实上是一致的,或者提出的回应是否相关,或者是否包含有害内容。与Likert量表相比,二元决策更精确,评分员之间更一致,并且提高了吞吐量。Doordash就是通过一系列是或否的问题为菜单条目设置标签队列的方式。

在成对比较中,向标注者提供一对模型响应,并询问哪个更好。因为对于人类来说,说“A比B好”比单独为A或B分配一个分数更容易,这导致更快和更可靠的标注(相对于Likert量表)。在Llama2聚会上,Llama2论文的作者之一Thomas Scialom确认,与收集监督式微调数据(如书面回应)相比,成对比较更快、更便宜。前者的成本是每单位3.5美元,而后者的成本是每单位25美元。

如果你正在开始编写标签指南,这里有一些来自谷歌和必应搜索的指南。

保护措施和评估可以互换使用

保护措施有助于捕捉不适当或有害的内容,而评估则有助于衡量模型输出的质量和准确性。对于无参考评估而言,它们可以被视为一体两面。无参考评估是指不依赖于“标准”参考(例如人类编写的答案)的评估,能够仅基于输入提示和模型的响应来评估输出的质量。

例如,摘要评估 中,我们只需考虑输入文档即可评估摘要在事实一致性和相关性方面的表现。如果摘要在这些指标上得分较低,我们可以选择不向用户展示它,有效地将评估作为保护措施。类似地,无参考的翻译评估 可以在不需要人工翻译参考的情况下评估翻译质量,同样允许我们将其作为保护措施使用。

6. 大模型即使不应该输出也会输出

与LLM合作的一个主要挑战是,它们经常会生成输出,即使它们不应该这样做。这可能导致无害但毫无意义的回应,或者更严重的缺陷,如有害或危险内容。例如,当被要求从文档中提取特定属性或元数据时,LLM可能会自信地返回值,即使这些值实际上并不存在。或者,模型可能会用非英语回应,因为我们在上下文中提供了非英语文档。

虽然我们可以尝试提示LLM返回一个“不适用”或“未知”的响应,但这并非万无一失。即使有日志概率 (log probabilities) 可用,它们也无法准确指示输出质量。虽然日志概率显示了一个词元在输出中出现的可能性,但它们不一定反映生成文本的正确性。相反,对于那些经过指令微调 (instruction-tuned) 的模型,即训练来响应查询并生成连贯回答的模型,日志概率可能校准得不够好。因此,高日志概率可能意味着输出流畅且连贯,但不代表其准确或相关。

虽然精心设计的提示工程可以在一定程度上有所帮助,我们应该用更强有力的保护措施来补充,以检测和过滤/重新生成不需要的输出。例如,OpenAI提供了一个内容审核 API,可以识别不安全的响应,如仇恨言论、自伤或性输出。同样,有许多包用于检测个人身份信息 (PII) 。一个好处是保护措施大体上不受用例的影响,因此可以广泛地应用于给定语言的所有输出。此外,通过精确检索,如果没有相关的文档的话,我们的系统可以确定地回应“我不知道”。

相应地,大语言模型有时在应该生成内容时却未能生成。这可能是由于各种原因,从 API 提供者的长尾延迟等简单问题到内容审核过滤器阻止输出等复杂问题。因此,持续记录输入和 (可能缺失的) 输出对于调试和监控非常重要。

7. 大模型的幻觉是个顽固的问题

不同于内容安全或个人可识别信息(PII)缺陷,事实上,不一致性问题更顽固,且更难以检测。它们更为常见,发生率在5 – 10%之间,而且根据我们从大模型(LLM)提供商那里学到的,即便是像摘要这样的简单任务,将其降至2%以下也颇具挑战。

为了解决这个问题,我们可以结合使用提示工程(生成前)和事实不一致性防护措施(生成后)。对于提示工程,如思维链(CoT)通过让LLM在最终返回输出之前解释其推理过程来帮助减少幻觉。然后,我们可以应用事实不一致防护措施来评估摘要的事实性,并过滤或重新生成幻觉。在某些情况下,可以确定性地检测到幻觉。当使用来自RAG检索的资源时,如果输出是结构化的并且标识了资源是什么,你应该能够手动验证它们来源于输入上下文。

版权声明

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处。如若内容有涉嫌抄袭侵权/违法违规/事实不符,请点击 举报 进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部