一支梅 發表於 2026-4-15 09:00:00

【从0到1构建一个ClaudeAgent】规划与协调-任务系统

<p>多个任务之间有依赖关系怎么搞?</p>
<h2 id="java实现代码">Java实现代码</h2>
<pre><code class="language-java">public class TaskSystem {
    // --- 配置 ---
    private static final Path WORKDIR = Paths.get(System.getProperty("user.dir"));
    private static final Path TASKS_DIR = WORKDIR.resolve(".tasks");// 任务存储目录
    private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
   
    // --- 工具枚举---
    public enum ToolType {
      BASH("bash", "Run a shell command."),
      READ_FILE("read_file", "Read file contents."),
      WRITE_FILE("write_file", "Write content to file."),
      EDIT_FILE("edit_file", "Replace exact text in file."),
      TASK_CREATE("task_create", "Create a new task."),      // 新增:创建任务
      TASK_GET("task_get", "Get full details of a task by ID."),// 新增:获取任务详情
      TASK_UPDATE("task_update", "Update a task's status or dependencies."),// 新增:更新任务
      TASK_LIST("task_list", "List all tasks with status summary.");// 新增:列出任务

      public final String name;
      public final String description;
      ToolType(String name, String description) { this.name = name; this.description = description; }
    }

    // ... 省略相同的 ToolExecutor 接口
   
    // --- 任务管理器 ---
    static class TaskManager {
      private final Path tasksDir;
      private int nextId = 1;
      
      public TaskManager(Path tasksDir) throws IOException {
            this.tasksDir = tasksDir;
            Files.createDirectories(tasksDir);
            this.nextId = getMaxId() + 1;// 自动计算下一个ID
      }
      
      private int getMaxId() {
            // 扫描已有任务文件,找到最大ID
            try {
                return Files.list(tasksDir)
                  .filter(p -&gt; p.getFileName().toString().startsWith("task_"))
                  .map(p -&gt; {
                        try {
                            String name = p.getFileName().toString();
                            return Integer.parseInt(name.substring(5, name.length() - 5));// task_xxx.json
                        } catch (NumberFormatException e) {
                            return 0;
                        }
                  })
                  .max(Integer::compare)
                  .orElse(0);
            } catch (IOException e) {
                return 0;
            }
      }
      
      private Map&lt;String, Object&gt; loadTask(int taskId) throws IOException {
            Path path = tasksDir.resolve("task_" + taskId + ".json");
            if (!Files.exists(path)) {
                throw new IllegalArgumentException("Task " + taskId + " not found");
            }
            String content = Files.readString(path);
            Type type = new TypeToken&lt;Map&lt;String, Object&gt;&gt;(){}.getType();
            return gson.fromJson(content, type);
      }
      
      private void saveTask(Map&lt;String, Object&gt; task) throws IOException {
            int id = ((Double) task.get("id")).intValue();
            Path path = tasksDir.resolve("task_" + id + ".json");
            Files.writeString(path, gson.toJson(task));// JSON格式存储
      }
      
      public String createTask(String subject, String description) throws IOException {
            Map&lt;String, Object&gt; task = new LinkedHashMap&lt;&gt;();
            task.put("id", nextId);
            task.put("subject", subject);
            task.put("description", description != null ? description : "");
            task.put("status", "pending");// 默认状态
            task.put("blockedBy", new ArrayList&lt;Integer&gt;());// 被哪些任务阻塞
            task.put("blocks", new ArrayList&lt;Integer&gt;());// 阻塞哪些任务
            task.put("owner", "");// 任务负责人
            
            saveTask(task);
            nextId++;
            return gson.toJson(task);
      }
      
      public String getTask(int taskId) throws IOException {
            return gson.toJson(loadTask(taskId));
      }
      
      public String updateTask(int taskId, String status,
                              List&lt;Integer&gt; addBlockedBy, List&lt;Integer&gt; addBlocks) throws IOException {
            Map&lt;String, Object&gt; task = loadTask(taskId);
            
            if (status != null) {
                if (!Arrays.asList("pending", "in_progress", "completed").contains(status)) {
                  throw new IllegalArgumentException("Invalid status: " + status);
                }
                task.put("status", status);
               
                // 任务完成时,从其他任务的 blockedBy 中移除
                if ("completed".equals(status)) {
                  clearDependency(taskId);
                }
            }
            
            if (addBlockedBy != null &amp;&amp; !addBlockedBy.isEmpty()) {
                @SuppressWarnings("unchecked")
                List&lt;Integer&gt; currentBlockedBy = (List&lt;Integer&gt;) task.get("blockedBy");
                List&lt;Integer&gt; newList = new ArrayList&lt;&gt;(currentBlockedBy);
                newList.addAll(addBlockedBy);
                task.put("blockedBy", newList.stream().distinct().collect(Collectors.toList()));
            }
            
            if (addBlocks != null &amp;&amp; !addBlocks.isEmpty()) {
                @SuppressWarnings("unchecked")
                List&lt;Integer&gt; currentBlocks = (List&lt;Integer&gt;) task.get("blocks");
                List&lt;Integer&gt; newList = new ArrayList&lt;&gt;(currentBlocks);
                newList.addAll(addBlocks);
                List&lt;Integer&gt; distinctBlocks = newList.stream().distinct().collect(Collectors.toList());
                task.put("blocks", distinctBlocks);
               
                // 双向更新:更新被阻塞任务的 blockedBy 列表
                for (int blockedId : distinctBlocks) {
                  try {
                        Map&lt;String, Object&gt; blockedTask = loadTask(blockedId);
                        @SuppressWarnings("unchecked")
                        List&lt;Integer&gt; blockedByList = (List&lt;Integer&gt;) blockedTask.get("blockedBy");
                        if (!blockedByList.contains(taskId)) {
                            blockedByList.add(taskId);
                            saveTask(blockedTask);
                        }
                  } catch (Exception e) {
                        // 忽略不存在的任务
                  }
                }
            }
            
            saveTask(task);
            return gson.toJson(task);
      }
      
      private void clearDependency(int completedId) throws IOException {
            Files.list(tasksDir)
                .filter(p -&gt; p.getFileName().toString().endsWith(".json"))
                .forEach(p -&gt; {
                  try {
                        String content = Files.readString(p);
                        Type type = new TypeToken&lt;Map&lt;String, Object&gt;&gt;(){}.getType();
                        Map&lt;String, Object&gt; task = gson.fromJson(content, type);
                        
                        @SuppressWarnings("unchecked")
                        List&lt;Integer&gt; blockedBy = (List&lt;Integer&gt;) task.get("blockedBy");
                        if (blockedBy != null &amp;&amp; blockedBy.contains(completedId)) {
                            blockedBy.remove(Integer.valueOf(completedId));
                            Files.writeString(p, gson.toJson(task));
                        }
                  } catch (IOException e) {
                        // 忽略读取错误
                  }
                });
      }
      
      public String listAllTasks() throws IOException {
            List&lt;Map&lt;String, Object&gt;&gt; tasks = new ArrayList&lt;&gt;();
            
            Files.list(tasksDir)
                .filter(p -&gt; p.getFileName().toString().endsWith(".json"))
                .sorted()
                .forEach(p -&gt; {
                  try {
                        String content = Files.readString(p);
                        Type type = new TypeToken&lt;Map&lt;String, Object&gt;&gt;(){}.getType();
                        tasks.add(gson.fromJson(content, type));
                  } catch (IOException e) {
                        // 忽略错误
                  }
                });
            
            if (tasks.isEmpty()) {
                return "No tasks.";
            }
            
            StringBuilder sb = new StringBuilder();
            for (Map&lt;String, Object&gt; task : tasks) {
                String status = (String) task.get("status");
                String marker = switch(status) {
                  case "pending" -&gt; "[ ]";
                  case "in_progress" -&gt; "[&gt;]";
                  case "completed" -&gt; "";
                  default -&gt; "[?]";
                };
               
                int id = ((Double) task.get("id")).intValue();
                String subject = (String) task.get("subject");
               
                @SuppressWarnings("unchecked")
                List&lt;Integer&gt; blockedBy = (List&lt;Integer&gt;) task.get("blockedBy");
                String blockedStr = (blockedBy != null &amp;&amp; !blockedBy.isEmpty())
                  ? " (blocked by: " + blockedBy + ")"
                  : "";
               
                sb.append(String.format("%s #%d: %s%s\n", marker, id, subject, blockedStr));
            }
            
            return sb.toString().trim();
      }
    }
   
    // --- 工具处理器映射 ---
    private static final Map&lt;String, ToolExecutor&gt; TOOL_HANDLERS = new HashMap&lt;&gt;();
   
    static {
      // 初始化任务管理器
      TaskManager taskManager;
      try {
            taskManager = new TaskManager(TASKS_DIR);
      } catch (IOException e) {
            throw new RuntimeException("Failed to initialize task manager", e);
      }
      
      // ... 省略基础工具注册
      
      // 注册 Task Create 工具
      TOOL_HANDLERS.put(ToolType.TASK_CREATE.name, args -&gt; {
            String subject = (String) args.get("subject");
            String description = (String) args.get("description");
            return taskManager.createTask(subject, description);
      });
      
      // 注册 Task Get 工具
      TOOL_HANDLERS.put(ToolType.TASK_GET.name, args -&gt; {
            int taskId = ((Number) args.get("task_id")).intValue();
            return taskManager.getTask(taskId);
      });
      
      // 注册 Task Update 工具
      TOOL_HANDLERS.put(ToolType.TASK_UPDATE.name, args -&gt; {
            int taskId = ((Number) args.get("task_id")).intValue();
            String status = (String) args.get("status");
            
            @SuppressWarnings("unchecked")
            List&lt;Integer&gt; addBlockedBy = (List&lt;Integer&gt;) args.get("addBlockedBy");
            
            @SuppressWarnings("unchecked")
            List&lt;Integer&gt; addBlocks = (List&lt;Integer&gt;) args.get("addBlocks");
            
            return taskManager.updateTask(taskId, status, addBlockedBy, addBlocks);
      });
      
      // 注册 Task List 工具
      TOOL_HANDLERS.put(ToolType.TASK_LIST.name, args -&gt; {
            return taskManager.listAllTasks();
      });
    }
   
    // ... 省略相同的工具实现和主循环
}
</code></pre>
<p>核心思想:利用基于文件的任务图,Agent 开始理解任务间的先后顺序与并行逻辑,成为真正的项目协调者。</p>
<h2 id="企业级任务管理系统架构">企业级任务管理系统架构</h2>
<p><strong>核心思想</strong>:从简单的内存中Todo管理器升级为<strong>持久化、结构化的企业级任务管理系统</strong>,支持<strong>复杂依赖关系、多任务协同、状态持久化</strong>,适用于真实的项目管理和协作场景。</p>
<pre><code class="language-java">// 任务管理器 - 持久化存储架构
static class TaskManager {
    private final Path tasksDir;// 任务存储目录
    private int nextId = 1;       // 自增ID
   
