Flutter AI Harness:从代码生成到可验证的工程协作
面向生产级的AI Harness开源模板,并基于此讨论项目契约、任务闭环、架构边界与多工具适配。

项目地址:github.com/bladeofgod/...
摘要
AI 编程工具已经可以承担页面实现、错误修复、测试补充和代码审查等工作。真正影响长期效率的,不再只是单次生成质量,而是 AI 能否持续理解同一套工程规则,能否在明确边界内修改代码,以及交付结果能否被稳定验证。
Flutter AI Harness 是一套面向 Flutter 与 Android、iOS 混合工程的仓库模板。它没有把 AI 封装成应用运行时能力,而是把项目契约、Command、Agent、Skill、任务卡、Review、质量门禁和工具适配放进代码仓库,让 AI 与开发者共享同一组工程事实。
这套模板同时提供一个本地电商 Demo,但 Demo 只是参考实现。更重要的使用方式,是让 AI 读取 Harness 的设计,结合既有工程的技术栈和约束进行裁剪与改造。
一、代码生成不是完整的工程能力
在一个短任务中,AI 很容易表现出较高效率:根据截图搭页面、补一个接口、修复一处异常,往往都能快速得到可运行结果。但当修改跨越多个模块,或者代码需要持续迭代时,问题会从"能否生成"转向"如何约束"。
一个工程至少要回答以下问题:
- 技术栈和架构不变量由谁定义;
- 包与 Feature 之间允许怎样依赖;
- 需求如何拆成可独立验收的任务;
- 哪些文件可以编辑,哪些文件只能由生成器维护;
- 静态检查、单元测试、平台构建和运行验证分别在何时触发;
- Review 发现的问题如何进入修复和复审,而不是停留在一份报告中。
如果这些信息只存在于聊天记录或个人经验里,每次对话都要重新解释,规则也很容易在多轮修改后失效。AI 的执行速度越快,结构漂移反而可能越早出现。
Harness 解决的正是这一层问题:它不替代编码工具,而是为编码工具提供可读取的工程上下文、可执行的流程和可验证的反馈。
二、Harness 的四层结构
Flutter AI Harness 将工程控制面分成四层:
- 项目契约:定义技术栈、目录职责、依赖方向、数据边界和生成文件规则。
- 工作流资产:用 Command 描述流程,用 Agent 描述角色,用 Skill 提供按需知识,用 Memory 保存低频且长期有效的经验。
- 执行与装配:任务卡进入实现,代码通过聚焦测试和平台运行得到验证。
- 验证与反馈:静态门禁、只读 Review、UI Spec、证据归档和 CI 构成交付反馈。

