因此这里主要展示了如何构建一个多智能体系统

在 原作者的Python代码 里,run_subagent 函数就像一个“虫洞”,把任务传送到一个新的平行宇宙(子线程/子上下文)去执行,执行完只带回结果。

在 Java 中,我们通常通过创建新的类实例来实现这种隔离。父 Agent 和子 Agent 拥有各自独立的 messages 列表,互不干扰。

Java 实现代码

java

public class AgentWithSubAgents {
    private static final Path WORKDIR = Paths.get(System.getProperty("user.dir"));
    
    // --- 1. 工具定义 ---
    public enum ToolType {
        BASH("bash"), READ_FILE("read_file"), WRITE_FILE("write_file"), 
        EDIT_FILE("edit_file"), TASK("task"); // 新增 TASK 工具
        public final String name;
        ToolType(String name) { this.name = name; }
    }

    // ... 省略相同的 ToolExecutor 接口和基础工具注册

    // --- 2. 子 Agent 类 (核心隔离单元) ---
    public static class SubAgent {
        private final List<Map<String, Object>> messages = new ArrayList<>(); // 独立上下文
        private static final String SYSTEM_PROMPT = "You are a coding subagent. Complete the task and summarize findings.";

        // 子 Agent 只能使用基础工具,不能递归创建子 Agent
        private final List<Map<String, Object>> allowedTools = Arrays.asList(
            createToolSpec("bash", "Run shell command", "command"),
            createToolSpec("read_file", "Read file", "path"),
            createToolSpec("write_file", "Write file", "path", "content"),
            createToolSpec("edit_file", "Edit file", "path", "old_text", "new_text")
        );

        // 执行子任务
        public String executeTask(String prompt) {
            messages.clear();
            messages.add(Map.of("role", "user", "content", prompt));

            System.out.println(">>> [SubAgent] 启动子任务...");
            
            // 安全循环限制,防止死循环
            for (int i = 0; i < 30; i++) {
                Map<String, Object> response = callLLM(messages, SYSTEM_PROMPT, allowedTools);
                messages.add(response);

                if (!"tool_use".equals(response.get("stop_reason"))) {
                    break; // 任务完成
                }

                List<Map<String, Object>> results = new ArrayList<>();
                List<Map<String, Object>> content = (List<Map<String, Object>>) response.get("content");
                
                for (Map<String, Object> block : content) {
                    if ("tool_use".equals(block.get("type"))) {
                        String toolName = (String) block.get("name");
                        String toolId = (String) block.get("id");
                        Map<String, Object> inputArgs = (Map<String, Object>) block.get("input");

                        // 通过共享的 TOOL_HANDLERS 执行工具
                        ToolExecutor handler = TOOL_HANDLERS.get(toolName);
                        String output = "";
                        try {
                            output = handler != null ? handler.execute(inputArgs) : "Unknown tool";
                        } catch (Exception e) {
                            output = "Error: " + e.getMessage();
                        }
                        
                        Map<String, Object> result = new HashMap<>();
                        result.put("type", "tool_result");
                        result.put("tool_use_id", toolId);
                        result.put("content", output);
                        results.add(result);
                    }
                }
                messages.add(Map.of("role", "user", "content", results));
            }

            // 提取最终文本结果
            return extractText(response);
        }
    }

    // --- 3. 父 Agent 核心循环 ---
    // 父 Agent 拥有所有工具,包括 TASK
    private final List<Map<String, Object>> parentTools = new ArrayList<>();
    {
        // 复制基础工具
        parentTools.addAll(Arrays.asList(
            createToolSpec("bash", "Run shell command", "command"),
            createToolSpec("read_file", "Read file", "path"),
            createToolSpec("write_file", "Write file", "path", "content"),
            createToolSpec("edit_file", "Edit file", "path", "old_text", "new_text")
        ));
        // 添加 TASK 工具
        parentTools.add(createTaskToolSpec());
    }

    // 创建任务工具规格
    private static Map<String, Object> createTaskToolSpec() {
        Map<String, Object> spec = new HashMap<>();
        spec.put("name", "task");
        spec.put("description", "Spawn a subagent with fresh context.");
        
        Map<String, Object> schema = new HashMap<>();
        schema.put("type", "object");
        Map<String, Object> props = new HashMap<>();
        props.put("prompt", Map.of("type", "string", "description", "The task for the subagent"));
        props.put("description", Map.of("type", "string", "description", "Short description"));
        schema.put("properties", props);
        schema.put("required", Arrays.asList("prompt"));
        spec.put("input_schema", schema);
        return spec;
    }

