# 机队模式

机群模式是 Copilot 的一种并行编排模式，适用于可拆分为由独立子代理分别处理的工作。 在运行时研究笔记中，集群模式被描述为“运行时的内置模式，用于通过 task 工具并行调度多个子代理，并以 SQL 待办事项作为共享协调状态。” 当需要由一个父会话协调多个工作单元、收集它们的结果，并在合并后的上下文中继续对话时，可使用它。

<!-- markdownlint-disable GHD046 GHD005 -->

<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

## 何时使用机群模式

当可以在执行前分解工作，并且每个单元可以在不等待其他人的情况下运行时，机群模式非常有用。

适合的对象包括：

* 多文件重构，其中每个工作单元负责一个文件、一个包或一种语言的 SDK。
* 批量审查中，每位工作人员分别检查单独的差异、模块或告警组。
* 跨独立存储库、服务或功能区域的并行研究。
* 文档更新中，每位工作人员各自负责一个页面或主题。
* 迁移任务，其中每个工作进程都可以验证各自负责的部分并反馈结果。

以下情况避免使用车队模式：

* 步骤 2 需要步骤 1 的具体输出结果的按顺序执行的任务。
* 紧耦合的编辑方式，协作者会争用同一文件。
* 一个同步子代理或父代理可以快速完成的小任务。
* 需要持续共享推理而不是明确所有权的任务。

当父会话能够创建清晰的工作单元、为每个单元指定一名负责人，并明确每个工作方需要返回的内容时，机群模式的效果最佳。

## 正在启动舰队模式

SDK 通过会话 RPC 命名空间以多种语言公开机群模式。 该绑定在生成的 RPC 接口中仍属实验性功能；如果你的应用程序依赖它，请将 SDK 和 Copilot CLI 运行时都固定到特定版本。

### 在会话中

接线方式为 `session.fleet.start`。 可选的 `prompt` 与运行时的设备群编排指令结合。

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
const result = await session.rpc.fleet.start({
    prompt: "Refactor each SDK package independently, then summarize the changes.",
});

if (result.started) {
    console.log("Fleet mode started");
}
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```python
from copilot.rpc import FleetStartRequest

result = await session.rpc.fleet.start(
    FleetStartRequest(
        prompt="Review each service independently, then summarize the risks."
    )
)

if result.started:
    print("Fleet mode started")
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

```golang
package main

import (
    "context"
    "fmt"

    copilot "github.com/github/copilot-sdk/go"
    "github.com/github/copilot-sdk/go/rpc"
)

func main() {
    ctx := context.Background()
    client := copilot.NewClient(nil)
    session, err := client.CreateSession(ctx, &copilot.SessionConfig{})
    if err != nil {
        return
    }

    prompt := "Update each package independently, then report validation results."
    result, err := session.RPC.Fleet.Start(ctx, &rpc.FleetStartRequest{
        Prompt: &prompt,
    })
    if err != nil {
        return
    }
    if result.Started {
        fmt.Println("Fleet mode started")
    }
}
```

```golang
prompt := "Update each package independently, then report validation results."
result, err := session.RPC.Fleet.Start(ctx, &rpc.FleetStartRequest{
    Prompt: &prompt,
})
if err != nil {
    return err
}
if result.Started {
    fmt.Println("Fleet mode started")
}
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

```csharp
using GitHub.Copilot;

await using var client = new CopilotClient();
await using var session = await client.CreateSessionAsync(new SessionConfig());

var result = await session.Rpc.Fleet.StartAsync(
    "Audit each project independently, then summarize the findings.");

if (result.Started)
{
    Console.WriteLine("Fleet mode started");
}
```

```csharp
var result = await session.Rpc.Fleet.StartAsync(
    "Audit each project independently, then summarize the findings.");

if (result.Started)
{
    Console.WriteLine("Fleet mode started");
}
```

</div>

<div class="ghd-codetab" data-lang="rust" data-label="Rust"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Rust</div>

```rust
use github_copilot_sdk::rpc::FleetStartRequest;

let result = session
    .rpc()
    .fleet()
    .start(FleetStartRequest {
        prompt: Some("Research each crate independently, then summarize the plan.".into()),
    })
    .await?;

if result.started {
    println!("Fleet mode started");
}
```

</div>

</div>

机群模式的原生类型绑定已在 Node.js/TypeScript、Python、Go、.NET 和 Rust 中得到验证。 此分支上的 `java/src/main/java` 中找不到Java绑定，因此在该图面可用之前，将省略Java示例。

### 从计划模式

计划模式界面可以通过返回 `autopilot_fleet` 退出操作来启动集群部署。 生成的会话事件类型将其描述为：

```typescript
type PlanModeExitAction =
  | "exit_only"
  | "interactive"
  | "autopilot"
  /** Exit plan mode and continue with parallel autonomous workers. */
  | "autopilot_fleet";
```

当用户批准已包含独立工作项的计划时，请使用此功能。 对于单个自主工作单元，使用 `autopilot`；当需要用户参与其中时，使用 `interactive`。

## 子代理如何协调

机群模式依赖于显式协调状态，而不是隐式共享内存。 父代理将工作分解为 todos，每个子代理拥有一个待办事项，业务流程协调程序会调度其依赖项已经完成的辅助角色。

规范架构为：

```sql
CREATE TABLE todos (
    id TEXT PRIMARY KEY,
    title TEXT NOT NULL,
    description TEXT,
    status TEXT DEFAULT 'pending'
);

CREATE TABLE todo_deps (
    todo_id TEXT,
    depends_on TEXT,
    PRIMARY KEY (todo_id, depends_on)
);
```

每个待办事项都通过小型状态机移动：

```text
pending -> in_progress -> done
                       \-> blocked
```

子代理应：

