514 lines
31 KiB
Markdown
514 lines
31 KiB
Markdown
|
|
# 多系统智能体平台 · 实施设计
|
|||
|
|
|
|||
|
|
> **来源**:飞书文档([原文](https://scneju2wtbd7.feishu.cn/docx/SNW8dLae7ozvBVxY7CDc2pLSnEe),A0-G 评审快照,2026-09-23 导入)
|
|||
|
|
> **权威版本**:本仓库。导入后飞书副本停止更新,改动走仓库提交与 ADR 流程。
|
|||
|
|
> **A0.10 补记**:1.4 已补入单机 SQLite 文件路径与跨库写法约定(ADR-0007);飞书副本未同步。
|
|||
|
|
|
|||
|
|
承接《多系统智能体平台 · 架构设计》,把落地问题定到“谁做、放在哪、走什么流程”。本文只写落地约束,不重复分层原理。
|
|||
|
|
|
|||
|
|
章节按从基础到高级排列:先看数据与界面,再看 Provider 扩展,最后看多 Sub-agent 协作。
|
|||
|
|
|
|||
|
|
# 总览
|
|||
|
|
|
|||
|
|
先看两张图:一张是用户实际怎么用,一张是系统怎么搭。后面的章节都是这两张图的展开。
|
|||
|
|
|
|||
|
|
## 用户使用流程(桌面端)
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart TB
|
|||
|
|
A["打开桌面端"] --> B["选项目 或 新建会话"]
|
|||
|
|
B --> C["用自然语言说出目标"]
|
|||
|
|
C --> D["服务端:Pi 理解目标并选能力"]
|
|||
|
|
D --> E{"只读 还是 写操作"}
|
|||
|
|
E -->|只读| F["工作区展示表格 / 甘特 / 图表"]
|
|||
|
|
E -->|写入| G["生成变更草案"]
|
|||
|
|
G --> H["确认卡:影响范围 · 参数 · 版本"]
|
|||
|
|
H -->|拒绝| I["记录并说明原因"]
|
|||
|
|
H -->|批准| J["Core 执行并留痕"]
|
|||
|
|
J --> K["回执与证据回到对话"]
|
|||
|
|
F --> L["追问 / 对比 / 导出"]
|
|||
|
|
K --> L
|
|||
|
|
|
|||
|
|
classDef start fill:#ffffff,stroke:#9aa7b8,color:#243247;
|
|||
|
|
classDef ui fill:#f5f8fc,stroke:#9aaec7,color:#243247;
|
|||
|
|
classDef gate fill:#fff1e7,stroke:#f97316,color:#243247;
|
|||
|
|
class A,B,C ui;
|
|||
|
|
class E,H gate;
|
|||
|
|
class D,F,G,I,J,K,L start;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
关键点:只读直接出结果,写入一律先出草案再出确认卡;批准后由 Core 执行,回执与证据回到对话,不留在后台。
|
|||
|
|
|
|||
|
|
## 整体架构
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart TB
|
|||
|
|
subgraph CLIENT[客户端]
|
|||
|
|
DESK["桌面端 · Electron
|
|||
|
|
界面 · 工作区 · 本地能力"]
|
|||
|
|
WEBUI["浏览器"]
|
|||
|
|
end
|
|||
|
|
subgraph SERVER[服务端 · 引擎中立的平台服务]
|
|||
|
|
APP["应用服务
|
|||
|
|
会话 · 编排 · 能力查询 · 事件推送"]
|
|||
|
|
ENGINE["引擎适配
|
|||
|
|
统一接口:Pi 或 Codex"]
|
|||
|
|
CORE["平台 Core
|
|||
|
|
身份 · 策略 · 审批 · 执行 · 审计"]
|
|||
|
|
SUITE["Provider 接入
|
|||
|
|
契约 · 路由 · 适配"]
|
|||
|
|
end
|
|||
|
|
subgraph DATA[数据层]
|
|||
|
|
PG[("PostgreSQL
|
|||
|
|
项目 · 执行 · 审批 · 审计")]
|
|||
|
|
JSONL[("会话记录
|
|||
|
|
服务端权威,本地离线副本")]
|
|||
|
|
OBJ[("文件存储
|
|||
|
|
附件 · 产物")]
|
|||
|
|
end
|
|||
|
|
APS["APS 系统"]
|
|||
|
|
ERP["ERP 系统"]
|
|||
|
|
EMS["EMS 系统"]
|
|||
|
|
DESK --> APP
|
|||
|
|
WEBUI --> APP
|
|||
|
|
APP --> ENGINE
|
|||
|
|
ENGINE --> CORE
|
|||
|
|
CORE --> SUITE
|
|||
|
|
SUITE --> APS
|
|||
|
|
SUITE --> ERP
|
|||
|
|
SUITE --> EMS
|
|||
|
|
APP --> PG
|
|||
|
|
APP --> JSONL
|
|||
|
|
APP --> OBJ
|
|||
|
|
|
|||
|
|
classDef ext fill:#fafafa,stroke:#7f8c9c,color:#243247,stroke-dasharray:5 4;
|
|||
|
|
class APS,ERP,EMS ext;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
\>
|
|||
|
|
|
|||
|
|
接入层只做界面;平台服务里入口、运行时、控制面、Provider 套件四段分开;数据层按结构化数据、会话文件、文件资产三类存放。桌面端与浏览器共用同一套平台服务。
|
|||
|
|
|
|||
|
|
# 1 数据管理
|
|||
|
|
|
|||
|
|
对象分五类:项目、会话、设置、工作区、运行与证据。
|
|||
|
|
|
|||
|
|
| 对象 | 作用域 | 关键内容 |
|
|||
|
|
|-|-|-|
|
|||
|
|
| 用户与租户 | 全局 | 身份、角色、所属租户 |
|
|||
|
|
| 项目 | 租户内 | 工作目录、成员与角色(owner / editor / viewer)、业务上下文 |
|
|||
|
|
| 会话 | 个人或项目 | 消息、工具调用、结论;个人会话私有且只读,写操作必须在项目会话内 |
|
|||
|
|
| 工作区 | 用户 × 项目 | 打开的视图集合、当前选择、会话;可恢复上次状态 |
|
|||
|
|
| 设置 | 系统 / 租户 / 项目 / 用户 / 会话 | 后一级覆盖前一级;会话级只在本次有效 |
|
|||
|
|
| 运行与执行 | 会话内 | executionId、参数摘要、幂等键、状态、回执 |
|
|||
|
|
| 审批 | 项目内 | 请求、一次性授权、决策事件 |
|
|||
|
|
| 审计 | 全局 | 哈希链,只追加不可删 |
|
|||
|
|
| 文件 | 项目内 | 元数据入库,内容放对象存储或本地目录 |
|
|||
|
|
|
|||
|
|
| 存储 | 放什么 | 备注 |
|
|||
|
|
|-|-|-|
|
|||
|
|
| PostgreSQL | 项目、权限、设置、运行、审批、审计等结构化数据;服务端模式的会话消息也在库里 | 桌面模式用 SQLite 承接同类数据 |
|
|||
|
|
| 对象存储或本地目录 | 上传的文件、导出物 | 数据库只存元数据与校验和 |
|
|||
|
|
| 会话 JSONL(桌面) | 每个会话一个文件,消息与工具调用按行追加 | 放 \~/.aps/sessions 下,见 1.4 |
|
|||
|
|
| 桌面端 \~/.aps | 本机配置、缓存、日志、Provider 包 | 与服务器同构,便于同步 |
|
|||
|
|
|
|||
|
|
**四条规矩:**审计只追加不修改;写操作必须有项目归属(个人会话只读,写操作一律在项目会话内,因为审批、审计与证据都要求项目归属);会话删除是软删,运行与证据保留;文件删除要过审批。
|
|||
|
|
|
|||
|
|
## 1.1 会话里都有什么
|
|||
|
|
|
|||
|
|
| 内容 | 存什么 | 放哪 | 生命周期 |
|
|||
|
|
|-|-|-|-|
|
|||
|
|
| 消息 | 角色、内容块、时间、token 数 | 桌面 JSONL / 服务端 PostgreSQL,只追加 | 随会话软删 |
|
|||
|
|
| 内容块 | 文本 / 图片 / 附件引用 / 工具调用 / 审批卡 / 视图引用 | 随消息 | 同上 |
|
|||
|
|
| 上下文快照 | 实际发给模型的消息集合与压缩摘要 | 随会话文件 / 服务端库 | 用于复盘“当时模型看到了什么” |
|
|||
|
|
| 工具调用 | capabilityId、参数摘要、结果引用、executionId | 随消息 | 只追加 |
|
|||
|
|
| 审批记录 | 请求、决策、批准人、失效条件 | 关联消息与审批表 | 只追加 |
|
|||
|
|
|
|||
|
|
## 1.2 附件与产物
|
|||
|
|
|
|||
|
|
| 类型 | 来源 | 归属 | 存法 |
|
|||
|
|
|-|-|-|-|
|
|||
|
|
| 附件 | 用户上传 | 项目文件库 | 原文件 + 元数据 + 校验和;消息里只放引用 |
|
|||
|
|
| 产物 | Agent 生成 | 项目 | 带版本号,记录产生它的 executionId,可对比与回滚 |
|
|||
|
|
| 导出物 | 报告 / 表格 / 图纸导出 | 项目 | 发布为文件,保留生成参数与来源快照 |
|
|||
|
|
| 视图快照 | 用户在工作区保存 | 用户 × 项目 | 只存定义与参数,不存渲染结果 |
|
|||
|
|
|
|||
|
|
| 规则 | 说明 |
|
|||
|
|
|-|-|
|
|||
|
|
| 大内容不进消息表 | 消息只放引用、摘要与校验和,正文与二进制进对象存储 |
|
|||
|
|
| 附件按校验和去重 | 同一文件被多个会话引用只存一份 |
|
|||
|
|
| 产物有版本 | 生成物不覆盖历史,能对比前后差异,能回滚到指定版本 |
|
|||
|
|
| 权限跟着项目走 | 离开项目后失去项目文件访问权,个人会话里的引用同样失效 |
|
|||
|
|
| 删除要留痕 | 附件删除需审批;产物保留版本历史,审计不删 |
|
|||
|
|
|
|||
|
|
## 1.3 上下文窗口
|
|||
|
|
|
|||
|
|
不把整段会话塞给模型。按 token 预算取「最近若干轮 + 滚动摘要 + 钉住的引用」,工具结果只进摘要与引用,需要细节时再调对应能力取回。压缩后的摘要与原始消息都保留,任何结论都能追到原始输入。
|
|||
|
|
|
|||
|
|
## 1.4 会话文件格式(服务端为主,本地 JSONL 副本)
|
|||
|
|
|
|||
|
|
架构改成客户端加服务端之后,会话默认由服务端保存;客户端本地用 JSONL 存一份离线副本,断网时可读、可导出。格式与 Pi 的会话文件一致:每个会话一个文件,一行一条 JSON,每行带 id 与 parentId 组成树,支持在同一个文件里原地分支。
|
|||
|
|
|
|||
|
|
| 存储形态 | 桌面端 | 服务端 |
|
|||
|
|
|-|-|-|
|
|||
|
|
| 会话消息 | \~/.aps/sessions/<项目>/<时间戳>\_<会话id>.jsonl | PostgreSQL |
|
|||
|
|
| 会话索引 | 本地 SQLite(列表、搜索、未读) | PostgreSQL |
|
|||
|
|
| 附件与产物 | 文件目录,JSONL 只存引用 | 对象存储 + 元数据表 |
|
|||
|
|
| 执行、审批、审计 | 本地 SQLite,不放 JSONL | PostgreSQL |
|
|||
|
|
| 单机库文件 | ~/.aps/aps.sqlite(与会话 JSONL 同级;备份即拷贝目录) | 不适用(用 PostgreSQL 自身的备份) |
|
|||
|
|
| 导出与交换 | JSONL | JSONL |
|
|||
|
|
|
|||
|
|
**一行 JSON 的字段:**
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{"v":1,"type":"header","sessionId":"s-...","project":"...","ts":1757404800000}
|
|||
|
|
{"v":1,"type":"message","id":"a1","parentId":null,"role":"user","ts":...,"content":[...]}
|
|||
|
|
{"v":1,"type":"tool_call","id":"a2","parentId":"a1","capabilityId":"aps.schedule.preview","argsDigest":"sha256:..."}
|
|||
|
|
{"v":1,"type":"tool_result","id":"a3","parentId":"a2","executionId":"exec-...","status":"accepted","jobId":"..."}
|
|||
|
|
{"v":1,"type":"approval","id":"a4","parentId":"a3","approvalId":"apr-...","decision":"approved"}
|
|||
|
|
{"v":1,"type":"summary","id":"a5","parentId":"a3","covers":["a1","a2","a3"],"text":"..."}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
| 规则 | 说明 |
|
|||
|
|
|-|-|
|
|||
|
|
| 只追加 | 不改历史行;分支靠 id 与 parentId 组成树,不新建文件 |
|
|||
|
|
| 带版本 | 文件头一行是会话元信息,含格式版本;加载时按版本迁移,旧文件可读 |
|
|||
|
|
| 大内容在外 | 附件与二进制不进 JSONL,只放引用、摘要与校验和 |
|
|||
|
|
| 不落敏感 | 参数只写摘要与规范化结果,凭据与敏感明文不落文件 |
|
|||
|
|
| 索引另存 | 会话列表、搜索、未读数走本地 SQLite,不在打开时扫描全部文件 |
|
|||
|
|
| 可直接使用 | 备份、导出、排查直接用文件;服务端导出也用同一格式,本地能打开 |
|
|||
|
|
|
|||
|
|
**为什么不把一切都放文件:**执行记录、审批与审计需要按条件查询、并发写入和防篡改,放进本地数据库更合适;JSONL 只承担会话消息流。共享与多端场景下,会话消息改由服务端 PostgreSQL 承接,本地 JSONL 作为离线副本与导出格式。两种存储实现同一个 SessionStore 接口,上层代码共用。
|
|||
|
|
|
|||
|
|
**跨库写法约定(ADR-0007):**时间统一存整数毫秒;主键由应用侧生成(ULID);JSON 列在 PostgreSQL 落 JSONB、在 SQLite 落 TEXT;金额与工时用整数最小单位;不用触发器、存储过程与数据库专属函数。一套方言无关 schema + 一个迁移工具,禁止两边各写一套。
|
|||
|
|
|
|||
|
|
## 1.5 谁是权威数据源
|
|||
|
|
|
|||
|
|
引擎在开发或部署期选定,会换;数据归属不能跟着换。应用服务持有会话与业务记录,Core 持有执行与审计,引擎的原生状态只用于同引擎恢复。
|
|||
|
|
|
|||
|
|
| 数据 | 权威在谁 | 说明 |
|
|||
|
|
|-|-|-|
|
|||
|
|
| 会话与消息 | 平台(应用服务) | 平台格式是权威;引擎只拿上下文,不拿所有权 |
|
|||
|
|
| 上下文检查点与摘要 | 平台 | 发给模型的上下文由平台构建,压缩结果一并保存,可追溯 |
|
|||
|
|
| 执行、审批与审计 | Core | 与引擎无关,进程重启或换引擎都继续存在 |
|
|||
|
|
| 引擎原生状态 | 对应引擎 | Pi 的内存上下文、Codex 的 thread:只保存原生引用,用于同引擎恢复,不作为业务真相 |
|
|||
|
|
| 客户端本地副本 | 平台(副本) | 桌面端 JSONL 只作离线读取与导出,冲突以服务端为准 |
|
|||
|
|
|
|||
|
|
# 2 界面设计
|
|||
|
|
|
|||
|
|
视觉与布局沿用现有 APS 项目的设计系统,不另起一套。现有界面已经跑过对话、视口、审批卡、证据链和桌面壳,直接继承比重新发明便宜,也让团队不用学第二套规范。
|
|||
|
|
|
|||
|
|
## 2.1 设计系统(沿用)
|
|||
|
|
|
|||
|
|
| 维度 | 规范 |
|
|||
|
|
|-|-|
|
|||
|
|
| 色彩 | 浅底 #FAFAF8 / 暗色 #1B1B1F;唯一强调色为工业橙 #F97316,只用于主操作与激活态;红黄绿只表达状态,不做装饰 |
|
|||
|
|
| 侧栏 | 浅色微透明,激活项用浅色胶囊,层级靠明度差不靠边框 |
|
|||
|
|
| 字体 | 系统栈 + Noto Sans SC;正文 14px / 1.65;数字用 tabular-nums 对齐 |
|
|||
|
|
| 圆角 | 卡片 12px、对话气泡 16px、按钮与输入框 10px、胶囊 999px |
|
|||
|
|
| 阴影与边框 | 低海拔柔和阴影,边框仅 1px 极浅色,不叠双重描边 |
|
|||
|
|
| 间距 | 8pt 网格:8 / 12 / 16 / 24 / 32 |
|
|||
|
|
| 暗色模式 | 跟随系统并支持手动切换,语义色配对暗色变体 |
|
|||
|
|
| 动效 | 150–250ms ease-out;输出流式呈现;左说右动时右侧目标元素脉冲高亮一次 |
|
|||
|
|
| 数据呈现 | KPI 用大数字卡片;表格弱化网格线;甘特用低饱和色板加悬浮细节卡 |
|
|||
|
|
| 空态与加载 | 空态给引导与快捷指令;长任务给骨架屏与可取消进度 |
|
|||
|
|
|
|||
|
|
## 2.2 三栏布局(沿用)
|
|||
|
|
|
|||
|
|
桌面端与 Web 端同一套界面,只是外壳不同。右栏在现有项目里是排产视口,这一版泛化为工作区,可以承载任意 Provider 视图。
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
┌──┬───────────────┬──────────────────────┬───────────────────────────┐
|
|||
|
|
│ │ 项目/会话面板 │ 中:会话区 │ 右:工作区 │
|
|||
|
|
│导│ ───────────── │ ┌────────────────┐ │ ┌─────────────────────┐ │
|
|||
|
|
│航│ ▸ 新建会话 │ │ 面包屑:项目/会话│ │ 表格 / 甘特 / 图表 │ │
|
|||
|
|
│轨│ ▸ 项目列表 │ │ 对话流(UI块) │ │ 对比 / 文件 / 网页 │ │
|
|||
|
|
│ │ ▸ 待审批 │ │ 审批卡 / 证据链 │ │ 运行记录 │ │
|
|||
|
|
│56│ ▸ 工作区 │ │ ────────────── │ │ │ │
|
|||
|
|
│px│ ▸ Provider │ │ 输入框(多模态) │ │ │ │
|
|||
|
|
│ │ ▸ 设置 │ │ │ │ │ │
|
|||
|
|
└──┴───────────────┴──└────────────────┘──┴──└─────────────────────┘──┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
| 区域 | 职责 |
|
|||
|
|
|-|-|
|
|||
|
|
| 导航轨 56px | 新建会话、项目、待审批、工作区、Provider、设置,图标加悬浮提示 |
|
|||
|
|
| 项目/会话面板 | 会话按项目分组,带状态徽章(运行中 / 待审批 / 已完成),支持搜索、归档、置顶 |
|
|||
|
|
| 中栏会话区 | 对话流内嵌 UI 块;顶部面包屑(项目 / 会话 / 分支);底部多模态输入框 |
|
|||
|
|
| 右栏工作区 | 可整栏收起或最大化,承载表格、甘特、图表、对比、文件与网页 |
|
|||
|
|
|
|||
|
|
## 2.3 UI 块协议(沿用并扩展)
|
|||
|
|
|
|||
|
|
模型不直接输出 HTML,而是输出结构化 UI 块,由前端按类型渲染。这套协议在现有项目里已经落地,继续沿用,只增加一个 Provider 类型。
|
|||
|
|
|
|||
|
|
| 块类型 | 用途 |
|
|||
|
|
|-|-|
|
|||
|
|
| text / markdown | 正文与说明 |
|
|||
|
|
| confirm-card | 门禁确认卡:影响范围、参数摘要、目标版本 |
|
|||
|
|
| evidence | 证据链:来源系统、时间、版本 |
|
|||
|
|
| diff | 方案与分支对比 |
|
|||
|
|
| gantt / load-heatmap / conflict-list | 排产类可视化 |
|
|||
|
|
| scenario-cards / sensitivity | 方案卡组与敏感性分析 |
|
|||
|
|
| report | 报告预览与导出 |
|
|||
|
|
| media | 图片、音频转写、视频帧 |
|
|||
|
|
| provider-view | Provider 声明的视图,由宿主转发数据(见第 4 节) |
|
|||
|
|
|
|||
|
|
和第 4 节的关系:Provider 可视化就是 UI 块协议的一个扩展点。Provider 只声明视图,平台用自己的组件渲染,不引入第二套渲染体系。
|
|||
|
|
|
|||
|
|
## 2.4 主要界面
|
|||
|
|
|
|||
|
|
| 界面 | 作用 | 关键交互 |
|
|||
|
|
|-|-|-|
|
|||
|
|
| 对话 | 主入口 | 消息流 + 工具调用卡 + 内联审批卡 + 内联图表 |
|
|||
|
|
| 审批中心 | 待我审批 / 我发起的 / 已处理 | 影响范围、参数摘要、目标版本,可拒绝与转交 |
|
|||
|
|
| 工作区 | 表格 / 甘特 / 图表 / 对比 / 文件 / 网页 | 与对话联动,点数字看来源 |
|
|||
|
|
| Provider 管理台 | 安装、启停、健康、契约、日志 | 双面板:左清单右详情 |
|
|||
|
|
| 运行记录 | 按 executionId 追溯 | 谁、什么时候、用什么参数、结果如何 |
|
|||
|
|
| 设置 | 账号绑定、模型、安全、数据位置 | 账号绑定逐系统显示登录态 |
|
|||
|
|
|
|||
|
|
**与现有界面的差异只有四处:**右栏从排产视口泛化为工作区;导航轨增加工作区与 Provider 入口;UI 块协议增加 provider-view 类型,数据经宿主转发;审批聚合为独立界面,支持待我审批 / 我发起的 / 已处理。其余包括设计系统、三栏布局、自绘顶栏与桌面壳全部沿用。
|
|||
|
|
|
|||
|
|
## 2.5 交互原则
|
|||
|
|
|
|||
|
|
| 原则 | 说明 |
|
|||
|
|
|-|-|
|
|||
|
|
| 写操作都有确认卡 | 影响范围 + 参数摘要 + 目标版本,参数变了即失效 |
|
|||
|
|
| 状态始终可见 | 排队、执行中、等待审批、已完成、结果未知 |
|
|||
|
|
| 数字可追溯 | 关键数字能点开看到来源系统、时间与版本 |
|
|||
|
|
| 失败显式 | 显示错误分类与是否可重试,不用话术圆场 |
|
|||
|
|
| 不暴露实现细节 | 界面不出现凭据、内部 token、Provider 内部结构 |
|
|||
|
|
|
|||
|
|
# 3 工作区
|
|||
|
|
|
|||
|
|
工作区是右侧的多标签面板:把对话里的结果钉下来,慢慢看、反复比。它不是第二个业务系统,所有数据都经 Core 获取。
|
|||
|
|
|
|||
|
|
| 面板类型 | 内容 | 数据来源 | 可否编辑 |
|
|||
|
|
|-|-|-|-|
|
|||
|
|
| 表格 | 订单池、资源、物料清单 | 能力调用(只读) | 编辑生成变更草案,需审批 |
|
|||
|
|
| 甘特 / 排程 | 计划、工序、资源占用 | 能力调用 | 拖拽生成草案,需审批 |
|
|||
|
|
| 图表 | 负荷曲线、KPI、方案对比 | 能力调用 | 否 |
|
|||
|
|
| 对比 | 方案 A/B、执行前后差异 | 两次执行结果 | 否 |
|
|||
|
|
| 文档预览 | 报告、PDF、Word | 产物 | 否 |
|
|||
|
|
| 文件浏览 | 项目目录树与文件预览 | 项目工作目录 | 上传、重命名走审批 |
|
|||
|
|
| 图纸 / 图片 | CAD 转图、现场照片 | 项目文件 | 否 |
|
|||
|
|
| 代码 / 文本 | 配置、工艺文件、脚本 | 项目文件 | 编辑走审批 |
|
|||
|
|
| 网页 | 外部页面 | 系统浏览器或受控内嵌 | 否 |
|
|||
|
|
| 运行记录 | 按 executionId 追溯 | 平台 | 否 |
|
|||
|
|
|
|||
|
|
组织方式:标签页 + 布局 + 当前选择,整体作为一个工作区状态保存,换设备也能恢复。对话里的卡片可以钉到工作区,工作区的当前选择也能回填给对话。
|
|||
|
|
|
|||
|
|
| 网页浏览 | 做法 | 说明 |
|
|||
|
|
|-|-|-|
|
|||
|
|
| 用户看网页 | 默认交给系统浏览器打开 | 最省事,也不把外部内容混进产品界面 |
|
|||
|
|
| 需要内嵌时 | 受控面板,域名白名单,明确标识外部内容 | 禁止自动填表与凭据注入 |
|
|||
|
|
| Agent 读网页 | 走 web.fetch 能力 | 域名白名单、体积上限、脱敏、全程审计;不给 Pi 通用 HTTP 工具 |
|
|||
|
|
|
|||
|
|
| 工作区边界 | 说明 |
|
|||
|
|
|-|-|
|
|||
|
|
| 不持有业务凭据 | 凭据只存在平台凭据代理,工作区只拿渲染所需的数据 |
|
|||
|
|
| 数据都经 Core | 每次取数带用户身份与权限,越权直接拒绝 |
|
|||
|
|
| 编辑先出草案 | 拖拽、改单元格生成变更草案,审批通过才写入业务系统 |
|
|||
|
|
| 文件访问受限 | 文件浏览限制在项目工作目录内,不遍历整机 |
|
|||
|
|
| 状态属于偏好 | 打开的标签、布局、列设置可跨端同步;不属于业务数据 |
|
|||
|
|
|
|||
|
|
# 4 Provider 可视化怎么集成
|
|||
|
|
|
|||
|
|
结论:平台定义视图契约,Provider 只做声明,渲染由平台负责;确有复杂交互时再开 iframe 沙箱。
|
|||
|
|
|
|||
|
|
| 方案 | 做法 | 适用 | 代价 |
|
|||
|
|
|-|-|-|-|
|
|||
|
|
| 平台渲染(推荐) | Provider 在 manifest 里声明视图,用平台的组件词汇表(表格 / 图表 / 表单 / 甘特 / 时间线 / 差异)描述界面;数据由 Core 提供 | 绝大多数业务视图 | 组件词汇表要覆盖得住场景,早期可能不够 |
|
|||
|
|
| iframe 沙箱 | Provider 自带页面,平台嵌进面板 | 第三方 Provider、复杂交互 | 要严格 sandbox 与 CSP,且不能让它直接拿凭据 |
|
|||
|
|
| 静态内容 | 只给 markdown 或图片 | 说明类内容 | 没有交互能力 |
|
|||
|
|
|
|||
|
|
数据只有一条通路:视图 → 宿主 postMessage → 平台校验身份 → Core.invoke → 返回。iframe 不允许直连业务系统,也不注入任何凭据。
|
|||
|
|
|
|||
|
|
| 视图契约 | 字段与取值 |
|
|||
|
|
|-|-|
|
|||
|
|
| 槽位 slot | nav.item / session.sidepanel / provider.detail.tab / message.inline |
|
|||
|
|
| 类型 kind | schema(平台组件渲染)/ iframe(受信沙箱)/ markdown(说明) |
|
|||
|
|
| 数据来源 | capabilityId + 参数模板,运行时由 Core 补齐身份与授权 |
|
|||
|
|
| 刷新 | 手动 / 定时 / 订阅事件,统一由平台调度 |
|
|||
|
|
|
|||
|
|
首版只开两类视图:只读表格与图表,且只允许 schema 类型。iframe 留到接入第三方 Provider 时再开。
|
|||
|
|
|
|||
|
|
# 5 Provider 怎么开发与管理
|
|||
|
|
|
|||
|
|
Provider 先写适配器,再以包的形式安装和管理。开发步骤与运行机制如下,包结构与生命周期见后。
|
|||
|
|
|
|||
|
|
**开发步骤:**
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
1. 定义能力:id、effect、mode、输入输出 Schema
|
|||
|
|
2. 写 manifest:providerType、version、capabilities
|
|||
|
|
3. 实现适配器:describe / invoke / health
|
|||
|
|
4. 跑契约测试
|
|||
|
|
5. 注册实例:地址、租户或工厂绑定、适配器版本
|
|||
|
|
6. 绑定账号与路由
|
|||
|
|
7. 灰度开放给引擎
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
| 运行机制 | 约定 |
|
|||
|
|
|-|-|
|
|||
|
|
| 凭据边界 | 首版 Provider 运行在平台信任域内,Core 按 execution 注入短期凭据,Provider 不落库、不缓存。外部团队接入时走跨进程模式,双向认证加一次性凭据。 |
|
|||
|
|
| 异步任务 | Core 登记 jobId 并负责轮询或接收回调,引擎只收到“已受理”和“终态”两类事件,不自己空转。 |
|
|||
|
|
| 审批 | Core 生成审批单(请求人、能力、目标实例、参数摘要、资源版本、影响范围),通过后写入执行授权,与主体、实例、参数摘要、版本和有效期绑定;参数或目标改变即失效。 |
|
|||
|
|
| 幂等与超时 | 发请求前持久化 executionId 与幂等键,一个授权只启动一个逻辑执行。超时先查回执,只有能确认未执行或下游支持可靠幂等时才重试。 |
|
|||
|
|
| 错误分类 | 统一映射为 invalid_argument、forbidden、conflict、rate_limited、unavailable、unknown_result;只有 rate_limited 与 unavailable 允许自动重试。 |
|
|||
|
|
| 契约测试 | 必须覆盖 Schema 校验、幂等重放、权限拒绝、错误映射、超时与结果未知、异步受理与查询。 |
|
|||
|
|
|
|||
|
|
| 包内容 | 说明 |
|
|||
|
|
|-|-|
|
|||
|
|
| provider.json | id、版本、供应方、能力清单、视图声明、兼容的平台版本 |
|
|||
|
|
| adapter | describe / invoke / health 的实现 |
|
|||
|
|
| ui/(可选) | 视图描述文件,走第 4 节的契约 |
|
|||
|
|
| tests/(可选) | 该 Provider 的补充契约用例 |
|
|||
|
|
| 签名与摘要 | 包签名 + SHA256,安装前必须校验 |
|
|||
|
|
|
|||
|
|
| 阶段 | 动作 | 权限级别 | 说明 |
|
|||
|
|
|-|-|-|-|
|
|||
|
|
| 发现 | 扫描目录或仓库,只读清单 | 只读 | 不执行任何代码 |
|
|||
|
|
| 安装 | 校验签名与摘要 → 解包到临时目录 → 契约校验 → 权限面变化提示 → 审批 → 落盘注册 | 需审批 | 会扩大可用能力面,必须走确认 |
|
|||
|
|
| 启用 / 停用 | 切换实例状态 | 需审批 | 停用立即阻断新调用,在途任务保留查询 |
|
|||
|
|
| 升级 | 旁路安装新版本 → 契约回归 → 审批 → 切换 | 需审批 | 保留上一版本目录,支持一键回滚 |
|
|||
|
|
| 卸载 | 先停用 → 检查在途执行与绑定 → 解除绑定 → 删除文件 | 需审批 | 执行历史与审计不删 |
|
|||
|
|
| 健康 | 定时探测 + 手动触发 | 只读 | 保留最近 N 次结果 |
|
|||
|
|
|
|||
|
|
落盘位置:桌面模式放 \~/.aps/providers/<id>/<version>/,服务端模式放平台的 provider 目录;注册表与实例绑定存数据库。
|
|||
|
|
|
|||
|
|
供应链约束:只允许内网 registry 或签名包,不从公网直接安装。Pi 自带的 pi install 是给开发者 CLI 用的,包拥有完整系统权限,不能直接搬进产品。
|
|||
|
|
|
|||
|
|
# 6 多 Sub-agent 与 Goal
|
|||
|
|
|
|||
|
|
先确认一个事实:**引擎不提供平台级的 Goal 与 Task**。Pi 的 agent-core 只有单个 Agent 循环(消息、工具、事件、steering、follow-up、abort 与思考预算),Codex 同样把它自己的多任务能力留给宿主。所以 Goal、Plan、Task 由平台定义,Sub-agent 是平台创建的一次受控运行,与所选引擎无关;每个运行记录它用的是哪个引擎。
|
|||
|
|
|
|||
|
|
| 概念 | 定义 | 关键字段 |
|
|||
|
|
|-|-|-|
|
|||
|
|
| Goal | 用户想达成的一件事 | goalId、标题、发起人、成功判据、涉及系统、期限、状态 |
|
|||
|
|
| Plan | Goal 下的步骤序列 | planId、步骤、每步输入输出、可回滚点 |
|
|||
|
|
| Task | 一个可独立执行的小任务 | taskId、角色、输入、输出 schema、工具子集、超时、预算 |
|
|||
|
|
| Sub-agent | 执行某个 Task 的一次 Agent 运行 | runId、taskId、能力子集、事件流、结果 |
|
|||
|
|
|
|||
|
|
| 规则 | 说明 |
|
|||
|
|
|-|-|
|
|||
|
|
| 权限只减不增 | Sub-agent 的能力子集必须是父级授权范围的子集,每次调用仍过 Core |
|
|||
|
|
| 写操作串行 | 同一 Goal 内的写操作串行;同一目标资源不允许并发写 |
|
|||
|
|
| 只读可并行 | 调研类只读任务可以并行,结果汇总回主 Agent |
|
|||
|
|
| 预算硬上限 | 每个 Sub-agent 有轮次、工具调用次数、超时三重上限,超限中止并回报 |
|
|||
|
|
| 输出结构化 | Sub-agent 必须按输出 schema 返回,不把整段对话塞回主上下文 |
|
|||
|
|
| 首版不互相对话 | Sub-agent 之间不直接通信,由父级编排,避免循环与成本失控 |
|
|||
|
|
|
|||
|
|
首版只做一种形态:主 Agent 派发只读调研任务(每个子任务一个能力子集),汇总后由主 Agent 出方案并走审批;写操作全部回到主 Agent 串行执行。
|
|||
|
|
|
|||
|
|
# 7 文档与规范管理
|
|||
|
|
|
|||
|
|
这一节定文档的归属与流转:权威会随阶段转移,但任何时刻只有一个权威。
|
|||
|
|
|
|||
|
|
分两个阶段。现在处于第一阶段:设计在飞书评审,评审通过后沉淀到仓库;沉淀完成即以仓库为准。
|
|||
|
|
|
|||
|
|
| 问题 | 规定 |
|
|||
|
|
|-|-|
|
|||
|
|
| 当前阶段 | 设计文档在飞书维护,方便评审与批注;仓库里保留一份镜像 |
|
|||
|
|
| 沉淀时机 | 评审通过后,用脚本把飞书文档导出为 Markdown 写入仓库,一次一份,不手工誊抄 |
|
|||
|
|
| 沉淀之后 | 仓库是唯一真相,飞书只作对外读物;冲突以仓库为准 |
|
|||
|
|
| 放在哪 | docs/ 一个入口,分 product / architecture / development / runbook / adr;本平台的设计放在 architecture/multi-system-agent-platform/ |
|
|||
|
|
| 什么时候改 | 改代码、改门禁、改能力清单、改契约,同一轮改文档,否则视为未完成 |
|
|||
|
|
| 决策留痕 | 重大选择写 ADR:背景、选项、结论、影响 |
|
|||
|
|
| 防漂移 | 用测试卡住:能力清单 ↔ 文档表格、schema ↔ 代码,对不上就红 |
|
|||
|
|
| 导出方式 | 脚本把正文导出为 Markdown,画板随正文内联为 mermaid 代码块;文件头写入来源与同步方式 |
|
|||
|
|
|
|||
|
|
# 8 测试体系
|
|||
|
|
|
|||
|
|
| 层 | 测什么 | 例子 | 运行时机 |
|
|||
|
|
|-|-|-|-|
|
|||
|
|
| 单元 | Core 纯逻辑 | 策略判定、幂等键、参数规范化、错误分类映射 | 每次提交 |
|
|||
|
|
| 契约 | Provider 是否合格 | schema 校验、幂等重放、权限拒绝、错误分类、超时与未知、异步受理 | 每次提交,接入新 Provider 必跑 |
|
|||
|
|
| 引擎适配 | 引擎实现是否合格 | 多轮对话、工具调用与回执、事件顺序、取消、错误分类、会话恢复;用假引擎回放 | 每次提交,接入新引擎必跑 |
|
|||
|
|
| 集成 | Core + Provider + 假业务系统 | 审批全链路、授权失效、并发写冲突 | 每次提交 |
|
|||
|
|
| 端到端 | 从对话到执行 | 固定模型响应回放,跑通查询、试排、发布三条主线 | 每日 |
|
|||
|
|
| 安全 | 边界是否守住 | 越权、凭据不出域、策略绕过、重放、停用后仍被调用 | 每次提交 + 发版前 |
|
|||
|
|
| 桌面 | 壳与本地服务 | 启停、单实例、离线升级与回滚、断网恢复 | 发版前 |
|
|||
|
|
| 漂移 | 文档与契约是否同步 | 能力清单 ↔ 文档、schema ↔ 代码 | 每次提交 |
|
|||
|
|
| 性能 | 求解与批量查询基线 | 黄金算例时限、并发会话数 | 每日 |
|
|||
|
|
|
|||
|
|
三条原则:测试模型只测边界不测措辞,用固定响应回放;所有写路径必须有“重试不重复生效”的用例;每条验收标准都要有一条自动化用例对应。
|
|||
|
|
|
|||
|
|
# 9 引擎怎么接入
|
|||
|
|
|
|||
|
|
架构设计只定了边界与契约,这里写怎么落地。
|
|||
|
|
|
|||
|
|
Pi 以 npm 包形式发布(MIT),直接装进 monorepo 当依赖,不需要 git submodule。agent-core 只提供智能体循环与事件流,工具由我们自己注册,默认不带文件、shell 这类工具。**硬前提:**Node ≥ 22.19.0,部署镜像要跟上。
|
|||
|
|
|
|||
|
|
| 接入方式 | 适用场景 | 说明 |
|
|||
|
|
|-|-|-|
|
|||
|
|
| npm 依赖(推荐) | 常规开发 | 装 @earendil-works/pi-agent-core 与 pi-ai,锁定版本;升级就是改 package.json |
|
|||
|
|
| 改源码:submodule 或 fork | 必须改 Pi 源码时 | 构建与升级成本高,还要自己维护 patch,并持续跟上游同步 |
|
|||
|
|
| 子进程跑 pi-coding-agent CLI | 不建议 | 它自带 read / bash / edit / write 工具,等于给模型开了本机 shell |
|
|||
|
|
| Python 平台 + Node sidecar | 平台栈必须是 Python 时 | 把 Pi 包成独立 agent 服务,Core 仍只通过 Core.invoke 与它交互 |
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"dependencies": {
|
|||
|
|
"@earendil-works/pi-agent-core": "0.85.1",
|
|||
|
|
"@earendil-works/pi-ai": "0.85.1",
|
|||
|
|
"typebox": "1.3.7"
|
|||
|
|
},
|
|||
|
|
"engines": { "node": ">=22.19.0" }
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**创建 Agent(位于 server/agent):**
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// server/agent/src/runtime.ts
|
|||
|
|
import { Agent } from "@earendil-works/pi-agent-core";
|
|||
|
|
import { createModels } from "@earendil-works/pi-ai";
|
|||
|
|
import { anthropicProvider } from "@earendil-works/pi-ai/providers/anthropic";
|
|||
|
|
|
|||
|
|
const models = createModels();
|
|||
|
|
models.setProvider(anthropicProvider()); // 也可换成 OpenAI 兼容端点
|
|||
|
|
const model = models.getModel("anthropic", "claude-sonnet-4-6");
|
|||
|
|
|
|||
|
|
export function createAgent(core: Core, subject: Subject, caps: Capability[]) {
|
|||
|
|
const agent = new Agent({
|
|||
|
|
initialState: { systemPrompt: SYSTEM_PROMPT, model },
|
|||
|
|
streamFn: models.streamSimple.bind(models),
|
|||
|
|
});
|
|||
|
|
agent.state.tools = caps.map((cap) => toTool(cap, core, subject));
|
|||
|
|
agent.subscribe((event) => publishRuntimeEvent(toRuntimeEvent(event))); // 先转成平台事件,界面对引擎无感
|
|||
|
|
return agent;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**把 Core 能力包成工具:**工具名用点号转下划线,返回值原样交给模型,失败直接 throw,Pi 会把它当工具错误反馈给模型。
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// server/agent/src/tool-bridge.ts
|
|||
|
|
export function toTool(cap: Capability, core: Core, subject: Subject): AgentTool {
|
|||
|
|
return {
|
|||
|
|
name: cap.id.replace(/\./g, "_"), // aps.schedule.publish → aps_schedule_publish
|
|||
|
|
label: cap.description,
|
|||
|
|
description: cap.description,
|
|||
|
|
parameters: cap.inputSchema,
|
|||
|
|
execute: async (_id, params, _signal, onUpdate) => {
|
|||
|
|
const receipt = await core.invoke({ subject, capabilityId: cap.id, params });
|
|||
|
|
if (receipt.status === "failed") throw new Error(receipt.errorKind);
|
|||
|
|
if (receipt.status === "accepted")
|
|||
|
|
onUpdate?.({ content: [{ type: "text", text: "已受理,执行中" }], details: receipt });
|
|||
|
|
return { content: [{ type: "text", text: JSON.stringify(receipt) }], details: receipt };
|
|||
|
|
},
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**推进方式:**现在只做三件事——定义引擎接口、守住三条纪律、写一个假的引擎实现跑一致性测试,约 3–5 天;Codex 驱动与工具面桥接等到真要切换时再写,约 2–4 周。
|
|||
|
|
|
|||
|
|
# 10 配套资源
|
|||
|
|
|
|||
|
|
架构分层与目录结构见架构设计的第 1–3 节,引擎适配与 Provider 契约见第 5–6 节;本项目的任务分解、优先级、验收标准与推进状态见下面的任务表,默认按阶段分组查看。
|
|||
|
|
|
|||
|
|
[多业务系统智能体平台 · 架构设计](https://scneju2wtbd7.feishu.cn/docx/DPHSdeVtAo8bLExzbufcpRZ3nAb)
|
|||
|
|
|
|||
|
|
[多系统智能体平台 · 项目任务](https://scneju2wtbd7.feishu.cn/base/UTkYbMacdaz6O1sxzsEcd3BTnne)</bookmark>
|
|||
|
|
|
|||
|
|
任务表内含 1 条大任务、11 个里程碑、65 个工作包与 5 个验收门禁,另有 6 条待决策项;提供「按阶段分组」「按优先级」「待决策」三个视图。
|