Skip to main content

过去一年建设AI产品实战经验(战术篇)

· 预计30分钟读完
圈友讨论

战术

本章节我们分享LLM堆栈核心组件的最佳实践:让Prompt具备更高质量和可靠性,用策略的方式评估输出,用RAG的想法改进基础等。我们还探讨如何设计人不断回路工作流程,虽然技术仍在迅速发展,但我们希望这些经验教训是进行过无数实验的副产品,它经得起时间的考验并帮助你构建和发布强大的LLM应用程序。

关于Prompting

我们建议在开发新应用程序时从Prompt开始,它是很容易被低估和被高估的重要性。它被低估是因为正确的Prompt技术,当正确稳定输出时可以让我们走得很远。它被高估是因为即使基于Prompt的应用程序也需要围绕Prompt进行大量工程才能运行良好。

充分利用基本的引导技巧

一些Prompt技术一直在各种模型和任务中帮助提高性能:n-shot提示+上下文学习、思维链和提供相关资源。 通过 n-shot 提示进行上下文学习的想法是为LLM提供一些示例,展示任务并将输出与我们的期望对齐。一些建议: - 如果 n 太低,模型可能会过度锚定在那些特定的示例上,从而损害其泛化能力。作为一个经验法则,目标是 n ≥ 5。不要害怕将 n 提高到几十个 - 示例应该代表预期的输入分布,如果你正在构建一个电影摘要生成器,请包括来自不同类型的样本,大致按照你在实践中期望看到的比例。 - 你不一定需要提供完整的输入-输出,许多情况下所需输出的示例就足够了。 - 如果你正在通过支持工具使用的LLM,你的 n-shot 示例也应该用你希望代理的工具。

在思维链(CoT)提示中,我们鼓励LLM在给出最终答案之前解释其思维过程,可以将其视为为LLM提供一个草图本,这样它就不必全部依赖记忆。最初的方法是简单地在说明中添加短语“让我们逐步思考”,然而发现通过额外的一两句使 CoT 更具体是有帮助的,通常可以显著降低幻觉率。例如,当要求LLM总结会议记录时,我们可以明确说明步骤,比如:

  • 首先,在草图本上列出关键决策、后续事项和相关负责人。
  • 然后,检查白板中的细节是否与期望结果相符。
  • 最后,将关键要点综合成简明扼要的总结。

最近,一些人对这种技术是否像人们所认为的那样强大表示怀疑。此外,关于在使用思维链时推理过程中到底发生了什么存在着重大争论。不过,这种技术是一种可以尝试的Prompt技术。

提供相关资源是扩展模型知识库、减少幻觉并增加用户信任的强大机制。通常通过检索增强生成(RAG)来实现,向模型提供文本片段,模型可以直接在其响应中使用,这是一项重要技术。在提供相关资源时,仅仅包含它们是不够的,不要忘记告诉模型优先使用它们或直接参考它们。有时还要提到当资源不足时,这些有助于将代理响应与资源语料库“联系”起来。

组织好你的输入和输出

结构化的输入和输出有助于模型更好地理解输入,并返回可靠集成到下游系统的输出。向你的输入添加序列化格式可以帮助模型提供更多线索,以了解上下文中令牌之间的关系,为特定令牌添加额外的元数据(如类型),或将请求与模型训练数据中的类似示例相关联。

举个例子,互联网上关于编写 SQL 的许多问题都是从指定 SQL 模式开始的。因此,你可能期望对于文本转为 SQL 的有效Prompt应该包括结构化的模式定义。

结构化输出具有类似的目的,它还简化了集成到系统下游组件中的过程。指导和概述对于结构化输出效果很好。(如果你正在导入LLM API SDK,请使用指导方式;如果你正在导入 Huggingface 用于自托管模型,请使用概述方式。)结构化输入清晰地表达任务,并类似于训练数据的格式,增加了更好输出的可能性。如下代码参考:

