大型语言模型(LLM) 潜力巨大,但开发可靠的生产级应用程序仍然充满挑战。在构建了数十个 LLM 系统之后,我将成功的秘诀提炼为 3+1 个基本原则,任何团队都可以应用。
“LLM-Native 应用程序 10% 是复杂的模型,90% 是实验性的数据驱动工程工作。”
构建可投入生产的LLM应用程序需要严谨的工程实践。当用户无法直接与LLM交互时,必须精心编写提示,涵盖所有细微差别,因为可能无法获得迭代的用户反馈。
介绍 LLM 三角原则
LLM 三角原则概括了构建高效 LLM 原生应用的基本准则。它们提供了坚实的概念框架,指导开发者构建稳健可靠的 LLM 原生应用,并提供指导和支持。

关键点
LLM 三角原则引入了四个编程原则来帮助您设计和构建 LLM-Native 应用程序。
第一个原则是标准操作程序(SOP)。SOP指导着我们三角形的三个顶点:模型、工程技术和上下文数据。
通过 SOP的视角优化三个顶点原则是确保高性能LLM 原生应用程序的关键 。
1.标准操作程序(SOP)
标准操作规程(SOP) 是工业界一个耳熟能详的术语。它是由大型组织编制的一套循序渐进的说明,旨在帮助员工执行常规操作,同时确保每次操作都能保持高质量且结果一致。通过编写详细的说明,SOP 实际上可以将缺乏经验或技能水平较低的员工变成专家。
LLM 三角原则借用了 SOP 范式,鼓励你将模型视为缺乏经验/不熟练的工人。我们可以通过“教”模型如何让专家执行这项任务来确保更高质量的结果。

“如果没有 SOP,即使是最强大的 LLM 也无法持续提供高质量的结果。”
在思考SOP指导原则时,我们应该确定哪些技术可以帮助我们最有效地实施 SOP。
1.1. 认知建模
为了创建 SOP,我们需要选取表现最佳的员工(领域专家),模拟他们的思维和工作方式以实现相同的结果,并记录下他们所做的一切。
经过编辑和正式化后,我们将提供详细的说明,帮助每一位缺乏经验或技能较低的工人取得成功并取得出色的工作。
就像人类一样,通过简化或拆分任务来减轻认知负荷至关重要。遵循简单的分步说明比冗长复杂的程序更直观。
在此过程中,我们会识别出隐藏的——内隐认知“跳跃”——专家们采取的细微、无意识的步骤,这些步骤会对结果产生重大影响。这些微妙、无意识、通常不言而喻的假设或决定,可能会对最终结果产生重大影响。

例如,假设我们要建模一位 SQL 分析师。我们将首先采访他们并询问他们几个问题,例如:
- 当您被要求分析业务问题时您会怎么做?
- 您如何确保您的解决方案满足要求?
- 这是否准确地捕捉了您的流程?
- ETC。

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

最终,我们将拥有完整的 SOP“方案”,使我们能够模仿表现最佳的分析师。
在规划这些复杂的流程时,将其可视化为图表会很有帮助。当流程细致入微,涉及许多步骤、条件和拆分时,这一点尤其有用。

我们的最终解决方案应该模仿 SOP 中定义的步骤。在此阶段,请尝试忽略具体实现——稍后,您可以在整个解决方案中跨一个或多个步骤/链来实现它。
与其他原则不同,认知建模(SOP 编写)是唯一独立的流程。强烈建议您在编写代码之前先对流程进行建模。也就是说,在实施过程中,您可能会根据获得的新见解或理解回过头来修改它。
现在我们了解了创建明确定义的 SOP 的重要性,它可以指导我们对问题的业务理解,让我们探索如何使用各种工程技术有效地实现它。
2.工程技术
工程技术可以帮助您切实地实施您的 SOP,并最大限度地利用模型。在思考工程技术原则时,我们应该考虑工具箱中的哪些工具(技术)可以帮助我们实施和塑造 SOP,并帮助模型与我们进行良好的沟通。

有些工程技术仅在提示层实现,而许多工程技术则需要软件层才能有效,还有一些工程技术则结合了这两层。

