人工智能学习

构建LLM应用:一个清晰的步骤指南

本文主要是介绍构建LLM应用:一个清晰的步骤指南,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
构建LLM原生应用的全面步骤:从初始想法到实验、评估和产品化

大型语言模型(LLMs)正迅速成为现代AI的基石。然而,目前没有确立的最佳实践,许多先驱者常常没有明确的路线图,不得不重新发明轮子或陷入困境。

在过去两年中,我帮助组织利用LLM构建创新应用。通过这些经验,我开发了一种经过实战考验的方法来创建创新解决方案(借鉴了LLM.org.il社区的见解),我将在本文中分享这种方法。

本指南提供了清晰的路线图,帮助你导航复杂且充满挑战的大型语言模型(LLM)原生开发领域。你将学习如何从构思到实验、评估和产品化,释放你创造突破性应用的潜力。

(由Dall-E3创建)

一个标准化流程为何至关重要

LLM领域发展如此迅速,以至于我们每天都能听到关于新的突破性创新的消息。这既令人兴奋,也让人感到非常混乱——你可能会在过程中迷失方向,不知道该做什么或如何将你的新想法付诸实践。

说白了,如果你是一名 AI 创新者(管理者或实践者),想要有效地构建 LLM 原生应用,这正是你需要的

实施标准化流程有助于启动新项目,并提供以下几个关键好处:

  1. 规范流程 — 标准化的流程有助于团队成员的协同,并确保新成员的顺利入职(尤其是在这种混乱的情况下)。
  2. 定义明确的里程碑 — 一种简单的方式来跟踪你的工作,衡量进度,并确保你走在正确的道路上。
  3. 识别决策点 — LLM原生开发充满了未知和“小实验”[见下文]。明确的决策点使我们能够轻松地降低风险,并始终保持开发工作的精简。
LLM 工程师的核心技能

与软件研发中的其他 established 角色不同,LLM 原生开发绝对需要一个新的角色:LLM 工程师AI 工程师

LLM 工程师是一种独特的混合体,结合了来自不同(已确立)角色的技能:

  • 软件工程技能— 和大多数SWE一样,大部分工作都是将各个组件拼接起来并把所有东西粘合在一起。
  • 研究技能— 正确理解LLM原生的实验性质是至关重要的。虽然构建“酷炫的演示应用”相对容易,但“酷炫的演示”与实际解决方案之间的差距需要实验和灵活性。
  • 深入的业务/产品理解— 由于模型的脆弱性,理解业务目标和流程比局限于我们定义的架构更为重要。能够模拟手动流程是LLM工程师的一项黄金技能。

在撰写本文时,LLM 工程仍然是一项全新的领域,招聘可能会非常具有挑战性。寻找具有后端/数据工程或数据科学背景的候选人可能是个好主意。

_软件工程师_可能会期望一个更平滑的过渡,因为实验过程更“工程化”,而不是那么“科学”(与传统的数据科学工作相比)。话虽如此,我也见过许多_数据科学家_进行这种过渡。只要你能够接受你将需要拥抱新的软技能,你就走在正确的道路上了!

LLM原生开发的关键要素

与传统的后端应用(如 CRUD)不同,这里没有一步一步的食谱。就像“AI”中的其他一切一样,LLM 原生应用需要一种 研究和实验的心态

要驯服这个野兽,你必须采取分而治之的方法,将工作分成更小的实验,尝试其中一些,并选择最有前景的实验。

我再怎么强调研究心态的重要性也不为过。这意味着你可能会花时间去探索某个研究方向,结果发现“不可行”、“不够好”或“不值得”。这完全没问题——这意味着你走在正确的道路上。

通过实验来构建 LLM 原生应用(并避开途中的陷阱)(使用 Dall-E3 创建)

拥抱实验:过程的核心

有时候,你的“实验”会失败,然后你稍微调整一下工作方向,结果另一个实验取得了更大的成功。

