Subagent Orchestration 深入解析:多Agent协作的层级架构

当单个Agent的能力不足以应对复杂任务时,Subagent Orchestration提供了"分而治之"的解决方案------将大任务拆解为子任务,委派给专门的Subagent执行,最终聚合结果。

环境准备

本文示例代码基于以下技术栈:

组件 版本要求
JDK 17+
Spring Boot 3.2+
Spring AI 2.0.0-M3+
spring-ai-agent-utils 0.7.0

Maven依赖

xml 复制代码
<dependencies>
    <!-- Spring AI 核心 -->
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-core</artifactId>
        <version>2.0.0-M3</version>
    </dependency>
    
    <!-- Spring AI Agent Utils -->
    <dependency>
        <groupId>org.springaicommunity</groupId>
        <artifactId>spring-ai-agent-utils</artifactId>
        <version>0.7.0</version>
    </dependency>
</dependencies>

💡 关于模型名称 :本文示例中使用haikusonnetopus等模型简称,实际配置时需要使用完整模型名称如anthropic/claude-3-haikuanthropic/claude-sonnet-4anthropic/claude-opus-4等。不同提供商的模型命名规则可能不同,请根据实际使用的提供商调整。


一、核心问题:为什么需要Subagent?

1.1 单Agent的能力边界

场景:企业级代码库重构

1.2 Subagent的设计哲学

核心理念:分而治之 + 专业分工 + 结果聚合


二、架构设计详解

2.1 核心组件

2.2 SubagentConfig定义

java 复制代码
public record SubagentConfig(
    String name,                    // Subagent名称
    String description,             // 描述(供Orchestrator决策)
    String model,                   // 模型标识
    String systemPrompt,            // 系统提示词
    List<String> enabledTools,      // 启用的工具
    List<String> disabledTools,     // 禁用的工具
    int maxIterations,              // 最大迭代次数
    Map<String, String> metadata    // 元数据(可选)
) {
    public static Builder builder() {
        return new Builder();
    }
    
    public static class Builder {
        private String name;
        private String description;
        private String model = "sonnet";  // 默认模型
        private String systemPrompt = "";
        private List<String> enabledTools = List.of();
        private List<String> disabledTools = List.of();
        private int maxIterations = 50;
        private Map<String, String> metadata = Map.of();
        
        // ... setter methods
    }
}

2.3 委派流程


三、内置Subagent类型

Spring AI Agent Utils提供了四种内置Subagent:

3.1 Code Analyzer Subagent

用途:代码分析、安全审计、架构评估

java 复制代码
@Bean
public SubagentConfig codeAnalyzerSubagent() {
    return SubagentConfig.builder()
        .name("code-analyzer")
        .description("""
            代码分析专家,用于:
            - 代码质量评估
            - 安全漏洞检测
            - 架构合理性分析
            - 性能问题识别
            """)
        .model("sonnet")  // 分析任务使用高能力模型
        .systemPrompt("""
            你是一位资深代码分析师,擅长发现代码中的问题。
            
            分析原则:
            1. 先理解代码的整体结构
            2. 逐层深入分析细节
            3. 提供具体的问题位置和建议
            
            输出格式:
            ## 分析报告
            
            ### 问题列表
            | 严重程度 | 位置 | 问题描述 | 建议修复 |
            |---------|------|---------|---------|
            | ...     | ...  | ...     | ...     |
            
            ### 总体评价
            ...
            """)
        .enabledTools(List.of(
            "read_file", "search_files", "terminal"
        ))
        .maxIterations(30)
        .build();
}

3.2 Test Writer Subagent

用途:编写单元测试、集成测试

java 复制代码
@Bean
public SubagentConfig testWriterSubagent() {
    return SubagentConfig.builder()
        .name("test-writer")
        .description("测试编写专家,根据代码生成高质量测试用例")
        .model("sonnet")
        .systemPrompt("""
            你是一位测试工程师,专注于编写高质量的测试代码。
            
            测试原则:
            1. 覆盖正常路径和边界条件
            2. 每个测试只验证一个行为
            3. 使用有意义的测试名称
            4. Mock外部依赖
            
            技术栈:
            - JUnit 5
            - Mockito
            - Spring Boot Test
            
            输出要求:
            - 完整可运行的测试类
            - 包含必要的import
            - 遵循AAA模式(Arrange-Act-Assert)
            """)
        .enabledTools(List.of(
            "read_file", "write_file", "terminal"
        ))
        .maxIterations(50)
        .build();
}

