返回整理

中文译文 · 原文发布于 2026-11-13

构建常驻 agent

常驻 agent 无限期运行,在许多会话之间自己决定何时行动、怎样行动。这篇指南讲它的核心原语,以及这些原语怎样组合在一起。

作者:William Hu原文阅读时间 14 分钟分类:最佳实践

先说结论

常驻 agent 大部分时间在睡眠,被事件唤醒后做一次短暂的 run,再回去睡。让它显得“一直在线”的是 run 外面的五个原语:事件收件箱、定时器、记忆、权限、发件箱。原文给出的落地做法以数据库表加后台服务为主:每个用户一个收件箱、同一时间只有一个 worker、记忆只存查不回来的东西、发件箱的消息先少后多。

过去几个月,常驻 agent(always-on agent)重新热了起来。

常驻 agent 有状态,也主动:它跨会话管理上下文,在没有直接监督时也会采取行动。底层上,它和其他 agent 跑的是同一个核心循环。区别在外围架构。外围架构由一组原语构成,这些原语决定 agent 何时醒来、哪些东西在两次 run 之间保留、它的工作成果怎样送到用户手里。

这次回潮主要来自最近的模型进步,模型进步让常驻 agent 更实用。第一,最新模型判断力更好:它们更可靠地理解用户意图,也更清楚什么时候该向用户确认。第二,智能在变便宜,长周期任务受益最大。例如在一项长周期编程基准测试上,Opus 5.5 每解决一个任务的成本比 Opus 5 低 78%;在常规工作负载上,这个数字是 40%。

客户开始问我们,怎样把这类体验集成进自己的产品。有些公司想让现有的 agent 更主动,另一些公司想从零构建。

本文拆解常驻 agent 背后的原语,并说明它们怎样组合在一起。

常驻 agent 背后的循环

常驻 agent 其实并不“常驻”。这个词描述的只是用户体验。

实际上,agent 大部分时间在睡眠,定期醒来做事。每一段工作叫一次 run:agent 收到一个事件,完成任务,然后保存这次发生了什么。run 在一个会话(session)里进行,会话就是消息和工具调用的记录。run 结束后,agent 回到睡眠,这个循环无限重复。

图 1:agent 的时间线。睡眠不花 token,每次 run 有四步。点图看原图。

核心原语

常驻 agent 的外围架构有五个核心原语:事件收件箱、定时器、记忆、权限和发件箱。下面逐个看。

事件收件箱

多数 AI agent 只在用户发消息时运行。常驻 agent 不同,它可以被多种事件触发,包括 webhook、定时任务和后台作业。

一个诱人的做法是让每个事件源直接调用 agent,但这有几种失败方式。例如,两个事件同时到达,会启动两个互相竞争的 run;一次崩溃会让某个事件彻底丢失。

事件收件箱就是为此准备的。事件源不再直接调用 agent,而是把每个事件发到收件箱,再由一个 worker 取走处理。

最简单的版本有三个组件:

收件箱应记录每个事件的状态,并可以按事件源提供的唯一标识去重。关系型数据库很适合做收件箱,每个事件追加为新的一行。我们建议从每个用户一个收件箱开始;如果需要更高的并行度,可以再拆分。

事件收件箱示意图。handler(一个 HTTP 端点)把每个事件写入收件箱,收件箱是一张记录状态、丢弃重复项的数据库表,然后唤醒 worker。worker 读取待处理事件,启动 run,等它结束,再把事件标为完成。
图 2:事件收件箱。handler 写入,worker 读取,表里记状态并去重。

新事件到来时,handler 把它写进收件箱并唤醒 worker。worker 读取所有待处理事件,启动一次 run。延续之前工作的事件(例如用户的回复)恢复已有会话,其他事件都开启新会话。

接着,worker 把事件交给 agent 循环,等 run 结束,再把对应事件标为完成。实现细节可能比较棘手,下面是几条最佳实践:

定时器

定时器和事件收件箱一起,让常驻 agent 能够主动行动。定时器一般分两类:跟进(follow-up)和定期任务(schedule)。跟进是 agent 给自己定的截止时间,例如过一阵去看有没有回复。定期任务是按已知节奏重复发生的任务,例如每日简报。

定时器放在自己的持久化存储里,通常是另一张数据库表,和收件箱分开。收件箱只应存放可以立即处理的事件。跟进和定期任务可以用相似的表结构,但定期任务还需要记录重复规则。

定时器示意图。run 在一张数据库表里设置定时器,可以是 agent 设的跟进,也可以是用户设的定期任务。调度器找出到期的定时器,向事件收件箱添加一个事件,由它启动下一次 run。
图 3:定时器。调度器不直接启动 run,而是往收件箱里投事件。

定时器本身不会启动 run。一个调度器(通常是后台服务)按固定间隔轮询存储,触发所有到期的定时器。每轮轮询,调度器会:

  1. 扫描存储,找出到期的定时器。
  2. 按类别更新每个定时器:
    • 跟进标为完成。
    • 定期任务把到期时间更新为下一次发生的时间。
  3. 向收件箱添加一个事件,并唤醒 worker。

