构建高效的 Agents

过去一年里,我们与来自不同行业的数十个团队合作,共同开发基于大语言模型(LLM)的代理系统。我们发现一个持续的现象:最成功的实现并非依赖复杂的框架或专门的代码库,而是采用简单、可组合的模式构建。

在这篇文章中,我们将分享与客户合作以及自主构建代理系统过程中的经验,并为开发者提供一些实用建议。

什么是 Agents 代理?

"代理"(Agent)可以有多种定义方式。有些客户将代理定义为完全自主的系统,它们能够长期独立运行,利用各种工具完成复杂任务。

也有客户用这个术语来描述更具规范性的实现,即遵循预定义工作流程的系统。

在Anthropic,我们将这些变体都归类为代理型系统,但在架构上区分了工作流和代理:

  • • 工作流是通过预定义的代码路径来编排LLM和工具的系统。
  • • 而代理则是LLM能够动态指导自身的处理过程和工具使用的系统,它们能够自主控制任务的完成方式。

接下来,我们将详细探讨这两类代理型系统。

在附录1("代理的实践应用")中,我们会介绍客户在使用这些系统时发现特别有价值的两个领域。

何时(以及何时不)使用代理?

在构建基于LLM的应用时,我们建议先寻找最简单的解决方案,只在必要时才增加复杂性。这可能意味着完全不需要构建代理型系统。代理型系统通常会用延迟和成本来换取更好的任务表现,您需要考虑这种取舍是否值得。当确实需要更复杂的系统时,对于明确定义的任务,工作流能提供更好的可预测性和一致性;而当需要大规模的灵活性和模型驱动的决策时,代理则是更好的选择。不过,对于许多应用来说,优化单个LLM调用(配合检索和上下文示例)通常就足够了。

框架的使用时机和方式

目前有许多框架可以让代理系统的实现变得更简单,包括:

  • • 来自LangChain的LangGraph;
  • • 亚马逊Bedrock的AI代理框架;
  • • Rivet,一个拖放式的LLM工作流构建工具;
  • • Vellum,另一个用于构建和测试复杂工作流的图形界面工具。

这些框架通过简化标准的底层任务(如调用LLM、定义和解析工具、链接调用等),使入门变得容易。但是,它们往往会创建额外的抽象层,这可能会掩盖底层的提示和响应,使调试变得更困难。它们也可能诱使开发者在一个更简单的设置就足够的情况下增加不必要的复杂性。我们建议开发者直接从使用LLM API开始:许多模式只需要几行代码就能实现。如果您确实要使用框架,请确保理解底层代码。对框架内部机制的错误假设是客户常见的错误来源。具体实现示例请参考我们的操作指南。

构建模块、工作流和代理

在这一节中,我们将探讨在生产环境中常见的代理系统模式。

我们将从基础构建模块 —— 增强型LLM开始,逐步增加复杂度,从简单的组合工作流到自主代理。

构建模块:增强型LLM

代理系统的基本构建模块是经过增强的LLM,它具备检索、工具使用和记忆等功能。

我们当前的模型可以主动使用这些能力 —— 生成自己的搜索查询、选择合适的工具,并决定保留哪些信息。
02102654-2025-01-02T02:26:53.png
The augmented LLM

对于实现,我们建议重点关注两个方面:将这些功能针对性地适配您的具体用例,并确保为LLM提供简单、文档完备的接口。虽然实现这些增强功能的方式有很多,但其中一种方法是通过我们最近发布的模型上下文协议(Model Context Protocol),它允许开发者通过简单的客户端实现来集成不断增长的第三方工具生态系统。

在本文的剩余部分,我们将假设每个LLM调用都能访问这些增强功能。

工作流:提示链

提示链将任务分解为一系列步骤,每个LLM调用都会处理前一个调用的输出。

您可以在任何中间步骤添加程序化检查(参见下图中的"gate"),以确保整个流程仍在正轨上。
02102716-2025-01-02T02:27:15.png
The prompt chaining workflow

工作流的使用时机:这种工作流最适合那些可以轻松、清晰地分解为固定子任务的情况。

主要目标是通过让每个LLM调用处理更简单的任务来用延迟换取更高的准确性。

提示链的实用示例:

  • • 生成营销文案,然后将其翻译成其他语言
  • • 撰写文档大纲,检查大纲是否符合特定标准,然后基于大纲撰写文档

工作流:路由

路由会对输入进行分类,并将其引导至专门的后续任务。这种工作流允许关注点分离,并构建更专门化的提示。如果没有这种工作流,为某一类型输入优化可能会影响到其他输入的性能表现。
02102809-2025-01-02T02:28:09.png
The routing workflow

使用时机:路由适用于那些有明显不同类别、需要分开处理的复杂任务,且这些类别可以通过LLM或传统的分类模型/算法进行准确分类。

路由的实用示例:

  • • 将不同类型的客服查询(一般问题、退款请求、技术支持)引导到不同的下游流程、提示和工具
  • • 将简单/常见问题路由给较小的模型(如Claude 3.5 Haiku),将困难/特殊问题路由给更强大的模型(如Claude 3.5 Sonnet),以优化成本和速度

工作流:并行化

LLM有时可以同时处理任务,并通过程序化方式汇总其输出。这种并行化工作流主要有两种关键变体:

  • • 分段:将任务拆分为并行运行的独立子任务
  • • 投票:多次运行相同任务以获得多样化的输出
    02103334-2025-01-02T02:33:33.png
    The parallelization workflow

