Skip to main content

作用

Plan Mode 让 agent 在动手前先”把意图想清楚 + 写下来”再执行。开启后 agent 进入一个只读阶段
  • 只能调用只读工具和 4 个白名单工具:plan_enter / plan_write / plan_exit / todo_write(shell 可按需放开,见下文);
  • 其它工具调用一律被拒绝(agent 看到一条”plan 阶段拒绝”提示);
  • 退出 Plan Mode 走 HITL 确认(复用权限系统的 ASK),避免模型一意孤行直接进入执行。
这条流程明确把”设计 → 写计划 → 人确认 → 执行”四步固化下来,配合 todo_write 与子 agent,能在长任务里有效降低”边想边改、改坏一片”的概率。

开启

Builder 选项: 也可以同时打开 enableTaskList(),让 plan 阶段里写的 todos 在每次推理前以小提示形式给 agent 看一遍。

三个工具

plan_write专门为 Plan Mode 设计的写入入口——避开了把通用 write_file 加入白名单的安全风险(后者会让模型在 plan 阶段写任意文件)。

工作流

中间任意时刻调用非白名单工具(比如 write_fileexecute 默认也被拒,除非你按需放开)都会被即时拒绝并返回类似这样的结果给模型:
模型看到拒绝信息会自然地切回”先写计划”。

如何判断运行结果

是否进入 plan mode 由模型自主决定,所以一次运行可能落到四种终态。只看 isPlanModeActive() == false 是有歧义的——别在没确认”是否真的规划过”之前就当成成功: 要在代码里区分这几种,可在监听最终 isPlanModeActive() 和计划文件是否存在的同时,记录是否调用过 plan_enter / plan_write(例如从 ToolCallStartEvent 捕获)。

在 plan 阶段放开 shell(可选)

默认情况下,shell 工具(execute)在 plan 阶段是被拒绝的。shell 是双用途工具:同一次调用既可能是读(cat / ls / grep / git log),也可能是写(rm / > / git commit / npm install),而 Plan Mode 完全靠工具名判定是否放行——无法区分这一次是读还是写。默认禁掉 shell,是为了保住”只读”这条保证。 但通过 shell 读取各种内容,往往是调查代码库、产出一个切实可行计划的最灵活方式。如果你愿意承担这个取舍,可以按需放开:
开启后:
  • execute 被加入 plan 阶段放行名单,模型可以用 shell 做调查;
  • plan banner 会追加一条提示,要求模型把 shell 用法限制在只读cat / ls / grep / git log/diff/show/status),在计划获批前不要跑 mutating 命令;
  • 专用的文件编辑工具(write_file / edit_file仍然被拒——它们是主要的改动入口,所以对文件写入的只读意图依然被强制保证。
这与 OpenCode 处理其 plan agent 的方式一致:放开 shell 用于调查、硬禁 edit/write 工具、靠提示词把 shell 约束为只读。因此这条保证比默认情况更弱(模型仍可能通过 shell 改东西),建议配合沙箱文件系统一起开,把爆炸半径关进沙箱。

运行期切换权限模式(“危险开关”逃生口)

Plan Mode 只是一个具体的阶段开关。在它之下,每个 session 都带着一个 PermissionMode,由权限引擎在评估时使用。你可以在运行期翻转这个 mode——比如提供一个由用户显式触发的”跳过所有权限确认”开关(类似其它编码工具里的 YOLO / dangerous-skip 开关):
setPermissionMode(...) 会保留该 session 已配置的 allow/deny/ask 规则与工作目录——只改 mode——并重建该 session 缓存的权限引擎,使切换在下一次 call 生效;正在进行中的 call 仍沿用它启动时的引擎。 BYPASS 会关闭所有规则评估,因此应当作为显式的、按 session 的主动操作,并建议配合沙箱使用。如果想要无人值守且不弹确认、但仍保留管控,请改用 PermissionMode.DONT_ASK(ASK 决策会变成 DENY,而不是被自动放行)。

Plan 阶段的状态会被持久化

Plan Mode 是运行时状态,会随 AgentState 自动持久化——进程重启、节点切换、跨副本恢复后,plan 阶段会一起恢复。计划文件本身写到工作区的 plans/ 下,跟着你选的文件系统模式(本机 / 沙箱 / 远端 KV)走,分布式可用。

程序化进出 Plan Mode

需要在业务代码里主动控制(例如管理台按钮):
如果用了 agentscope-admin-spring-boot-starter,还可以通过 admin HTTP 接口操作(POST /v1/admin/sessions/{id}:enter-plan-mode / :exit-plan-mode / GET /v1/admin/sessions/{id}/plan)。

与子 agent 的关系

⚠ 当前已知缺口:Plan Mode 期间通过 agent_spawn 启动的子 agent 不会自动继承只读限制。如果希望子 agent 也只读:
  • 在子 agent 的声明里把 tools 过滤到只读集合;或
  • 在子 agent 的 builder 里也开 enablePlanMode() 并自行进入
未来版本会让 plan 阶段的限制按父→子自动传播。

todo_write 的协作

Plan Mode 与 todo_write(core 提供)是两个独立但常常一起用的概念:
  • Plan Mode —— 阶段开关 + 计划文件 + HITL 退出
  • todo_write —— 在执行阶段维护”当前要做什么”的结构化清单(全量替换,必须恰好一个 in_progress
典型工作流:plan 阶段写完 PLAN.mdplan_exit → 执行阶段用 todo_write 把 PLAN 拆成 5–8 条 todo → 逐条推进。Agent 每轮推理前能看到 todos 的小提示,帮助保持聚焦。 ⚠ 不要和子 agent 的后台任务task_output / task_cancel / task_list)混淆——那是另一回事,详见 子 Agent

查看任务列表

任务列表保存在 AgentState.tasksContext 中,每次 call() 后自动持久化。在业务代码中读取:
如果用了 agentscope-admin-spring-boot-starter,可以直接调 admin REST 接口:
返回每个任务的 subject、state、owner 和依赖关系(blocks / blockedBy)。 如果需要通过事件流实时感知任务变更,可以在 streamEvents() 中监听 todo_write 工具调用:

相关文档

  • 工作区plans/ 目录的位置
  • 子 Agenttodo_write ≠ subagent task,不要混淆
  • 架构 — Plan Mode 在 call() 时序中的位置