Anthropic 发布的 Agent 开发指南,系统阐述高效可靠 Agent 的设计原理和实现方案。对 Agent 开发者有重大参考价值。
过去一年,我们与来自各行各业的数十个团队合作,帮助他们构建大语言模型 (LLM) agent。我们一致地发现,最成功的实现并未使用复杂的框架或专用库。相反,它们都在采用简单的、可组合的模式。
在这篇文章中,我们分享从与客户合作以及自己构建 agent 中学到的经验,并为开发者提供构建有效 agent 的实用建议。
"Agent" 的定义有多种方式。有些客户将 agent 定义为完全自主的系统,可以在长期内独立运作,使用各种工具完成复杂任务。有些则用这个术语描述遵循预定义工作流的更具约束性的实现。在 Anthropic,我们将所有这些变体都归类为 agent 系统,但在工作流和 agent 之间进行了重要的架构区分:
工作流是指 LLM 和工具通过预定义代码路径进行编排的系统。
而 agent 则是指 LLM 动态指导自身流程和工具使用的系统,保持对如何完成任务的控制权。
下面我们将详细探讨这两种 agent 系统。在附录 1("Agents in Practice")中,我们描述了两个客户发现这些系统特别有价值的领域。
在使用 LLM 构建应用时,我们建议找到最简单的可行方案,只在必要时增加复杂度。这可能意味着根本不构建 agent 系统。Agent 系统通常是用更高的延迟和成本换取更好的任务表现,你应该考虑这种权衡何时是值得的。
当需要更多复杂性时,工作流为定义明确的任务提供可预测性和一致性,而 agent 则是在需要灵活性和模型驱动决策来大规模处理时的更好选择。但对于许多应用来说,用检索和上下文示例优化单个 LLM 调用通常就足够了。
有许多框架可以使 agent 系统的实现更容易,包括:
Claude Agent SDK;
AWS 的 Strands Agents SDK;
Rivet,一个拖拽式 GUI LLM 工作流构建器;以及
Vellum,另一个用于构建和测试复杂工作流的 GUI 工具。
这些框架通过简化调用 LLM、定义和解析工具、链接调用等标准低级任务,使入门变得容易。但是,它们常常创建额外的抽象层,这可能会模糊底层提示和响应,使调试变得更困难。它们也可能诱使你在更简单的设置就足够时增加不必要的复杂性。
我们建议开发者从直接使用 LLM API 开始:许多模式可以用几行代码实现。如果你确实使用框架,要确保你理解底层代码。对框架内部工作方式的错误假设是导致客户出错的常见原因。
参考我们的 cookbook 获取一些示例实现。
在本节中,我们将探讨在生产环境中看到的 agent 系统的常见模式。我们将从基础构建块——增强型 LLM——开始,逐步增加复杂性,从简单的组合工作流到自主 agent。
Agent 系统的基本构建块是用增强功能(如检索、工具和记忆)增强的 LLM。我们当前的模型能够主动使用这些能力——生成自己的搜索查询、选择合适的工具,以及确定保留哪些信息。
我们建议关注实现的两个关键方面:根据你的具体用例定制这些能力,并确保为 LLM 提供简单、文档完善的接口。虽然实现这些增强功能有许多方式,一种方法是通过我们最近发布的 Model Context Protocol,它允许开发者通过简单的客户端实现与日益增长的第三方工具生态系统集成。
在本文的其余部分,我们将假设每个 LLM 调用都能访问这些增强能力。
Prompt chaining 将任务分解为一系列步骤,其中每个 LLM 调用处理前一个的输出。你可以在任何中间步骤上添加程序检查(参见下图中的"gate")以确保流程仍在正轨上。
何时使用此工作流: 当任务可以轻松地、完整地分解为固定子任务时,此工作流最理想。主要目标是通过使每个 LLM 调用都变成更简单的任务来权衡延迟以换取更高的准确性。
Prompt chaining 有用的例子:
生成营销文案,然后将其翻译成不同的语言。
编写文档大纲,检查大纲是否符合某些标准,然后基于大纲编写文档。
Routing 对输入进行分类并将其指向专门的后续任务。这个工作流允许关注点分离,并构建更专门化的提示。没有这个工作流,为一种输入优化可能会损害对其他输入的表现。
何时使用此工作流: Routing 适用于有明确的、最好单独处理的不同类别的复杂任务,且分类可以由 LLM 或更传统的分类模型/算法准确处理。
Routing 有用的例子:
将不同类型的客户服务查询(常规问题、退款请求、技术支持)指向不同的下游流程、提示和工具。
将简单/常见问题路由到较小、成本高效的模型(如 Claude Haiku 4.5),将困难/不常见的问题路由到更强大的模型(如 Claude Sonnet 4.5)以优化最佳表现。
LLM 有时可以同时处理任务,并通过程序方式聚合其输出。这种工作流——parallelization——表现为两个关键变体:
Sectioning: 将任务分解为并行运行的独立子任务。
Voting: 多次运行相同任务以获得不同的输出。
何时使用此工作流: 当分割的子任务可以并行化以提高速度,或当需要多个视角或尝试以获得更高的信心结果时,parallelization 是有效的。对于有多个考量的复杂任务,LLM 通常在每个考量由单独的 LLM 调用处理时表现更好,允许对每个特定方面集中关注。
Parallelization 有用的例子:
Sectioning:
实现护栏,其中一个模型实例处理用户查询,而另一个则筛选不当内容或请求。这往往比同一 LLM 调用同时处理护栏和核心响应表现更好。
为评估 LLM 表现而自动化评估,其中每个 LLM 调用评估模型在给定提示上表现的不同方面。
Voting:
审查代码漏洞,其中多个不同的提示审查代码并在发现问题时标记。
评估给定的内容是否不当,多个提示评估不同方面或需要不同的投票阈值以平衡假阳性和假阴性。
在 orchestrator-workers 工作流中,中央 LLM 动态地分解任务、将其委派给 worker LLM,并综合它们的结果。
何时使用此工作流: 此工作流适合无法预测所需子任务的复杂任务(例如在编码中,需要更改的文件数量和每个文件中更改的性质可能取决于任务)。虽然在拓扑上类似,但与 parallelization 的关键区别在于其灵活性——子任务不是预定义的,而是由 orchestrator 根据特定输入确定的。
Orchestrator-workers 有用的例子:
编码产品,每次都对多个文件进行复杂更改。
涉及从多个来源收集和分析信息以寻找可能相关信息的搜索任务。
在 evaluator-optimizer 工作流中,一个 LLM 调用生成响应,而另一个在循环中提供评估和反馈。
何时使用此工作流: 当我们有明确的评估标准,以及迭代改进能提供可衡量的价值时,此工作流特别有效。良好匹配的两个信号是,首先,当人类表述反馈时,LLM 响应可以明显改进;其次,LLM 可以提供这样的反馈。这类似于人类作者在创作精美文档时经历的迭代写作过程。
Evaluator-optimizer 有用的例子:
文学翻译,其中有翻译 LLM 最初可能无法捕捉的细微差别,但评估 LLM 可以提供有用的批评。
需要多轮搜索和分析以收集全面信息的复杂搜索任务,其中评估器决定是否需要进一步搜索。
随着 LLM 在关键能力上的成熟——理解复杂输入、进行推理和规划、可靠地使用工具以及从错误中恢复——agent 正在生产环境中出现。Agent 从用户的命令或与人类用户的互动讨论开始其工作。一旦任务明确,agent 就会计划和独立操作,可能会为了获取进一步的信息或判断而回到人类。在执行过程中,agent 在每个步骤获得来自环境的"地面真实"(如工具调用结果或代码执行)至关重要,以评估其进展。Agent 可以在检查点或遇到阻碍时暂停以获取人类反馈。任务通常在完成时终止,但也常见包含停止条件(如最大迭代次数)以保持控制。
Agent 可以处理复杂的任务,但它们的实现通常很直接。它们通常只是在循环中基于环境反馈使用工具的 LLM。因此,清晰而深思熟虑地设计工具集及其文档至关重要。我们在附录 2("Prompt Engineering your Tools")中详细阐述了工具开发的最佳实践。
何时使用 agent: Agent 可用于难以或不可能预测所需步骤数量的开放式问题,以及无法硬编码固定路径的问题。LLM 可能会运行许多轮,你必须在某种程度上信任其决策能力。Agent 的自主性使其非常适合在受信环境中扩展任务。
Agent 的自主性意味着更高的成本以及潜在的复合错误。我们建议在沙箱环境中进行广泛测试,以及适当的护栏。
Agent 有用的例子:
以下示例来自我们自己的实现:
编码 Agent,用于解决 SWE-bench 任务,涉及基于任务描述对多个文件的编辑;
我们的"computer use"参考实现,其中 Claude 使用计算机完成任务。
这些构建块不是规范性的。它们是开发者可以塑造和组合以适应不同用例的常见模式。成功的关键,就像 LLM 功能的任何其他方面一样,是测量表现并迭代实现。重复一遍:你应该只在明确改进结果时考虑增加复杂性。
LLM 空间的成功不是关于构建最复杂的系统。而是关于为你的需求构建正确的系统。从简单提示开始,用全面的评估优化它们,只有当更简单的解决方案不足时才添加多步 agent 系统。
在实现 agent 时,我们尝试遵循三个核心原则:
在 agent 的设计中保持简洁。
通过明确显示 agent 的规划步骤来优先考虑透明性。
通过彻底的工具文档和测试精心设计你的 agent-computer 接口 (ACI)。
框架可以帮助你快速入门,但在向生产过渡时不要犹豫,减少抽象层并用基本组件构建。通过遵循这些原则,你可以创建不仅强大而且可靠、可维护并为用户所信任的 agent。
由 Erik S. 和 Barry Zhang 撰写。这项工作基于我们在 Anthropic 构建 agent 的经验以及客户分享的宝贵见解,对此我们深表感谢。
我们与客户的合作揭示了两个特别有前景的 AI agent 应用,这些应用展示了上述模式讨论的实际价值。两个应用都说明了 agent 在需要对话和行动、有明确的成功标准、能够实现反馈循环、集成有意义的人工监督的任务中如何增加最大价值。
客户支持结合了熟悉的聊天机器人界面与通过工具集成增强的能力。这对于更开放式的 agent 是一个很自然的适配,因为:
支持交互自然地遵循对话流,同时需要访问外部信息和操作;
工具可以被集成以提取客户数据、订单历史和知识库文章;
诸如发放退款或更新工单等操作可以通过程序处理;以及
成功可以通过用户定义的解决方案清晰地测量。
多家公司通过使用基于使用量的定价模型(只对成功的解决方案收费)展示了这种方法的可行性,显示出对其 agent 有效性的信心。
软件开发领域展现了 LLM 功能的显著潜力,能力从代码完成演进到自主问题解决。Agent 特别有效,因为:
代码解决方案可通过自动化测试验证;
Agent 可以使用测试结果作为反馈来迭代解决方案;
问题空间定义明确且结构化;以及
输出质量可以客观地测量。
在我们自己的实现中,agent 现在可以仅基于拉取请求描述就在 SWE-bench Verified 基准上解决真实的 GitHub 问题。然而,虽然自动化测试有助于验证功能,人工审查仍然对于确保解决方案与更广泛的系统需求保持一致至关重要。
无论你构建的是哪种 agent 系统,工具都可能是你的 agent 的重要部分。工具使 Claude 能够通过在我们的 API 中指定其确切结构和定义来与外部服务和 API 交互。当 Claude 响应时,如果它计划调用工具,API 响应中将包含工具使用块。工具定义和规范应该获得与总体提示同样多的 prompt engineering 关注。在这个简短的附录中,我们描述了如何对你的工具进行 prompt engineering。
通常有多种方式来指定相同的操作。例如,你可以通过编写 diff 或重写整个文件来指定文件编辑。对于结构化输出,你可以在 markdown 中或在 JSON 中返回代码。在软件工程中,这样的差异在语义上是装饰性的,可以从一种无损地转换为另一种。但是,有些格式对 LLM 来说比其他格式更容易编写。编写 diff 需要知道在写入新代码之前块头中有多少行在更改。在 JSON 中写入代码(相比 markdown)需要额外对换行符和引号进行转义。
我们对决定工具格式的建议如下:
给模型足够的 token 来"思考",以免它把自己逼到角落里。
保持格式接近模型在互联网上的文本中自然出现的样子。
确保没有格式"开销",如需要保持数千行代码的准确计数,或对它编写的任何代码进行字符串转义。
一个经验法则是考虑人机界面 (HCI) 花费了多少努力,并计划投入同样多的努力来创建良好的 agent-computer 接口 (ACI)。以下是如何做到这一点的一些思考:
设身处地为模型着想。基于描述和参数,使用这个工具是否很明显,还是需要仔细思考?如果是后者,模型也可能是这样。一个好的工具定义通常包括使用示例、边界情况、输入格式要求和与其他工具的清晰边界。
你如何通过改变参数名称或描述来使事情更明显?把这想象成为你团队中的初级开发人员编写一个很好的文档字符串。当使用许多类似工具时这特别重要。
测试模型如何使用你的工具:在我们的 workbench 中运行许多示例输入,看看模型犯了什么错误,并进行迭代。
Poka-yoke 你的工具。改变参数使其更难犯错。
在为 SWE-bench 构建我们的 agent 时,我们实际上花了更多时间优化工具而不是整体提示。例如,我们发现当 agent 移出根目录后,模型会在使用相对文件路径的工具上犯错。为了解决这个问题,我们改变了工具以始终需要绝对文件路径——我们发现模型无缺陷地使用了这种方法。