Agent 工作流的 Preview & Trajectory 渐进式披露
学习目标
- 理解 Preview & Trajectory 模式在 Agent 长工作流中的价值
- 掌握三层持久化模型(Bundle / Session / Trajectory)的设计
- 应用 Producer/Consumer 角色分离原则
- 设计 Agent-Cheap 的
preview live status --json接口
前置知识
本章涉及 Agent 工作流渐进式披露的通用模式,建议先阅读:
下文假设你已理解上述概念,直接聚焦 CLI-Anything 的具体实现。
项目实践
为什么需要 Preview
Agent 操作 Blender 建模、FreeCAD 设计零件、Kdenlive 剪辑视频——这些是可能耗时数十分钟的长工作流。如果 Agent 完成所有步骤后才发现第一步就错了,代价巨大。
CLI-Anything 的 Preview 机制解决了这个问题:
preview_bundle.py 共享协议
preview_bundle.py(~500 行)是跨所有 Harness 的共享 Preview 协议实现(preview-bundle/v1):
Bundle 目录结构:
bundle_003/├── manifest.json # 元数据:时间戳、命令、源指纹├── render.png # 渲染产物├── summary.json # 摘要:命令、关键属性└── artifacts/ # 额外产物三层持久化实现
| 对象 | 可变性 | 用途 |
|---|---|---|
bundle_dir | 不可变 | 每次 capture 的快照,一旦发布不再修改 |
session.json | 可变 | Live Preview 的当前头,指向最新 Bundle |
trajectory.json | 追加式 | 命令 → Preview 的完整历史,可回放 |
关键设计:_bundle_dir 不是永久的构建身份——它是单点快照路径,会随源指纹变化而改变。稳定的回放身份锚定在 session_dir + trajectory.json。
Producer/Consumer 角色分离
CLI-Anything 严格分离了两个角色:
| 角色 | 命令 | 能力 |
|---|---|---|
| Producer | cli-anything-<software> preview capture | 与后端对话、渲染、发布 Bundle |
| Consumer | cli-hub previews inspect/watch/open | 读取已发布的 Bundle、展示给人类 |
Consumer 不渲染、不回放、不合成预览制品——它只读取 Producer 已发布的状态。这个分离防止了消费者误以为自己在渲染。
Live Preview 语义
FreeCAD 和 Blender 的 Harness 展示了完整的 Live Preview 实现:
# 启动 Live 会话cli-anything-freecad preview live start --name rover-design
# 每次操作后推送 Previewcli-anything-freecad chassis build --wheels 6cli-anything-freecad preview live push --reason "chassis built"
# 轻量状态探测(Agent 高频调用)cli-anything-freecad preview live status --jsonpreview live status --json 返回紧凑摘要(trajectory_summary),让 Agent 无需读取整个 trajectory.json:
{ "active": true, "session_dir": "/path/to/session_001", "trajectory_summary": { "total_commands": 42, "latest": { "command": "chassis build", "bundle": "bundle_007", "timestamp": "2026-05-31T10:45:00Z" } }}真实性原则
HARNESS.md 强调:
Truthful previews matter more than pretty previews. Agents need intermediate state they can trust when deciding what to do next.
CLI-Anything 的 Preview 实现遵守:
- 使用真实后端渲染(Blender render、FreeCAD export)
- 禁止 Python 伪造渲染
- 禁止屏幕抓取 GUI 窗口
- 如果注入临时相机/灯光辅助渲染,在 Bundle 状态中标注
实战案例
FreeCAD Curiosity Rover 演示(README 中的演示 GIF):
- Agent 逐步组装火星车模型
- 每个步骤发布 Preview Bundle(Blender 渲染的 PNG)
preview live追踪当前设计状态trajectory.json记录完整的设计历史- 最终产出可通过轨迹完整回放
问题与规避
| 问题 | 规避策略 |
|---|---|
| Agent 频繁读取 trajectory.json 浪费 Token | preview live status --json 返回紧凑 trajectory_summary |
_bundle_dir 被当作永久身份 | 稳定回放锚定 session_dir + trajectory.json |
| Consumer 被误用为渲染路径 | 文档和 HARNESS.md 严格分离角色 |
| Preview 伪造导致 Agent 误判 | 坚持真实性原则,所有 Preview 来自真实后端 |
| 源指纹变化后旧 Preview 仍被引用 | 源指纹变化时强制重新 capture |
设计取舍
Preview 为可选而非必须
选择:Preview 支持是可选的,Harness 可以不实现。
原因:不是所有软件都有”可视化中间状态”。例如 Zoom CLI(API 调用)或 Eth2 QuickStart(节点管理)没有视觉产出。
何时应实现:当软件产生”有意义的可预览中间状态”时(3D 模型、视频帧、图像、设计图)。
poll-first vs push-first
Live Preview 支持两种刷新模式:
- push-first:每次 mutation 后主动 push(默认,准确但可能有延迟)
- poll-first:后台轮询检测变化(适用于无法精确 hook 的场景)
CLI-Anything 默认 push-first,因为 Harness 控制 mutation 流程,可以精确知道何时需要 capture。
参考来源
- 源码验证:
preview_bundle.py(~500 行) - 源码验证:
HARNESS.mdPreview & Live Preview Norms 章节 - 源码验证:
guides/preview-methodology.md设计指南 - 源码验证:FreeCAD/Blender Harness 中的 preview 命令实现