前言

这是我最近在项目开发中逐渐形成的工作方式,也许后续还有别的调整,但目前确实这样。

我在把 iOS 项目迁移到 Android 的过程中。它涉及账号迁移、跨端登录、会话恢复、视频播放、资料读取、系统生命周期和后续发布流程。真正困难的地方,不是让 AI 写出一段 Kotlin,而是让它在不确定的接口、复杂的状态和有限的验证条件下,持续做出正确的工程判断。

我现在把 AI 当作一个可以独立推进任务的工程协作者,但不会把“代码生成完成”当作“任务完成”。我的完整闭环是:

事实核对 → 需求收敛 → 小范围实现 → 自动验证 → 真实路径验证 → 对抗性审查 → 人工验收 → 记录未知边界

一、先给 Agent 事实,再给它任务

我不会一开始就对 Agent 说:“把这个页面做出来。”

在 PhotonAndroid 中,Agent 开始工作前需要先读取几类信息:

  • GLOSSARY.md:确认业务术语和概念边界;
  • docs/adr/:确认已经做出的架构决策;
  • docs/agents/:确认开发、文档和验证规则;
  • .scratch/ 下的规格、任务和交接记录;
  • 当前 Android、iOS、后端源码及已有验证记录。

这套顺序很重要,因为不同材料的可信度不同。

当前后端源码和真实部署行为,决定接口到底是什么;iOS 当前代码和运行表现,决定用户实际看到什么;Android 规格和 ADR,决定状态应该由谁拥有;fixture、旧日志和历史文档,只能证明某个范围内曾经发生过什么。

如果这些信息发生冲突,我不会让 Agent 自己猜一个“看起来合理”的方案。例如,Apple 和 Meta 登录所需的浏览器交易、回调和兑换字段还没有拿到最新的后端契约时,任务就应该暂停,而不是沿用旧网页地址或示意字段继续开发。

这不是降低效率,而是避免把错误假设扩散到实现、测试和验收里。

二、需求对齐只做到足以改变实现方向的程度

我会先把 PRD、任务描述、会议结论、现有代码和用户反馈放在一起,让 Agent 找出:

  • 哪些是已经确认的事实;
  • 哪些是实现假设;
  • 哪些问题会改变接口、状态模型或验收结果;
  • 哪些问题只是实现细节,可以边做边决定;
  • 当前任务明确不包含什么。

我不会要求所有细节在开发前都被规划完。需求对齐的目标,是消除会改变方向的歧义,而不是提前写出一份几百行的实现说明。

在项目中,任务 00 到任务 16 就是按这个原则拆出来的。每个任务都有明确的依赖、范围、验收项和未验证边界。任务 16 只负责三 Tab 应用框架和滚动栏,个人主页视觉进入任务 13,播放逻辑继续由播放模块持有。这样做的结果是,每个任务都可以单独验证,也不会因为某个外部条件未准备好而冻结整个项目。

我的判断标准很简单:

如果剩余问题不会显著改变实现方向和验收结果,就开始开发;如果会改变,就先把它变成明确决策。

三、用短 Prompt 激活方法论,而不是堆一套僵硬流程

我很少再给 Agent 写几百字的“第一步做什么、第二步做什么”。

很多成熟的方法论,模型已经学过。与其把流程写死,不如用一句话告诉它应该以什么方式思考。

例如:

第一性原理

不要沿着现有方案继续加机制,先重新分析问题的真实瓶颈和最小必要解。

对抗性审查

不要帮当前方案找理由,优先寻找能够推翻核心假设的反例。

消融实验

把这次改动拆成独立变量,设计对照实验,判断每个机制到底贡献了什么。

奥卡姆剃刀

在满足需求的前提下,删除所有没有证据证明必要的抽象、缓存、状态和补偿机制。

职责审查

按高内聚、低耦合检查模块边界,不要为了拆文件而拆文件。

这些 Prompt 的价值不是让模型“变聪明”,而是让它切换思考模式。

在 PhotonAndroid 中,我经常把几个方法论组合起来:

