aps-agent/docs/architecture.md

27 KiB
Raw Permalink Blame History

多业务系统智能体平台 · 架构设计

来源:飞书文档(原文,A0-G 评审快照,2026-09-23 导入) 权威版本:本仓库。导入后飞书副本停止更新,改动走仓库提交与 ADR 流程。

**一句话:**用户在前台说需求,Pi 这个大脑把它翻译成工具调用,Core 门禁决定能不能做,Provider 翻译成各系统自己的接口,最后由业务系统执行。

本文覆盖四件事:客户端与服务端的边界、项目代码结构、控制面与智能体运行时的实现、Provider 的接入方式。文中的目录与能力名称为设计示例。

**与现有项目的关系:**本次是对现有 APS 项目的重构。现有代码不保留,只作借鉴;新系统从零实现。项目仍在开发阶段,没有客户试用数据,因此不考虑与既有数据、表结构、接口版本的兼容与迁移——旧的一切随旧代码一起退役。

落地细节(Provider 套件怎么装、多 Sub-agent 怎么协作、数据与界面、文档规范与测试)见配套文档:多系统智能体平台 · 实施设计

1 客户端与服务端

flowchart TB
  subgraph CLIENT[客户端]
    DESK["Electron 桌面端"]
    WEBUI["Web 浏览器"]
  end

  subgraph SERVER["Agent Platform Server"]
    ENTRY["HTTP / SSE 入口"]
    APP["应用服务
会话 · 任务 · 事件发布
平台持有会话与业务记录"]
    ENGINE["统一 AgentEngine 契约
开发 / 部署启动时注入一个实现"]

    subgraph RUNTIME["引擎实现二选一 · 每个部署实例只运行一种"]
      PIAD["PiAdapter"]
      CDAD["CodexAdapter"]
      PI["Pi agent-core
原生状态由适配器管理"]
      CODEX["Codex app-server
原生状态由适配器管理"]
      PIAD --> PI
      CDAD --> CODEX
    end

    CORE["平台 Core
可信身份 · 代码策略 · 持久审批
幂等执行 · 审计"]
    SUITE["Provider 接入
契约 · 路由 · 适配"]
  end

  S1["APS"]
  S2["ERP"]
  S3["EMS"]

  DESK --> ENTRY
  WEBUI --> ENTRY
  ENTRY --> APP
  APP --> ENGINE
  ENGINE --> PIAD
  ENGINE --> CDAD
  PI -->|工具桥接| CORE
  CODEX -->|工具桥接| CORE
  APP -->|能力查询 · 审批决策 · 执行状态| CORE
  CORE --> SUITE
  SUITE --> S1
  SUITE --> S2
  SUITE --> S3

  classDef default fill:#ffffff,stroke:#8a96a3,stroke-width:1.2px,color:#243247;
  classDef selected fill:#fff3e8,stroke:#d78842,stroke-width:1.5px,color:#563418;
  classDef ext fill:#fafafa,stroke:#8a96a3,color:#243247,stroke-dasharray:5 4;
  class ENGINE selected;
  class S1,S2,S3 ext;
  style CLIENT fill:#f8fafc,stroke:#b7c0c9,color:#243247
  style SERVER fill:#f8fafc,stroke:#b7c0c9,color:#243247
  style RUNTIME fill:#ffffff,stroke:#b7c0c9,stroke-dasharray:5 4,color:#526174
  linkStyle default stroke:#8a96a3,stroke-width:1.3px;

整体分两段:客户端只做界面与本地能力;服务端是引擎中立的平台服务,内部再分入口与应用服务、引擎适配、控制面、适配器四块。Pi 与 Codex 二选一,在开发或部署期选定,整段链路对客户端透明。APS、ERP、EMS 始终是平台外部的独立系统。

段 / 层 打个比方 负责 不负责
客户端 前台 界面、工作区、本地能力(文件、打印、设备)、断网缓存 业务判断、权限判断、持有业务凭据
应用服务 传达室 + 调度员 HTTP / SSE、会话与任务、能力查询、审批流转、事件推送 业务规则、直接调业务系统
Agent 引擎 大脑 理解目标、挑工具、把结果讲成人话;Pi 或 Codex 二选一 碰凭据、判断权限、直连业务库
平台 Core 门禁 + 调度台 决定能用哪些能力、以谁的身份、要不要审批,并留痕 业务规则、业务数据
Provider 接入 翻译官 把统一调用翻译成某个系统的 API,再翻译回统一回执 业务决策、持有模型上下文
业务系统 车间 自己的数据、权限、规则和状态,最终执行 因为平台放行就执行

2 项目结构

一个 monorepo,按客户端与服务端两段组织。服务端是引擎中立的平台服务:应用服务、引擎适配、控制面、Provider 接口各归其位,引擎在适配层内部选定;客户端只通过一套接口与其通信。业务系统的代码不在这个仓库里。(开发期例外:APS 暂放本仓库 aps/ 目录,形态见 ADR-0010;迁出条件也写在里面。)

agent-platform/
├── client/                      # 客户端:桌面与浏览器共用
│   ├── app/                     # React 界面:对话、工作区、审批
│   └── desktop/                 # Electron 壳:窗口、本地守护、离线升级
├── server/                      # 服务端:引擎中立的平台服务
│   ├── entry/                   # HTTP / SSE 入口、会话、鉴权
│   ├── app/                     # 应用服务:请求编排、能力查询、审批流转、事件推送
│   ├── agent/                   # 引擎适配:统一接口 + Pi / Codex 两个实现
│   ├── core/                    # 控制面
│   │   ├── registry/            # 能力目录、实例与路由
│   │   ├── identity/            # 平台用户 ↔ 各系统账号
│   │   ├── policy/              # 允许 / 拒绝 / 需审批
│   │   ├── credentials/         # 凭据托管与取用
│   │   ├── execution/           # 授权、幂等、调用网关
│   │   └── audit/               # 证据链
│   ├── provider-sdk/            # Provider 契约与契约测试
│   └── workflows/               # 跨系统顺序流程
├── providers/                   # aps / erp / ems,只放适配器
├── contracts/                   # 客户端与服务端共享的接口类型
├── deploy/                      # 部署与实例配置
└── docs/                        # 架构与接入文档
目录 职责 不该出现什么
client/app 对话、工作区、审批界面(React) 业务判断、直接调 Provider
client/desktop Electron 壳:窗口、本地守护、离线升级 业务逻辑、绕开服务端直连 Provider
server/entry HTTP / SSE 入口、会话与鉴权、装配各模块 业务规则、直接调业务系统
server/agent 引擎适配层:统一接口,以及 Pi / Codex 两个实现;唯一允许 import 引擎 SDK 的地方 业务逻辑、直接 HTTP 调业务系统
server/core 能力目录、身份、策略、凭据、执行、审计 import 任何具体 Provider
server/provider-sdk Provider 接口、Schema、契约测试、跨进程调用 具体系统的业务语义
server/workflows 跨系统顺序流程定义 协议与字段细节
providers/aps APS 适配器:manifest、adapter、字段映射 排产算法、业务数据
contracts 客户端与服务端共享的类型与接口定义 任何运行时实现细节

**依赖方向:**client → server/entry → server/app → server/agent → server/core → provider-sdk ← providers。反向依赖用 dependency-cruiser 或 eslint 的 no-restricted-imports 卡在 CI 里,避免几个月后又缠成一团。

3 一次调用怎么走

用户说:“把下周的排产计划往后推一天。”

sequenceDiagram
    participant C as 客户端
    participant A as 应用服务
    participant E as Agent
    participant K as 平台 Core
    participant P as Provider
    participant B as 业务系统
    Note over A,E: Agent 通过统一接口接入,Pi / Codex 在开发或部署期选定
    C->>A: 消息与身份令牌
    A->>A: API 鉴权、会话管理
    A->>K: 按身份与会话请求可用工具
    K-->>A: 工具清单与授权作用域
    A->>E: 消息、上下文与受限工具集
    E->>K: 受限工具桥:结构化调用
    K->>K: 校验身份、作用域与策略
    Note over E,K: 业务审批由 Core 管理,与引擎命令权限分开
    opt 策略要求业务审批(通过后继续)
        K->>K: 持久化审批单 approvalId
        K-->>A: 待审批事件与影响范围
        A-->>C: 业务审批卡:参数与资源版本
        C->>A: 审批决定与身份凭据
        A->>K: approvalId、决定与审批人
        K->>K: 校验审批人及授权 grant
    end
    K->>K: 复核权限与资源版本
    K->>K: 持久化 executionId 与幂等键
    K->>P: 受控执行与短期凭据
    P->>B: 业务 API 调用
    B->>B: 校验自身业务规则
    B-->>P: 执行回执
    P-->>K: 结构化回执
    K->>K: 持久化执行结果与审计
    K-->>E: 工具结果与证据引用
    E-->>A: 统一格式的 Agent 事件
    A-->>C: 流式呈现结果与状态
边界 传什么 谁决定
客户端 → 服务端 消息与身份令牌;不含业务凭据 客户端发起,服务端受理
应用服务 → 引擎 用户目标、上下文、本会话可见的能力清单 应用服务装配,引擎不决定权限
引擎 → Core capabilityId 与参数;不含凭据,不自报身份 引擎提议,Core 裁决
Core → Provider 主体、实例、连接、executionId、deadline、参数、幂等键、授权引用 Core
Provider → 业务系统 原生 API 调用 Provider
Provider → Core 状态、结果引用、jobId 或 errorKind 以业务系统的事实为准
Core → 客户端 结果与证据引用,经 SSE 流式下发,不回灌凭据 Core

记住一句就够:引擎只能提议,Core 决定能不能做,业务系统最终说了算。所以换引擎或换模型都不影响安全,加系统也不用动引擎。

4 控制面 Core 怎么实现

Core 不是所有请求的中转站,而是一组被多方调用的确定性后端模块:应用服务在运行前查能力、在审批时落决定、在事后查执行;Agent 在运行中提出工具调用。这些调用都是普通代码调用,不需要再放几个 Agent 来判断。

五个服务,首版放在同一个进程里,共用 PostgreSQL:

服务 具体做什么 正确性的关键
身份 Identity 验证登录身份,查用户所属租户、项目角色,以及对应业务系统的账号映射 身份来自可信登录链路;不接受模型自报的 userId
策略 Policy 用代码判断角色、能力、目标资源与操作类型,返回允许 / 拒绝 / 需审批 默认拒绝;每次真正执行前都检查,不能只在展示工具列表时过滤
审批 Approval 把待确认动作与状态落库,界面提交确认或拒绝,校验确认者是会话发起人 确认绑定具体动作、参数、目标与版本;不能变成通用通行证
执行 Execution 建执行记录,管幂等、并发、超时,调用 Provider,跟踪异步任务 防重复执行;超时不等于失败,结果未知时先查询
审计 Audit 记录请求人、批准人、操作、参数摘要、结果与证据引用 记录完整且关联一致,并限制修改权限;普通日志文件不够

**以「发布排产计划」为例:**Agent 提出「发布计划 P,版本 V」→ Core 确认身份 → 判断策略 → 需要则建审批单并推送确认卡 → 批准后复核权限与资源版本 → 用唯一执行编号与幂等键调 Provider → 保存回执与审计记录。成功记回执,异步受理跟踪 jobId,结果未知进待核实。

三个容易被低估的地方:

常见误解 实际情况
审批就是一个弹窗 弹窗只是界面。真正的审批是数据库里的状态与授权记录,进程重启、Agent 退出后依然存在;聊天里说一句「同意」不能批准任意操作
执行就是发请求,失败就重试 对方可能已经执行成功而回执丢失。只有业务系统支持可靠幂等或状态查询时才能安全重试,否则必须保留「结果未知」
Core 放行就代表能执行 Core 查的是平台权限与授权条件;业务系统仍要校验自己的规则。审批后计划被改,应由版本校验阻止发布旧方案

**为什么要这么做:**业务操作是否被允许、是否已执行、是否需要审批,由这套代码决定,不随所选引擎变化。前提是每个引擎的业务调用都必须经过 Core,不能存在绕开的路径。

4.1 协作与权限以业务系统为准

平台不做协作模型:没有审批转派、委托、多人计数、角色策略、双人分离。这些是业务系统(APS、ERP)本来就有的能力,平台重复实现一遍必然和它们的权限模型对不上。人的协作发生在业务系统里,平台只负责把人映射进去、把动作调出去、把过程记下来。

职责 谁负责 说明
能否做(权限、角色、多级审批) 业务系统 用该用户在业务系统里的身份判定;平台不复制这套规则
用什么身份做(账号映射) 平台 把登录用户映射到各系统账号,调用时使用用户自己的身份,业务系统的权限随之生效
是不是想这么做(意图确认) 平台 确认卡防的是 Agent 误解意图,不是防越权;答的只是发起人本人
做过什么(审计与执行记录) 平台 业务系统只知道账号改了数据,不知道经由 Agent、模型建议了什么、用户确认了什么

**一句话:**权限归业务系统,映射与确认归平台。动作在业务系统里已有审批流的,交给它审;只有跨系统编排这类没人能替你决定意图的动作,才由平台出确认卡。

**登录态从哪来(ADR-0012):**用户在每个系统上各自绑定一次——首选跳转该系统的授权登录(OAuth2 / OIDC),拿回来的 token 只以密文存在平台的凭据代理里;老系统没有标准登录时退化为「账号密码一次性换 token」,密码用完即弃、绝不落盘。平台不实现业务系统的登录页,也不把业务 token 下发给客户端。

4.2 确认与执行记录只存一张表

现有实现用三张表(审批请求、一次性凭据、审批事件)承载一件事。单用户场景下可以合并成一张待确认动作表:请求参数摘要、状态(待确认 / 已确认 / 已执行 / 已拒绝)、执行回执、幂等键、有效期。

**为什么能合:**批准与执行由同一个人、同一个进程完成,不需要把"批准"与"执行"拆成两个可独立消费的凭据;审批事件与审计记录重复,只保留审计。**不能省的两件事:**待确认状态必须跨进程重启存活(用户可能过一会儿才回来点确认),执行只能生效一次(幂等键加执行记录)。

4.3 代码落地(A4 已实现)

服务 代码位置 一句话契约
身份 server/core/identity/context.ts 平台用户 → 各系统账号;未绑定默认拒绝,一个系统停用不影响另一个
策略 server/core/policy/engine.ts 只返回允许 / 拒绝 / 需审批;顺序固定(可见性 → 身份 → 会话范围 → 动作分级),可换成 OPA 一类引擎
凭据 server/core/credentials/broker.ts 库里只有 AES-256-GCM 密文;按 execution 签发一次性句柄,用完即废
确认 server/core/approval/store.ts 确认与执行记录同表;绑定参数摘要、目标版本与有效期,重启后仍在
审计 server/core/audit/log.ts 只追加的哈希链,verify() 能定位被改过的那一条

五个模块由 server/core/control-plane/control-plane.ts 绑在一起注入 Core.invoke——引擎可以不认识它们,但绕不过它们。

**平台不覆盖业务系统的拒绝:**Provider 回 forbidden 就是最终结果,平台不改写成成功、不自动重试;审计里记的是「业务系统拒绝」。平台能加限制,不能替业务系统放行。

**开发期例外:**Provider 在 manifest 里声明 requiresIdentity: false 表示该系统没有账号概念(假 Provider 与联调桩),真实系统默认需要绑定。

5 引擎适配

5.1 适配层的边界规则

Pi 以 npm 包形式发布(MIT),装进 monorepo 当依赖,不需要 git submodule。首版把 Pi 作为长驻子进程运行:用官方 RpcClient 驱动(它负责拉起进程、按 id 关联响应、把事件推给监听者),协议是标准输入输出的 JSONL。这样与 Codex 的进程模型一致,也把智能体循环从平台的事件循环里隔离出去。

**硬前提:**Node ≥ 22.19.0,部署镜像要跟上。具体接入方式、代码示例与推进顺序见实施设计。

边界规则 说明
只有一个入口 只有 server/agent 允许 import Pi,其它模块必须通过这一层
工具只来自能力目录 不注册文件、shell、网络类工具,避免绕开 Core
每次都过 Core 工具的 execute 内部只调 core.invoke,不允许自己发 HTTP 请求到业务系统
按身份给工具 工具列表按用户身份过滤;切换用户要重建会话,不能复用工具集
凭据不进工具 凭据在 server/core/execution 注入,工具参数与模型上下文里出现凭据即视为缺陷
会话落库 消息与执行记录存 PostgreSQL;Pi 只负责内存态与事件流

5.2 两个引擎与切换方式

两个引擎都以长驻子进程运行,循环模型一致:平台拉起进程、发提示、收事件、发取消,互不理解对方的内部协议。差异集中在工具面——Codex 可通过 MCP 或实验性动态工具接收平台能力,Pi 需要在 pi 侧写一个扩展,把工具调用以本地 HTTP 回调平台,平台再走 Core.invoke。所以适配层要抹平的是工具面,不是事件循环。

目标是可替换,不是行为一致:三个固定点不动,两个实现可换。

**切换发生在开发或部署期,不是用户使用中。**一个部署实例只运行一种引擎,整段链路对客户端透明;这省掉了跨引擎会话交接、双引擎并行和审批跨引擎延续等一大堆复杂度。同一会话不中途换引擎。

固定点 内容 为什么
领域类型 会话、消息、事件、回执都是我们自己的类型 一旦运行时的类型渗出来,换的时候就是全平台改造
工具出口 任何运行时的工具调用都落到 Core.invoke 这是门禁,也是唯一能统一两个运行时的地方
状态 会话与执行记录由平台保存 运行时只借循环、不借状态,换的时候不用迁数据

接口只描述「怎么驱动一个循环」,不描述「允许做什么」:

interface AgentRuntime {
  createSession(input: {
    subject: Subject;
    system?: string;
    tools: ToolDescriptor[];   // 能力目录投影
    history?: Message[];       // 平台保存的历史,可恢复
  }): Promise<RuntimeSession>;
}

interface RuntimeSession {
  send(text: string, opts?: { signal?: AbortSignal }): AsyncIterable<RuntimeEvent>;
  abort(): void;
}

type RuntimeEvent =
  | { type: "text"; delta: string }
  | { type: "tool_call"; callId: string; name: string; args: unknown }
  | { type: "tool_result"; callId: string; receipt: ExecutionReceipt }
  | { type: "approval_required"; request: ApprovalRequest }
  | { type: "turn_end"; usage: Usage }
  | { type: "error"; kind: ErrorKind };
部件 Pi Codex 共同契约
驱动 长驻子进程(RpcClient 驱动,JSONL 协议) 子进程 app-server AgentRuntime 接口
工具面 RPC 无注册工具通道,靠 Pi 侧扩展桥回调平台 MCP 服务,并关掉它自带的 shell 与文件工具 两边都落到 Core.invoke
事件 subscribe 回调 协议事件流 统一的 RuntimeEvent
审批 不内置,由 Core 出确认卡 自带审批,需映射到 Core 确认卡 统一的审批请求与响应
会话 平台存 平台存,镜像它的事件 平台自己的会话格式

**难点只有一个,而且是已知的:**工具面的接法两边不同——Codex 有现成的 MCP 通道,Pi 要靠扩展桥。所以「兼容」的实质是两个工具面都要实现,且都必须汇到 Core.invoke。这也是为什么切换成本集中在工具面,而不是事件循环。进程管理那部分反而是共用的:启停、超时、崩溃重启、日志轮转、父进程看门狗只写一套。

**不实现别人的协议。**Codex 的协议只活在它的适配器内部,客户端与 Core 都不感知;服务端与客户端之间只认我们自己的一套接口(HTTP / SSE)。协议的所有权比协议的兼容性重要。

**推进方式:**现在只做四件事——定义引擎接口、守住三条纪律、写引擎进程管理与 Pi 扩展桥、写一个假引擎跑一致性测试;Codex 驱动等到真要切换时再写。

**验收方式就是一套一致性测试:**两个驱动跑同一套用例——多轮对话、工具调用与回执、事件顺序、取消、错误分类、会话恢复。过不了就不算兼容。

**做不到的部分要说清楚:**运行时独有的能力(Pi 的插话与追问、Codex 的沙箱)用能力声明暴露,界面按开关走,不做统一封装;审批粒度不可能完全对等,Codex 审批命令与补丁,我们审批业务动作,只能近似映射;提示词与工具描述格式不同,要各调一份。

6 Provider 契约

Provider 是能力适配器,不是业务系统,也不承载模型上下文。接口只三个方法:

interface Provider {
  describe(): Promise<ProviderManifest>;   // 声明能力
  invoke(ctx: ExecutionContext, call: CapabilityCall): Promise<ExecutionReceipt>;
  health(): Promise<HealthStatus>;
}

interface Capability {
  id: string;                          // 如 aps.schedule.publish
  description: string;                 // 给模型看的用途说明
  effect: "read" | "draft" | "write";  // draft:只写隔离草稿
  mode: "sync" | "async";
  inputSchema: JsonSchema;
  outputSchema: JsonSchema;
  idempotency: "none" | "key" | "natural";
  errors: ErrorKind[];
}

Provider 还要声明登录方式(ADR-0012),平台按声明走同一条绑定流程,不自己实现业务系统的登录页:

auth.kind 用于 平台做什么
oauth 有标准授权登录的系统(首选) 发起跳转 → 收回调 code → 用 exchange() 换 token
password-exchange 老系统,没有标准登录 收一次账号密码 → exchange() 换 token,密码用完即弃
apikey 系统级集成、无人值守 管理员配置,密钥挂在租户或实例上
不声明 没有账号概念的自建系统(联调桩) 视为 requiresIdentity: false

Provider 的开发步骤、运行机制与契约测试见实施设计。

**能力声明的取舍:**read 不改变状态;draft 只写隔离草稿,不走审批但必须声明清理方式;write 必须绑定唯一目标、幂等键与授权引用。sync 直接返回结果,async 先返回 jobId。

7 桌面端怎么选

桌面端在客户端这一侧,只做界面与本地能力;引擎与 Core 都在服务端。服务端可以集中部署在内网、与客户端同机部署,或混合部署(本地只保留设备与文件能力)。桌面壳的选择不影响智能体架构,真正决定选型的是“服务端部署在哪、工厂有没有网”。

方案 体积 Node 支持 工厂离线环境 结论
Electron 150MB 起 内置,Pi 可直接跑 自带 Chromium,不依赖系统组件 首版推荐
Tauri v2 10-20MB,另加 Node sidecar 需自带 sidecar 二进制 依赖系统 WebView2,老机器可能缺失 包体或内存成为硬指标时再评估
纯浏览器 / PWA 0 无 依赖现场浏览器版本 不需要本地设备能力时最省

**首版选 Electron:**工厂离线 PC 不用赌 WebView2,离线升级、进程守护、单实例都有成熟做法。Tauri 包体小,但没有 Node 运行时,主进程逻辑要用 Rust 重写且依赖系统 WebView2;等包体或内存成为硬指标时再评估。

桌面端边界 说明
不直连 Provider 所有业务调用走平台 API,桌面端只是入口
不持有业务凭据 凭据只存在平台凭据代理,本地不落长期密钥;设备证书加用户登录双重身份,换设备或换人都可追溯
本地 runner 只做本地事 打印、扫码、文件、设备采集可以本地做,业务写操作仍要过 Core
离线只缓存不越权 断网时排队与重试,恢复后仍要过策略与审批,不能本地放行

8 首版范围

先做 暂不做
一个 TypeScript / Node 平台服务 + Pi 运行库 + PostgreSQL OPA、消息总线、Temporal / Camunda
Electron 桌面壳,复用同一套 Web 界面 Tauri 迁移
Provider 跑在平台侧,进程内或边车 可视化编排
代码内声明的顺序流程 + 每步结果落库 配置化 DAG 引擎
APS 三个能力跑通,外加 ERP 或 EMS 一个只读能力 一次接入全部系统
验收项 标准
身份 不同系统的登录态可独立失效;桌面端能定位到设备与用户
权限 业务拒绝不会被 Core 放行
幂等 同一写请求重试不重复生效,或明确返回结果未知
停用 停用 Provider 后不再接收新调用
可观测 一个系统失败时能看清各步骤的实际结果

9 附录:ChatGPT 客户端的架构

记录另一个真实产品的做法,供参考,不是本项目采用的方案。一句话概括:宿主负责策略与界面,独立进程负责循环与执行,能力以 MCP 子进程接入,审批用 RPC 回流。证据来自本机进程实测与开源仓库源码,官方文档站在当前环境访问不到。

部件 形态 职责
外壳 ChatGPT.exe(Electron),9 个进程 窗口与交互,以及宿主能力:文件、浏览器、电脑操作、插件
agent 后端 codex app-server(Rust),1 个进程 模型调用、智能体循环、工具编排、沙箱执行、审批策略
能力进程 MCP 服务器(Node),22 个进程 每个启用的插件一个,作为工具接入后端
状态 ~/.codex 会话与回放记录、会话索引、历史文件,以及线程历史、状态、日志等数据库
通信 标准输入输出;源码还支持本地 socket 与 WebSocket 自有 app-server 协议(v1 / v2),RPC 风格;审批请求从 agent 回流到宿主
结论 做法 说明
可借鉴 后端长驻,不随请求起进程 模型与工具状态可以复用,冷启动只发生一次
可借鉴 能力独立进程或独立服务 插件崩溃不拖垮 agent;与本项目 Provider 独立部署是同一个思路
可借鉴 审批从 agent 回流到宿主 策略留在宿主,agent 不自己放行;与 Core 做唯一裁决者一致
不照搬 直接采用它的 app-server 协议 内部演进的协议,两代并存,跟着走会被绑住
不照搬 把会话状态交给它 状态归它所有,我们拿不到控制权,还会出现两份真相
不照搬 按它的规模铺进程 实测整棵树 54 个进程、约 3.25 GB,工厂现场需要评估

形态可学,实现自建:Core 是唯一裁决者,Provider 独立部署且只暴露契约,客户端只做界面与本地守护。要切换引擎的做法见 5.2。