跳到正文
Claude:Blog·· 21 小时前精选AI 评分62

Anthropic 详解常驻智能体的五个核心架构原语

Building always-on agents

AI 导读

Anthropic 发布博客,拆解常驻智能体(always-on agents)背后的架构。这类智能体有状态且可主动行动,其兴起得益于模型判断力提升和智能成本下降,例如长程编码任务上 Opus 5.5 每解决一个任务的成本比 Opus 5 低 78%。

推荐理由

Anthropic 把常驻智能体拆成五个可落地的架构原语,并给出实现细节与最佳实践,读者可按此搭建自己的方案。

正文 · AI 翻译

过去几个月里,常驻智能体(always-on agent)重新流行起来。

常驻智能体是有状态、主动的,也就是说,它们能跨会话管理上下文,并在没有直接监督的情况下采取行动。底层上,它们和其他智能体运行在同一个核心循环上。区别在于外围架构:这套架构由若干基础构件组成,用来控制智能体何时唤醒、每次运行之间保留什么,以及它们的工作如何送达用户。

这波回潮很大程度上源于近期的模型进步,让常驻智能体运行起来更实际。首先,最新模型的判断力更强:它们更能可靠地理解用户意图,也知道什么时候该来确认一下。其次,智能成本在下降,长周期任务受益最大。例如,在一个长周期编程基准上,Opus 5.5 每解决一个任务的花费比 Opus 5 低 78%,而典型工作负载下只低 40%。

客户开始问我们,如何把这种体验集成到自己的产品里。有些公司想让现有智能体更主动,另一些则打算从头构建。

本文拆解常驻智能体背后的基础构件,并说明它们如何协同工作。

常驻智能体的循环

常驻智能体其实并不是“常驻”。这只是对用户体验的一种描述。

实际上,智能体大部分时间都在休眠,定期醒来干活。每一段工作称为一次运行(run):智能体收到一个事件,完成任务,然后保存发生了什么。运行在会话(session)中进行,会话是消息和工具调用的记录。运行结束后,智能体重新休眠,这个循环无限重复。

Animated diagram of an always-on agent’s timeline: long stretches asleep with no tokens spent, broken by brief runs. Each run has four steps: an event arrives, a session starts, the agent loop runs, and the run writes back to stored state that carries over between runs.

核心基础构件

常驻智能体的外围架构有五个核心基础构件:事件收件箱、定时器、记忆、权限和发件箱。下面逐一来看。

事件收件箱

大多数 AI 智能体只在用户发消息时运行。相比之下,常驻智能体可以由多种事件触发,包括 webhook、定时任务和后台作业。

一种诱人的做法是让每个事件源直接调用智能体,但这有几种失败模式。例如,两个事件同时到达,可能启动相互竞争的运行;一次崩溃则可能彻底丢失一个事件。

这就是事件收件箱的用武之地。每个来源不直接调用智能体,而是把事件发送到收件箱,由工作进程取走处理。

最简单的版本包含三个组件:

  • 一份持久化的事件列表,通常是一张数据库表;
  • 一个处理器,通常是 HTTP 端点,负责把事件写入列表;以及
  • 一个工作进程,通常是后台服务,负责从列表中读取。

收件箱应跟踪每个事件的状态,并可根据来源提供的唯一标识符对事件去重。关系型数据库很适合做收件箱,每个事件作为新行追加。我们建议先从每个用户一个收件箱开始,如果需要更高并行度,可以进一步拆分。

Diagram of the event inbox. A handler (an HTTP endpoint) writes each event to the inbox, a database table that tracks status and drops duplicates, and wakes the worker. The worker reads what’s pending, starts the run, waits for it to finish, and marks the events done.

新事件到来时,处理器把事件写入收件箱并唤醒工作进程。工作进程读取所有待处理事件,启动一次运行。延续先前工作的事件(例如用户的回复)会恢复现有会话,其他事件则开启新会话。

