LLM 应用性能优化:三角原则指南

2024年07月25日 由 alex 发表 262 0

大型语言模型(LLM)拥有巨大的潜力,但开发可靠的生产级应用仍然充满挑战。在构建了数十个 LLM 系统后,我将成功的公式提炼为 3+1 基本原则,任何团队都可以应用。


“LLM-Native应用10%是复杂的模型,90%是实验数据驱动的工程工作"。


构建生产就绪的 LLM 应用程序需要谨慎的工程实践。当用户无法与 LLM 直接交互时,提示必须精心编写,以涵盖所有细微差别,因为可能无法获得迭代用户反馈。


介绍 LLM 三角原则

LLM 三角原则囊括了构建有效 LLM 原生应用程序的基本准则。它们提供了一个坚实的概念框架,指导开发人员构建稳健可靠的 LLM 本机应用程序,并提供指导和支持。


31


关键应用

LLM 三角原则介绍了四项编程原则,可帮助你·设计和构建 LLM 本地应用程序。


第一条原则是标准操作程序(SOP)。SOP 指导我们三角形的三个尖: 模型、工程技术和上下文数据。


通过 SOP 的视角优化三个尖原则是确保高性能 LLM 原生应用程序的关键。


1. 标准操作程序 (SOP)

标准操作程序(SOP)是工业领域的一个著名术语。它是大型组织编制的一套按步骤进行的说明,用于帮助工人执行例行操作,同时保持每次操作的高质量和相似结果。这实际上是通过编写详细的作业指导书,将缺乏经验或低技能的工人变成专家。


LLM 三角原则借鉴了 SOP 的范式,并鼓励大家将其视为无经验/无技术工人的模式。我们可以通过 “教导 ”模型专家如何完成这项任务来确保获得更高质量的结果。


32


“没有 SOP,即使是最强大的 LLM 也无法持续提供高质量的结果"。


在思考 SOP 指导原则时,我们应该明确哪些技术可以帮助我们最有效地实施 SOP。


认知建模

要创建 SOP,我们需要把表现最好的员工(领域专家)找出来,模拟他们是如何思考和工作以实现相同结果的,并写下他们所做的一切。


经过编辑和正规化后,我们就能获得详细的指导,帮助每一位缺乏经验或技能不高的员工取得成功,完成出色的工作。


就像人类一样,通过简化或拆分任务来减轻认知负担是至关重要的。与冗长复杂的程序相比,按部就班地执行简单的指令更直截了当。


在这个过程中,我们会发现隐藏的内隐认知 “跳跃”--专家们无意识采取的小步骤,对结果产生了重大影响。这些微妙的、无意识的、通常不为人知的假设或决定会对最终结果产生重大影响。


33


例如,假设我们想为 SQL 分析师建模。我们首先要对他们进行访谈,问他们几个问题,例如:


  • 当你被要求分析一个业务问题时,你会怎么做?
  • 如何确保你的解决方案满足要求?
  • <向受访者反映我们所了解的流程>。
  • 这是否准确地反映了你的流程?<获取更正>
  • 等等。


34


内隐认知过程有多种形态和形式,一个典型的例子就是 “特定领域定义”。例如,“畅销书 ”对我们的领域专家来说可能是一个突出的术语,但对其他人来说却不是。


35


最终,我们将拥有一份完整的 SOP “食谱”,让我们能够效仿表现出色的分析师。


在绘制这些复杂流程时,将其可视化为图表会很有帮助。当流程细致入微,涉及许多步骤、条件和分割时,这一点尤其有用。


36


我们的最终解决方案应模仿 SOP 中定义的步骤。在这一阶段,请尽量忽略实施--稍后,你可以在整个解决方案的一个或多个步骤/链中实施。


与其他原则不同,认知建模(编写 SOP)是唯一独立的流程。强烈建议你在编写代码前对流程进行建模。尽管如此,在实施过程中,你可能会根据获得的新见解或理解回头修改它。


既然我们已经了解了创建一个定义明确的 SOP 的重要性,它可以指导我们对问题的业务理解,那么让我们来探讨一下如何利用各种工程技术有效地实施它。


工程技术

工程技术可以帮助你切实执行 SOP,并从模型中获得最大收益。在思考工程技术原则时,我们应该考虑我们工具箱中的哪些工具(技术)可以帮助我们实施和塑造我们的 SOP,并协助模型与我们进行良好的沟通。


37


有些工程技术只在提示层中实施,而许多技术需要软件层才能有效实施,有些技术则将这两层结合在一起。


