ByteByteGo Newsletter

Best Practices for Building AI Agents That Work in Production

8.5内容质量
Best Practices for Building AI Agents That Work in Production

TL;DR · AI 摘要

构建生产级AI代理需聚焦上下文控制、确定性流程、状态管理和范围控制,基于Twelve-Factor Agents原则并结合多家公司实践。

核心要点

  • 上下文控制需明确模型可见范围,避免信息过载或缺失
  • 控制流应通过确定性代码管理循环和停止条件,减少模型依赖
  • 状态管理需在软件中保存记忆,保持模型无状态设计

结构提纲

按章节快速跳转。

  1. 揭示演示环境与生产环境AI代理性能差距的根本原因

  2. 通过可见性范围定义模型决策依据的边界条件

  3. 用确定性代码实现循环控制与终止条件判定

  4. 软件层保存记忆状态,模型保持无状态架构

  5. 通过窄范围设计实现代理的可监督性与可控性

  6. 不同设计选择对系统可靠性与复杂度的影响对比

思维导图

用一张图看清主题之间的关系。

查看大纲文本(无障碍 / 无 JS 友好)
  • 生产级AI代理构建
    • 核心实践
      • 上下文控制
      • 控制流管理
      • 状态管理
      • 范围控制
    • 演进基础
      • Twelve-Factor App
      • Twelve-Factor Agents

金句 / Highlights

值得收藏与分享的关键句。

#AI代理#生产环境#Twelve-Factor Agents#工程实践
打开原文

构建可在生产环境中运行的AI代理的最佳实践

ByteByteGo

2026年7月22日

[网络研讨会] AI原生工程中的上下文成熟度8个层级(赞助)

AI已经融入了您的工程工作流程。虽然令牌消耗量显示了这一点,但吞吐量却并未体现。人类仍然在循环中扮演重要角色,这实际上是一个上下文问题。

7月23日(免费)加入直播,学习以下内容:

  • 上下文成熟度的8个层级:大多数团队卡在哪个阶段,每个阶段的上限是什么样子
  • 为什么更多的MCP、规则和技能为代理提供了访问权限但没有带来理解能力
  • 领先的工程团队如何使用上下文引擎充分利用其代理

立即注册

在演示中表现良好的AI代理与在真实生产流量下稳定运行的代理之间存在持续的差距。

这是因为处理实时客户工作负载的系统往往比演示所暗示的要少依赖语言模型。大多数行为通过常规的、确定性的代码运行,模型仅在少数特定的决策点被调用。可靠代理与脆弱代理之间的差异通常归结为一组工程决策:在哪些地方赋予模型控制权,在哪些地方限制其作用。

但如何构建在生产环境中可靠运行的代理?是否存在任何最佳实践?

2011年,Heroku联合创始人发布了《十二要素应用》,这是一套构建可可靠部署和扩展的Web服务的原则,这份文档影响了整整一代工程师对软件的思考方式。

后来,针对AI领域出现了类似的实践,被称为《十二要素代理》的广泛传播原则。这些原则旨在使语言模型应用足够健壮以适应生产环境。此后这些具体实践持续演进,AnthropicCognitionIntercom等公司的团队也加入了他们自己的经验教训。

在本文中,我们试图将这些集体思考提炼成更少的实践,并解释每个实践背后的原理,而不是要求任何人记忆一个编号列表。这些实践分为四个领域,最后一部分讨论权衡取舍。我们将涵盖以下内容:

  • 上下文如何控制模型在每次调用中看到的内容?
  • 控制流如何通过确定性代码保持循环及其停止条件?
  • 状态如何在软件中保存记忆,同时保持模型无状态?
  • 范围如何保持每个代理的狭窄性和可监督性?

到文章结束时,我们将建立一个生产代理的工作定义,并明确哪些决策具有最大的影响力。

免责声明:本文基于来自多个来源的公开信息。文末有参考文献。如果您发现任何不准确之处,请留言评论。

循环

让我们从任何人都可以构建的最简单代理开始,因为它揭示了所有其他内容所优化的结构。

