Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

多 Agent 编排

octos 可以同时运行多个 Agent,形态分为三种。按由谁拥有这份工作以及你何时需要结果来选择:

模型入口归属结果生命周期
子 Agentspawn 工具当前轮次的子代在本轮内返回(同步),或作为新的入站消息返回(后台)随轮次结束而销毁
对等 Agent(peer)peer_handoff 工具独立自治的会话异步返回,通过文件存活;断连时关闭
流水线(pipeline)run_pipeline 工具DOT 图工作流结构化的多节点结果每次运行

子 Agent 是函数调用;对等 Agent 是独立的协作者。本页其余部分聚焦于对等 Agent —— 持久、分离的 Agent。关于 spawn 子 Agent 的内部机制,参见架构 → 子 Agent 与对等 Agent

什么是对等 Agent

**对等 Agent(peer)**是一个自治的会话,拥有自己持久化的简报(brief)、工作区和生命周期,独立于创建它的那一轮运行。与子 Agent(当前轮次的子代、结果内联返回)不同,对等 Agent:

  • 收到一份自包含的简报,且看不到发起它的会话
  • 运行自己的 session/open + turn/start 生命周期;
  • 在轮次结束后继续存活 —— 没有逐轮自动关闭;只有在其客户端断开连接时才关闭;
  • 每一轮都在 peers/<slug>/ 下写出持久化的 result.md(外加带版本号的 result-N.mdturns.txt 索引),因此其产出可审阅、可 diff、可重新拉起。

当工作应当独立存在时使用对等 Agent —— 一次并行调研、一个长时任务、一个你会去查看的第二 Agent。当本轮需要结果来继续推理时,使用子 Agentspawn)。

对等 Agent 工具

Agent 通过五个工具与对等 Agent 交互,覆盖完整生命周期 —— 创建peer_handoff)、引导peer_send_input)、读取peer_gather)、列举peer_list)、关闭peer_close)。它们仅在网关/serve 运行时可用(一次性的 octos chat 中不可用)。

peer_handoff —— 创建对等 Agent

把工作从当前会话中提升为一个新的自治对等 Agent。

  • 参数: brief(必填,≤ 64 KB —— 对等 Agent 的全部上下文,必须自包含)、title(可选,用于生成 slug)、worktree(可选布尔 —— 在分支 peer/<slug> 上用 git worktree 隔离该对等 Agent)。
  • 行为: 完成对等 Agent 的暂存后立即返回,指向 peers/<slug>/result.md发射即忘 —— 你不会在本轮拿到结果。每轮限 4 次 handoff

peer_send_input —— 引导一个运行中的对等 Agent

向一个已打开的对等 Agent 注入一个后续轮次。

  • 参数: slug(必填)、message(必填,≤ 64 KB)。
  • 行为: 该消息作为对等 Agent 的下一个用户轮次投递,原样呈现(如同操作者亲自键入),并持久化为一条真实的用户消息。只有对等 Agent 的**发起者(originator)**可以发送输入(见护栏)。多次发送各自携带唯一的 occurrence id,因此不同消息不会被折叠,而真正的重试仍会去重。

peer_gather —— 收集结果

读取对等 Agent 的“黑板”(fan-in 汇聚)。

  • 参数: slugs(可选数组;省略则读取所有对等 Agent)。
  • 行为: 以文本返回每个指定对等 Agent 的简报与最新结果;尚未完成的对等 Agent 被标记为仍在运行。只读。这是唯一的跨对等 Agent 通道 —— 对等 Agent 之间不在带内共享上下文。

peer_list —— 查看有哪些对等 Agent

你的对等 Agent 的紧凑状态索引(peer_gather 的搭档)。

  • 参数: 无 —— 它总是列出你暂存的每一个对等 Agent。
  • 行为: 每个对等 Agent 返回一行 —— slug、状态(running 运行中 / done 已完成 / closed 已关闭)、最近更新时间、轮次数,以及是否拥有自己的 worktree。用 peer_list 查看存在哪些、哪些已完成;用 peer_gather 读取某个对等 Agent 的实际产出。只读。

peer_close —— 退役一个对等 Agent

优雅地关闭一个你创建的、运行中的对等 Agent。

  • 参数: slug(必填)。
  • 行为: 把该对等 Agent 标记为已关闭(closed)(一个持久化标记)并驱逐其活动连接,使其不再接收任何输入;随后 peer_listpeer_gather 都会报告它已关闭,peer_send_input 也会拒绝它。只有该对等 Agent 的发起者(originator)可以关闭它。这是一次优雅的退役 —— 该对等 Agent 会完成任何进行中的轮次;它不会中止正在运行的轮次 —— 其 result.md 仍可通过 peer_gather 读取。

从客户端创建与汇聚

人类通过两个服务端方法驱动对等 Agent,在 octoscode 中表现为 /peer/gather

  • peer/prepare —— 以编队方式暂存 1–8 个对等 Agent(全有或全无)。纯资源预留;随后由客户端打开每个会话并启动其首轮。
  • peer/gather —— 黑板的面向人类的一侧;把各对等 Agent 的结果汇入调用方的会话。

