从零实现 GeekAgent —— Day9 任务规划与子 Agent
内容提要
本文介绍GeekAgent第9天开发:为多步骤任务添加TODO清单和子Agent功能。通过todo_write工具让模型规划并更新任务进度,delegate_task将独立子任务交给隔离上下文的子Agent处理。系统指令控制何时规划,强制回写确保进度更新,TUI右栏实时显示TODO状态。实现约113行代码,验证通过。
延伸解读
TODO 清单的设计取舍
本文选择整表重写而非拆分增删改工具,理由是避免模型维护编号协议,且清单通常较短,重写成本低。校验集中在入口,不合格则整张退回,防止半份计划上屏。这种设计简化了工具协议,但要求模型每次从历史中重建完整清单,对模型的上下文利用能力有一定依赖。
子 Agent 的隔离与回写机制
子 Agent 通过不带主历史的独立请求执行,只返回结论,避免挤占主上下文。但委派期间主 Agent 的 TODO 可能停滞,因此强制在委派后下一轮调用 todo_write 回写进度。这种设计保证了进度一致性,但子 Agent 无工具且串行执行,适合边界清晰的分析任务,不适合需要多步操作或并行的场景。
强制规划与自由执行的平衡
系统指令规定多步骤任务先规划,简单任务直接回答,避免不必要的 TODO 调用。同时通过关键词检测和委派后强制回写,确保关键节点不遗漏。这种混合策略在灵活性和可靠性之间取得平衡,但关键词匹配可能误判或漏判,实际效果依赖指令设计和模型遵循能力。
Q&A
GeekAgent Day9 新增了哪两个工具?它们分别解决什么问题?
新增了 todo_write 和 delegate_task 两个工具。todo_write 让模型把多步骤任务写成可勾选的清单并更新进度,解决进度不可见的问题;delegate_task 将独立子任务交给隔离上下文的子 Agent 处理,避免分析过程占用主对话上下文。
todo_write 工具是如何工作的?为什么采用整表写入而不是增删改?
todo_write 要求模型每次调用时提交完整的 TODO 列表,todos.ts 校验后覆盖保存,并通过 onChange 通知 TUI 刷新右栏。采用整表写入是因为清单通常较短,整表重写 token 开销小,且省去维护编号的复杂性;校验失败会整张退回,旧表保留。
delegate_task 子 Agent 的上下文是如何隔离的?它有什么限制?
delegate_task 执行时,子 Agent 的请求只包含 system 指令和任务描述两条消息,不携带主 Agent 的历史,实现上下文隔离。子 Agent 没有工具可用,不能继续委派,也不能直接修改 TODO,只负责返回结论,由主 Agent 继续执行。
GeekAgent 如何强制模型在委派后更新 TODO 进度?
在委派返回后的下一轮,通过 tool_choice 将请求强制指定为 todo_write,迫使主 Agent 调用 todo_write 更新进度,而不是依赖模型自觉。
系统指令在任务规划中起什么作用?如何判断是否需要规划?
系统指令规定:多步骤任务先规划再执行,简单任务直接回答。同时通过正则匹配用户输入中的关键词(如“todo”、“任务清单”、“然后”等)来强制第一轮调用 todo_write,其余情况由模型自行决定。
TODO 状态是如何实时显示在 TUI 右栏的?
todos.ts 在保存新表后调用 onChange 回调,入口将回调接到 TUI 的 updatePanel(),从而刷新右栏。右栏和 /todos 命令都读取同一个 formatTodos() 函数,保证显示一致。
Day9 的代码改动量是多少?主要涉及哪些文件?
Day9 源码相对 Day8 新增 123 行、删除 10 行,净增 113 行。主要涉及 todos.ts(新增)、chat.ts(新增 delegate 方法和系统指令)、permissions.ts(添加新工具权限)、index.ts(接入 TUI 和 /todos 命令)。
Day9 没有实现哪些功能?
没有实现 TODO 持久化(不跟随会话切换)、子 Agent 不能调用工具或继续委派、没有并行调度和失败重试。