本质上,代理是一个循环机制。模型接收一些上下文,这些上下文记录了到目前为止发生的所有事件,然后模型返回一个关于下一步操作的决策。该决策以结构化输出的形式呈现,例如JSON格式的机器可读数据,而非自由流动的文本,这样普通代码可以读取并执行这些决策。外围代码执行请求的步骤,将结果追加到上下文中,并将所有内容返回给模型以进行下一步决策。循环持续进行,直到模型发出工作完成的信号。

一个有用的视角是将模型的作用视为一个函数,每次调用时都从零开始。

每次调用时,模型仅能看到提供的上下文,做出一个决策,并在响应后立即丢弃所有信息。上下文窗口是模型在每次调用时读取的文本集合,它构成了系统的全部记忆。

这种设计的优势显而易见。开发者只需描述目标并提供一组工具,模型就能自行推导出操作顺序。由于模型处理决策,这种设计减少了分支逻辑的需求。这是在演示环境中表现良好的代理版本。然而,当真实流量到来时,问题就开始显现。

故障模式

我们在上一节看到的设计在生产环境中会失败,且失败模式具有可预测的规律:

  • 累积误差在链式步骤中呈指数级增长。
  • 确定性错误输出传递给用户。
  • 循环运行时间超出预期。
  • 当计划仅存在于模型内部时,状态会丢失。

让我们更详细地理解这些模式。

第一个模式是累积误差。每次模型调用都存在一定概率做出错误决策,而自由放任的代理会将许多调用串联在一起。假设每一步有95%的正确率,这听起来很可靠。但连续执行二十个这样的步骤后,所有步骤都成功的概率会降至约三分之一。数学计算是乘法关系,因此看似可靠的独立可靠性会在长链中迅速下降。这一事实解释了为什么生产团队会添加大量防护措施。

第二个模式是确定性错误输出传递给用户。2025年,代码工具Cursor的客服代理向客户宣传了“每个订阅仅限一台设备”的规则,后来公司确认这是虚构的,随后引发大量用户取消订阅。一年前,加拿大航空因聊天机器人编造了“丧事优惠票价政策”而被法庭判责,并被要求执行该政策。研究表明,即使在受控环境中,模型产生看似合理但虚假陈述的幻觉率在3%到27%之间。直接面向客户的代理会将这一比率转化为重大的商业风险。

最后两个模式更难察觉,但同样代价高昂。

带有弱停止条件的循环可能运行远超预期时间,每次迭代都会消耗令牌和资金。最后,当计划仅存在于模型的上下文中时,崩溃或长时间运行的任务可能导致整个工作线程丢失。

每个故障都指向特定的实践,归类到以下四个领域,首先从输入开始。

上下文

上下文窗口是模型在每次调用时所知的所有信息,因此控制其内容是可靠性管理的首要且最重要的杠杆。以下三种习惯在此处发挥主要作用。

控制流

只有当周围代码决定模型何时运行以及循环何时结束时,掌控输入才有意义。在可靠的代理系统中,控制流属于模型周围的确定性代码,模型仅在少数几个特定时刻被调用。

将整体流程想象为普通代码,一系列步骤、条件判断和对外部系统的调用。在流程中的两三个关键点上,当真正需要判断时,系统才会调用模型。其余所有环节均由普通确定性逻辑处理,因为这种方式运行成本更低、输出可预测、测试更简单。

两个实用规则使这种模式生效:

  • 首先,每个循环都需要一个逃生舱口,即强制停止的硬性限制。通过设置迭代次数上限、超时机制和明确的完成条件,即使模型希望无限运行,代理也能保证终止。
  • 其次,要刻意调用模型。模型应仅在需要开放性推理的问题环节使用,而普通代码处理所有可预先指定的逻辑。

Intercom 的客户服务产品展示了这种模式的大规模应用。

其更新后的流程功能允许代理以自然语言进行推理,而周围系统则提供确定性控制,包括决策点的条件步骤、保证相同输入始终产生相同输出的小型代码片段,以及在执行敏感操作前暂停等待人工批准的检查点。

总结来说,应从能解决问题的最简版本开始,仅在简单逻辑无法满足需求时再添加模型驱动的自主性。

状态

一旦周围代码掌控了循环,自然会引发一个后续问题:代理的记忆存储在哪里?

