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

多个任务之间有依赖关系怎么搞?

Java实现代码

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管理器升级为持久化、结构化的企业级任务管理系统 ,支持复杂依赖关系、多任务协同、状态持久化,适用于真实的项目管理和协作场景。

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冲突
    // 持久化:重启后任务状态不丢失
}
  • 企业级存储:从内存中Todo升级为文件系统持久化存储
  • 原子操作:每个任务独立文件,避免并发问题
  • 增量ID:自动管理任务ID,支持大规模任务
  • 灾备恢复:文件存储支持手动备份和恢复

任务数据结构与依赖管理

java 复制代码
// 创建任务时初始化完整数据结构
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格式:人类可读,便于调试和手动修改

双向依赖同步机制

java 复制代码
// 更新任务时自动同步依赖关系
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
}
  • 关系自动维护:更新一个任务的依赖时,自动更新相关任务
  • 完成时清理:任务完成后自动清理阻塞关系
  • 容错设计:忽略不存在任务的引用
  • 数据一致性:确保依赖关系的双向一致性

复杂查询与可视化展示

java 复制代码
// 列出所有任务的摘要信息
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();
}
  • 状态可视化:用图标清晰展示任务状态
  • 依赖提示:明确显示阻塞关系
  • 批量加载:高效加载所有任务
  • 人性化格式:便于人类阅读和理解

任务工具生态系统

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:创建、读取、更新、删除(通过更新状态为完成)
    // 语义清晰:每个工具单一职责
    // 与基础工具分离:任务管理工具独立于文件操作工具
}
  • 完整CRUD:提供完整的任务管理操作
  • 单一职责:每个工具功能明确
  • 语义接口:名称明确,便于LLM理解
  • 分离关注:任务工具与基础文件工具分离

JSON存储格式

java 复制代码
// 任务存储格式示例
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
存储方式 内存存储 文件系统持久化
依赖管理 无依赖关系 双向依赖管理
数据持久性 重启丢失 永久保存
任务复杂性 简单待办 复杂项目管理
协同能力 单人使用 支持团队协作
可扩展性 有限 强大
相关推荐
极光代码工作室1 小时前
基于SpringBoot的订单管理系统
java·springboot·web开发·后端开发
xiaoduzi19911 小时前
ConcurrentHashMap学习
java·学习
折哥的程序人生 · 物流技术专研1 小时前
《Java 100 天进阶之路》第53篇:volatile与JMM(2026版)
java·volatile·内存屏障·可见性·java内存模型·jmm·java100天进阶
米饭不加菜1 小时前
使用万用表判断三极管(BJT)好坏
java·开发语言
Maynor9961 小时前
AI Coding 零基础实战教程|第五部分:完整项目案例实操
java·前端·人工智能·claude code·ai coding
小猿备忘录2 小时前
JVM 调优完全手册(Java 8 版)
java·开发语言·jvm
生戎马2 小时前
Tomcat Container容器之Engine:StandardEngine _
java·tomcat
zhangjw342 小时前
第29篇:Java伪共享与对象分配:并发性能优化的关键
java·开发语言·性能优化
宠友信息2 小时前
内容社区源码多端数据协议与 Spring Boot 状态流转实现思路
java·spring boot·websocket·uni-app
一路向北North3 小时前
Spring Security OAuth2.0(19):JWT令牌
java·后端·spring