Anthropic发了一篇Agent年度雄文,全是知识点。

今年,Agent 很流行,各大公司发布会都在提。有意思的是,关于 Agent 的说法却莫衷一是。一些公司仅仅在工作流中融入了一些 AI 技术,也宣称这是 Agent,让我很迷惑。直到今天阅读了这篇 Anthropic 团队撰写的文章,我才豁然开朗。
这篇文章清晰地说明了工作流与 Agent 之间的差异,并详细介绍了构建 Agent 的方法和思路。推荐你一定要看。
在过去的一年里,我们有幸与来自各行各业的数十个团队携手合作,共同致力于开发 LLM Agent。我们发现,最成功的实现并非依赖于复杂的框架或专用库,而是通过采用简洁且可组合的模式来构建。
在这篇文章中,我们将分享我们在与客户合作及自主构建 Agent 过程中积累的宝贵经验,并为开发者提供一些构建高效 Agent 的实用建议。

#01

什么是 Agent?
“Agent” 可以有多种定义。一些客户将其定义为能够自主操作并长时间独立执行任务的系统,这类系统能够利用各种工具来完成复杂的任务。而另一些客户则使用这个术语来描述那些遵循预定义工作流的系统。在 Anthropic,我们将所有这些变体统一归类为 Agent 系统,但在架构上我们明确区分了工作流和 Agent:
  • 工作流系统是通过预定义的代码路径来协调 LLM 和工具的系统。

  • Agent 则是由 LLM 动态指导,自主执行任务的过程和工具使用,控制完成任务的方式。
接下来,我们将深入探讨这两种类型的 Agent 系统。在附录 1(“Agent 实践”)中,我们详细描述了客户发现使用这类系统特别有价值的两个领域。

#02

何时使用 Agent?
在利用 LLM 构建应用程序时,我们建议优先考虑最简单的解决方案,并仅在必要时增加复杂性。这有时意味着可能根本不需要构建 Agent 系统。Agent 系统通常以牺牲延迟和成本为代价,以换取更好的任务性能,因此在使用时需要仔细权衡这种取舍是否合理。
当确实需要更复杂的解决方案时,工作流系统能够为明确定义的任务提供可预测性和一致性。而当需要在 LLM 环境中进行灵活的、模型驱动的决策时,Agent 则成为更优的选择。然而,对于许多应用场景而言,通过检索和上下文示例来优化单次 LLM 调用通常已经足够。

#03

使用框架的时机与方式
有许多框架可以使 Agent 系统的实现更加简便,包括:
  • LangChain 的 LangGraph:https://langchain-ai.github.io/langgraph/

  • Amazon Bedrock 的 AI Agent 框架:https://aws.amazon.com/bedrock/agents/

  • Rivet,一个拖放式图形用户界面(GUI)LLM Workflow 构建器:https://rivet.ironcladapp.com/

  • Vellum,另一个用于构建和测试复杂 Workflow 的 GUI 工具:https://www.vellum.ai/
这些框架通过简化常规低级任务(如调用 LLM、定义和解析工具,以及串联调用)来帮助开发者快速入门。但是,它们常常会增加额外的抽象层,这可能会使底层的提示词和响应变得不够透明,进而增加调试的难度。它们也可能诱使开发者在简单设置已足够的情况下增加不必要的复杂性。
我们建议开发者直接使用 LLM API:许多模式可以通过几行代码来实现。如果使用框架,务必确保理解底层代码。对底层实现的错误假设是客户常见的错误源。
请参见我们的手册,了解一些示例实现:https://github.com/anthropics/anthropic-cookbook/tree/main/patterns/agents

#04

