10 · M2:单机 AIN 执行层
状态:核心切片完成(2026-11)。本文记录实际实现与规格的差异,避免把 M2 当成完整 Ainet。
10.1 实现了什么
crates/ain-runtime(新 crate):
| 能力 | 实现 |
|---|---|
| Stateful agents | 每个 agent 有 id/kind/config/state/inbox/ports |
| 确定性调度 | 单线程;按 agent id 字典序选下一个有消息的 inbox;FIFO |
| Effects | EffectBus + mock llm / mock search;同步调用;usage 记账 |
| Budget | {usd, tokens, steps} 上限;超支返回 BudgetExceeded |
| Trace | receive/act/send/effect/error/finish 事件(JSON) |
| Replay | 从 trace 的 effect 记录重放;校验 request hash + 最终 state hash |
| Outputs | 没有 edge 的端口进入 outputs["<agent>.<port>"] |
crates/ain-cli:
ain flow demo
ain flow run examples/research-pipeline.json
ain flow run examples/research-pipeline.json --save-trace examples/research-trace.json
ain flow replay examples/research-pipeline.json examples/research-trace.json
3 Agent demo(Researcher → Critic → Writer):
- Researcher:
task→ mock search → mock LLM →draft - Critic:
draft→ mock LLM →review - Writer:
review→ mock LLM →final(终端输出) - 4 次 effect;约 0.0003 USD;7 步。
10.2 为什么不是纯交互网
标准交互网没有:
- 可寻址的 agent 信箱;
- effect 请求/响应;
- 预算;
- 可重放的外部结果。
M2 按 docs/04-ain-model.md 的分层实现 L1(状态)+ L3(effects)+ L6(成本) 的运行时;
纯计算/组合子仍由 ain-core 负责。Agent 间通信暂由运行时信箱管理(actor-style),
而不是 session-typed net channel。这是有意的工程取舍:
- 先验证"确定性 + 能力 + 成本"是否真的可用;
- 避免在 M2 就陷入 session continuation / 通道重连的复杂语义;
- M3 再把信箱降到 net wire + session types,做真正的图级分布。
10.3 数据流
FlowSpec (JSON)
│
▼
Runtime (single node)
├── agents: BTreeMap<id, AgentState> // state + inbox + ports
├── behaviors: kind -> Behavior // researcher/critic/writer
├── effects: EffectBus // llm / search (mock)
├── ledger: tokens/usd/effects/steps
└── log: Vec<Event> // trace + replay
调度:
loop {
agent = first inbox non-empty (id order)
msg = agent.inbox.pop_front()
action = behavior.handle(agent, msg)
agent.state = action.state
for (port, msg) in action.send { route or output }
if action.effect { call; ledger.add; enqueue "effect" response }
}
10.4 重放
Runtime::replay_log(&log):
- 从
Event::Effect提取(request_hash, response)。 - 重置 agents/ledger/outputs/step。
- 用相同 spec/behaviors 重跑;effect 请求必须匹配记录。
- 比较最终
state_hash与 outputs。
测试:
replay_is_deterministic_100x:live 跑 100 次,state hash 全等。replay_log_reproduces_state:从 trace 重放,state hash 与 outputs 全等。- 失败路径:budget 超支、step 上限、未知 behavior。
10.5 与规格的差异
| 规格(docs/04–06) | M2 实际 | 顺延 |
|---|---|---|
| AIN net 上的 state-indexed agents | 运行时 AgentState |
M3 编译到 net |
| Join/Select/session channels | 运行时信箱 + ports map | M3 |
| Effect cell(net 节点) | 运行时 EffectBus | M3 |
| 单机多线程 + work stealing | 单线程确定性 | M3 |
| WAL + fsync + checkpoint | JSON trace 文件 | M3 |
| 文本 Ainet DSL | JSON FlowSpec |
M3 |
| 真实 LLM/HTTP/tool | mock LLM/search | M3 |
10.6 下一步(M3)
ain-lang:解析 Ainet Flow 文本 →FlowSpec;类型检查 effect/budget/端口。- Session channels:把运行时信箱降到 net wire;Join/Select;死锁检查。
- 真实 effects:LLM provider、HTTP、工具沙箱;异步/超时/取消。
- WAL/checkpoint:append-only log + 快照;崩溃恢复。
- 并行 runtime:多 worker、work stealing、原子链接(复用
ain-core)。 ain trace view:复用 Netbook 渲染器展示 flow/effect 时间线。