04 Agent 框架


尽管本文提出了构建成功的 AI 驱动应用和 Agent 的许多主要组成部分,但绝大部分工作都落在技术栈的四个不同部分上,我们称之为「四大要素」:

  • LLMs,作为应用的智能核心
  • 代码,增强 LLM 并将其连接到现实世界
  • 数据库,作为模型的内存和知识存储库
  • 其他模型,为 LLM 和代码提供额外的功能

我们的观点是,随着这些应用的成熟,技术栈中的其他部分,如中间件和安全工具,将变得更加重要。 但目前,这四个要素是驱动像 Rask 这样的 AI 驱动应用的关键,Rask 可以在60种语言中以原始内容创作者的声音进行本地化,还有像 Aomni 这样能够研究任何主题并提供详细报告的应用。

此外,我们预计测试软件将变得更加重要。对于传统软件,编写单元测试和回归测试很容易,以确保新功能或错误修复不会以意外的方式破坏软件。 但是对于 Agent 和 AI 驱动应用程序来说,这是一项挑战,因为通常需要人类查看结果并决定其质量,这是不可扩展的。

如今,我们与绝大多数生产级应用程序开发人员交流时了解到,他们更倾向于使用自己编写的自定义代码和框架,而不是目前存在的主要 Agent 框架之一,例如 LangChainHaystackSemantic KernelLlamaIndex 。 虽然这些框架在该领域的新开发人员和原型阶段拥有大量用户,但我们发现许多复杂团队在进一步发展时会编写适用于自己应用程序的专门框架。

这并不让人感到意外。Agent、生成式 AI 和 AI 驱动应用程序仍然是非常新颖的领域。开发人员和设计师只是在探索如何有效构建它们。 在 AIIA,我们相信模块化和真正的抽象将是长期胜出并成为未来 Agent 的代码编写方式的关键。 这与我们在社区中联系到的开发人员以及 Reddit 等地方的公开帖子中的人们谈论他们的经验是一致的

我的工作流程主要涉及从 Pinecone 查询文本,然后使用 Hugging Face 的模型或者 Lllama.cpp 版本的模型。 我在 Pinecone 中将元数据与嵌入一起存储,并希望基于此进行过滤。

随着过滤器和条件的增加,使用 Pinecone 进行文本检索变得非常繁琐。最终,我将整个代码进行了重写,去掉了 LLMs 链,将代码分解为查询/检索类、提示创建函数和文本生成类。
这样,代码具有模块化的特点。可以在不修改完整链条和每次传递所有元数据过滤器的情况下检查提示和文本生成的性能。
—— Reddit 节选

它们与传统的确定性应用程序是非常不同的类型。最佳的设计模式、抽象和解决方案需要时间才能出现。 这是任何早期生态系统的典型特征。容器管理的理想方式花费了十年的时间,有许多解决方案争夺优势,在此过程中,Google 开发者的 Borg,然后是 Omega,最后是 Kubernetes 根据他们在过程中学到的东西进行了建设。

随着时间的推移,这些框架将不断成熟,并在向开发人员提供正确的抽象方面变得更加出色,节省他们的时间和精力,但在目前阶段,称其为赢家还为时过早。 此外,许多这些框架已经显示出足够好的吸引力,吸引了风险投资,因此预计它们的代码基础将在未来几年中迅速演变。

现在,让我们依次简要介绍每个最知名的框架,我们明白我们无法在这里全面涵盖它们,但我们将概述它们的基本基准能力。

LangChain 目前是最受欢迎的框架之一。该团队最近在种子轮融资中筹集了1000万美元,估值2亿美元的A轮融资又筹集了2000万至2500万美元。

LangChain 最初由 Harrison Chase 开发,是一个用于与 OpenAI 的 GPT API 进行交互的 Python 和 JavaScript 库,后来该框架扩展了更多模型。 LangChain 的想法来自于 DeepMind、Google Brain等研究人员撰写的论文《ReAct: Synergizing Reasoning and Acting in Language Models》,通常称为 ReAct 论文。该论文展示了一种提示技术,通过使用预定义的工具集(例如搜索互联网)让模型进行更好的推理和采取更好的行动。 推理和行动的双重打击已经成为一种流行的工作流程,通常可以改善输出并使 LLMs 更有效地解决问题。

