插件化 Agent 架构系列 · 3 / 4 · 空间维度
Spatial Composability:依赖可声明可反应(Reactive Coeffects)
空间维度 = 组件间依赖能不能显式声明 + 反应式协调。论文核心机制:Reactive Coeffects—— 每个组件声明它需要什么 coeffect(co- = 共同 / 一起 / 反向 effect),依赖变化时自动通知, 3 种反应分类:activate / deactivate / neutral。
概览
3
关键属性
3
反应类型
1
反应时序图
2
agent 落地场景
本系列 4 页进度
第一篇 · Spatial Composability 是什么
第 3 讲 · 1 定义 + 3 属性
什么是 Spatial Composability(论文 §1.1)
论文定义:spatial composability 是"components must be able to declare, discover, and resolve their dependencies on one another in a structured and verifiable manner"。换种说法——
组件声明"我要 X"——runtime 在上下文里找 X——找到就把 X 注入,找不到就保持 inactive;X 变化时,runtime 主动通知所有声明 X 的组件。
3 个关键属性
- 显式声明(declarative):依赖以 typed coeffect 形式在组件 metadata 里声明,不需要手写查找代码
- 反应式协调(reactive):依赖变化时,所有声明该依赖的组件自动被通知——不需要组件自己"轮询"或"监听"
- 生命周期联动:依赖者的 active/inactive 状态由其依赖的满足状态决定——provider 不在 → consumer 自动 inactive;provider 来了 → consumer 自动 reload
Coeffect vs Effect:effect 描述"组件对世界做了什么"(外向);coeffect 描述"组件需要世界提供什么"(内向)。一个 tool 加载时向 registry 注册(effect),同时依赖一个 logger(coeffect)——两面同时存在。
第 3 讲 · 1 时序图 + 3 反应类型
图 1 · 3 种反应:activate(依赖到位)/ deactivate(依赖消失)/ neutral(uid 不变则不动)
机制:Reactive Coeffects(论文 §3.2)
核心思想:coeffect 是"声明 + 反应式通知",变化触发 3 种反应:
3 种反应(论文 Definition 26)
| 反应类型 | 触发条件 | consumer 行为 |
|---|---|---|
| activate | 依赖由"未满足"变"已满足" | consumer reload(重新 instantiate) |
| deactivate | 依赖由"已满足"变"未满足" | consumer unload(撤销 effects) |
| neutral | 依赖已满足,但是同一个 provider 的等价更新 | 无动作(依赖者不被打扰) |
3 种反应的时序(截图:provider 来了 / 走了 / 等价更新)
sequenceDiagram
autonumber
participant P as Provider 组件
participant R as Runtime
participant C as Consumer 组件
Note over R: 初始:依赖 X 未满足
C->>R: 我声明 coeffect X(激活等待)
Note over P,R: 1) Provider 加载
P->>R: ctx.set(X, value1)
R->>R: notify: 满足状态变化
R->>C: activate (X 满足)
C->>C: reload → 进入 ACTIVE
Note over P,R: 2) Provider 卸载
P->>R: ctx.set(X, ⊥) via dispose
R->>R: notify: 满足状态变化
R->>C: deactivate (X 不再满足)
C->>C: unload → 撤销 effects → INACTIVE
Note over P,R: 3) Provider 等价更新(自己改自己绑的 value)
P->>R: ctx.set(X, value2)(same provider uid)
R->>R: 同一个 provider 重新装
R-->>C: neutral(uid 没变,target digest 不变)
Note over C: 无动作(连续性保持)
Note over P,R: 4) Provider 替换(new uid)
P->>P: 卸载旧 + 装新(uid 变)
R->>C: activate → deactivate → activate
(uid digest 变化触发 reload)
(uid digest 变化触发 reload)
关键设计:uid 而非 value(论文 §5.1.3 原文)——一个 coeffect 变化是否触发 reload,不是看 value 是否变化,而是看绑定的 provider 的 uid是否变化。uid 是单调生成的,永不复用——所以"同一个 provider 的等价更新"会被识别为 neutral,不会打扰依赖者;"新 provider 替换"会被识别为 activate-deactivate-activate 序列(这是 4 种 reaction 中的第 4 种 trigger)。
第二篇 · 落地:多 agent 协作 + 工具发现
第 3 讲 · 2 场景 + 1 对比
应用到 agent 架构:2 个场景
场景 1 · 单 agent 内的工具发现("coeffect 即 capability")
- 传统:agent 启动时手动注册工具列表;想加新工具?重启 agent
- Cordis 化:每个工具是 component,ctx.set("web_search", impl) 注册;consumer agent 声明 inject: ["web_search"]——工具就位自动 activate,工具下线自动 deactivate
- agent 价值:长跑 agent 在不停服务的同时能动态加载新能力——论文 §1.2.2 提到的 "self-evolving harness" 的空间维度基础
场景 2 · 多 agent 协作("agent-as-coeffect")
- 传统:agent A 调 agent B,需要 A 硬编码 B 的 endpoint / 等 A 自己 poll B 的状态
- Cordis 化:B 把自己注册为 ctx.set("summarizer_agent", impl);A 声明 inject: ["summarizer_agent"]——B 升级 / 重启 / 替换时,A 自动 reload;B 下线时,A 自动降级为"无 summarizer"模式(而不是报错)
- agent 价值:多 agent 拓扑变化时,不需要任何 agent 写容错代码——runtime 替你协调
对比:传统 DI 框架 vs Reactive Coeffects
| 维度 | 传统 DI(Spring / Guice / Angular) | Reactive Coeffects(Cordis) |
|---|---|---|
| 注入时机 | 初始化时一次性 | 依赖变化时反应式 |
| provider 替换 | consumer 不会被通知 | consumer 自动 reload |
| provider 卸载 | consumer 持有旧引用,调用时炸 | consumer 自动 deactivate |
| 依赖图管理 | 靠 DI 容器配置 | runtime 自动遍历 |
| agent 时代的适应性 | 差(provider 频繁变化的场景) | 强(为 provider 频繁变化设计) |
跟我们仓 swebench-exp-web/ 的连接:本仓 Web 平台已经做了多 agent 协作(参考本仓 wiki 中"过程洞察"子模块)。把每个 agent 子模块视作 component、每个子模块的输入视作 coeffect,就能用 Cordis 视角审视当前实现——会发现很多"agent 找不到依赖"的错误,本质是 spatial composability 没做。
← 返回入口
末篇:Context 范式
回 §2 时间
对比:Fowler 2004, "Inversion of Control Containers and the Dependency Injection pattern"