Plan 的前端呈现——进度条还是设计文档?

2026-10-05·编排与协作·Plan 系统
同一份 Plan 数据,在编程工具中是代码变更追踪器,在对话助手中是任务进度条,在企业平台中是部门工作流仪表板。前端呈现不只是'渲染一个列表'——事件 payload 的丰富度决定了前端能力的上限,而进度显示的准确性直接影响用户对 Agent 的信任。
Plan 给谁看?
前面三篇文章聚焦引擎内部——Plan 解决什么问题、为什么从 DAG 退回线性清单、步骤状态机有多复杂。但引擎产出的 Plan 数据最终要到用户面前。
"Plan 长什么样"不是前端问题,是产品定义问题。 因为它直接决定了:
- 用户对 Agent 工作的信任程度——"我知道它在做什么" vs "它在黑箱里不知道干嘛"
- 用户的干预时机——什么时候该让它继续、什么时候该喊停
- 用户的期望管理——进度条显示 3/5 但实际已经完成了 4/5(或者反过来)
截至本文写作时,主流 AI Agent 产品对 Plan 的呈现差异巨大——从"完全不显示"到"四层可视化"。这些差异不是审美偏好,是对"Agent 和用户关系"的不同理解。

五种产品的五种选择
Cursor:四层可视化,Plan 是协作产物
Cursor 对 Plan 的视觉投入在截至本文写作时的 AI 编程工具中是最高的:
第一层:对话内 Todo 组件 Agent Mode 执行时,对话流中嵌入一个带 checkbox 的步骤列表。用户在对话过程中直接看到步骤状态变化——哪些完成了、哪些在进行中。
第二层:Plan 文件编辑器 .plan.md 文件在 Cursor 中有自定义渲染——YAML frontmatter 的 todos 被解析为带状态图标的任务列表,body 部分用 Markdown 渲染。这相当于一个内嵌的项目管理视图。
第三层:Plan 文件浏览 ~/.cursor/plans/ 目录下的历史 Plan 文件可以浏览、搜索。命名规范 {slug}_{hash}.plan.md 让用户能回溯过去的决策。Plan 完成后不删除——长期保留为设计决策记录。
第四层:Plan Mode 入口 Shift+Tab 切换到 Plan Mode。UI 状态的切换建立用户的心理预期:"接下来是讨论方案,不是执行。"
核心设计决策:Cursor 把 Plan 当作协作产物——不只是模型对自己说的话,是模型和用户之间的对话结果。用户可以编辑 Plan 中的 todo 项、修改分析文本、然后让 Agent 按修改后的 Plan 执行。这是 Plan 作为"用户和 Agent 之间的契约"的最直观体现。
Claude Code:无显式 Plan UI,活动流就是进度
Claude Code 没有 Plan 进度条。用户看到的是工具调用的实时活动流——模型在读哪个文件、在运行什么命令、在写什么代码。
这个设计选择有它的逻辑:如果模型足够可靠,用户需要的不是"还剩几步",是"它现在在做什么"。活动流回答了后一个问题。
Claude Code 的 Plan 子 Agent 产出的分析不以独立 UI 呈现——它作为子 Agent 的返回值融入主对话流。用户如果想回顾 Plan 内容,需要在对话历史中寻找。
优势:界面极简,信息噪声低。 劣势:长任务中(200+ 轮),用户失去了"全局视角"——不知道还有多少工作、已经完成了什么比例。
OpenAI Codex:Plan 是可转移的蓝图
Codex 的 Plan UI 在 TUI(终端 UI)中以 checklist 形式渲染。模型在 Plan Mode 中产出 <proposed_plan> 标签块,TUI 解析后渲染为结构化列表。
独特之处在于 Plan 审批弹窗(Plan Mode approval popup)——Plan 完成后弹出选项:
- 在当前上下文中实施:直接进入执行阶段
- 清空上下文后实施:清掉当前对话历史,在全新会话中只注入 Plan 文本
第二个选项意味着 Plan 被当作可转移的蓝图——它必须自包含到另一个 Agent(即使是同一个模型在新会话中)也能理解和执行。
这对 Plan 的质量提出了更高要求——如果 Plan 中引用了"上面讨论过的 X"而没有说明 X 是什么,清空上下文后执行的 Agent 就会困惑。
GitHub Copilot Workspace(已退出):最"工程化"的 Plan UI
GitHub Copilot Workspace(2024-2025 年技术预览,2025 年 5 月停止)有截至本文写作时最工程化的 Plan UI:
- Topic:一个问题形式的任务总结
- Current Specification:代码库当前状态的结构化描述
- Proposed Specification:变更后应该达到的状态
- Plan:要修改/创建/删除的文件列表,每个文件附带具体步骤
- Implementation Preview:每个文件的代码 diff 预览
每一步都可以编辑和重新生成。Plan 步骤直接关联到文件变更。
虽然 Copilot Workspace 已经演进为 Copilot Coding Agent(更自主、更少人工干预),但它的 spec → plan → implementation 流程思想被保留了——只是不再对用户可见。
启示:过于详细的 Plan UI 可能和自主性矛盾——用户花在审阅 Plan 上的时间可能比 Agent 执行任务的时间还长。Copilot Workspace 的退出可能部分反映了这个问题。
Devin:Planner 面板,漂亮但可能误导
Devin 有一个专门的 Planner 面板——左侧时间线显示步骤状态、右侧预览关联的代码变更。视觉上很精致。
但 Answer.AI 的评测指出了一个微妙的问题:进度条给人"它在推进"的幻觉。在 14/20 任务失败的评测中,Devin 的 Planner 面板一直在"更新步骤"——但实际上模型在追逐不可能的方案。用户看到步骤状态在变化(pending → in_progress → failed → retry),以为 Agent 在取得进展,实际上是在同一面墙前反复撞头。
教训:进度显示如果不准确,比没有进度显示更有害。 错误的进度条消耗的是用户的信任——当用户发现 3/5 的进度实际上是 0/5 的假象后,他们不会再信任进度条的任何状态。

