大型语言模型 (LLM) 正在迅速成为现代人工智能的基石。然而,目前还没有既定的最佳实践,而且先驱者往往没有明确的路线图,需要重新发明轮子或陷入困境。
在过去的两年中,我帮助组织利用 LLM 来构建创新应用程序。通过这段经历,我开发了一种经过实践检验的方法来创建创新解决方案(由LLM.org.il社区的见解形成),我将在本文中分享。
本指南提供了清晰的路线图,帮助您应对 LLM 原生开发的复杂环境。您将学习如何从构思转向实验、评估和产品化,释放您创造突破性应用程序的潜力。
(使用 Dall-E3 创建)
为什么标准化流程至关重要
LLM 领域非常活跃,有时我们每天都会听到新的突破性创新。这令人兴奋,但也非常混乱——你可能会发现自己迷失在这个过程中,不知道该做什么或如何将你的新想法变成现实。
长话短说,如果您是一位想要有效构建 LLM 原生应用程序的AI 创新者(经理或从业者),那么这适合您。
实施标准化流程有助于启动新项目并带来几个主要好处:
- 标准化流程——标准化流程有助于协调团队成员并确保新成员入职流程顺利进行(尤其是在这种混乱的情况下)。
- 定义明确的里程碑——一种直接的方式来跟踪你的工作,衡量它,并确保你在正确的道路上
- 确定决策点— LLM 本土开发充满未知数和“小实验”[见下文]。明确的决策点让我们能够轻松降低风险,并始终保持开发工作的精简。
大语言模型工程师的基本技能
与软件研发领域中任何其他既定角色不同,LLM 本土开发绝对需要一个新的角色:LLM 工程师或AI 工程师。
LLM 工程师是一个独特的混合体,涉及不同(既定)角色的技能:
- 软件工程技能——与大多数 SWE 一样,大部分工作涉及将乐高积木拼在一起并将所有东西粘合在一起。
- 研究技能— 正确理解 LLM 本土的实验性质至关重要。虽然构建“酷炫的演示应用程序”相当容易,但“酷炫的演示”与实际解决方案之间的距离需要实验和敏捷性。
- 深入理解业务/产品 —由于模型的脆弱性,了解业务目标和流程至关重要,而不是坚持我们定义的架构。对 LLM 工程师来说,对手动流程进行建模的能力是一项黄金技能。
在撰写本文时,LLM 工程仍然是一个新兴领域,招聘可能非常具有挑战性。寻找具有后端/数据工程或数据科学背景的候选人可能是一个好主意。
软件工程师可能希望过渡得更顺利,因为实验过程更“工程化”而不是“科学化”(与传统的数据科学工作相比)。话虽如此,我也看到许多数据科学家也经历了这种转变。只要你能接受必须接受新软技能的事实,你就走在了正确的道路上!
LLM 本土发展的关键要素
与传统的后端应用程序(例如 CRUD)不同,这里没有循序渐进的配方。与“AI”中的其他一切一样,LLM 原生应用程序需要研究和实验的心态。
为了驯服这头野兽,你必须分而治之,将你的工作分成几个较小的实验,尝试其中一些,然后选择最有希望的实验。
我再怎么强调研究心态的重要性都不为过。 这意味着你可能会花时间探索一个研究方向,然后发现它“不可能”、“不够好”或“不值得”。这完全没问题——这意味着你走在正确的道路上。
使用 LLM 进行实验是构建 LLM 原生应用程序的唯一方法(并避免遇到阻碍)(使用 Dall-E3 创建)
拥抱实验:过程的核心
有时,你的“实验”会失败,然后你稍微调整一下工作,另一个实验就会取得更大的成功。
这就是为什么在设计最终解决方案之前,我们必须从简单开始并对冲风险。
- 定义“预算”或时间范围。让我们看看在 X 周内可以做什么,然后决定如何或是否继续。通常,2-4 周的时间来了解基本的 PoC 就足够了。如果它看起来很有希望 — 继续投入资源来改进它。
- 实验——无论您选择自下而上还是自上而下的方法进行实验,您的目标都是最大化结果连续率。在第一次实验迭代结束时,您应该有一些 PoC(利益相关者可以使用)和您实现的基准。
- 回顾——在研究阶段结束时,我们可以了解构建此类应用的可行性、局限性和成本。这有助于我们决定是否将其投入生产以及如何设计最终产品及其用户体验。
- 产品化——遵循标准 SWE 最佳实践并实施反馈和数据收集机制,开发项目的生产就绪版本并将其与其余解决方案集成。
LLM-Native 应用程序开发生命周期(作者提供图片)
为了更好地实施面向实验的过程,我们必须对如何进行和构建这些实验做出明智的决定:
开始精益:自下而上的方法
虽然许多早期采用者很快就进入了具有成熟的 Langchain 或类似产品的“最先进的”多链代理系统,但我发现“自下而上的方法”通常会产生更好的结果。
从精益开始,非常精益,秉承“一个提示统治一切”的理念。虽然这种策略可能看起来不合常规,一开始可能会产生不良结果,但它为您的系统建立了基线。
从那里开始,不断迭代和改进您的提示,采用提示工程技术来优化结果。当您确定精益解决方案中的弱点时,通过添加分支来解决这些缺点,从而拆分流程。
在设计我的 LLM 工作流图或 LLM 原生架构的每个“叶子”时,我遵循LLM 三角原则³ 来确定在何时何地切割树枝、劈开树枝或加粗根部(通过使用快速工程技术)并榨出更多的柠檬。
自下而上方法的图示(图片来自作者)
例如,为了以自下而上的方法实现“本机语言 SQL 查询”,我们首先将模式发送到 LLM 并要求它生成查询。
自下而上的方法示例(图片来自作者)
通常,这并不与“自上而下的方法”相矛盾,而是作为其前一步。这使我们能够展示快速的成果并吸引更多的项目投资。
大局在前:自上而下的策略
“我们知道 LLM 工作流程并不容易,为了实现我们的目标,我们可能会采用一些工作流程或 LLM 原生架构。”
自上而下的方法认识到这一点,并从第一天开始设计 LLM 原生架构,并从一开始就实现其不同的步骤/链。
这样,您可以测试整个工作流架构并挤压整个柠檬,而不是单独精炼每片叶子。
自上而下的方法流程:设计架构一次,实施、测试和测量(作者提供图片)
例如,为了以自上而下的方法实现“本机语言 SQL 查询”,我们将在开始编码之前开始设计架构,然后跳到完整实现:
自上而下方法的示例(图片来自作者)
找到正确的平衡
当你开始尝试 LLM 时,你可能会从其中一个极端开始(过于复杂的自上而下或极其简单的一次性)。实际上,没有这样的赢家。
理想情况下,你会定义一个好的 SoP¹ 并建模专家,然后再对模型进行编码和实验。实际上,建模非常困难;有时,你可能无法接触到这样的专家。
我发现,第一次尝试就找到一个好的架构/SoP¹ 很有挑战性,因此在开始大干一场之前,值得先进行一些简单的实验。然而,这并不意味着一切都必须太精简。如果你已经事先明白,某些东西必须分解成更小的部分——那就这么做吧。
您应该利用LLM 三角原则³ 并在设计解决方案时正确模拟手动流程。
优化解决方案:挤柠檬
在实验阶段,我们不断挤压柠檬并添加更多“复杂性层次”:
- 及时工程技术——例如 Few Shots、角色分配,甚至动态少样本
- 将上下文窗口从简单的变量信息扩展到复杂的 RAG 流可以帮助改善结果。
- 尝试不同的模型— 不同的模型在不同的任务上表现不同。此外,大型 LLM 通常不太划算,值得尝试更多针对特定任务的模型。
- 及时节食 —我了解到,对 SOP¹(具体来说,提示和所要求的输出)进行“节食”通常可以改善延迟。
通过减少提示大小和模型需要经历的步骤,我们可以减少模型需要生成的输入和输出。您可能会感到惊讶,但及时节食有时甚至可以提高质量!
请注意,节食也可能导致质量下降,因此在这样做之前设置健全性测试非常重要。 - 将流程拆分成更小的步骤也非常有益,使优化 SOP¹ 的子流程变得更容易、更可行。
请注意,这可能会增加解决方案的复杂性或损害性能(例如,增加处理的令牌数量)。为了缓解这种情况,请尽量使用简洁的提示和更小的模型。
根据经验,当系统提示的重大变化为 SOP¹ 流程的这一部分带来更好的结果时,拆分通常是一个好主意。
挤榨人工智能柠檬 (使用 Dall-E3 创建)
LLM 实验的剖析
就我个人而言,我更喜欢使用 Python、Pydantic 和 Jinja2 通过简单的 Jupyter Notebook开始精益开发:
- 使用 Pydantic从模型中定义我的输出模式。
- 使用Jinja2编写提示模板。
- 定义结构化的输出格式(以YAML²为单位)。这将确保模型遵循“思考步骤”并以我的 SOP 为指导。
- 通过 Pydantic 验证确保此输出;如果需要 — — 重试。
- 稳定您的工作——使用 Python 文件和包将您的代码构建为功能单元。
在更广泛的范围内,您可以使用不同的工具,例如openai-streaming来轻松利用流(和工具)、LiteLLM来跨不同提供商获得标准化的 LLM SDK ,或使用vLLM来提供开源 LLM。
通过健全性测试和评估确保质量
健全性测试会评估您的项目质量,并确保您不会降低您定义的某个成功率基线。
将您的解决方案/提示视为一条短毯子 - 如果您将其拉得太长,它可能会突然无法覆盖以前覆盖的一些用例。
为此,请定义一组您已经成功覆盖的案例,并确保保持这种状态(或至少值得这样做)。将其视为表驱动测试可能会有所帮助。
评估“生成式”解决方案(例如,编写文本)的成功程度比使用 LLM 执行其他任务(例如分类、实体提取等)要复杂得多。对于这些类型的任务,您可能需要使用更智能的模型(例如 GPT4、Claude Opus 或 LLAMA3–70B)来充当“裁判”。
尝试让输出在“生成式”输出之前包含“确定性部分”也可能是一个好主意,因为这些类型的输出更容易测试:
有一些尖端的、🤩🤩 有前途的解决方案值得研究。我发现它们在评估基于 RAG 的解决方案时特别有用:看看DeepChecks、Ragas或ArizeAI。
做出明智的决定:回顾的重要性
在每次重大/时间框架的实验或里程碑之后,我们应该停下来并做出明智的决定,考虑如何以及是否继续这种方法。
此时,您的实验将有一个明确的成功率基线,并且您将知道需要改进的地方。
这也是开始讨论此解决方案的产品化含义并从“产品工作”开始的好时机:
- 这在产品中会是什么样子?
- 有哪些限制/挑战?您将如何缓解这些限制/挑战?
- 您当前的延迟是多少?够好吗?
- 用户体验应该是什么样子?您可以使用哪些 UI 技巧?流媒体能有所帮助吗?
- 代币的预计支出是多少?我们可以使用较小的模型来减少支出吗?
- 优先事项是什么?有哪些挑战是棘手的?
假设我们达到的基准“足够好”,并且我们相信我们可以缓解我们提出的问题。在这种情况下,我们将继续投资和改进项目,同时确保它永远不会退化并使用健全性测试。
(使用 Dall-E3 创建)
从实验到产品:将您的解决方案变为现实
最后但同样重要的是,我们必须将我们的工作产品化。与任何其他生产级解决方案一样,我们必须实现生产工程概念,如日志记录、监控、依赖管理、容器化、缓存等。
这是一个巨大的世界,但幸运的是,我们可以借鉴经典生产工程的许多机制,甚至采用许多现有的工具。
话虽如此,特别注意涉及 LLM 原生应用程序的细微差别非常重要:
- 反馈循环— 我们如何衡量成功?它只是一种“赞成/反对”机制,还是考虑采用我们的解决方案的更复杂的机制?收集这些数据也很重要;将来,这可以帮助我们重新定义我们的理智“基线”或通过动态少量镜头
微调我们的结果或微调模型。 - 缓存— 与传统 SWE 不同,当我们在解决方案中涉及生成方面时,缓存可能非常具有挑战性。为了缓解这种情况,请探索缓存类似结果(例如,使用 RAG)和/或减少生成输出(通过采用严格的输出模式)的选项
- 成本跟踪——许多公司发现从“强模型”(例如 GPT-4 或 Opus)开始非常诱人,然而,在生产中,成本可能会迅速上升。避免对最终账单感到惊讶,并确保测量输入/输出令牌并跟踪工作流程的影响(如果没有这些做法——以后分析它时就祝你好运了)
- 可调试性和跟踪— 确保您已设置正确的工具来跟踪“有缺陷的”输入并在整个过程中对其进行跟踪。这通常涉及保留用户输入以供日后调查并设置跟踪系统。请记住:“与传统软件不同,AI 的失败是悄无声息的!”
结束语:您在推动 LLM 本土技术发展中发挥的作用
这可能是本文的结尾,但肯定不是我们工作的结束。LLM 原生开发是一个迭代过程,涵盖更多用例、挑战和功能,并不断改进我们的 LLM 原生产品。
在您继续 AI 开发之旅时,请保持敏捷、大胆尝试,并牢记最终用户。与社区分享您的经验和见解,我们可以共同突破 LLM 原生应用的极限。继续探索、学习和构建 — 可能性无穷无尽。