1. 通过设置 `status = 'in_progress'`声明完全相同的待办事项。
2. 仅处理该待办事项范围内的内容。
3. 将其结果存储在对话或相关任务输出中。
4. 完成后设置 `status = 'done'` 。
5. 在无法继续时设置 `status = 'blocked'` ，并包括原因。

协调器可以通过如下查询找到其依赖项已满足的任务：

```sql
SELECT t.*
FROM todos t
WHERE t.status = 'pending'
  AND NOT EXISTS (
      SELECT 1
      FROM todo_deps td
      JOIN todos dep ON td.depends_on = dep.id
      WHERE td.todo_id = t.id
        AND dep.status != 'done'
  );
```

这种模式为每个工作单元明确指定了负责人，并使父会话能够判断哪些处于就绪、运行中、已完成或被阻塞状态。

## 生命周期挂钩

机群模式通过运行时的任务机制调用子代理。 运行时会针对子代理工具调用发出 hook 活动：运行时 1.0.52 的更新日志指出，`preToolUse`、`postToolUse`、`subagentStart` 和 `subagentStop` 都会针对子代理工具调用正确触发。

在此分支的公开 SDK 接口中，未找到针对 `subagentStart` 或 `subagentStop` 的专用 SDK 钩子回调。 SDK 用户可以通过通用会话事件流观察子代理活动，其中包括诸如 `subagent.started`、`subagent.completed`、`subagent.failed`、`subagent.selected` 和 `subagent.deselected` 等事件。

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

```typescript
session.on((event) => {
    if (event.type === "subagent.started") {
        console.log(`Started ${event.data.agentDisplayName}`);
    }

    if (event.type === "subagent.completed") {
        console.log(`Completed ${event.data.agentDisplayName}`);
    }
});
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

```python
import asyncio
from copilot import CopilotClient
from copilot.session import PermissionHandler

async def main():
    client = CopilotClient()
    await client.start()
    session = await client.create_session(
        on_permission_request=PermissionHandler.approve_all,
    )

    def handle_event(event):
        if event.type == "subagent.started":
            print(f"Started {event.data.agent_display_name}")
        elif event.type == "subagent.completed":
            print(f"Completed {event.data.agent_display_name}")

    unsubscribe = session.on(handle_event)

asyncio.run(main())
```

```python
def handle_event(event):
    if event.type == "subagent.started":
        print(f"Started {event.data.agent_display_name}")
    elif event.type == "subagent.completed":
        print(f"Completed {event.data.agent_display_name}")

unsubscribe = session.on(handle_event)
```

</div>

</div>

有关已在 SDK 层公开的挂钩配置，请参阅 [使用挂钩](/zh/copilot/how-tos/copilot-sdk/features/hooks)。 有关子代理事件负载，请参阅 [自定义代理和子代理编排](/zh/copilot/how-tos/copilot-sdk/features/custom-agents)。

## 插件子代理

运行时可以通过 `--plugin-dir` 加载插件。 以这种方式加载的插件可以在提示词模式下将其代理注册为可用的`task(agent_type=...)`子代理类型，这意味着集群模式可以将任务分派给这些插件提供的工作器类型。

这目前是一种运行时层面的配置方式，而不是有文档说明的 SDK 层面的注册 API。 使用插件目录配置 Copilot CLI 运行时，然后将 SDK 客户端连接到该运行时。 将来可能会添加用于注册插件子代理类型的本机 SDK 帮助程序。

在概念层面上，这样一来，fleet 提示词便可以请求特定的工作器类型：

```text
Use task(agent_type="security-review") for each independent package.
Run the workers in parallel and summarize only high-confidence findings.
```

使插件提供的子代理类型保持窄和描述性，以便业务流程协调程序能够可靠地选择它们。

## 最佳做法

* 在启动机群模式之前，将工作分解为独立单位。
* 尽量减少待办事项之间的依赖关系；依赖关系会降低并行性。
* 为每个待办事项设置持久标识符、清晰的标题和完整的描述。
* 让每个子代理在同一时间只负责一个待办事项。
* 使用后台子代理实现真正的并行处理。
* 对序列化的步骤或验证入口使用同步子代理调用。
* 为每个子代理提供完整的上下文；子代理在调用之间不保留状态。
* 在每个工作代理提示中包含文件路径、命令、预期输出和约束。
* 不要派发单个后台子代理；应优先使用同步调用，或并行批量调度多个工作器。
* 除非父代理会明确解决冲突，否则应避免将相互重叠的文件分配给不同的工作代理。
* 要求每个工作者报告其更改了哪些内容、如何验证这些更改，以及哪些事项仍然受阻。
* 让父代理在工作代理完成后对合并后的结果进行验证。

## 限制和开放问题

* 机群模式通过生成的会话 RPC 绑定公开，并在多个 SDK 中标记为实验性。
* SQL todos 模式是运行时指南中的规范协调模型，但它是否是 SDK 使用者的稳定扩展性协定仍然是一个悬而未决的问题。
* `subagentStart` 和 `subagentStop` 是运行时钩子名称；该分支通过通用会话事件流（而非专用钩子回调）向 SDK 使用者暴露子代理的生命周期。
* 插件子代理注册是通过 `--plugin-dir`运行时层配置的;在此分支上未验证 SDK 级插件注册帮助程序。
* 在此分支的 Java SDK 源代码中未找到 `session.fleet.start` 的 Java 原生类型绑定。
* 机队模式不会消除父代理评审的需要。 并行工作器可能会产生不一致的假设，而这需要由协调器进行调和。

## 另请参阅

* [自定义代理和子代理编排](/zh/copilot/how-tos/copilot-sdk/features/custom-agents)
* [使用挂钩](/zh/copilot/how-tos/copilot-sdk/features/hooks)