Skip to content

Agent Teams 是一项实验性协调能力,把一个编码会话变成一个小型工作团队:会话的 agent 成为 Lead(负责人),为委派的工作创建具名队友,与他们交换持久消息,并在共同的任务板上跟踪共享任务。成员名册、邮箱与任务状态都从 Lead 的会话日志重放得出,因此能在崩溃、重载与中断后存活。整个特性位于 experimental 包组:它被排除在官方发布与 npm 发布之外,不提供任何稳定性承诺,并且默认禁用——没有任何已发布的 bundle 接入它。

包角色ctx key
packages/experimental/agent-team服务定义:以 Lead 会话日志为后端的持久名册、邮箱与任务板ctx.agentTeams
packages/experimental/tool-agent-team用于创建、通信与协调队友的十个模型工具在 ctx.tools 上注册 scoped 工具
packages/experimental/agent-team-profile基于 dsh-base 的显式源码检出配置层(profile layer)—
packages/experimental/agent-team-web-profile用于 Host Team 配置的显式源码检出 Web 层—
packages/experimental/client-ui-agent-teamWeb 端的团队名册、任务板与队友导航—

这里的一切都是源码检出原型,不属于任何官方发布载荷。放置与发布排除的理由记录在 .agents/notes/implemented/architecture/2026-08-18-experimental-agent-teams-packages.md 中;docs/subsystems/agent-team.md 子系统参考拥有持久类型与服务 API。

团队领域 ​

每个普通运行时根都是某个团队的隐式 Lead,其 TeamId 等于它的 SessionId——没有创建事件,持久状态从第一条成员、消息或任务记录开始。Lead 以唯一的小写名称(如 reviewer)创建具名队友;队友可以全新开始(没有 Lead 历史),也可以作为继承 Lead 已完成轮次的 fork 开始。名称是永久的:即使创建失败的队友也保留其名称,任何名称都不会被复用。

名册显示每个成员的角色(lead 或 teammate)与当前状态——running、idle、inactive(存在但未加载)、provisioning 或 failed。只有 Lead 能创建队友或中断他们。

持久事件 ​

团队事件被追加到确切的实时 Lead 会话,并在操作报告成功或唤醒等待者之前 flush。共有恰好四个可变事件类型,全部仅写日志——它们绝不进入对话表面,因此派生模型历史不受协调记录影响:

ts
type MutableTeamEventType =
  | 'team/member'            // 每次队友生命周期变更
  | 'team/task'              // 每次 CAS 任务变更
  | 'team/message/queued'    // 消息已持久存入 Lead 日志
  | 'team/message/delivered' // 目标回执已被确认

会话事件的 seq 与 time 负责排序与时序;Team 快照不重复它们。一个 invariant 伴件(packages/experimental/agent-team/src/invariant.ts)会在追加前把每个候选 Team 事件对其已提交前缀重放,并拒绝非法转换。

状态是重放出来的,从不单独存储 ​

Lead 会话日志是唯一事实来源。foldTeam() 把一个根会话重放成名册、任务板以及每个 Team 操作读取的 queued-minus-delivered 邮箱。它按 TeamId 选择记录,因此普通 fork 继承的事件保留祖先 id,绝不进入新根的状态。这正是该特性能在崩溃与重载后存活的机制:

team/member, team/task, team/message/*  (追加 + flush 到 Lead 会话日志)
        │
        └── foldTeam(root Session) ──► 名册 ──► 任务板 ──► queued-minus-delivered 邮箱
                                      (每次读取都是一次重放)

没有持久会话存储,事件就无处落地,所以团队特性需要持久会话存储才能激活。最小的可运行配置是持久存储加上两个 Team 包:

yaml
# smallest team setup — durable storage plus both Team packages
- name: '@deepseek-ai/dsh-session-persistence-jsonl'
- name: '@deepseek-ai/dsh-experimental-agent-team'
- name: '@deepseek-ai/dsh-experimental-tool-agent-team'

服务:TeamService ​

TeamService(ctx.agentTeams,见 packages/experimental/agent-team/src/index.ts)是 Host 侧领域服务。每个方法都取确切的实时调用 Agent 作为权威凭据;只有 Lead 能 spawn、重新指派或中断:

ts
membership(agent: Agent): TeamMembership
listMembers(agent: Agent): TeamMemberView[]
spawnTeammate(caller: Agent, request: SpawnTeammateRequest): Promise<SpawnTeammateResult>
sendMessage(caller: Agent, request: SendTeamMessageRequest): Promise<SendTeamMessageResult>
createTask(caller: Agent, request: CreateTeamTaskRequest): Promise<TeamTaskView>
getTask(caller: Agent, id: TeamTaskId): TeamTaskView
listTasks(caller: Agent): TeamTaskView[]
updateTask(caller: Agent, request: UpdateTeamTaskRequest): Promise<TeamTaskView>
waitForChange(caller: Agent, timeoutMs: number, signal: AbortSignal): Promise<TeamWaitResult>
interrupt(caller: Agent, targetName: string): { previousStatus: 'running' | 'idle' | 'inactive' }

持久邮箱 ​

发出的消息首先作为 team/message/queued 追加到 Lead 会话,并在尝试投递之前 flush,因此 queued 结果已经安全落盘,绝不能重发。两种投递模式覆盖两种意图:quiet 消息(send_message)传递信息但不唤醒空闲队友,而follow-up(followup_task)让该消息成为接收者的下一轮。目标消息以 Team message <id> from <name>: 开头,并在 TeamMessageSource 中保留相同的 id 与发送者。只有在目标会话把消息身份持久保存在其 pending inbox 或已记录历史中之后,回执才以 team/message/delivered 确认。投递在重试前会合并目标侧实时与已持久化的 inbox/history 状态,因此 inbox 接受与模型认领之间的崩溃不会重复消息——这是进程内重试加上目标会话去重,而非跨进程 exactly-once 投递。

共享任务板 ​

任务是完整的带版本快照(TeamTaskSnapshot),带数字 task-<n> id、每次变更递增的 revision、可选的 blockedBy 边(指向未删除任务且保持无环),以及咨询性的 writeScopes——归一化的工作区相对路径前缀,绝非锁:

ts
interface TeamTaskSnapshot {
  readonly id: TeamTaskId
  readonly revision: number
  readonly subject: string
  readonly description: string
  readonly status: TeamTaskStatus        // pending | in_progress | completed | deleted
  readonly ownerId?: SessionId
  readonly blockedBy: TeamTaskId[]
  readonly writeScopes: string[]
}

每次变更都是比较并交换(compare-and-set):它携带 expectedRevision,过期调用方会收到 TEAM_TASK_STALE_REVISION 而不是覆盖更新的值。任务只有在其全部依赖完成时才可认领。两个进行中任务之间的文件提示重叠会产生警告,绝不阻塞。已删除任务作为 tombstone 保留以支持重放与 id 稳定,但会从活动列表中消失。

工具:十个 Team 操作 ​

@deepseek-ai/dsh-experimental-tool-agent-team 在每位实时 Team 成员的确切 Agent 作用域内注册完整工具集(见 packages/experimental/tool-agent-team/src/index.ts),外加一个 team:policy 系统提示词小节,其排序位于 TEAM_POLICY 槽位(packages/core/system-prompt/src/index.ts 中顺序为 600):

工具操作
spawn_teammate仅 Lead:创建一个具名、持久的队友(fresh 或 fork 上下文)
send_message向另一成员发送 quiet 持久消息,不唤醒空闲成员
followup_task需要时启动目标轮次的持久后续任务
list_agents列出 Lead 与每个持久队友及其当前运行时状态
wait_agent等待下一个队友状态、邮箱或任务变更(10 秒至 1 小时)
interrupt_agent仅 Lead:中断队友当前轮次,保留其 pending inbox
team_task_create在共享板上创建一个无主 pending 任务
team_task_update使用最新 revision 对任务执行 CAS 动作
team_task_get读取一个任务的完整最新值
team_task_list以状态/所有者/就绪过滤器与游标列出共享任务

TEAM_POLICY 小节(顺序 600)告诉模型如何在团队中行事:共享工作目录、咨询性写作用域、FS_STALE_VERSION 重定基、quiet 与 follow-up 消息的区别,以及 Lead 必须在给出最终答案前等待必需队友的规则。

已知限制 ​

以下是当前包的约束,如实列出——不是与其他协调机制的对比:

  • 单一进程与单一共享检出——成员共享 cwd 并立即看到彼此的编辑;没有 worktree、远程成员、merge 或文件系统锁。
  • 咨询性写作用域——Bash、格式化器、代码生成器与直接的外部写入者可以绕过文件系统版本检查;Lead 必须协调所有权并审查最终 diff。
  • 扁平且不可变的名册——只有 Lead 创建直接队友;没有嵌套团队、重命名、删除或名称复用。
  • 不会自动释放任务所有权——空闲、中断、进程退出与失败的工作都不会释放任务所有者。
  • 邮箱不是跨进程 exactly-once——不支持多个 harness 进程并发操作同一个团队;保证是进程内重试加目标会话去重。
  • 需要持久会话存储才能激活——团队事件必须落入持久化的 Lead 会话日志,并且该特性未接入任何已发布 bundle。

包 ​

包
@deepseek-ai/dsh-experimental-agent-team
@deepseek-ai/dsh-experimental-tool-agent-team
@deepseek-ai/dsh-experimental-agent-team-profile
@deepseek-ai/dsh-experimental-agent-team-web-profile
@deepseek-ai/dsh-experimental-client-ui-agent-team

延伸阅读 ​

  • packages/experimental/README.md——实验包组地图与发布排除
  • packages/experimental/agent-team/README.md——操作、授权、恢复与限制行为
  • packages/experimental/tool-agent-team/README.md——模型工具表面
  • docs/subsystems/agent-team.md——持久 Team 类型与 ctx.agentTeams 服务 API
  • packages/experimental/agent-team/src/types.ts——TeamMemberSnapshot、TeamMessageSnapshot、TeamTaskSnapshot