    public TaskManager(Path tasksDir) throws IOException {
      this.tasksDir = tasksDir;
      Files.createDirectories(tasksDir);
      this.nextId = getMaxId() + 1;// 启动时自动计算下一个ID
    }
    // 文件系统存储:每个任务存储为独立的JSON文件
    // 自动ID管理:启动时扫描现有文件,避免ID冲突
    // 持久化:重启后任务状态不丢失
}
</code></pre>
<ul>
<li><strong>企业级存储</strong>:从内存中Todo升级为文件系统持久化存储</li>
<li><strong>原子操作</strong>:每个任务独立文件,避免并发问题</li>
<li><strong>增量ID</strong>:自动管理任务ID,支持大规模任务</li>
<li><strong>灾备恢复</strong>:文件存储支持手动备份和恢复</li>
</ul>
<h2 id="任务数据结构与依赖管理">任务数据结构与依赖管理</h2>
<pre><code class="language-java">// 创建任务时初始化完整数据结构
public String createTask(String subject, String description) throws IOException {
    Map&lt;String, Object&gt; task = new LinkedHashMap&lt;&gt;();
    task.put("id", nextId);
    task.put("subject", subject);      // 任务主题
    task.put("description", description != null ? description : "");// 详细描述
    task.put("status", "pending");       // 状态:pending/in_progress/completed
    task.put("blockedBy", new ArrayList&lt;Integer&gt;());// 被哪些任务阻塞
    task.put("blocks", new ArrayList&lt;Integer&gt;());   // 阻塞哪些任务
    task.put("owner", "");               // 任务负责人,支持分派
    // 结构化任务:包含完整元数据和关系
    // 依赖管理:blockedBy和blocks双向记录依赖关系
    // 权限控制:owner字段支持任务分派
   
    saveTask(task);
    nextId++;
    return gson.toJson(task);
}
</code></pre>
<ul>
<li><strong>结构化元数据</strong>:任务包含丰富的信息字段</li>
<li><strong>依赖管理</strong>:支持任务间的阻塞/被阻塞关系</li>
<li><strong>扩展性</strong>:预留owner字段支持团队协作</li>
<li><strong>JSON格式</strong>:人类可读,便于调试和手动修改</li>
</ul>
<h2 id="双向依赖同步机制">双向依赖同步机制</h2>
<pre><code class="language-java">// 更新任务时自动同步依赖关系
public String updateTask(int taskId, String status,
                        List&lt;Integer&gt; addBlockedBy, List&lt;Integer&gt; addBlocks) throws IOException {
    Map&lt;String, Object&gt; task = loadTask(taskId);
   
    if (status != null) {
      task.put("status", status);
      
      // 任务完成时,从其他任务的 blockedBy 中移除
      if ("completed".equals(status)) {
            clearDependency(taskId);
      }
    }
   
    if (addBlocks != null &amp;&amp; !addBlocks.isEmpty()) {
      // 双向更新:更新被阻塞任务的 blockedBy 列表
      for (int blockedId : distinctBlocks) {
            try {
                Map&lt;String, Object&gt; blockedTask = loadTask(blockedId);
                @SuppressWarnings("unchecked")
                List&lt;Integer&gt; blockedByList = (List&lt;Integer&gt;) blockedTask.get("blockedBy");
                if (!blockedByList.contains(taskId)) {
                  blockedByList.add(taskId);
                  saveTask(blockedTask);
                }
            } catch (Exception e) {
                // 忽略不存在的任务
            }
      }
    }
    // 依赖自动化:更新一个任务时,自动更新相关任务的依赖关系
    // 完成清理:任务完成后自动清理对它的阻塞依赖
    // 容错处理:忽略不存在的任务ID
}
</code></pre>
<ul>
<li><strong>关系自动维护</strong>:更新一个任务的依赖时,自动更新相关任务</li>
<li><strong>完成时清理</strong>:任务完成后自动清理阻塞关系</li>
<li><strong>容错设计</strong>:忽略不存在任务的引用</li>
<li><strong>数据一致性</strong>:确保依赖关系的双向一致性</li>
</ul>
<h2 id="复杂查询与可视化展示">复杂查询与可视化展示</h2>
<pre><code class="language-java">// 列出所有任务的摘要信息
public String listAllTasks() throws IOException {
    List&lt;Map&lt;String, Object&gt;&gt; tasks = new ArrayList&lt;&gt;();
   
    Files.list(tasksDir)
      .filter(p -&gt; p.getFileName().toString().endsWith(".json"))
      .sorted()// 按文件名排序,通常是ID顺序
      .forEach(p -&gt; {
            // 逐个加载任务文件
      });
   
    StringBuilder sb = new StringBuilder();
    for (Map&lt;String, Object&gt; task : tasks) {
      String status = (String) task.get("status");
      String marker = switch(status) {
            case "pending" -&gt; "[ ]";
            case "in_progress" -&gt; "[&gt;]";
            case "completed" -&gt; "";
            default -&gt; "[?]";
      };
      
      int id = ((Double) task.get("id")).intValue();
      String subject = (String) task.get("subject");
      
      @SuppressWarnings("unchecked")
      List&lt;Integer&gt; blockedBy = (List&lt;Integer&gt;) task.get("blockedBy");
      String blockedStr = (blockedBy != null &amp;&amp; !blockedBy.isEmpty())
            ? " (blocked by: " + blockedBy + ")"
            : "";
      // 状态可视化:[ ]待办 [&gt;]进行中 已完成
      // 依赖提示:显示哪些任务阻塞了当前任务
      // 简洁摘要:只显示关键信息
      
      sb.append(String.format("%s #%d: %s%s\n", marker, id, subject, blockedStr));
    }
   
    return sb.toString().trim();
}
</code></pre>
<ul>
<li><strong>状态可视化</strong>:用图标清晰展示任务状态</li>
<li><strong>依赖提示</strong>:明确显示阻塞关系</li>
<li><strong>批量加载</strong>:高效加载所有任务</li>
<li><strong>人性化格式</strong>:便于人类阅读和理解</li>
</ul>
<h2 id="任务工具生态系统">任务工具生态系统</h2>
<pre><code class="language-java">// 完整的任务工具集定义
public enum ToolType {
    TASK_CREATE("task_create", "Create a new task."),      // CRUD: Create
    TASK_GET("task_get", "Get full details of a task by ID."),// CRUD: Read
    TASK_UPDATE("task_update", "Update a task's status or dependencies."),// CRUD: Update
    TASK_LIST("task_list", "List all tasks with status summary.");// CRUD: List
    // 完整CRUD:创建、读取、更新、删除(通过更新状态为完成)
    // 语义清晰:每个工具单一职责
    // 与基础工具分离:任务管理工具独立于文件操作工具
}
</code></pre>
<ul>
<li><strong>完整CRUD</strong>:提供完整的任务管理操作</li>
<li><strong>单一职责</strong>:每个工具功能明确</li>
<li><strong>语义接口</strong>:名称明确,便于LLM理解</li>
<li><strong>分离关注</strong>:任务工具与基础文件工具分离</li>
</ul>
<h2 id="json存储格式">JSON存储格式</h2>
<pre><code class="language-java">// 任务存储格式示例
private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();

private void saveTask(Map&lt;String, Object&gt; task) throws IOException {
    int id = ((Double) task.get("id")).intValue();
    Path path = tasksDir.resolve("task_" + id + ".json");
    Files.writeString(path, gson.toJson(task));// 美化的JSON格式
}
// 标准化格式:每个任务存储为格式化的JSON文件
// 命名规范:task_&lt;id&gt;.json
// 人类可读:美化的JSON便于手动查看和编辑
// 可互操作:标准JSON格式支持外部工具处理
</code></pre>
<ul>
<li><strong>标准化存储</strong>:JSON是通用的数据交换格式</li>
<li><strong>可读性</strong>:美化格式便于调试</li>
<li><strong>可扩展</strong>:随时可以添加新字段</li>
<li><strong>互操作性</strong>:其他工具可以读取任务文件</li>
</ul>
<h2 id="架构演进与价值">架构演进与价值</h2>
<p><strong>从 AgentWithTodo 到 TaskSystem 的升级</strong>:</p>
<table>
<thead>
<tr>
<th>维度</th>
<th>AgentWithTodo</th>
<th>TaskSystem</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>
<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/19821558
頁: [1]
查看完整版本: 【从0到1构建一个ClaudeAgent】规划与协调-任务系统