面向愿望编程:许愿、拆解和实现

复盘 Android 用量小组件从实现功能到贴合视觉意图的过程,展示如何用具体约束和截图反馈纠正代码代理对需求的误解。

AIAgentCodexHermes编程

我只是想做一个 Android 桌面小组件,让 ChatGPT/Codex 的剩余用量一眼就能看出来。

Codex 很快把它做出来了。

但第一版仍然失败了。

它通过了构建,也实现了百分比展示,却没有符合我的视觉预期,还破坏了原有按钮的可见性。更准确地说,它完成了自己理解的那部分任务,而完整的目标并没有实现。

我给出的要求并不复杂:剩余量要清楚,卡片要保持简洁,刷新按钮要能正常工作。真正的麻烦不在功能数量,而在于“进度效果”究竟应该对应什么对象。

第一版能显示百分比,却没有完成目标

从代码代理的角度看,第一版方案并不荒谬。

它把“让剩余量可视化”理解成:在两个窗口卡片的底部各增加一条独立的进度条,并根据相应的百分比调整长度。第一版界面如下。

第一版小组件:窗口卡片底部加入独立进度条,底部操作按钮不可见

代码能够编译,资源也能正常打包,界面上确实出现了进度效果。但新增的进度条控件挤占了有限的布局空间,导致原本位于底部的“刷新”和“设置”按钮没有出现在小组件的可视区域内。

但我看到之后,还是觉得不对。

我想要的不是“卡片下面多了几根进度条”,而是让整张窗口卡片本身承担进度条的视觉语义。卡片的填充区域代表剩余量,卡片仍然是原来的卡片,不应该凭空多出新的控件。

修改后的界面如下。

修改后的小组件:由窗口卡片本身表达剩余量,底部保留“刷新”和“设置”按钮

回头看,这里其实包含两类问题。

第一类是我没有把意图说清楚。我希望卡片本身表达进度,但第一次任务描述并没有把这个视觉偏好说清楚。独立进度条是合理的候选方案,但不符合我最后确认的选择。

第二类是客观的布局回归。新增控件挤占了空间,使原有按钮不可见。这已经超出设计偏好,属于实现和验收都没有守住原有功能。

所以,“Agent 正确实现了错误理解”只准确描述了第一类问题,不能替代对第二类问题的判断。

两个方案都能表达百分比,却改变了不同的工程对象:前者在窗口卡片中增加独立的 ProgressBar,后者保留原有卡片,只改变内部的填充方式。前者在数据展示层面成立,后者才符合我确认过的视觉要求。

从愿望到可执行任务

“让剩余量一眼能看出来”是一句人话,但它还不足以成为一条可以直接交给代码代理的任务。

如果把它润色成:

请设计一个清晰直观的剩余量展示界面。

事情并不会因此变得更清楚。这只是把一句模糊的话换成了另一句更像需求文档的模糊话。

真正需要解决的是:这个愿望对应哪个工程对象?这个对象是已经确定的设计,还是需要先让我选择的候选方案?

在第一次实现之前,更稳妥的做法是先把方案分开,不急着锁定某一种表达方式:

  • 方案 A:让现有窗口卡片内部承担填充语义;
  • 方案 B:在窗口卡片中增加独立的进度条。

如果我还没有表达明确偏好,协调层应该把它们当成待确认选项,不要擅自把其中一种当成需求本身。

这次是在看见第一版结果后,我才明确说出:不要独立进度条,让原有卡片本身表达进度。这个反馈把一个设计偏好变成了硬约束。

我把这句反馈交回 Hermes 后,它先重新定义了问题:百分比和填充长度都不是重点,真正需要调整的是表达进度的对象。

于是,任务变成了几条具体约束:

保留原有窗口卡片;
卡片本身承担剩余量的填充语义;
填充长度映射剩余百分比;
禁止新增独立进度条;
不改变原有小组件的整体高度;
刷新按钮保持为“刷新”;
在目标小组件尺寸下,“刷新”和“设置”按钮完整可见、可点击;
点击“刷新”后,用量数据按预期更新。

这一步的意义不在于换一种说法,而在于确认任务的对象和边界:已经确定的目标和偏好进入约束,尚未确定的部分继续保留为选项。

这次协作的分工

这次协作里,我没有让 Hermes 代替 Codex 写布局代码。它先处理我的反馈,把“再改一下进度条”变成具体任务;Codex 再在这个边界内实现。

