aps-agent/docs/adr/0006-engine-as-subprocess.md

47 lines
2.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ADR-0006:引擎以长驻子进程运行
- **状态**:已接受
- **日期**:2026-09-23
- **决策人**:技术负责人
- **相关**:任务表 A3(决策 D10);设计文档《架构设计》5.1、5.2
## 背景
平台需要一个智能体循环来理解意图、挑工具、解释结果。这一循环跑在哪,决定了三件事:故障隔离、进程模型的复杂度、以及工具怎么交给引擎。
两项事实约束着选择:Codex 是 Rust 二进制,只能以子进程驱动,无法进程内嵌入;Pi 提供两种形态——进程内库(SDK),以及长驻子进程(RPC 模式,官方附带 `RpcClient` 客户端库)。若一个进程内、一个子进程,适配层要维护两套进程模型。
另有一个运行期问题:Node 是单线程。智能体循环与平台服务同进程时,长任务会挤占事件循环,影响所有会话的响应。
## 选项
| 选项 | 做法 | 代价 | 不选的理由 |
| --- | --- | --- | --- |
| A 引擎都进程内 | Pi 进程内、Codex 也进程内 | 无 IPC 开销 | Codex 无法进程内嵌入,此路不通 |
| B 引擎都子进程 | 两个引擎都以长驻子进程运行,平台通过各自官方客户端通信 | Pi 侧要写扩展桥与进程管理 | 选定 |
| C Pi 进程内 + Codex 子进程 | 维持现状 | 无需新增工作 | 两套进程模型;智能体循环与平台争抢事件循环 |
## 结论
选 B:**两个引擎都以长驻子进程运行**,由平台拉起与守护。
- Pi:子进程 + `RpcClient`,协议是标准输入输出的 JSONL
- Codex:子进程 + app-server 协议
- 平台侧只认统一的 `AgentRuntime` 接口,不感知两者协议差异
首版一个会话对应一个引擎进程;若进程数成为负担,再评估进程复用(Pi 支持会话切换,Codex 支持多线程复用)。
## 影响
- **隔离**:智能体循环不再占用平台的事件循环,长任务不拖累其他会话
- **工具面仍然不同,没有统一**:Codex 可通过 MCP 或实验性动态工具接收平台能力;Pi 需要在 pi 侧写一个扩展,注册工具并把调用以本地 HTTP 回调平台,平台再走 `Core.invoke`。该链路的鉴权复用现有模式:loopback 随机端口 + nonce 注入 + origin 校验
- **进程管理是共用的**:启停、超时、崩溃重启、日志轮转、父进程看门狗只写一套;可借鉴现有 Electron sidecar 的实现
- **对代码**:`server/agent` 增加引擎进程管理与 Pi 扩展桥;Pi 扩展放在 pi 侧的扩展目录,由平台启动子进程时指定
- **对任务**:A3.3 改为以子进程接入;新增两个工作包(引擎进程管理、Pi 扩展桥)
- **不可省**:无论哪个引擎,工具调用只有一个出口 `Core.invoke`
## 遗留
- Pi 扩展桥的鉴权细节:nonce 轮换周期、端口预留策略,在 A3 设计时定
- 引擎进程的复用策略(一进程一会话还是一款多会话)首版不做,观察实际进程数后再评估