获取开发者通讯
产品更新、操作指南、社区聚焦等。每月发送至您的收件箱。
*注意:自 2024 年 12 月以来,本文中描述的许多工具生态已发生变化。关于我们当前的方法,请参阅 *
在本文中,我们分享了从与客户合作以及自行构建代理中学到的经验,并为开发者提供了构建有效代理的实用建议。
“代理”可以有多种定义方式。一些客户将代理定义为完全自主的系统,能够在较长时间内独立运行,使用各种工具完成复杂任务。其他人则用该术语描述遵循预定义工作流的更具规范性的实现。在 Anthropic,我们将所有这些变体归类为代理系统,但在工作流和代理之间划出了重要的架构区分:
下面,我们将详细探讨这两种类型的代理系统。在附录 1(“实践中的代理”)中,我们描述了客户在使用这类系统时发现特别有价值的两个领域。
在使用 LLM 构建应用程序时,我们建议寻找最简单的解决方案,仅在需要时增加复杂性。这可能意味着根本不构建代理系统。代理系统通常以延迟和成本换取更好的任务性能,您应该考虑这种权衡何时有意义。
当需要更高复杂性时,工作流为定义明确的任务提供可预测性和一致性,而当需要大规模灵活性和模型驱动的决策时,代理是更好的选择。然而,对于许多应用来说,通过检索和上下文示例优化单个 LLM 调用通常就足够了。
有许多框架可以使代理系统更易于实现,包括:
这些框架通过简化调用 LLM、定义和解析工具以及将调用链接在一起等标准底层任务,使入门变得容易。然而,它们通常会创建额外的抽象层,可能掩盖底层的提示和响应,使其更难调试。当更简单的设置就足够时,它们也可能诱使人们增加复杂性。
我们建议开发者从直接使用 LLM API 开始:许多模式可以用几行代码实现。如果您确实使用框架,请确保理解底层代码。对底层机制的错误假设是客户错误的常见来源。
请参阅我们的食谱获取一些示例实现。
在本节中,我们将探讨在生产环境中看到的代理系统的常见模式。我们将从基础构建块——增强型 LLM——开始,逐步增加复杂性,从简单的组合工作流到自主代理。
代理系统的基本构建块是一个通过检索、工具和记忆等增强功能增强的 LLM。我们当前的模型可以主动使用这些能力——生成自己的搜索查询、选择合适的工具,并确定要保留哪些信息。
我们建议重点关注实现中的两个关键方面:根据你的具体用例定制这些能力,并确保它们为你的 LLM 提供一个简单且文档完善的接口。虽然实现这些增强功能的方法有很多,但其中一种方式是通过我们最近发布的 Model Context Protocol,它允许开发者通过一个简单的 客户端实现 与不断增长的第三方工具生态系统集成。
在本文的剩余部分,我们将假设每次 LLM 调用都可以访问这些增强能力。
提示链将任务分解为一系列步骤,其中每次 LLM 调用都会处理上一次调用的输出。你可以在任何中间步骤上添加程序化检查(见下图中的“gate”),以确保流程仍在正轨上。
何时使用此工作流: 当任务可以轻松且清晰地分解为固定子任务时,此工作流非常理想。主要目标是通过让每次 LLM 调用都成为更简单的任务,以延迟换取更高的准确性。
提示链有用的示例:
路由会对输入进行分类,并将其引导到专门的后续任务。此工作流允许关注点分离,并构建更专门的提示。如果没有此工作流,针对一种输入进行优化可能会损害其他输入上的性能。
何时使用此工作流: 对于存在明显类别且更适合分别处理的复杂任务,并且分类可以由 LLM 或更传统的分类模型/算法准确完成时,路由效果很好。
路由有用的示例:
LLM 有时可以同时处理一个任务,并以程序化方式聚合它们的输出。此工作流,即并行化,表现为两个关键变体:
何时使用此工作流: 当拆分后的子任务可以并行化以提升速度,或者需要多个视角或尝试以获得更高置信度的结果时,并行化是有效的。对于具有多个考虑因素的复杂任务,当每个考虑因素都由单独的 LLM 调用处理时,LLM 通常表现更好,因为这样可以专注于每个具体方面。
并行化有用的示例:
在编排器-工作者工作流中,一个中央 LLM 动态分解任务,将其委派给工作者 LLM,并综合它们的结果。
何时使用此工作流: 此工作流非常适合无法预测所需子任务的复杂任务(例如在编码中,需要更改的文件数量以及每个文件中更改的性质很可能取决于任务)。虽然它在拓扑上相似,但与并行化的关键区别在于其灵活性——子任务不是预先定义的,而是由编排器根据具体输入确定的。
编排器-工作者有用的示例:
在评估器-优化器工作流中,一次 LLM 调用生成响应,而另一次则在循环中提供评估和反馈。
何时使用此工作流: 当我们有明确的评估标准,并且迭代改进能提供可衡量的价值时,此工作流特别有效。良好契合的两个标志是:第一,当人类阐明其反馈时,LLM 的响应能够被明显改进;第二,LLM 能够提供这样的反馈。这类似于人类作者在撰写一份精炼文档时可能经历的迭代写作过程。
评估器-优化器有用的示例:
随着 LLM 在关键能力上的成熟——理解复杂输入、进行推理和规划、可靠地使用工具以及从错误中恢复——代理正在生产环境中涌现。代理从人类用户的命令或交互式讨论开始其工作。一旦任务明确,代理就会独立计划和操作,可能会返回人类以获取更多信息或判断。在执行过程中,代理在每一步从环境获取“地面真相”(例如工具调用结果或代码执行)以评估其进展至关重要。然后,代理可以在检查点或遇到阻碍时暂停以获取人类反馈。任务通常在完成后终止,但包含停止条件(例如最大迭代次数)以保持控制也很常见。
代理可以处理复杂的任务,但其实现通常很直接。它们通常只是 LLM 在循环中根据环境反馈使用工具。因此,清晰地、深思熟虑地设计工具集及其文档至关重要。我们在附录 2(“为你的工具进行提示工程”)中扩展了工具开发的最佳实践。
何时使用代理: 代理可用于开放式问题,其中难以或不可能预测所需的步骤数,并且无法硬编码固定路径。LLM 可能会运行多轮,你必须对其决策有一定程度的信任。代理的自主性使其成为在可信环境中扩展任务的理想选择。
代理的自主性意味着更高的成本和复合错误的可能性。我们建议在沙盒环境中进行广泛测试,并配备适当的护栏。
代理有用的示例:
以下示例来自我们自己的实现:
这些构建块并非规定性的。它们是常见模式,开发者可以根据不同的用例进行塑造和组合。成功的关键,与任何 LLM 功能一样,是衡量性能并迭代实现。重复一遍:你应该考虑添加复杂性仅当它明显改善结果时。
在 LLM 领域的成功不在于构建最复杂的系统。而在于为你的需求构建正确的系统。从简单的提示开始,通过全面评估优化它们,并仅在更简单的解决方案不足时添加多步代理系统。
在实现代理时,我们尝试遵循三个核心原则:
框架可以帮助你快速开始,但在转向生产时,不要犹豫减少抽象层并使用基本组件构建。通过遵循这些原则,你可以创建不仅强大而且可靠、可维护且受用户信任的代理。
作者:Erik S. 和 Barry Zhang。本项工作借鉴了我们在 Anthropic 构建代理的经验以及客户分享的宝贵见解,对此我们深表感激。
我们与客户的合作揭示了两个特别有前景的 AI 代理应用,它们展示了上述模式的实际价值。这两个应用都说明了代理在为既需要对话又需要行动、具有明确成功标准、能够实现反馈循环并融入有意义的人类监督的任务中如何发挥最大价值。
客户支持将熟悉的聊天机器人界面与通过工具集成增强的能力相结合。这对于更开放的代理来说是一个自然的契合,因为:
多家公司通过基于使用量的定价模式展示了这种方法的可行性,该模式仅对成功解决收费,显示了对其代理有效性的信心。
软件开发领域已经显示出 LLM 功能的显著潜力,其能力从代码补全发展到自主问题解决。代理特别有效,因为:
在我们自己的实现中,代理现在仅根据拉取请求描述就能在 SWE-bench Verified 基准测试中解决真实的 GitHub 问题。然而,尽管自动化测试有助于验证功能,但人工审查对于确保解决方案符合更广泛的系统要求仍然至关重要。
无论你正在构建哪种代理系统,工具都可能是你的代理的重要组成部分。工具 使 Claude 能够通过在我们的 API 中指定其确切结构和定义来与外部服务和 API 交互。当 Claude 响应时,如果它计划调用工具,它将在 API 响应中包含一个 工具使用块。工具定义和规范应该像你的整体提示一样受到同等的提示工程关注。在这个简短的附录中,我们描述了如何对你的工具进行提示工程。
通常有多种方式指定相同的操作。例如,你可以通过编写差异或重写整个文件来指定文件编辑。对于结构化输出,你可以在 markdown 或 JSON 中返回代码。在软件工程中,这些差异是表面性的,可以无损地相互转换。然而,有些格式对 LLM 来说比其他格式难写得多。编写差异需要在编写新代码之前知道块头中有多少行在变化。在 JSON 中编写代码(与 markdown 相比)需要对换行符和引号进行额外的转义。
我们关于决定工具格式的建议如下:
一个经验法则是考虑在人机界面(HCI)上投入了多少努力,并计划在创建良好的 代理-计算机界面(ACI)上投入同样多的努力。以下是一些关于如何做到这一点的想法:
在构建用于 SWE-bench 的 agent 时,我们实际上花在优化工具上的时间比花在整体提示词上的时间更多。例如,我们发现,在 agent 移出根目录后,模型会在使用相对文件路径的工具时出错。为了解决这个问题,我们修改了工具,使其始终要求使用绝对文件路径——结果我们发现模型完美地使用了这种方法。
产品更新、操作指南、社区聚焦等。每月发送到你的收件箱。