38


虽然每天都会发现许多细微差别和技术,但我将介绍两种主要技术:工作流/链和代理。


LLM 本地架构(又称流程工程或链)

LLM-Native 架构描述了你的应用程序为获得任务结果所经历的代理流程。


流程中的每一步都是实现任务所必须经历的独立过程。有些步骤只需确定性代码即可完成;有些步骤则需要使用 LLM(代理)。


为此,我们可以反思我们绘制的标准作业程序 (SOP),并思考:

  1. 我们应该将哪些 SOP 步骤粘合到同一个代理中?哪些步骤应该拆分为不同的代理?
  2. 哪些 SOP 步骤应该以独立的方式执行(但可能会从之前的步骤中获取信息)?
  3. 哪些 SOP 步骤可以在确定性代码中执行?
  4. 等等。


39


在进入架构/图表中的下一步之前,我们应该定义其关键属性:

  • 输入和输出 - 这一步的特征是什么?在我们采取行动之前需要什么?(这也可以作为代理的输出格式)
  • 质量保证--怎样的响应才算 “足够好”?循环中是否存在需要人工干预的情况?我们可以配置哪些类型的断言?
  • 自主级别--我们需要对结果的质量进行多大程度的控制?这一阶段可以处理哪些范围的用例?换句话说,在这一点上,我们对模型独立工作的信任度有多高?
  • 触发器 - 下一步是什么?是什么定义了下一步?
  • 非功能性 - 所需的延迟时间是多少?我们是否需要特别的业务监控?
  • 故障转移控制 - 可能发生哪种故障(系统故障和代理故障)?我们的后备措施是什么?
  • 状态管理 - 我们是否需要特殊的状态管理机制?如何检索/保存状态(定义索引键)?我们需要持久存储吗?该状态有哪些不同用途(如缓存、日志等)?
  • 等等。


什么是代理?

LLM 代理是 LLM-Native 架构中涉及调用 LLM 的独立组件。


这是一个使用 LLM 的实例,提示包含上下文。并非所有代理都是一样的--有些代理会使用 “工具”,有些则不会;有些代理可能在流程中 “只使用一次”,而有些则可以递归或多次调用,并携带之前的输入和输出。


使用工具的代理

一些 LLM 代理可以使用 “工具”--用于计算或网络搜索等任务的预定义函数。代理输出指定工具和输入的指令,应用程序执行这些指令,并将结果返回给代理。


为了理解这一概念,让我们来看一个简单的工具调用提示实现。即使模型没有经过调用工具的原生训练,也可以使用这种方法:


You are an assistant with access to these tools:
- calculate(expression: str) -> str - calculate a mathematical expression
- search(query: str) -> str - search for an item in the inventory
Given an input, Respond with a YAML with keys: `func`(str) and `arguments`(map) or `message`(str).Given input


重要的是要区分拥有工具的代理(因此是自主代理)和输出结果可导致执行行动的代理。


“自主代理是指有能力产生完成任务的方法的代理"。


自主代理有权决定是否采取行动以及采取何种行动。相比之下,(非自主)代理只需 “处理 ”我们的请求(如分类),根据这一处理过程,我们的确定性代码就会执行一项行动,而模型对此的控制权为零。


40


当我们提高代理在计划和执行任务方面的自主性时,我们增强了代理的决策能力,但却有可能降低对输出质量的控制。虽然这看起来是一个神奇的解决方案,能让代理变得更 “聪明 ”或更 “先进”,但代价却是失去对质量的控制。


41


小心完全自主代理的诱惑。虽然它们的架构可能看起来更吸引人、更简单,但将其用于所有情况(或作为初始 PoC)可能会对 “真正的生产 ”情况造成很大的欺骗。自主代理难以调试且不可预测(响应质量不稳定),因此无法用于生产。


目前,代理(在没有隐式指导的情况下)并不擅长规划复杂的流程,通常会跳过必要的步骤。例如,在我们的 “维基百科作家 ”用例中,他们会直接开始写作,跳过系统化流程。这就使得代理(尤其是自主代理)只能和模型一样好,或者更准确地说--只能和它们在与你的任务相关的数据上接受的训练一样好。


与其让代理(或代理群)自由地完成端到端的所有任务,不如尝试将他们的任务对冲到流程/SOP 中需要这种灵活性或创造性的特定区域。这样可以获得更高质量的结果,因为你可以同时享受两个世界。