3.3 Doc Generator Subagent

用途:生成API文档、README、架构文档

java 复制代码
@Bean
public SubagentConfig docGeneratorSubagent() {
    return SubagentConfig.builder()
        .name("doc-generator")
        .description("文档生成专家,根据代码生成清晰的文档")
        .model("haiku")  // 文档生成可以用更轻量的模型
        .systemPrompt("""
            你是一位技术文档撰写专家。
            
            文档原则:
            1. 结构清晰,层次分明
            2. 代码示例完整可运行
            3. 包含使用场景和注意事项
            
            Markdown格式:
            - 使用标准Markdown语法
            - 代码块指定语言
            - 表格用于参数说明
            """)
        .enabledTools(List.of(
            "read_file", "search_files", "write_file"
        ))
        .maxIterations(20)
        .build();
}

3.4 Refactor Agent Subagent

用途:代码重构、架构调整

java 复制代码
@Bean
public SubagentConfig refactorAgentSubagent() {
    return SubagentConfig.builder()
        .name("refactor-agent")
        .description("代码重构专家,负责代码结构优化和设计模式应用")
        .model("sonnet")
        .systemPrompt("""
            你是一位资深软件工程师,专注于代码重构。
            
            重构原则:
            1. 保持功能不变
            2. 小步重构,每次只改一点
            3. 确保测试通过
            4. 不破坏现有接口
            
            常用手法:
            - 提取方法
            - 提取类
            - 引入设计模式
            - 消除重复代码
            
            安全措施:
            - 重构前确认有测试覆盖
            - 每次修改后运行测试
            - 保留原始代码注释
            """)
        .enabledTools(List.of(
            "read_file", "write_file", "patch", "terminal"
        ))
        .maxIterations(100)  // 重构可能需要更多迭代
        .build();
}

四、自定义Subagent开发

4.1 创建自定义Subagent

场景:创建一个专门处理支付系统的Subagent

java 复制代码
@Configuration
public class PaymentSubagentConfig {
    
    @Bean
    public SubagentConfig paymentExpertSubagent() {
        return SubagentConfig.builder()
            .name("payment-expert")
            .description("""
                支付系统专家,处理:
                - 支付网关集成(支付宝、微信支付、Stripe)
                - 订单状态管理
                - 退款流程处理
                - 幂等性保证
                - 对账逻辑
                """)
            .model("sonnet")
            .systemPrompt(loadPromptFromResource("prompts/payment-expert.md"))
            .enabledTools(List.of(
                "read_file", "write_file", "patch", 
                "search_files", "terminal"
            ))
            .disabledTools(List.of(
                "browser_navigate", "web_search"  // 不需要网络工具
            ))
            .maxIterations(80)
            .metadata(Map.of(
                "domain", "payment",
                "expertise_level", "senior",
                "requires_review", "true"
            ))
            .build();
    }
    