构建块、工作流和 Agent
在本节中,我们将探讨在生产环境中常见的 Agent 系统模式。我们将从基础构建块 —— 增强型 LLM 开始,并逐步增加复杂性,从简单的组合工作流到自主 Agent。
构建块:增强型 LLM
Agent 系统的基础构建块是经过增强的 LLM,通过检索、工具和记忆等功能进行增强。我们当前的模型能够主动使用这些功能 —— 生成自己的搜索查询、选择合适的工具,并决定哪些信息需要保留。
增强型 LLM
我们建议将实现的重点放在两个关键方面:一是根据特定的使用场景定制这些功能,二是确保它们为你的 LLM 提供一个简洁且文档完善的接口。尽管有多种方式可以实现这些增强功能,但其中一种方法是通过我们最近发布的模型上下文协议(Model Context Protocol),该协议允许开发者通过简单的客户端实现,与不断扩展的第三方工具生态系统进行集成。
在本文的其余部分,我们假设每次 LLM 调用都能够访问这些增强功能。
工作流:提示链
提示链将任务分解为一系列步骤,其中每个 LLM 调用都会处理前一步的输出。你可以在任何中间步骤中添加编程检查(见下图中的 “gate”)以确保流程仍然按预期进行。
提示链工作流
何时使用该工作流:该工作流非常适合于任务能够轻松且干净地分解为固定子任务的情况。主要目标是通过将每次 LLM 调用任务简化,从而以更高的准确性换取更低的延迟。
适用提示链调用的例子:
  • 生成市场营销文案,然后将其翻译成另一种语言。

  • 撰写文档的大纲,检查大纲是否满足某些标准,然后根据大纲编写文档。
工作流:路由
路由将输入进行分类,并将其引导至一个专门的后续任务。该工作流使得不同任务之间能够分离关注点,并构建更为专业化的提示词。没有这个工作流的情况下,优化某种输入可能会影响其他输入的性能。
路由工作流
何时使用该工作流:路由适用于那些任务复杂、存在明确分类并且这些分类最好单独处理的情况,且能够通过 LLM 或更传统的分类模型 / 算法准确完成分类的任务。
路由有用的示例:
  • 将不同类型的客户服务查询(如一般问题、退款请求、技术支持)分别引导到不同的下游流程、提示词和工具中。

  • 将简单或常见的问题路由到较小的模型(如 Claude 3.5 Haiku),而将复杂或不常见的问题路由到更强大的模型(如 Claude 3.5 Sonnet),以优化成本和速度。
工作流:并行化
LLM 有时可以同时执行一个任务,并以编程方式将它们的输出汇总。这个工作流 —— 并行化 —— 有两个主要变体:
  • 划分:将任务拆解为独立的子任务并行执行。

  • 投票:多次执行相同的任务以获取多样化的输出。
并行化工作流
何时使用该工作流:当拆分后的子任务可以并行化以提高处理速度,或者当需要多个视角或尝试以获得更高置信度的结果时。对于复杂任务,涉及多个因素时,通常当每个因素由独立的 LLM 调用处理时,LLM 的表现更佳,从而能够集中精力处理每个具体方面。
并行化有用的示例:
  • 划分:
  • 实现保护机制,其中一个模型实例处理用户查询,另一个实例筛查不当内容或请求。与让同一个 LLM 调用同时处理保护机制和核心响应相比,这种方法通常效果更好。

  • 自动化评估 LLM 的性能,其中每个 LLM 调用都会根据给定提示评估模型性能的不同方面。

  • 投票:
  • 审查代码中的漏洞,多个提示词审查并标记代码中的问题。

  • 评估给定内容是否不当,多个提示词评估不同方面或设置不同的投票阈值,以平衡假阳性和假阴性。
工作流:Orchestrator-workers
在 Orchestrator-workers 工作流中,中央 LLM 动态地将任务拆解并委派给工作者 LLM,最后将它们的结果合成。
Orchestrator-workers 工作流
何时使用该工作流:该工作流非常适用于那些无法预测所需子任务的复杂任务(例如在编程中,更改的文件数量及每个文件中需要的更改通常取决于具体任务)。尽管在形式上与并行化类似,但其关键区别在于灵活性 —— 子任务不是预定义的,而是由协调器根据特定的输入动态确定。
Orchestrator-workers 工作流的有用示例:
  • 编程产品,每次对多个文件进行复杂的更改。

  • 搜索任务,涉及从多个来源收集并分析信息以找到可能相关的内容。