那正是为什么,在设计我们的最终解决方案之前,我们必须从简单开始并降低风险。

  1. 定义一个“预算”或时间框架。 让我们看看在X周内能做些什么,然后再决定是否继续进行。通常,2-4周的时间来理解基本的PoC就足够了。如果看起来有前景——继续投入资源来改进它。
  2. 实验—— 不管你选择自下而上还是自上而下的实验方法,你的目标是最大化实验成功率。在第一次实验迭代结束时,你应该有一些PoC(利益相关者可以使用)和你已经实现的基础线。
  3. 回顾—— 在我们的研究阶段结束时,我们可以理解构建这样一个应用的可行性、限制和成本。这有助于我们决定是否将其投入生产以及如何设计最终产品及其用户体验。
  4. 产品化—— 按照标准的SWE最佳实践开发一个生产就绪版本的项目,并通过实现反馈和数据收集机制将其集成到你的解决方案中。

LLM-Native 应用开发生命周期(作者供图)

为了更好地实施以实验为导向的过程,我们必须明智地决定如何进行和构建这些实验:

开始精简:自下而上的方法

虽然许多早期采用者迅速投入到“最先进的”多链代理系统中,例如使用完整的 Langchain 或类似系统,但我发现“自下而上的方法”往往能取得更好的结果。

开始精简,非常精简,拥抱 “一个提示通吃所有” 的理念。虽然这种策略可能看起来不传统,并且最初可能会产生糟糕的结果,但它为你的系统建立了一个 基准

从那里开始,持续迭代和优化您的提示,运用提示工程技巧来优化结果。在您发现精简解决方案中的弱点时,通过添加分支来解决这些不足之处。

在设计我的 LLM 工作流图或 LLM 原生架构的每个“叶子”时,我遵循LLM Triangle Principles 原则,以确定何时何地剪枝、分裂枝干或加粗根部(通过使用提示工程技术),从而榨取更多的价值。

底部向上方法的示例(作者供图)

例如,要使用自底向上方法实现“原生语言 SQL 查询”,我们将从简单地将模式发送给LLM并要求它生成查询开始。

自底向上方法示例(作者供图)

通常,这并不违背“自上而下的方法”,而是作为其之前的另一个步骤。这使我们能够展示快速胜利并吸引更多项目投资。

一开始就看清全貌:自上而下的策略

“我们知道LLM工作流并不容易,为了实现我们的目标,我们可能会采用某种工作流或原生LLM架构。”

自上而下的方法认识到这一点,并从一开始就设计LLM原生架构,并从一开始就实现其不同的步骤/链。

这样,你可以整体测试你的工作流架构,而不是分别精炼每一片叶子,而是榨取整个柠檬。

自上而下的方法流程:一次设计你的架构,实现、测试及测量(作者提供图片)

例如,要使用自顶向下方法实现“原生语言SQL查询”,我们将从设计架构开始,甚至在开始编写代码之前,然后直接进行完整实现:

自顶向下方法的例子(作者提供图片)

找到合适的平衡点

当你开始尝试使用LLM时,你可能会从两个极端之一开始(过度复杂的自上而下方法或极其简单的单次尝试)。实际上,并没有一种方法能胜出。

理想情况下,你应该定义一个好的操作规程¹,并在编码和实验之前模拟一个专家。实际上,建模非常困难;有时你可能无法获得这样的专家。

我发现一开始很难一下子就找到一个好的架构/SoP¹,所以在投入大量资源之前进行一些轻量级的实验是值得的。但这并不意味着所有事情都必须过于精简。如果你已经有一个先验的理解,某些东西必须被拆分成更小的部分——那就去做吧。

你应该利用LLM三角原则³,并在设计解决方案时正确地模拟手动流程。

优化您的解决方案:榨干柠檬