随后,worker 把事件交给智能体循环,等待本次运行结束,再把对应事件标记为已完成。具体实现有不少门道,下面列出几条最佳实践:

  • 处理程序应当尽快确认收到事件。有些来源(比如 webhook 提供方)会把响应慢当成失败。处理程序仍可做轻量检查,但更深入的校验(例如检查提示词注入)应放到运行阶段完成。
  • 收件箱应当作为唯一可信来源。worker 被唤醒后,应先从收件箱拉取最新事件。这样即使 worker 在运行中途挂掉,新起的 worker 也能拿到同一个事件并重试。
  • 一个收件箱同一时间只应有一个活跃 worker。这样可以避免两次运行重复干活或互相覆盖。如果运行中途来了新事件,你可以把它推到下一轮运行、并入当前运行,或者中断当前运行重新开始。
  • worker 应把待处理事件批量合并。例如用户连续发来几条消息,worker 可以把它们合并成一次运行,智能体只需回复一次。

定时器

定时器与事件收件箱配合,让常驻智能体具备主动性。定时器一般分两类:跟进和日程。跟进是智能体给自己设的截止时间,比如到点去查看某个回复;日程则是按固定节奏重复执行的任务,比如每日简报。

定时器存放在自己独立的持久化存储里,通常是另一张数据库表,与收件箱分开。收件箱只应存放已经可以处理的事件。跟进和日程可以共用相似的 schema,但日程还需要额外记录重复规则。

Diagram of timers. A run sets a timer in a database table, either a follow-up set by the agent or a schedule set by the user. A scheduler finds what’s due and adds an event to the event inbox, which starts the next run.

定时器本身不会发起运行。真正干活的是调度器,通常是一个后台服务,它按固定间隔轮询存储,把到期的定时器触发出去。每一轮调度中,调度器会:

  1. 扫描存储,找出已到期的定时器。
  2. Updates each timer based on its category.
    1. 跟进类定时器应标记为已完成。
    2. 日程类定时器应把到期时间更新为下一次触发时间。
  3. 向收件箱添加一个事件,并唤醒 worker。

调度器可以自己写一个服务,也可以直接用持久化执行引擎。

记忆

常驻智能体要跨越许多彼此独立的运行,靠记忆来保持连续性。

和事件收件箱、定时器一样,记忆也应有自己的存储。在我们的产品里,比如 Claude Code 的 auto memory 和 Messages API 的 memory tool,记忆被实现为一个文件目录。对常驻智能体来说,这些目录应映射到持久化存储,通常是数据库或对象存储,这样记忆的生命周期就能长于 worker。

一条经验法则是:记忆只应保存智能体无法再次查到的东西。如果某些信息已经存在于其他系统(比如问题跟踪器),那就存一个指针即可。下面是常驻智能体应当保存的记忆类型:

  • 用户指令:用户关于智能体行为的任何指令都应单独存成一个文件,并在每次运行开始时加载。用户不会总在旁边给智能体指方向,所以这些指令必须能跨运行延续下去。
  • 用户笔记:智能体应当保存它了解到的用户信息,比如用户的角色、偏好,或者用户给出的纠正。你可以先从一个文件开始,随着笔记增多再拆成多个小文件。拆成多个文件后,每次运行开始时只加载一个索引,需要更多细节时智能体再把对应的单个文件拉进上下文。
  • 历史消息:智能体应当记录自己已经告诉过用户什么,避免重复。它可以把它存进一个单独的文件,在每次运行开始时加载;也可以让执行单元加载智能体与用户最近几条消息。
  • 任务进度:对每个进行中的任务,智能体应当维护一个进度文件,记录已完成和待完成的部分。这样任何一次新的运行都能读取该文件,从上次中断的地方接着做。和用户笔记类似,每次运行开始时只加载索引,需要更多细节时智能体再把单个文件拉进上下文。

下图展示了一种示例配置。

Diagram of an example memory setup as a directory of files. instructions.md, index.md, and reported.md are loaded at the start of every run, while the notes/ and progress/ folders are read when needed. The agent writes to memory during the run.

以上说的都是运行期间保存的记忆。你还可以加入“做梦”机制,回顾过去的会话以整理记忆。做梦可以替换过时的条目,并发现只有跨多次运行才会显现的规律。如果想了解更多,我们的智能体记忆文章有更详细的介绍。

上下文窗口内部

在开始任何工作之前,智能体会加载系统提示词、工具定义和记忆文件。这部分初始上下文的“开销”会包含在每次运行中,所以我们建议保持精简,并使用提示词缓存来降低成本。

新会话开始时只有这部分上下文开销,以及触发本次运行的事件。而已有会话则会带回它此前各次运行中的消息和工具调用。