使用时机

  • • 并行化在以下情况下特别有效:
  • • 一是可以将子任务并行化以提高速度
  • • 二是需要多个视角或尝试来获得更高置信度的结果。
  • • 对于涉及多个考虑因素的复杂任务,当每个考虑因素由单独的LLM调用处理时,LLM通常表现更好,因为这允许对每个具体方面进行专注处理。

并行化的实用示例:

分段应用:

  • • 实现安全防护,其中一个模型实例处理用户查询,而另一个筛查不当内容或请求。这比让同一个LLM调用同时处理安全防护和核心响应的效果更好
  • • 自动化评估LLM性能,每个LLM调用评估模型在给定提示下的不同表现方面。

投票应用:

  • • 审查代码中的漏洞,多个不同的提示审查代码并在发现问题时进行标记。
  • • 评估给定内容是否不当,多个提示评估不同方面,或要求不同的投票阈值来平衡误报和漏报。

工作流:编排者-执行者

在编排者-执行者工作流中,一个中央LLM动态地分解任务,将它们分配给执行者LLM,并综合它们的结果。
02103348-2025-01-02T02:33:48.png
The orchestrator-workers workflow

使用时机

这种工作流非常适合那些无法预测所需子任务的复杂任务(例如,在编程中,需要修改的文件数量和每个文件中的修改性质可能都取决于具体任务)。

虽然在结构上与并行化类似,但关键区别在于其灵活性 —— 子任务不是预先定义的,而是由编排者根据具体输入来确定。

编排者-执行者工作流的实用示例:

  • • 需要对多个文件进行复杂修改的编程产品
  • • 涉及从多个来源收集和分析可能相关信息的搜索任务

工作流:评估者-优化者

在评估者-优化者工作流中,一个LLM调用生成响应,而另一个在循环中提供评估和反馈。
02103357-2025-01-02T02:33:56.png
The evaluator-optimizer workflow

使用时机

当我们有明确的评估标准,且迭代优化能带来可衡量的价值时,这种工作流特别有效。

判断是否适合使用这种工作流有两个标志:

  • • 首先,当人类明确表达反馈时,LLM的响应能够明显改善;
  • • 其次,LLM能够提供这样的反馈。这类似于人类作者在创作精良文档时可能经历的迭代写作过程。

评估者-优化者工作流的实用示例:

  • • 文学翻译,其中译者LLM最初可能无法捕捉到的细微差别可以通过评估者LLM的有用批评来改进。
  • • 需要多轮搜索和分析才能收集全面信息的复杂搜索任务,其中评估者决定是否需要进行更多搜索。

代理

随着LLM在关键能力上日趋成熟 —— 理解复杂输入、进行推理和规划、可靠地使用工具以及从错误中恢复,代理系统正在生产环境中逐渐兴起。代理通过接收用户的指令或与用户进行交互对话来开始工作。一旦任务明确,代理就会独立规划和运行,必要时会向用户寻求更多信息或判断。在执行过程中,代理需要在每个步骤都从环境中获取"基准事实"(如工具调用结果或代码执行情况)来评估其进展。代理可以在检查点或遇到障碍时暂停等待人类反馈。任务通常在完成时终止,但也常常包含停止条件(如最大迭代次数)以保持控制。

代理可以处理复杂的任务,但其实现往往很直接。它们通常就是基于环境反馈在循环中使用工具的LLM。因此,清晰、周到地设计工具集及其文档至关重要。

我们在附录2("工具的提示工程")中详细展开了工具开发的最佳实践。
02103407-2025-01-02T02:34:06.png
Autonomous agent

使用时机

代理适用于难以或无法预测所需步骤数量的开放性问题,以及无法硬编码固定路径的场景。LLM可能需要运行多个回合,因此您必须对其决策能力有一定程度的信任。代理的自主性使其非常适合在可信环境中扩展任务。代理的自主特性意味着更高的成本,以及错误累积的可能性。我们建议在沙盒环境中进行广泛测试,并配备适当的安全防护措施。

代理的实用示例:

以下是我们自己实现的例子:

  • • 一个用于解决SWE-bench任务的编码代理,该任务涉及根据任务描述对多个文件进行编辑
  • • 我们的"计算机使用"参考实现,其中Claude使用计算机来完成任务
    02103430-2025-01-02T02:34:29.png
    High-level flow of a coding agent

组合和定制这些模式

这些构建模块并非强制性的规范。它们是开发者可以根据不同用例来塑造和组合的常见模式。与任何LLM功能一样,成功的关键在于衡量性能并迭代实现。

需要重申的是:只有在确实能够改善结果的情况下,才考虑增加复杂性。

总结

在LLM领域取得成功并不在于构建最复杂的系统,而在于构建最适合您需求的系统。

从简单的提示开始,通过全面的评估来优化它们,只有在更简单的解决方案不足以满足需求时,才添加多步骤的代理系统。

在实现代理时,我们遵循三个核心原则:

  • • 保持代理设计的简单性
  • • 通过明确展示代理的规划步骤来确保透明度
  • • 通过全面的工具文档和测试来精心设计代理-计算机接口(ACI)

框架可以帮助您快速入门,但当转向生产环境时,不要犹豫于减少抽象层并使用基本组件构建。通过遵循这些原则,您可以创建既强大又可靠、可维护,并能获得用户信任的代理系统。

致谢

本文由Erik Schluntz和Barry Zhang撰写。

这项工作源于我们在Anthropic构建代理的经验,以及客户分享的宝贵见解,我们对此深表感谢。

原文:《Building effective agents》 https://www.anthropic.com/research/building-effective-agents