工作流:Evaluator-optimizer
在 Evaluator-optimizer 工作流中,一个 LLM 调用生成响应,而另一个则提供评估和反馈,形成一个循环。
Evaluator-optimizer 工作流
何时使用该工作流:当我们有明确的评估标准,并且迭代优化能够带来可衡量的价值时尤其有效。两个适配的标志是:首先,LLM 的回应可以在人工反馈后明显改进;其次,LLM 能够提供这种反馈。这与人类作者在写作过程中进行的迭代式优化类似。
Evaluator-optimizer 工作流的有用示例:
  • 文学翻译,其中可能存在翻译 LLM 最初未捕捉到的细微差异,但评估者 LLM 可以提供有价值的反馈。

  • 复杂的搜索任务,涉及多轮搜索和分析以收集全面信息,评估者决定是否需要进一步的搜索。
Agent
随着 LLM 在理解复杂输入、进行推理与规划、可靠地使用工具以及从错误中恢复等关键能力上的不断进步,Agent 在实际生产环境中的应用开始展现其价值。这些 Agent 的工作流程通常始于人类用户的指令或与人类的互动讨论。一旦任务明确,Agent 便能够独立进行规划和执行,并且在需要时主动返回向人类获取更多信息或进行判断。
在执行过程中,Agent 必须在每个步骤获取 “真实情况”(例如工具调用结果或代码执行),以便评估进度。当遇到障碍或需要人类反馈时,Agent 会在检查点暂停。任务通常会在完成时终止,但通常也会设定停止条件(如最大迭代次数)来保持控制。
Agent 能够处理复杂的任务,但其实现方式通常是直接而简洁的。它们本质上是基于环境反馈,在循环中使用工具的 LLM因此,在设计工具集及其文档时,必须追求清晰度和深思熟虑。我们将在附录2(提示词工程与工具)中详细探讨工具开发的最佳实践。
自主 Agent
何时使用 Agent:Agent 特别适合处理那些步骤数量难以预测的开放性问题,以及那些无法通过硬编码固定路径来解决的场景。在这些情况下,LLM 可能需要执行多轮操作,这就要求用户对模型的决策过程保持一定程度的信任。Agent 的自主性使其在可信的环境中扩展任务时显得特别合适,能够灵活应对不断变化的需求和环境。
在考虑部署具有自主特性的 Agent 时,我们必须认识到这可能会带来更高的成本,并且有可能导致错误累积。因此,我们强烈建议在沙盒环境中对 Agent 进行彻底的测试,以确保其行为符合预期。
Agent 有用的示例:
以下是我们自己实现的一些示例:
  • 用于解决 SWE-bench 任务的编程 Agent,这些任务涉及根据任务描述对多个文件进行编辑:https://www.anthropic.com/research/swe-bench-sonnet
  • 我们的 “计算机使用” 参考实现,其中 Claude 使用计算机来完成任务:https://github.com/anthropics/anthropic-quickstarts/tree/main/computer-use-demo
编码 Agent 的高级流程

#05

结合和定制这些模式
这些构建模块并非强制性规定,而是常见的模式,开发者可以根据不同的使用场景进行调整和组合。像所有 LLM 功能一样,成功的关键在于衡量性能并通过迭代来改进实现。
这些构建模块并非硬性规定,而是作为普遍适用的模式供参考。开发者可以依据特定的应用场景,灵活地对这些模块进行调整和组合。正如所有 LLM 的功能一样,成功实施的关键在于持续评估性能,并通过对实现过程的迭代优化来提升效果。
再次强调:增加复杂性应当谨慎考虑,只有在这样做能够明显提升结果质量时,才应当予以采纳。

#06

总结
在 LLM 领域获得成功并不是打造最复杂的系统,而是打造最适合你需求的系统。从简单的提示词开始,经过全面评估进行优化,并仅在更简单的解决方案无法满足需求时,才引入多步骤的 Agent 系统。
实现 Agent 时,我们遵循三个核心原则:
  • 保持 Agent 设计的简洁性。

  • 优先考虑透明度,明确展示 Agent 的规划步骤。

  • 通过详细的工具文档和测试,精心设计 Agent 与计算机的接口(ACI)。
框架可以帮助你快速入门,但在进入生产阶段时,减少抽象层次、使用基本组件进行构建是值得推荐的。遵循这些原则,你将能够创建既强大又可靠、可维护并且值得用户信任的 Agent。

#07

