Plan 系统
wescode 中的 Plan 系统——LLM 驱动的线性任务清单,用于管理多步骤任务。
Plan 概念
Plan 是 LLM 驱动的线性任务清单(不是 DAG):
Plan: "重构 UserService"
1. [done] 分析现有 UserService 接口
2. [in_progress] 拆分 CRUD 和业务逻辑
3. [pending] 更新调用方
4. [pending] 添加测试
5. [pending] 更新文档
核心原则
- LLM 驱动:引擎不自动推进步骤,模型决定一切
- 线性清单:执行顺序 = 数组顺序,无依赖图
- 引擎不伪造完成:Run 结束时 pending 步骤保留原状
Plan 工具
模型通过 plan 工具管理 Plan:
plan(create)
{
"tool": "plan",
"action": "create",
"title": "重构 UserService",
"steps": [
"分析现有 UserService 接口",
"拆分 CRUD 和业务逻辑",
"更新调用方",
"添加测试",
"更新文档"
]
}
plan(update)
{
"tool": "plan",
"action": "update",
"task_id": 0,
"status": "done",
"result": "UserService 有 12 个公开方法,其中 5 个是纯 CRUD"
}
plan(complete)
{
"tool": "plan",
"action": "complete"
}
complete 会收口所有剩余 open 步骤为 done。
PlanStatus 枚举
| 状态 | 含义 | 允许的迁移 |
|---|---|---|
planning | 初始/草拟 | → active |
active | 正在执行 | → completed / terminated |
completed | 模型声明完成 | → terminated(中断时) |
terminated | 被终止 | → completed(恢复后完成) |
状态迁移函数
ApplyCompletion(plan) // → completed(合法迁移)
ApplyTermination(plan, reason) // → terminated(合法迁移)
TerminationReason
| 原因 | 触发方式 |
|---|---|
run_interrupted | 用户中断 / 异常终止 |
nudge_exhausted | Nudge 次数耗尽 |
validation_failed | 验证失败 |
注意:terminated → completed 是合法的 resume 迁移(恢复后重新完成)。
Plan 步骤状态
| 状态 | 含义 |
|---|---|
pending | 未开始 |
in_progress | 正在执行 |
done | 已完成 |
skipped | 已跳过 |
实质化验证(INV-PE-15)
步骤标记为 done 需要实质化验证——必须有真实工作发生过:
PlanStep.Substantiated:该步骤在之前的轮次中有非 plan 的工具调用
PlanWorkThisTurn:本轮有非 plan 的工具调用
done 与工作发生过同构:
→ Session ledger 记录每步的 Substantiated 状态
→ execute 开始给全部 open 步骤盖章
→ 盖章对象是全部 open 步骤(禁止 first-pending-only)
→ 记账可以是下一轮
为什么实质化很重要
场景:模型读了几个文件,然后批量 plan(update, done) × 5
→ 如果不验证:模型可以声称完成但实际没做
→ 实质化验证:检查是否真的有非 plan 的工具调用发生过
Plan Nudge 机制
当 Run 准备结束(end_turn)但 Plan 仍有 pending 步骤时,引擎会 nudge 模型继续工作:
Nudge 规则
end_turn + pending 步骤存在 + Plan 未终态
→ 注入提醒消息:继续执行 + 完成即 update 补标
→ 最多 nudge 3 次(maxPlanPendingNudges)
→ 3 次后正常终止,步骤留在 pending
Nudge 内容
nudge 消息包含:
1. pending 步骤列表(带 0-based task_id 索引)
2. 引导"继续执行 + 完成即 plan(update, done)"
3. 显式警告"不要调 plan(complete),它使 pending 无法解决"
Nudge 耗尽
3 次 nudge 用完
→ Run 正常终止
→ 步骤留在 pending(真实进度)
→ 发出 EventPlanNudge(提醒非错误)
Plan 分类
在 CycleDetector 中,plan 工具被分类为 categoryExploration(探索类):
// plan 在 toolCategoryMap 内置分类为 categoryExploration
// 意味着:探索预算 + 进度减半
// 合法的多步更新不会触发 action streak
应用层不得重复声明 ExtraCategories/progressAwareTools(冗余声明 = 同源尾巴)。
Plan 与 CognitiveSettlement
Plan 是 SessionState 的子字段(INV-CTX-46):
Run 结束
→ CognitiveSettlement
→ SessionState 持久化
├── 对话摘要
├── 关键事实
└── Plan 状态(steps + status + progress)← 子字段
Plan 状态不独立持久化——随 CognitiveSettlement 一同存储。
Plan 中断与恢复
中断
Run 异常终止时(非 end_turn + 有 pending 步骤):
ApplyTermination(plan, "run_interrupted")
→ PlanStatus = terminated
→ TerminationReason = run_interrupted
→ EventPlanInterrupted 事件发出
恢复
下次 Run 开始时,terminated 状态的 Plan 可以恢复:
新 Run 开始 → 读取上次 SessionState
→ Plan.Status == terminated
→ 模型可以继续执行 pending 步骤
→ plan(complete) → ApplyCompletion → completed
terminated → completed 是合法的 resume 迁移。
Plan 补标(INV-PE-14)
Plan 处于 completed 状态时,仍允许步骤终态补标(done/skipped):
模型先做了多步 read/grep/exec
→ plan(complete)
→ 还有步骤是 pending
→ 可以继续 plan(update, task_id=2, status=done) 补标
PlanTerminated 状态则保持锁定,不允许补标。
最佳实践
- 让 AI 自然使用 Plan:不需要手动创建
- 关注 Plan 面板:实时查看任务进度
- 相信实质化验证:0/N 进度可能只是显示延迟
- 理解 Nudge:AI 会被提醒继续,但最终决定权在 AI