feat(ack): add structured worker model routing
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
# 模型路由(稳定核心)
|
||||
|
||||
本文件是**三角色默认模型档位**和**升级规则**的单一事实源(SSOT)。目标:在不牺牲质量的前提下降低 token 和模型成本——把昂贵的强模型留给需要判断的工作,把机械执行交给较弱模型。
|
||||
本文件是**三角色默认模型档位、升级规则和 worker profile 选择规则**的单一规范源。
|
||||
目标是在不牺牲质量的前提下降低 token 和模型成本:把昂贵的强模型留给需要判断的
|
||||
工作,把机械执行交给较弱模型。
|
||||
|
||||
角色定义见 `roles-and-permissions.md`(Coordinator 编排 / Test 验证 / Developer 实现)。本文件只补一层正交的「用哪个档位的模型」。
|
||||
角色定义见 `roles-and-permissions.md`(Coordinator 编排 / Test 验证 / Developer
|
||||
实现)。本文件只补一层正交的「用哪个档位、以什么安全 profile 启动 worker」。
|
||||
|
||||
---
|
||||
|
||||
@@ -14,7 +17,9 @@
|
||||
| Test | 中低模型 | 按既定验收信号执行浏览器/API/脚本,主要做观察、记录、逐条 pass/fail |
|
||||
| Developer | 中低模型(按任务升级) | 多数实现可照规格执行;跨系统、数据迁移、重复失败时再升级 |
|
||||
|
||||
关键点:Coordinator 用强模型但**不亲自跑测试**(测试由 Test 承担),所以强模型的 token 花在思考和终检上,而不是反复点击页面、跑 smoke、复制日志。这一分工天然省 token,同时保持「验证者 ≠ 实现者」。
|
||||
Coordinator 用强模型但**不亲自跑测试**(测试由 Test 承担),所以强模型的 token
|
||||
花在思考和终检上,而不是反复点击页面、跑 smoke、复制日志。这一分工天然省 token,
|
||||
同时保持「验证者 != 实现者」。
|
||||
|
||||
---
|
||||
|
||||
@@ -51,67 +56,183 @@
|
||||
- 需要设计新的抽象。
|
||||
- 低档位反复产出表面修复。
|
||||
|
||||
升级动作本身由 Coordinator 判断并记录(可写进 `tasks.yaml` 的 `dispatch` 备注或 `resolution`)。
|
||||
升级由 Coordinator 判断并记录原因。升级不是修改一个正在运行的终端:必须选择
|
||||
对应强档 profile,重新计算 `profileHash`,再通过 launcher 创建新的 worker。
|
||||
v0.10 不自动复用持久化 receipt 指向的旧终端,Test 也不得使用 Developer 的强档
|
||||
worker。
|
||||
|
||||
---
|
||||
|
||||
## 如何给 worker 指定模型(编排相关)
|
||||
## 结构化 worker profile
|
||||
|
||||
**模型不由编排层设置。** Orca 的 `orchestration task-create` / `dispatch` 没有 `--model` 参数——`dispatch` 只是把任务投递给一个已存在的终端 handle。**模型在创建 worker 终端、启动 agent CLI 时用 CLI 自带的 flag 固定**,之后该终端的所有 dispatch 都用这个模型。
|
||||
### 机器事实源
|
||||
|
||||
**默认不跨 Agent CLI 创建 worker。** Coordinator 应按自己所在的运行环境选择同类 worker:Cursor 会话创建 `cursor-agent` worker,Codex 会话创建 `codex` worker。不要依赖 Coordinator 凭模型回答来猜测运行环境或精确模型名;以实际 CLI / 终端环境为准。只有项目 overlay 或用户明确指定跨 Agent 时,才混用不同 CLI,并记录原因。
|
||||
worker 路由的机器可读事实只保存在 `docs/ack/tasks.yaml` 的
|
||||
`project.orchestration`。`project.md` 可以解释项目为何选某个档位,但不能另写一份
|
||||
完整启动命令或覆盖机器配置。字段结构以 `templates/tasks.schema.json` 为准。
|
||||
|
||||
因此「档位 → 具体模型」的映射是 **agent 相关** 的,落地方式见 `orca-adapter.md` §「给 worker 终端固定模型」。常见 CLI:
|
||||
每个 profile 明确声明:
|
||||
|
||||
| Agent CLI | 指定模型的方式 |
|
||||
|-----------|----------------|
|
||||
| Cursor (`cursor-agent`) | `cursor-agent --model <model>`;`--model auto` 让 Cursor 自动选(推荐给 Test/Developer worker) |
|
||||
| Codex (`codex`) | `codex -m <model> -c model_reasoning_effort=<effort>` |
|
||||
| 其它(opencode 等) | 用各自 CLI 的模型参数或配置 |
|
||||
- `role`:`developer` 或 `test`;
|
||||
- `cli`:受支持的 Agent CLI;
|
||||
- `tier`:角色模型档位;
|
||||
- `model`:项目 allowlist 中的精确模型 ID;
|
||||
- `reasoningEffort`:CLI 支持时显式声明;
|
||||
- `permissionMode`:只允许 `read-only` 或 `workspace-write`。
|
||||
|
||||
执行模式也必须在创建 worker 时固定,并服从项目覆盖层或用户的明确要求。Cursor 的 YOLO 参数是 `--yolo`;Codex 的等价参数是 `--dangerously-bypass-approvals-and-sandbox`。不要把 Cursor 的 `--yolo` 原样传给 Codex,也不要把裸启动 `codex` 当作“自动选择了正确角色模型”。如果项目提供 worker 命令校验脚本,校验通过是 `terminal create` 的前置条件。
|
||||
`project.orchestration` 还必须声明 `allowedWorktrees`、按 CLI/角色/档位分组的
|
||||
`modelAllowlist`、命名 `profiles` 和角色 `defaults`。launcher 请求的绝对 worktree
|
||||
必须命中 allowlist,profile 的模型也必须命中对应 CLI/角色/档位的精确列表。
|
||||
|
||||
**ACK 对 Cursor 的默认建议**:Test 与 Developer worker 用 `cursor-agent --yolo --model auto`(自动选型,天然偏向高效模型,符合"中低档位"意图,并按当前项目授权启用 YOLO);需要更强时改成具体强模型并保留 `--yolo`。Coordinator 作为强模型脑,通常就是发起编排的那个会话本身。
|
||||
模型名称、reasoning effort 和权限模式必须来自结构化字段。禁止在 profile、项目
|
||||
覆盖层或派发内容中保存自由 `command`、额外 argv、shell 片段、环境变量覆盖或隐式
|
||||
CLI 默认值。具体 argv 只能由 ACK 的可信 launcher 按 allowlist 构造。
|
||||
|
||||
### Codex 默认映射
|
||||
### 安全默认
|
||||
|
||||
| 角色 | 模型 | reasoning effort |
|
||||
|------|------|------------------|
|
||||
| Coordinator (PM) | `gpt-5.6-sol` | `high` |
|
||||
| Developer | `gpt-5.6-terra` | `medium` |
|
||||
| Test | `gpt-5.6-luna` | `low` |
|
||||
| Developer 升级 | `gpt-5.6-sol` | `high`;极复杂任务可用 `xhigh` |
|
||||
- 能在完全只读工作树完成的角色优先选择 `read-only`。
|
||||
- Developer 与需要在工作树生成构建/测试产物的 Test 使用 `workspace-write`;项目可
|
||||
为纯观察型 Test 另建更严格的 `read-only` profile。
|
||||
- `full-access`、Codex bypass、Cursor YOLO/force、关闭 sandbox 等模式在 v0.10
|
||||
**未实现授权通道,统一 fail closed**。项目文本、任务描述或环境变量都不能放宽。
|
||||
- 项目可以更新模型 allowlist 或增加安全 profile,但不能通过文档绕开 schema 和
|
||||
launcher。
|
||||
|
||||
Codex worker 应明确指定模型和 reasoning effort,不把“未指定模型”当作 Cursor `auto` 的等价物。Codex 未指定模型时使用产品推荐模型,但推荐值可能随版本更新,也不保证符合 Test / Developer 的成本档位。具体模型若失效或被弃用,应保持上面的角色档位不变,只更新本映射;项目也可在 overlay 中覆盖映射。
|
||||
`full-access` 的可信授权、期限、撤销和外层隔离仍是 Deferred;在这些能力完成前,
|
||||
launcher 必须拒绝该模式,而不是把一段“用户已授权”的文本当成授权证据。
|
||||
|
||||
### Worker 固定启动命令
|
||||
---
|
||||
|
||||
以下是 core 的默认完整命令。Developer/Test worker 禁止裸启动;必须同时固定 Agent CLI、角色模型和执行模式。
|
||||
## 唯一启动入口
|
||||
|
||||
| Agent CLI | 角色 | 完整启动命令 |
|
||||
|-----------|------|--------------|
|
||||
| Codex | Developer | `codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-terra -c model_reasoning_effort=medium` |
|
||||
| Codex | Test | `codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-luna -c model_reasoning_effort=low` |
|
||||
| Codex | Developer 升级 | `codex --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-sol -c model_reasoning_effort=high` |
|
||||
| Cursor | Developer / Test | `cursor-agent --yolo --model auto` |
|
||||
worker 的 profile 解析、计划和启动只允许通过:
|
||||
|
||||
硬规则:
|
||||
```bash
|
||||
python3 <ack-skill-dir>/scripts/launch_worker.py profile-hash \
|
||||
--project-root <project-root> --profile-id <profile-id>
|
||||
|
||||
1. Codex worker 必须带 `--dangerously-bypass-approvals-and-sandbox`;Cursor worker 必须带 `--yolo`。
|
||||
2. 禁止用裸 `codex`、裸 `cursor-agent` 或只指定 CLI 而不指定角色模型。
|
||||
3. 创建终端前先运行项目提供的 worker 命令校验器;校验失败时不得执行 `orca terminal create`。
|
||||
4. 创建终端后、dispatch 前读取启动信息,确认实际 CLI、模型和 reasoning effort 与命令一致。
|
||||
5. Developer 升级到强模型必须由 Coordinator 记录原因;Test 不得复用 Developer 的强模型终端。
|
||||
6. YOLO 会跳过确认和沙箱,只能在用户已明确授权、外层运行环境受控时启用;项目覆盖层可以收紧执行模式,不能静默放宽。
|
||||
python3 <ack-skill-dir>/scripts/launch_worker.py plan \
|
||||
--project-root <project-root> --task-id <task-id> \
|
||||
--attempt-id <task-id>-A<round> --role <developer-or-test> \
|
||||
--profile-id <profile-id> --worktree <absolute-worktree> [--slot <1..99>]
|
||||
|
||||
项目可以覆盖模型名称或收紧权限,但必须在 `project.md` 中写出完整替代命令,不能只写“auto”“默认模型”或依赖当前 CLI 的隐式默认值。
|
||||
python3 <ack-skill-dir>/scripts/launch_worker.py launch \
|
||||
--project-root <project-root> --task-id <task-id> \
|
||||
--attempt-id <task-id>-A<round> --role <developer-or-test> \
|
||||
--profile-id <profile-id> --worktree <absolute-worktree> [--slot <1..99>] \
|
||||
--expected-launch-fingerprint <plan 中的 sha256:...>
|
||||
```
|
||||
|
||||
`--project-root` 始终指向保存权威 `docs/ack/tasks.yaml` 的项目根;`--worktree` 是本次
|
||||
worker 实际工作的绝对路径,两者可以不同。后者仍必须属于同一项目并命中
|
||||
`project.orchestration.allowedWorktrees`。
|
||||
|
||||
- `profile-hash` 读取 `tasks.yaml` 中的 profile,输出确定性 hash。
|
||||
- `plan` 只校验并展示将使用的结构化计划,不创建终端。
|
||||
- `launch` 是唯一允许创建 worker 的入口;它要求传入刚审阅的
|
||||
`plan.launchFingerprint`,当前 profile、任务/attempt、worktree、CLI 或 argv
|
||||
任一事实漂移都会在创建前失败。它内部固定 Orca 调用和 Agent argv,标准输出只有
|
||||
一份 JSON 结果。
|
||||
- launcher 的内部 bootstrap 属于私有协议,Coordinator 不直接调用、不复制到项目
|
||||
文档,也不自行拼装 Orca 的底层终端创建文本。
|
||||
|
||||
Coordinator 在执行 `launch` 前必须先审阅 `plan`。任何校验失败、字段未知、路径不
|
||||
匹配、CLI 不可用或权限模式不支持,都停止创建并回报,不回退到裸 Agent 命令。
|
||||
|
||||
---
|
||||
|
||||
## 可执行信任边界
|
||||
|
||||
v0.10 的 launcher 还执行以下约束:
|
||||
|
||||
- 不读取调用者传入的 `PATH` 来寻找 `git`、Orca 或 Agent CLI,只在固定的系统与
|
||||
当前用户工具目录中解析受支持的可执行文件;候选目标必须由 root/当前用户拥有、
|
||||
不是 group/other writable,并在 plan 与 bootstrap 间保持相同 device/inode。
|
||||
- Git、Orca 和 CLI version probe 使用不含供应商凭据的控制环境;worker 使用
|
||||
`per-cli-allowlist-v1`,Codex 只取得 Codex 所需凭据,Cursor 只取得 Cursor 凭据,
|
||||
不跨 CLI 透传。`DBUS_*`、`DISPLAY`、`WAYLAND_DISPLAY`、`XDG_RUNTIME_DIR`、
|
||||
`LD_*`、`PYTHON*`、`NODE_OPTIONS`、`CODEX_HOME`、`GIT_*` 和调用者 PATH 均不会
|
||||
透传给 worker。
|
||||
- worktree 除了命中项目 allowlist、属于同一 Git common-dir,还必须精确出现在
|
||||
`git worktree list --porcelain -z` 中;`.git` symlink 冒充的目录会失败。
|
||||
- Orca 的 `--command` 只含固定 bootstrap 与随机 launch ID。终端创建后,父进程先
|
||||
绑定 runtime/handle/incarnation/worktree,再通过该终端 stdin 发送一次性 nonce;
|
||||
bootstrap 校验 nonce 后才允许启动 Agent CLI,并把 child PID 与 nonce/launch
|
||||
fingerprint 绑定的 proof 原子写入 ready 状态;父进程看到并核对 proof 后才把
|
||||
worker 视为可派发。
|
||||
- `orca terminal create` 一经发出,在取得确定 handle 前遇到超时、transport/解码
|
||||
异常、进程中断、非零退出、畸形 JSON 或缺字段,一律标记为 `indeterminate`,
|
||||
禁止自动重试。
|
||||
- 取得 handle 后若任一绑定或握手检查失败,launcher 会先用
|
||||
`orca terminal close --tab --json` 请求持久关闭,并严格核对 runtime、handle、
|
||||
tab 和 close mode。只有关闭回执完整匹配才记为普通 `failed`;关闭无法确认时保持
|
||||
`indeterminate/reconcile-required`,调用方必须先人工核对,不能直接重试。
|
||||
- bootstrap 在真正启动 Agent 前,会在同一 launch-record 锁内再次确认状态仍为
|
||||
`awaiting-authorization` 且没有 cleanup;父进程一旦先进入 cleanup/reconcile,
|
||||
bootstrap 必须拒绝 `Popen`,不能让取消后的 workspace-write worker 继续启动。
|
||||
- 异常路径的 launch record 写入失败不能阻断上述关闭动作,也不能遮蔽原始
|
||||
`indeterminate`。即使关闭已确认,只要最终状态无法可靠持久化,也保守返回
|
||||
`indeterminate/reconcile-required`。
|
||||
|
||||
这些约束防止任务板、任务文本和普通环境变量变成第二个启动命令入口。它们不抵御已经
|
||||
完全控制 Coordinator 用户账户、Orca 运行时、受信 Agent/Orca 可执行文件或
|
||||
Coordinator 用户级 Agent 配置/插件/MCP 的攻击者;该场景需要独立 OS 身份、受控
|
||||
Agent 配置或平台签发能力。`permissionMode` 约束的是 Agent CLI 的 shell/文件系统
|
||||
执行模式,不是模型供应商或外部工具能力的 attestation。
|
||||
|
||||
---
|
||||
|
||||
## Receipt、审计与复用边界
|
||||
|
||||
成功启动返回的 JSON 含一个可校验 receipt。Coordinator 把 receipt 追加到
|
||||
`tasks.yaml` 顶层 `workerReceipts`,并把它的 `id` 写入当前任务
|
||||
`dispatch.<role>.receiptId`、把 `profileId` 写入 `dispatch.<role>.profileId`,同时把
|
||||
本次 `<task-id>-A<round>` 写入 `dispatch.<role>.attemptId`。
|
||||
|
||||
这三个字段不是可任意组合的历史索引。任务板校验器要求被引用 receipt 的
|
||||
`createdFor.taskId` 等于当前 ACK `tasks[].id`,`createdFor.role` 等于 dispatch
|
||||
角色,`profileId` 完全相同,且 `createdFor.attemptId` 等于
|
||||
`dispatch.<role>.attemptId`。`receiptId: null` 时 `attemptId` 必须同为 `null`;
|
||||
`receiptId` 非空时 `attemptId` 必须存在并命中本轮。`dispatch.<role>.taskId` 是 Orca
|
||||
运行时 task ID,不能拿来替代 ACK task ID 或稳定 attempt ID。
|
||||
|
||||
receipt 至少把以下事实绑定在一起:
|
||||
|
||||
- `profileHash` 与请求的角色、模型、effort、权限和精确 argv;
|
||||
- `slot`,确保 fingerprint 也绑定审阅过的 worker 槽位和派生标题;
|
||||
- 任务、attempt、绝对 worktree 及 path/device/inode/git common-dir 等稳定身份;
|
||||
- Orca `runtimeId`、terminal `handle` 和 `incarnationId`;
|
||||
- 创建时间、launcher 指纹和 `receiptHash`。
|
||||
|
||||
`receiptHash` 是无密钥的规范 JSON checksum,只能发现意外漂移或未同步修改,**不是
|
||||
launcher 身份证明,也不是复用授权**。项目内有写权限的一方可以修改 receipt 后重算
|
||||
hash;而当前 Orca metadata 又不能证明终端最初执行的命令、模型和权限。因此 v0.10
|
||||
明确禁止根据持久化 receipt 自动复用既有终端:每次需要自动派发 worker,都重新走
|
||||
`plan` → 带 expected fingerprint 的 `launch`,只使用该次 launcher 标准输出中的
|
||||
fresh handle 完成本次派发。
|
||||
|
||||
`launchFingerprint` 是确定性的完整计划漂移校验,不是一次性授权或幂等键。同一份
|
||||
计划重复执行 `launch` 会创建新的 fresh terminal;成功后不得用同一 fingerprint
|
||||
再次启动。若结果不确定,必须先 reconcile,不能把重跑当作恢复方式。未来需要自动
|
||||
防重放时,应由 Orca/ACP 的原子 idempotency/claim 能力或项目外可信 launch intent
|
||||
提供,而不是把 checksum 冒充成一次性令牌。
|
||||
|
||||
持久化 receipt 仍用于审计、dispatch 关联和检测配置漂移;标题、preview、分支名、
|
||||
worker 自报或单独的 Orca live metadata 都不能把旧终端提升为可信 worker。未来只有
|
||||
在 Orca/ACP 提供启动参数 attestation,或存在项目外可信签发与校验通道后,才开放
|
||||
自动复用。CLI / 模型变更仍需更新 allowlist 并重新生成 receipt。
|
||||
|
||||
`ackVersion` 必须使用合法 SemVer。`0.10.0` 及以后版本的任务板必须同时存在
|
||||
`project.orchestration` 与顶层 `workerReceipts`;其中任一字段出现,另一个也必须
|
||||
出现,避免 schema-only 校验把半迁移任务板误判为可自动派发。
|
||||
|
||||
---
|
||||
|
||||
## 成本原则
|
||||
|
||||
强模型产出高密度、可复用的产物:需求、架构决策、验收信号、任务拆分、失败复盘。
|
||||
中低模型消费这些产物,产出可核对的执行证据:测试结果、快照、API 响应、构建日志、改动文件清单。
|
||||
中低模型消费这些产物,产出可核对的执行证据:测试结果、快照、API 响应、构建日志、
|
||||
改动文件清单。
|
||||
|
||||
这样把昂贵推理挡在重复执行之外。
|
||||
|
||||
@@ -119,4 +240,6 @@ Codex worker 应明确指定模型和 reasoning effort,不把“未指定模
|
||||
|
||||
## 一句话
|
||||
|
||||
Coordinator 是脑,Test 是眼,Developer 是手。脑用最强的模型且不做机械测试,眼和手用便宜模型,只有常规闭环卡住时才升级。
|
||||
Coordinator 是脑,Test 是眼,Developer 是手。脑用强模型且不做机械测试,眼和手
|
||||
默认用安全、较低成本的结构化 profile;只有常规闭环卡住时才升级,并且所有 worker
|
||||
都必须经 launcher 产生可核对的 receipt。
|
||||
|
||||
Reference in New Issue
Block a user