ΓDocsInteractiveNet

13 · M4c:cell 级分布式运行时

状态:核心切片完成(2026-11)。这是从“整 flow 调度”走到“agent cell 归属 + 远程消息 + 迁移/接管”的一步。

13.1 完成了什么

新增 crates/ain-cluster:

模块 内容
protocol.rs Envelope / Outbound;spawn/deliver/snapshot/remove/ping/stats
wire.rs NDJSON/TCP 一行请求/响应
worker.rs CellHost:持有多个 AgentState,执行 behavior + effects,ack 携带 state/sends/usage
cluster.rs cell 归属(placement)、消息队列、seq、worker 端 dedupe、迁移、failover、audit
CLI ain cell serve、ain cluster demo/run/echo100

关键语义:

  • cell 归属:每个 agent 恰好属于一个 worker;coordinator 维护 placement: cell -> node。
  • 远程消息:每次消息是 Envelope { id, from, to, port, message };worker ack 里带 sends, coordinator 按 placement 路由到目标 worker。
  • seq/dedupe:coordinator 单调 id;worker seen 集合丢弃重复 envelope。
  • effect:worker 本地执行 EffectBus(mock LLM/search + HTTP/shell),返回 usage;coordinator 汇总 ledger。
  • 迁移:snapshot → spawn 到目标 → remove 源;更新 placement;audit Migrate。
  • 故障接管:节点失联时,用 last_states(最后一次 ack 的 cell 状态)在存活节点重新 spawn;audit Failover。
  • 审计:Spawn/Deliver/Send/Effect/Migrate/Failover/NodeDown 事件。

13.2 实测

3 个 cell worker:

ain cell serve --bind 127.0.0.1:7281 --id n1
ain cell serve --bind 127.0.0.1:7282 --id n2
ain cell serve --bind 127.0.0.1:7283 --id n3

ain cluster demo --nodes n1@127.0.0.1:7281,n2@127.0.0.1:7282,n3@127.0.0.1:7283

结果:

cluster scenario=pipeline nodes=3 steps=3 effects=4 usd=0.000322 state=58cedc39...
audit={"deliver": 3, "effect": 3, "send": 3, "spawn": 3}
output writer.out=[{"tag":"final", ...}]
placement=critic@n2,researcher@n1,writer@n3

迁移:

ain cluster demo --nodes ... --migrate critic:n3
# audit 增加 migrate: 1;placement critic@n3, writer@n3

故障接管:

ain cluster demo --nodes ... --kill n1
# audit: failover:1, node_down:1;researcher 迁到 n2,仍输出 writer.out

100 个 cell(echo 链):

ain cluster echo100 --nodes n1@127.0.0.1:7281,n2@127.0.0.1:7282,n3@127.0.0.1:7283
# steps=100, deliver=100, send=100, spawn=100, output c99.out

ain cluster run examples/research.flow --nodes ... 也支持任意 FlowSpec。

13.3 测试

crates/ain-cluster/tests/cluster.rs(16 个):

  • 3 节点 pipeline:最终 writer.out,3 个节点都参与。
  • 迁移 critic 后结果不变。
  • kill 节点后从最后 ack 状态 failover,仍输出。
  • 重复 envelope 被 dedupe。
  • 100 个 echo cell 跨 3 节点跑完(steps=100)。
  • 错误 token 拒绝 spawn。

总计:82 个测试(27 core/golden + 9 language + 19 runtime + 8 sched + 19 cluster)。

13.4 与“真正分布式交互网”的差距

项目 M4c 实际
cell 归属 ✅ agent 级
远程消息 ✅ TCP NDJSON + seq/dedupe
迁移 ✅ snapshot/spawn/remove
故障接管 ✅ last-ack 状态,at-least-once
传输安全 ❌ 仅共享 token;无 mTLS
背压 ❌ 无界队列
精确一次 ❌ at-least-once;重复消息靠 id dedupe
session 协议 ❌ 只有 FlowSpec protocol label
worker 自动心跳/再入 ❌ 需手动 kill/health
100 agents 单 flow ✅ echo 链(非 LLM)
LLM agents 单 flow 100 ❌ 未做

13.5 M4d 计划(已实现,见 13.6)

  1. backpressure:每 cell/每节点有界队列 + credit。
  2. mTLS + capability token:每个 cell 一条 capability;撤销。
  3. worker watch:自动心跳、摘除、重新加入。
  4. at-least-once → exactly-once:effect idempotency + dedupe 持久化。
  5. 100 个真实 LLM agents 单 flow 与 kill-node 5s 恢复演练。
  6. remote wire 的图级语义:跨节点 wire 也进入 trace/可视化。

13.6 M4d 追加(安全/通道/幂等/LLM 100)

per-cell capability

  • Spawn 携带 capability;Envelope 携带 capability;worker 对 deliver/snapshot/remove 校验。
  • Cluster::revoke(cell) → 生成新 capability → SetCapability → 旧 capability 立即失效。
  • 测试:错误 capability 拒绝;revoke 后旧 cap 拒绝、新 cap 可用;cluster revoke 后仍输出。
  • 注意:capability 是 run_id-cell-seq 字符串,不是密码学 token;仍依赖共享 token + 受信网络。

per-edge channels

  • Envelope 增加 channel = "<from>:<port>" 与 seq。
  • worker 按 (run, channel) 维护 last_seq:
    • seq == last+1 接受;
    • seq <= last 视为重复(ack duplicate);
    • seq > last+1 拒绝(gap)。
  • 测试:gap 拒绝;旧 seq dedupe;跨 run 复用 worker 正常(channel key 含 run)。

effect 幂等缓存

  • worker 缓存 run:cell:op:input_hash -> output。
  • 同一 effect 输入再次出现(不同 envelope id)不会重复调用 handler,也不会重复计费。
  • 测试:counting handler 只被调用 1 次;effect_cache_len=1。
  • 限制:缓存是 per-worker;跨节点 failover 后缓存丢失,仍可能重复执行(需持久化幂等键)。

worker watch / rejoin

  • Cluster::watch_once():ping 所有节点;失联 → failover;恢复 → NodeUp。
  • Cluster::watch(rounds, interval);CLI ain cluster watch。
  • Cluster::add_node(id, address) 可把恢复的 worker 重新挂到同一 node id。
  • 测试:kill 后 down 包含节点;新 worker + add_node 后 rejoined + NodeUp。

100 LLM-cell 链

  • demo::llm_chain(100):每个 cell 执行一次 mock LLM effect,再发给下一个。
  • ain cluster llm100 --nodes ...:3 节点、100 cells、100 effects、100 steps。
  • --kill-after 30 --kill n1:34 个 cell failover,最终仍 100 effects、同 output。
  • --kill-after 30 --kill n1:34 个 cell failover,最终仍 100 effects、同 output。

audit 落盘

  • ain cluster ... --save-audit <path> 输出完整 audit JSON(Spawn/Deliver/Send/Effect/Migrate/Failover/NodeUp/Revoke)。

仍然没做

  • mTLS / 密码学 capability / capability 撤销的持久化。
  • 背压(coordinator 队列无界)。
  • 跨 worker exactly-once:M5 已用 coordinator ledger 复用 effect 结果;provider 调用成功但 ledger 未落盘的窗口仍存在。
  • wire 级(同一 cell 多端口)通道与重连窗口。
  • 100 个真实 LLM provider(当前 mock)。

测试总数:82。

在 GitHub 编辑本文