如果会话变得过长,你可以压缩较早的消息,或者开启一个新会话。这两种做法都会丢失细节,所以任何需要长期保留的内容都应当随时写入记忆。

Animated chart of context used over time. A fixed band for the system prompt, tools, and memory is present on every run. An existing session brings back its whole transcript and grows until compaction turns the older transcript into a summary.

权限

权限是常驻智能体风险最大的地方。一次运行持有用户的访问权限,而且按设计是在无人值守的情况下运作。对每次工具调用,智能体都需要判断是自己继续执行、阻止,还是等待批准。

权限相关的组件与其他智能体所用的相同:

  • 凭据存储:常驻智能体往往需要密码或访问令牌这类敏感的用户凭据才能发挥作用。推荐的做法是在智能体环境之外设一个代理,由它给对外请求加上凭据。智能体发送不带凭据的请求,代理在转发前注入真实凭据。
  • 自动模式:常驻智能体应当能在没有用户持续输入的情况下工作。我们已经在 Claude Code 的自动模式中处理过这类问题的一个版本。自动模式用分类器审查风险较高的操作,拦截被判定为危险的操作,让 Claude 能找到更安全的做法。不过,最重要的决策仍然需要用户审核。
  • 延迟工具调用:在 Claude Code 中,钩子可以延迟一次工具调用,等待用户提供更多输入。同样的模式也适用于常驻智能体:它们在执行某些操作前,可能需要用户澄清或批准。调用被延迟时,本次运行结束,会话在调用中途保存。请求会展示给用户(例如通过用 MCP Apps 构建的交互式卡片),用户的回答则以事件形式回到收件箱。该事件会启动一次新的运行,带着用户的输入恢复已保存的会话。在延迟调用等待响应期间,工作进程可以继续处理其他事件,因此智能体不会被阻塞。

发件箱

大多数 AI 智能体在生成回复时会实时流式输出给用户,让用户能跟随 Claude 一步步推理问题、调用工具并写出答案。

而常驻智能体的大部分工作都在后台完成。用户拿到的是结果和少量细节,而不是完整的逐步过程。

Diagram of the outbox. A run ends with nothing to say, a send tool call, or a deferred tool call that asks the user. Messages go to the outbox, a database table, and a dispatcher delivers them to the user. A deferred request can go through the outbox or be shown in your own interface.

一次运行可能以三种方式之一结束:

  • 智能体向发件箱发送一条消息;
  • 智能体判断无需发送任何内容;
  • 智能体通过延迟工具调用来请求权限或补充输入。

大多数常驻智能体用一个“发送”工具直接把消息送达用户就够了。只有当你需要控制智能体发消息的节奏,或让智能体从错误中恢复时,才需要正式的发件箱。

发件箱是一张单独存放待发消息的表,对应事件收件箱。此外还有一个调度器,通常是后台服务,对应工作进程。调度器读取待发消息,决定投递哪些,再把它们发送给用户。延迟工具调用发出的请求既可以走发件箱,也可以直接在界面中展示。

除了投递,调节智能体发送消息的数量也很重要。发得太多会变得吵闹,发得太少又会漏掉用户需要知道的事情。我们建议通过构建评估来找到合适的平衡点。实践中,智能体最好一开始保持安静,再逐步赢得用户更多的关注。

各部分如何协同

以下是五个基础组件如何组合在一起:

Animated diagram of how the five primitives fit together. Timers and the event inbox start a run, the run works with memory and permissions inside a session, and the outbox delivers messages to the user, whose answer comes back as an event.

每次运行都始于收件箱中的一个事件,无论是用户消息、webhook 还是定时器。工作进程取到事件后,就启动一次运行,在新的或已有的会话中唤醒智能体。智能体读取记忆以获得基线,在权限范围内执行操作,然后把学到的东西更新到记忆中。运行结束后,智能体向发件箱写入一行记录,由调度器把消息投递给用户。

这些环节共同构成一个循环。一次运行可以设置定时器,稍后再次唤醒智能体;当用户回复消息时,其回答又会作为事件回到收件箱。每次运行都很短暂,但这个循环会一直持续下去,这正是智能体让人感觉始终在线的原因。

致谢

作者:William Hu。特别感谢 Rodrigo Olivares 和 Michael Segner 的贡献。

来源:Claude:Blog · claude.com

事件后续 · 1

查看事件全部