如何构建从0到1的ClaudeAgent任务系统规划与协调策略?

摘要:多个任务之间有依赖关系怎么搞? Java实现代码 public class TaskSystem {配置 private static final Path WORKDIR = Paths.get(System.getPropert
多个任务之间有依赖关系怎么搞? 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 -> p.getFileName().toString().startsWith("task_")) .map(p -> { 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<String, Object> 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<Map<String, Object>>(){}.getType(); return gson.fromJson(content, type); } private void saveTask(Map<String, Object> 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<String, Object> task = new LinkedHashMap<>(); task.put("id", nextId); task.put("subject", subject); task.put("description", description != null ? description : ""); task.put("status", "pending"); // 默认状态 task.put("blockedBy", new ArrayList<Integer>()); // 被哪些任务阻塞 task.put("blocks", new ArrayList<Integer>()); // 阻塞哪些任务 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<Integer> addBlockedBy, List<Integer> addBlocks) throws IOException { Map<String, Object> 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 && !addBlockedBy.isEmpty()) { @SuppressWarnings("unchecked") List<Integer> currentBlockedBy = (List<Integer>) task.get("blockedBy"); List<Integer> newList = new ArrayList<>(currentBlockedBy); newList.addAll(addBlockedBy); task.put("blockedBy", newList.stream().distinct().collect(Collectors.toList())); } if (addBlocks != null && !addBlocks.isEmpty()) { @SuppressWarnings("unchecked") List<Integer> currentBlocks = (List<Integer>) task.get("blocks"); List<Integer> newList = new ArrayList<>(currentBlocks); newList.addAll(addBlocks); List<Integer> distinctBlocks = newList.stream().distinct().collect(Collectors.toList()); task.put("blocks", distinctBlocks); // 双向更新:更新被阻塞任务的 blockedBy 列表 for (int blockedId : distinctBlocks) { try { Map<String, Object> blockedTask = loadTask(blockedId); @SuppressWarnings("unchecked") List<Integer> blockedByList = (List<Integer>) 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 -> p.getFileName().toString().endsWith(".json")) .forEach(p -> { try { String content = Files.readString(p); Type type = new TypeToken<Map<String, Object>>(){}.getType(); Map<String, Object> task = gson.fromJson(content, type); @SuppressWarnings("unchecked") List<Integer> blockedBy = (List<Integer>) task.get("blockedBy"); if (blockedBy != null && blockedBy.contains(completedId)) { blockedBy.remove(Integer.valueOf(completedId)); Files.writeString(p, gson.toJson(task)); } } catch (IOException e) { // 忽略读取错误 } }); } public String listAllTasks() throws IOException { List<Map<String, Object>> tasks = new ArrayList<>(); Files.list(tasksDir) .filter(p -> p.getFileName().toString().endsWith(".json")) .sorted() .forEach(p -> { try { String content = Files.readString(p); Type type = new TypeToken<Map<String, Object>>(){}.getType(); tasks.add(gson.fromJson(content, type)); } catch (IOException e) { // 忽略错误 } }); if (tasks.isEmpty()) { return "No tasks."; } StringBuilder sb = new StringBuilder(); for (Map<String, Object> task : tasks) { String status = (String) task.get("status"); String marker = switch(status) { case "pending" -> "[ ]"; case "in_progress" -> "[>]"; case "completed" -> "[x]"; default -> "[?]"; }; int id = ((Double) task.get("id")).intValue(); String subject = (String) task.get("subject"); @SuppressWarnings("unchecked") List<Integer> blockedBy = (List<Integer>) task.get("blockedBy"); String blockedStr = (blockedBy != null && !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<String, ToolExecutor> TOOL_HANDLERS = new HashMap<>(); 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 -> { 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 -> { int taskId = ((Number) args.get("task_id")).intValue(); return taskManager.getTask(taskId); }); // 注册 Task Update 工具 TOOL_HANDLERS.put(ToolType.TASK_UPDATE.name, args -> { int taskId = ((Number) args.get("task_id")).intValue(); String status = (String) args.get("status"); @SuppressWarnings("unchecked") List<Integer> addBlockedBy = (List<Integer>) args.get("addBlockedBy"); @SuppressWarnings("unchecked") List<Integer> addBlocks = (List<Integer>) args.get("addBlocks"); return taskManager.updateTask(taskId, status, addBlockedBy, addBlocks); }); // 注册 Task List 工具 TOOL_HANDLERS.put(ToolType.TASK_LIST.name, args -> { return taskManager.listAllTasks(); }); } // ... 省略相同的工具实现和主循环 } 核心思想:利用基于文件的任务图,Agent 开始理解任务间的先后顺序与并行逻辑,成为真正的项目协调者。 企业级任务管理系统架构 核心思想:从简单的内存中Todo管理器升级为持久化、结构化的企业级任务管理系统,支持复杂依赖关系、多任务协同、状态持久化,适用于真实的项目管理和协作场景。 // 任务管理器 - 持久化存储架构 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冲突 // 持久化:重启后任务状态不丢失 } 企业级存储:从内存中Todo升级为文件系统持久化存储 原子操作:每个任务独立文件,避免并发问题 增量ID:自动管理任务ID,支持大规模任务 灾备恢复:文件存储支持手动备份和恢复 任务数据结构与依赖管理 // 创建任务时初始化完整数据结构 public String createTask(String subject, String description) throws IOException { Map<String, Object> task = new LinkedHashMap<>(); 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<Integer>()); // 被哪些任务阻塞 task.put("blocks", new ArrayList<Integer>()); // 阻塞哪些任务 task.put("owner", ""); // 任务负责人,支持分派 // 结构化任务:包含完整元数据和关系 // 依赖管理:blockedBy和blocks双向记录依赖关系 // 权限控制:owner字段支持任务分派 saveTask(task); nextId++; return gson.toJson(task); } 结构化元数据:任务包含丰富的信息字段 依赖管理:支持任务间的阻塞/被阻塞关系 扩展性:预留owner字段支持团队协作 JSON格式:人类可读,便于调试和手动修改 双向依赖同步机制 // 更新任务时自动同步依赖关系 public String updateTask(int taskId, String status, List<Integer> addBlockedBy, List<Integer> addBlocks) throws IOException { Map<String, Object> task = loadTask(taskId); if (status != null) { task.put("status", status); // 任务完成时,从其他任务的 blockedBy 中移除 if ("completed".equals(status)) { clearDependency(taskId); } } if (addBlocks != null && !addBlocks.isEmpty()) { // 双向更新:更新被阻塞任务的 blockedBy 列表 for (int blockedId : distinctBlocks) { try { Map<String, Object> blockedTask = loadTask(blockedId); @SuppressWarnings("unchecked") List<Integer> blockedByList = (List<Integer>) blockedTask.get("blockedBy"); if (!blockedByList.contains(taskId)) { blockedByList.add(taskId); saveTask(blockedTask); } } catch (Exception e) { // 忽略不存在的任务 } } } // 依赖自动化:更新一个任务时,自动更新相关任务的依赖关系 // 完成清理:任务完成后自动清理对它的阻塞依赖 // 容错处理:忽略不存在的任务ID } 关系自动维护:更新一个任务的依赖时,自动更新相关任务 完成时清理:任务完成后自动清理阻塞关系 容错设计:忽略不存在任务的引用 数据一致性:确保依赖关系的双向一致性 复杂查询与可视化展示 // 列出所有任务的摘要信息 public String listAllTasks() throws IOException { List<Map<String, Object>> tasks = new ArrayList<>(); Files.list(tasksDir) .filter(p -> p.getFileName().toString().endsWith(".json")) .sorted() // 按文件名排序,通常是ID顺序 .forEach(p -> { // 逐个加载任务文件 }); StringBuilder sb = new StringBuilder(); for (Map<String, Object> task : tasks) { String status = (String) task.get("status"); String marker = switch(status) { case "pending" -> "[ ]"; case "in_progress" -> "[>]"; case "completed" -> "[x]"; default -> "[?]"; }; int id = ((Double) task.get("id")).intValue(); String subject = (String) task.get("subject"); @SuppressWarnings("unchecked") List<Integer> blockedBy = (List<Integer>) task.get("blockedBy"); String blockedStr = (blockedBy != null && !blockedBy.isEmpty()) ? " (blocked by: " + blockedBy + ")" : ""; // 状态可视化:[ ]待办 [>]进行中 [x]已完成 // 依赖提示:显示哪些任务阻塞了当前任务 // 简洁摘要:只显示关键信息 sb.append(String.format("%s #%d: %s%s\n", marker, id, subject, blockedStr)); } return sb.toString().trim(); } 状态可视化:用图标清晰展示任务状态 依赖提示:明确显示阻塞关系 批量加载:高效加载所有任务 人性化格式:便于人类阅读和理解 任务工具生态系统 // 完整的任务工具集定义 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:创建、读取、更新、删除(通过更新状态为完成) // 语义清晰:每个工具单一职责 // 与基础工具分离:任务管理工具独立于文件操作工具 } 完整CRUD:提供完整的任务管理操作 单一职责:每个工具功能明确 语义接口:名称明确,便于LLM理解 分离关注:任务工具与基础文件工具分离 JSON存储格式 // 任务存储格式示例 private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); private void saveTask(Map<String, Object> 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_<id>.json // 人类可读:美化的JSON便于手动查看和编辑 // 可互操作:标准JSON格式支持外部工具处理 标准化存储:JSON是通用的数据交换格式 可读性:美化格式便于调试 可扩展:随时可以添加新字段 互操作性:其他工具可以读取任务文件 架构演进与价值 从 AgentWithTodo 到 TaskSystem 的升级: 维度 AgentWithTodo TaskSystem 存储方式 内存存储 文件系统持久化 依赖管理 无依赖关系 双向依赖管理 数据持久性 重启丢失 永久保存 任务复杂性 简单待办 复杂项目管理 协同能力 单人使用 支持团队协作 可扩展性 有限 强大