虽然每天都会发现许多细微的差别和技巧,但我将介绍两种主要技术:工作流/链和代理。
2.1. LLM-Native 架构(又称流程工程或链)
LLM-Native 架构描述了您的应用程序为产生任务结果所经历的代理流程。
我们流程中的每个步骤都是一个独立的过程,必须完成才能完成我们的任务。有些步骤只需使用确定性代码即可执行;而有些步骤,我们将使用 LLM(代理)。
为此,我们可以反思一下我们制定的标准操作程序(SOP)并思考:
- 哪些 SOP 步骤应该整合到同一个代理?哪些步骤应该拆分到不同的代理?
- 哪些 SOP 步骤应该以独立的方式执行(但它们可能会从前面的步骤中获取信息)?
- 我们可以在确定性代码中执行哪些 SOP 步骤?
- ETC。

在进入架构/图表的下一步之前,我们应该定义其关键属性:
- 输入和输出——这一步的签名是什么?采取行动之前需要什么?(这也可以作为代理的输出格式)
- 质量保证——如何确保响应“足够好”?是否存在需要人工干预的情况?我们可以配置哪些类型的断言?
- 自主水平——我们需要对结果的质量进行多大程度的控制?这个阶段可以处理哪些范围的用例?换句话说,在目前这个阶段,我们能多大程度上信任模型能够独立工作?
- 触发因素——下一步是什么?下一步的定义是什么?
- 非功能性——所需的延迟是多少?我们需要特殊的业务监控吗?
- 故障转移控制——可能发生哪些类型的故障(系统性故障和代理性故障)?我们的后备方案是什么?
- 状态管理——我们需要一个特殊的状态管理机制吗?如何检索/保存状态(定义索引键)?我们需要持久化存储吗?状态有哪些不同的用途(例如,缓存、日志记录等)?
- ETC。
2.2. 什么是代理?
LLM 代理是涉及调用 LLM 的 LLM-Native 架构的独立组件。
这是 LLM 用法的一个实例,其提示符包含上下文。并非所有代理都相同——有些代理会使用“工具”,有些则不会;有些代理可能在流程中“只使用一次”,而有些代理则可以递归调用或多次调用,并携带先前的输入和输出。
2.2.1. 带有工具的代理
一些 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
区分具有工具的代理(因此称为自主代理)和其输出可以导致执行动作的代理非常重要。
“自主代理是有能力生成完成任务的方法的代理。”
自主代理有权决定是否应该采取行动以及采取何种行动。相比之下,(非自主)代理只是简单地“处理”我们的请求(例如分类),并基于此过程,我们的确定性代码执行相应的操作,而模型对此没有任何控制权。

随着我们提升智能体在规划和执行任务方面的自主性,其决策能力也随之增强,但同时也可能削弱其对输出质量的控制。虽然这看起来像是一个让智能体更加“智能”或“先进”的神奇解决方案,但它的代价是失去对质量的控制。

警惕完全自主代理的诱惑。虽然它们的架构可能看起来很吸引人且更简单,但将其用于所有用途(或作为初始概念验证)可能会与“实际生产”案例存在很大偏差。自主代理难以调试且不可预测(响应质量不稳定),这使得它们无法用于生产。
目前,缺乏隐式指导的代理在规划复杂流程方面表现不佳,通常会跳过必要的步骤。例如,在我们的“维基百科编写器”用例中,它们会直接开始写作,跳过系统性流程。这使得代理(尤其是自主代理)的性能仅取决于模型,或者更准确地说,仅取决于它们根据你的任务进行训练时所用的数据。
不要让代理(或一群代理)自由地完成所有端到端的工作,而是尝试将他们的任务限制在流程/SOP中需要这种敏捷性或创造力的特定区域。这样可以产生更高质量的结果,因为您可以同时享受两者。
一个很好的例子是AlphaCodium:通过将结构化流程与不同的代理(包括一个迭代编写和测试代码的新型代理)相结合,他们将 CodeContests 上的 GPT-4 准确率(pass@5)从 19% 提高到了 44%。

虽然工程技术为实现我们的 SOP 和优化 LLM 原生应用程序奠定了基础,但我们还必须仔细考虑 LLM 三角的另一个关键组成部分:模型本身。
3.模型
我们选择的模型是项目成功的关键因素——大型模型(例如 GPT-4 或 Claude Opus)可能会产生更好的结果,但规模化成本相当高昂;而小型模型可能不那么“智能”,但有助于节省预算。在思考模型原则时,我们应该明确我们的约束条件和目标,以及哪种模型能够帮助我们实现这些目标。