AlphaCodium 就是一个很好的例子: 通过将结构化流程与不同的代理(包括迭代编写和测试代码的新型代理)相结合,他们将 CodeContests 的 GPT-4 准确率(pass@5)从 19% 提高到了 44%。


42


工程技术为实现我们的 SOP 和优化 LLM 本地应用程序奠定了基础,但我们还必须仔细考虑 LLM 三角形的另一个关键组成部分:模型本身。


模型

我们选择的模型是项目成功与否的关键因素--大型模型(如 GPT-4 或 Claude Opus)可能会产生更好的结果,但在规模化时成本相当高;而小型模型可能不那么 “聪明”,但有助于节省预算。在考虑模型原则时,我们应该确定我们的限制和目标,以及什么样的模型可以帮助我们实现这些限制和目标。


43


“并非所有的法律硕士都是一样的。让模型与任务相匹配"。


事实上,我们并不总是需要最大的模型;这取决于任务。为了找到正确的匹配,我们必须有一个实验过程,并尝试我们解决方案的多种变化。


看看我们的 “缺乏经验的工人 ”类比就会有所帮助--一个非常 “聪明 ”的工人,拥有许多学历证书,可能会在某些任务中轻而易举地取得成功。不过,他们也可能无法胜任这份工作,而雇佣一个 “更便宜 ”的候选人会更划算。


在考虑一种模式时,我们应该根据我们愿意做出的取舍来定义和比较解决方案:

  • 任务复杂性 - 较简单的任务(如总结)使用较小的模型更容易完成,而推理通常需要较大的模型。
  • 推理基础设施 - 应该在云端还是边缘设备上运行?模型的大小可能会对小型手机造成影响,但对于云服务来说是可以承受的。
  • 定价--我们能承受的价格是多少?考虑到业务影响和预估使用量,它是否具有成本效益?
  • 延迟 - 随着模型的增大,延迟也会随之增加。
  • 标记数据 - 我们是否拥有可以立即使用的数据,以丰富模型的示例或相关信息?


微调模型

在对模型进行微调之前,你必须考虑以下几个方面:


  • 隐私--你的数据中可能包含一些必须在模型中保留的私人信息。如果数据中包含私人信息,你必须对数据进行匿名化处理,以避免承担法律责任。
  • 法律、合规性和数据权利 - 在训练模型时可能会遇到一些法律问题。例如,OpenAI 使用条款政策禁止你在未使用 OpenAI 生成的响应的情况下训练模型。另一个典型的例子是遵守 GDPR 法律,其中要求 “撤销权”,即用户可以要求公司从系统中删除信息。这就提出了是否应重新训练模型的法律问题。
  • 更新延迟--训练模型时的延迟或数据截止时间要高得多。与通过上下文嵌入新信息(见下文 “4.上下文数据 ”部分)提供即时延迟不同,训练模型是一个漫长的过程,需要时间。因此,模型的再训练频率较低。
  • 开发和运行 - 在持续评估结果性能的同时,实施可重复、可扩展和可监控的微调管道至关重要。这一复杂过程需要持续维护。
  • 成本--由于其复杂性和每次训练所需的高强度资源(GPU),重新训练被认为是昂贵的。


LLM 能够作为上下文学习器,而且最新模型支持更大的上下文窗口,这大大简化了我们的实现过程,即使不进行微调也能提供出色的结果。由于微调的复杂性,我们建议将微调作为最后的手段或完全跳过微调。


相反,针对特定任务(如结构化 JSON 输出)或特定领域语言对模型进行微调可能会非常高效。与大型 LLM 相比,针对特定任务的小型模型可以非常有效,而且推理成本更低。明智地选择解决方案,并在升级到 LLM 训练之前评估所有相关考虑因素。


情境数据

LLM 是一种情境学习器。这意味着,通过提供特定任务的信息,LLM 代理可以帮助我们完成任务,而无需专门的培训或微调。这使我们能够轻松地 “传授 ”新知识或技能。在考虑 “情境数据 ”原则时,我们应着眼于对可用数据进行组织和建模,以及如何在我们的提示中对其进行组合。


44


为了编写上下文,我们会在发送给 LLM 的提示中包含相关(上下文)信息。我们可以使用两种语境:


  • 嵌入式上下文--作为提示信息的一部分提供的嵌入式信息片段。


You are the helpful assistant of <name>, a <role> at <company>


  • 附件上下文 - 按提示开头/结尾粘贴的信息碎片列表


Summarize the provided emails while keeping a friendly tone.
---
<email_0>
<email_1>


