硅基俊宁.
Skills · 技能体系 ↗
← 返回文章

Sidecar 边车模式:给本地 Agent 划出一间受控执行舱

俊宁 · 2026-07-18
迁自历史博客,保留原文、署名、引用与原始日期;文中的版本、成果与性能结论不代表重新完成了当前验收。
查看原始出处 ↗ · 查看迁移清单
Sidecar 边车模式:给本地 Agent 划出一间受控执行舱封面

最近在设计一个本地 Agent Host 时,我遇到了一个很典型的架构冲突:桌面应用希望用 Tauri 的原生层建立稳定的本地可信边界,但 Codex、Qoder、MCP 等 Agent 能力又高度依赖 Node.js 与 TypeScript 生态。

把所有能力塞进一个进程当然最快,但代价也很直接:UI、数据库、凭据、文件系统和 Agent Runtime 混成一团,一个 Provider SDK 崩溃或越权,就可能拖垮整个应用。

我最后采用的是 Sidecar,也就是边车模式。

一句话总结

Sidecar 是由主应用启动和监管、通过明确协议协作的独立辅助进程。它适合隔离异构运行时和高风险能力,但进程隔离不等于安全沙箱,权限仍然必须由主应用强制执行。

Sidecar 边车模式总体结构

Sidecar 到底是什么

这个名字来自摩托车边车:主车决定方向,边车跟随主车一起运行,但拥有独立空间。

放到软件架构里,主应用负责生命周期、权限和核心状态;Sidecar 负责一组边界清晰的辅助能力。实现上它通常就是子进程、独立容器或本地服务,但“子进程”是操作系统概念,“Sidecar”描述的是架构角色。

概念关注点
Child Process谁创建进程、PID、stdin/stdout、退出码
Sidecar为什么拆分、职责边界、协议、权限和故障治理
Microservice独立部署、网络边界、团队和服务自治
Plugin可扩展能力,可能仍与宿主运行在同一进程

一个进程只有在具备“随主应用交付、由主应用监管、职责受限、通过协议协作”这些特征时,才更接近 Sidecar,而不只是随手启动的脚本。

为什么本地 Agent 特别适合边车模式

本地 Agent 天然跨越多个技术栈:桌面壳需要窗口、更新、Keychain 和系统权限;Agent Runtime 需要 Provider SDK、MCP、工具调用和流式事件;数据层又需要 SQLite、索引与事务一致性。

如果全部交给 Node 主进程,接入生态很舒服,但 Node 同时成了窗口、数据库、凭据和执行权限的可信根。反过来,如果全部重写为原生实现,首版成本高,Provider SDK 更新也要长期追赶。

边车提供了第三条路:原生 Core 保留控制权,Node Agent Host 只承载 Node 生态中不可替代的部分。

组件主要职责不应该拥有的能力
React WebviewUI、交互、无特权状态原始 Secret、任意 Shell、数据库连接
原生 Core权限、生命周期、更新、审计、IPC 校验Provider 业务实现细节
原生数据服务SQLite、同步、索引、事务UI 和 Provider Token
Node SidecarCodex/Qoder SDK、ACP、MCP Adapter最终授权决策、主数据库所有权

一次 Agent 请求怎样穿过边界

Sidecar 设计真正难的不是“把 Node 启起来”,而是定义每一步谁有权做什么。

Sidecar 请求与事件流

典型链路是:

  1. Webview 提交声明式任务,例如“在当前 workspace 分析这组文件”。
  2. 原生 Core 校验调用来源、workspace scope、参数长度、组织策略和用户审批。
  3. Core 给任务生成受限 capability profile,再通过版本化 IPC 发给 Sidecar。
  4. Sidecar 调用 Provider SDK,并把 token、tool call、progress 和 error 作为有序事件流返回。
  5. Core 对事件做审计和脱敏,再通过 Tauri Channel 推给 UI。

低频控制请求可以用 NDJSON framed protocol;高频流也可以使用本地 Socket。关键不是选哪一种传输,而是必须有 protocolVersion、requestId、事件序号、取消语义、超时和背压。

不要把协议消息和普通 stdout 日志混在一起。否则一条调试日志就可能破坏 framing,让控制面变得不可预测。

进程隔离不等于安全沙箱

这是 Sidecar 最容易被误解的地方。

把 Node 放进独立进程,只解决了部分故障隔离:Sidecar 崩溃后可以单独拉起,内存泄漏不会直接污染原生 Core。但如果它继承了完整环境变量、用户目录和网络权限,它仍然能够读取不该读取的文件,或者绕过审批直接访问外部服务。

Sidecar 的可信边界与防线

因此我会把原生 Core 设计为 Permission Broker:

Tauri capability 主要约束 Webview → 原生 Core,不会自动沙箱已经启动的原生插件或 Node Sidecar。把平台 ACL 当成完整安全方案,是一个危险的边界误判。

生命周期治理比启动命令重要

生产级 Sidecar 至少需要处理下面这些状态:

starting → handshaking → ready → busy → draining → stopped
                         ↘ degraded → restarting

主应用需要回答:握手失败怎么办?任务执行中 Sidecar 崩溃是否重试?取消后怎样确保子进程和工具进程都被清理?升级时协议不兼容如何阻止启动?连续崩溃是否进入熔断?

我的判断是:Sidecar 可以独立重启,但主数据库事务和资产 revision 不能由它持有。否则所谓故障隔离只是把崩溃位置挪了一个进程,数据一致性仍被绑在 Agent Runtime 上。

什么时候值得用,什么时候不要用

Sidecar 值得用:

不值得用:

最后一种尤其常见:付出了多进程复杂度,却没有获得真实边界。

我的判断框架

我不会因为“Sidecar 是一种成熟模式”就默认采用它。我的判断顺序是:

  1. 是否存在必须保留的异构运行时或高风险能力?
  2. 能否用小而稳定的协议描述输入、输出和事件?
  3. 宿主能否真正掌握权限、生命周期和核心数据?
  4. 故障隔离收益是否大于打包、签名和调试成本?

四个问题都能给出明确答案,Sidecar 才是架构;否则它只是多启动了一个进程。

对本地 Agent 来说,我倾向于采用“可信 Core + 受控 Sidecar”:Core 决定谁能做什么,Sidecar 负责把某一种运行时的能力做到最好。边车可以执行任务,但不能决定规则。