并非所有LLM课程都生而平等。要根据课程目标选择合适的学习模式。
事实上,我们并不总是需要最大的模型;这取决于任务。为了找到合适的匹配,我们必须有一个实验过程,并尝试解决方案的多种变体。
不妨看看我们之前提到的“缺乏经验的员工”这个类比——一个非常“聪明”、拥有丰富学术背景的员工,很可能轻松完成某些任务。然而,他们可能资历过高,而雇佣一个“更便宜”的候选人会更划算。
在考虑模型时,我们应该根据我们愿意采取的权衡来定义和比较解决方案:
- 任务复杂性——简单的任务(例如总结)更容易用较小的模型完成,而推理通常需要更大的模型。
- 推理基础设施——它应该在云端还是边缘设备上运行?模型大小可能会对小型手机造成影响,但对于云服务来说,这是可以接受的。
- 定价——我们可以接受什么价格?考虑到业务影响和预期用途,这个价格是否划算?
- 延迟——随着模型变大,延迟也会增加。
- 标记数据——我们是否有可以立即使用的数据来丰富模型,其中包含未经训练的示例或相关信息?
在许多情况下,除非你拥有“内部专业知识”,否则为经验丰富的员工支付一点额外费用是有帮助的——这同样适用于LLM。
如果您没有标记数据,请从更强大(更大)的模型开始,收集数据,然后利用它来通过少量或微调来增强模型。
3.1. 微调模型
在对模型进行微调之前,必须考虑以下几个方面:
- 隐私——您的数据可能包含一些必须对模型保密的私人信息。您必须对数据进行匿名化处理,以避免在数据包含私人信息时承担法律责任。
- 法律、合规性和数据权利——在训练模型时可能会引发一些法律问题。例如,OpenAI 的使用条款政策禁止您在没有 OpenAI 的情况下使用生成的响应来训练模型。另一个典型示例是遵守 GDPR 的法律,该法律要求“撤销权”,即用户可以要求公司从系统中删除信息。这引发了关于是否应该重新训练模型的法律问题。
- 更新延迟 –训练模型时,延迟或数据截断会高得多。与通过上下文嵌入新信息(参见下文“4. 上下文数据”部分)提供即时延迟不同,训练模型是一个耗时的漫长过程。因此,模型重新训练的次数较少。
- 开发和运营——在持续评估结果性能的同时,实施可重复、可扩展且可监控的微调流程至关重要。这个复杂的过程需要持续的维护。
- 成本——由于再训练的复杂性以及每次训练所需的高度密集的资源(GPU),因此被认为是昂贵的。
LLM 能够充当上下文学习器,而且新模型支持更大的上下文窗口,这极大地简化了我们的实现,即使无需微调也能提供出色的结果。由于微调的复杂性,建议将其作为最后的手段,或者完全跳过它。
相反,针对特定任务(例如结构化 JSON 输出)或领域特定语言进行微调的模型可以非常高效。小型、特定任务的模型可以非常高效,并且推理成本比大型 LLM 低得多。请明智地选择你的解决方案,并在升级到 LLM 训练之前评估所有相关因素。
“即使最强大的模型也需要相关且结构良好的上下文数据才能发挥作用。”
4. 上下文数据
LLM 是情境学习器。这意味着,通过提供特定于任务的信息,LLM 代理可以帮助我们执行任务,而无需特殊训练或微调。这使我们能够轻松地“教授”新知识或技能。在思考情境数据原则时,我们应该致力于组织和建模可用数据,以及如何在我们的提示中编写它们。