    private String loadPromptFromResource(String path) {
        try {
            return new ClassPathResource(path)
                .getContentAsString(StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new RuntimeException("Failed to load prompt: " + path, e);
        }
    }
}

prompts/payment-expert.md

markdown 复制代码
# 支付系统专家

你是一位资深的支付系统工程师,有10年以上的支付领域经验。

## 核心能力

### 1. 支付网关集成
- 支付宝:熟悉即时到账、手机网站支付、当面付
- 微信支付:熟悉JSAPI、H5、Native支付
- Stripe:熟悉 Charges、PaymentIntents、Webhooks

### 2. 核心问题处理

#### 幂等性设计
所有支付操作必须保证幂等性:
```java
// 使用唯一订单号作为幂等键
@Transactional
public PaymentResult processPayment(PaymentRequest request) {
    // 检查是否已处理
    Optional<Payment> existing = paymentRepository
        .findByOrderId(request.getOrderId());
    if (existing.isPresent()) {
        return existing.get().toResult();
    }
    // 新处理...
}

状态机管理

订单状态必须严格遵循状态机:

markdown 复制代码
CREATED → PENDING → PAID → COMPLETED
                  ↘ FAILED
                  ↘ REFUNDED

3. 安全检查清单

  • 敏感信息加密存储
  • 签名验证
  • IP白名单
  • 金额校验(防止篡改)
  • 超时处理

4. 异常处理

异常类型 处理策略
网络超时 重试3次,间隔递增
余额不足 返回明确错误码
签名失败 记录日志,拒绝请求
系统异常 人工介入标记

输出规范

修改支付相关代码时:

  1. 保持幂等性
  2. 添加必要的日志
  3. 不改变现有接口签名
  4. 更新状态转换注释
java 复制代码
### 4.2 注册自定义Subagent

```java
@Configuration
public class SubagentRegistryConfig {
    
    @Bean
    public SubagentRegistry subagentRegistry(
            List<SubagentConfig> subagentConfigs) {
        SubagentRegistry registry = new SubagentRegistry();
        
        for (SubagentConfig config : subagentConfigs) {
            registry.register(config);
        }
        
        return registry;
    }
}

4.3 在Skill中引用Subagent

markdown 复制代码
---
name: payment-migration
description: 支付系统迁移专家,处理支付模块的重构和迁移
tools: [delegate_task, read_file, write_file]
---

# 支付系统迁移

## 工作流程

1. 分析现有支付模块结构
2. 使用 `delegate_task` 委派给 `payment-expert` Subagent
3. 验证迁移结果

## 委达示例

delegate_task({ "subagent": "payment-expert", "goal": "将支付宝集成从v1迁移到v3", "context": "当前代码在 src/main/java/com/example/payment/alipay/" })

markdown 复制代码
## 注意事项

- 支付相关修改必须经过 code review
- 测试覆盖率不能降低
- 保持向后兼容

五、多模型路由策略

5.1 为什么需要多模型路由?

不同任务适合不同模型:

任务类型 推荐模型 原因
简单文本处理 haiku 成本低、速度快
代码分析 sonnet 推理能力强
复杂架构设计 opus 需要深度思考
多模态处理 vision模型 支持图像输入

5.2 路由配置

java 复制代码
@Configuration
public class ModelRoutingConfig {
    
    @Bean
    public ChatModelRouter chatModelRouter(
            @Qualifier("haikuChatModel") ChatModel haikuModel,
            @Qualifier("sonnetChatModel") ChatModel sonnetModel,
            @Qualifier("opusChatModel") ChatModel opusModel) {
        
        return ChatModelRouter.builder()
            // 默认模型
            .defaultModel(sonnetModel)
            
            // 按Subagent类型路由
            .routeForSubagent("code-analyzer", opusModel)
            .routeForSubagent("test-writer", sonnetModel)
            .routeForSubagent("doc-generator", haikuModel)
            .routeForSubagent("refactor-agent", sonnetModel)
            .routeForSubagent("payment-expert", opusModel)  // 支付用高级模型
            
            // 按任务特征动态路由
            .routeByComplexity(complexity -> {
                if (complexity > 0.8) return opusModel;
                if (complexity > 0.5) return sonnetModel;
                return haikuModel;
            })
            
            .build();
    }
}

5.3 动态复杂度评估

java 复制代码
@Component
public class TaskComplexityEvaluator {
    
    /**
     * 评估任务复杂度(0-1)
     */
    public double evaluate(String goal, String context) {
        double score = 0;
        
        // 因素1:涉及文件数量
        int fileCount = countFiles(context);
        score += Math.min(fileCount / 20.0, 0.3);  // 最多贡献0.3
        
        // 因素2:关键词复杂度
        if (goal.contains("架构") || goal.contains("设计")) {
            score += 0.2;
        }
        if (goal.contains("安全") || goal.contains("加密")) {
            score += 0.2;
        }
        if (goal.contains("性能") || goal.contains("优化")) {
            score += 0.15;
        }
        
        // 因素3:预估代码行数
        int estimatedLines = estimateLines(goal);
        score += Math.min(estimatedLines / 1000.0, 0.15);
        
        return Math.min(score, 1.0);
    }
    