上下文通常使用 “提示模板”(如 jinja2 或 mustache 或简单的本地格式化字面字符串)来实现;这样,我们就能在保持提示本质的同时优雅地编写它们:


# Embedded context with an attachment context
prompt = f"""
You are the helpful assistant of {name}. {name} is a {role} at {company}.
Help me write a {tone} response to the attached email.
Always sign your email with:
{signature}
---
{email}
"""


少量学习

少量学习是通过实例 “教授” LLM 的一种有效方法,而不需要进行大量的微调。在提示中提供一些有代表性的例子,可以引导模型理解所需的格式、风格或任务。


例如,如果我们希望 LLM 生成电子邮件回复,我们可以在提示中包含一些写得很好的回复示例。这有助于模型学习首选的结构和语气。


我们可以使用不同的示例来帮助模型捕捉不同的角落情况或细微差别,并从中学习。因此,必须包含各种示例,以涵盖应用程序可能遇到的各种情况。


随着应用程序的发展,你可以考虑实施 “动态少量实例”(Dynamic few-shot),即通过编程为每个输入选择最相关的实例。虽然这会增加实施的复杂性,但它能确保模型在每种情况下都能获得最合适的指导,从而显著提高各种任务的性能,而无需进行昂贵的微调。


检索增强生成

检索增强生成(RAG)是一种在生成响应之前检索相关文档以获取额外上下文的技术。这就好比让 LLM 快速查看特定的参考资料,为其回答提供参考。这样,无需重新训练模型就能保持回复的时效性和真实性。


例如,在支持聊天机器人应用中,RAG 可以调取相关的帮助台维基页面,为法律硕士的回答提供信息。


这种方法可以帮助 LLM 保持与时俱进,并通过以检索到的事实为基础进行回答来减少幻觉。RAG 尤其适用于需要更新或专业知识的任务,而无需重新训练整个模型。


例如,假设我们正在为我们的产品创建一个支持聊天工具。在这种情况下,我们可以使用 RAG 从我们的帮助台维基站点检索相关文档,然后将其提供给 LLM 代理,要求它根据问题撰写答案并提供文档。


在实施 RAG 时,我们需要关注三个关键部分:

  • 检索机制 - 虽然 RAG 的传统实现方式是使用向量相似性搜索检索相关文档,但有时使用基于关键字的搜索(如 BM-25)等更简单的方法会更好或更便宜。
  • 索引数据结构 - 不进行预处理,直接索引整个文档可能会限制检索过程的有效性。有时,我们希望增加一个数据准备步骤,比如根据文档准备一个问题和答案列表。
  • 元数据--存储相关元数据可以更有效地引用和过滤信息(例如,将维基页面缩小到只与用户特定产品查询相关的页面)。这个额外的数据层简化了检索过程。


提供相关上下文

与代理相关的上下文信息可能各不相同。向模型(就像 “非熟练工人”)提供过多的信息虽然看似有益,但可能会让人不知所措,而且与任务无关。从理论上讲,这会导致模型学习不相关的信息(或标记连接),从而导致混乱和幻觉。


当 Gemini 1.5 发布并推出可处理多达 1000 万个标记的 LLM 时,一些从业者质疑上下文是否仍然是个问题。虽然这是一项了不起的成就,尤其是对于某些用例(如与 PDF 聊天)而言,但它仍然是有限的,尤其是在对各种文档进行推理时。


压缩提示并只向 LLM 代理提供相关信息至关重要。这样可以减少模型在无关令牌上投入的处理能力,提高质量,优化延迟并降低成本。


提高所提供上下文相关性的技巧有很多,其中大部分都与数据的存储和编目方式有关。

对于 RAG 应用程序来说,添加一个数据准备来塑造你存储的信息(例如,基于文档的问题和答案,然后只向 LLM 代理提供答案;这样,代理就能获得一个概括的、更短的上下文),并在检索文档的基础上使用重新排序算法来完善结果,是非常方便的。


结论

LLM 三角原则为开发高质量的 LLM 原生应用程序提供了一种结构化方法,解决了 LLM 的巨大潜力与现实世界的实施挑战之间的差距。开发人员可以通过专注于 3+1 关键原则(模型、工程技术和上下文数据),在定义明确的 SOP 指导下,创建更可靠、更有效的 LLM 驱动型解决方案。


45

文章来源:https://towardsdatascience.com/the-llm-triangle-principles-to-architect-reliable-ai-apps-d3753dd8542e
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
写评论取消
回复取消