具体问题与边界
Spawn、消息投递与子 Agent 终态为什么要先解决身份、预留容量和反压,再谈并行模型循环?
AgentPool 是控制面骨架:唯一 ID、父子边、状态、resident capacity、bounded mailbox 和 final 通知;它不替子 Agent 运行 Session/ModelClient。 下面同时给出状态所有者、顺序、伪代码、故障残留和不可外推边界。
状态所有权
| 对象 | 所有者 | 生命周期 | 持久化 |
|---|---|---|---|
| AgentRecord registry | AgentPool | 根树生命周期 | Mini 仅内存 |
| agent_id/parent_id | AgentPool._create | Agent 生命周期 | 否 |
| status | AgentPool | Idle/Running/Completed/Closed | 否 |
| Mailbox Queue | 目标 AgentRecord | 直到消息消费 | 否 |
| capacity count | AgentPool | 每次 spawn 动态计算 resident | 否 |
正常路径
- Host 先 create_root,AgentPool 只允许一个 root;spawn 必须引用存在且未 closed 的 parent。
- spawn 在创建 child 之前统计非 Closed resident。达到 max_agents 就拒绝,不产生半注册子节点。
- 每个 Agent 有固定容量 Queue。send_message 校验 sender/target 后 await target.mailbox.put;满时生产者自然反压。
- receive 可永久等待或带 timeout;消息明确携带 sender_id、kind 和 text。
- child complete 先把 status 改为 Completed,再向直接父 Mailbox 发送 kind=final;重复完成或 root complete 被拒绝。
Python 风格伪代码
def spawn(parent_id, name):
parent = require_agent(parent_id)
require(parent.status != CLOSED)
resident = count(record.status != CLOSED)
if resident >= max_agents:
raise AgentCapacityError()
child = create_record(new_id(), parent_id, bounded_mailbox)
child.status = RUNNING
return child
async def send_message(sender, target, text, kind="message"):
require_agent(sender)
record = require_agent(target)
require(record.status != CLOSED)
await record.mailbox.put(MailboxMessage(sender, kind, text))
async def complete(child_id, result):
child = require_nonterminal_child(child_id)
child.status = COMPLETED
await send_message(child.id, child.parent_id, result, kind="final")
伪代码没有复制 Rust 语法;它保留了状态修改、await、取消、外部副作用和结果反馈的实际顺序。
失败、取消与恢复
| 故障点 | 残留/风险 | 处理 |
|---|---|---|
| capacity 已满 | 无 child record | AgentCapacityError |
| parent/target 不存在 | 无可解析地址 | KeyError |
| target Closed | 消息不能被消费 | 拒绝发送 |
| Mailbox 满 | 消息尚未入队 | sender await 反压 |
| 重复 complete | 可能发送两个终态 | 拒绝第二次 |
| 父 Mailbox 满时 child complete | child 已标 Completed,通知等待 | Host 必须持续 drain;这是显式成本 |
不变量
容量预留失败不能留下半注册 Agent;一个 child 只能产生一次 final;Mailbox 满时必须等待或显式失败,不能静默丢消息。
设计取舍与不能外推的结论
先复刻控制面能单独测试最危险的容量/终态问题,但不能据此声称多 Agent Runtime 完成。Mini 没有子 Session 启动、角色指令、Fork history、residency/eviction、AgentGraphStore 和崩溃恢复。
测试与复现
cd examples/mini-codex
uv run pytest -q -k 'test_agent_pool_enforces_capacity_and_delivers_child_result or test_bounded_mailbox_applies_backpressure'
uv run mypy src
uv run python benchmarks/runtime_baseline.py
test_agent_pool_enforces_capacity_and_delivers_child_resulttest_bounded_mailbox_applies_backpressure
官方源码导航
- codex-rs/core/src/agent/registry.rs:AgentRegistry、reservation、status 与拓扑
- codex-rs/core/src/agent/control.rs:共享控制面
- codex-rs/core/src/agent/control/spawn.rs:spawn transaction 与 child Session
- codex-rs/core/src/tools/handlers/multi_agents.rs:模型工具到 AgentControl 操作
- codex-rs/core/src/tools/handlers/multi_agents_common.rs:父子上下文与结果反馈
Mini Codex 对照
src/mini_codex/runtime/agents.py:AgentPool、AgentRecord、Mailbox 与 capacity
本节结论
容量预留失败不能留下半注册 Agent;一个 child 只能产生一次 final;Mailbox 满时必须等待或显式失败,不能静默丢消息。
评论
登录后即可评论