附录 1:Agent 的实践应用
我们的合作项目向客户展示了两种极具潜力的 AI Agent 应用场景,这些场景不仅验证了我们之前讨论的模式,还突显了它们在现实世界中的实际价值。这两个案例都清晰地展示了 AI Agent 如何在需要对话与行动并重、具有明确成功指标、能够启动反馈机制,并整合有效的人工监督的任务中,发挥最大的增值作用。
A. 客户支持  
客户支持结合了熟悉的聊天机器人界面和通过工具集成增强的功能。这是更开放的 Agent 的自然适配场景,因为:
  • 支持交互通常遵循对话流程,同时需要访问外部信息和执行操作;

  • 可以集成工具来提取客户数据、订单历史和知识库文章;

  • 诸如发放退款或更新工单等操作可以通过程序化处理;

  • 成功可以通过用户定义的解决方案进行明确衡量。
一些公司通过基于使用量的定价模型展示了这种方法的可行性,只有在成功解决问题时才收费,表现出了对其智能体有效性的信心。
B. 编程 Agent
在软件开发领域,LLM 功能展示了巨大的潜力,从代码补全到自主解决问题。Agent 特别有效的原因包括:
  • 代码解决方案可以通过自动化测试来验证;

  • Agent 可以使用测试结果作为反馈反复优化解决方案;

  • 问题空间定义明确且结构化;

  • 输出质量可以客观衡量。
在我们的实现中,Agent 现在可以仅凭拉取请求描述,解决 SWE-bench Verified 基准中的实际 GitHub 问题。然而,尽管自动化测试帮助验证功能,但人工审核仍然很重要,以确保解决方案与更广泛的系统需求一致。
链接:https://www.anthropic.com/research/swe-bench-sonnet

#08

附录 2:工具的提示词工程
无论你在构建哪种 Agent 系统,工具可能都是 Agent 的重要组成部分。工具使得 Claude 能够通过在我们的 API 中指定工具的确切结构和定义来与外部服务和 API 交互。当 Claude 作出回应时,如果计划调用工具,它将在 API 响应中包括一个工具使用块。工具的定义和规格应当与整体提示词一样,给予同样的工程关注。在这一简短的附录中,我们将介绍如何对工具进行提示词工程。
通常有几种方式可以指定相同的操作。例如,你可以通过写一个 diff 或重写整个文件来指定文件编辑。对于结构化输出,你可以在 markdown 或 JSON 中返回代码。在软件工程中,这些差异通常是表面上的,可以无损地从一种格式转换为另一种格式。然而,有些格式比其他格式更难让 LLM 编写。写 diff 需要知道在新代码写入之前,区块头部有多少行需要更改。将代码写入 JSON(与 markdown 相比)需要额外转义换行符和引号。
我们决定工具格式的建议如下:
  • 给模型足够的 Token “思考”,以避免其写入死胡同。

  • 将格式保持在模型在互联网上自然看到的格式范围内。

  • 确保没有格式上的 “额外开销”,例如,避免模型需要精确计算成千上万行代码的行数,或者在编写代码时进行转义。
一条经验法则是,考虑人机接口(HCI)的设计投入多少努力,并且打算在创建好的 Agent 计算机接口(ACI)时投入同样的努力。以下是一些实现建议:
  • 将自己放在模型的位置。根据工具的描述和参数,是否很明显如何使用这个工具?如果是,那么模型也可能有相同的理解。好的工具定义通常包括示例用法、边界情况、输入格式要求和与其他工具的清晰区分。

  • 如何改变参数名称或描述,使得更加直观?可以将其视为为团队中的初级开发者编写一个出色的文档字符串。当使用多个相似工具时,这一点尤其重要。

  • 测试模型如何使用你的工具:在我们的工作台中运行多个示例输入,查看模型会犯什么错误,并进行迭代。

  • 对工具进行防错处理。更改参数,使错误更难发生。
在构建我们为 SWE-bench 实现的 Agent 时,我们实际上花了比整体提示词更多的时间来优化工具。例如,我们发现当 Agent 从根目录移出后,使用相对文件路径的工具会出错。为了解决这个问题,我们将工具修改为始终要求使用绝对文件路径 —— 我们发现这种方法模型使用得非常顺利。
链接:https://www.anthropic.com/research/swe-bench-sonnet

(文:AI大模型实验室)

发表评论