react-paper-x

ReAct 工作流对于 InstructGPT/text-davinci-003 模型,也就是 GPT-3,是有效的,但对于 GPT-4 来说并没有被证明同样有效或必要。 时间将告诉我们,资金的激增是否有助于生态系统以智能和平衡的方式发展,从而为 Agent 和智能应用程序开发人员带来真正的价值。 目前,LangChain 社区非常庞大,网络效应通常可以引导一个项目走向伟大,如果能吸引懂得抽象的优秀开发人员。

其核心思想,LangChain 允许开发人员创建一个 「chained」 应用程序,即一系列对组件的调用,这些组件可以包括其他链。

LangChain 在继续发展,由于他们获得了广泛的支持和资金,未来几年可能会发生巨大的变化,但目前基本组件如下:

组件名称 描述
Model I/O 模型I/O 与语言模型进行输入/输出的主要接口。
Indexes 索引 用于检索应用程序特定的数据,如PDF、网页、数据库等。
Chains 允许开发人员构建对外部工具和 LLM 进行硬编码调用的序列。
Agents 代理 给予 LLM 更多自主权,选择实现高级目标的最佳方式,如使用API,而不是硬编码链条。
Memory 内存 允许开发人员在链的运行之间保持应用程序状态。
Callbacks 回调 记录和流式传输任何链的中间步骤

LangChain 是最早采用代理式方法构建模型的之一,这意味着 LLMs 在与 API 交互时,执行很多逻辑和规划,或者找出正确的事件序列。 现在大多数框架都在迅速转向这一点。微软的 Semantic Kernel 已经具备了这些能力,并且团队越来越倾向于使用它。Agent 与链的主要区别在于代替程序员选择行动的顺序,LLM 选择行动的顺序。 在链中,行动的顺序是硬编码的(在代码中)。而在 Agent 中,使用语言模型作为推理引擎来确定采取哪些行动以及顺序。