先从第一性原理重新定义问题,再进行对抗性审查;通过测试或消融实验验证机制贡献;最后用奥卡姆剃刀删除不必要的复杂度。

这比预先规定一整套固定 Workflow 更适合复杂项目。简单修改直接做,复杂任务才增加拆分、规划和交叉审查。

四、让架构约束成为 Agent 的工作边界

AI 很容易把局部问题解决得过于完整。一个页面加载失败,它可能顺手新增一套全局状态;一个接口需要复用,它可能建立一个包含所有端点的巨大 API 文件。

所以我会把稳定的工程判断写进项目规则,而不是每次重新解释。

PhotonAndroid 当前有几条非常明确的边界:

  • ui/<feature>/ 负责页面、页面状态和功能组件;
  • 公共 HTTP 能力集中在 data/network/;
  • 具体端点、DTO 和错误映射归属各自的业务 Adapter;
  • 页面不能直接构造 URL 或网络客户端;
  • SessionController 是登录会话的唯一事实所有者;
  • PlaybackController 是播放状态和播放器生命周期的唯一事实所有者;
  • 页面只组合界面、展示状态并发送事件;
  • 异步结果提交前必须核对环境、账号 UUID 和执行代次;
  • 旧账号、旧请求和旧页面的迟到结果不能覆盖当前状态。

这些规则不是为了让代码看起来整齐,而是为了防止状态分裂。

例如,登录页面不能自己保存一份会话,资料页面也不能再维护一份账号事实。页面只订阅会话模块的状态。播放页面不能自行创建第二个播放器,否则 Home、资料详情和返回恢复之间就会出现难以解释的行为。

AI 最擅长写局部逻辑,但系统正确性往往取决于“谁拥有状态”和“谁负责结束状态”。这部分必须由工程规则提前说清楚。

五、把任务拆成主 Agent、验证 Agent 和审查 Agent

我不会让多个 Agent 随意并行修改同一片代码。

主 Agent 负责理解任务、实现代码、运行验证和整合结果。只有边界清晰、可以独立验收的部分,才适合交给其他 Agent 在独立 worktree 中推进。

在代码审查阶段,我会把审查拆成两条轴:

Standards:

  • 是否违反项目开发约束;
  • UI、业务 Adapter、公共 HTTP 和状态所有者是否边界清晰;
  • 是否出现不必要的大页面、大 ViewModel 或透传层;
  • 是否引入了不必要的依赖和全局状态。

Spec:

  • 是否实现了规格真正要求的行为;
  • 取消、失败、重试、换号和迟到结果是否正确;
  • 是否把未验证能力伪装成已完成;
  • 是否遗漏了用户可观察的边界条件。

这两种审查关注点不同。代码可能结构很漂亮,却没有实现需求;也可能功能通过了,却把状态放错了位置。把它们分开,可以减少“看起来没问题”的错觉。

六、测试不是装饰,而是 Agent 的执行环境

仅仅让 AI 写单元测试还不够。Agent 必须能够从真实入口执行流程,并拿到足够的失败证据。

我现在把验证分成几层。

第一层是工程检查:

1
./scripts/verify.sh

它负责构建 development、QA 和 production 变体,运行 lint、JVM 测试以及设备测试 APK 编译。

第二层是可控的 JVM 测试。HTTP、时钟、存储、播放引擎和身份 SDK 都通过 Interface 注入,使用 MockWebServer 和受控结果验证失败、超时、取消、重试及旧结果隔离。

第三层是模拟器上的 Android 测试。所有 adb 命令显式指定设备序列号,避免误操作其他设备。这里验证真实 Activity、Compose 节点、旋转、深色模式、大字体、返回路径和页面重建。

第四层是正式变体和正式 API 的只读联调。真实接口读取默认使用 productionRelease,不能拿 Debug API 的失败推断正式读取能力。

第五层才是维护者执行的人工真实验证,例如真实 Google 登录、签名、Play 分发和真机行为。

这几层不能互相替代。

