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

12 KiB
Raw Permalink Blame History

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 子进程,聊天链路逐字节走原话术。

显式开启:

{"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 现场核对

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 目录形态:

<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

.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),命令:

.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)

.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
.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 范围。