先前我们聊到了《从零开始构建大模型(LLM)应用》,不少朋友偷偷问我:“什么是LLM的三角原则?”今天就给大家仔细讲讲构建LLM应用的三角原则。这套原则其实不复杂,由“3+1”(一范式三原则)个基础组成,适合任何团队来实践。
说到以LLM为核心的应用,有不少人以为是高大上的模型占主导,但其实情况是这样的:10%是那些复杂的模型,而有足足90%是实验性的、以数据为驱动的工程作业。
当我们把LLM应用到实际产品中时,需要的不仅是代码功底,更多的是工程上的精磨细打。如果用户不能直接和LLM打交道,那我们就必须搭建完善的构造prompt ,确保涵盖所有必要的细节,否则用户的反馈可能就没法收集完整,将会影响到后续的迭代升级!
1、LLM三角原则概念
提到LLM三角原则,你可能会觉得这是个很复杂的概念,但实际上,它就是我们构建高效LLM本地应用的一套基本指南。这套原则为开发者们提供了清晰的框架和方向,一步一步地打造出既健壮又可靠的LLM应用。有了这个原则作为指南,开发的过程将会变得更有条不紊,有效率。
1.1关键点
在我们打造LLM本地应用的过程中,LLM三角原则介绍了一个范式三大实用原则。
我们来看看范式:标准操作程序(SOP)。这个原则帮助我们把握好三个重要原则:模型、工程集成和上下文数据。
简单地说,把这三部分通过SOP进行精细调整,就是打造一个高效强大LLM本地应用的秘诀。这就像是确保我们的应用在正确的轨道上高速前进,既稳定又快速。
2. 标准操作程序(SOP)
标准操作程序(SOP)是一个常见的概念。其实就是一本操作手册,里面详细记录了每一步怎么做,确保每个员工做同一个工作时,效果都差不多,质量都很高。就像是给没有经验的员工一个详细的指导书,让他们也能像正常工作。
在我们构建LLM应用时,我们也用了这个原则。把模型想象成一个刚入行的新手,通过SOP这样的标准操作指南来“教”它怎么像专家那样完成任务。这样一来,我们的应用不仅运行得更流畅,出来的成果也能保证是高质量的。
“没有SOP,再厉害的LLM也难以保持一贯的高质量。”
在弄清楚SOP指导范式的时候,我们需要思考哪些技术工具可以帮助我们最有效地实行三大原则。
2.1 认知建模
要制定SOP,我们得先观察那些干得最好的员工——也就是我们的业务专家。我们需要模仿他们的思考和工作方式,确保能够达到他们同样的成果,并且要把他们的每一步操作都记录下来。
当我们编辑和正式化这些记录后,就会形成一套详尽的操作指南。这套指南能帮助经验不够或技术不足的员工也能够顺利完成工作。
我们自己在工作时,如果任务太复杂,就会感到头脑负担重。所以,把复杂的任务简化或者分解成小步骤,可以帮助我们更轻松地完成任务。遵循这样简单明了的分步指导,比起那些长长的、复杂的操作流程要容易得多。
在这个过程中,我们还会注意到一些专家在不经意间采取的小小习惯,这些习惯可能看起来微不足道,但实际上对最终结果有很大的影响。
比如说,我们想要模拟一个数据分析(通常是使用SQL或者表格)的工作方式。我们可以先从访谈开始,问他们一些具体的问题,了解他们的日常工作流程:
当需要你分析一个业务问题时,你通常会怎么做?
你是如何确保你的解决方案完全符合需求的?
接下来,我们会把我们理解的过程反馈给受访者看看,比如说:“所以你是这样分析的吗?”
然后询问:“这个流程可以覆盖你的工作过程吗?”这样可以让他们纠正我们可能理解错误的地方。
诸如此类的问题。
隐性认知过程有很多种,它们的形式和表现各不相同。比如说,“业务特定定义”就是一个典型例子。拿“畅销书”这个词来说,对于我们的业务专家来讲,这是一个非常重要的术语,他们对这个词有着明确的理解和定义。但如果你问一般人,他们可能就不那么清楚这个词具体是什么意思了。
到最后,我们就能拥有一套完整的SOP流程,这让我们可以模仿我们最优秀分析师的工作方法。当我们试图绘制这些复杂的流程时,将它们用图表形式展示出来会非常有帮助。特别是当这些流程包括许多小步骤、条件选择和不同分支时,图表的方式可以让我们更清晰地看到每一个环节,理解和执行起来也会更加直观。这样的方法能帮助我们更好地掌握流程,确保像那些优秀的分析师一样执行每一步操作。
我们的最终解决方案应该严格按照SOP中定义的步骤来模仿执行。在设计初期,不必过多关注实现的具体细节——这部分我们可以在后续阶段,针对解决方案的具体步骤或环节中逐步实施。
与其他原则不同,认知建模(即编写SOP)是一个独立的过程。我强烈推荐,在动手编写代码之前,先对整个流程进行模拟。当然,在实际实施过程中,随着对问题的理解不断深入,你可能需要根据新的认识对模型进行调整。
既然我们已经了解到创建一个SOP的重要性,这个SOP将指导我们更好地理解产品的问题及定位,并探讨如何有效利用各种工程技术来实施这一过程。这种方法确保我们的方案既符合需求又具有执行效率。
3. 工程集成
工程集成是实施SOP并最大化模型效用的关键。在考虑工程集成原则时,我们需要思考:使用的“工具”里有哪些技术可以帮助我们执行和完善SOP?这些技术又如何确保模型能有效执行并满足我们的需求?
在我们的工程技术中,有些技术仅在提示层面实施,而更多技术则需要在软件层面才能有效运作,还有一些技术是结合了这两个层面。
虽然每天我们都能遇到很多小调整,但在这里主要介绍两种重要的技术:工作流/链路和Agents。这两种技术对于我们的系统来说至关重要,它们帮助我们更高效地管理和执行复杂的任务。
3.1. LLM应用架构设计(工作流或链路)
LLM应用架构设计其实是在描述我们的LLM应用要完成任务的各个流程。
在我们的设计中,每一个步骤都是不可或缺的,各自独立地完成特定任务。有些步骤可能只需要靠一些固定的代码来执行;而对于其他步骤,我们可能会用到LLM(Agents)。
为了更好地构建这个架构,我们需要重新审视之前制定的标准操作程序(SOP),并思考以下几个问题:
哪些SOP步骤应该合并到同一个流程中?哪些步骤需要分开处理?
哪些步骤应该独立执行(虽然它们可能依赖前一个步骤的信息)?
哪些步骤可以通过固定步骤来实现?
等等。
在我们继续深入架构或流程图的具体步骤之前,我们应该明确一些关键属性:
输入和输出 —— 每一步需要什么输入?我们在行动前需要准备什么?(这同样适用于Agents的输出格式)。
质量保证 —— 什么样的响应才算是“足够好”?有没有需要人工介入的情况?我们可以设置哪些检查来确保质量?
自主级别 —— 我们希望对结果的质量控制到什么程度?这个阶段能处理哪些问题的范围?换句话说,我们对模型在这个阶段独立工作的能力有多大的信任?
触发器 —— 下一步我们要做什么?什么决定了下一步的行动?
非功能性要求 —— 我们需要的响应时间是多少?是否需要特别的业务监控?
故障转移控制 —— 可能会出现哪些类型的故障(包括系统性和代理性)?我们准备了哪些应对措施?
状态管理 —— 我们需要特殊的状态管理机制吗?我们如何检索或保存状态(确定索引键)?是否需要持久化存储?这种状态有哪些不同的应用(例如,用于缓存、记录日志等)?
3.2. 代理(Agents)是什么?
在LLM本地架构中,LLM Agents是一个独立的组件,它的工作就是调用一个LLM。
每个Agents都是LLM的一个实例,其中的prompt 包含了相应的上下文。但是,并不是所有的Agents都一样——有些Agents会使用“工具”,而有些则不会;有些可能在流程中只被使用一次,而其他的可以被递归调用或多次调用,它们会携带前一个输入和输出。这种设计让每个Agents都能根据需要灵活地执行任务,从而有效地支持整个LLM应用的运行。
3.2.1. Agents 与工具集
一些LLM Agents可以利用“工具”——这些工具是预先定义好的功能,可以用来执行数学计算或网络搜索等操作。当Agents需要使用某个工具时,它会明确指出所需的工具及其输入参数,随后应用程序依照这些指令执行任务,并将结果反馈给Agents。
为了帮助大家更好地理解这个概念,我通过一个简单的例子来看看如何实现工具调用。这个示例可以在没有专门训练用于调用工具的模型中工作:
你扮演的是一个助手,可以使用以下工具:
- calculate(expression: str) -> str - 用于计算数学表达式
- search(query: str) -> str - 用于在库存中搜索项目
接到一个输入后,你需要以YAML格式回应,其中包括以下键:`func`(字符串类型) 和 `arguments`(映射类型) 或 `message`(字符串类型)。
给定输入
我们需要区分两种代理:一种是带有工具的代理(即自主Agent),另一种是其输出可以直接导致执行动作的代理。
“自主Agent是具备独立完成任务方法的代理。”
自主Agent拥有决定是否采取行动及其具体行动的权力。相比之下,非自主代理只是简单地“处理”我们的请求(例如,进行分类),处理完成后,由我们的确定性代码来执行具体动作,模型本身对这一过程没有控制权。
随着我们增加Agent在规划和执行任务中的自主性,我们确实增强了决策能力。这看似一个非常好的解决方案,可以让Agent显得更“智能”。但是,这样做的一个潜在风险是可能会降低我们对最终输出质量的控制。
不要过分依赖全自主代理。虽然这类Agent的设计看起来简单且很有吸引力,但如果在所有情况下或作为初步概念验证使用,可能会在实际应用中产生误导。自主Agent难以调试且其响应质量不稳定,因此通常不适合在生产环境中使用。
以经验来看,在没有详细指导的情况下,Agent在规划复杂过程时往往表现不佳,可能会忽略一些关键步骤。例如,在我们的“百科编辑者”示例中,Agent可能会直接开始写作,而忽视了必要的准备工作。这说明Agent的性能很大程度上依赖于它们训练的数据——简单来说,Agent只能做得和它们训练的数据一样好。
与其让一个或一组Agent自由地完成所有环节的任务,不如在流程或标准操作程序(SOP)中的特定区域限定它们的任务,特别是那些需要创造力和灵活性的环节。这种做法可以提高成果的质量,因为它既利用了流程的规范性,又保留了创新的空间。
以AlphaCodium(一个代码生成任务增强流程很火的开源项目)为例:通过将固定的流程与不同功能的Agent相结合(包括一个专门负责重复编写和测试代码的新型代理),他们成功地将GPT-4在CodeContests上的准确率(pass@5)从19%提高到了44%。这个例子很好地说明结合流程控制和Agent创造力的重要性,以及这种结合如何有效提升任务执行的效果。
在我们利用工程集成来实施标准操作程序(SOP)和优化LLM本地应用的同时,我们也不能忽视LLM三角原则中的另一个核心要素:模型本身。
4. 模型
我们选用的模型是项目成功的关键因素。例如,像GPT-4或Claude Opus这样的大模型虽然能够提供更优质的结果,但在大规模应用时成本也相当高。相比之下,较小的模型虽然可能不那么“强大”,但有助于我们控制预算,而且在某些特定领域能达到我们想要的效果。因此,在考虑选择模型时,我们必须清楚自己的约束条件和目标,才能确定哪种类型的模型最适合帮助我们达成这些目标。
并非所有的LLM都是相同的。要使模型与任务相匹配。
事实是,我们并不总是需要最大的模型;这取决于具体任务。为了找到合适的匹配,我们必须进行实验过程,并尝试我们解决方案的多种变体。
考虑到我们的“无经验工人”类比——一个拥有众多学术资质的非常“聪明”的工人可能会轻松完成一些任务,但他们可能对某些工作来说过于高资,雇用一个“更便宜”的候选人会更加具有成本效益。
在选择模型时,我们需要根据可以接受的各种权衡来定义和评估不同的解决方案:
任务复杂度 — 对于简单的任务,如生成摘要,一个小型模型就足够了,但处理更复杂的推理任务通常需要较大的模型。
推理基础设施 — 我们选择在云端还是在端侧上运行模型?模型的大小可能会限制设备配置的性能,但在云服务中这通常不是问题。
定价 — 我们能接受的最高价格是多少?结合业务影响和预期的使用频率,这个投入是否划算?
延迟 — 模型越大,其处理速度可能越慢。
标注数据 — 我们是否拥有足够的标注数据来丰富模型,尤其是那些模型未曾学习过的信息?
在许多情况下,在我们积累足够的“专业知识”之前,为了获得经验丰富的效果而支付额外成本是非常需要的——这对于LLMs也是适用的。这可以在初期阶段帮助我们实现更好的性能和效果。
如果手头没有标注数据,一个好的策略是先使用一个更强大(也就是更大)的模型开始工作,通过这个模型来收集数据,但这个需要注意合规风险。然后,利用收集到的这些数据,我们可以通过少样本学习或者对模型进行微调,从而进一步提升模型的性能。
4.1. 模型微调
在对模型进行微调之前,您必须考虑以下几个方面:
隐私:如果您的数据中包含敏感或个人信息,必须对这些信息进行匿名化处理,以避免可能的法律责任。
法律、合规性和数据权利:训练模型时可能涉及法律问题。例如,OpenAI的使用条款禁止未经许可使用其生成的内容来训练模型。另外,根据欧盟的GDPR法规,用户有权要求企业删除其个人数据,这可能会引起关于模型是否需要重新训练的法律问题。
更新延迟:与直接在上下文中嵌入新信息相比,重新训练模型通常需要更多时间,因此更新的频率可能较低。
开发和操作:建立一个可重复、可扩展并可监控的微调流程是至关重要的,同时需要持续评估性能。这一过程复杂且需要持续的维护。
成本:由于训练过程的复杂性以及高密集的资源需求(如GPU),重新训练模型通常代价高昂。
LLMs作为“上下文学习者”的功能,以及新模型支持更宽广上下文窗口的能力,已经大大简化了我们的应用实现。这意味着即使不进行模型微调,我们也能获得很好的效果。因此,考虑到微调的复杂性,我们建议只在必要时才采用,或者尽可能避免使用微调。
另一方面,对于特定任务(例如生成结构化的JSON输出)或特定领域的应用进行微调,可能会更有效。一个专为特定任务设计的小模型在处理这些任务时既高效又成本低,比大型LLMs要经济得多。因此,在决定是否升级到更大规模的LLM训练之前,评估所有相关因素是非常必要的。
请注意,即使是最先进的模型,也需要依赖相关而且结构合理的上下文数据,才能充分发挥其潜力。
5. 上下文数据
LLMs 是上下文学习的高手。只要我们提供相关任务的具体信息,LLM Agent就能够在不经过特殊训练或微调的情况下帮助我们完成这些任务。这让我们可以很轻松地向它们“传授”新的知识或技能。
当涉及到上下文数据的处理时,我们应该要向如何组织和建模手头上的数据,并考虑如何在我们的prompt 中有效地整合这些数据。这样一来,LLM就能更好地理解和执行任务,从而提高效率和效果。
要构建有效的上下文,我们需要在发送给LLM的提示(prompt)中包含相关的信息。通常,我们可以采用两种类型的上下文:
嵌入上下文:这种上下文直接嵌入到prompt的文本中,作为信息的一部分提供。
你是<name>的得力助手,<name>在<company>担任<role>。
附件上下文:这种上下文通过在prompt的开头或结尾附加信息片段来提供。
在保持友好语气的同时总结所提供的电子邮件。
---
<email_0>
<email_1>
我们通常使用“prompt模板”来实现这些上下文,比如使用jinja2、mustache或简单的原生格式化字符串。通过这种方式,我们可以优雅地构建提示内容,同时保持其核心本质清晰:
# 带有附件上下文的嵌入上下文
prompt = f"""
你是{name}的得力助手,{name}在{company}担任{role}。
帮助我用{tone}语气回复附加的电子邮件。
始终以以下签名结尾:
{signature}
---
{email}
"""
5.1. 少样本学习
少样本学习是一个不需要大量调整模型就能教会LLMs新技能的方法。我们只需在prompt中加入一些准备好的示例,模型就能学会我们需要的格式、风格或怎样完成任务。
比如,如果我们想让LLM帮忙回复电子邮件,我们可以在prompt中加入几个认为写的好的回复示例。这样,模型就能学到我们希望的回复结构和语气。
通过提供多种不同的示例,模型可以更好地理解各种复杂的情况和细微的差异。因此,确保你的示例全面,能覆盖所有可能的情况是非常重要的。
随着应用程序的进步,你可以采取“动态少样本学习”的策略,根据每个特定的输入选择最相关的示例。这种方式虽然更复杂,但能让模型针对不同的情况得到最好的指导,从而在处理多种任务时提高性能,同时避免了成本高的大规模调整。
5.2. RAG
检索增强生成(Retrieval Augmented Generation,简称RAG)是一种特别的技术,它会在LLM生成回答之前先查找相关的文档,以此来提供更多的上下文信息。可以想象成,在LLM回答问题之前,它会先快速查阅相关的资料,这样做可以帮助它给出更准确和更新的信息。
例如,在聊天机器人的应用中,RAG能够自动查找并提取相关的帮助台维基页面,这些信息将直接用来支持LLM的回答。
这种方法让LLM能够依据最新获取的信息来生成回答,这不仅确保了信息的及时更新,还减少了生成不准确或虚假信息的风险。对于那些需要最新数据或专门知识的任务,使用RAG特别有效,而且这样做不需要重新训练整个模型,既节约了时间也节省了资源。
例如,假设我们正在为产品开发一个在线支持聊天功能。在这种情况下,我们可以利用RAG技术从知识库中检索出相关的文档,然后把这些信息提供给LLM Agent。接着,让它根据提供的问题和文档内容撰写出合适的答案。
在部署RAG技术时,我们需要特别关注以下几个关键点:
检索机制:通常的做法是通过搜索相似的内容来找到相关文档,有时候采用更简单的搜索方法(例如,基于关键词的BM-25搜索)可能更有效或成本更低。
索引数据结构:如果我们直接索引整篇文档而不做预处理,可能会影响搜索结果的质量。因此,我们可能需要先进行一些数据准备,例如根据文档内容制作一份问答对列表。
元数据:保留与查询相关的元数据可以帮助我们更有效地筛选和引用信息(比如,只关注与用户查询直接相关的知识页面)。这一额外的数据层可以使检索过程更简单。
5.3. 提供相关上下文
在提供信息给Agent时,关键是要把握一个度。提供很多信息似乎看起来非常有用,但是如果信息太多、太杂,反而可能会让模型感到不堪重负,难以区分哪些信息是真正相关的。过多的无关信息可能会让模型学到错误的东西,造成混淆甚至错误的判断。
例如,当Gemini 1.5发布时,它能处理高达10M标记的数据,一些专家开始质疑这样庞大的数据处理能力是否真的有效。尽管这种能力对某些特定场景(比如处理PDF文件的对话)很有帮助,但在需要对多种文档进行综合推理的情况下,它的效果还是非常有限。
因此,我们在提供信息时,应该尽量保证信息的相关性。这样做不仅能减少模型处理无关数据时的计算负担,还能提高任务的执行质量和效率,同时也能降低成本。选择什么样的信息提供给模型,直接影响到模型的表现和效果。
要提高我们提供给LLM的上下文信息的相关性,有很多有效的方法,这些方法主要涉及如何更好地存储和管理数据。特别是在使用检索增强生成(RAG)技术的应用中,加入一个准备数据的步骤会非常有帮助。例如,我们可以先从文档中提取出问题和答案,然后只向LLM代理提供这些答案。这样,Agent接收到的上下文就会更加简洁明了。同时,使用一些算法对检索到的文档进行重新排序,也能优化最终的输出结果。
“数据是LLM应用的核心驱动力。好的上下文数据能最大限度地发挥出它的潜力。”
6、总结
LLM三角原则提供了一个基础框架,帮助我们在开发产品时发挥LLMs的功能。这个框架基于三个主要的元素:模型、工程集成、上下文数据,以及一套详细的操作步骤(SOP)。
6.1关键要点
从明确的操作步骤开始:先模拟专家如何思考和操作,然后根据这些信息为你的LLM应用制定一份详细的操作指南。这个指南将成为你实施其他步骤的基础。
选择合适的模型:在选择模型时要考虑到性能和成本之间的平衡。你可以先从一个大模型开始,如果需要,以后再改用一个经过微调的小模型。
利用工程技术:建立一个LLM本地架构,并巧妙地利用代理来提升性能,同时确保能控制整个过程。试验不同的提示技术,找到最适合你需求的方法。
提供相关上下文:合理利用上下文信息来增强学习,比如使用检索增强生成(RAG),但要注意避免给模型提供太多无关的信息。
不断迭代和实验:通常,找到最好的解决方案需要不断的测试和调整。推荐阅读《从零开始构建大模型(LLM)应用》来获得更多关于LLM开发过程的详细指导。
通过这些方法,组织不仅能超越基本的概念验证阶段,还能开发出强大、准备好上线的LLM应用,最大限度地发挥这项技术的潜力。
6.2干货推荐
在项目中,构建大模型应用时,以下几款工具是非常实用且常用的:
框架 | 使用场景 | 优点 | 缺点 |
---|---|---|---|
LangChain | 1、适合需要快速开发和部署大型模型应用的场景。 2、适合有编程基础和对大模型有了解的开发者。 | 1、易用性:LangChain简直是为程序员量身打造的工具集,简化了开发工作量。 2、模块化设计:各种模块(如Retrievers、Memory、Chain、Agent、Tools)可以随意组合,开发效率杠杠的。 3、快速迭代:几乎每天都有新版本,成熟度不断提升。 4、社区支持:在GitHub上人气很高,社区非常活跃,获取帮助很方便。 | 1、学习成本:虽然设计简单,但还是需要点代码能力和对大模型的理解。 2、部分模块成熟度不一:有些第三方功能还不太成熟,不建议直接用。 |
LlamaIndex | 1、适合需要结合大型语言模型和私有数据或特定领域数据的应用场景。 2、适合有技术背景的开发者使用。 | 1、数据连接能力:LlamaIndex的数据连接器简直无敌,能读多种外部数据源。 2、索引构建:支持多种索引方式,用户可以根据需求自由构建索引。 3、查询接口:提供大模型对话接口,让大模型理解和回应外部数据查询。 4、扩展性和灵活性:用户可以自定义索引和查询逻辑,满足不同需求。 | 1、技术门槛:构建和管理索引需要一定技术背景,对初学者有些难度。 2、资源消耗:索引和查询会消耗较多计算资源,特别是处理大量数据时。 |
RAGFlow | 1、适合处理复杂格式非结构化数据并构建知识类应用的企业和个人。 2、适合对文档理解和问答质量要求高的场景。 | 1、深度文档理解能力:RAGFlow从复杂格式的非结构化数据中提取真知灼见,支持无限上下文场景。 2、可控可解释的文本切片:多种文本模板,结果可控可解释,降低幻觉风险。 3、兼容异构数据源:支持Word、PPT、Excel、PDF等多种文件类型,方便集成。 4、自动化RAG工作流:全面优化的RAG工作流,支持各种规模的生态系统。 | 目前具体缺点信息较少,可能包括某些特定功能的限制或性能瓶颈。 |
DB-GPT | 1、适合围绕数据库构建大模型应用的企业和个人。 2、适合对模型管理、数据处理和问答体验要求高的场景。 | 1、多模型管理:DB-GPT支持多种开源和API代理的大语言模型,管理功能强大。 2、Text2SQL效果优化:优化了Text2SQL任务,提高应用智能化水平。 3、RAG框架:基于RAG能力构建知识类应用。 4、数据驱动的Multi-Agents框架:支持自定义插件执行任务,智能体协作高效。 5、数据隐私和安全:注重数据隐私,通过私有化大模型、代理脱敏等技术保障数据安全。 | 相比其他框架,DB-GPT更侧重数据应用和模型管理,对某些特定场景支持不如其他框架全面。 |