    private int countFiles(String context) {
        // 统计context中提到的文件数
        return (int) Pattern.compile("\\b\\w+\\.java\\b")
            .matcher(context)
            .results()
            .count();
    }
    
    private int estimateLines(String goal) {
        // 基于目标描述预估代码量
        // 简化实现,实际可用ML模型
        return goal.length() * 2;  // 粗略估计
    }
}

5.4 成本优化策略

java 复制代码
@Service
public class CostOptimizedRouter {
    
    private final ChatModelRouter baseRouter;
    private final CostTracker costTracker;
    
    /**
     * 带预算限制的路由
     */
    public ChatModel routeWithBudget(String subagentName, 
                                     String goal,
                                     double budgetRemaining) {
        
        // 获取模型成本
        Map<String, Double> modelCosts = Map.of(
            "haiku", 0.00025,   // per 1K tokens
            "sonnet", 0.003,
            "opus", 0.015
        );
        
        // 预估Token消耗
        int estimatedTokens = estimateTokens(goal);
        
        // 选择成本合适的模型
        if (budgetRemaining < modelCosts.get("haiku") * estimatedTokens / 1000) {
            throw new BudgetExceededException("预算不足");
        }
        
        // 原本应该用opus,但预算不够时降级
        ChatModel preferred = baseRouter.route(subagentName);
        String preferredName = getModelName(preferred);
        
        if (modelCosts.get(preferredName) * estimatedTokens / 1000 > budgetRemaining) {
            // 降级到更便宜的模型
            return findCheaperAlternative(preferredName, budgetRemaining, 
                                          estimatedTokens, modelCosts);
        }
        
        return preferred;
    }
}

六、与A2A和MCP集成

6.1 Subagent与A2A协议

A2A(Agent-to-Agent)协议允许Subagent作为独立服务运行:

配置远程Subagent

java 复制代码
@Bean
public SubagentConfig remotePaymentSubagent() {
    return SubagentConfig.builder()
        .name("payment-expert-remote")
        .description("远程支付系统专家服务")
        .model("remote")  // 标记为远程
        .metadata(Map.of(
            "a2a_endpoint", "https://payment-agent.example.com",
            "auth_type", "api_key",
            "timeout_seconds", "300"
        ))
        .build();
}

A2A客户端适配器

java 复制代码
public class A2ASubagentAdapter implements SubagentExecutor {
    
    private final WebClient webClient;
    private final String endpoint;
    
    @Override
    public SubagentResult execute(SubagentTask task) {
        // 构建A2A请求
        A2ATaskRequest a2aRequest = A2ATaskRequest.builder()
            .id(UUID.randomUUID().toString())
            .goal(task.goal())
            .context(task.context())
            .build();
        
        // 发送到远程服务
        A2ATaskResponse response = webClient.post()
            .uri(endpoint + "/a2a/tasks")
            .bodyValue(a2aRequest)
            .retrieve()
            .bodyToMono(A2ATaskResponse.class)
            .block(Duration.ofSeconds(300));
        
        // 转换结果
        return SubagentResult.builder()
            .success(response.status() == A2ATaskStatus.COMPLETED)
            .summary(response.result().summary())
            .artifacts(response.result().artifacts())
            .build();
    }
}

6.2 Subagent与MCP协议

MCP(Model Context Protocol)允许Subagent使用MCP Server提供的工具:

java 复制代码
@Bean
public SubagentConfig mcpEnabledSubagent() {
    return SubagentConfig.builder()
        .name("database-expert")
        .description("数据库专家,使用MCP工具操作数据库")
        .model("sonnet")
        .systemPrompt("你是一位数据库专家...")
        .enabledTools(List.of(
            "mcp:postgres:query",      // MCP Postgres工具
            "mcp:postgres:schema",     // 查看schema
            "read_file", "write_file"
        ))
        .build();
}

// MCP工具注册
@Bean
public McpClient postgresMcpClient() {
    return McpClient.builder()
        .serverUrl("http://mcp-postgres-server:8080")
        .toolPrefix("postgres")  // 工具前缀
        .build();
}

6.3 混合架构示例

七、并行执行与结果聚合

7.1 并行委派

当多个子任务相互独立时,可以并行执行:

java 复制代码
@Service
public class ParallelSubagentExecutor {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(4);
    private final SubagentRegistry registry;
    
