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-team | Web 端的团队名册、任务板与队友导航 | — |
这里的一切都是源码检出原型,不属于任何官方发布载荷。放置与发布排除的理由记录在 .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。共有恰好四个可变事件类型,全部仅写日志——它们绝不进入对话表面,因此派生模型历史不受协调记录影响:
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 包:
# 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、重新指派或中断:
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——归一化的工作区相对路径前缀,绝非锁:
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服务 APIpackages/experimental/agent-team/src/types.ts——TeamMemberSnapshot、TeamMessageSnapshot、TeamTaskSnapshot