图 1:规则、流程、执行和验证共同构成 Harness。单独增加提示词,并不能替代这个闭环。
这四层并不是为了增加流程数量,而是为了明确不同信息的生命周期。稳定不变量应进入项目契约;特定技术知识应按任务加载;一次性实现要求应留在任务卡;只有能够跨任务复用的经验才进入 Memory。
这种区分可以减少上下文浪费。AI 不需要在每次任务中加载所有平台规范、全部历史 Review 和所有业务模块,只需读取项目契约,再按当前任务补充相关 Command、Agent 或 Skill。
三、仓库中的事实源如何组织
当前仓库的核心结构如下:
text
flutter-ai-harness/
├── CLAUDE.md 权威项目契约
├── AGENTS.md Codex 入口
├── .claude/ Command、Agent、Skill 与 Memory 事实源
├── .agents/ 生成的 Codex Skill 适配
├── .codex/ 生成的 Codex Agent 适配
├── docs/ 架构、任务、Review 与设计输入
├── scripts/ Git Hooks 与可执行质量门禁
└── app/ Flutter Workspace 与参考 Demo
其中,CLAUDE.md 负责定义仓库级不变量,.claude/ 是 AI 工程资产的唯一事实源。Codex 所需的 AGENTS.md、Skill 和 Agent 配置由仓库工具确定性生成,而不是另外维护一套内容相近的文档。
这一设计解决了多工具协作中常见的配置漂移:Claude 与 Codex 可以保留各自的发现和调用机制,但它们读取的工程规则来自同一个源头。修改 Command、Agent 或 Skill 后,生成检查会阻止过期适配层进入提交。
docs/ 也不是一个不加区分的文档集合。当前约定中:
| 位置 | 保存内容 | 不保存什么 |
|---|---|---|
docs/tasks/ |
尚未完成的任务卡 | 虚构计划和固定 Sprint 层级 |
docs/tasks/done/ |
已完成任务与验收信息 | 可复用项目知识 |
docs/reviews/ |
Review 报告与测试证据 | 无法复现的口头结论 |
docs/app-operator/ |
人工安排的 UI Spec、Audit、Run | 普通任务的默认门禁 |
.claude/memories/ |
低频、长期有效的工程经验 | 任务流水账和重复规范 |
任务产物与长期知识分开,既方便追溯,也避免 Memory 随项目推进不断膨胀。
四、Flutter Workspace 的边界设计
模板中的 Demo 使用 Flutter Pub Workspace 和 Melos 管理多个 Package。当前依赖方向为:
text
apps/demo -> app_features, app_data, app_im, app_core, app_ui
app_features -> app_data, app_im, app_core, app_ui
app_data / app_im -> app_core
app_core / app_ui -> no other workspace packages
这里的箭头表示左侧 Package 可以依赖右侧 Package。apps/demo 位于最上层,负责全局服务、路由和依赖装配;app_core 与 app_ui 位于基础层,不能反向引用业务实现。
各 Package 的职责并不复杂:
app_core提供ApiClient、ApiTransport、存储抽象、日志和平台无关基础设施;app_data提供 Domain Entity、Fixture、LocalDataSource、Mapper 以及未来的协议或持久化适配;app_ui保存设计 Token 和不包含业务规则的通用 UI;app_im保存消息基础设施,不承载 Feature 页面;app_features保存业务 API 抽象、Controller、Page、Route 与 Feature 实现;apps/demo只做装配,不直接依赖 Feature 内部实现类。
数据类型边界
跨层传递的数据统一使用 Domain Entity 或明确的 Value Object。Proto Message、数据库 Row 和原始 Fixture Payload 必须在数据适配层完成转换:
text
Fixture Payload ─┐
Wire / Proto ────┼─> Mapper -> Domain Entity -> API -> Controller -> UI
Database Row ────┘
这条约束的价值在于隔离变化。当前 Demo 没有真实远程 API,使用确定性 Fixture 和本地 Mock 链路;未来引入真实 Endpoint 时,可以替换 Transport、DataSource 和 Mapper,而不需要让页面或业务 API 感知底层协议变化。
模板没有提前引入 Dio、Proto 或 Drift 来填充技术清单。只有出现真实消费者、远程协议或跨重启持久化需求时,相关依赖才进入对应 Package。对模板工程而言,控制无效抽象的数量,与建立分层本身同样重要。
五、任务卡驱动的交付闭环
普通开发任务遵循一条相对短的闭环:

图 2:任务卡负责收敛范围,Review 与证据负责把结果反馈给后续任务。
1. 产品输入
输入可以是需求说明、Figma 节点、原型或技术问题。涉及 Figma 时,Agent 通过本地 MCP 读取真实节点,不依靠截图猜测布局。
2. 任务卡
任务卡不绑定固定生产者。开发者、Agent、Command 或外部工具都可以创建,只要名称清晰且唯一,并包含足够的事实来源、范围、依赖、限制和验收方式。
3. 实现与聚焦验证
执行阶段只加载当前任务需要的 Skill,完成代码后优先运行受影响范围内的格式检查、静态分析和测试。共享契约或基础 Package 发生变化时,再扩大验证范围。
4. 只读 Review 与显式修复
Review 默认只报告问题,不在审查过程中顺手修改代码。修复需要明确进入下一阶段,完成后重新审查。这样能够区分"发现了什么"和"实际改了什么",也便于控制跨任务改动。
5. 证据归档
归档内容包括运行过的命令、结果、环境限制和仍未覆盖的平台。原始日志中的本机路径、设备标识和凭据需要脱敏,不能为了保留证据引入新的信息泄露风险。
六、UI 自动化为什么独立于普通任务
模板提供 UI 行为 Spec、静态 Audit 和运行 Run 三类结构化产物:
text
.spec.yaml 产品要求 App 应该如何表现
.audit.yaml 代码静态上是否实现了这些行为
.run.yaml 行为是否在指定平台真实运行通过
三者分别回答产品契约、代码实现和运行结果,不应混为一份报告。
UI 自动化由人独立安排。只有在明确选择 Spec 和平台后,App Operator 才通过 Marionette 连接运行中的 Debug App,执行检查并生成对应平台的 Run。普通任务执行不会自动启动 App Operator,也不会因为缺少 Run 文件而无法归档。
这种设计有两点考虑:
第一,真实设备和本地 MCP 连接依赖外部环境,不适合作为每个小任务的强制前置;第二,静态审计没有通过时,继续运行设备测试没有实际价值。把两者分开,可以在保持反馈完整的同时,避免给日常开发增加不必要的等待和人工确认。
Marionette 操作的是 Flutter Widget Tree,并不覆盖 Android、iOS 的原生系统界面。涉及相册权限、系统弹窗或原生页面时,仍需使用相应平台工具或人工验证。
七、质量门禁如何落到可执行规则
模板中的质量规则不是一份建议清单,而是由脚本、Git Hook 和 CI 共同执行。
仓库级检查包括:
- Dart 格式与静态分析;
- 单元测试、Widget 测试和按需 Integration Test;
- Feature 之间的内部引用检查;
- Controller 的 API 注入方式检查;
- 壳工程越界引用检查;
- Workspace Package 依赖矩阵检查;
- Claude 与 Codex 适配层同步检查;
- 文档链接、配置文件、任务卡 Schema 和敏感信息检查;
- Android Debug 与 iOS no-codesign Debug 构建。
这些检查按影响范围触发,而不是要求开发者在每次修改后手工执行所有命令。实现阶段运行聚焦检查,提交和推送阶段由 Hook 执行轻量门禁,CI 再提供统一的远端结果。需要设备、MCP 授权或 Apple 工具链的步骤,则准确记录环境限制。
门禁本身也需要控制成本。一个规则只有在对应真实风险、具备清晰失败信息并有正反 Fixture 时,才值得长期维护。否则,质量系统很容易变成另一套需要绕开的流程负担。
八、模板的两种采用方式

