跳转至

11 · 审批、预算、成本与审计

ApprovalsBudget Hard StopCost LedgerDecisionsActivity Audit

一句话结论: Paperclip 把“能做”与“现在可以做”分开:授权给出能力边界,Approval/Decision 处理人类判断,Budget 在执行前和记账后双重收敛,Activity/Cost/Audit 保存可追责证据。

1. 治理热路径

flowchart LR
  INTENT["Agent / User intent"] --> AUTH["Authorization"]
  AUTH --> BUDGET{"Budget / quota"}
  BUDGET --> APPROVAL{"Approval / interaction / tool policy"}
  APPROVAL --> EXEC["Mutation / tool call / run"]
  EXEC --> COST["Usage + cost ledger"]
  COST --> ENFORCE["Threshold enforcement"]
  EXEC --> AUDIT["Activity / decision / call audit"]

治理不是一个“Admin 页面”,而是嵌入 wakeup、hire、tool call、strategy、secret 和 mutation 路径。

2. Approval 的状态机

状态包括:

pending
  ├─→ revision_requested → resubmitted/pending
  ├─→ approved
  ├─→ rejected
  └─→ cancelled

Approval 保存 company、type、requestor、payload、status、resolution actor/time,以及 comments/linked issues。

不同 approval type 的 payload 和批准副作用不同,不能只做一个通用 status = approved。

3. Resolution 使用条件更新

批准/拒绝要避免两个 Board 成员同时决策覆盖。概念上:

UPDATE approvals
SET status = :outcome, resolved_at = now(), resolved_by = :user
WHERE id = :id AND status IN ('pending', 'revision_requested')
RETURNING *;

0 行后重新读取:

  • 已经是同一结果 → 幂等返回;
  • 已由他人做出不同结果 → 409;
  • 已取消/终态 → 不允许重写历史。

这是与 Issue checkout 相同的 CAS 思路,用于人类并发决策。

4. Hire Approval 的事务副作用

批准一次 hire 可能需要:

  1. 验证 draft/pending Agent 与 Company;
  2. 激活 Agent 或从 payload 创建;
  3. 建立 budget policy;
  4. 记录组织关系和配置 revision;
  5. 发送首次 hire/assignment wake;
  6. 记录 activity。

拒绝则终止/归档 draft Agent,不能留下可被 scheduler 调用的半激活员工。

这说明 Approval 是“受控命令”,不只是表单工单。

5. Approval、Interaction、Decision 的区别

对象 典型用途 谁参与 输出
Approval 招聘、策略、特权动作 Board/授权审批人 approved/rejected/revision
Issue Thread Interaction Agent 在任务线程中询问/确认/请求选择 assignee、指定 participant、人或 Agent response/verdict + continuation
Decision 更丰富的方案、证据、签名、影响和长期学习 决策队列/Board selected option/effects/retention

Tool action request 又是一类特化审批:它签署具体 arguments hash,批准后只能重试同一参数。

不要把所有“等待人点一下”塞进 Approval,否则会失去任务 continuation、参数意图签名和决策学习语义。

6. Budget Policy 模型

Budget policy 通常包含:

  • scope(company/agent/project 等);
  • metric(常见为 billed cents);
  • rolling/calendar window;
  • limit;
  • warning threshold percentage;
  • hard-stop 行为;
  • enabled/status。

budget_incidents 按 policy + window + threshold 去重,避免每次 cost event 都创建同一报警。

7. 为什么要“执行前检查 + 记账后执行”

执行前

enqueueWakeup 和 invokability 检查当前窗口 spend,已经达到硬限制就不再创建可执行 run。

执行后

新 cost event 可能让累计值跨过阈值。Budget service 需要:

  • 更新 spend/read model;
  • 生成 warning/hard incident;
  • 在 100% 硬阈值暂停 Agent 或 scope;
  • 阻止后续 invocation;
  • 处理正在排队/可取消工作;
  • 记录活动与通知。

只做执行前检查会有并发窗口:多个 run 同时看到“还剩一点”并全部启动。因此系统还需要 cost ingestion 后收敛,且对高风险场景应保守预留或限制并发。

8. Cost Event 是账本,不是 Agent 表上的一个数字

cost_events 连接:

  • company;
  • agent;
  • issue/project/goal;
  • heartbeat run;
  • provider/biller/model;
  • event/status/type;
  • input/output/cache token;
  • billed cents;
  • occurred time。

Agent/Company 上的 spend 更像快速读模型;细粒度 cost event 才支持:

  • 按 provider/biller 时间线;
  • 归因到任务和目标;
  • 纠正/退款/状态变化;
  • 审核预算窗口;
  • 构建 Finance 页面。

9. “Provider”与“Biller”分开

模型运行提供方和最终计费方可能不同:

  • 本地 CLI 使用订阅,不按 API token 逐次计费;
  • gateway/provider 代付;
  • Cloud Agent 返回自己的账单;
  • 手工 finance event 不对应 token。

