当前位置: 首页 > news >正文

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

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

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() {// 扫描已有任务文件,找到最大IDtry {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;       // 自增IDpublic 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/completedtask.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: CreateTASK_GET("task_get", "Get full details of a task by ID."),  // CRUD: ReadTASK_UPDATE("task_update", "Update a task's status or dependencies."),  // CRUD: UpdateTASK_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
存储方式 内存存储 文件系统持久化
依赖管理 无依赖关系 双向依赖管理
数据持久性 重启丢失 永久保存
任务复杂性 简单待办 复杂项目管理
协同能力 单人使用 支持团队协作
可扩展性 有限 强大
http://www.jsqmd.com/news/643985/

相关文章:

  • 2026年好用的高精度线材轧机推荐,企业选择探讨 - myqiye
  • 基于Qwen3.5-2B的MySQL智能运维助手:安装配置与性能调优
  • 从PRT到STP:除了批量转换,工程师更该关心的数据完整性与版本管理
  • StructBERT在不同行业术语下的相似度计算适应性展示
  • AI 名片的核心功能拆解:哪些功能是企业真正需要的?(避坑指南)
  • 2026商务出行平台推荐:企业差旅痛点分析与数字化解决方案 - 匠言榜单
  • 如何通过手机号找回QQ号:3分钟快速解决方案
  • 2/3英寸靶面工业镜头配置全攻略:如何用25mm焦距实现0.05mm检测精度
  • 3步解决Windows多语言软件兼容性问题:Locale Emulator完全指南
  • 三步搞定Windows语音转文字:免费离线神器深度解析
  • RoadRunner场景建模避坑指南:从FBX模型导入到Simulink联合仿真全流程解析
  • 武汉佰利和建筑防水工程有限公司:武汉防水维修电话 - LYL仔仔
  • 3个维度重新定义SillyTavern:从技术工具到情感伙伴的进化之路
  • PyTorch 2.8通用镜像惊艳效果:RTX 4090D跑Llama3-70B推理延迟实测分享
  • 3步解锁网易云音乐:ncmdump让NCM格式文件随处播放
  • 终极Windows 11安装指南:MediaCreationTool.bat让老旧电脑轻松升级
  • 2026年实测10款硬核论文降AI工具:高效降低AI率,AI率降至6% - 降AI实验室
  • 别再混淆了!5分钟搞懂ARM Cortex-M的异常、中断、NVIC和向量表到底啥关系
  • <项目代码>yolo 胸部X光疾病识别<目标检测>
  • 如何找到靠谱的大润发购物卡回收渠道? - 团团收购物卡回收
  • 西门子S7-1200 PLC博途全方位学习包
  • LLM核心参数配置指南:基础篇 - AI
  • intv_ai_mk11开源模型优势:Apache 2.0协议商用友好,支持商业闭源集成与白标定制
  • 突破光学装配瓶颈,DTAS 3D公差分析及尺寸链计算-光线装配赋能精密制造
  • 有源晶振与温度补偿晶振的应用与优势分析
  • 2026年室内装修公司选择支招,推荐靠谱的家装公司哪家强 - 工业品网
  • 3分钟搞定魔兽争霸III终极优化:免费解决宽屏、卡顿与地图加载问题
  • 2702基于51单片机的液位上下限报警系统设计(LCD1602,ADC0832)
  • 抖音批量下载工具:从单视频到全主页的高效解决方案
  • 10分钟精通Sunshine游戏串流:零基础搭建高性能串流服务器