    /**
     * 并行执行多个Subagent
     */
    public List<SubagentResult> executeParallel(
            List<SubagentTask> tasks,
            Duration timeout) {
        
        List<CompletableFuture<SubagentResult>> futures = tasks.stream()
            .map(task -> CompletableFuture.supplyAsync(
                () -> registry.execute(task),
                executor
            ))
            .collect(Collectors.toList());
        
        // 等待所有完成
        try {
            return futures.stream()
                .map(f -> f.get(timeout.toMillis(), TimeUnit.MILLISECONDS))
                .collect(Collectors.toList());
        } catch (TimeoutException e) {
            // 超时处理
            futures.forEach(f -> f.cancel(true));
            throw new SubagentTimeoutException(
                "并行执行超时: " + timeout);
        }
    }
}

7.2 并行执行的错误处理

并行执行时,错误处理比串行更复杂。需要考虑部分成功、部分失败的情况:

java 复制代码
@Component
public class FaultTolerantParallelExecutor {
    
    private final ExecutorService executor = Executors.newFixedThreadPool(4);
    private final SubagentRegistry registry;
    private final int maxRetries = 3;
    
    /**
     * 容错并行执行:部分失败不影响其他任务
     */
    public ParallelExecutionResult executeWithFaultTolerance(
            List<SubagentTask> tasks,
            Duration timeout) {
        
        // 使用CompletableFuture处理异常
        List<CompletableFuture<TaskResult>> futures = tasks.stream()
            .map(task -> CompletableFuture.supplyAsync(() -> executeTask(task), executor)
                .exceptionally(ex -> TaskResult.failed(task, ex)))
            .collect(Collectors.toList());
        
        // 等待所有完成(包括失败的)
        List<TaskResult> results = futures.stream()
            .map(f -> {
                try {
                    return f.get(timeout.toMillis(), TimeUnit.MILLISECONDS);
                } catch (Exception e) {
                    return TaskResult.failed(null, e);
                }
            })
            .collect(Collectors.toList());
        
        // 分类结果
        List<SubagentResult> successes = results.stream()
            .filter(TaskResult::isSuccess)
            .map(TaskResult::result)
            .collect(Collectors.toList());
        
        List<TaskFailure> failures = results.stream()
            .filter(TaskResult::isFailure)
            .map(TaskResult::failure)
            .collect(Collectors.toList());
        
        return new ParallelExecutionResult(successes, failures);
    }
    
    /**
     * 带重试的单任务执行
     */
    private TaskResult executeTask(SubagentTask task) {
        Exception lastException = null;
        
        for (int attempt = 1; attempt <= maxRetries; attempt++) {
            try {
                SubagentResult result = registry.execute(task);
                return TaskResult.success(task, result);
            } catch (Exception e) {
                lastException = e;
                log.warn("Subagent {} execution failed (attempt {}/{}): {}", 
                    task.subagentName(), attempt, maxRetries, e.getMessage());
                
                // 指数退避
                if (attempt < maxRetries) {
                    sleep(Duration.ofSeconds((long) Math.pow(2, attempt)));
                }
            }
        }
        
        return TaskResult.failed(task, lastException);
    }
    