代理组件在原始 ReAct 概念的基础上继续发展。目前,这基本上是一种提示策略,可以包括以下内容:

  • Agent 的个性(有助于以特定方式回应)
  • Agent 的背景上下文(有助于为其提供更多关于所要执行任务类型的上下文)
  • 调用更好推理的提示策略(最著名/广泛使用的是 ReAct

LlamaIndex 是另一个流行的框架,开发人员已经尝试过或将其融入到他们的项目中。 LlamaIndex 更专注于作为一个「数据框架」,帮助您构建 LLM 应用程序。 其 GitHub Readme 对其进行了很好的总结:

  • 提供数据连接器,用于导入您现有的数据源和数据格式(APIs、PDFs、Docs、SQL 等)。
  • 提供了一种将数据结构化(索引、图表)的方法,以便这些数据可以轻松与 LLM 一起使用。
  • 提供了一个高级的检索/查询接口,让您可以输入任何 LLM 输入提示,获取检索到的上下文和增强知识的输出。
  • 允许与外部应用程序框架(例如 LangChain、Flask、Docker、ChatGPT 等)进行轻松集成。

Haystack 存在的时间比其他工具要长一些,正如一位开发人员所指出的,它主要专注于提取式问答。 早期的开发工作主要集中在问题回答和检索方面,而 LangChain 更多地关注 Agent 和在早期就将精力放在那里。 Haystack 最初的重点是为应用程序构建者充分利用本地 Transformer 模型。它允许用户构建复杂的 NLP 流水线,用于摘要、文档相似度、语义搜索等。 他们最近还增加了更多的 Agent 能力,允许 Agent 使用预定义的提示控制来找到最适合任务的基础流水线或工具。

根据 Haystack 的文档,目前它支持以下功能:

Semantic Kernel(SK)是由微软团队开发的「轻量级软件开发工具包(SDK)」。 用于将 OpenAIAzure OpenAIHugging Face 等 LLM 与 C#、Python 和 Java 等传统编程语言进行集成。 Semantic Kernel 通过允许您定义可以在几行代码中 链接在一起的 plugins 来实现此目标。

与其他讨论过的框架相比,它更专注于推理和规划。例如,它可以生成达到目标的 planners,然后执行该计划。 这种高级抽象可能会成为未来所有 Agent 框架的基石,但目前 Semantic Kernel 对此最为依赖。

目前主要的缺点是项目在支持的三种语言中能力没有对齐,您可以在图表中看到。 特别是 Python 代码目前存在一些不足,这是一个遗憾,因为 Python 是机器学习和 Agent 开发以及智能应用程序中最常用的语言。

planner-support-old

注意:在文档翻译的时候,python 模块能力的不足已经有所改善。
planner-support-new

SK 支持提示模板化、函数链式调用、矢量化内存和智能规划,尽管所有这些功能仍在不断完善中。

SK 的最大目标之一是支持最新的人工智能研究中的设计模式,以便开发人员可以为其应用程序注入递归推理等复杂技能。 他们还采用了 OpenAI 插件规范作为自己的标准。

通过原生函数,您可以直接调用 C# 或 Python 代码,以便操作数据或执行其他操作。 原生函数就像您的 AI 应用程序的「手」一样。它们可以用于保存数据、检索数据以及执行在 LLMs 中不适合的代码中的任何其他操作(例如执行计算)。 SK 框架允许您创建两种类型的函数:

Function
描述
Semantic functions(语义函数) 使您的 AI 应用程序能够监听用户并以自然语言进行回应。SK 使用连接器来在 LLMs 之间传递这些请求和响应。
Native functions(原生函数) 允许内核直接调用 C# 或 Python 代码,以便您可以操作数据或执行其他操作。根据文档
…因此,原生函数有点像您的 AI 应用程序的「手」。它们可以用于保存数据、检索数据以及执行在 LLMs 中不适合的代码中的任何其他操作(例如执行计算)。
—— 摘自官方文档

planner 可能是 SK 最独特的部分,团队将继续致力于其发展,因为他们认为这是使他们的框架得到广泛应用和特殊的关键。

planner 是一个函数,它接收一个用户的请求,并返回一个计划,说明如何完成该请求。它允许 LLMs 混合和匹配已注册到内核的插件,以创建一系列步骤,类似于 LangChain 的 Agent 功能。 它使开发人员能够创建可能尚未考虑的原子函数。他们使用以下示例:

如果您有任务和日历事件插件,planner 可以将它们组合起来创建工作流程,例如 「当我去商店时提醒我买牛奶」 或 「明天提醒我给妈妈打电话」 ,而无需您明确为这些情景编写代码。
—— 摘自官方文档

planner 是可扩展的。这意味着有多种规划器可供选择,并且随着时间的推移,随着关于如何从 LLMs 中引发最佳推理的新论文和概念的出现,可能会有更多的 planner。 开发人员还可以编写自己的自定义 planner。

文档中给出了一些如何使用 planner 的示例

在幕后,planner 使用 LLM 提示生成计划。您可以通过导航到 Semantic Kernel 存储库中的 skprompt.txt 文件来查看 Sequential Planner 使用的提示。 您还可以查看 Python 基本 planner 使用的提示。
—— 摘自官方文档

在 AIIA 中,我们建议开发人员尝试许多不同的框架,不要害怕在生态系统发展的这个阶段选择自己的路线,但要准备好在框架成熟时可能放弃自己的解决方案。

重要的是要意识到所有这些框架都非常新颖,它们可能会消失、发生巨大变化,或者被全新的框架所取代。 目前,没有一个框架可以被视为完全适用于生产环境,尽管它们正在迅速朝着这个方向发展。

通过与开发人员进行广泛交流,并对历史上类似软件技术发展进行分析,我们认为这些框架最有可能在未来几年中发展或被替代。 在某个领域中,最佳的抽象解决方案是一个随时间逐渐发展的复杂问题。它需要许多工程师在较长时间内进行编码,并相互学习。 随着时间的推移,越来越多被接受的解决方案和处理类似问题的方法会逐渐收敛。

这些框架主要是用 Python 编写的,但 SK 还支持 C# 和 Java。 我们预计在未来几年中会有更多的语言获得更好的推广,特别是像 Rust 这样灵活的现代语言,尽管目前在这些语言中,主要的工具是微调或接口还可以满足需求。