构建高效的智能体

Apr 14 · 35min

原文:Building Effective Agents by Erik S. and Barry Zhang, Anthropic

在过去一年中,我们与数十个行业的团队合作,构建基于大语言模型(LLM)的智能体。始终如一的是,最成功的实现并非使用复杂的框架或专用库,而是采用简单、可组合的架构模式。

在这篇文章中,我们分享从客户合作和自行构建智能体中学到的经验,并为开发者提供构建有效智能体的实践建议。

什么是智能体?

"智能体"可以有多种定义。部分客户将智能体定义为能长期独立运行、使用多种工具完成复杂任务的完全自主系统。另一些客户用这个词描述遵循预定义工作流的更具规定性的实现。在 Anthropic,我们将所有这些变体都归类为智能体系统(agentic systems),但在架构上区分了两种重要类型:

  • 工作流(Workflows):通过预定义的代码路径来编排 LLM 和工具的系统。
  • 智能体(Agents):由 LLM 动态指导自己的流程和工具使用,并控制任务完成方式的系统。

下文我们将详细探讨这两种类型的智能体系统。在附录1("智能体实践")中,我们描述了客户在使用这类系统中发现特别价值的两个领域。

何时(以及何时不)使用智能体

在使用 LLM 构建应用时,我们建议找到最简单的解决方案,仅在需要时才增加复杂性。这可能意味着根本不构建智能体系统。智能体系统通常以延迟和成本换取更好的任务表现,你需要考虑这个权衡在何时有意义。

当复杂度确实正当时,工作流为明确定义的任务提供了可预测性和一致性,而智能体则是需要在大规模下实现灵活性和模型驱动决策时的更好选择。然而,对于许多应用来说,通过检索和上下文示例优化单次 LLM 调用通常就足够了。

何时(以及如何)使用框架

有许多框架可以简化智能体系统的实现,包括:

这些框架通过简化调用 LLM、定义和解析工具、链接调用等标准底层任务,使得入门变得容易。然而,它们经常创建额外的抽象层,可能掩盖底层的 prompt 和响应,使调试更加困难。它们也可能诱使开发者在更简单的设置就足够时添加复杂性。

我们建议开发者直接使用 LLM API 开始:许多模式可以用几行代码实现。如果你确实要使用框架,请确保你理解底层代码。对"黑箱"内内容的错误假设是客户错误的常见来源。

我们的 cookbook 中有一些示例实现。

构建模块、工作流和智能体

本节中,我们将探讨在生产环境中见过的智能体系统的常见模式。我们将从基础构建模块——增强型 LLM 开始,逐步增加复杂度,从简单的组合工作流到自主智能体。

构建模块:增强型 LLM

智能体系统的基本构建模块是增强了检索、工具和记忆能力的 LLM。我们当前的模型可以主动使用这些能力——生成自己的搜索查询、选择合适的工具,以及确定保留哪些信息。

我们建议关注实现的两个关键方面:根据你的具体用例定制这些能力,以及为 LLM 提供一个易于使用且有完善文档的接口。实现这些增强的方式有很多种,其中一种是通过我们最近发布的 Model Context Protocol,它允许开发者通过简单的 客户端实现 与不断增长的第三方工具生态系统集成。

在本文的剩余部分,我们假设每次 LLM 调用都可以访问这些增强能力。

工作流:Prompt Chaining(链式提示)

Prompt Chaining 将任务分解为一系列步骤,每个 LLM 调用处理前一个的输出。你可以在任何中间步骤添加编程检查(见下图中的"gate")以确保过程仍在正轨上。

何时使用此工作流:当任务可以轻松、干净地分解为固定子任务时,这种工作流是理想的。主要目标是通过让每次 LLM 调用成为更简单的任务来以延迟换取更高的准确性。

适合使用 Prompt Chaining 的场景

  • 生营销文案,然后将其翻译成不同语言。
  • 写文档大纲,检查大纲是否符合某些标准,然后根据大纲写文档。

工作流:Routing(路由)

路由对输入进行分类并将其引导到专门的后续任务。这种工作流允许关注点分离,并构建更专业的 prompt。如果没有这种工作流,优化一种输入类型可能会损害其他输入的性能。

何时使用此工作流:路由适用于复杂任务中有明显不同类别需要分别处理,且分类可以准确执行(通过 LLM 或更传统的分类模型/算法)的场景。

适合使用路由的场景

  • 将不同类型的客服查询(一般问题、退款请求、技术支持)引导到不同的下游流程、prompt 和工具。
  • 将简单/常见问题引导到更小、成本更低的模型(如 Claude Haiku 4.5),将困难/不寻常的问题引导到更有能力的模型(如 Claude Sonnet 4.5),以优化最佳性能。