调度器可以自己写一个服务,也可以用持久化执行引擎(durable execution engine)。

记忆

常驻 agent 在许多互不相连的 run 之间工作,靠记忆保持连续性。

和事件收件箱、定时器一样,记忆也应有自己的存储。在我们的产品里,例如 Claude Code 的自动记忆和 Messages API 的记忆工具,记忆的实现是一个文件目录。对常驻 agent,这些目录应映射到持久化存储,通常是数据库或对象存储。这样记忆的寿命比 worker 长。

经验法则:记忆只存 agent 无法再查到的东西。如果某样东西已经在别的系统里(例如工单系统),就只存一个指针。常驻 agent 应存的记忆有以下几类:

下图是一种示例配置。

一种以文件目录实现的记忆示例。instructions.md、index.md 和 reported.md 在每次 run 开始时加载,notes/ 和 progress/ 两个文件夹按需读取。agent 在 run 中写入记忆。
图 4:记忆目录示例。instructions.md、index.md、reported.md 每次都加载,notes/ 和 progress/ 按需读。

以上说的都是 run 期间保存的记忆。你还可以加上“做梦”(dreaming):回看过去的会话来整理记忆。做梦可以替换过时的条目,也能发现只有跨许多次 run 才显现的规律。想了解更多,可以看我们关于 agent 记忆的文章。

上下文窗口内部

开始干活前,agent 先加载系统提示词、工具定义和记忆文件。这部分初始上下文“开销”每次 run 都有,所以我们建议保持精简,并用提示词缓存降低成本。

新会话开始时,只有这部分开销和触发本次 run 的事件。已有会话则会带回它之前各次 run 的消息和工具调用。

会话太长时,可以压缩较早的消息,也可以开一个新会话。两种做法都会丢失细节,所以需要保留的东西应在过程中随时存进记忆。

图 5:上下文用量。固定开销每次都在,已有会话不断变长,直到压缩。

权限

权限是常驻 agent 风险最大的地方。一次 run 持有用户的访问权限,而且按设计无人值守。对每个工具调用,agent 都要决定:自己继续、拦下,还是等待批准。

权限用到的组件和其他 agent 一样:

发件箱

对多数 AI agent,回复在生成时就流式传给用户,用户可以看着 Claude 推理问题、调用工具、写出答案。

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

发件箱示意图。一次 run 以三种方式之一结束:无话可说、调用 send 工具、用延迟工具调用询问用户。消息进入发件箱(一张数据库表),由分发器送到用户。延迟请求可以走发件箱,也可以在你自己的界面里展示。
图 6:发件箱。run 的三种结局,以及消息怎样到达用户。

一次 run 可以以三种方式之一结束:

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

发件箱是一张单独的待发消息表,和事件收件箱相对应。还有一个分发器(dispatcher),通常是后台服务,和 worker 相对应。分发器读取待发消息,决定送哪些,再发给用户。延迟工具调用产生的请求可以走发件箱,也可以直接在界面里展示。

除了投递,调好 agent 发多少消息也很重要。发太多,agent 就成了噪音;发太少,会漏掉用户需要知道的事。我们建议构建评测(eval)来找到平衡点。实践中,agent 最好先保持安静,再随时间赢得用户更多的注意力。

各部分如何组合

五个原语这样组合在一起:

图 7:五个原语组成的循环。

每次 run 都从收件箱里的一个事件开始,可能是用户消息、webhook,也可能是定时器。worker 取到事件后启动一次 run,在新会话或已有会话里唤醒 agent。agent 读取记忆获得基础信息,在权限范围内采取行动,再把学到的东西写回记忆。run 结束后,agent 往发件箱推一行,分发器把消息送到用户。

这些部分合起来构成一个循环。一次 run 可以设一个定时器,让 agent 稍后再醒;用户回复消息时,回答作为事件回到收件箱。每次 run 都很短,但循环无限持续,正是这一点让 agent 感觉一直在线。

致谢

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

方法与来源

本页是全文翻译,没有删减或增补原文内容。“先说结论”一块是译者加的摘要,不属于原文。原文抓取于 2026-11-14。七张图来自原文,以原尺寸内嵌;点图可打开原站上的原图。图中文字保留英文,图下说明和替代文本是译文。

术语译法:always-on agent 译作“常驻 agent”;run、worker、handler、webhook 保留英文;session 译作“会话”,event inbox 译作“事件收件箱”,outbox 译作“发件箱”,timer 译作“定时器”,scheduler 译作“调度器”,dispatcher 译作“分发器”,deferred tool call 译作“延迟工具调用”,dreaming 译作“做梦”。

  1. claude.com,William Hu,《Building always-on agents》,2026-11-13,claude.com/resources/articles/building-always-on-agents

返回阅读整理页