【learn-claude-code】S07TaskSystem - 任务系统:大目标拆成小任务,持久化到磁盘

核心理念

"大目标拆成小任务,持久化到磁盘" -- 任务图 + 依赖管理 + 文件持久化。

上篇回顾

上篇文章我们实现了三层压缩策略,让无限会话成为可能。

问题

s03 的 TodoManager 保存在内存中:

  • 会话结束,任务丢失
  • 重启后无法恢复进度
  • 无法在多轮对话间保持状态

我们需要:持久化的任务图

解决方案

复制代码
TaskManager (内存)
    │
    │  save / load
    ▼
tasks/ (文件系统)
    ├── task_1.json
    ├── task_2.json
    └── task_3.json

每个任务文件:

json 复制代码
{
  "id": 1,
  "subject": "搭建项目",
  "description": "初始化 Maven 项目结构",
  "status": "completed",
  "blockedBy": [],
  "blocks": [2, 3],
  "owner": ""
}

Java 实现详解

1. 任务实体结构

json 复制代码
{
  "id": 1,
  "subject": "搭建项目",
  "description": "初始化 Maven 项目结构",
  "status": "pending | in_progress | completed",
  "blockedBy": [1, 2],
  "blocks": [3, 4],
  "owner": ""
}
字段 说明
id 唯一标识,自增
subject 任务主题
description 任务描述
status 状态:pending / in_progress / completed
blockedBy 依赖列表(哪些任务完成后我才开始)
blocks 我阻塞的任务列表
owner 任务负责人

2. TaskManager:任务管理器

java 复制代码
public class TaskManager {
    private final Path taskDir;
    private int nextId;

    public TaskManager(String tasksDir) {
        this.taskDir = Paths.get(tasksDir);
        Files.createDirectories(this.taskDir);
        this.nextId = findMaxId() + 1;
    }
}

3. 文件持久化

java 复制代码
private void saveTask(JSONObject task) {
    int id = task.getIntValue("id");
    Path path = taskDir.resolve("task_" + id + ".json");
    String json = JSON.toJSONString(task);
    Files.writeString(path, json);
}

private JSONObject loadTask(int taskId) {
    Path path = taskDir.resolve("task_" + taskId + ".json");
    String content = Files.readString(path);
    return JSON.parseObject(content);
}

4. 创建任务

java 复制代码
public String create(String subject, String description) {
    JSONObject task = new JSONObject();
    task.put("id", nextId);
    task.put("subject", subject);
    task.put("description", description == null ? "" : description);
    task.put("status", "pending");
    task.put("blockedBy", new ArrayList<>());
    task.put("blocks", new ArrayList<>());
    task.put("owner", "");

    saveTask(task);
    nextId++;
    return JSON.toJSONString(task);
}

5. 依赖管理

java 复制代码
public String update(int taskId, String status,
                     List<Integer> addBlockedBy,
                     List<Integer> addBlocks) {
    JSONObject task = loadTask(taskId);

    if (status != null) {
        task.put("status", status);
        if ("completed".equals(status)) {
            clearDependency(taskId);  // 完成后清理依赖
        }
    }

    if (addBlockedBy != null) {
        Set<Integer> set = new HashSet<>(task.getList("blockedBy", Integer.class));
        set.addAll(addBlockedBy);
        task.put("blockedBy", new ArrayList<>(set));
    }

    if (addBlocks != null) {
        // 双向更新:更新自己的 blocks,也更新被阻塞任务的 blockedBy
        for (Integer blockedId : addBlocks) {
            JSONObject blocked = loadTask(blockedId);
            List<Integer> blockedBy = blocked.getList("blockedBy", Integer.class);
            if (!blockedBy.contains(taskId)) {
                blockedBy.add(taskId);
                blocked.put("blockedBy", blockedBy);
                saveTask(blocked);
            }
        }
    }

    saveTask(task);
    return JSON.toJSONString(task);
}

6. 清理依赖

任务完成后,自动从所有任务的 blockedBy 中移除自己:

java 复制代码
private void clearDependency(int completedId) {
    Files.list(taskDir)
            .filter(p -> p.getFileName().toString().startsWith("task_"))
            .forEach(p -> {
                JSONObject task = JSON.parseObject(Files.readString(p));
                List<Integer> blockedBy = task.getList("blockedBy", Integer.class);
                if (blockedBy != null && blockedBy.contains(completedId)) {
                    blockedBy.remove(Integer.valueOf(completedId));
                    task.put("blockedBy", blockedBy);
                    saveTask(task);
                }
            });
}

7. 列出任务