整个过程更接近一条回路:

初步愿望 → 候选方案 → 我的反馈 → 明确约束 → 实现与验收
                         ↑                      │
                         └── 未满足目标时继续调整 ──┘

对应到这次协作,就是:

我表达愿望 → Hermes 整理任务 → Codex 实现

这里的分工不在于谁更“聪明”,而在于谁处理哪一层问题。

Hermes 负责把我的目标和反馈整理成可执行任务,Codex 负责具体实现。对于会显著影响视觉效果、交互方式或返工成本的未定设计,应先提供候选方案让我确认;其余实现细节可以在约束内自主决定。

这次经历不能证明多一个协调 Agent 必然比单个 Coding Agent 更好。它只能说明,需求澄清和验收值得被显式安排。具体是否引入独立协调层,可以按任务复杂度和沟通成本决定。

简单、边界清楚的修改可以直接交给 Codex;任务同时包含模糊目标、否定约束、平台兼容性和多层验收时,我会考虑引入协调层。

构建通过,不等于愿望实现

Android 小组件很容易暴露出另一个问题:代码可以成立,但我看到的东西仍然可能不成立。

构建通过,只能说明 XML、Kotlin 和资源通过了构建阶段的检查。它不能证明桌面宿主会怎样测量布局,也不能证明所有内容都能在有限空间里正常显示,更不能证明它表达出了我想要的视觉语义。

桌面小组件与普通 App 页面不同:Launcher 会重新参与布局测量,文字可能被裁切,原本合理的比例也可能发生变化。某个已验证设备和尺寸上的显示正常,也只能证明这个验证环境中的表现,不能直接推出所有设备都能可靠适配。

这些技术细节最终说明的是同一件事:

代码层面的“成功”,和愿望层面的“成功”,不是同一种成功。

这次任务至少有几层不同的证据:

编译通过,只说明代码通过了构建检查。
RemoteViews 能加载,表示这条加载路径可用。
在已验证的设备、尺寸和桌面宿主中显示正常,只覆盖这个验证环境中的展示。
我确认这就是自己想要的效果,才算愿望真正实现。

因此,视觉截图不能替代交互验收:还要在目标尺寸下确认“刷新”和“设置”按钮完整可见且可点击,并实际点击“刷新”确认数据更新。

因此,错误也不应该只被归类为“代码错误”。

它可能是需求澄清不足:在视觉表达尚未确定时,直接选定了独立进度条方案。

也可能是实现错误:新增控件破坏了原有按钮的可见性。

还可能是验收错误:只检查构建结果,没有检查目标尺寸下的展示和交互。

对这类任务来说,真正需要验收的,是代码运行后有没有产生愿望对应的、我能够观察到的结果。

到这里,问题已经不再只是怎么写一个 Android 小组件了。

所以,我把它叫作“面向愿望编程”

所谓面向愿望编程,是指以人期望的最终状态为起点,通过需求澄清、方案反馈和验收,将愿望逐步转化为明确的工程对象、约束与实现任务,再由代码代理完成实现。协调职责可以由独立 Agent 承担,也可以由同一个 Agent 分阶段完成。

它可以进一步表示为三个层次:

Wish / 愿望
    ↓
Task / 任务
    ↓
Code / 代码

这个模型也不是一次性的流水线,真实过程会在三层之间来回调整。

在这个模型里,人表达目标,任务层处理对象、约束和验收,代码代理负责实现。

在把任务交给 Coding Agent 之前,我现在会先问四个问题:

  • [ ] 我真正想看到或感受到什么?

  • [ ] 这个愿望对应的工程对象是什么?如果有多个候选,哪些需要先由我确认?

  • [ ] 哪些实现方式或结构明确禁止?

  • [ ] 什么证据能够证明它真的完成了?

对这次小型界面改动,这份清单比一套完整的 Agent SOP 更轻便。它没有试图提前规定所有步骤,只是先把最容易出错的地方说清楚。

Codex 并没有因为这次任务突然变得更聪明。真正发生变化的是,愿望和代码之间出现了一个可以承载澄清、反馈和验收的任务层。

我不必一开始就知道代码该怎么写,也不必一次性说清所有偏好。我需要表达目标,再通过候选方案、反馈和验收,让愿望逐步拥有工程形状。