当下正是使用大型语言模型(LLM)构建应用的好时机。过去一年,LLM 已经发展到了足够用于实际应用的水平。LLM 的进化速度与社交媒体层出不穷的演示应用,将在 2025 年吸引对 AI 领域的约 2000 亿美元投资。LLM 的门槛也很低,让每个人(而不仅仅是 ML 工程师和科学家)都可以将智能融入他们的产品中。不过虽然构建 AI 产品比以前要容易得多,但创建出超越演示范畴,真正可用的产品仍是一项较为困难的工作。
在过去的一年里,我们一直在基于 LLM 构建现实世界的应用程序。我们意识到有必要将这些经验提炼出来造福大众。
我们有着不同的背景,担任不同的角色,但大家都亲身经历了使用这项新技术所带来的挑战。我们中的两位是独立顾问,他们帮助众多客户将 LLM 项目从最初的概念转变为成功的产品,从而总结出了决定项目成败的模式。有一位是研究人员,研究 ML/AI 团队的工作方式以及如何改进他们的工作流程。还有两位是 AI 应用团队的领导者:一位在科技巨头公司,一位在初创公司。最后一位已经向数千人教授了深度学习知识,现在致力于让 AI 工具和基础设施更加易用。在过去的一年里,我们艰难前行,收获了很多宝贵的经验教训来向大家分享。
这项工作分为三个部分:战术、运营和战略。这篇文章是第一部分,深入探讨了使用 LLM 的战术细节。文章分享了有关提示、设置检索增强生成、应用流程工程以及评估和监控等领域的一众最佳实践和常见陷阱。
战 术
提示
我们建议大家在开发新应用程序时从提示开始。人们很容易低估或高估它的重要性。所谓低估,是因为如果我们有效使用正确的提示技术可以走得很远。所谓高估,是因为即使是基于提示的应用程序也需要围绕提示进行大量工程设计才能正常工作。
专注于充分利用基本提示技术
以下提示技术总能用来提高各种模型和任务的性能:n-shot 提示 + 情境学习、思维链,以及为模型提供相关资源。
通过 n-shot 提示进行情境学习的方法,具体来说是为 LLM 提供一些示例来演示任务,并使输出符合我们的期望。一些技巧如下:
-
如果 n 太低,模型可能会过度锚定这些特定示例,从而损害其泛化能力。根据经验法则,n 至少要 ≥ 5,几十个也不嫌多。
-
示例应该代表预期的输入分布。如果你正在构建一个电影摘要应用,请用各种类型的样本构建示例,其比例应大致与你期望在实践中看到的比例一致。
-
你不一定需要提供完整的输入 - 输出对。在许多情况下,提供输出的期望示例就足够了。
-
如果你使用的 LLM 支持工具,那么你的 n-shot 示例也应该使用那些你希望代理使用的工具。
在思维链(CoT)提示方法中,我们鼓励 LLM 在返回最终答案之前解释其思维过程。可以把它看作是为 LLM 提供一个草图板,这样它就不需要全凭记忆做事了。一开始的方法是简单地在提示中加入“让我们一步一步思考”的短语,后来我们发现 CoT 更具体会更有用,通过一两句额外提示来增加特异性通常会显著降低幻觉率。例如,要求 LLM 总结会议记录时,我们可以明确说明各个步骤,例如:
-
首先,在草图板中列出关键决策、后续项目和相关负责人;
-
然后,检查草图板中的细节是否与会议文本在事实上一致;
-
最后,将要点综合成一个简明的总结。
最近,有人质疑这种技术是否真的那么强大。此外,思维链的推理过程也是颇受争议的。无论如何,只要可行的话,这种技术是值得尝试的。
提供相关资源是一种强大的机制,可以扩展模型的知识库、减少幻觉,并增加用户的信任度。它通常通过检索增强生成(RAG)技术来实现,为模型提供可以在其响应中直接使用的文本片段是一种很重要的技术。在提供相关资源时,仅仅喂给模型是不够的,还要告诉模型应该优先使用它们、直接引用它们,并在资源不足时提及它们。这些方法能够让代理输出的响应尽量围绕这些资源展开。
结构化你的输入和输出
结构化的输入和输出能够帮助模型更好地理解输入,以及返回能够可靠地与下游系统集成的输出。向输入添加序列化格式可以为模型提供更多线索,帮助它了解上下文中各个 token 之间的关系、特定 token 的附加元数据(如类型),或将请求与模型训练数据中的类似示例关联起来。
例如,互联网上许多关于 SQL 代码编写的问题都是从指定 SQL 模式开始的。因此,你可能会想到有效的 Text-to-SQL 提示应该包括结构化的模式定义。
结构化输出的用途类似,但它也简化了与系统下游组件的集成。Instructor 和 Outlines 非常适合结构化输出。(如果你要导入 LLM API SDK,请使用 Instructor;如果你要为自托管模型导入 Huggingface,请使用 Outlines。)结构化输入可以清楚地表达任务,且与训练数据的格式类似,这样获得更好输出的概率就会增加。
使用结构化输入时,请注意每个 LLM 家族都有自己的偏好。Claude 更喜欢 xml,而 GPT 则喜欢 Markdown 和 JSON。使用 XML 时,你甚至可以提供如下的 response 标签来预填充 Claude 的响应。
`</> python``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>" ``}` `]`
提示要短,每个提示只做好一件事
软件中常见的一种反模式是“上帝对象”,说的是用一个类或函数做所有事情。提示也得避免这种模式。
提示一开始往往很简单,几句说明、几个例子就可以起步了。但当我们尝试提高性能并处理更多极端情况时,复杂性就会逐渐显现。更多的说明、多步骤推理、几十个示例……不知不觉中,我们的提示现在变成了一个 2000 token 的怪物。更糟糕的是,它在更常见和更直接的输入上的表现反而更差!
就像我们努力让系统和代码保持简洁一样,提示也是一回事。以会议记录摘要应用为例:
-
将关键决策、行动项目和负责人提取为结构化格式
-
根据原始文本检查提取出来的内容细节以确保一致性
-
从结构化的细节内容中生成简明摘要
也就是说我们要将单个提示拆分为多个简单、有针对性且易于理解的提示,每个提示都能单独迭代和评估。
精心调整你的上下文 token
你实际需要向代理发送多少上下文?不管你之前的假设是怎样的,现在都要重新思考并挑战这个假设。你得像米开朗基罗一样,不是堆砌起来那座上下文雕塑,而是凿掉多余的材料,直到雕塑显露出来。RAG 是一种整理所有可能相关的内容的流行方法,但你该如何提取出真正重要的部分呢?
我们发现,将发送给模型的最终提示(包括所有上下文构造、元提示和 RAG 结果)放在一起再读几遍,能够帮助你重新思考上下文。这种方法能让你找出提示中的冗余、自相矛盾的语言和糟糕的格式。
另一个关键优化是上下文的结构。如果你的文档包在人类眼中就是一团糟,那就不要假设它对代理有任何好处。仔细考虑如何构建上下文以强调其各部分之间的关系,让提示尽可能简洁清晰。
信息检索 /RAG
除了提示之外,引导 LLM 的另一种有效方法是在提示中加入知识,这被称为检索增强生成(RAG)。从业者发现 RAG 能够有效地为模型提供知识并提高产出,同时与微调相比,它所需的工作量和成本要少得多。RAG 的好坏取决于检索到的文档的相关性、密度和细节
RAG 输出的质量取决于检索到的文档的质量,而这又涉及几个因素
第一个也是最明显的指标是相关性,一般来说通过几种排名指标来量化,例如平均倒数排名(MRR)或归一化折扣累积增益(NDCG)。MRR 评估的是系统有多大可能将第一个相关结果放在排名列表中,而 NDCG 则考虑所有结果及其位置的相关性。它们衡量系统有没有很好地将相关文档排在较高位置和将不相关文档排在较低位置。例如,如果我们要检索用户摘要以生成电影评论摘要,我们会希望将特定电影的评论排在较高位置,同时排除其他电影的评论。
与传统推荐系统一样,检索到的项目的排名将对 LLM 在下游任务中的表现产生重大影响。为了衡量这种影响,我们可以运行一个基于 RAG 的任务,但对检索到的项目乱序排列——那么 RAG 输出的表现如何?
其次,我们还想考虑信息密度。如果两个文档的相关性一样高,我们应该选择更简洁、无关细节更少的文档。回到我们的电影示例,我们可能会认为电影脚本和所有用户评论在广义上都是相关的。尽管如此,评分最高的评论和专业编辑评论的信息密度可能会更高。
最后,考虑文档中提供的详细程度。假设我们正在构建一个 RAG 系统来从自然语言生成 SQL 查询。我们可以简单地用带有列名的表模式作为上下文。但是,如果我们加入列描述和一些代表性的值呢?额外的细节可以帮助 LLM 更好地理解表的语义,从而生成更正确的 SQL。
不要忘记关键字搜索;将其用作基线并用于混合搜索策略
由于基于嵌入的 RAG 演示非常流行,我们很容易忘记或忽略信息检索领域数十年来的研究成果和解决方案积累。
无论如何,虽然嵌入无疑是一种强大的工具,但它们并不是万能的。首先,虽然它们擅长捕捉高级语义的相似性,但它们可能难以处理更具体的,基于关键字的查询,比如说当用户搜索名称(如 Ilya)、首字母缩略词(例如 RAG)或 ID(例如 claude-3-sonnet)时就是这样。基于关键字的搜索(例如 BM25)是专门为此设计的。有了多年的基于关键字的搜索经验后,用户可能已经将其视为理所当然,如果搜索没有返回他们期望检索的文档,他们可能会感到很沮丧。
向量嵌入并不能神奇地解决搜索问题。事实上,在使用语义相似性搜索方法重新做排名之前的步骤才是重头戏。对 BM25 或全文搜索做出真正的改进是很难的事情。
——Aravind Srinivas,Perplexity.ainormal 首席执行官
几个月来,我们一直在向客户和合作伙伴传达这一点。使用简单嵌入的最近邻搜索会产生非常嘈杂的结果,你最好从基于关键字的方法开始。
——Beyang Liu,Sourcegraphnormal 首席技术官
其次,使用关键字搜索可以更直接地理解系统为什么会检索到某份文档——我们查看与查询匹配的关键字即可。相比之下,基于嵌入的检索就不太容易解释了。最后,得益于 Lucene 和 OpenSearch 等经过数十年优化和实战考验的系统,关键字搜索通常在计算上更高效。
在大多数情况下,混合方法效果最好:关键字匹配方法用于明显的匹配,嵌入用于同义词、上位词和拼写错误以及多模态(例如图像和文本)情况。Shortwave 分享了他们如何构建 RAG 管道,包括查询重写、关键字 + 嵌入检索和排名。(https://www.shortwave.com/blog/deep-dive-into-worlds-smartest-email-ai/)
对于新知识,更偏重 RAG 而不是微调
RAG 和微调都可用来将新信息纳入 LLM 并提高特定任务的性能。那么,我们应该先尝试哪一个呢?
最近的研究表明 RAG 可能有优势。一项研究将 RAG 与无监督微调(又称持续预训练)方法作了对比,对 MMLU 的一个子集和一些当前事件做了评估。他们发现,无论是针对在训练期间遇到的知识还是全新的知识,RAG 方法总是优于微调。在另一篇论文中,他们用一个农业数据集对 RAG 与监督微调做了对比。同样,RAG 的性能提升大于微调,尤其是对于 GPT-4 而言。
除了提高性能之外,RAG 还有几个实际优势。首先,与持续预训练或微调相比,它更容易保持检索索引在最新状态,也更便宜!其次,如果我们的检索索引中存在包含有害或有偏见内容的问题文档,我们可以轻松删除或修改有问题的文档。
此外,RAG 中的 R 可以更精细地控制我们检索文档的方式。例如,如果我们为多个组织托管 RAG 系统,那么通过对检索索引进行分区,我们可以确保每个组织只能从自己的索引中检索文档。这确保了我们不会无意中将一个组织的信息泄露给另一个组织。
长上下文模型不会让 RAG 过时
由于 Gemini 1.5 提供了高达 10M 个 token 大小的上下文窗口,一些人开始质疑 RAG 的未来。
我倾向于认为 Sora 的炒作让 Gemini 1.5 的光芒被大大掩盖了。10M 个 token 的上下文窗口实际上让大多数现有的 RAG 框架变得没有必要了——你只需将数据放入上下文中,然后像往常一样与模型对话即可。想象一下它对所有初创公司 / 代理 /LangChain 项目的影响,他们的大部分工程工作都投入到了 RAG 上
标签:RAG,中学,输出,提示,模型,构建,LLM,我们,评估 From: https://blog.csdn.net/2401_85325557/article/details/141125119