图 3:两条路径共享同一套工程原则,但对目录和业务代码的保留程度不同。
方式一:直接运行参考 Demo
仓库包含一套 Shoppe 风格的本地电商 Demo,覆盖 Welcome、Auth、Shop、Categories、Wishlist、Cart、Profile、Settings、Orders、Search、Promotions、Rewards、Support 和 Product Detail 等流程。
Demo 使用确定性本地 Fixture 和 Mock API,不依赖远程后端。它的主要作用是展示项目契约、任务卡、Figma 输入、代码实现、Review 和质量门禁如何在同一个仓库中协作。
这条路径适合评估 Harness 的完整形态,也适合验证本机环境和 Android、iOS 构建链路。
方式二:改造到现有工程
对于已经存在的工程,更合理的做法不是复制整个目录,而是先让 AI 完成适配分析:
- 阅读 Harness 的项目契约、架构文档和
.claude/事实源; - 盘点目标工程的技术栈、Package 边界、原生平台、CI 和团队流程;
- 将资产分成"可直接复用""需要调整""只作为参考"三类;
- 先形成适配方案和任务卡,再开始迁移;
- 更新目标工程自己的事实源,并重新生成 Codex 等工具的适配层;
- 用第一张真实业务任务验证新流程,再决定是否继续扩展。
在这条路径中,目录名称、状态管理、路由方案、平台集成和命令都可以调整。需要保留的是工程原则和反馈闭环,而不是仓库外观。
九、适用边界与取舍
Flutter AI Harness 更适合以下场景:
- Flutter Monorepo 或长期维护 Android、iOS 原生宿主的混合项目;
- 多个 AI 工具共同参与开发,需要统一事实源;
- 团队希望把架构约束变成 CI 可执行规则;
- 需求会持续迭代,需要保留任务、Review 和验证证据;
- 希望 AI 能读取 Figma、操作 Debug App,但不希望这些工具侵入普通任务流程。
它不能替代以下工作:
- 产品范围、业务规则和交互取舍;
- 设计稿授权、素材许可和真实数据策略;
- 原生系统 UI、签名、权限和设备兼容性验证;
- 团队对高风险修改、发布范围和外部系统访问的最终决定。
另外,Harness 不应无限增长。Agent 和 Skill 不是越多越好,Memory 也不应该成为第二份项目文档。每增加一项资产,都应明确它解决了什么重复问题,以及为什么现有契约、任务卡或脚本不能承担这个职责。
结语
AI 编程带来的变化,不只是代码生成速度提高,也改变了项目如何保存和执行工程知识。过去依赖开发者长期记忆的规则,需要逐步变成仓库内可读取、可执行和可审查的资产。
Flutter AI Harness 给出了一种具体实现:项目契约负责稳定边界,Command、Agent 和 Skill 负责按需执行,任务卡与 Review 负责控制变更范围,Git Hook 与 CI 负责提供确定性反馈,Demo 则用于验证这些设计能够在真实 Flutter 工程中工作。
它不是必须原样安装的插件。可以直接运行 Demo,也可以让 AI 基于目标工程重新抽象。对多数已有项目而言,后者往往更有价值:工具和目录可以变化,但清晰的事实源、单向的架构边界、独立的验证阶段和可追溯的交付结果,应当保留下来。