aps-agent/Pi-Agent兜底能力详细方案.md

173 lines
16 KiB
Markdown
Raw Normal View History

# Pi Agent 兜底能力 · 详细实施方案
> 版本 v2.0 · 2026-09-02 · 取代:`Pi-Agent接入计划.md` / `Pi-Agent接入详细计划.md`(那两份是"接入通道"定位,本方案是"**全系统兜底能力**"定位,范围显著扩大)
> 依据:`plan.md` §2.1/§2.2/§3、`PROJECT_OPERATING_RULES.md`、`docs/architecture/harness.md`、`docs/architecture/skills.md`、`docs/architecture/overview.md`
> 现状代码锚点:`server/aps_domain/workflow.py:2875`(当前 unknown 意图兜底 = 纯话术回复,**无能力**)、`server/agent_core/harness.py`(`_POWER_MAP` 62 项登记 + 未登记默认 P3 拒绝)、`server/agent_core/tool_runtime.py`(唯一执行入口)、`server/agent_core/mcp_bus.py`、`server/agent_core/feature_flags.py`(FF-01 开关机制)、`apps/desktop/sidecar.cjs`(子进程环境清洗/看门狗,Pi runtime 可直接复用这套模式)
---
## 1. 定位重述:什么是"兜底能力"
**现状**:用户说一句系统听不懂的话,走到 `workflow.py:2875` 的 `assistant.reply/unknown` 分支——LLM 回一段话术,**事情没办成**。已登记意图执行失败(求解器 fatal、数据缺字段、接口超时)也只有报错,没有自救。
**目标态**:Pi Agent 成为 APS 的**通用能力后备层**——产品化路径"不能办"或"办砸了"时,由 Pi 这个具备读/写/执行能力的通用智能体,在 Harness 划定的围墙内把事办成,并且全程可审计、可回滚、可熔断。
```
用户请求 → 意图管线
├─ 命中已登记意图 → 产品化路径(现状,快/稳/确定性)
│ └─ 执行失败 ──┐
└─ 未识别/未登记 ───┤
▼
【受治理的兜底车道 Governed Fallback Lane】
Pi 分析任务 → 产出《执行计划草稿》(P1,只读可直通)
→ 确认卡呈人类审批 (P2 起)
→ 批准后 Pi 在沙箱内执行(工具桥只暴露登记过的能力)
→ 执行后世界状态 diff 验证 + 报告
→ 全程审计链 + 证据链 + 可回滚 checkpoint
```
**一句话:Pi 是被 Harness 雇佣的临时工——有手艺,但进厂要登记、干活要批条、动设备要有人在场、出活要验收。**
## 2. 与产品宪法的冲突分析与消解
这是本方案最关键的一节。兜底能力天然想"什么都能干",宪法要求"未经授权什么都不能干"。逐条消解:
| 宪法红线(PROJECT_OPERATING_RULES 原文) | 表面冲突 | 消解设计 |
|---|---|---|
| 「动作必须经 `_POWER_MAP` 白名单登记,未登记默认 P3 拒绝」 | 兜底场景恰恰是"未登记意图" | 新增 3 个**元意图**登记进 `_POWER_MAP`:`agent.fallback.propose`=P1(产出计划草稿,沙盒语义)、`agent.fallback.execute`=P2(执行已批准计划)、`agent.fallback.execute.highrisk`=P3(涉主干写/外部系统,逐字段人工确认或默认拒绝)。Pi 从未"直接做事",它做的事都被这三个登记动作包裹 |
| 「LLM 只有提议权」(tool_runtime) | Pi 是 LLM 驱动的执行体 | Pi 的**计划**是提议;**执行**走 `/api/actions/confirm` 唯一通道。Pi 能调用的工具本身就是经过登记的意图封装(见 §4.3 工具桥),物理上无法直写 store/DB |
| 「不得引入未设计的隐式副作用」 | Pi 自由执行副作用不可枚举 | 沙箱围墙(§4.2):文件系统圈禁在 run 专属目录、网络只通 APS loopback、shell 白名单、环境变量清洗(复用 sidecar.cjs 的 allowlist 模式)。墙内副作用显式枚举,墙外物理不可达 |
| 「写前必须建 checkpoints 成对快照」 | Pi 执行前后状态未知 | 兜底车道**强制**执行前 checkpoint、执行后 world diff 验证报告,diff 摘要进确认卡和审计 |
| 「失败必须显式报告」 | LLM 倾向"圆场" | Pi 输出契约强制 `status: success|partial|failed|blocked`;`partial/failed/blocked` 必须附未竟事项清单;gateway 侧校验缺失字段即判 failed |
| 「mock/stub 不得进入产品路径」 | Pi 可能"假装"调用了工具 | 工具桥每次调用返回真实调用凭证(callId),Pi 报告中引用 callId 可被审计对账;无 callId 支撑的成果声明判无效 |
## 3. 场景矩阵(10 类兜底场景 × 治理策略)
| # | 场景 | 触发条件 | 权力 | 治理策略 | 验证方式 | Pi 干不了时的降级 |
|---|------|---------|------|---------|---------|------------------|
| S1 | **意图未识别**(新说法/新需求口令) | 意图管线产出 `unknown` | propose=P1 / execute=P2 | 计划草稿确认卡必出 | 执行后 diff + 用户确认回执 | 退回话术 + "已记录需求"工单 |
| S2 | **已登记意图执行失败**(求解器 fatal、数据缺字段) | handler 抛错/返回失败 | P1 诊断只读 / 修复=P2 | 诊断报告直通;修复动作出卡 | 重跑原意图成功即为验证 | 显式报错原文 + 诊断附件 |
| S3 | **新数据格式接入**(客户给了没人写过 importer 的 Excel/CSV/JSON) | data.import 解析失败或用户直接给文件 | P2(导入写主干) | 计划含字段映射表,确认卡呈现映射供审 | 导入后行数/金额对账 + 抽样比对 | 输出《手工整理指引》 |
| S4 | **缺算法/策略**(某工艺无现成排产策略) | flex.schedule 无匹配 skill 或用户明示"试个新策略" | P1(沙盒试排) | 仅沙盒语义,产物为草稿版本 | 沙盒 KPI 对比基线版本 | 明确告知"超出兜底能力" |
| S5 | **ad-hoc 分析/报告**("帮我看看哪条线最容易拖期") | report.generate/data.analyze 覆盖不了的自由分析 | P1 | 只读工具桥 + 沙盒计算 | 报告数字必须引用冻结快照字段(宪法既有规则) | 返回原始数据 + 分析失败说明 |
| S6 | **外部集成故障**(MES/WMS 接口挂了,要手工补录/对数) | integrations 调用失败告警 | P2 | 补录动作逐笔出卡 | 与外部系统恢复后对账 | 生成待补录清单(Excel)交人工 |
| S7 | **现场运维诊断**(support 工程师查日志/修配置) | 运维人员在运维入口显式发起 | P2;改配置 P3 | 仅运维角色可见入口;全程录屏级审计 | 修复后健康检查绿 | 输出诊断报告 + 建议人工操作 |
| S8 | **演示/售前救场** | 演示中任何上述场景 | 同对应场景 | 无特殊豁免(宪法) | 同对应场景 | 话术降级 |
| S9 | **批量数据处理**(一次性清洗/转换 5000 行工单) | 用户发起且无对应产品功能 | P2 | 计划含抽样预览(前 20 行变换结果)出卡 | 全量校验规则 + 抽样人工确认 | 分批+断点,失败批次显式列出 |
| S10 | **Pi 自身失败**(模型不可用/超时/超预算/死循环/部分写入) | 熔断器触发 | — | 超时(默认 10min)/步数(50)/token 预算三重熔断;部分写入由 checkpoint 回滚 | 回滚后 diff 为空即验证 | 显式失败报告 + 已回滚声明 |
**矩阵结论**:10 类场景中 S1/S2/S3/S5/S9 是价值主干(覆盖 80% 真实需求),S4/S6/S7 价值高但风险也高(放后期),S10 是必须设计的元场景。
## 4. 详细设计
### 4.1 组件清单(新增 4 个可重生模块 + 1 个外部进程)
| 组件 | 位置 | moduleId | 职责 |
|------|------|----------|------|
| FallbackLane 编排器 | `server/agent_core/fallback_lane.py`(新增,~600 行) | `core-fallback-lane` | 触发判定 → 任务简报 → 调 Pi → 收计划 → 出卡 → 执行 → 验证 → 审计 |
| Pi 工具桥 | `server/integrations/pi_bridge.py`(新增,~400 行) | `integ-pi-bridge` | 向 Pi 暴露围墙内工具集(§4.3),每次调用发 callId 凭证 |
| 兜底验证器 | `server/agent_core/fallback_verify.py`(新增,~300 行) | `core-fallback-verify` | 执行后 world diff、规则校验、报告生成(数字只许来自冻结快照) |
| 熔断与预算 | 并入 fallback_lane(~150 行) | 同上 | 超时/步数/token 三重熔断 + audit_alerts 联动 |
| Pi runtime 进程 | Node 进程(`pi-agent-core` headless 模式) | — | 被编排器以子进程拉起,生命周期管理**复用 sidecar.cjs 的 SidecarManager 模式**(端口/nonce/环境清洗/看门狗/日志轮转全套照搬) |
### 4.2 沙箱围墙(自内向外四层)
```
L1 工具层:Pi 只能看见工具桥暴露的工具(§4.3),没有裸 fs/shell/net
L2 文件层:cwd 圈禁 ~/.aps/fallback/<runId>/(Web 态 server/data/fallback/<runId>/);
可读注入区(用户上传文件副本)、可写工作区、产物出口目录三区分离
L3 网络层:仅允许 127.0.0.1:<gateway port>;模型 API 出口走 gateway 代理(可关)
L4 进程层:环境变量清洗(CONDA/Python 变量剥离,照搬 buildChildEnv)、
父进程看门狗、taskkill 进程树回收、10MiB 日志轮转
```
> 说明:Pi 官方支持 Gondolin/Docker 沙箱,但工业现场 Windows 离线机器上 Docker 不可靠,故以 L1-L4 进程级围墙为主,Docker 沙箱作为 Web/服务器部署的可选加强项。
### 4.3 工具桥暴露面(围墙内 Pi 的全部"手艺")
| 工具 | 包装自 | 权力 | 说明 |
|------|--------|------|------|
| `aps_invoke(intent, params)` | `/api/agent/invoke`(即 handle_intent) | 随意图 | **Pi 写世界的唯一方式**,内部仍过 _POWER_MAP/确认卡 |
| `aps_query(sql_like)` | master.query / data.analyze 只读集 | P0 | 世界状态只读视图 |
| `knowledge_query(q)` | `/api/rag/query`(ragScopes 鉴权) | P0 | 知识库 |
| `fs_read/fs_write(path)` | 沙箱 L2 三区 | — | 物理圈禁,越界即 EACCES |
| `shell_run(cmd)` | 白名单(python 脚本、xlsx 处理等显式登记命令) | — | 每条命令正则白名单 + 参数审查 |
| `checkpoint_create()` | state checkpoints | — | Pi 可主动建回滚锚点 |
| `report_emit(md)` | fallback_verify | — | 产物唯一出口,强制走验证器 |
### 4.4 意图与权力登记(harness 变更)
```python
# _POWER_MAP 新增 3 项(harness.md 权力矩阵同轮更新)
"agent.fallback.propose": "P1", # 产出执行计划草稿(沙盒语义,不写主干)
"agent.fallback.execute": "P2", # 执行已批准计划 → 确认卡
"agent.fallback.execute.highrisk": "P3", # 涉外部系统/主干批量写 → 默认拒绝,白名单放行
```
确认卡内容(P2 出卡时必须冻结):计划步骤清单、每步工具与权力、预计影响面(目标实体清单)、`evidenceRefs`、执行前 checkpoint id、回滚方式。**卡片上的承诺即执行上限**——执行时逐步比对,Pi 偏离计划即熔断(计划外工具调用 → blocked)。
### 4.5 证据链与审计
- 每次兜底运行:`runId` 贯穿 propose→confirm→execute→verify 全链;
- Pi 每步工具调用:TOOL 审计(actor=`pi-fallback:<runId>`、callId、入参摘要、结果摘要);
- 确认卡批准/拒绝:GATE 审计(既有机制);
- 验证报告:REPORT 审计 + 产物落 `~/.aps/fallback/<runId>/report.md`;
- 全链可通过既有 `/api/gov/audit` 按 runId 过滤回放。
### 4.6 开关与熔断(复用 FF-01)
- `features.json` 新增 `"fallback": false`——**默认全关**,现场按需开;开关本身 P2 确认卡管理;
- 熔断三闸:单次运行超时 10min / 步数 50 / token 预算(可配);日维度累计预算;
- 触发熔断 → 显式失败 + checkpoint 回滚 + audit_alerts 通知。
## 5. 部署形态(两个大坑,提前说)
| 形态 | 方案 | 坑 |
|------|------|-----|
| **Web/服务器部署** | docker-compose 增加 `pi-runtime` 服务(Node 22 + pi-agent-core) | 小,标准做法 |
| **桌面端打包** | PyInstaller sidecar 之外再加 Node runtime(~60-80MB)打进安装包,或做成**可选组件**首次使用时下载 | ① 体积恶化(与 Tauri 瘦身诉求矛盾,两事更该串行决策);② **离线工厂没有模型 API 出口**——兜底重度依赖 LLM,断网即瘫。对策:模型出口走 gateway 代理可配内网模型网关;无模型时 fallback 开关强制关闭且 UI 明示原因(失败显式,不装死) |
## 6. 阶段计划(修订版,替代 v1.0 计划)
| 阶段 | 内容 | 工期 | 出口标准 |
|------|------|------|---------|
| **P0 PoC** | 单场景 e2e 打穿:S5(ad-hoc 分析)。Python 编排器拉起 Pi headless → 计划 → 假确认 → 沙箱执行 → 报告。**不碰产品路径**,全部在 `poc/` | 4-5 人日 | 一个真实分析任务从发起到报告全链跑通;四层围墙验证有效(故意越狱测试被拒) |
| **P1 只读兜底** | S1(只读类)/S5/S9-只读部分 进产品路径;fallback_lane + pi_bridge 转正;`agent.fallback.propose` 登记;FF-01 开关接入 | 7 人日 | 意图未识别时用户能拿到"办成的事"而非话术;越狱/注入黄金测试 10 例全拦 |
| **P2 沙盒写兜底** | S2/S3/S9 写路径;`agent.fallback.execute`=P2 出卡;checkpoint 强制 + diff 验证器;熔断三闸 | 10-12 人日 | 新格式 Excel 导入从"给文件"到"对账通过"全链路演示绿;计划偏离熔断测试通过 |
| **P3 高风险与运维** | S4/S6/S7;`execute.highrisk`=P3;运维入口与角色门禁;集成故障对账流 | 7-10 人日 | MES 断连补录场景验收;运维全程审计可回放 |
| **P4 评估与硬化** | 兜底质量 golden 集(30+ 场景用例:成功率/误写率/确认轮次/token 成本四指标);prompt 注入防护集(工单备注藏指令等 20 例);离线降级演练 | 8 人日 | golden 集成功率 ≥85% 且误写率 0;注入集 100% 拦截 |
| **P5 验收发布** | 全量黄金(1071+ 基线)、桌面打包冒烟(含可选组件)、文档同轮、现场 runbook | 5 人日 | 发布门禁全绿;康尼数据集真实验收 |
| **合计** | | **41-47 人日(1 人约 8-10 周)** | |
### 里程碑视图
```
W1 W2-3 W4-6 W7-8 W9-10 W11
[P0] → [P1 只读] → [P2 写兜底] → [P3 高风险] → [P4 硬化] → [P5 发布]
↑go/no-go ↑已可演示价值 ↑核心能力闭环 ↑按需可裁剪 ↑质量门禁
```
## 7. 风险登记册(兜底定位特有)
| # | 风险 | 等级 | 对策 |
|---|------|------|------|
| F1 | **非确定性**:同一请求两次兜底结果不同 | 🔴 | 计划审批制(人看的是计划不是黑盒)+ golden 集回归 + 产物必须经验证器,不靠 Pi 自述 |
| F2 | **Prompt 注入**:订单备注/导入文件里藏"忽略之前指令" | 🔴 | 注入防护 golden 集(P4);用户数据进 Pi 前包裹隔离标记;工具桥不认 Pi 的"用户已确认"自述——确认只信 gateway 会话内的真实确认卡 |
| F3 | **部分写入**:执行到一半熔断 | 🟡 | checkpoint 强制前置 + 回滚验证(diff 为空才算回滚成功) |
| F4 | **成本失控**:LLM token 烧穿预算 | 🟡 | 三闸熔断 + 日预算 + audit_alerts |
| F5 | **离线工厂无模型出口**,兜底变废铁还误导用户 | 🟡 | 无模型时开关强制关 + UI 明示原因;支持内网模型网关地址配置 |
| F6 | **Node runtime 进桌面包** | 🟡 | 可选组件化;与 Tauri 决策串行 |
| F7 | **"兜底兜不住还装兜住"**(LLM 圆场) | 🔴 | 输出契约强制 status 字段 + callId 对账(§2 最后一行),圆场在网关层被物理判失败 |
| F8 | 团队对"治理下通用智能体"的调试经验不足,问题定位难 | 🟡 | 全程 runId 可回放 + Pi trace 落盘;P0 即建立调试工具链 |
| F9 | 范围蔓延:兜底太好用 → 产品化路径荒废 | 🟢 | 治理指标:兜底触发率应随产品化下降;触发率周报,高的场景反哺产品化立项 |
## 8. 与 v1.0 接入计划的关系
v1.0 的 `/api/agent/` 适配层、Agent Token、MCP 总线登记**全部保留**——它们在本方案中变成工具桥的基础设施(`aps_invoke` 就是走那层面)。外向接入(人在 Pi 终端里用 APS)成为 P1 完成后的副产品,不再单独排期。
## 9. 三条决策建议
1. **先 P0 后承诺**:4-5 人日的 PoC 直接验证最危险的两个未知数(围墙有效性、计划审批可用性),PoC 不过则退回 v1.0 纯接入定位;
2. **S 场景分批上线**:P2 之后每批场景单独灰度(FF-01 开关粒度到场景),不一锅端;
3. **与 Tauri 串行已定**,再强调一次:F6 意味着如果未来迁 Tauri,Node runtime 的打包方案要一起重设计。