本文是一份详尽的AI代理系统构建指南,主要内容翻译整理自Anthropic官方博客最新的研究文章《Building Effective Agents》,涵盖从基础概念到高级实践的全方位内容,并结合了我自身的一些实践经验做了注释。无论您是想了解LLM代理的工作原理,还是正在寻找构建企业级AI代理系统的最佳实践,希望这篇文章都能为您提供有价值的参考。
关键词:AI代理系统、LLM应用、工作流设计、系统架构、企业应用
在过去的一年中,我们与众多企业团队合作,在各行各业构建基于大型语言模型(LLM)的AI代理系统。通过实践,我们发现最成功的实现并不依赖于复杂的框架或专业库,而是采用简单、可组合的架构模式。
在这篇深度技术文章中,我们将分享与顶级科技公司合作和自主研发的一手经验,为开发者提供构建高效AI代理系统的实用指南。
什么是代理?
在AI领域,"代理"(Agent)是一个广义概念。从技术角度看,它可以是一个在较长时间内独立运行、使用各种工具来完成复杂任务的完全自主系统,也可以是一个遵循预定义工作流程的指令性实现。在Anthropic的实践中,我们将这些变体统一归类为AI代理系统 ,并在工作流 和代理之间做出关键的架构区分:
- 工作流是指通过预定义代码路径协调LLM和工具的系统。
- 代理则是指LLM动态指导其自身的过程和工具使用,保持对完成任务方式的控制。
下面,我们将详细探讨这两种类型的代理系统。在附录1("代理在实践中")中,我们描述了客户在使用这些系统时所获得的特别价值的两个领域。
何时(以及何时不)使用代理
在使用LLM构建应用时,我们建议寻找尽可能简单的解决方案,只有在需要时才增加复杂性。这可能意味着根本不构建代理系统。代理系统通常为了更好的任务表现而牺牲延迟和成本,因此您应该考虑这种权衡何时是合理的。
当更多复杂性是合理的时,工作流 为明确的任务提供可预测性和一致性,而在需要灵活性和模型驱动决策时,代理则是更好的选择。然而,对于许多应用程序而言,使用检索和上下文示例来优化单个LLM调用通常已经足够。
何时以及如何使用框架
有许多框架可以使代理系统更容易实现,包括:
- LangGraph 来自LangChain;
- 亚马逊Bedrock的 AI代理框架;
- Rivet,一个拖放式图形用户界面LLM工作流程构建工具;以及
- Vellum,另一个用于构建和测试复杂工作流程的图形用户界面工具。
这些框架通过简化调用LLM、定义和解析工具以及将调用链接在一起的标准低级任务,帮助使用者快速入门。然而,它们通常会创造额外的抽象层,这可能会掩盖底层提示和响应,使其更难以调试。它们还可能诱使开发者在更简单的设置足够时增加复杂性。
因此,我们建议开发者直接使用LLM API:许多模式可以用几行代码实现。如果您确实希望使用框架,请确保了解底层代码。对底层实现的错误假设是客户错误的常见来源。
如果需要,请参见我们的 Cookbook 获取一些示例实现。
构建模块、工作流与代理
在本节中,我们将探讨我们在生产中看到的代理系统的常见模式。我们将从我们的基础构建模块------增强型LLM开始,并逐步增加复杂性,从简单的组合工作流到自主代理。
构建模块:增强型LLM
代理系统的核心基础是具备检索增强、工具调用和记忆能力的增强型LLM。现代LLM模型已经能够主动使用这些增强功能 - 自主生成搜索查询、选择适当的工具,并管理信息存储。
我们建议关注实现的两个关键方面:将这些功能量身定制以满足您的特定用例,并确保它们为您的LLM提供一个易于使用、文档齐全的接口。虽然有许多方法可以实现这些增强功能,但一种方法是通过我们最近发布的模型上下文协议(Model Context Protocol),该协议允许开发者通过简单的客户端(Client)实现与日益增长的第三方工具生态系统集成。
比如我之前文章介绍的Cline,就是基于MCP协议实现的,用户可以轻松添加自定义的工具。另一个典型的增强型LLM就是OpenAI的用户自定义GPT,它允许用户上传自己的知识库,然后通过LLM调用这些知识库。同时也可以调用搜索,画布,代码解释器等工具。
在本文的其余部分,我们将假设每个LLM调用都可以访问这些增强功能。
工作流模式一:提示链
提示链将任务分解为一系列步骤,其中每个LLM调用处理前一个调用的输出。您可以在任何中间步骤上添加程序性检查(见下图中的"门"),以确保过程仍在轨道上。
何时使用此工作流: 此工作流理想用于任务可以轻松且干净地分解为固定子任务的情况。主要目标是通过使每个LLM调用成为一个更简单的任务来权衡延迟与更高的准确性。
提示链有用的示例:
- 生成营销文案,然后将其翻译成另一种语言。
- 撰写文档大纲,检查大纲是否满足某些标准,然后根据大纲撰写文档。
大家可能会问,为什么这样的提示链不能用一次LLM调用完成?一个原因是LLM的调用每次都需要有提示词来提升输出的准确度,一次调用难免会把多个任务的提示词混在一起,导致输出结果不够准确。实践证明,多次调用LLM,每次调用都只专注于一个任务,效果会更好。另一个原因是,可能需要人为确认中间结果,比如文中提到的撰写大纲,一般需要人为确认大纲是否合理,然后再让LLM继续根据大纲撰写文档。一个典型的例子就是豆包的长文输出功能,就是基于这个思路,先产生大纲,让用户确认,然后再根据大纲输出长文。
工作流模式二:路由
路由对输入进行分类并将其引导至特定的后续任务。此工作流允许关注点分离,并构建更专业的提示。如果没有这个工作流,优化一种类型的输入可能会影响对其他输入的表现。
何时使用此工作流: 路由适用于复杂任务,其中存在不同类别,且这些类别最好分别处理,并且分类可以由LLM或更传统的分类模型/算法准确处理。
路由有用的示例:
- 将不同类型的客户服务查询(一般问题、退款请求、技术支持)引导到不同的下游流程、提示和工具。
- 将简单/常见问题路由到小型模型(如Claude 3.5 Haiku),而将困难/不寻常问题路由到更强大的模型(如Claude 3.5 Sonnet),以优化成本和速度。
这个模式的关键点是利用LLM进行意图识别,然后再根据意图选择不同的LLM来完成任务。其实就理解成If-Else的逻辑,只不过这里用LLM来实现路径选择。实际应用中经常会用到,比如公众号服务机器人设计的时候,就会很自然的区分用户的问题是否和公众号内容相关,相关则查询公众号的知识库并给出回答,不相关则给出比较通用的回答。
工作流模式三:并行化
LLM有时可以同时处理任务,并以编程方式聚合它们的输出。此工作流即并行化,有两个关键变体:
- 分区:将任务拆分为独立的子任务并行运行。
- 投票:多次运行相同的任务以获得多样化的输出。
何时使用此工作流: 当划分的子任务可以并行化以提高速度,或者当需要多个视角或尝试以获得更高置信度的结果时,并行化是有效的。对于复杂任务,LLM通常在每个考虑因素由单独的LLM调用处理时表现更好,从而在每个特定方面集中注意力。
并行化有用的示例:
- 分区 :
- 实施保护措施,其中一个模型实例处理用户查询,而另一个对不当内容或请求进行筛选。这通常比让同一个LLM调用同时处理保护措施和核心响应效果更好。
- 自动评估LLM性能,其中每个LLM调用评估模型在给定提示上的不同性能方面。
- 投票 :
- 审查代码中的漏洞,其中多个不同的提示审查并标记代码中的问题。
- 评估给定内容是否不当,多个提示评估不同方面或要求不同的投票阈值以平衡假阳性和假阴性。
这个模式有个非常经典的应用场景,但是LLM的厂家都不爱提,那就是同一任务的多模型对比输出。做应用实现的时候,我们往往不会依赖于单一模型,而是会使用多个模型进行对比,然后选择性价比最高的模型来完成指定的任务。又或者类似Monica和Sider的聊天机器人允许同时接入多种模型,然后让用户自己选择满意的答复,也是这种模式的典型应用。
工作流模式四:协调者-工作者
在协调者-工作者工作流中,中央LLM动态地分解任务,将其委派给工作者LLM,并综合它们的结果。
何时使用此工作流: 此工作流程适用于复杂任务,您无法预测所需的子任务(例如,在编码中,每次需要更改的文件数量和每个文件中的更改性质可能取决于任务)。尽管其拓扑结构类似于并行化,但与之的关键区别在于其灵活性------子任务不是预定义的,而是由协调者根据特定输入确定的。
协调者-工作者有用的示例:
- 编码产品,每次对多个文件进行复杂更改。
- 搜索任务,涉及从多个来源收集和分析信息以获取可能相关的信息。
这个模式也有个非常典型的应用就是AI编程助手Aider的架构师模式,我们可以使用善于推理的高级别模型,如o1进行编程任务的规划,然后由擅长编码的模型,如claude-3.5-sonnet进行代码的编写,这样的整体性价比是最高的。尤其是明年咱有o3了,那面对复杂任务,为了平衡成本和性能,这个模式会越来越流行。该模式看起来和模式二很像,但是要注意,模式二的路径选择是单一的,而该模式的路径选择是多样且动态的,可以同时选择多个下游模型来完成任务,所以需要一个下游的综合者来综合多个模型的输出。
工作流模式五:评估者-优化器
在评估者-优化器工作流程中,一个LLM调用生成响应,而另一个在循环中提供评估和反馈。
何时使用此工作流: 当我们有明确的评估标准,并且迭代改进提供可衡量的价值时,此工作流程特别有效。两个良好适配的标志是,首先,当人类明确表达反馈时,LLM的响应可以显著改进;其次,LLM可以提供这样的反馈。这类似于人类作家在撰写精致文档时可能经历的迭代写作过程。
评估者-优化器有用的示例:
- 文学翻译,其中翻译LLM可能最初无法捕捉到细微差别,但评估者LLM可以提供有用的批评。
- 复杂搜索任务,需要多轮搜索和分析以收集全面信息,评估者决定是否需要进一步的搜索。
这个模式就是典型的迭代优化,一般用户可以选择迭代的次数,以此来控制质量和成本。我们可以把他看成While循环的逻辑,只不过这里用LLM来实现迭代。其实我们平时和ChatGPT这样的聊天机器人讨论问题,就是这个模式,只不过评估者是我们人类而已,往往解答一个问题,要追问好几轮才能得到一个满意的答案。所以有时候我们为了加快对话速度,会让LLM自己来评估自己是否完成了任务,然后设一个最大迭代次数,让LLM自己来决定是否停止迭代。最典型的就是Cline最新的功能,Auto Approve,给LLM一个任务,LLM会自动评估是否完成任务,如果没完成,则继续迭代,直到完成任务。
代理
随着LLM在理解复杂输入、进行推理和规划、可靠使用工具以及从错误中恢复等关键能力上的成熟,代理在生产中逐渐崭露头角。代理以人类用户的命令或互动讨论开始工作。一旦任务明确,代理就会独立规划和操作,可能会返回人类以获取进一步的信息或判断。在执行过程中,代理在每一步获取来自环境的"真实信息"(例如工具调用结果或代码执行)以评估其进展至关重要。然后,代理可以在检查点或遇到障碍时暂停以获取人类反馈。任务通常在完成时终止,但通常也会包括停止条件(例如最大迭代次数)以保持控制。
代理可以处理复杂任务,但它们的实现通常很简单。它们通常只是使用基于环境反馈的工具的LLM循环。因此,清晰而深思熟虑地设计工具集及其文档至关重要。我们在附录2("提示工程您的工具")中扩展了工具开发的最佳实践。
何时使用代理: 代理可用于难以或不可能预测所需步骤数量的开放性问题,并且无法硬编码固定路径。LLM可能会进行多轮操作,您必须对其决策能力有一定的信任。代理的自主性使其非常适合在受信环境中扩展任务。
代理的自主性意味着更高的成本和潜在的复合错误。我们建议在沙盒环境中进行广泛测试,并采取适当的保护措施。
代理有用的示例:
以下示例来自我们自己的实现:
- 一个编码代理来解决 SWE-bench任务,这些任务涉及根据任务描述对多个文件进行编辑;
- 我们的 "计算机使用"参考实现,其中Claude使用计算机完成任务。
正如文中所述,代理的实现其实很简单,它们通常只是使用基于环境反馈的工具的LLM循环。所以本质上,代理就是一种LLM循环,这和工作流模式五的评估者-优化器很像,只不过这里多了个环境反馈,所以可以代替人类直接对任务执行结果进行评估,从而决定是否需要继续迭代。既然提到环境交互,所以关键点是工具的设计,毕竟LLM需要依靠工具来和环境进行交互,这也是为什么MCP协议对代理的发展如此重要。Cline已经率先实现了MCP协议,所以可以作为通用代理平台,而同样拥有Agent模式的Cursor和Windsurf目前的工具还只是自己定义的,所以还不能作为通用代理平台,估计很快就会支持MCP协议。
组合和自定义这些模式
这些构建模块并不是规范性的。它们是开发者可以塑造和组合以适应不同用例的常见模式。成功的关键,与任何LLM特性一样,是测量性能并对实现进行迭代。重申一下:您应该在明显改善结果的情况下,才考虑增加复杂性。
总结与最佳实践
在LLM技术快速发展的今天,构建AI代理系统的关键不在于追求系统的复杂度,而在于为特定需求打造最适合的解决方案。我们建议:
- 从简单的提示工程开始
- 通过全面评估持续优化
- 只在必要时才引入多步骤代理系统
在实现企业级AI代理时,我们始终遵循三个核心原则:
- 在系统设计中保持简单性
- 通过清晰的规划步骤确保透明度
- 通过完善的文档和测试构建可靠的代理-计算机接口(ACI)
相关资源
关于作者: 本文由Anthropic AI研究团队的Erik Schluntz和Barry Zhang撰写。基于在为全球顶级科技公司构建AI代理系统的实践经验,以及来自企业客户的宝贵反馈。
附录1:实践中的代理
我们与客户的合作揭示了AI代理的两个特别有前途的应用,展示了上述模式的实际价值。这两个应用都说明了代理在需要对话和行动、具有明确成功标准、启用反馈循环并整合重要人类监督的任务中增值最多。
A. 客户支持
客户支持结合了熟悉的聊天机器人界面与通过工具集成增强的能力。这是开放性代理的自然契合,因为:
- 支持互动自然遵循对话流程,同时需要访问外部信息和操作;
- 可以集成工具来提取客户数据、订单历史和知识库文章;
- 可以以编程方式处理诸如退款或更新票务等操作;
- 成功可以通过用户定义的解决方案明确衡量。
一些公司通过基于使用的定价模型展示了这一方法的可行性,仅对成功解决方案收费,显示了对其代理有效性的信心。
目前实现一个客户支代理已经相当简单,比如字节的扣子平台,直接提供了一个完整的客户支持代理的模板,用户只需要根据自己业务实际情况,配置相应的设置,就可以完成一个基本的客户支持代理,可以自动回答用户的问题,再配合扣子平台提供的API插件,就可以轻松实现自动处理用户的请求,比如退款、更新票务等。
B. 编码代理
软件开发领域展示了LLM特性的显著潜力,能力从代码补全演变为自主问题解决。代理特别有效,因为:
- 代码解决方案可以通过自动化测试进行验证;
- 代理可以使用测试结果作为反馈来迭代解决方案;
- 问题空间是明确和结构化的;
- 输出质量可以客观衡量。
在我们自己的实现中,代理现在可以仅根据拉取请求描述解决实际的GitHub问题。尽管自动化测试有助于验证功能,但人工审查仍然对确保解决方案符合更广泛的系统要求至关重要。
这个方向最典型的案例,当属每月500美金的Devin啦,目前它已经可以独立完成GitHub的代码提交、合并、创建Pull Request等操作,而且可以通过Slack平台和人类程序员协同工作,不得不说,应用潜力是巨大的。
附录2:提示工程您的工具
无论您构建的是哪种代理系统,工具都可能是您代理的重要组成部分。工具使Claude能够通过在我们的API中指定其确切结构和定义与外部服务和API交互。当Claude做出响应时,如果它计划调用工具,它将在API响应中包含一个工具使用块。工具定义和规范应与您的整体提示一样,给予同样多的提示工程关注。在这个简短的附录中,我们描述了如何提示工程您的工具。
通常有几种方法可以指定相同的操作。例如,您可以通过编写差异或重写整个文件来指定文件编辑。对于结构化输出,您可以在markdown或JSON中返回代码。在软件工程中,这些差异是表面的,可以无损转换。然而,有些格式对于LLM来说比其他格式更难以编写。编写差异需要在写入新代码之前知道在块头中有多少行正在更改。将代码写入JSON(与markdown相比)需要额外转义换行符和引号。
我们对决定工具格式的建议如下:
- 给模型足够的令牌以便其"思考",避免陷入死胡同。
- 保持格式接近模型在互联网上自然出现的文本。
- 确保没有格式"开销",例如需要准确计算数千行代码,或者对其编写的任何代码进行字符串转义。
一个经验法则是考虑人机接口(HCI)需要多少努力,并计划在创建良好的代理-计算机接口(ACI)上投入同样多的努力。以下是一些建议:
- 站在模型的角度思考。根据描述和参数,使用这个工具是否显而易见,还是需要仔细考虑?如果是这样,那么模型也可能是如此。良好的工具定义通常包括示例用法、边缘情况、输入格式要求以及与其他工具的明确界限。
- 您如何可以更改参数名称或描述以使其更明显?将其视为为团队中的初级开发人员编写一个出色的文档字符串。这在使用许多相似工具时尤其重要。
- 测试模型如何使用您的工具:在我们的工作台中运行许多示例输入,以查看模型犯了什么错误,并进行迭代。
- 对您的工具进行Poka-yoke。更改参数,使得更难出错。
在为SWE-bench构建我们的代理时,我们实际上花了更多时间来优化我们的工具,而不是整体提示。例如,我们发现模型在代理移动出根目录后,使用相对文件路径的工具会出错。为了解决这个问题,我们将工具更改为始终要求绝对文件路径------我们发现模型完美地使用了这种方法。
这个附录的建议实在太戳中我的痛点了。我之前在开发Cline的MCP工具时,就遇到不少类似问题。举个例子,我设计了一个根据mermaid代码生成图片的工具,但是模型在调用这个工具时总是出错,后来发现我的工具要求LLM提供一个文档路径,以此来判断在哪个工作目录里创建图片,但是LLM在调用工具时,总是只提供相对路径,这导致MCP工具总是把图片放在自己的工作目录下,而不是LLM的工作目录。之后我在工具描述中明确指出参数需要提供绝对路径,并且在返回错误的时候,也提示LLM要提供绝对路径,这样成功引导LLM正确的使用了工具。这和Anthropic的团队遇到的问题一模一样,真是宝贵经验。