11 · 审批、预算、成本与审计¶
一句话结论: 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 的状态机¶
状态包括:
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 可能需要:
- 验证 draft/pending Agent 与 Company;
- 激活 Agent 或从 payload 创建;
- 建立 budget policy;
- 记录组织关系和配置 revision;
- 发送首次 hire/assignment wake;
- 记录 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:
否则返回 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. 可复用经验¶
- Authorization 与 Approval 分层:前者判能力,后者判具体高影响动作。
- Approval resolution 使用 CAS,并为同结果重试提供幂等。
- 预算在调度前阻断、记账后收敛,两边都不可少。
- 细粒度 cost event 是事实,聚合 spend 是读模型。
- 高风险工具批准应签署规范化参数,而不只签 tool name。
- 跨领域 activity 和领域专用 audit 分开。
- 决策应保存证据、选项和效果,才可能形成组织学习。
源码入口¶
packages/db/src/schema/approvals.ts、approval_comments.tsserver/src/services/approvals.tspackages/db/src/schema/budget_policies.ts、budget_incidents.tsserver/src/services/budgets.tspackages/db/src/schema/cost_events.ts、finance_events.tsserver/src/services/costs.ts、finance.tspackages/db/src/schema/activity_log.tsserver/src/services/activity-log.tspackages/db/src/schema/decisions.ts、decision_queues.tsserver/src/services/decisions.ts、decision-signing.ts
这些事实最终都落在 PostgreSQL。下一章:12 · PostgreSQL、Drizzle 与迁移。