messages=[     
    {         
        "role": "user",         
        "content": """Extract the <name>, <size>, <price>, and <color> 
                   from this product description into your <response>.   
                <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>"     
   } 
]

简单Prompt专注做一件事且做得很好

软件中常见的反模式/代码异味是“上帝对象”,其中我们有一个单一的类或函数负责一切,Prompt也是如此。 Prompt通常从简单开始:几句指示、几个例子,我们就可以开始了。但是当我们试图提高性能并处理更多边缘情况时,复杂性悄然而至,比如更多的指示、多步推理、数十个例子。在我们意识到之前,我们最初简单的Prompt现在是一个有 2000 个Token,更让人伤心的是它反而在输入上表现更差! 就像我们努力保持系统和代码简单一样,我们应该在Prompt也这样做。与其为会议记录摘要生成器设置一个通用提示,我们可以将其分解为以下步骤: - 提取关键决策、行动项和责任人到结构化格式 - 检查提取的细节与原始抄录进行一致性检查 - 从结构化细节生成简明摘要 因此,我们将单个提示分成多个简单、专注且易于理解的Prompt。通过拆分它们,我们现在可以逐个迭代和评估每个Prompt。

精心制作你的上下文标记

重新思考并挑战你对实际需要发送给代理的上下文量的假设。像米开朗基罗一样,不要建立你的上下文雕塑——凿掉多余的材料,直到雕塑显现出来。RAG 是一个流行的方法,用来整理所有可能相关的大理石块,但你又在做什么来提取必要的内容呢? 我们发现将发送给模型的最终Prompt(包括所有的上下文构建、元提示和 RAG 结果)放在空白页面上,阅读它可以有助于重新思考你的上下文。我们使用这种方法就会发现存在冗余、自相矛盾的语言和糟糕的格式。 另一个关键的优化是你上下文的结构,你的文档库如果对人类没有帮助,不要假设它对代理人有任何好处。仔细考虑如何构建你的上下文以突出其各部分之间的关系,并使提取尽可能简单。

信息检索/RAG

除了Prompt之外,另一种有效的引导LLM的方法是在Prompt的一部分提供知识。这将使LLM基于所提供的上下文,然后用于上下文学习,它被称为检索增强生成(RAG)。实践者发现 RAG 在提供知识和改善输出方面非常有效,而与微调相比,所需的工作量和成本要少得多。RAG 的好坏取决于检索到的文档的相关性、密度和细节。

RAG输出质量取决于检索文档的质量,要考虑几个因素

首先,最明显的指标是相关性,这通常是通过排名指标来量化的,比如平均倒数排名(MRR)或归一化折现累积增益(NDCG)。MRR 评估系统在排名列表中放置第一个相关结果的效果如何?而 NDCG 则考虑所有结果及其位置的相关性,它们衡量系统在将相关文档排名较高而无关文档排名较低方面的表现。例如,我们正在检索用户评论以生成电影摘要,希望将特定电影的评论排名较高,同时排除其他电影的评论。 与传统的推荐系统一样,检索到物品的排名将对LLM在下游任务中表现产生重大影响。为了衡量影响,运行一个基于 RAG 的任务,但检索到的物品被打乱了 —— RAG 输出表现又如何呢?

其次,我们还要考虑信息密度,如果两个文档同等相关,应该偏好那个更简洁、包含更少无关细节的文档。回到电影示例,可能认为电影剧本和所有用户评论在广义上是相关的。尽管如此,排名靠前的评论和编辑评论可能会更加信息密集。

最后,考虑文档中提供的详细级别,想象下我们正在构建一个从自然语言生成 SQL 查询的 RAG 系统,我们可以简单地提供包含列名的表模式作为上下文,如果也包括列描述和一些代表性值呢?额外的细节可以帮助LLM更好地理解表的语义,从而生成更正确的 SQL。

不要忘记关键词搜索,将其用作基线和混合搜索

...

解锁「写代码,赚美元」新技能