Paperclip 里的 Agent 不是常驻进程:心跳、唤醒与一次运行链路

2026-08-17

很多人第一次配 Paperclip 的 agent,会拿常驻服务的思路去理解它:以为建好一个 agent,它就在后台一直转,任务来了自动接。然后就会遇到一堆看起来矛盾的现象——明明 agent 状态是 active,却半天没动静;改了提示词,下一次运行好像还带着上一轮的记忆;把超时时间填成 0,本以为是”不允许运行”,结果它跑得比谁都久。

这些都不是 bug,是因为 Paperclip 的执行模型和常驻进程根本不是一回事。官方文档《How Agents Work》开篇就把话说死了:agent 是”醒来、干活、再睡回去”的 AI 员工,它们不持续运行,而是在被称作 heartbeat(心跳)的短窗口里执行。

搞懂这一句,上面那些现象就全串起来了。这篇按官方的《How Agents Work》和《Agent Runtime Guide》两份文档,把一次心跳从触发到落盘的完整链路、以及每一环你能配什么,逐段捋一遍。

一次 heartbeat 到底发生了什么

《How Agents Work》给的执行模型是六步:

  1. Trigger——某个东西把 agent 叫醒(调度、任务分派、被提及、手动触发);
  2. Adapter invocation——Paperclip 调用这个 agent 配置的适配器;
  3. Agent process——适配器拉起 agent 运行时,文档举的例子是 Claude Code CLI;
  4. Paperclip API calls——agent 自己去查分派、认领任务、干活、更新状态;
  5. Result capture——适配器把输出、用量、成本和会话状态捕获回来;
  6. Run record——Paperclip 把这次运行的结果存下来,供审计和调试。

《Agent Runtime Guide》从运维视角又描述了一遍同一件事,措辞更贴近实际发生的顺序:启动配置好的适配器(比如 Claude CLI 或 Codex CLI)→ 把当前的提示词和上下文给它 → 让它一直干到自己退出、超时或被取消 → 存下结果(状态、token 用量、错误、日志)→ 实时更新界面。

两份文档合起来,有三个点值得单独拎出来:

第一,真正在干活的是适配器拉起来的那个进程,不是 Paperclip 本身。Paperclip 负责叫醒、给上下文、收结果。

第二,agent 是主动调 Paperclip API 的一方。它醒来之后自己去查”有什么分派给我”、自己认领、自己更新状态,而不是被动接收一条指令。

第三,每次心跳都会留下一条 run 记录,带状态、错误文本、stderr/stdout 摘录、token 用量。这条记录是后面所有排查的起点。

四种唤醒来源,以及重复唤醒为什么不会叠加

《Agent Runtime Guide》列了四种唤醒方式:

唤醒类型含义
timer按调度间隔(文档举例:每 5 分钟)
assignment有工作被分派/签出给这个 agent 时
on_demand手动唤醒(按钮或 API)
automation系统触发,文档写明是留给后续自动化用的

关键一句在下面:如果一个 agent 已经在运行中,新的唤醒会被合并(coalesced),而不是再拉起一次重复运行。

这条对排查很有用。如果你连点几次手动唤醒、又赶上定时器到点,看到的仍然只是一次运行,那是设计如此。同样地,“agent 状态 active 却没动静”通常也不神秘:active 在文档里的定义只是”准备好接收心跳”,不等于此刻正在跑;正在跑的状态叫 running

对应的心跳策略在 agent 运行时设置里配,字段是这几个:

  • enabled:是否允许调度心跳;
  • intervalSec:定时器间隔,填 0 表示禁用
  • wakeOnAssignment:分派时唤醒;
  • wakeOnOnDemand:允许 ping 式的按需唤醒;
  • wakeOnAutomation:允许系统自动化唤醒。

运行时注入了哪些环境变量

这部分是写自定义 agent 时最实用的一段。《How Agents Work》说明,每个 agent 在运行时都会被注入一组环境变量:

变量说明
PAPERCLIP_AGENT_IDagent 的唯一 ID
PAPERCLIP_COMPANY_IDagent 所属的公司
PAPERCLIP_API_URLPaperclip API 的基础 URL
PAPERCLIP_API_KEY用于 API 鉴权的短期 JWT
PAPERCLIP_RUN_ID当前这次心跳的 run ID

当这次唤醒有具体触发源时,还会额外注入一组上下文变量:

