跳转至

01 · 产品定位与拆解方法

产品边界控制平面四大支柱拆解方法

一句话结论: Paperclip 不是“再包一层模型调用”,而是把 Agent 当成员、把任务当可竞争资源、把每次执行当可审计事务的组织控制平面。

1. 从产品口号还原工程问题

README 用一句很准确的话定位它:如果某个 Agent 运行时像“员工”,Paperclip 就像“公司”。这句话背后至少包含七个必须由软件解决的问题:

  1. 身份:谁是人,谁是 Agent,当前请求代表谁?
  2. 组织:Agent 向谁汇报,谁能委派、暂停或终止谁?
  3. 工作:任务处于什么状态,谁拥有它,依赖何时满足?
  4. 执行:什么时候唤醒哪个 Agent,在什么目录、环境和会话中运行?
  5. 治理:哪些动作必须审批,哪些工具可见,预算耗尽时能否硬停?
  6. 恢复:进程、服务器或上游失败后,怎样避免永久悬空或重复执行?
  7. 证据:人如何知道任务真的完成,而不是 Agent 只说“完成了”?

普通任务管理器主要处理第 3 项,普通 Agent SDK 主要处理第 4 项的一小部分。Paperclip 的主体恰恰在它们之间:把组织意图转成受约束、可恢复的执行。

2. “控制平面”到底控制什么

Paperclip 把系统划成两层:

flowchart TB
  subgraph CP["Paperclip 控制平面"]
    ID["身份与权限"]
    WORK["目标 / 项目 / Issue"]
    SCHED["Wakeup / Heartbeat / Recovery"]
    GOV["审批 / 预算 / 审计"]
    RUNTIME["Workspace / Environment / Tool Gateway"]
  end

  subgraph EP["外部执行面"]
    CLAUDE["Claude Code"]
    CODEX["Codex"]
    GEMINI["Gemini / Grok / Pi"]
    HTTP["HTTP / Process / Gateway Agent"]
  end

  CP -->|"任务、短期凭据、上下文、约束"| EP
  EP -->|"事件、用量、产物、状态、会话"| CP

控制平面保存“应然”和“事实”:应该做什么、谁能做、一次执行是否仍然有效、消耗多少、是否需要批准。执行面负责真正调用模型和工具。

控制平面不等于完全不启动进程

本地 adapter 会由 Server 启动 CLI 子进程,runtime service 也可能由 Paperclip 管理。所谓“控制面而非执行面”是架构职责:Paperclip 不把某个模型 loop 写死为核心,它通过 adapter contract 管理多种运行时。

这解释了为什么 adapter-utils、adapter registry、session codec、workspace realization 都是一等模块,而不是散落在某个 runAgent() 函数里的 if/else。

3. 四大支柱怎样落到源码

README 的“四大支柱”不是纯营销分类,它们可以映射到明确的代码群。

支柱 产品含义 主要源码落点
Agentic Task Manager 意图、任务、评审与输出证据 issues、comments、documents、work products、execution policy
Org Chart for Agents 人与 Agent 的角色、汇报、权限和边界 agents、memberships、authorization、approvals
Agent Employee Training Skills、测试运行、团队模板与学习 company skills、skills catalog、teams catalog、evals
Agentic OS 多运行时、sandbox、MCP、密钥、成本和恢复 heartbeat、adapters、workspace、tool gateway、secrets、recovery

这四组能力共享同一个 Company 边界和活动日志,所以它们不是四个互不相干的产品。

4. 最重要的对象不是 Agent,而是 Company

Paperclip 支持一个实例运行多家公司。绝大多数业务表都有 companyId,绝大多数服务方法要求先给出 company scope,实时事件也按 company channel 发布。

这带来一个很重要的建模顺序:

Instance
  └─ Company
      ├─ people / agents / memberships / permissions
      ├─ goals / projects / issues / documents
      ├─ budgets / approvals / secrets / tool policies
      └─ runs / workspaces / events / audit

Agent 不是跨公司漂移的全局进程;它首先是某家公司的 principal 和 employee。跨公司读取失败时,很多路由倾向返回“not found”而不是暴露目标存在性。

5. 规划对象、执行对象和证据对象

Paperclip 没把所有东西塞进 Issue:

类别 代表对象 回答的问题
规划 Goal、Project、Issue、Routine、Pipeline Case 为什么做、做什么、怎样分解
执行 Wakeup Request、Heartbeat Run、Session、Execution Workspace、Lease 这一次由谁、在哪里、以什么上下文做
证据 Activity、Run Event、Document Revision、Attachment、Work Product、Cost Event 做过什么、花了多少、输出在哪里

