aps-agent/docs/development/pi-fallback-runbook.md

224 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Pi Agent 兜底能力发布与现场运行手册
> 角色:Agent-D(P5 发布实现)· 成文日期:2026-09-04
> 依据:`poc/pi-fallback/P4-P5-DESIGN.md` §5、`poc/pi-fallback/P4-P5-AUDIT.md`、`docs/architecture/fallback.md` 与当前代码。
> 本文只写运行与发布准备边界,不替代 `CHANGELOG.md`/`fallback.md`;那两份由主管统一更新。
## 1. 启用前提与 fail-closed 开关
当前兜底形态是**本地 spawn runner**:Python 编排器在应用进程内拉起 Node + Pi CLI 子进程;没有已交付的独立 pi-runtime service。仓库 `poc/pi-fallback/runtime` 只是开发用安装,**不是发布产物**。启用前必须满足:
- 应用容器或部署机具备 Node(建议 22)与 Pi 制品,或显式配置 `APS_FALLBACK_PI_CLI`/`APS_FALLBACK_NODE`;
- 模型网关可由服务端访问,并配置 `LLM_BASE_URL`/`LLM_API_KEY`;
- 持久化目录可写且可长期保留 run/审计证据;
- P3 高风险场景使用前准备好 `fallback-highrisk.json` 与审批角色策略。
### 1.1 默认关
`server/agent_core/feature_flags.py` 的 `_DEFAULT_OFF_KEYS = {"fallback"}`。文件缺失、JSON 损坏、结构非法、取值非 bool、加载异常,全部回退 `fallback=False`。因此**未显式开启时不拉起 Pi 子进程**,聊天链路逐字节走原话术。
显式开启:
```json
{"version": 1, "features": {"fallback": true}}
```
配置路径默认 `APS_FEATURES_PATH`,未设置时为 `path_under_data("features.json")`(Web 通常 `server/data/features.json`,桌面 `~/.aps/data/features.json`)。可用 `GET /api/features` 的 `defaultOff` 核对语义。
### 1.2 环境变量
| 变量 | 作用 | 默认 |
|---|---|---|
| `APS_FALLBACK_DIR` | run 根目录 | `path_under_data("fallback")`(Web=`server/data/fallback`,桌面=`~/.aps/data/fallback`) |
| `APS_FALLBACK_PI_CLI` | Pi CLI 路径 | **代码默认回仓库 poc 路径,发布必须显式覆盖** |
| `APS_FALLBACK_PI_HOME` | Pi 配置目录 | `<fallback_root>/pi-home` |
| `APS_FALLBACK_NODE` | Node 可执行文件路径 | `node`(Windows 优先 `node.exe`;建议显式给绝对路径) |
| `APS_FALLBACK_MODEL` | 显式模型 | 空则 `GET {LLM_BASE_URL}/models` 协商,缓存 300s |
| `APS_FALLBACK_TIMEOUT_SEC` | 单次运行超时 | 90 |
| `APS_FALLBACK_MAX_STEPS` | 工具步数上限 | 30 |
| `APS_FALLBACK_MAX_OUTPUT_BYTES` | 输出体量上限 | 2 MiB |
| `APS_FALLBACK_EXEC_TIMEOUT_SEC` | 执行段预算 | 120 |
| `APS_FALLBACK_EXEC_MAX_STEPS` | 执行段步数 | 40 |
| `APS_FALLBACK_MAX_PLAN_STEPS` | 计划步骤上限 | 10 |
| `APS_FALLBACK_OPS_LOG_LINES` | S7 日志尾部行数 | 300 |
| `APS_FALLBACK_S6_MAX_CARDS` | S6 出卡全局封顶 | 20(白名单 `maxItemsPerRun` 优先) |
| `APS_FALLBACK_HIGHRISK_PATH` | P3 白名单路径 | `path_under_data("fallback-highrisk.json")` |
| `LLM_BASE_URL` | 模型网关地址 | 无默认,缺失即不可用 |
| `LLM_API_KEY` | 模型网关密钥 | 无默认,缺失即不可用;只进子进程环境,不打印不落盘 |
| `LLM_MODEL` | 期望模型 | 可选;不在清单时取第一项并记录协商说明 |
即使设置 `APS_FALLBACK_MODEL`,仍需 `LLM_BASE_URL`/`LLM_API_KEY`,因为 Pi 侧需要网关地址与密钥引用。P3 审批可能还涉及 `APS_APPROVAL_ROLE_POLICIES`(例如 `{"approval.approve":{"P3":["ops","admin"]}}`)。
## 2. Web/Docker 部署与 Pi 制品路径
### 2.1 现状
- Web/服务端部署当前是本地 spawn:Python 服务在本容器内启动 `node cli.js`;
- 现有 Dockerfile 只含 Python 与 `apps/web/dist`,**没有 Node/pi**;
- `packaging/k8s/deployment.yaml` 没有 `APS_FALLBACK_*`、Node/pi 相关配置;
- 因此镜像/Deployment 当前**不具备启用兜底的运行时**,只改环境变量无效。
### 2.2 Web/Docker 两态
主管裁决前,只记录两种可验收形态:
1. **Node + Pi 制品打进应用镜像或部署目录**:镜像/挂载卷提供固定版本 Node 与 Pi 制品,Python 通过 `APS_FALLBACK_PI_CLI`/`APS_FALLBACK_NODE` 指向;run 目录挂持久卷。这是“本地 spawn runner + 制品”形态。
2. **独立 pi-runtime service**:未来新增运行器协议与边界;**本轮不承诺已可用**,不得写入部署文档作为已完成能力。
镜像内建议 `APS_FALLBACK_DIR=/app/server/data/fallback`(或对应持久卷路径);容器临时层不适合保留审计/回放证据。缺少 Node/pi/模型时,功能保持显式失败,服务不得崩溃。
### 2.3 现场核对
```powershell
Get-ChildItem -Recurse -LiteralPath "<镜像或部署目录>" -Filter cli.js |
Where-Object { $_.FullName -match 'pi-coding-agent' } |
Select-Object -First 10 FullName
```
发布清单必须能看到明确 Pi 制品;只看到仓库 poc 路径不能算“镜像已含 runtime”。
## 3. 桌面可选组件与 sidecar env 边界
当前桌面默认包不含 Node/pi:
- `apps/desktop/package.json` 的 `extraResources` 只含 `web/dist` 与 PyInstaller sidecar;
- `packaging/aps-sidecar.spec` 只收 Python 模块,未收 Node/pi;
- `sidecar.cjs` 的 `CHILD_ENV_ALLOWLIST` 不含 `LLM_*`/`APS_FALLBACK_*`,因此当前 Electron sidecar 不能把模型/兜底环境传给 Python。
文档边界:**不声称桌面已内置启用 Pi 兜底**。未来若要桌面启用,至少需由主管拍板:
1. 是否把 Node + Pi 作为安装包内可选组件,或首次使用下载;
2. sidecar 环境 allowlist 是否扩展 `LLM_*`/`APS_FALLBACK_*`;
3. 组件签名、体积、无网络安装、升级/回滚验收(参照 `docs/development/packaging-smoke.md`);
4. 若迁 Tauri,Node runtime 方案与 Tauri 决策串行重设计。
本轮只给出可选组件边界与可复跑清单,不做“桌面默认可用”表述。
## 4. 无模型、断网与 MES 断连处置
### 4.1 无模型/模型网关不可达
当前行为是**逐次显式失败**:
- 缺少 `LLM_BASE_URL`/`LLM_API_KEY`、Node/pi 不可解析、`GET /models` 超时/异常/空清单 → 回原话术并附 `unavailable:<原因>`;
- 写 FAILED 审计;不会自动把 `fallback` 置 false;
- 当前没有专门 UI 状态位“模型不可用已强制关闭”。
这与详细方案 F5 的“无模型 force-off + UI 明示”**不一致**,已在缺口表中列为待主管裁决项。运维处置:看失败原因,检查 Node/Pi/网关配置后重试;不打算启用时把 `features.json` 显式写回 false。
### 4.2 断网/超时
propose 默认 90s/30 步/2MiB,执行段默认 120s/40 步;任一超限即杀进程树、显式判败。成败只看事件流 `stopReason=stop` 且报告非空,不看进程退出码。网络不可达不阻塞聊天主链路。
### 4.3 MES 断连(S6)
- 在线路径不变:未声明 `offlineBooking` 时先推 MES 后落账,断连即显式失败并回滚;
- 离线落账必须双成立:计划 params 显式 `offlineBooking:true` **且** 出卡/执行端实时探测 MES `failed`;
- 双成立才本地落账并打 `syncStatus=PENDING_SYNC`,确认卡明示“本地落账待同步”;
- 审批窗口内 MES 已恢复 → 执行端拒绝/回滚;offlineBooking 不能用来绕过 MES 在线校验;
- 恢复后由人重新发起“对一下账”;探测仍失败则回复“尚未恢复”,不轮询、不猜;
- 对账为纯读:MATCH/DRIFT/MISSING,外部原文与 `reconcile-manifest.json` sha256 冻结,报告不写世界;
- PENDING_SYNC 自动补推属后续轮次,当前未实现。
## 5. run 目录、审计回放、checkpoint/回滚
根:`APS_FALLBACK_DIR` 或 `path_under_data("fallback")`。单个 run 目录形态:
```text
<fallback_root>/fb-YYYYMMDD-HHMMSS-xxxxxx/
├── inbox/ # snapshot.md / orders.csv / 集成状态 / ops 诊断 / external
├── work/ # Pi 子进程工作目录
├── outbox/ # report.md / plan.json / sandbox 产物 / reconcile 产物
├── events.jsonl
├── orchestrator.log
├── result.json
├── calls.jsonl
├── guard-<runId>.ts
├── execution.jsonl / execution.events.jsonl
└── outbox/reconcile-manifest.json # S6 对账证据冻结文件
```
审计关联:完成审计 rationale 含 `runId`;工具事件 actor=`pi-fallback:<runId>`;`evidence_refs=["fallback-run:<runId>"]`;S6 对账另含 `manifestSha256`。
回放现状:`GET /api/gov/audit` 只返回最近 `limit` 条,**没有服务端 runId 过滤参数**;GovConsole 无 runId 搜索/一键回放视图。当前可靠回放是“runId + run 目录文件 + sha256 + 客户端筛选审计”,不能写成系统现成 runId 回放功能。
P3-DESIGN 曾要求 S7 每 run 追加通用 `manifest.json`;当前源码只找到 S6 `reconcile-manifest.json` 写路径,**未发现通用 S7 manifest 写路径**,作为发布前缺口处理。
回滚/收尾:
- S6 逐笔独立确认卡/checkpoint,单笔拒绝不影响其他;
- S7 配置为整文档替换:tmp + 原子 replace + `.bak` + 回读校验;
- S4 沙盒不改主世界,校验前后世界指纹 + 零 `WORLD_WRITE`;
- 失败后不得残留 `_saga_cp.json` 或 Pi 进程。
## 6. 回归与验收命令(.venv\Scripts\python.exe)
Python 一律使用仓库 `.venv\Scripts\python.exe`;命令只验证,不 commit/push、不跑真实打包。
### 6.1 定向确定性 golden
```powershell
.venv\Scripts\python.exe -m pytest `
tests/golden/test_fallback_lane.py `
tests/golden/test_fallback_execute.py `
tests/golden/test_fallback_highrisk.py `
tests/golden/test_fallback_offline_booking.py `
tests/golden/test_fallback_p3_attack.py `
tests/golden/test_feature_flags.py `
-q
```
P4 质量专项已交付并经主管复核(2026-09-04),命令:
```powershell
.venv\Scripts\python.exe -m pytest tests/golden/test_fallback_p4_quality.py -q
```
主管复核结果:
- P4 质量:44 passed,结论与场景映射见 `poc/pi-fallback/P4-QUALITY-NOTES.md`;
- P4 注入:57 passed / 1 skipped,见 `poc/pi-fallback/P4-SECURITY-NOTES.md`;
- P4 离线:24 passed,见同一 security notes;
- 主管 8 文件联合(lane / execute / highrisk / p3_attack / offline_booking +
P4 quality / injection / offline):197 passed / 1 skipped in 51.87s;
- ruff:All checks passed;
- 汇总复核记录见 `poc/pi-fallback/P4-P5-VALIDATION.md`。
确定性门禁现可按上述结果勾选;真实 runtime/Docker/桌面打包、真实 smoke 与
发布批准仍以本手册其余边界与 `poc/pi-fallback/P5-RELEASE-NOTES.md` 为准。
### 6.2 S6/S7 真实冒烟(需真实 Node/Pi/LLM key)
```powershell
.venv\Scripts\python.exe poc/pi-fallback/smoke/smoke_s6_reconcile.py setup
.venv\Scripts\python.exe poc/pi-fallback/smoke/smoke_s6_reconcile.py outage
.venv\Scripts\python.exe poc/pi-fallback/smoke/smoke_s6_reconcile.py recovery
.venv\Scripts\python.exe poc/pi-fallback/smoke/smoke_s6_reconcile.py control
.venv\Scripts\python.exe poc/pi-fallback/smoke/smoke_s6_reconcile.py finalize
```
```powershell
.venv\Scripts\python.exe poc/pi-fallback/smoke/smoke_s7_ops.py setup
.venv\Scripts\python.exe poc/pi-fallback/smoke/smoke_s7_ops.py ops
.venv\Scripts\python.exe poc/pi-fallback/smoke/smoke_s7_ops.py control
.venv\Scripts\python.exe poc/pi-fallback/smoke/smoke_s7_ops.py finalize
```
冒烟收尾核对:无 `_saga_cp.json`、无 `server/data` 非预期残留、无残留 pi 进程。冒烟脚本会构造临时现场/CSV/假 MES,属验证设施,不是产品文件摄入能力。
### 6.3 已知未实现项与待裁决
1. P3 产品代码未提交;P3-VALIDATION 存在 GO/NO-GO 文档矛盾;
2. Pi runtime 未进 Docker/K8s/桌面发布包;仓库 poc 路径不是发布产物;
3. 桌面 sidecar 不允许 `LLM_*`/`APS_FALLBACK_*` 透传;
4. P4 注入/离线专项、P4 notes、P4-P5-VALIDATION 已交付并复核(注入 57 passed / 1 skipped、
离线 24 passed),不再作为“未交付/无结论”缺口;
5. P4-QUALITY-NOTES 已提供确定性集成功率/误写率/确认轮次/耗时与 cost_points 近似聚合,
产品层仍无统一指标导出、真实 token/cost 与 per-step 耗时;
6. 无 Pi usage/token/cost 解析、日预算/告警、触发率周报;
7. F5 无模型 force-off + UI 明示与现状不一致;
8. `/api/gov/audit` 无 runId 服务端过滤,GovConsole 无 runId 回放视图;
9. S4 真实冒烟未做;S6 超上限真实冒烟未做;S7 通用 manifest 写路径未见;
10. 全量 golden 基线数字口径过期(1071+ 等),需主管统一;
11. WMS 侧补录不在 P3 范围。