工作流:Parallelization(并行化)

LLM 有时可以同时处理任务,并通过程序聚合其输出。这种工作流(并行化)有两种关键变体:

  • Sectioning:将任务分解为并行运行的独立子任务。
  • Voting:多次运行同一任务以获得多样化的输出。

何时使用此工作流:当分解的子任务可以并行化以提高速度,或者需要多个视角或尝试以获得更高置信度的结果时,并行化是有效的。对于具有多个考虑因素的复杂任务,LLM 通常在每个考虑因素由单独的 LLM 调用处理时表现更好,从而允许专注处理每个特定方面。

适合使用并行化的场景

  • Sectioning:实现护栏时,一个模型实例处理用户查询,另一个筛查不当内容或请求。这往往比同一个 LLM 调用同时处理护栏和核心响应表现更好。
  • 自动化评估用于评估 LLM 在给定 prompt 下表现的不同方面,每个 LLM 调用评估一个方面。
  • Voting:审查代码漏洞时,多个不同的 prompt 审查代码并在发现问题时标记。
  • 评估给定内容是否不当,多个 prompt 评估不同方面或需要不同的投票阈值来平衡误报和漏报。

工作流:Orchestrator-Workers(编排器-工作者)

在编排器-工作者工作流中,一个中心 LLM 动态分解任务,将其委托给工作者 LLM,并综合它们的结果。

何时使用此工作流:这种工作流非常适合复杂任务,因为在这些任务中,你无法预测所需的子任务(例如在编码中,可能需要修改的文件数量以及每个文件中改动的性质很可能取决于任务)。虽然它在地形上与并行化相似,但关键区别在于其灵活性——子任务不是预定义的,而是由编排器根据特定输入决定的。

适合使用编排器-工作者工作流的场景

  • 每次都对多个文件进行复杂修改的编码产品。
  • 从多个来源收集和分析信息以查找可能相关信息的搜索任务。

工作流:Evaluator-Optimizer(评估器-优化器)

在评估器-优化器工作流中,一次 LLM 调用生成响应,而另一次在循环中提供评估和反馈。

何时使用此工作流:当我们有明确的评估标准且迭代优化能带来可衡量的价值时,这种工作流特别有效。两个适合的标志是:第一,当人类阐述他们的反馈时,LLM 响应可以明显改进;第二,LLM 能够提供此类反馈。这类似于人类作家在制作精品文档时可能经历的迭代写作过程。

适合使用评估器-优化器的场景

  • 文学翻译中存在细微差别,译者 LLM 最初可能无法捕捉,但评估器 LLM 可以提供有用的批评。
  • 复杂搜索任务需要多轮搜索和分析以收集综合信息,评估器决定是否需要进一步搜索。

智能体

智能体正在生产中涌现,因为 LLM 在关键能力上日趋成熟——理解复杂输入、进行推理和规划、可靠使用工具,以及从错误中恢复。智能体开始工作时,要么接收人类的命令,要么与人类进行交互式讨论。一旦任务明确,智能体就独立规划和操作,可能会返回人类那里获取更多信息或判断。在执行过程中,让智能体从环境(如工具调用结果或代码执行)中获得"真实依据"来评估其进展至关重要。智能体可以在检查点或遇到障碍时暂停以获取人类反馈。任务通常在完成时终止,但也常见包含停止条件(如最大迭代次数)以保持控制。

智能体可以处理复杂的任务,但其实现通常很简单。它们本质上只是基于环境反馈在循环中使用工具的 LLM。因此,清晰且深思熟虑地设计工具集及其文档至关重要。我们将在附录2("为工具做 Prompt Engineering")中扩展工具开发的最佳实践。

何时使用智能体:智能体可用于开放性问题,在这些问题中,很难或不可能预测所需的步数,且无法硬编码固定路径。LLM 可能需要运行许多轮次,你必须对其决策能力有一定程度的信任。智能体的自主性使其成为在可信环境中扩展任务的理想选择。

智能体的自主性意味着更高的成本,以及误差累积的潜在可能。我们建议在沙盒环境中进行广泛测试,并配备适当的护栏。

智能体有用的场景示例

以下示例来自我们的自行实现:

组合和定制这些模式

这些构建模块不是规定性的。它们是开发者可以塑造和组合以适应不同用例的常见模式。成功的关键与任何 LLM 功能一样——衡量性能并迭代实现。重复:你应该只在更简单的解决方案不足时,才在证明能改善结果的情况下添加复杂性。

总结

在 LLM 领域取得成功,不是关于构建最复杂的系统,而是关于为你的需求构建正确的系统。从简单的 prompt 开始,用全面的评估优化它们,只在更简单的解决方案不够时,才添加多步骤的智能体系统。