事件 payload 决定前端能力上限
前端能渲染什么,完全取决于引擎通过事件系统发送了什么。这不是前端问题——是引擎 API 设计问题。
早期:太薄的事件
我们的 Plan 系统最初的事件 payload 只有:
{
"type": "plan_updated",
"step_id": "step-3",
"status": "done"
}
前端能做的事:渲染一个 checkbox 列表,步骤 3 从空框变成勾选框。
前端做不到的事:显示 Plan 的整体分析、显示每个步骤的详细描述、显示已完成步骤的结果、显示 Plan 的整体进度百分比(因为不知道总步骤数的变化)。
中期:补了字段但格式不统一
补了更多字段后出现了新问题——流式事件和轮询端点的格式不一致。
流式事件(SSE 推送)中步骤状态用 "done",轮询端点(HTTP GET)中同一步骤状态返回 "completed"。前端不得不维护一个映射表来统一两种来源。
这不只是命名问题——它意味着前端需要知道数据来自哪个通道,才能正确解析。当前端开发者不知道有两个数据源时(比如新加入团队的成员),他们可能只对接了一个通道,另一个通道的状态变化就被静默丢弃了。
最终:足够丰富的事件
经过多次迭代,Plan 相关的事件最终包含了:
| 事件 | 关键 payload | 前端用途 |
|---|---|---|
| plan_created | 完整 Plan 结构 + overview | 渲染初始 Plan 视图 |
| plan_updated | step_id + status + result | 更新步骤状态 + 显示步骤结果 |
| plan_completed | total_steps + done_steps | 最终统计 |
| plan_interrupted | reason + termination_detail | 中断原因展示 |
其中一个关键修复:plan_updated 事件的 result 字段,前端最初只读 detail(步骤描述),丢弃了 result(步骤执行结果)。一个字段名的选择差异导致前端丢了步骤的核心产出。修复是双读兜底——detail ?? result。

