ClaudeCode: 怎么规划任务
在claude code源码当中,当用户下达任务后,会由plan agent进行任务拆解,但是当任务复杂并且拆解的任务数量过多时,模型非常容易忘记后续的任务,因此一个行之有效的方法就是设置一个TodoManager,强制让AI大模型将任务转化为todo list,然后再调用大模型进行下一步的规划。
核心思想
- LLM绑定工具,包括文件读写,执行命令,编辑文件,以及任务更新等
- 使用TodoManager让模型自己管理任务状态(待办/进行中/完成)
- 模型连续3轮不更新任务-> 自动注入提醒
- 全程不写四执行步骤,模型自主规划,自主推进
核心创新点
模型自己追踪进度,而不是程序硬编码流程
nag reminder提醒机制,3轮不更新todo就强制提醒
同一时间只能有一个任务进行,防止模型发生混乱
流程分析
下面我们来分析一下流程:
- 如果超过三次没有调用todo工具,则直接在
messages中插入一条提醒消息, 并计数归零
ifrounds_since_todo>=3:# 将提醒作为一条独立的 user 消息注入messages.append({"role":"user","content":"<reminder>Update your todos.</reminder>"})# 注意:注入提醒后,计数器重置为 0 或保持?原逻辑没有重置,这里保持原样:# 提醒只是附加消息,不影响计数,但为避免无限提醒,可以重置 rounds_since_todo = 0# 建议根据需求调整,以下重置为 0 更合理:rounds_since_todo=0- 当大模型接受到这条最新的消息后,则会调用
todo工具,其中todo工具的distpatch map是这么定义的:
{"name":"todo","description":"Update task list. Track progress on multi-step tasks.","input_schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"status":{"type":"string","enum":["pending","in_progress","completed"]}},"required":["id","text","status"]}}},"required":["items"]}},从代码中我们可以看出,大模型会返回一个items列表,该任务列表中会详细列举任务的id,text,状态
然后我们看一下当大模型返回todo列表后,程序会遍历items, 检查是否所有的to do list是否合法,以及当前输入in_progress的任务是否只有一个,如果都符合要求,则进行render。 将render后的字符串组转成消息,发送给大模型,进行下一轮的任务。
这里提一下render的规则:
如果是pending任务: 渲染成: [ ] #item_id #item[text]
如果是in_progress任务: 渲染成: [>] #item_id #item[text]
如果是completed任务: 渲染成: [x] #item_id #item[text]
defupdate(self,items:list)->str:iflen(items)>20:raiseValueError("Max 20 todos allowed")validated=[]in_progress_count=0fori,iteminenumerate(items):text=str(item.get("text","")).strip()status=str(item.get("status","pending")).lower()item_id=str(item.get("id",str(i+1)))ifnottext:raiseValueError(f"Item{item_id}: text required")ifstatusnotin("pending","in_progress","completed"):raiseValueError(f"Item{item_id}: invalid status '{status}'")ifstatus=="in_progress":in_progress_count+=1validated.append({"id":item_id,"text":text,"status":status})ifin_progress_count>1:raiseValueError("Only one task can be in_progress at a time")self.items=validatedreturnself.render()//reader函数defrender(self)->str:ifnotself.items:return"No todos."lines=[]foriteminself.items:marker={"pending":"[ ]","in_progress":"[>]","completed":"[x]"}[item["status"]]lines.append(f"{marker}#{item['id']}:{item['text']}")done=sum(1fortinself.itemsift["status"]=="completed")lines.append(f"\n({done}/{len(self.items)}completed)")return"\n".join(lines)