答案是保持模型无状态,将状态保存在应用程序控制的软件中。

范围

拥有输入、循环和状态仍然留下一个决策未定。单个代理应尝试完成多少任务?较好的答案倾向于使用多个小型、专注的代理并在监督下运行,而不是让一个宽泛的代理承担所有任务。

一个职责明确、专注于单一任务的窄代理具有更小的失败面。它更容易测试、更容易推理,并且在行为异常时更容易修复。当任务涉及多个不同工作时,多个窄代理可以在确定性编排下协同完成。外围代码决定哪个代理运行以及何时运行,而不是让一个通用代理承担大量责任。

Klarna 的客户服务助手展示了这种设计的优势。在上线的第一个月,它处理了约 230 万次对话,其中大部分遵循可预测的路径,例如检查退款状态或跟踪订单,这些结构化逻辑处理得非常好,而模型仅用于真正需要的情况。

监督是范围的另一部分。

人工交接应被设计为一个核心步骤。当操作敏感、置信度较低或客户要求与人工沟通时,才会主动进入该步骤。Intercom 直接构建了这一机制,当继续对话的风险较高时,会自动将对话转交给人工。将人工参与视为一个计划路径,并配备必要的状态信息以便向人工人员说明情况,这使系统具备了优势,而非表示出现了问题。

权衡

到目前为止描述的所有内容都是当前可行的实践。但也存在分歧和一些尚未解决的问题。

主要的争论集中在单代理与多代理系统之间。

2025 年 6 月,开发 Devin 编程代理的团队反对多代理设计,因为并行子代理会做出相互冲突的独立决策。一天后,Anthropic 描述了其自己的多代理研究系统,该系统使用的 token 数量约为单代理方法的 15 倍,在某些研究任务上的得分高出约 90%。

看似矛盾的问题在接下来的几个月里逐渐演变为一种共同的模式。一个单一的协调器拥有完整的上下文,并生成孤立的、生命周期短暂的子代理,每个子代理完成一项任务后返回摘要。需要理解的关键在于:在严格协调下,小型且专注的代理表现最佳,而直接相互沟通的子代理往往会产生冲突结果。

更深层次的问题源于理查德·萨顿(Rich Sutton)提出的“苦涩教训”(The Bitter Lesson)。这一观察指出,依赖更多计算的一般性方法会随着时间推移超越手工设计的技术。应用到当前场景,这警示我们:为弥补当前模型缺陷而构建的一些支撑架构,随着模型的改进将变得多余。这一观点部分成立,也是反对过度工程化最强的论据。

但另一方面,一些问题无论模型能力如何都会持续存在。有限的上下文窗口长度、需要保持文档第五页与第八百页中同一图表的一致性、安全暂停与恢复的需求,这些挑战即使在更强大的模型面前依然存在。

成本成为每个决策必须考虑的因素。自主性和多代理设计会消耗更多token,有时消耗远超预期,因此它们只有在任务价值足以抵消成本时才值得采用。

结论

一个生产级代理的核心本质,基本上是确定性软件,仅在少数关键节点调用语言模型。设计决策的关键在于选择这些节点,并限制模型自主决策的范围。

通向这一定义的路径,经历了最简单代理及其可预测的失败过程,每个失败都催生出相应的实践准则:

  • 控制模型可见的信息范围。
  • 主导流程并设置强制终止点。
  • 在软件中维护状态,同时保持模型无状态。
  • 保持每个代理的职责单一且受监督。

围绕这些原则存在真实权衡,包括多代理系统的开放性争论,以及模型能力持续提升将逐步淘汰部分工作的趋势。合理的做法应从最简单的能解决问题的设计开始,测量其不足之处,并仅在自主性确实带来明确价值的场景中赋予模型更多自主权。

References:

  • The Twelve-Factor App
  • 12-Factor Agents — HumanLayer
  • Anthropic — Building Effective Agents
  • Anthropic — How We Built Our Multi-Agent Research System
  • Cognition — Don’t Build Multi-Agents
  • Intercom — What’s New with Fin 3
  • Rich Sutton — The Bitter Lesson
  • Cursor support-bot incident — eWeek
  • Air Canada chatbot ruling — AI Business