受控 fixture 可以证明状态机和页面流程,不能证明真实 Google 授权成功。模拟器可以证明 2D HLS 播放,不能证明所有真机的解码能力。旧包名下的 Google 登录成功,也不能自动证明新包名下的 OAuth 配置已经正确。

我会把这些边界写进验证记录,而不是只写一句“测试通过”。

七、工具负责提供证据,业务契约负责定义正确

这是我特别重视的一点。

数据库查询、日志、Trace、APK 扫描和屏幕节点,都只是证据来源。它们不能替代业务契约。

例如,服务端返回了一个结构完整的对象,不代表这个对象一定应该展示;播放器回调了错误,也不代表页面应该清空用户当前会话;列表里找不到某个帖子,也不代表它一定没有被发布。

在 PhotonAndroid 中,发布管理区分上传任务、待处理帖子、发布受理和最终可播放内容;通知区分分类已读边界和逐条曝光;账号注销也区分业务访问失效和媒体资源异步回收。

如果不先定义这些概念,Agent 很容易根据某个 HTTP 状态码或某次列表结果做出错误结论。

所以我会要求验证记录同时包含:

  • 业务契约期待什么;
  • 实际系统返回了什么;
  • 当前实现如何解释这个结果;
  • 哪些条件仍然没有验证。

八、Review 重点看业务路径,而不是逐行阅读

AI 生成代码的速度,已经超过了人工逐行阅读的速度。我的 Review 方式也因此发生了变化。

我会先看验收标准,再看测试结果,然后沿着用户业务路径检查高风险位置:

  • 登录和账号身份是否匹配;
  • 会话是否可靠保存和恢复;
  • 换号后旧结果是否会回来;
  • 重试是否会重复提交;
  • 页面重建后状态是否丢失;
  • 并发请求是否有唯一状态所有者;
  • 播放器是否在后台、锁屏和退出时正确暂停或释放;
  • 生产包是否包含 Debug 能力;
  • 包名、签名、环境和缓存是否隔离;
  • 测试证据是否真的覆盖本次变更。

对于稳定的 CRUD 模式,我不会花同样多的时间。对于新增的抽象、缓存、状态机和补偿机制,我会专门问一句:

如果删掉它,哪个验收条件会失败?

如果没有明确答案,这个机制很可能只是 AI 为了“完整”而增加的复杂度。

九、把“未验证”当成一种正式状态

AI 开发最危险的地方,是它很容易把“局部通过”扩展成“整体完成”。

我现在会明确区分:

  • 已实现;
  • 自动检查通过;
  • 真实联调通过;
  • 维护者人工确认;
  • 尚未验证;
  • 被外部依赖阻塞;
  • 明确不在本次范围内。

例如,PhotonAndroid 当前已经验收了登录入口、普通会话、Google 登录、审核码登录和三 Tab 应用框架。资料读取和独立 2D HLS 播放也已经有基础实现和正式 API 模拟器复测。

但 Apple、Meta 的浏览器交易仍等待后端/Web 契约;Home Feed、Messages、上传、完整播放操控和阶段整体验收也没有被提前宣布完成。

这种“保留缺口”的做法,短期看起来没有那么漂亮,却能避免项目在后续阶段被错误结论反噬。

十、真正想优化的是 Review 速度

现在 AI 能同时推进多个任务,但人的理解、判断和验收速度不会同步增长。

如果只是让 Agent 写更多代码,最后得到的可能是一堆等待 Review 的变更。

所以我接下来更关注三件事:

第一,把类型检查、单元测试、设备测试和业务断言前移,让 Agent 在交付前自己发现更多问题。

第二,把重复的排障流程沉淀成脚本、CLI 和 Skill,让 Agent 可以自己检查环境、准备数据、执行场景和收集证据。

第三,持续清理已经失效的约束。

有些规则是为了弥补旧模型的缺点。模型能力变化后,过重的流程就可能变成噪声。项目中真正应该长期保留的,是领域事实、状态边界、验收标准和安全约束;具体的操作步骤和 Prompt,则应该随着模型和项目变化持续做减法。

站内搜索

没有找到内容!