java 复制代码
public String list() {
    List<JSONObject> tasks = new ArrayList<>();
    Files.list(taskDir)
            .filter(p -> p.getFileName().toString().matches("task_\\d+\\.json"))
            .forEach(p -> tasks.add(JSON.parseObject(Files.readString(p))));

    List<String> lines = new ArrayList<>();
    for (JSONObject t : tasks) {
        String status = t.getString("status");
        String marker = switch (status) {
            case "pending" -> "[ ]";
            case "in_progress" -> "[>]";
            case "completed" -> "[x]";
            default -> "[?]";
        };

        List<Integer> blockedBy = t.getList("blockedBy", Integer.class);
        String blocked = (blockedBy != null && !blockedBy.isEmpty())
                ? " (依赖: " + blockedBy + ")"
                : "";

        lines.add(marker + " #" + t.getIntValue("id") + ": " 
                + t.getString("subject") + blocked);
    }
    return String.join("\n", lines);
}

输出示例:

复制代码
[ ] #1: 搭建项目 (依赖: [])
[x] #2: 编写代码 (依赖: [1])
[x] #3: 编写测试 (依赖: [1])
[ ] #4: 代码审查 (依赖: [2, 3])

任务工具注册

java 复制代码
private static final TaskManager TASKS = new TaskManager(Commons.TASK_DIR);

private static final Map<String, Function<String, String>> TOOL_HANDLERS = new HashMap<>();

static {
    TOOL_HANDLERS.put("bash", Tools::runBash);
    TOOL_HANDLERS.put("readFile", Tools::runReadFile);
    TOOL_HANDLERS.put("writeFile", Tools::runWriteFile);
    TOOL_HANDLERS.put("editFile", Tools::runEditFile);
    TOOL_HANDLERS.put("taskCreate", TASKS::create);
    TOOL_HANDLERS.put("taskUpdate", TASKS::update);
    TOOL_HANDLERS.put("taskList", args -> TASKS.list());
    TOOL_HANDLERS.put("taskGet", TASKS::get);
}

private static final List<ChatCompletionTool> tools = List.of(
    Tools.bashTool(),
    Tools.readFileTool(),
    Tools.writeFileTool(),
    Tools.editFileTool(),
    Tools.taskCreateTool(),
    Tools.taskUpdateTool(),
    Tools.taskListTool(),
    Tools.taskGetTool()
);

任务图示意

复制代码
代码重构任务看板

   [解析]
      │
      ├──→ [转换] ──┐
      │             ├──→ [测试]
      └──→ [生成] ──┘
                     │
              依赖关系: 转换和生成都依赖解析
              转换和生成可以并行执行

相对 s06 的变更

组件 s06 s07
任务管理 内存 TodoManager 持久化 TaskManager
依赖管理 blockedBy / blocks 双向关联
存储 内存 tasks/*.json 文件
工具 4 + compact 4 + taskCreate/taskUpdate/taskList/taskGet

试试看

  1. 创建 3 个任务:"搭建项目"、"编写代码"、"编写测试",并按顺序设置依赖关系
  2. 列出所有任务并展示依赖关系图
  3. 完成任务 1,然后列出任务,查看任务 2 是否解除阻塞
  4. 创建一个用于代码重构的任务看板:解析 → 转换 → 生成 → 测试

核心要义

"Break big goals into small tasks, order them, persist to disk"

任务持久化,进度不丢失

设计原则:

  • 文件即状态:每个任务一个 JSON 文件
  • 依赖双向维护:blockedBy + blocks 同步更新
  • 完成即清理:完成任务时自动解除阻塞
相关推荐
做萤石二次开发的哈哈2 小时前
AI+台球 | 萤石点亮智慧台球厅,让娱乐更智能
人工智能
qq_235132172 小时前
五金制造行业ERP系统多少钱?易呈erp五金行业版功能模块详解与成功案例分享
大数据·运维·人工智能·制造·智能制造
SmartBrain2 小时前
基于华为管理理念刨析:三医领域数字化转型战略规划研究报告
人工智能·华为
云栖梦泽2 小时前
【AI】AI安全工具:AI模型安全检测工具的实战使用
人工智能·安全·机器学习
Ashmcracker2 小时前
Codex Desktop如何接入Azure OpenAI?AI Foundry部署GPT‑5.3‑codex 实操
人工智能·gpt·microsoft·azure
Datawhale2 小时前
Claude AI 全套课程,如何从零开始构建并自动化各种项目!
运维·人工智能·自动化
Rsun045512 小时前
MessageUtils.message(“user.jcaptcha.expire“)
java
与遨游于天地2 小时前
AI的细胞哲学:从单体闭环到协同进化生态
人工智能
数据知道2 小时前
claw-code 源码详细分析:子系统目录地图——几十个顶层包如何用五条轴(会话 / 工具 / 扩展 / 入口 / 桥接)读懂?
服务器·python·ai·claude code