    public void agentLoop(List<Map<String, Object>> messages) {
        SubAgent subAgent = new SubAgent(); // 需要时创建子 Agent

        while (true) {
            System.out.println(">>> [Parent] 思考中...");
            Map<String, Object> response = callLLM(messages, "You are a manager. Use 'task' to delegate.", parentTools);
            messages.add(response);

            if (!"tool_use".equals(response.get("stop_reason"))) return;

            List<Map<String, Object>> results = new ArrayList<>();
            List<Map<String, Object>> content = (List<Map<String, Object>>) response.get("content");

            for (Map<String, Object> block : content) {
                if ("tool_use".equals(block.get("type"))) {
                    String toolName = (String) block.get("name");
                    String toolId = (String) block.get("id");
                    Map<String, Object> inputArgs = (Map<String, Object>) block.get("input");
                    
                    String output;
                    if ("task".equals(toolName)) {
                        // 委托给子 Agent
                        String desc = (String) inputArgs.getOrDefault("description", "Subtask");
                        String prompt = (String) inputArgs.get("prompt");
                        System.out.println("> task (" + desc + "): " + prompt.substring(0, Math.min(prompt.length(), 50)));
                        output = subAgent.executeTask(prompt);
                    } else {
                        // 自己执行基础工具
                        ToolExecutor handler = TOOL_HANDLERS.get(toolName);
                        try {
                            output = handler != null ? handler.execute(inputArgs) : "Unknown tool";
                        } catch (Exception e) {
                            output = "Error: " + e.getMessage();
                        }
                    }

                    System.out.println("  Result: " + output.substring(0, Math.min(output.length(), 100)));
                    
                    Map<String, Object> result = new HashMap<>();
                    result.put("type", "tool_result");
                    result.put("tool_use_id", toolId);
                    result.put("content", output);
                    results.add(result);
                }
            }
            messages.add(Map.of("role", "user", "content", results));
        }
    }

    // --- 辅助方法 ---
    private static String extractText(Map<String, Object> response) {
        List<Map<String, Object>> content = (List<Map<String, Object>>) response.get("content");
        for (Map<String, Object> block : content) {
            if ("text".equals(block.get("type"))) return (String) block.get("text");
        }
        return "(no summary)";
    }
}

subAgent

核心思想:引入分层架构和上下文隔离,让Agent能够分解复杂任务,分配给专门的"子Agent"处理,避免上下文污染。

java

// 子 Agent 类 - 独立的执行单元
public static class SubAgent {
    private final List<Map<String, Object>> messages = new ArrayList<>(); // 独立上下文
    private static final String SYSTEM_PROMPT = "You are a coding subagent. Complete the task and summarize findings.";
    // 独立上下文:每个子任务有自己独立的消息历史
    // 系统提示:为子任务定义专门的角色,如"编码专家"
    
    // 子 Agent 只能使用基础工具,不能递归创建子 Agent
    private final List<Map<String, Object>> allowedTools = Arrays.asList(
        createToolSpec("bash", "Run shell command", "command"),
        createToolSpec("read_file", "Read file", "path"),
        // 权限控制:限制工具集,防止无限递归
    );
    
    public String executeTask(String prompt) {
        messages.clear();  // 清空历史,从零开始
        messages.add(Map.of("role", "user", "content", prompt));
        // 每次调用都是全新的上下文,避免历史干扰
        
        // 安全循环限制,防止死循环
        for (int i = 0; i < 30; i++) {  // 最多30轮
            // ... 执行子任务
        }
    }
}
  • 上下文隔离:每个子任务在干净的环境中执行,不继承父任务的上下文污染
  • 角色专业化:可以通过不同的SYSTEM_PROMPT让子Agent专注特定领域
  • 防递归保护:子Agent不能调用task工具,防止无限递归
  • 资源限制:限制最大轮数,防止死循环

任务委派:TASK 工具

核心思想:将"委派子任务"抽象为一种工具,实现任务分解和并行化

java

// 父 Agent 的工具列表
private final List<Map<String, Object>> parentTools = new ArrayList<>();
{
    // 基础工具
    parentTools.addAll(Arrays.asList(
        createToolSpec("bash", "Run shell command", "command"),
        // ... 其他基础工具
Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