变量说明
PAPERCLIP_TASK_ID触发这次唤醒的 issue
PAPERCLIP_WAKE_REASON唤醒原因,文档给的例子是 issue_assignedissue_comment_mentioned
PAPERCLIP_WAKE_COMMENT_ID触发这次唤醒的具体评论
PAPERCLIP_APPROVAL_ID被处理掉的审批
PAPERCLIP_APPROVAL_STATUS审批结论,取值 approvedrejected

注意 PAPERCLIP_API_KEY短期 JWT,不是长期密钥;换句话说,agent 侧的代码不该把它缓存到下一次心跳去用。第二组变量则决定了 agent 醒来后第一步该干什么——同样是被叫醒,issue_assignedissue_comment_mentioned 显然要走不同分支。

内置适配器:跑的其实是你本机那个 CLI

《Agent Runtime Guide》列出的内置适配器有这些:

  • claude_local:跑你本地的 claude CLI
  • codex_local:跑你本地的 codex CLI
  • opencode_local:跑你本地的 opencode CLI
  • cursor:以后台模式运行 Cursor
  • pi_local:本地跑一个内嵌的 Pi agent
  • hermes_local:通过 @paperclipai/hermes-paperclip-adapter 启动本地 hermes CLI
  • hermes_gateway:通过 @paperclipai/hermes-paperclip-adapter/gateway 调用一个已经在跑的 Hermes API 服务
  • openclaw_gateway:连接一个 OpenClaw 网关端点
  • process:通用 shell 命令适配器
  • http:调用外部 HTTP 端点

另外还有外部插件适配器,通过适配器管理器或 API 安装,文档列的是 droid_local(跑本地 Factory Droid CLI,包名 @henkey/droid-paperclip-adapter)。

有一条前置假设必须记住:对本地 CLI 类适配器(claude_localcodex_localopencode_localhermes_localdroid_local),Paperclip 假定这些 CLI 已经在宿主机上装好并完成认证。它不负责替你装、替你登录。hermes_gateway 同理,假定 Hermes API 服务已在运行、Paperclip 服务器能访问到、并且配了 API key。文档还专门说明,旧的 @paperclipai/adapter-hermes-gateway npm 包只是一个已废弃的兼容垫片,适配器类型名仍然是 hermes_gateway

适配器怎么选、各自的接法差异,另有专篇,可参考 五类适配器分别怎么接

timeoutSec 填 0 和填负数,语义完全不同

本地适配器要配工作目录和执行限制,这几个字段的语义有坑:

  • cwd:工作目录;
  • timeoutSec:每次心跳的最长运行时间。0 用的是目标(target)的默认值——本地/SSH 目标下没有适配器超时,沙箱目标下有 4 小时兜底;填负值则在所有环境下都关闭适配器超时,包括沙箱
  • graceSec:超时或取消之后,强杀之前留的缓冲时间;
  • 可选的环境变量和额外 CLI 参数。

所以开头那个”填 0 反而跑得没完没了”的现象,就是这条规则的直接后果:0 不是”不给时间”,是”用目标默认”。真要限制,就填一个正数。文档同时提到,agent 配置里有 Test environment,可以在保存前跑适配器相关的诊断。

提示词模板这块只有一个字段是推荐的:promptTemplate,每次运行都用(首次运行和续接会话都一样),支持 {{agent.id}}{{agent.name}} 这类变量以及运行上下文的值。文档明确写了 bootstrapPromptTemplate 已废弃,新 agent 不要用,老配置虽然还能跑但应迁移到托管指令包(managed instructions bundle)体系。

工作目录这一环还牵扯到执行工作区的组织方式,见 执行工作区与 git worktree

会话为什么会”记得”上一轮,以及什么时候该重置

《How Agents Work》讲的是机制:agent 通过会话持久化在多次心跳之间保持对话上下文,适配器在每次运行后把会话状态序列化下来(例如 Claude Code 的 session ID),下次唤醒时再恢复。文档给的收益是——agent 不用把所有东西重读一遍就记得自己在干什么。

《Agent Runtime Guide》讲的是运维口径:Paperclip 会给可续接的适配器存 session ID,下一次心跳自动复用;你也可以在上下文变陈旧或跑歪时重置会话。文档给的三个重置时机:

  • 你大幅改了提示词策略;
  • agent 陷在一个坏循环里出不来;
  • 你就是想干干净净重来一次。

这也解释了”改完提示词第一次运行没生效”的困惑:会话是续接的,旧上下文还在。改了策略就顺手重置一次。

两张状态表:agent 状态 vs run 状态

这两套状态经常被混着看,实际上是两个维度。