为了编写上下文,我们会在发送给 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}
"""
4.1. 小样本学习
少样本学习是一种有效的方法,可以通过示例“教授”LLM,而无需进行大量的微调。在提示中提供一些有代表性的示例可以引导模型理解所需的格式、风格或任务。
例如,如果我们希望(LLM 生成电子邮件回复,我们可以在提示中包含一些写得好的回复示例。这有助于模型学习到合适的结构和语气。
我们可以使用多样化的示例来帮助模型捕捉不同的极端情况或细微差别,并从中学习。因此,包含各种示例至关重要,这些示例要涵盖应用程序可能遇到的各种场景。
随着应用程序的发展,您可以考虑实现“动态小样本”,即以编程方式为每个输入选择最相关的样本。虽然这会增加实现的复杂性,但它可以确保模型针对每种情况获得最合适的指导,从而显著提升各种任务的性能,而无需进行成本高昂的微调。
4.2. 检索增强生成
检索增强生成 (RAG)是一种在生成回复之前检索相关文档以获取更多上下文的技术。这就像让LLM 快速浏览特定的参考资料,以帮助其提供答案。这可以使回复保持最新且符合事实,而无需重新训练模型。
例如,在支持聊天机器人应用程序上,RAG 可以提取相关的帮助台 wiki 页面来告知 LLM 的答案。
这种方法通过将响应建立在检索到的事实之上,帮助 LLM保持与时俱进,并减少幻觉。RAG 对于需要更新或专业知识且无需重新训练整个模型的任务尤其有用。
例如,假设我们正在为我们的产品构建一个支持聊天系统。在这种情况下,我们可以使用 RAG 从我们的帮助台 wiki 中检索相关文档,然后将其提供给 LLM 代理,并要求其根据问题撰写答案并提供文档。
实施 RAG 时需要考虑三个关键部分:
- 检索机制——虽然 RAG 的传统实现涉及使用向量相似性搜索来检索相关文档,但有时使用更简单的方法(例如基于关键字的搜索(如BM-25))会更好或更便宜。
- 索引数据结构——未经预处理就直接索引整个文档可能会限制检索过程的效率。有时,我们希望添加数据准备步骤,例如根据文档准备问题和答案列表。
- 元数据——存储相关的元数据可以更有效地引用和过滤信息(例如,将wiki页面范围缩小到仅与用户特定产品查询相关的页面)。这一额外的数据层简化了检索过程。
4.3. 提供相关背景信息
与你的代理相关的上下文信息可能会有所不同。虽然这看起来可能有益,但向模型(例如“非熟练工人”)提供过多的信息可能会使其不堪重负,并且与任务无关。理论上,这会导致模型学习不相关的信息(或标记连接),从而导致混乱和幻觉。
当 Gemini 1.5 发布并作为可处理高达 10M 个 token 的 LLM 引入时,一些从业者质疑上下文是否仍然是一个问题。虽然这是一个了不起的成就,尤其是对于某些用例(例如与 PDF 聊天)而言,但它仍然受到限制,尤其是在对各种文档进行推理时。
压缩提示并仅向 LLM 代理提供相关信息至关重要。这可以减少模型在不相关 token 上投入的处理能力,提高质量,优化延迟,并降低成本。
有很多技巧可以提高所提供上下文的相关性,其中大多数与数据存储和分类方式有关。对于 RAG 应用程序,可以方便地添加数据准备功能来调整存储的信息(例如,基于文档的问题和答案,然后仅向 LLM 代理提供答案;这样,代理就能获得经过汇总且更简短的上下文),并在检索到的文档上使用重排序算法来优化结果。
数据为LLM原生应用提供动力。对情境数据的战略性设计能够释放其真正的潜力。
结论与启示
LLM 三角原则提供了一种结构化的方法,用于开发高质量的 LLM 原生应用程序,弥补了 LLM 巨大潜力与实际实施挑战之间的差距。开发者可以通过关注 3+1 个关键原则(模型、工程技术和上下文数据)来创建更可靠、更高效的 LLM 驱动解决方案,所有这些原则均由明确的SOP指导。

关键要点
- 从清晰的SOP开始:模拟专家的认知过程,为你的LLM申请创建一份循序渐进的指南。在思考其他原则的同时,可以将其作为指导。
- 选择正确的模型:平衡功能和成本,并考虑从较大的模型开始,然后再转向较小的、经过微调的模型。
- 利用工程技术:实施 LLM 原生架构,并策略性地使用代理来优化性能并保持控制。尝试不同的提示技术,找到最适合您案例的有效提示。
- 提供相关背景:在适当的时候使用上下文学习,包括 RAG,但要小心不要让不相关的信息淹没模型。
- 迭代和实验:找到正确的解决方案通常需要测试和改进你的工作。我建议阅读并实践“构建 LLM 应用程序:清晰的分步指南”中的技巧,以获得详细的 LLM-Native 开发流程指南。
通过应用 LLM 三角原则,组织可以超越简单的概念验证,开发出真正利用这种变革技术力量的强大、可投入生产的 LLM 应用程序。
RA/SD 衍生者AI训练营。发布者:稻草人,转载请注明出处:https://www.shxcj.com/archives/9556