因此 UI 有按 provider、biller、kind 的不同聚合,避免把技术来源误当财务归属。

10. 硬停的状态传播

sequenceDiagram
  participant A as Adapter Result
  participant C as Cost Service
  participant B as Budget Service
  participant DB as PostgreSQL
  participant H as Heartbeat Scheduler
  participant UI as Board UI

  A->>C: usage + billed cost
  C->>DB: append cost event
  C->>B: evaluate affected policies/windows
  B->>DB: create incident (idempotent)
  alt hard threshold crossed
    B->>DB: pause/block agent or scope
    B->>H: suppress future invocation / cancel eligible queued work
    B->>UI: activity + live update
  else warning crossed
    B->>UI: warning incident
  end

“自动暂停”必须持久化;如果只停止当前内存 scheduler,Server 重启后会忘记预算已经耗尽。

11. Budget Incident 的处置

Incident 状态包括 open/resolved/dismissed。典型 resolution action:

  • keep_paused;
  • raise_budget_and_resume。

提高预算并恢复要作为一个受授权的组合动作:先更新 policy/limit,再确认当前窗口不再 blocked,最后恢复 Agent 并记录谁做了决定。

12. Activity Log:业务事件账本

activity_log 保存:

  • company;
  • actor type/id;
  • action;
  • entity type/id;
  • agent/run/responsible user;
  • details;
  • timestamp。

它服务于 Board feed、审计和实时失效。Activity 不应包含 secret 明文或无限大的 adapter payload。

典型动作:Issue created/updated/commented/checkout、Agent status、approval resolution、watchdog、budget incident、workspace、plugin 等。

13. 专用 Audit 不能全塞 Activity

某些领域需要更细结构:

  • tool call event:profile/policy decision、risk、arguments/result redaction;
  • secret access event:谁在何 run 投影了哪个 version;
  • connection lifecycle:OAuth/catalog/health;
  • heartbeat run event:运行时顺序;
  • decision signing:选项、证据、签名 bundle。

Activity 是跨领域摘要,专用表保存可查询的领域证据。

14. Decision 系统

Decision 不只保存一个答案,还可包含:

  • inputs/evidence;
  • options;
  • selected outcome;
  • signed bundle;
  • target/effects;
  • queue/triage;
  • attention 与 retention;
  • training example。

它把“组织为什么这样决定”变成可学习资产,而非只留一条评论。Decision queue、attention 和 training 是 Agent employee training 支柱的一部分。

15. Tool Approval 的意图签名

高风险 tool call 的 approval 记录:

  • tool/catalog/schema identity;
  • canonical arguments hash;
  • signed arguments;
  • actor/run/issue;
  • expiry。

批准后 Agent 重试必须携带 approvedActionRequestId,Gateway 重新计算参数 hash:

hash(retry arguments) == approved hash

否则返回 signed_arguments_mismatch。这防止“批准读取 A,实际重试删除 B”。

批准还可被提升为有范围、次数或 expiry 的 trust rule;tool/schema/arguments 漂移会使其失效。

16. 失败与边界

场景 系统原则
两人同时批准 CAS,只接受首个终态;同结果幂等
Agent 声称已批准 不采信文本,只查持久化 Approval/Action Request
cost event 重复 使用来源/业务键去重,避免重复计费
多 run 同时跨预算 记账后 hard-stop 收敛,未来 invocation 被阻断
提高预算后恢复 组合授权动作并留活动记录
审计含敏感值 redaction/summary/hash,secret value 不落普通日志
Approval 已过期 不允许旧批准授权新动作

17. 可复用经验

  1. Authorization 与 Approval 分层:前者判能力,后者判具体高影响动作。
  2. Approval resolution 使用 CAS,并为同结果重试提供幂等。
  3. 预算在调度前阻断、记账后收敛,两边都不可少。
  4. 细粒度 cost event 是事实,聚合 spend 是读模型。
  5. 高风险工具批准应签署规范化参数,而不只签 tool name。
  6. 跨领域 activity 和领域专用 audit 分开。
  7. 决策应保存证据、选项和效果,才可能形成组织学习。

源码入口

  • packages/db/src/schema/approvals.ts、approval_comments.ts
  • server/src/services/approvals.ts
  • packages/db/src/schema/budget_policies.ts、budget_incidents.ts
  • server/src/services/budgets.ts
  • packages/db/src/schema/cost_events.ts、finance_events.ts
  • server/src/services/costs.ts、finance.ts
  • packages/db/src/schema/activity_log.ts
  • server/src/services/activity-log.ts
  • packages/db/src/schema/decisions.ts、decision_queues.ts
  • server/src/services/decisions.ts、decision-signing.ts

这些事实最终都落在 PostgreSQL。下一章:12 · PostgreSQL、Drizzle 与迁移。