    private void sleep(Duration duration) {
        try {
            Thread.sleep(duration.toMillis());
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

/**
 * 并行执行结果
 */
public record ParallelExecutionResult(
    List<SubagentResult> successes,
    List<TaskFailure> failures
) {
    public boolean allSucceeded() {
        return failures.isEmpty();
    }
    
    public double successRate() {
        int total = successes.size() + failures.size();
        return total > 0 ? (double) successes.size() / total : 0.0;
    }
}

/**
 * 任务失败记录
 */
public record TaskFailure(
    SubagentTask task,
    Exception exception,
    int attemptCount
) {}

错误处理策略对比

策略 适用场景 优点 缺点
Fail-Fast 任务间强依赖 快速发现问题 部分失败导致整体失败
Fail-Safe 任务独立 部分失败不影响全局 需要额外处理失败任务
Retry 网络抖动等临时故障 提高成功率 可能掩盖系统性问题
Circuit Breaker 远程服务调用 防止雪崩 增加延迟

配置示例

java 复制代码
@Bean
public FaultTolerantParallelExecutor parallelExecutor(SubagentRegistry registry) {
    return FaultTolerantParallelExecutor.builder()
        .registry(registry)
        .threadPoolSize(4)
        .maxRetries(3)
        .retryBackoff(Duration.ofSeconds(2))
        .timeout(Duration.ofMinutes(5))
        .failureStrategy(FailureStrategy.PARTIAL_SUCCESS)  // 继续执行
        .build();
}

7.3 结果聚合策略

java 复制代码
public interface ResultAggregator {
    String aggregate(List<SubagentResult> results);
}

// 简单拼接聚合器
@Component
public class ConcatAggregator implements ResultAggregator {
    @Override
    public String aggregate(List<SubagentResult> results) {
        return results.stream()
            .filter(SubagentResult::success)
            .map(SubagentResult::summary)
            .collect(Collectors.joining("\n\n---\n\n"));
    }
}

// 结构化聚合器
@Component
public class StructuredAggregator implements ResultAggregator {
    @Override
    public String aggregate(List<SubagentResult> results) {
        StringBuilder sb = new StringBuilder();
        sb.append("# 并行执行结果汇总\n\n");
        
        for (int i = 0; i < results.size(); i++) {
            SubagentResult result = results.get(i);
            sb.append(String.format("## 结果 %d: %s\n\n", 
                i + 1, result.subagentName()));
            sb.append(result.summary()).append("\n\n");
            
            if (!result.artifacts().isEmpty()) {
                sb.append("### 产出物\n");
                for (Artifact artifact : result.artifacts()) {
                    sb.append("- ").append(artifact.type())
                      .append(": ").append(artifact.name()).append("\n");
                }
                sb.append("\n");
            }
        }
        
        // 统计信息
        long successCount = results.stream()
            .filter(SubagentResult::success)
            .count();
        sb.append(String.format("\n**成功率**: %d/%d\n",
            successCount, results.size()));
        
        return sb.toString();
    }
}

7.3 冲突检测与解决

当多个Subagent修改同一文件时:

java 复制代码
@Component
public class ConflictDetector {
    
    public List<Conflict> detectConflicts(List<SubagentResult> results) {
        Map<String, List<SubagentResult>> fileModifications = new HashMap<>();
        
        // 收集所有文件修改
        for (SubagentResult result : results) {
            for (Artifact artifact : result.artifacts()) {
                if (artifact.type().equals("file_modification")) {
                    String filePath = artifact.path();
                    fileModifications
                        .computeIfAbsent(filePath, k -> new ArrayList<>())
                        .add(result);
                }
            }
        }
        
        // 检测冲突
        List<Conflict> conflicts = new ArrayList<>();
        for (Map.Entry<String, List<SubagentResult>> entry : 
                fileModifications.entrySet()) {
            if (entry.getValue().size() > 1) {
                conflicts.add(new Conflict(
                    entry.getKey(),
                    entry.getValue().stream()
                        .map(SubagentResult::subagentName)
                        .collect(Collectors.toList())
                ));
            }
        }
        
        return conflicts;
    }
}

// 冲突解决策略
public interface ConflictResolver {
    ResolvedModification resolve(Conflict conflict);
}

// 最新优先策略
@Component
public class LatestWinsResolver implements ConflictResolver {
    @Override
    public ResolvedModification resolve(Conflict conflict) {
        // 选择最后完成的Subagent的修改
        return conflict.results().stream()
            .max(Comparator.comparing(SubagentResult::completedAt))
            .map(r -> r.artifacts().stream()
                .filter(a -> a.path().equals(conflict.filePath()))
                .findFirst()
                .orElse(null))
            .map(a -> new ResolvedModification(conflict.filePath(), a.content()))
            .orElse(null);
    }
}

八、最佳实践与踩坑指南

8.1 常见问题

问题 原因 解决方案
Subagent递归调用 Subagent委派给自己 配置maxDepth=2防止无限递归
上下文污染 Subagent共享上下文 确保每个Subagent有独立的ChatMemory
Token超限 并行返回大量结果 使用ResultAggregator压缩输出
超时失败 Subagent执行时间过长 设置合理的timeout,添加进度回调
工具不可用 Subagent缺少必要工具 检查enabledTools配置

8.2 设计原则

1. 单一职责

每个Subagent应该专注一个明确的领域:

css 复制代码
✅ 好:payment-expert、security-auditor、test-writer
❌ 坏:general-helper、code-assistant(职责不清)

2. 适当的粒度

diff 复制代码
粒度过粗:
- full-stack-developer(太宽泛)

粒度过细:
- java-syntax-fixer
- java-import-organizer
- java-format-helper(太碎片化)

粒度适当:
- java-refactor-expert
- java-test-writer
- java-doc-generator

3. 避免循环依赖

css 复制代码
❌ 循环依赖:
Orchestrator → A → B → A(循环)

✅ 有向无环图(DAG):
Orchestrator → A → C
            → B → C

8.3 调试技巧

启用详细日志

yaml 复制代码
logging:
  level:
    org.springaicommunity.agent.subagent: DEBUG

追踪Subagent调用链

java 复制代码
@Bean
public SubagentExecutionTracer tracer() {
    return SubagentExecutionTracer.builder()
        .logToFile(true)
        .filePath("logs/subagent-trace.log")
        .includeToolCalls(true)
        .build();
}

可视化执行图

java 复制代码
@Component
public class SubagentGraphVisualizer {
    
    public String toMermaid(SubagentExecutionGraph graph) {
        StringBuilder sb = new StringBuilder();
        // 使用字符拼接避免Markdown解析问题
        sb.append("`").append("`").append("`mermaid\n");
        sb.append("graph TD\n");
        
        for (SubagentNode node : graph.nodes()) {
            sb.append(String.format("    %s[%s]\n", 
                node.id(), node.name()));
        }
        
        for (SubagentEdge edge : graph.edges()) {
            sb.append(String.format("    %s --> %s\n",
                edge.from(), edge.to()));
        }
        
        sb.append("`").append("`").append("`\n");
        return sb.toString();
    }
}

九、总结

Subagent Orchestration的核心价值:

  1. 专业分工 → 每个Subagent专注擅长领域
  2. 上下文隔离 → 避免信息过载和污染
  3. 并行执行 → 提升整体效率
  4. 可扩展性 → 易于添加新的专业能力

与其他模式的协作

模式 与Subagent的关系
Agent Skills Skill指导何时委派、委派给谁
TodoWriteTool 大任务拆分为Subagent任务
AskUserQuestionTool Subagent内部可能需要询问用户
A2A 远程Subagent通过A2A协议通信
MCP Subagent使用MCP工具扩展能力
AutoMemoryTools 保存Subagent偏好和历史结果

架构选择指南


参考资料


相关推荐
双普拉斯2 小时前
打造工业级全栈文件管理器:深度解析上传、回收站与三重下载流控技术
spring·vue·js
码农BookSea2 小时前
Hermes 深度解析:自我进化的 AI 智能体新范式
后端·ai编程
老马95272 小时前
opencode4-在已有项目中增加修改功能
java·后端·ai编程
量子位2 小时前
Mythos架构被22岁小伙“逆推”开源了!MoE和注意力借鉴DeepSeek
ai编程·deepseek
OpenTiny社区3 小时前
WebSkill —— 运行在浏览器的 Agent 技能
前端·开源·ai编程
圊妖3 小时前
Claude Code 一些进阶用法
人工智能·ai编程·claude
不恋水的雨3 小时前
手动调用spring的@Validated校验
java·spring
xxjj998a3 小时前
【Spring】Spring MVC案例
java·spring·mvc
_志哥_4 小时前
# Agent 时代的底层逻辑:Harness 即操作系统
人工智能·agent·ai编程