在实验阶段,我们不断挤柠檬并增加更多的“复杂性层次”:

  • Prompt 工程技术 — 如 Few Shots、角色分配,甚至是动态 Few-Shot
  • 扩展上下文窗口 从简单的变量信息到复杂的 RAG 流程,可以帮助改善结果。
  • 尝试不同的模型 — 不同的模型在不同的任务上表现不同。此外,大型 LLM 通常不太经济,尝试更多特定任务的模型是值得的。
  • Prompt 节食 — 我发现将 SOP¹(具体来说是提示和请求的输出)通过一个“节食”通常可以减少延迟。
    通过减少提示的大小和模型需要经过的步骤,我们可以减少模型需要生成的输入和输出。你可能会惊讶地发现,Prompt 节食有时甚至可以提高质量!

请注意,节食也可能导致质量下降,因此在这样做之前设置一个合理性测试是很重要的。

  • 将流程拆分为更小的步骤 也可以非常有益,使优化 SOP¹ 的子流程更容易实现。

请注意,这可能会增加解决方案的复杂性或损害性能(例如,增加处理的 token 数量)。为了缓解这一点,尽量使用简洁的提示和较小的模型。

作为一条经验法则,通常在系统提示发生重大变化时将 SOP¹ 流程的这一部分分割开来,可以获得更好的结果。

挤柠檬的AI(使用Dall-E3创建)

LLM 实验的解剖结构

就我个人而言,我喜欢从简单的 Jupyter Notebook 开始,使用 Python、Pydantic 和 Jinja2:

  1. 使用 Pydantic 定义模型输出的模式。
  2. 使用 Jinja2 编写 提示模板
  3. 定义结构化的输出 格式(使用 YAML ²)。这将确保模型遵循“思考步骤”并按照我的 SOP 指导。
  4. 使用 Pydantic 验证 确保输出;如有必要 — 重试。
  5. 稳定你的工作 — 将代码结构化为功能单元,使用 Python 文件和包。

在更广泛的范围内,你可以使用不同的工具,例如 openai-streaming 来轻松地 利用流式传输(和工具),LiteLLM 来在不同的提供商之间拥有一个 标准化的 LLM SDK,或者 vLLM 来 提供开源的 LLMs

通过 Sanity 测试和评估确保质量

一个合理性测试会评估你的项目的质量,并确保你没有降低你定义的某个成功率基准。

想想你的解决方案/提示就像一条短被子——如果你把它拉得太长,它可能突然无法覆盖以前能够覆盖的一些用例。

要做到这一点,定义一组你已经成功覆盖的案例,并确保保持这种状态(或者至少这样做是值得的)。可以将它想象成一个表驱动测试。

评估一个“生成式”解决方案(例如写文本)的成功与否要比使用LLM(大型语言模型)完成其他任务(如分类、实体提取等)复杂得多。对于这类任务,你可能希望使用更智能的模型(如GPT4、Claude Opus或LLAMA3–70B)来充当“裁判”。
在生成式输出之前,尝试让输出包含“确定性部分”也是一个好主意,因为这类输出更容易进行测试。

    城市:  
      - New York  
      - Tel Aviv  
    氛围:  
      - 活力四射  
      - 充满活力  
      - 年轻  
    目标受众:  
      年龄最小: 18  
      年龄最大: 30  
      性别: 男女皆宜  
      特征:  
        - 喜欢冒险  
        - 外向  
        - 对文化好奇  
    # 忽略以上内容,只显示 `text` 属性。  
    text: 纽约和特拉维夫都充满活力,提供无尽的活动、夜生活和文化体验,非常适合年轻、喜欢冒险的游客。

有几个前沿的、🤩🤩 有前景的解决方案值得研究。在评估基于RAG的解决方案时,我发现它们特别相关:可以看看 DeepChecks、Ragas 或 ArizeAI。

做出明智决策:回顾的重要性

每次进行重大或有时间框架的实验或里程碑之后,我们应该停下来,对是否继续采用这种方法做出明智的决定

到这时,你的实验将有一个明确的成功率基准,你也会知道需要改进的地方。

