古龙橙子味 發表於 2026-4-12 09:00:00

【从0到1构建一个ClaudeAgent】规划与协调-子Agent

<p>子任务污染主对话上下文怎么办?</p>
<p>因此这里主要展示了如何构建一个<strong>多智能体系统</strong>。</p>
<p>在 原作者的Python代码 里,<code>run_subagent</code>&nbsp;函数就像一个“虫洞”,把任务传送到一个新的平行宇宙(子线程/子上下文)去执行,执行完只带回结果。</p>
<p>在 Java 中,我们通常通过<strong>创建新的类实例</strong>来实现这种隔离。父 Agent 和子 Agent 拥有各自独立的&nbsp;<code>messages</code>&nbsp;列表,互不干扰。</p>
<h2 id="java-实现代码">Java 实现代码</h2>
<pre><code class="language-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&lt;Map&lt;String, Object&gt;&gt; messages = new ArrayList&lt;&gt;(); // 独立上下文
      private static final String SYSTEM_PROMPT = "You are a coding subagent. Complete the task and summarize findings.";

      // 子 Agent 只能使用基础工具,不能递归创建子 Agent
      private final List&lt;Map&lt;String, Object&gt;&gt; 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("&gt;&gt;&gt; 启动子任务...");
            
            // 安全循环限制,防止死循环
            for (int i = 0; i &lt; 30; i++) {
                Map&lt;String, Object&gt; response = callLLM(messages, SYSTEM_PROMPT, allowedTools);
                messages.add(response);

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

                List&lt;Map&lt;String, Object&gt;&gt; results = new ArrayList&lt;&gt;();
                List&lt;Map&lt;String, Object&gt;&gt; content = (List&lt;Map&lt;String, Object&gt;&gt;) response.get("content");
               
                for (Map&lt;String, Object&gt; block : content) {
                  if ("tool_use".equals(block.get("type"))) {
                        String toolName = (String) block.get("name");
                        String toolId = (String) block.get("id");
                        Map&lt;String, Object&gt; inputArgs = (Map&lt;String, Object&gt;) 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&lt;String, Object&gt; result = new HashMap&lt;&gt;();
                        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&lt;Map&lt;String, Object&gt;&gt; parentTools = new ArrayList&lt;&gt;();
    {
      // 复制基础工具
      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&lt;String, Object&gt; createTaskToolSpec() {
      Map&lt;String, Object&gt; spec = new HashMap&lt;&gt;();
      spec.put("name", "task");
      spec.put("description", "Spawn a subagent with fresh context.");
      
      Map&lt;String, Object&gt; schema = new HashMap&lt;&gt;();
      schema.put("type", "object");
      Map&lt;String, Object&gt; props = new HashMap&lt;&gt;();
      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&lt;Map&lt;String, Object&gt;&gt; messages) {
      SubAgent subAgent = new SubAgent(); // 需要时创建子 Agent

      while (true) {
            System.out.println("&gt;&gt;&gt; 思考中...");
            Map&lt;String, Object&gt; 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&lt;Map&lt;String, Object&gt;&gt; results = new ArrayList&lt;&gt;();
            List&lt;Map&lt;String, Object&gt;&gt; content = (List&lt;Map&lt;String, Object&gt;&gt;) response.get("content");

            for (Map&lt;String, Object&gt; block : content) {
                if ("tool_use".equals(block.get("type"))) {
                  String toolName = (String) block.get("name");
                  String toolId = (String) block.get("id");
                  Map&lt;String, Object&gt; inputArgs = (Map&lt;String, Object&gt;) 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("&gt; 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&lt;String, Object&gt; result = new HashMap&lt;&gt;();
                  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&lt;String, Object&gt; response) {
      List&lt;Map&lt;String, Object&gt;&gt; content = (List&lt;Map&lt;String, Object&gt;&gt;) response.get("content");
      for (Map&lt;String, Object&gt; block : content) {
            if ("text".equals(block.get("type"))) return (String) block.get("text");
      }
      return "(no summary)";
    }
}
</code></pre>
<h2 id="subagent">subAgent</h2>
<p><strong>核心思想</strong>:引入<strong>分层架构和上下文隔离</strong>,让Agent能够分解复杂任务,分配给专门的"子Agent"处理,避免上下文污染。</p>
<pre><code class="language-java">// 子 Agent 类 - 独立的执行单元
public static class SubAgent {
    private final List&lt;Map&lt;String, Object&gt;&gt; messages = new ArrayList&lt;&gt;(); // 独立上下文
    private static final String SYSTEM_PROMPT = "You are a coding subagent. Complete the task and summarize findings.";
    // 独立上下文:每个子任务有自己独立的消息历史
    // 系统提示:为子任务定义专门的角色,如"编码专家"
   
    // 子 Agent 只能使用基础工具,不能递归创建子 Agent
    private final List&lt;Map&lt;String, Object&gt;&gt; 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 &lt; 30; i++) {// 最多30轮
            // ... 执行子任务
      }
    }
}
</code></pre>
<ul>
<li><strong>上下文隔离</strong>:每个子任务在干净的环境中执行,不继承父任务的上下文污染</li>
<li><strong>角色专业化</strong>:可以通过不同的SYSTEM_PROMPT让子Agent专注特定领域</li>
<li><strong>防递归保护</strong>:子Agent不能调用task工具,防止无限递归</li>
<li><strong>资源限制</strong>:限制最大轮数,防止死循环</li>
</ul>
<h2 id="任务委派task-工具">任务委派:TASK 工具</h2>
<p><strong>核心思想</strong>:将"委派子任务"抽象为一种工具,实现<strong>任务分解和并行化</strong>。</p>
<pre><code class="language-java">// 父 Agent 的工具列表
private final List&lt;Map&lt;String, Object&gt;&gt; parentTools = new ArrayList&lt;&gt;();
{
    // 基础工具
    parentTools.addAll(Arrays.asList(
      createToolSpec("bash", "Run shell command", "command"),
      // ... 其他基础工具
    ));
    // 添加 TASK 工具
    parentTools.add(createTaskToolSpec());// 关键:父Agent独有的委派能力
}

// 任务工具规格定义
private static Map&lt;String, Object&gt; createTaskToolSpec() {
    Map&lt;String, Object&gt; spec = new HashMap&lt;&gt;();
    spec.put("name", "task");
    spec.put("description", "Spawn a subagent with fresh context.");
    // 工具描述:明确这是创建子Agent的委派工具
   
    Map&lt;String, Object&gt; schema = new HashMap&lt;&gt;();
    schema.put("type", "object");
    Map&lt;String, Object&gt; props = new HashMap&lt;&gt;();
    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;
}
</code></pre>
<ul>
<li><strong>委派抽象</strong>:将"让子Agent做某事"封装为一个工具调用</li>
<li><strong>权限控制</strong>:只有父Agent有这个工具,子Agent没有</li>
<li><strong>接口设计</strong>:明确的任务描述接口,便于LLM使用</li>
</ul>
<h2 id="父子协作流程">父子协作流程</h2>
<pre><code class="language-java">// 父 Agent 的核心循环
public void agentLoop(List&lt;Map&lt;String, Object&gt;&gt; messages) {
    SubAgent subAgent = new SubAgent(); // 创建可重用的子Agent实例

    while (true) {
      // 父Agent思考,可以使用所有工具(包括task)
      Map&lt;String, Object&gt; response = callLLM(messages, "You are a manager. Use 'task' to delegate.", parentTools);
      
      for (Map&lt;String, Object&gt; block : content) {
            if ("tool_use".equals(block.get("type"))) {
                String toolName = (String) block.get("name");
                Map&lt;String, Object&gt; inputArgs = (Map&lt;String, Object&gt;) 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("&gt; task (" + desc + "): " + prompt.substring(0, Math.min(prompt.length(), 50)));
                  output = subAgent.executeTask(prompt);// 调用子Agent
                } else {
                  // 自己执行基础工具
                  ToolExecutor handler = TOOL_HANDLERS.get(toolName);
                  output = handler != null ? handler.execute(inputArgs) : "Unknown tool";
                }
               
                // 将子Agent的结果返回给父Agent
                result.put("content", output);
            }
      }
    }
}
</code></pre>
<ul>
<li><strong>主从模式</strong>:父Agent是管理者,子Agent是工作者</li>
<li><strong>结果聚合</strong>:子Agent返回结果,父Agent继续处理</li>
<li><strong>上下文切换</strong>:子任务执行时,父Agent暂停等待</li>
<li><strong>可重用子Agent</strong>:一个子Agent实例可处理多个任务</li>
</ul>
<h2 id="架构演进与价值">架构演进与价值</h2>
<p><strong>从 AgentWithTodo 到 AgentWithSubAgents 的升级</strong>:</p>
<table>
<thead>
<tr>
<th>维度</th>
<th>AgentWithTodo</th>
<th>AgentWithSubAgents</th>
</tr>
</thead>
<tbody>
<tr>
<td>架构模式</td>
<td>单例模式</td>
<td>分层模式(父子)</td>
</tr>
<tr>
<td>上下文管理</td>
<td>共享上下文</td>
<td>上下文隔离</td>
</tr>
<tr>
<td>任务处理</td>
<td>线性顺序</td>
<td>并行/委派</td>
</tr>
<tr>
<td>复杂性</td>
<td>状态管理</td>
<td>分治策略</td>
</tr>
<tr>
<td>可扩展性</td>
<td>有限</td>
<td>强大</td>
</tr>
</tbody>
</table>


</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自在线网站:seven的菜鸟成长之路,作者:seven,转载请注明原文链接:www.seven97.top</p><br><br>
来源:https://www.cnblogs.com/sevencoding/p/19821512
頁: [1]
查看完整版本: 【从0到1构建一个ClaudeAgent】规划与协调-子Agent