agent 状态(来自《How Agents Work》):

状态含义
active准备好接收心跳
idle处于活跃状态,但当前没有心跳在跑
running心跳进行中
error上一次心跳失败
paused手动暂停,或超预算被停
terminated永久停用

单次 run 的状态(来自《Agent Runtime Guide》):queuedrunningsucceededfailedtimed_outcancelled。每条 run 还带错误文本与 stderr/stdout 摘录、适配器能提供时的 token 用量与成本,以及完整日志(日志单独存放,针对大输出做过优化,本地/开发环境下落在配置的 run-log 路径里)。

注意 paused 的两种成因里有一条是超预算——所以 agent 突然不干活了,别只盯着适配器,先看预算是不是被打满了。至于”心跳该有却没有”这一类问题,另有 Agent 不干活:心跳、看门狗、卡住怎么查 专门讲排查路径。

运行反复失败时,按这个顺序查

文档给了固定顺序,照着走就行:

  1. 检查适配器命令是否可用(claude / codex / opencode / hermes 装了没、登录了没);
  2. 确认 cwd 存在且可访问;
  3. 先看 run 的错误信息和 stderr 摘录,再看完整日志;
  4. 确认超时时间不是设得太低;
  5. 重置会话再试;
  6. 如果它在反复产生糟糕的更新,先把 agent 暂停掉。

典型失败原因文档也列了:CLI 没装或没认证、工作目录不对、适配器参数或环境变量写错、提示词太宽泛缺约束、进程超时。

还有一条 Claude 专属提醒:如果适配器环境变量或宿主机环境里设了 ANTHROPIC_API_KEY,Claude 会走 API key 认证而不是订阅登录。Paperclip 在环境测试里把这个报成警告,不是硬错误。这条容易背刺——你以为在用订阅额度,实际在按 API 计费。

三种运行节奏,按风险选

文档把常见操作模式归成三类:

模式配置要点
简单自治循环开定时唤醒(举例 300 秒)+ 保持分派唤醒;用聚焦的提示词模板,要求 agent 在同一次心跳内就动手、留下可持久的进展、被卡住时标明负责人和动作;再看日志迭代配置
事件驱动循环关掉定时器或设很长的间隔,保留分派唤醒;用子 issue、评论、按需唤醒来做交接,而不是靠轮询 agent、会话或进程
安全优先循环短超时、保守提示词、盯错误并及时取消、发现漂移就重置会话

最小可用清单也很短:选适配器 → 本地适配器设好 cwd → 可选加 promptTemplate 或用托管指令包 → 配心跳策略 → 手动触发一次唤醒 → 确认运行成功且会话与 token 用量都记上了 → 看实时更新并迭代。

一次运行内部具体经历了哪些语义环节,超出了这两份文档的范围,见 执行语义:一次运行到底做了什么

什么时候这套模型不适合你

有几种情况值得先想清楚再上手。

要求毫秒级响应的场景不适合。 心跳是短窗口执行,定时器最快也是按秒配的间隔,加上唤醒合并机制,天然不是给同步请求用的。

不能接受本地无沙箱执行的环境要慎重。 文档在安全与风险一节写得很直白:本地 CLI 适配器在宿主机上不加沙箱运行。由此文档提醒三件事——提示词里写的指令是有实际后果的、配置的凭据和环境变量是敏感的、工作目录权限很重要。官方给的原则是尽量最小权限起步,除非确有必要,别把密钥暴露在通用的可复用提示词里。

如果你的 agent 状态必须完全靠外部系统维护,会话续接反而是负担。 它默认帮你保留上下文,而你可能每次都想要干净起点,那就得主动管理重置节奏。

最后是这两份文档没覆盖的部分。适配器各自的参数细节、processhttp 两类通用适配器怎么对接自建 agent、审批与预算的具体机制、执行工作区的隔离方式,都在各自的专篇里,本文只到”驱动链路”这一层为止。文档标注 automation 唤醒是留给后续自动化能力的,具体形态官方文档在这两份里没有展开。

延伸阅读


本文依据 Paperclip 官方仓库(github.com/paperclipai/paperclip,MIT 协议)的 docs/ 用户文档 与 doc/ 下的规范、运维与连接器手册整理,核对日 2026-08-17。 我们没有部署或运行过 Paperclip,因此不涉及界面外观与操作手感; 部分规范文档描述的是目标架构而非当前实现,文中已就地标注,不构成对实际行为的保证。 请以仓库最新内容为准。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。