# 三行速读
- 这章把工作目标从会话内 todo 升级成持久任务图。
- 关键是依赖关系:谁阻塞谁、谁解锁谁。
- 任务状态能跨会话延续,是后续运行时与团队协作基础。
# 先修知识
- 已理解 s03 todo 的会话内边界。
- 知道 JSON 持久化与状态同步基本逻辑。
# 读完后你应该能做到(可检验清单)
# 本篇要解决什么
s03 的 todo 只适合会话内计划。s12 要解决的是跨会话、跨阶段的工作协调:任务需要持久化,并且要有依赖关系。
核心变化:从 “临时清单” 升级为 “持久任务图”。
# 用一个类比先理解
把 todo 当便签,把 task 当项目管理系统:
- 便签能提醒你现在做什么;
- 项目系统能记录谁依赖谁、谁完成后解锁谁。
这就是 s12 的定位。
# 为什么这一步必须现在做
后续要做后台执行、调度、多 Agent 认领,没有持久任务图就无法稳定协作。s12 是运行时阶段的基座。
# 关键代码怎么读
# 1) TaskManager 落盘模型
1 | class TaskManager: |
任务状态写入 .tasks/task_*.json ,会话结束也不会丢。
# 2) 任务字段设计
1 | task = { |
blockedBy/blocks 是依赖图关键字段,不是装饰。
# 3) 完成任务触发解锁
1 | if status == "completed": |
完成不是只改自己状态,还会影响下游节点是否可执行。
# 4) 任务工具接入统一 loop
1 | TOOL_HANDLERS = { |
任务系统与基础文件工具共用一个调用管道,架构一致性很好。
# 你可以怎么复现
- 建三个有依赖的任务(A -> B -> C)。
- 完成 A,观察 B 是否自动解除阻塞。
- 重启会话,检查任务图是否仍在。
# 常见误区
- 误区 1:把 task 当会话临时计划。
- 误区 2:只记录状态,不维护依赖。
- 误区 3:完成任务后不清理下游阻塞。
# 一句话总结
s12 让系统从 “会话驱动” 走向 “工作图驱动”,这是长期执行能力的关键转折。
# 补充解读:任务图的细节行为
# A. _max_id() 保证 ID 连续增长
1 | ids = [int(f.stem.split("_")[1]) for f in self.dir.glob("task_*.json")] |
这让任务 ID 在重启后仍然连续,不会重号。
# B. update() 同时维护双向依赖
1 | if add_blocks: |
这是容易忽略的点:依赖关系要双向同步,不能只改一侧。
# C. list_all() 的可读输出
1 | marker = {"pending": "[ ]", "in_progress": "[>]", "completed": "[x]", "deleted": "[-]"} |
标记化输出虽然简单,但极大提升了任务面板可读性。
# D. task 工具作为 “统一入口”
任务创建、查询、更新都通过工具调用进入 loop,说明任务系统不是旁路模块。
# 进阶练习
- 为任务加
due_date字段,并扩展 list 输出。 - 增加 “循环依赖检测”,防止 A->B->A。
- 增加 “批量解锁报告”,显示一次完成解锁了哪些任务。
# 再补一层:任务图建模的实践建议
# 1) 任务粒度怎么定
一个实用原则:单个任务应当在一次稳定工作块里可完成(比如 30~120 分钟)。过大难追踪,过小会产生大量管理噪音。
# 2) 依赖字段怎么用才不会乱
blockedBy表示 “我依赖谁”。blocks表示 “我解锁谁”。
两者要么双向维护,要么只存一边并动态计算。教学版选择双向,读起来更直观。
# 3) owner 字段什么时候写
建议在 “认领” 那一刻写入,而不是创建时就填。否则任务可能长期显示归属错误。
# 4) deleted 与 completed 的区别
completed: 目标达成。deleted: 目标取消或失效。
这两个状态在统计报表里意义完全不同,别混用。
# 统一术语口径(本章)
Task Record:持久化任务节点(目标对象)。blockedBy:当前任务依赖的前置任务集合。blocks:当前任务完成后可解锁的后置任务集合。
# 章节衔接(从易到难)
- 本章解决 “任务目标持久化”。
- 下一章
s13进入 “运行时执行槽位与后台任务机制”。