这种三分法是读懂源码的关键。比如:

  • Issue 是 done,不代表任何历史 run 必须保持 running;
  • Run succeeded,也不必然代表 Issue 已 done,它可能只推进了一步;
  • 文件出现在 workspace 中,不等于它已经成为可远程审查的 artifact;
  • 一次 wakeup 被合并,不等于相关业务事件消失,它仍可有持久化请求记录。

6. 产品承诺被写成哪些硬不变量

仓库的 AGENTS.md 和实现共同强调一组“不能只靠 Prompt”的规则:

6.1 公司隔离

创建、读取、更新都必须携带或推导 company scope;关联对象要再次验证同公司。

6.2 单一受让人

Issue 同时只有一个 assignee。责任所有权和当前执行锁分字段保存,checkout 用条件更新竞争。

6.3 原子认领

两个 Agent 同时认领,数据库只允许一个满足旧状态前置条件;另一个得到 409 或进入明确的 stale-lock adoption 分支。

6.4 审批门

聘用、策略、工具写操作等高影响动作不会因为 Agent 声称“已经获批”就放行,服务端要核对持久化审批状态、参数哈希和权限上下文。

6.5 预算硬停

预算不是仪表盘数字。达到硬阈值后,invokability 检查会阻断新运行,并触发暂停或收敛动作。

6.6 活动留痕

关键 mutation 同时产生 activity 或更细粒度的 audit/cost/run event,使“当前状态”与“为何到达当前状态”可以分别查询。

7. 为什么 Heartbeat 是核心抽象

Agent 不作为永远在线的线程存在,而在短暂执行窗口中醒来:

stateDiagram-v2
  [*] --> Idle
  Idle --> Queued: timer / assignment / mention / manual
  Queued --> Running: claim queue slot
  Running --> Running: tool / model / API work
  Running --> Idle: succeeded + no continuation
  Running --> Queued: retry / follow-up / completion wake
  Running --> Paused: budget / governance / operator
  Running --> Error: terminal failure

Heartbeat 让系统可以:

  • 给每次执行独立的身份、成本和日志;
  • 在会话层恢复上下文,而不是让进程永驻;
  • 对同一 Agent 做排队、合并和并发控制;
  • 服务器重启后依据数据库重建真实状态;
  • 把“还有没有下一步”单独建模为 liveness。

8. 本站怎样拆解它

参考 dg-ai-notes 的写法,本文不以文件列表为纲,而以系统问题为纲。每个问题同时给出:

它是什么
→ 源码怎样实现
→ 为什么这么做
→ 哪些边界容易误解
→ 哪些模式值得复用

同时做三种横切:

  1. 垂直追踪:从 HTTP/UI 入口一路追到 service、DB、event 和 adapter;
  2. 状态还原:把分散的常量、字段和条件更新还原成状态机;
  3. 故障追踪:不只讲成功路径,还追 timeout、stale lock、restart、approval、budget 和 cleanup。

9. 当前实现的三个现实边界

9.1 巨型服务集中复杂度

heartbeat.ts、issues.ts、tool-access.ts 等文件非常大。优点是跨步骤不变量集中,代价是认知负担和修改风险很高。本文会按阶段拆分它们,而不是假装每个文件对应一个小职责。

9.2 事件总线仍是进程内实现

实时事件由 Node EventEmitter 发布,再通过 WebSocket 转发。它简单、低延迟,但没有持久化回放,也天然假定单服务进程;浏览器断线后通过 refetch 对账。

9.3 规格和代码会漂移

例如较旧架构文档提到 PGlite,但当前代码用 embedded PostgreSQL;插件规格也清楚标注当前 UI 扩展仍是 same-origin trusted JavaScript。评估能力时必须把“目标设计”和“已落地防线”分开。

10. 可复用经验

  1. 先把组织与资源边界写进 schema,再写 Agent Prompt。
  2. 把“任务”“执行尝试”“交付证据”建成不同对象。
  3. 为 every wake 建立持久化请求,为 every try 建立独立 run。
  4. 让预算、审批和授权出现在动作之前,而不是事后报警。
  5. 把恢复当成正常状态机,而不是 catch 中的一次补救。

源码入口

  • README.md:产品定位、四大支柱与核心承诺
  • doc/GOAL.md、doc/PRODUCT.md:目标与产品边界
  • doc/SPEC-implementation.md:实现级不变量
  • docs/start/what-is-paperclip.md:控制面/执行面模型
  • packages/shared/src/constants.ts:全局状态词汇

下一章把产品模型映射到代码结构:02 · Monorepo 分层与依赖方向。