在实施智能体时,我们尝试遵循三个核心原则:

  • 在智能体的设计中保持简洁。
  • 通过明确展示智能体的规划步骤来优先考虑透明度。
  • 通过完善的工具文档和测试来精心设计你的智能体-计算机接口(ACI)。

框架可以帮助你快速入门,但在进入生产阶段时,不要犹豫减少抽象层并使用基本组件构建。遵循这些原则,你可以创建不仅强大,而且可靠、可维护并受用户信任的智能体。

致谢

由 Erik S. 和 Barry Zhang 撰写。这项工作借鉴了我们在 Anthropic 构建智能体的经验以及客户分享的宝贵见解,对此我们深表感谢。

附录1:智能体实践

我们与客户的合作揭示了 AI 智能体两个特别有前景的应用,展示了所讨论模式的具体价值。两个应用都说明,对于需要对话和行动结合、有明确成功标准、能实现反馈循环并整合有意义的人类监督的任务,智能体增加了最大价值。

A. 客户支持

客户支持将熟悉的聊天机器人界面与通过工具集成增强的能力相结合。这对于更开放的智能体来说是很自然的选择,因为:

  • 支持交互自然地遵循对话流程,同时需要访问外部信息和操作;
  • 工具可以集成以拉取客户数据、订单历史和知识库文章;
  • 退款或更新工单等操作可以编程处理;
  • 成功可以通过用户定义的解决方案进行明确衡量。

几家公司通过基于使用量的定价模式证明了这种方法是不可行的,该模式只为成功解决的案例收费,展示了对其智能体有效性的信心。

B. 编码智能体

软件开发领域已显示出 LLM 功能的显著潜力,能力从代码补全发展到自主问题解决。智能体特别有效,因为:

  • 代码解决方案可以通过自动化测试验证;
  • 智能体可以使用测试结果作为反馈来迭代解决方案;
  • 问题空间定义良好且结构化;
  • 输出质量可以客观衡量。

在我们自己的实现中,智能体现在可以根据拉取请求描述独自解决 SWE-bench Verified 基准中的真实 GitHub 问题。然而,虽然自动化测试有助于验证功能,但人类审查对于确保解决方案符合更广泛的系统要求仍然至关重要。

附录2:为工具做 Prompt Engineering

无论你构建哪种智能体系统,工具都可能成为智能体的重要组成部分。工具 使 Claude 能够通过在我们的 API 中指定其确切结构和定义来与外部服务和 API 交互。当 Claude 响应时,如果它计划调用工具,它将在 API 响应中包含一个工具使用块。工具定义和规范应与你的整体 prompt 一样受到同等的 prompt 工程关注。在这个简短的附录中,我们描述了如何为工具做 prompt engineering。

指定同一操作通常有多种方式。例如,你可以通过写 diff 或重写整个文件来指定文件编辑。对于结构化输出,你可以在 markdown 内或 JSON 内返回代码。在软件工程中,像这样的差异是 cosmetics(装饰性)的,可以无损地相互转换。然而,某些格式对 LLM 来说编写难度大得多。写 diff 需要在写入新代码之前知道 chunk 头中有多少行正在更改。在 JSON 中编写代码(与 markdown 相比)需要额外的换行符和引号转义。

关于我们决定工具格式的建议:

  • 给模型足够的 token 空间来"思考",然后再把自己写进死角。
  • 格式尽量接近模型在互联网上自然看到的文本形式。
  • 确保没有格式化"开销",例如必须准确计算数千行代码,或对其编写的任何代码进行字符串转义。

一个经验法则是,想想人机界面(HCI)需要多少努力,并计划在创建好的智能体-计算机接口(ACI)上投入同样多的努力。以下是具体做法:

  • 站在模型的立场上思考。根据描述和参数,使用该工具的方式是否显而易见,还是需要仔细思考?如果对人类来说很明显,对模型来说可能也是如此。一个好的工具定义通常包括示例用法、边缘情况、输入格式要求和与其他工具的清晰边界。
  • 如何改变参数名称或描述使事情更明显?把这想象成为团队中的初级开发人员写一份出色的文档字符串。当使用许多类似的工具时,这尤其重要。
  • 测试模型如何使用你的工具:在我们的 workbench 中运行许多示例输入,观察模型犯的错误,然后迭代。
  • Poka-yoke 你的工具。改变参数使错误更难发生。

在构建用于 SWE-bench 的智能体时,我们实际上在优化工具上花费的时间比整体 prompt 还要多。例如,我们发现模型在智能体离开根目录后使用相对文件路径时会出错。为了解决这个问题,我们将工具改为始终要求绝对路径——我们发现模型使用这个方法完美无缺。

>
CC BY-NC-SA 4.0 2021-PRESENT © Remywwo