这也是开始讨论这个解决方案的产品化影响以及开始“产品工作”的好时机:

  1. 这在产品中会是什么样子?
  2. 有哪些限制/挑战?你如何缓解它们?
  3. 当前的延迟是多少?是否足够好?
  4. 用户体验应该是什么样的?可以使用哪些 UI 技巧?流式处理 是否能有所帮助?
  5. 预计在 token 上的花费是多少?能否使用较小的模型来减少花费?
  6. 优先事项是什么?是否有任何挑战是无法克服的?

假设我们达到的 基准 是“足够好”,并且我们认为可以解决我们提出的问题,那么我们将继续投资并改进该项目,同时 确保其永远不会退化 并使用健全性测试。

(由Dall-E3创建)

从实验到产品:让您的解决方案变为现实

最后但同样重要的是,我们需要将我们的工作产品化。像任何其他生产级解决方案一样,我们必须实现生产工程概念,如日志记录、监控、依赖管理、容器化、缓存等。

这是一个巨大的世界,但幸运的是,我们可以借鉴许多传统生产工程中的机制,甚至可以采用许多现有的工具。

说到底,需要注意涉及LLM原生应用的细微差别:

  • 反馈循环 — 我们如何衡量成功?仅仅是“点赞/点踩”机制,还是更复杂一些,考虑我们解决方案的采用情况?
    收集这些数据也很重要;长远来看,这可以帮助我们重新定义我们的“基线”或使用 动态少量样本 或微调模型来调整结果。
  • 缓存 — 与传统软件工程不同,当我们的解决方案涉及生成方面时,缓存可能会非常具有挑战性。为了解决这个问题,可以考虑缓存相似的结果(例如,使用 RAG)和/或减少生成的输出(通过严格的输出模式)。
  • 成本跟踪 — 许多公司发现从一开始就使用“强模型”(如 GPT-4 或 Opus)非常诱人,但在生产环境中,成本可能会迅速上升。避免在最终账单上感到惊讶,并确保测量输入/输出令牌,并跟踪工作流程的影响(如果没有这些实践,以后很难进行分析)。
  • 调试和跟踪 — 确保您已经设置了正确的工具来跟踪“有问题”的输入,并在整个过程中进行跟踪。这通常涉及保留用户输入以供后续调查,并设置 跟踪系统。记住:“与传统软件不同,AI 失败时不会发出任何警告!”
结语:您在推进LLM原生技术中的角色

这可能是文章的结尾,但绝不是我们工作的终点。LLM原生开发是一个迭代过程,涵盖了更多的应用场景、挑战和功能,并不断改进我们的LLM原生产品。

随着你继续你的AI开发旅程,保持灵活,大胆实验,并始终牢记最终用户。与社区分享你的经验和见解,我们一起可以推动LLM原生应用可能的边界。继续探索、学习和构建——可能性是无穷无尽的。

希望这篇指南能成为你在LLM原生开发旅程中的宝贵伴侣!我很想听听你的故事——在下面的评论中分享你的成功和挑战吧!💬

如果你觉得这篇文章有帮助,请在 Medium 上给它点几个 👏,并把它分享给你的 AI 爱好者朋友们。你的支持对我来说意义重大!🌍

让我们继续交流——你可以通过 邮件 或者 领英上联系我 🤝

特别感谢 Yonatan V. Levin、Gal Peretz、Philip Tannor、Ori Cohen、Nadav、Ben Huberman、Carmel Barniv、Omri Allouche 和 Liron Izhaki Allerhand 提供见解、反馈和编辑意见。

¹SoP - 标准操作程序,一个借鉴自 《LLM 三角原则》³ 的概念

²YAML - 我发现使用 YAML 来结构化输出与 LLM 的配合效果更好。为什么呢?我的理论是 YAML 可以减少无关的标记,并且表现得像一种原生语言。这篇文章深入探讨了这个主题。

³LLM 三角原则 - 用于设计和构建原生 LLM 应用的软件设计原则;更新 - 最近发布的白皮书,你可以在这里阅读。

这篇关于构建LLM应用:一个清晰的步骤指南的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!