free-code-dotnet/docs/核心模块设计/核心模块设计-多代理协调.md
应文浩wenhao.ying@xiaobao100.com e25ac591a7 init easy-code
2026-04-06 07:24:24 +08:00

10 KiB
Raw Blame History

核心模块设计 — 多代理协调器 (Coordinator)

所属项目: free-code .NET 10 重写
文档类型: 核心模块设计
原始代码来源: ../../src/coordinator/../../src/assistant/
原始设计意图: 将单轮 LLM 交互扩展为多代理编排,负责 worker 生成、消息路由、团队管理与协调模式切换
上级文档: 核心模块设计总览
交叉参考: 工具系统 | 后台任务管理


概述

多代理协调器是 free-code 中用于“把工作拆给多个 worker”的编排层。它不是简单的工具调用器而是面向复杂任务的调度中枢当用户问题可被拆分为研究、实现、验证等多个并行分支时协调器负责创建 worker、下发上下文、接收回传结果并在需要时继续同一 worker 的上下文。

原始源码中,../../src/coordinator/coordinatorMode.ts 承担了本模块的核心语义:定义 coordinator mode 的开关、worker 可用工具集合、系统提示词、session mode 匹配逻辑,以及 worker 结果的消息协议。../../src/assistant/ 则提供与会话历史、会话筛选和辅助选择相关的配套能力,可视为协调器在“恢复旧会话”和“读取历史事件”场景下的支撑模块。

在 .NET 10 重写中,本模块应被抽象为独立服务层,避免与 QueryEngine、工具系统、后台任务管理直接耦合同时保留原有行为

  • 允许 coordinator 生成 worker 并并发分发任务
  • 允许 worker 通过消息队列继续执行
  • 允许在会话恢复时自动匹配 coordinator/normal 模式
  • 允许读取会话历史以重建协作上下文

设计职责

1. 多代理任务编排

协调器负责将一个高层目标拆解为多个子任务,并为每个子任务创建独立 worker。worker 适合执行以下类型工作:

  • 代码库研究
  • 定向实现
  • 验证与测试
  • 失败修复

2. worker 生命周期管理

协调器需掌握 worker 的创建、继续、停止与结果归档。worker 不是一次性调用;其价值在于保留已加载上下文后继续推进。

3. 代理间消息路由

worker 的结果以结构化任务通知返回,协调器再据此向用户总结,或把后续指令发回同一个 worker。

4. 团队协作管理

协调器支持 team create / delete / send-message 这类“代理团队”操作,用于将多个 worker 视为一个协作单元管理。

5. 会话模式同步

当用户恢复旧会话时,协调器需要根据保存的 session mode 自动切换当前环境变量,确保继续运行时处于正确的 coordinator/normal 模式。


原始实现要点

../../src/coordinator/coordinatorMode.ts

该文件是本模块的语义核心,包含以下能力:

coordinator 模式开关

isCoordinatorMode() 通过 feature gate COORDINATOR_MODE 和环境变量 CLAUDE_CODE_COORDINATOR_MODE 判断当前是否进入协调模式。

会话模式匹配

matchSessionMode(sessionMode) 会比较当前模式与已恢复会话记录的模式:

  • 若一致,直接返回
  • 若不一致,自动翻转环境变量
  • 同时记录 analytics 事件

这说明 coordinator 是“会话状态敏感”的,而不是一个纯工具注册器。

worker 工具上下文

getCoordinatorUserContext(mcpClients, scratchpadDir) 会为 worker 注入可用工具说明:

  • 简化模式下仅暴露 Bash / Read / Edit
  • 常规模式下暴露 async agent 允许工具集
  • 追加 MCP 服务名
  • 在 scratchpad gate 开启时暴露 scratchpad 目录

coordinator 系统提示词

getCoordinatorSystemPrompt() 描述了 coordinator 的核心职责:

  • 直接回答能答的问题
  • 用 worker 处理适合并行化的工作
  • 只能把新信息总结给用户,不能把 worker 当作对话对象
  • 通过 AgentSendMessageTaskStop 管理 worker 生命周期

同时它还明确了 worker 结果的 <task-notification> 协议格式。

../../src/coordinator/workerAgent.ts

当前快照中该文件为占位实现,但从模块命名可知,它原本承载 worker agent 的启动入口或 worker 代理适配层。在 .NET 重写里,这一职责应由 worker 启动器与任务执行器拆分承接。