生命周期

  1. 暂存(Stage) —— 预留 peers/<slug>/(原子式目录占位),可选地添加 git worktree,写入 brief.md,并写下一个 originator 文件记录该对等 Agent 归属哪个会话。任何失败都会干净回滚。
  2. 通知(Notify) —— 一个持久化的 peer/staged 事件请求客户端在后台打开该对等会话。由于它是持久化的,重连会重放它;若会话已打开,客户端会去重。
  3. 打开与追踪(Open & track) —— 对等会话打开时,其活动连接被记录进一个进程级全局的对等连线注册表(peer wire registry){profile}:peer:{slug} → 活动会话,最新打开者胜出,上限 8192 条)。
  4. 运行(Run) —— 对等 Agent 运行自己的轮次,每轮写出 result.md。它在轮次结束后继续存活。
  5. 关闭(Close) —— 有两种方式。显式地,Agent 调用 peer_close(仅发起者):它写入一个持久化的 closed 标记并驱逐 wire,使该对等 Agent 不再接收任何输入 —— 这是一次优雅退役,其中进行中的轮次仍会完成。隐式地,WebSocket 断连时驱逐该 wire 映射(仅当它仍指向本会话时,从而并发的重新打开者胜出),删除会话会清除其 actor 与收件箱。

发送输入:投递路径

peer_send_input 必须触达一个运行中的对等 Agent,而它可能位于不同的连接、甚至不同的进程,因此投递不只是一次函数调用:

  1. 鉴权(Authorize) —— 调用方必须是该对等 Agent 记录的 originator;不匹配即拒绝(fail-closed 失败即拒)。
  2. 两条路径,取决于进程:
    • 网关中,消息被直接推入对等 actor 的收件箱(快路径)。
    • serve 中,该收件箱位于另一个进程,因此投递回落到一个持久化的延续队列(continuation queue):消息作为一个对等延续项入队(以唯一 occurrence id 为键)并被持久化。若持久化失败,入队会回滚,工具返回错误,而不是虚假的“已发送”。
  3. 抽取(Drain) —— 一个逐连接的抽取器大约每 2 秒运行一次,并由一个与连接无关的**全局抽取(每 5 秒)**兜底,用于无客户端连接时。延续项仅在对等 Agent 空闲时运行。
  4. 新鲜度门控(Freshness gate) —— 仅当目标仍是该 slug当前注册的 wire 时才派发注入;否则重新入队。
  5. 派发(Dispatch) —— 作为对等 Agent 的下一个用户轮次投递(原样呈现,持久化为真实用户消息)。
  6. 重新打开时的重新归位(Re-home on reopen) —— 若对等 Agent 关闭又重新打开,滞留在旧 wire 上的注入会被迁移到新 wire(崩溃安全:新的持久化记录在旧记录被退役之前写入)。
  7. 带上限的重试(Retry with a cap) —— 派发失败的消息会重新入队,但会被推进到新工作之后,因此永远不会饿死其他消息,并在 5 次尝试(约 10 秒)封顶 —— 超过上限即丢弃并记录日志,而非无限重试。

投递保证与已知限制

对等输入投递是**尽力而为、单用户(best-effort, single-user)**的。正常运行时它表现为至少一次(at-least-once),由去重折叠重试;在对抗性竞态下,它偶尔可能丢失,或(在有持久化存储时)重复一条消息。三个限制已被记录并接受:

  • 关闭-重开竞态 —— 新鲜度检查与派发并非原子,因此在一个狭窄窗口内关闭又重开的对等 Agent,可能出现一条消息被投递到正在关闭的会话(丢失),或在窗口中途崩溃时于重启后被重放(重复)。
  • 断电持久性 —— 持久化队列会 flush 到操作系统但不做 fsync,因此硬断电或内核崩溃(而非普通的进程崩溃)可能丢失最近入队的消息。这是全存储范围的性质,并非对等 Agent 特有。
  • 墓碑写入失败导致的泄漏 —— 若在重新打开时的重新归位过程中磁盘写入失败,旧记录可能持久残留(每次重启时被再次丢弃)。正常运行时它不会造成重复 —— 只是一处小泄漏。

在下述单用户模型下,这些是可接受的;要彻底关闭它们需要跨子系统的原子加锁或逐次写入的 fsync,对一个尽力而为的本地通道而言代价不成比例。

护栏、鉴权与限制

  • 深度-1(Depth-1) —— 对等 Agent 不能调用 peer_handoffpeer_send_inputpeer_close(这些工具不在对等会话上提供),因此对等 Agent 不能递归地 handoff、注入或退役其他对等 Agent。对等 Agent 可以调用 peer_gatherpeer_list(只读,无递归风险)。
  • 每轮 4 次 handoff;编队上限 1–8 个对等 Agent。
  • 仅发起者可注入(Originator-only) —— 只有创建该对等 Agent 的会话可以向它发送输入;对照对等 Agent 的 originator 文件以 fail-closed 方式强制执行。
  • 大小上限 —— 简报与注入消息均为 64 KB。
  • 单用户单配置档案的威胁模型 —— 在 serve 中,通过鉴权的身份就是该配置档案(profile),因此一个 profile 即一个用户的信任域。LLM 不能跨会话注入(其调用方身份由服务端捕获,且它无法打开会话);跨用户注入被 profile 作用域阻断。剩余情形 —— 用户有意跨越自己的多个会话 —— 被视为用户行使其自身权限,属于设计上接受的行为。不可伪造的能力(capability)模型将推迟到 serve 具备多用户身份之后再引入。