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偏好和历史结果

架构选择指南


参考资料


相关推荐
飞哥数智坊16 分钟前
我给 DeepSeek 看了两次截图,才发现 Vision 真正的价值
人工智能·ai编程·deepseek
IT 行者1 小时前
用 HiddenHttpMethodFilter 解决浏览器不支持 PUT/DELETE/PATCH 的问题
java·spring
有来技术8 小时前
开源项目维护者的自救:用 TRAE Work 造了个 Issue 集结号
ai编程
城管不管10 小时前
重生——第十一次面试之挖财一面2026.8.19已OC
java·服务器·jvm·数据库·spring·面试·职场和发展
小虎AI生活11 小时前
手把手:把 Remotion 封装成 DeepSeek Harness 插件,一句话让 AI 出视频
ai编程
亚历克斯神14 小时前
智能搜索系统的升级复盘——从 Elasticsearch 到混合检索的检索质量提升
java·spring·微服务
stormzhangV15 小时前
这个本地模型,让我 token 自由了
人工智能·ai编程·claude
全栈弄潮儿15 小时前
让 AI 帮你拆分一个功能需求:页面、接口、数据和测试任务怎么分
aigc·openai·ai编程
m0_5873830017 小时前
社区家政系统开发实战:从需求分析到上线部署全指南
java·spring boot·spring·需求分析
松小鼠呀18 小时前
我不敢再生孩子:ChatGPT 曾花 $2m 让他闭嘴,AI 巨头到底隐藏了什么秘密?
人工智能·安全·chatgpt·ai编程·科技热点