../../src/assistant/*

../../src/assistant/sessionHistory.ts 提供了会话事件分页读取:

  • 先构造 OAuth 请求上下文
  • 再按 anchor_to_latest / before_id 拉取分页事件
  • 返回历史事件、游标与是否还有更旧内容

sessionDiscovery.tsgate.tsindex.tsAssistantSessionChooser.tsx 在本快照中多为占位或轻量 UI 适配,但它们体现出 assistant 模块的定位:用于发现、筛选、恢复与展示历史会话。


.NET 10 接口设计

ICoordinatorService

public interface ICoordinatorService
{
    bool IsCoordinatorMode { get; }

    string? MatchSessionMode(SessionMode? sessionMode);

    string BuildCoordinatorSystemPrompt(CoordinatorPromptContext context);

    CoordinatorUserContext BuildWorkerContext(
        IReadOnlyList<McpClientDescriptor> mcpClients,
        string? scratchpadDirectory = null);

    Task<WorkerHandle> SpawnWorkerAsync(
        SpawnWorkerRequest request,
        CancellationToken cancellationToken = default);

    Task SendMessageAsync(
        string workerId,
        string message,
        CancellationToken cancellationToken = default);

    Task StopWorkerAsync(
        string workerId,
        CancellationToken cancellationToken = default);

    Task<WorkerResult?> GetWorkerResultAsync(string workerId);

    Task<TeamHandle> CreateTeamAsync(CreateTeamRequest request,
        CancellationToken cancellationToken = default);

    Task DeleteTeamAsync(string teamId,
        CancellationToken cancellationToken = default);

    Task SendTeamMessageAsync(string teamId, string message,
        CancellationToken cancellationToken = default);
}

IAgentWorker

public interface IAgentWorker
{
    string WorkerId { get; }
    string Description { get; }
    WorkerStatus Status { get; }

    Task StartAsync(CancellationToken cancellationToken);
    Task ContinueAsync(string message, CancellationToken cancellationToken);
    Task StopAsync(CancellationToken cancellationToken);
    Task<WorkerSnapshot> CaptureSnapshotAsync();
}

支撑模型

public enum SessionMode { Normal, Coordinator }

public sealed record CoordinatorPromptContext(
    string WorkingDirectory,
    string? ScratchpadDirectory,
    IReadOnlyList<string> AllowedTools,
    IReadOnlyList<string> McpServerNames);

public sealed record CoordinatorUserContext(
    string WorkerToolsContext,
    string SystemPrompt);

public sealed record SpawnWorkerRequest(
    string Description,
    string Prompt,
    string WorkerType,
    string? Model = null,
    string? TeamId = null);

这些类型遵循 .NET 命名习惯,使用 PascalCase并把“提示词构建”和“worker 运行实例”分离,避免协调器直接依赖底层 LLM 调用细节。


Worker 生成与生命周期

生成流程

  1. 协调器接收高层目标
  2. 判断是否适合并行拆分
  3. 为每个分支构造自包含 prompt
  4. 通过 worker 工厂创建 IAgentWorker
  5. 记录 worker 到会话/任务存储

生命周期阶段

阶段 说明
Created worker 已创建但未启动
Running worker 正在执行
Waiting worker 暂停等待继续指令
Completed worker 已完成任务
Failed worker 执行失败
Stopped worker 被协调器主动停止

生命周期原则

  • worker 应保留自己的上下文快照
  • 继续 worker 时优先复用旧上下文,而不是重新启动新 worker
  • 停止 worker 应保留最后状态,供后续诊断或继续执行

消息路由

结果回传协议

原始实现定义了 <task-notification> XML 作为 worker 结果消息格式。.NET 重写可保留相同语义,但建议使用结构化模型解析后再渲染给终端:

public sealed record WorkerNotification(
    string TaskId,
    string Status,
    string Summary,
    string? Result,
    WorkerUsage? Usage);

路由规则

  • worker → coordinator上报任务完成、失败、暂停、进度
  • coordinator → worker发送续作指令、修正指令、停止指令
  • coordinator → 用户:仅输出总结,不暴露内部通知原文

设计约束

  • 不能用一个 worker 检查另一个 worker
  • 不能把低价值文件内容回读任务交给 worker
  • 继续 worker 时必须使用其原始 task id

Agent Team 管理

team 机制用于把多个 worker 归入一个协作单元,常见场景是“研究组 + 实现组 + 验证组”。

TeamCreate

创建 team 时应生成团队 ID并维护成员 worker、目标、状态与消息历史。

TeamDelete

删除 team 应清理团队元数据,但不能无条件销毁已完成 worker 的结果记录。

SendMessage

team message 应广播到 team 成员,或按策略路由给主 worker。 .NET 设计应把广播规则显式化,避免隐式分支。


关联 ../../src/assistant/ 的 .NET 设计

../../src/assistant/ 更适合映射为“会话访问与恢复辅助服务”,建议拆为:

  • IAssistantSessionHistoryService:读取会话事件分页
  • IAssistantSessionDiscoveryService:发现可恢复会话
  • IAssistantSessionChooser:会话选择 UI 适配层

其中 sessionHistory.ts 的分页逻辑适合直接迁移为可测试的基础设施服务,而非放进协调器主服务中。


设计要点

  • coordinator 是编排层,不是 worker 执行层
  • worker 适合做局部自治coordinator 负责全局收敛
  • 会话模式必须可恢复、可切换、可记录
  • worker prompt 必须自包含,不能依赖隐式上下文
  • 协调器输出面向用户,内部通知面向系统

参考资料