每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领域的领跑者。点击订阅,与未来同行! 订阅:https://rengongzhineng.io/
使用大型语言模型(LLM)进行开发的时代令人兴奋。过去的一年中,LLM在实际应用中的表现已经达到“足够好”的水平,并且每年都在变得更好且更便宜。再加上社交媒体上的一系列演示,到2025年,预计将有2000亿美元的投资进入人工智能领域。此外,提供者的API使LLM变得更加易于访问,使得不仅是机器学习工程师和科学家,任何人都可以将智能融入他们的产品。然而,尽管构建AI的门槛已经降低,但创建真正有效的产品和系统——不仅仅是演示——仍然非常困难。
我们过去一年一直在构建过程中,发现了许多棘手的问题。虽然我们不敢说代表整个行业,但我们希望分享我们的经验,以帮助你避免我们犯过的错误,并加速你的迭代。这些经验分为三个部分:
战术层面:提示、RAG、流程工程、评估和监控的实践。不管你是构建LLM的从业者,还是周末项目的爱好者,这部分内容都是为你而写。
操作层面:产品发布的组织和日常关注点,以及如何打造高效团队。针对希望可持续且可靠地部署产品的产品/技术领导者。
战略层面:长远的宏观视角,带有明确观点,如“在产品市场契合前不使用GPU”和“关注系统而非模型”,以及如何迭代。专为创始人和高管们撰写。
我们的目的是提供一份实际指南,帮助你成功构建LLM产品,基于我们的经验,并引用行业中的案例。
准备好深入探讨了吗?让我们开始吧。
战术层面:使用LLM的具体操作
在本部分中,我们分享了新兴LLM堆栈核心组件的一些最佳实践:提高质量和可靠性的提示技巧、评估策略、改进基础生成的检索增强生成(RAG)思路等。我们还将探讨如何设计人机协作工作流。尽管技术仍在快速发展,但我们希望这些经验——我们通过无数实验获得的副产品——能够经受住时间的考验,帮助你构建和发布可靠的LLM应用。
提示
开发新应用时,我们建议从提示开始。提示的作用经常被低估和高估。低估是因为正确的提示技术,使用得当,可以取得非常好的效果。高估是因为即使基于提示的应用,也需要围绕提示进行大量工程工作以取得良好效果。
充分利用基本提示技术
一些提示技术在各种模型和任务中一贯有助于提高性能:n-shot提示+上下文学习、链式思维(CoT)以及提供相关资源。
通过n-shot提示进行上下文学习的理念是向LLM提供几个示例,展示任务并对齐输出和我们的期望。一些小建议:
- 如果n值太低,模型可能会过度依赖这些特定示例,削弱其泛化能力。经验法则是,n值≥5。不妨尝试几打示例。
- 示例应代表预期的输入分布。如果你在构建一个电影摘要器,包含不同类型的样本,与实际情况中看到的大致相同。
- 不一定要提供完整的输入-输出对。在许多情况下,期望输出的示例就足够了。
- 如果使用支持工具使用的LLM,n-shot示例也应使用你希望代理使用的工具。
在链式思维(CoT)提示中,我们鼓励LLM在返回最终答案之前解释其思考过程。可以将其视为提供给LLM的草图本,使其不必全在记忆中完成。原始方法是简单地将短语“让我们一步步思考”添加到指令中,但我们发现,通过添加一两句额外的句子使CoT更具体,通常可以显著减少幻觉率。例如,当要求LLM总结会议记录时,我们可以明确步骤,如:
- 首先,列出关键决策、跟进事项及相关负责人。
- 然后,检查草图本中的细节是否与记录一致。
- 最后,将关键点综合成简洁的摘要。
请注意,最近一些人对这一技术的实际效果提出了质疑。此外,关于使用链式思维进行推理时具体发生了什么,也存在大量争论。不管怎样,当有可能时,这一技术值得尝试。
提供相关资源是一种强大的机制,可以扩展模型的知识库,减少幻觉,并增加用户的信任。通常通过检索增强生成(RAG)实现,向模型提供可以直接在响应中使用的文本片段是一种基本技术。在提供相关资源时,不仅仅是包括它们;还要告诉模型优先使用它们,直接引用它们,有时还要提到当资源不足时。这些有助于将代理响应“定位”到资源库。
结构化输入和输出
结构化输入和输出有助于模型更好地理解输入,并返回可以可靠集成到下游系统的输出。为输入添加序列化格式可以为模型提供更多的上下文关系线索、特定标记的附加元数据(如类型),或将请求与模型训练数据中的类似示例关联。
例如,许多互联网上关于编写SQL的问题都会先指定SQL模式。因此,你可能期望有效的文本到SQL提示应包括结构化模式定义;确实如此。
结构化输出也有类似的目的,但它还简化了与系统下游组件的集成。Instructor和Outlines在结构化输出方面表现良好。(如果你正在导入LLM API SDK,请使用Instructor;如果你正在导入Huggingface用于自托管模型,请使用Outlines。)结构化输入清晰表达任务,类似于训练数据的格式,增加了更好输出的可能性。
在使用结构化输入时,注意每个LLM家族有其自己的偏好。Claude偏好,而GPT偏好Markdown和JSON。使用XML时,你甚至可以通过提供标签来预填充Claude的响应,如下所示:
{"messages": [{"role": "user","content": "从这个产品描述中提取<name>, <size>, <price>和<color>并放入<response>标签中。\n<description>The SmartHome Mini is a compact smart home assistant available in black or white for only $49.99. At just 5 inches wide, it lets you control lights, thermostats, and other connected devices via voice or app—no matter where you place it in your home. This affordable little hub brings convenient hands-free control to your smart devices.</description>"},{"role": "assistant","content": "<response><name>"}]
}
保持简洁的小提示
软件中的“神对象”是一个常见的反模式,同样适用于提示。
提示通常从简单开始:几句指令,加上几个示例,就可以开始了。但是,当我们试图提高性能并处理更多的边缘情况时,复杂性会逐渐增加。更多的指令。多步推理。几十个示例。不知不觉中,我们最初简单的提示变成了一个2000个标记的怪物。而且更糟糕的是,它在更常见和简单的输入上表现更差!GoDaddy分享了他们构建LLM的第一大教训,正是这个问题。
就像我们努力(艰难)保持系统和代码简单一样,我们也应该对提示保持简单。不要将所有任务放在一个提示中,而是将其分解成多个步骤。例如,对于会议记录摘要器,我们可以将其分解为:
- 将关键决策、行动项和负责人提取成结构化格式
- 将提取的细节与原始记录进行一致性检查
- 根据结构化细节生成简洁摘要
结果是,我们将一个提示分解成多个简单、专注且易于理解的提示。通过分解,我们可以单独迭代和评估每个提示。
设计上下文标记
重新思考并挑战你关于需要多少上下文才能发送给代理的假设。像米开朗基罗一样,不要堆砌你的上下文雕塑——削减多余的材料,直到雕塑显现。RAG是一种汇集所有可能相关信息的流行方法,但你做了什么来提取必要的内容?
我们发现,将发送给模型的最终提示——包括所有上下文构建、元提示和RAG结果——放在一个空白页面上阅读,真的有助于重新思考你的上下文。我们发现冗余、自相矛盾的语言和糟糕的格式。
另一个关键优化是上下文的结构。你的文档袋表示对人类没有帮助,不要假设它对代理有用。仔细考虑如何结构化你的上下文,以突出其各部分之间的关系,并尽可能简化提取过程。
信息检索 / RAG
除了提示,另一种有效引导LL
M的方法是提供知识作为提示的一部分。这使LLM能够在提供的上下文中进行在上下文学习。这被称为检索增强生成(RAG)。实践者发现,RAG在提供知识和改进输出方面有效,同时所需的精力和成本远低于微调。RAG的效果取决于检索到的文档的相关性、密度和详细程度。
RAG输出质量取决于检索到的文档质量,可以从几个方面考虑:
- 首先是相关性。通常通过排名指标如平均倒数排名(MRR)或归一化折扣累计增益(NDCG)来量化。MRR评估系统在排名列表中第一个相关结果的表现,而NDCG则考虑所有结果的相关性及其位置。
- 其次是信息密度。如果两个文档同样相关,我们应该选择更简洁、没有多余细节的那个。
- 最后是文档的详细程度。想象我们在构建一个RAG系统,用于从自然语言生成SQL查询。我们可以简单地提供表模式及列名作为上下文。但如果我们包括列描述和一些代表性值呢?额外的详细信息可以帮助LLM更好地理解表的语义,从而生成更正确的SQL。
不要忘记关键词搜索;将其作为基线和混合搜索的一部分
在嵌入式RAG演示如此流行的情况下,很容易忽略或忘记信息检索领域的几十年研究和解决方案。
虽然嵌入无疑是强大的工具,但它们并不是万能的。首先,它们在捕捉高级语义相似性方面表现出色,但在更具体的基于关键词的查询(如用户搜索名字、首字母缩略词或ID)时可能表现较差。基于关键词的搜索(如BM25)就是专门为此设计的。并且经过多年的关键词搜索,用户可能已经习惯了它,如果未能返回他们期望检索到的文档,可能会感到沮丧。
矢量嵌入并没有神奇地解决搜索问题。事实上,繁重的工作在于你用语义相似性搜索重新排序之前的步骤。要在BM25或全文搜索基础上取得实质性改进是很难的。——Aravind Srinivas,Perplexity.ai CEO
我们一直在向客户和合作伙伴传达这一信息。使用简单嵌入的最近邻搜索会产生非常嘈杂的结果,你可能更适合从关键词搜索开始。——Beyang Liu,Sourcegraph CTO
其次,用关键词搜索更容易理解为什么某个文档会被检索到——我们可以查看与查询匹配的关键词。相比之下,基于嵌入的检索则不那么可解释。最后,感谢像Lucene和OpenSearch这样的系统经过几十年的优化和实战测试,关键词搜索通常在计算效率上更高。
在大多数情况下,混合搜索效果最好:关键词匹配用于显而易见的匹配,嵌入用于同义词、上位词和拼写错误,以及多模态(如图像和文本)。Shortwave分享了他们如何构建RAG管道,包括查询重写、关键词+嵌入检索和排名。
优先使用RAG而非微调以获取新知识
RAG和微调都可以用于将新信息纳入LLM,并提高特定任务的性能。那么,应该先尝试哪个呢?
最近的研究表明,RAG可能占有优势。一项研究比较了RAG和无监督微调(又称连续预训练),在MMLU子集和当前事件上进行评估。他们发现,RAG在处理训练中遇到的知识和完全新知识方面, consistently outperformed fine-tuning for knowledge encountered during training as well as entirely new knowledge。另一篇论文中,他们比较了RAG和有监督微调在农业数据集上的表现。同样,RAG的性能提升大于微调,特别是对于GPT-4。
除了改进的性能外,RAG还具有一些实际优势。首先,与连续预训练或微调相比,保持检索索引的最新状态更容易——也更便宜!其次,如果我们的检索索引中包含有毒或偏见内容的问题文档,我们可以轻松删除或修改这些文档。
此外,RAG提供了更细粒度的控制。例如,如果我们为多个组织托管一个RAG系统,通过分区检索索引,可以确保每个组织只能检索其自己的索引文档,防止无意中将一个组织的信息暴露给另一个组织。
长上下文模型不会使RAG过时
随着Gemini 1.5提供长达10M标记的上下文窗口,一些人开始质疑RAG的未来。
我倾向于认为Sora对Gemini 1.5的宣传过头了。10M标记的上下文窗口实际上使现有的大多数RAG框架变得不必要——你只需将你的数据放入上下文中,然后像平常一样与模型对话。想象一下,这对所有初创公司/代理/语言链项目的影响,其中大部分工程工作都是RAG😅 或者用一句话说:10m上下文杀死了RAG。好工作Gemini——Yao Fu
虽然长上下文确实将在分析多个文档或与PDF对话等用例中带来变革,但RAG的“死亡”传言被大大夸大了。
首先,即使有一个10M标记的上下文窗口,我们仍然需要选择要提供给模型的信息。其次,除了针在干草堆评估,我们还没有看到令人信服的数据表明模型可以有效地在这么大的上下文中进行推理。因此,如果没有好的检索(和排名),我们可能会用分心内容压倒模型,甚至可能填满完全无关的信息。
最后是成本。Transformer的推理成本随着上下文长度呈二次(或线性)增加。虽然存在可以在回答每个问题前读取整个Google Drive内容的模型,但这并不意味着这是一个好主意。将其类比于我们使用RAM的方式:我们仍然从磁盘读取和写入,即使存在运行数十TB RAM的计算实例。
所以暂时不要扔掉你的RAG。即使上下文窗口变大,这种模式仍将有用。
调整和优化工作流
提示LLM只是开始。要充分利用它们,我们需要超越单一提示,拥抱工作流。例如,如何将单个复杂任务拆分为多个简单任务?何时微调或缓存有助于提高性能并减少延迟/成本?在本节中,我们分享了一些经过验证的策略和真实案例,以帮助你优化并构建可靠的LLM工作流。
步步为营,多回合“流”可以大幅提升
我们已经知道,通过将单个大提示分解为多个小提示,可以获得更好的结果。AlphaCodium就是一个例子:通过从单一提示切换到多步工作流,他们将GPT-4在CodeContests上的准确率(pass@5)从19%提高到44%。工作流包括:
- 反思问题
- 推理公开测试
- 生成可能的解决方案
- 排名可能的解决方案
- 生成合成测试
- 在公开和合成测试上迭代解决方案
明确目标的小任务非常适合作为代理或流提示。并不是每个代理提示都要求结构化输出,但结构化输出在与系统交互时非常有帮助。
可以尝试一些方法:
- 明确的规划步骤,尽可能具体。考虑从预定义的计划中选择。
- 将原始用户提示重写为代理提示。注意,这一过程有损!
- 将代理行为视为线性链、DAG和状态机;不同的依赖和逻辑关系对于不同的规模可能更适合。可以从不同任务架构中挤出性能优化吗?
- 规划验证;你的规划可以包括评估其他代理响应的指示,以确保最终组合良好。
- 固定上游状态的提示工程——确保你的代理提示针对可能发生的前置状态变体进行评估。
优先采用确定性工作流
虽然AI代理可以动态响应用户请求和环境,但其非确定性特性使其部署具有挑战性。每一步都有可能失败,并且恢复错误的机会很小。因此,代理完成多步任务的可能性随着步骤数的增加呈指数下降。因此,构建代理的团队发现难以部署可靠的代理。
一种有前途的方法是让代理系统生成确定性计划,然后以结构化、可重复的方式执行这些计划。在第一步中,给定一个高层目标或提示,代理生成一个计划。然后,计划以确定性方式执行。这样,每一步都更可预测和可靠。好处包括:
- 生成的计划可以作为少数示例,用于提示或微调代理。
- 确定性执行使系统更可靠,因此更容易测试和调试。此外,失败可以追溯到计划的具体步骤。
- 生成的计划可以表示
为有向无环图(DAG),相比静态提示,更容易理解和适应新情况。
最成功的代理构建者可能是那些有丰富管理初级工程师经验的人,因为生成计划的过程类似于我们指导和管理初级工程师的方式。我们给初级工程师明确的目标和具体的计划,而不是模糊的开放性指示,我们也应该对代理这样做。
最终,构建可靠的工作代理的关键可能在于采用更结构化、确定性的方法,以及收集数据以完善提示和微调模型。否则,我们将构建偶尔表现非常好的代理,但平均而言会让用户失望,导致用户留存率下降。
超越温度设置以获得更多样化的输出
假设你的任务需要LLM输出的多样性。也许你在编写一个LLM管道,建议用户从你的目录中购买产品,给定他们之前购买的产品列表。运行提示多次后,你可能会注意到结果推荐过于相似,因此你可能会增加LLM请求中的温度参数。
简单地说,增加温度参数使LLM响应更为多样化。在采样时,下一个标记的概率分布变得更平坦,这意味着通常不太可能的标记更常被选中。然而,增加温度时,你可能会注意到一些与输出多样性相关的失败模式。例如,
一些可能适合的产品可能永远不会被LLM输出。因为它们在LLM训练时学习的基础上非常可能跟随提示。同样,如果温度太高,你可能会得到引用不存在产品(或胡言乱语!)的输出。
换句话说,增加温度并不保证LLM将从你期望的概率分布(如均匀随机)中采样输出。然而,我们有其他技巧来增加输出的多样性。最简单的方法是调整提示中的元素。例如,如果提示模板包括一个项目列表,如历史购买,将这些项目的顺序每次插入提示时进行随机排列可以产生显著差异。
此外,保持最近输出的短列表有助于防止冗余。在我们的推荐产品示例中,通过指示LLM避免建议这个最近列表中的项目,或者拒绝和重新采样类似的建议,我们可以进一步多样化响应。另一种有效策略是变化提示中的措辞。例如,结合“选择用户可能会经常使用的产品”或“选择用户可能会向朋友推荐的产品”等短语,可以转移焦点,从而影响推荐产品的多样性。
缓存被低估了
缓存节省成本并消除了生成延迟,不需要重新计算相同输入的响应。此外,如果之前已经对响应进行了保护措施,我们可以提供这些经过审核的响应,减少提供有害或不适当内容的风险。
一种简单的缓存方法是使用处理项的唯一ID,例如,如果我们在总结新文章或产品评论时。当请求到来时,我们可以检查缓存中是否已有摘要。如果有,可以立即返回;如果没有,则生成、审核并提供,然后将其存储在缓存中以供将来请求使用。
对于更开放的查询,我们可以借鉴搜索领域的技术,该领域也利用缓存处理开放输入。自动补全和拼写校正等功能也有助于规范化用户输入,从而增加缓存命中率。
何时进行微调
即使是最巧妙设计的提示也可能在某些任务上不够好。例如,即使经过大量提示工程,我们的系统仍可能无法返回可靠、高质量的输出。如果是这样,那么可能需要为你的特定任务微调一个模型。
成功的例子包括:
- Honeycomb的自然语言查询助手:最初,“编程手册”与n-shot示例一起提供,用于上下文学习。虽然这效果不错,但微调模型后在语法和领域特定语言规则上的输出更好。
- Rechat的Lucy:LLM需要以非常特定的格式生成响应,将结构化和非结构化数据结合,以便前端正确呈现。微调是确保其一致工作的关键。
尽管微调可以有效,但它也带来显著成本。我们必须注释微调数据,微调和评估模型,最终自托管它们。因此,考虑前期更高的成本是否值得。如果提示已经解决90%的问题,那么微调可能不值得投资。然而,如果我们决定微调,为了降低收集人工注释数据的成本,我们可以生成和微调合成数据,或者从开源数据开始。
评估与监控
评估LLM可以是雷区。LLM的输入和输出是任意文本,而我们设置的任务各不相同。然而,严格和周到的评估至关重要——OpenAI的技术领导者也在评估上工作,并对每个评估提供反馈。
评估LLM应用需要多种定义和简化:这只是单元测试,或更像可观察性,或也许只是数据科学。我们发现这些观点都很有用。在以下部分中,我们提供了一些我们学到的关于构建评估和监控管道的重要经验。
从真实输入/输出样本创建一些基于断言的单元测试
创建单元测试(即断言),由生产中的输入和输出样本组成,基于至少三个标准对输出进行期望判断。虽然三个标准可能看起来随意,但它是一个实际的起点;更少可能表明你的任务定义不充分或过于开放,如通用聊天机器人。这些单元测试或断言应由任何对管道的更改触发,无论是编辑提示、添加新上下文(通过RAG)还是其他修改。这个写作有一个实际用例的基于断言的测试示例。
考虑从指定所有响应中要包含或排除的短语或想法的断言开始。还可以考虑检查单词、项目或句子计数是否在范围内。对于其他类型的生成,断言可能不同。执行-评估是一种强大的代码生成评估方法,即运行生成的代码,并确定运行时状态是否满足用户请求。
例如,如果用户要求一个名为foo的新函数;然后在执行代理生成的代码后,foo应该是可调用的!执行-评估的一项挑战是代理代码经常会使运行时状态与目标代码略有不同。放宽断言到任何可行答案都会满足的绝对最弱假设可能是有效的。
最后,按客户预期使用你的产品(即“狗粮”)可以提供关于真实数据失败模式的见解。这种方法不仅有助于识别潜在弱点,还提供了一个有用的生产样本来源,可以转换为评估。
LLM-as-Judge可以工作(某种程度上),但不是银弹
LLM-as-Judge,即使用强LLM评估其他LLM的输出,受到了某些人的怀疑。(我们中的一些人最初也是巨大的怀疑者。)然而,当实施得当时,LLM-as-Judge与人类判断有很好的相关性,至少可以帮助建立对新提示或技术表现的先验知识。特别是在进行成对比较时(如对照与处理),LLM-as-Judge通常方向正确,尽管胜负的幅度可能有噪声。
这里有一些建议,帮助你最大限度地利用LLM-as-Judge:
- 使用成对比较:而不是让LLM对单个输出进行Likert评分,向其提供两个选项并让其选择更好的一个。这往往导致更稳定的结果。
- 控制位置偏差:提供选项的顺序可能会偏向LLM的决定。为减轻这种情况,每个成对比较进行两次,交换顺序。只需确保在交换后将胜利归属正确的选项!
- 允许平局:在某些情况下,两个选项可能同样好。因此,允许LLM宣布平局,以免不得不任意选择一个赢家。
- 使用链式思维:要求LLM在给出最终偏好之前解释其决定可以增加评估的可靠性。作为额外奖励,这允许你使用较弱但更快的LLM,仍能获得类似的结果。因为这部分管道通常处于批处理模式,CoT的额外延迟不是问题。
- 控制响应长度:LLM往往偏向较长的响应。为减轻这种情况,确保响应对的长度相似。
LLM-as-Judge的一个特别强大的应用是检查新的提示策略是否回归。如果你跟踪了一系列生产结果,有时你可以用新提示策略重新运行这些生产示例,并使用LLM-as-Judge快速评估新策略可能存在的问题。
这里有一个简单但有效的方法,用于迭代LLM-as-Judge,我们记录LLM响应、评审的批判(即CoT)和最终结果。然后与利益相关者一起审查,以确定改进的领域。通过三次迭代,人类与LLM的协议从68%提高到94%!
LLM-as-Judge不是银弹。语言中的微妙方面,即使是最强的模型也可能无法可靠地评估。此外,我们发现传统分类器和奖励模型可以比LLM-as-Judge获得更高的准确性,且成本和延
迟更低。对于代码生成,LLM-as-Judge可能比更直接的评估策略如执行-评估要弱。
用于评估生成的“实习生测试”
我们喜欢使用以下“实习生测试”评估生成:如果你将语言模型的输入,包括上下文,交给相关专业的普通大学生作为任务,他们能否成功?需要多长时间?
如果答案是否定的,因为LLM缺乏所需知识,考虑如何丰富上下文。
如果答案是否定的,并且我们无法改进上下文解决这个问题,那么我们可能遇到了对现有LLM来说过于困难的任务。
如果答案是肯定的,但需要一些时间,可以尝试减少任务的复杂性。它可以分解吗?任务的某些方面是否可以模板化?
如果答案是肯定的,他们会很快完成,那么是时候深入数据了。模型哪里出错了?能找到失败模式吗?尝试在模型响应前或后要求其解释,帮助你建立心智模型。
过度强调某些评估可能会损害整体性能
“当一个指标成为目标时,它就不再是一个好指标。”——Goodhart定律。
一个例子是干草堆中的针(NIAH)评估。最初的评估帮助量化模型在上下文大小增加时的回忆能力,以及针位置如何影响回忆。然而,它被过度强调,以至于成为Gemini 1.5报告的图1。该评估涉及将特定短语(“特殊的魔法{城市}号码是:{号码}”)插入到长文档中,并重复保罗·格雷厄姆的文章,然后提示模型回忆魔法号码。
虽然一些模型实现了近乎完美的回忆,但NIAH是否真正反映了实际应用中所需的推理和回忆能力是值得怀疑的。考虑一个更实际的场景:给定一个小时长的会议记录,LLM能否总结关键决策和下一步,并正确归属每个项目给相关人员?这一任务更现实,超越了机械记忆,还考虑了解析复杂讨论、识别相关信息并综合摘要的能力。
这是一个实际的NIAH评估示例。使用医生-患者视频通话的记录,LLM被询问患者的药物。还包括一个更具挑战性的NIAH,插入随机比萨配料的短语,如“完美比萨所需的秘密成分是:咖啡浸泡的枣、柠檬和山羊奶酪。”在药物任务上的回忆约为80%,而在比萨任务上的回忆约为30%。
顺便说一下,过度强调NIAH评估可能导致提取和摘要任务的性能下降。因为这些LLM过于微调以关注每句话,它们可能开始将无关细节和干扰信息视为重要,从而将它们包含在最终输出中(当它们不应该这样做时!)
这也适用于其他评估和用例。例如,摘要。强调事实一致性可能导致摘要不够具体(因此不太可能与事实不一致)且可能不相关。相反,强调写作风格和优雅可能导致更花哨、营销类型的语言,可能引入事实不一致。
简化注释为二元任务或成对比较
为模型输出提供开放式反馈或Likert评分是认知上具有挑战性的任务。结果,收集的数据更噪声——由于人类评分者之间的变异性——因此不太有用。一种更有效的方法是简化任务,减少评分者的认知负担。两个工作良好的任务是二元分类和成对比较。
在二元分类中,评分者被要求对模型输出进行简单的“是”或“否”判断。他们可能被问到生成的摘要是否与源文档一致,建议的响应是否相关,或是否包含毒性。与Likert评分相比,二元决策更精确,评分者一致性更高,产出更高。这是Doordash如何设置其标签队列,通过树状是非问题标记菜单项的。
在成对比较中,评分者被提供一对模型响应,并被问到哪一个更好。因为人类更容易说“A比B好”,而不是单独给A或B打分,这比Likert评分更快、更可靠。Llama2聚会上,Llama2论文的作者之一Thomas Scialom证实,成对比较比收集有监督的微调数据(如书面响应)更快、更便宜。前者的成本为每单位$3.5,而后者的成本为每单位$25。
如果你开始编写标签指南,这里有一些来自Google和Bing搜索的参考指南。
(无参考)评估和护栏可以互换使用
护栏帮助捕捉不当或有害内容,而评估帮助衡量模型输出的质量和准确性。在无参考评估的情况下,它们可以视为同一事物的两面。无参考评估是不依赖于“黄金”参考(如人类书写的答案)的评估,可以仅基于输入提示和模型响应评估输出质量。
一些例子是摘要评估,我们只需考虑输入文档,评估摘要的事实一致性和相关性。如果摘要在这些指标上得分较低,我们可以选择不向用户显示它,有效地将评估用作护栏。同样,无参考翻译评估可以在不需要人类翻译参考的情况下评估翻译质量,再次允许我们将其用作护栏。
LLM将在不应该生成时生成输出
使用LLM的一个关键挑战是它们经常会生成不应该生成的输出。这可能导致无害但无意义的响应,或更严重的缺陷如毒性或危险内容。例如,当被要求从文档中提取特定属性或元数据时,LLM可能会自信地返回即使这些值实际上不存在的值。或者,因为我们提供了非英语文档,模型可能会用其他语言响应。
虽然我们可以尝试提示LLM返回“不适用”或“未知”响应,但这并不万无一失。即使对数概率可用,它们也是输出质量的差指标。虽然对数概率指示标记在输出中出现的可能性,但它们不一定反映生成文本的正确性。相反,对于被训练以响应查询并生成连贯响应的指令调优模型,对数概率可能校准不佳。因此,虽然高对数概率可能表明输出流畅且连贯,但并不意味着它是准确或相关的。
虽然仔细的提示工程可以在某种程度上有所帮助,但我们应补充以检测和过滤/重新生成不期望输出的强大护栏。例如,OpenAI提供的内容审核API可以识别仇恨言论、自残或性内容等不安全响应。同样,有许多包用于检测个人身份信息(PII)。一个好处是护栏对用例大致不敏感,因此可以广泛应用于给定语言的所有输出。此外,通过精确检索,我们的系统可以确定性地响应“我不知道”如果没有相关文档。
一个相关的结论是,当期望输出时,LLM可能会生成失败。这可能由于各种原因,从API提供者的长尾延迟到更复杂的问题如输出被内容审核过滤器阻止。因此,持续记录输入和(可能缺少的)输出以进行调试和监控是重要的。
幻觉是一个顽固的问题
与内容安全或PII缺陷相比,事实不一致更顽固且更难检测。它们更常见,发生率在5-10%之间,LLM提供者告诉我们,即使在简单任务如摘要上,降低到2%以下也很困难。
为了解决这个问题,我们可以结合提示工程(生成前)和事实不一致护栏(生成后)。对于提示工程,链式思维等技术通过让LLM解释其推理过程,可以减少幻觉。然后,我们可以应用事实不一致护栏评估摘要的事实性,过滤或重新生成幻觉。在某些情况下,可以确定性地检测幻觉。当使用RAG检索资源时,如果输出是结构化的并标识了资源是什么,你应该能够手动验证它们是否来自输入上下文。
操作:日常和组织关注点
数据
就像食材的质量决定了菜肴的味道,输入数据的质量决定了机器学习系统的性能。此外,输出数据是衡量产品是否工作的唯一方式。所有作者都密切关注数据,每周花几个小时查看输入和输出数据,以更好地理解数据分布:其模式、边缘情况和模型的局限性。
检查开发与生产偏差
传统机器学习管道中常见的错误来源是训练-服务偏差。当用于训练的数据与模型在生产中遇到的数据不同步时,就会发生这种情况。虽然我们可以在不进行训练或微调的情况下使用LLM,因此没有训练集,但类似的问题出现在开发-生产数据偏差上。本质
上,我们在开发过程中测试系统的数据应与系统在生产中面临的数据相似。如果不这样做,我们可能会发现生产准确率下降。
LLM开发-生产偏差可分为两类:结构性和基于内容的。结构性偏差包括格式不一致的问题,如JSON字典中的列表类型值与JSON列表之间的差异、不一致的大小写以及拼写错误或句子片段等错误。这些错误可能导致模型性能不可预测,因为不同LLM在特定数据格式上进行训练,提示对微小变化非常敏感。基于内容或“语义”偏差是指数据的含义或上下文的差异。
像传统机器学习一样,定期测量LLM输入/输出对之间的偏差是有用的。输入和输出的长度或特定格式要求(如JSON或XML)等简单指标是追踪变化的直接方法。对于更“高级”的漂移检测,考虑聚类输入/输出对的嵌入,以检测语义漂移,如用户讨论主题的变化,这可能表明他们正在探索模型未接触过的领域。
在测试更改时,如提示工程,确保保留的数据集是最新的,反映最
最近的用户交互类型。例如,如果拼写错误在生产输入中很常见,它们也应该出现在保留数据中。除了数值偏差测量,定期对输出进行定性评估也是有益的。定期查看模型输出(俗称“气氛检查”)确保结果符合预期,并保持与用户需求的相关性。最后,加入非确定性偏差检查也很有用——通过多次运行管道的每个输入测试数据集,分析所有输出,增加捕捉偶尔出现异常的可能性。
每天查看LLM输入和输出样本
LLM是动态且不断发展的。尽管其强大的零样本能力和通常令人愉悦的输出,其失败模式可能极为不可预测。对于定制任务,定期查看数据样本对发展直觉至关重要。
来自生产的输入-输出对是LLM应用的“实事实地”(genchi genbutsu),无法替代。最近的研究强调,开发者对“好”与“坏”输出的感知会随着他们处理更多数据而变化(即标准漂移)。虽然开发者可以事先提出一些标准来评估LLM输出,但这些预定义标准通常是不完整的。例如,在开发过程中,我们可能会更新提示,以增加良好响应的概率并减少不良响应的概率。这一迭代评估、再评估和标准更新的过程是必要的,因为在没有直接观察输出的情况下,很难预测LLM行为或人类偏好。
为有效管理这一点,我们应该记录LLM的输入和输出。通过每天查看这些日志的样本,我们可以快速识别和适应新模式或失败模式。当发现新问题时,我们可以立即编写断言或评估来处理它。同样,对失败模式定义的任何更新应反映在评估标准中。这些“气氛检查”是坏输出的信号;代码和断言将其操作化。最后,这一态度必须在团队中推广,例如将输入和输出的审查或注释添加到值班轮换中。
使用模型
通过LLM API,我们可以依赖少数提供者的智能。虽然这是一个优势,但这些依赖关系也涉及性能、延迟、吞吐量和成本的权衡。此外,随着越来越多的新型号出现(过去一年中几乎每月都有新型号发布),我们应该准备更新产品,因为旧型号将被弃用并迁移到新型号。在本节中,我们分享了一些与我们无法完全控制的技术合作的经验,这些模型无法自托管和管理。
生成结构化输出以简化下游集成
对于大多数实际用例,LLM的输出将通过某种机器可读格式被下游应用程序消耗。例如,ReChat,一个房地产CRM,需要结构化响应以便前端呈现小部件。类似地,Boba,一个生成产品战略想法的工具,需要结构化输出,包括标题、摘要、可行性评分和时间范围。最后,LinkedIn分享了如何限制LLM生成YAML,用于决定使用哪种技能,以及提供调用技能的参数。
这种应用模式是Postel法则的极端版本:在你接受的内容(任意自然语言)上自由,而在你发送的内容(类型化、机器可读的对象)上保守。因此,我们期望它是非常持久的。
目前,Instructor和Outlines是从LLM生成结构化输出的事实标准。如果你使用的是LLM API(如Anthropic,OpenAI),请使用Instructor;如果你使用的是自托管模型(如Huggingface),请使用Outlines。
在模型之间迁移提示是件麻烦事
有时,我们精心设计的提示在一个模型上效果很好,但在另一个模型上表现不佳。这可能发生在我们在不同模型提供者之间切换时,也可能发生在我们升级同一模型的不同版本时。
例如,Voiceflow发现从gpt-3.5-turbo-0301迁移到gpt-3.5-turbo-1106导致其意图分类任务下降了10%(谢天谢地,他们有评估!)。同样,GoDaddy观察到一个积极的趋势,升级到版本1106缩小了gpt-3.5-turbo和gpt-4之间的性能差距。(或者,如果你是个乐观主义者,你可能会失望地发现gpt-4的领先优势减少了)
因此,如果我们必须在模型之间迁移提示,预计需要的时间不仅仅是更改API端点。不要假设插入相同提示会产生类似或更好的结果。此外,拥有可靠、自动化的评估有助于在迁移前后衡量任务性能,减少手动验证的工作量。
版本和固定你的模型
在任何机器学习管道中,“任何变化都会改变一切”。这尤其适用于依赖我们自己不训练的组件如大型语言模型(LLM),它们可能会在我们不知情的情况下发生变化。
幸运的是,许多模型提供者提供了“固定”特定模型版本的选项(如gpt-4-turbo-1106)。这使我们可以使用特定版本的模型权重,确保其不变。在生产中固定模型版本可以避免模型行为的意外变化,这可能导致客户投诉新出现的问题,如过于冗长的输出或其他不可预见的失败模式。
此外,考虑维护一个镜像生产设置的影子管道,但使用最新的模型版本。这允许安全地进行新版本的实验和测试。一旦验证了这些新版本输出的稳定性和质量,可以自信地更新生产环境中的模型版本。
选择最小的能完成任务的模型
在进行新应用开发时,很容易使用最大的、最强大的模型。但一旦确定任务在技术上可行,值得实验是否较小的模型可以取得相似的结果。
较小模型的好处是较低的延迟和成本。虽然它可能较弱,但链式思维、n-shot提示和上下文学习等技术可以帮助较小模型表现得超乎其预期。除了LLM API,针对具体任务的微调也有助于提高性能。
总体而言,使用较小模型精心设计的工作流往往可以匹配甚至超越单一大模型的输出质量,同时更快且更便宜。例如,这条推文分享了Haiku+10-shot提示优于零样本Opus和GPT-4的轶事。在长期来看,我们预计会看到更多使用较小模型的流工程实例,以达到输出质量、延迟和成本的最佳平衡。
再比如,谦逊的分类任务。像DistilBERT(67M参数)这样的轻量级模型是一个惊人的强大基线。400M参数的DistilBART是另一个不错的选择——微调开源数据后,它能够以0.84的ROC-AUC检测幻觉,超过大多数LLM,且延迟和成本不到5%。
重点是,不要忽视较小的模型。虽然可以为每个问题使用一个庞大的模型,但通过一些创造性和实验,我们通常可以找到更高效的解决方案。
产品
虽然新技术带来了新的可能性,但构建优秀产品的原则是永恒的。因此,即使我们在解决新问题时,我们也不必在产品设计上重新发明轮子。基于坚实的产品基本原则进行LLM应用开发,可以为我们服务的人带来实际价值。
早期和频繁地参与设计
拥有设计师将推动你深入了解和思考如何构建和展示你的产品给用户。我们有时将设计师刻板印象为将事物变得美丽的人。但除了用户界面,他们还重新思考如何改进用户体验,即使这意味着打破现有规则和范式。
设计师特别擅长将用户需求重新表述为各种形式。其中一些形式更容易解决,因此可能提供更多或更少的AI解决方案机会。像许多其他产品一样,构建AI产品应
围绕要完成的工作,而不是驱动它们的技术。
重点是问自己:“用户要求这个产品为他们完成什么工作?这项工作适合聊天机器人吗?自动完成呢?也许是其他东西!”考虑现有的设计模式以及它们如何与待完成的工作相关。这些是设计师为你的团队带来的宝贵资产。
设计你的UX以实现人类在环
获取高质量注释的一种方法是将人类在环(HITL)集成到用户体验(UX)中。通过允许用户轻松提供反馈和更正,我们可以改善即时输出并收集宝贵数据以改进我们的模型。
想象一个电子商务平台,用户上传和分类他们的产品。有几种方法可以设计UX:
用户手动选择正确的产品类别;LLM定期检查新产品,并在后台更正分类错误。
用户不选择任何类别;LLM在后台定期分类产品(可能有错误)。
LLM实时建议产品类别,用户可以验证和更新。
虽然这三种方法都涉及LLM,但它们提供非常不同的UX。第一种方法将初始负担放在用户身上,让LLM作为后处理检查。第二种方法对用户没有任何努力,但不透明且无控制。第三种方法达到了平衡。通过让LLM提前建议类别,我们减少了用户的认知负担,他们不必学习我们的分类法来分类他们的产品!同时,通过允许用户审查和编辑建议,用户对如何分类他们的产品拥有最终决定权,控制权牢牢在他们手中。作为奖励,第三种方法为模型改进创建了一个自然的反馈循环。好的建议被接受(正面标签),不好的建议被更新(负面然后正面标签)。
这种建议、用户验证和数据收集的模式在几个应用中常见:
编码助手:用户可以接受建议(强烈肯定),接受并调整建议(肯定)或忽略建议(否定)
Midjourney:用户可以选择放大和下载图像(强烈肯定),变异图像(肯定)或生成一组新图像(否定)
聊天机器人:用户可以对响应提供点赞(肯定)或点踩(否定),或者选择重新生成响应(如果真的很糟糕)。
反馈可以是显式的或隐式的。显式反馈是用户在产品请求下提供的信息;隐式反馈是我们从用户交互中学到的信息,无需用户故意提供反馈。如果设计良好,如编码助手和Midjourney,我们可以收集大量隐式反馈来改进我们的产品和模型。
无情地优先考虑需求层次
在考虑将演示投入生产时,我们必须考虑的需求包括:
可靠性:99.9%的正常运行时间,结构化输出的遵守
无害性:不生成冒犯性、NSFW或其他有害内容
事实一致性:忠实于提供的上下文,不编造
有用性:与用户需求和请求相关
可扩展性:延迟SLA,支持的吞吐量
成本:因为我们没有无限预算
以及更多:安全性、隐私、公平性、GDPR、DMA等
如果我们尝试一次解决所有这些需求,将永远无法发布任何东西。因此,我们需要优先考虑。无情地。这意味着明确哪些是不可协商的(如可靠性、无害性),否则我们的产品无法运作或不可行。找到最少的可爱产品是关键。我们必须接受第一个版本不会完美,只是发布和迭代。
根据用例校准风险容忍度
在决定语言模型和应用程序的审查级别时,考虑用例和受众。对于提供医疗或财务建议的客户面对面聊天机器人,我们需要非常高的安全性和准确性标准。错误或不良输出可能造成实际伤害,破坏信任。但对于不太关键的应用,如推荐系统,或内部应用如内容分类或摘要,过于严格的要求只会减缓进展,而不会增加太多价值。
这与最近a16z报告显示的许多公司在内部LLM应用上比外部应用进展更快是一致的。通过在内部生产力中实验AI,组织可以开始捕获价值,同时在更可控的环境中学习如何管理风险。然后,随着信心的增加,他们可以扩展到客户面对面的用例。
团队与角色
没有一个工作功能是容易定义的,但在这个新领域中编写工作描述比其他更具挑战性。我们将避免使用重叠职位图或工作描述建议。但我们将承认一个新角色——AI工程师——的存在,并讨论其位置。重要的是,我们将讨论团队的其余部分以及如何分配职责。
关注过程,而不是工具
当面对新范式,如LLM时,软件工程师倾向于偏爱工具。结果,我们忽略了工具应该解决的问题和过程。在此过程中,许多工程师承担了意外复杂性,这对团队的长期生产力产生了负面影响。
例如,这篇文章讨论了某些工具如何自动创建大型语言模型的提示。它认为(正确地IMHO)工程师在不了解问题解决方法或过程的情况下使用这些工具,最终承担了不必要的技术债务。
除了意外复杂性,工具通常是未指定的。例如,LLM评估工具行业正在增长,提供“LLM评估一站式服务”,具有毒性、简洁、语气等通用评估器。我们看到许多团队在没有批判性思考其领域的具体失败模式的情况下采用这些工具。与此相比,EvalGen关注教用户通过深度参与每个步骤创建领域特定评估,从指定标准,到标注数据,再到检查评估。软件引导用户完成如下工作流:
EvalGen引导用户通过最佳实践进行LLM评估,即:
定义领域特定测试(自动从提示引导)。这些定义为代码中的断言或LLM-as-Judge。
强调测试与人类判断对齐的重要性,确保测试捕捉到指定的标准。
随着系统(提示等)变化迭代你的测试。
EvalGen为开发人员提供了评估构建过程的心智模型,而不是将他们锚定到特定工具。我们发现,在为AI工程师提供这一背景后,他们经常选择更精简的工具或自己构建。
LLM的组件超出提示编写和评估太多,不可能在这里详尽列出。然而,重要的是AI工程师在采用工具之前理解过程。
不断实验
机器学习产品与实验密切相关。不仅仅是A/B、随机对照试验,还有频繁尝试修改系统最小组件,并进行离线评估。大家对评估的热情不仅仅是关于信任和信心——是关于启用实验!你的评估越好,你在实验上的迭代就越快,因此你在系统最佳版本上的收敛速度就越快。
现在尝试不同方法解决同一问题很常见,因为实验成本非常低。收集数据和训练模型的高成本被最小化了——提示工程几乎只需要人力时间。将你的团队定位为每个人都学习提示工程的基础知识。这样鼓励每个人实验,带来来自组织各处的多样化想法。
此外,不仅仅是探索实验——还要利用实验!有了新任务的工作版本?考虑让团队中的其他人用不同的方法处理。尝试以更快的方式进行。研究链式思维或少数提示等提示技术,使其质量更高。不要让你的工具限制你的实验;如果限制了,重建它,或购买更好的。
最后,在产品/项目规划中,为构建评估和运行多个实验留出时间。将工程产品的产品规范,但添加明确的评估标准。在制定路线图时,不要低估实验所需的时间——预计在获得生产绿灯之前进行多次开发和评估迭代。
赋能所有人使用新AI技术
随着生成式AI的采用增加,我们希望整个团队——不仅仅是专家——了解并感到能够使用这一新技术。没有比使用它更好的方法来发展对LLM工作方式(如延迟、失败模式、用户体验)的直觉了。LLM相对易访问:你不需要知道如何编码就可以提高管道的性能,每个人都可以通过提示工程和评估开始贡献。
教育是这一点的重要组成部分。可以从提示工程的基础知识开始,n-shot提示和链式思维等技术有助于将模型条件化为期望的输出。拥有知识的人还可以教育更技术方面,如LLM是自回归的。换句话说,虽然输入标记是并行处理的,但输出标记是顺序生成的。因此,延迟更多取决于输出长度而不是输入长度——这是设计用户体验和设定性能期望时的关键考虑因素。
我们还可以进一步提供动手实验和探索的机会。也许是黑客松?虽然让整个团队花几天时间在投机项目上进行黑客攻击似乎很昂贵,但结果可能会让你惊讶。我们知道有一个团队,通过黑客松,在一年内加
速并几乎完成了他们的三年路线图。另一个团队的黑客松带来了生成式AI使之成为可能的范式转变用户体验,现在已被优先考虑并用于未来。
不要陷入“AI工程就是我所需要的”陷阱
随着新职位头衔的出现,最初倾向于夸大与这些角色相关的能力。这通常导致随着工作实际范围变得清晰而进行的痛苦纠正。进入这一领域的新手和招聘经理可能会做出夸大其词或期望过高的声明。过去十年中的一些显著例子包括:
数据科学家:“比任何软件工程师都擅长统计,比任何统计学家都擅长软件工程的人。”
机器学习工程师(MLE):以软件工程为中心的机器学习视角
最初,许多人认为仅数据科学家就足以完成数据驱动的项目。然而,很明显,数据科学家必须与软件和数据工程师合作,才能有效地开发和部署数据产品。
这一误解再次出现在新角色AI工程师中,有些团队认为AI工程师就是你所需要的一切。事实上,构建机器学习或AI产品需要广泛的专业角色。我们与十几家公司就AI产品进行了咨询,始终观察到他们陷入“AI工程就是你所需要的一切”的陷阱。结果,产品往往难以超越演示,因为公司忽视了构建产品涉及的关键方面。
例如,评估和测量对于将产品扩展到超越气氛检查至关重要。有效评估所需的技能与传统上在机器学习工程师中看到的一些优势一致——一个仅由AI工程师组成的团队可能缺乏这些技能。合著者Hamel Husain在他最近关于检测数据漂移和设计领域特定评估的工作中说明了这些技能的重要性。
以下是构建AI产品的过程中你需要的角色类型及其时间的大致进展:
首先,专注于构建产品。这可能包括AI工程师,但不一定。AI工程师在原型和快速迭代产品(用户体验、管道等)方面非常有价值。
接下来,创建正确的基础,通过记录你的系统并收集数据。根据数据的类型和规模,你可能需要平台和/或数据工程师。还必须有用于查询和分析这些数据以调试问题的系统。
接下来,你最终希望优化你的AI系统。这不一定涉及训练模型。基本步骤包括设计指标、构建评估系统、运行实验、优化RAG检索、调试随机系统等。机器学习工程师在这些方面表现出色(尽管AI工程师也可以学会)。除非完成了前置步骤,否则通常不建议雇佣机器学习工程师。
除此之外,你始终需要一个领域专家。在小公司,这通常是创始团队——在大公司,产品经理可以扮演这一角色。了解角色的进展和时间安排至关重要。在错误的时间雇佣人员(如过早雇佣机器学习工程师)或以错误顺序构建是浪费时间和金钱,并导致人员流失。此外,在第1-2阶段定期与机器学习工程师(但不是全职雇佣)进行检查将帮助公司建立正确的基础。