# 多系统智能体平台 · 实施设计 > **来源**:飞书文档([原文](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///,服务端模式放平台的 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) 任务表内含 1 条大任务、11 个里程碑、65 个工作包与 5 个验收门禁,另有 6 条待决策项;提供「按阶段分组」「按优先级」「待决策」三个视图。