进度显示的准确性问题
分数 vs 百分比
Plan 的进度应该用分数(3/5)还是百分比(60%)?
我们选了分数。原因:
- 步骤数在运行中会变:模型可能追加新步骤或跳过某些步骤。百分比的分母不稳定——用户看到进度从 60% "倒退"到 50%(因为新增了步骤)会困惑。
- 分数传达更多信息:3/5 告诉用户"总共 5 步、完成了 3 步",60% 只告诉用户"完成了六成"。前者让用户能判断"还有多少工作量",后者不能。
- Cursor 的做法一致:Cursor 的 todo list 显示的是 checkbox 列表,每个步骤独立可见。这本质上就是分数形式。
"运行中" vs "已完成"的 UI 区分
一个微妙但重要的 UI 决策:Plan 步骤是否需要区分"正在执行中"和"已完成"?
- 三态模型(pending / in_progress / done):渲染为空圈 / 旋转动画 / 勾选。用户能看到"Agent 现在在做哪一步"。
- 二态模型(未完成 / 已完成):渲染为空圈 / 勾选。更简洁但信息更少。
我们选了三态——因为在长任务中,"Agent 现在在做哪一步"是用户最常关心的问题。这个信息帮助用户判断"是否需要等"和"是否需要干预"。
Plan 终态的视觉差异
Plan 有四种终态(planning / active / completed / terminated),前端需要为每种终态提供不同的视觉反馈:
| 终态 | 视觉表现 | 用户行动引导 |
|---|---|---|
| completed | 绿色勾选 + "任务完成" | 查看结果、开始新任务 |
| terminated (run_interrupted) | 橙色警告 + "任务中断" | 了解中断原因、决定是否恢复 |
| terminated (nudge_exhausted) | 橙色警告 + "进度卡住" | 检查被卡步骤、手动干预 |
| terminated (validation_failed) | 红色 × + "验证失败" | 检查失败原因、修正后重试 |
一个常见的前端反模式是:所有错误共用同一个红色 "Error" 样式 + "重试"按钮。 但 guardrail 拦截、预算用尽、安全策略阻止——这些重试同样输入只会得到同样结果。正确的做法是区分可重试错误(provider 瞬时故障)和不可重试错误(策略拦截),后者显示引导文案而非重试按钮。
同一引擎、四种产品、四种渲染
同一个 Plan 引擎事件,在四种产品中渲染为完全不同的 UI。这是"引擎和应用分离"的直观体现。
编程工具(编程工具):Plan 关联代码文件
编程场景中,Plan 的每个步骤通常对应一组文件变更。前端把步骤和文件关联起来:
- 步骤描述中提到的文件路径自动链接到编辑器
- 步骤完成后,关联文件的 diff 在编辑器中高亮
- Plan 面板可以和代码编辑器并排显示
这和 GitHub Copilot Workspace 的理念类似——Plan 不只是文本列表,是文件变更的组织者。
对话助手(桌面助手):Plan 是任务进度
对话场景中,Plan 是对话流中的一个嵌入组件。用户在对话过程中看到 Plan 的进度变化。
关键设计:Plan 组件不能遮挡对话——它是对话的一部分,不是一个独立的面板。通常渲染为一个可折叠的卡片:展开显示所有步骤和状态,折叠只显示 "3/5 完成中"。
信息工作台(信息工作台):Plan 是项目管理视图
工作台场景中(知识管理、文档编辑),Plan 更接近传统的项目管理工具——步骤有描述、预估时间、完成条件。前端渲染为看板或时间线视图。
企业平台(企业版):Plan 是部门工作流
企业场景中,一个 Plan 可能涉及多个员工的协作。前端需要显示:
- 谁发起了这个任务
- 当前执行者是谁
- 哪些步骤需要人工审批
- 部门级的统计(本周完成了多少个 Plan、平均耗时多少)
同一份引擎事件数据,通过不同的前端解读,服务了从个人编程到企业管理的完整光谱。
进度条如何建立(或摧毁)信任
回到最开始的问题:Plan 的前端呈现为什么重要?
因为它是用户判断"这个 Agent 是否可靠"的主要信号。
信任建立三要素
- 透明性:用户能看到 Agent 在做什么(活动流 + Plan 步骤状态)
- 准确性:显示的进度和实际进度一致(分数不虚报、终态不遗漏)
- 可干预性:用户在需要时能介入(中断、修改 Plan、跳过步骤)
三者缺一不可。Claude Code 的无 Plan UI 牺牲了部分透明性(长任务中的全局视角),但通过活动流保持了实时透明。Devin 的 Planner 面板有透明性,但准确性不足(追逐不可能方案时进度条仍在"推进")。
信任摧毁是不可逆的
一个用户看到 Plan 显示 0/14 但 Agent 其实完成了 9/14 的工作(我们 auto-verify Bug 的症状),他不会想"哦进度条有 Bug"——他会想"这个 Agent 什么都没做"。
修完 Bug 之后,进度条恢复正常了。但用户的信任已经损失了——他需要多次准确的进度显示才能重建信心。
在 Agent 产品中,进度显示的准确性是产品可靠性的代理指标。 用户无法直接评估引擎的内部质量(代码覆盖率、不变量数量),但他们能直接看到进度条是否准确。
一个总结表
| 维度 | Cursor | Claude Code | Codex | Copilot Workspace(已退出) | Devin |
|---|---|---|---|---|---|
| Plan 可见性 | 四层可视化 | 无显式 Plan UI | TUI 清单 + 审批弹窗 | 五步 spec→plan→impl | Planner 面板 |
| 用户可编辑 | ✅ Plan + todos 均可编辑 | ❌ | ✅ 审批前可修改 | ✅ 每步可编辑重生成 | 有限 |
| 持久化 | .plan.md 永久保留 | 子 Agent 返回值(非持久化) | 可存文件 | PR 即持久化 | Session 级 |
| 跨会话引用 | ✅ 可读取历史 Plan | ❌ | ✅ 清空上下文实施 | ✅ PR 链接 | ❌ |
| 进度准确性 | 高(步骤级 checkbox) | N/A(无进度条) | 高 | 高 | 存疑(可能误导) |
| 核心隐喻 | 协作文档 | 活动流 | 可转移蓝图 | 工程变更单 | 项目面板 |
每种选择都有合理的产品理由。没有最好的 Plan UI——只有最适合特定用户和场景的。
但有一条普适原则:如果你选择显示进度,就必须保证进度准确。 不准确的进度比没有进度更有害——因为用户会基于错误信息做出错误判断(等待一个永远不会完成的 Plan、或者中断一个即将完成的 Plan)。
你现在能做什么
1. 进度用分数(3/5),不用百分比(60%)。 步骤数在运行中会变(追加/跳过),百分比的分母不稳定——用户看到进度从 60% "倒退"到 50% 会困惑。分数传达更多信息。
2. 区分"可重试"和"不可重试"错误。 Agent 因策略拦截停止 → 不显示重试按钮(重试同样输入只会得到同样结果)。Agent 因网络超时停止 → 显示重试按钮。一个通用的"重试"按钮在不可重试场景中是误导。
3. 如果你选择显示进度,就必须保证进度准确。 不准确的进度比没有进度更有害——用户基于错误信息做出错误判断。不确定时宁可不显示进度,也不要显示假进度。
4. Plan 事件的 payload 要足够丰富。 如果你在设计 Agent 的事件系统——Plan 事件至少需要:步骤 ID、状态、结果文本、总步骤数、已完成数。"只有步骤 ID 和状态"的事件让前端只能做 checkbox 列表,做不了更有信息量的渲染。
引用来源
- Cursor Blog, "Introducing Plan Mode" — https://cursor.com/blog/plan-mode
- Cursor Docs, "Plan Mode" — Plan Mode | Cursor Docs
- Claude Code 官方文档, "Create custom subagents" — Create custom subagents - Claude Code Docs
- OpenAI Codex PR #17499, "clear-context plan implementation" — feat(tui): add clear-context plan implementation by fcoury-oai · Pull Request #17499 · openai/codex · GitHub
- GitHub Copilot Workspace User Manual — GitHub - githubnext/copilot-workspace-user-manual: 📖 The user manual for GitHub Copilot Workspace · GitHub
- QWE AI Academy, "GitHub Copilot Workspace Planning: From Issue to Plan" — GitHub Copilot Workspace Planning: From Issue to Plan [2026] | QWE AI Academy
- Answer.AI Devin evaluation — The Register (Jan 2025)
- Qubika, "Devin AI review" — https://qubika.com/blog/devin-ai-coding-agent/
Plan前端渲染产品设计SSE
更多推荐


所有评论(0)