☰
Flutter 项目 AI 编码规范:Claude Code 与 Codex 工程约束实战
2026/10/17 8:27:59 网站建设 项目流程

1. 为什么 Flutter 项目最容易被 AI 写“散架”

先说一个我观察到的现象:Flutter 项目是所有移动端技术栈里,被 AI 辅助编码“带偏”概率最高的一个。原因不复杂——Flutter 的 widget 树天然是嵌套结构,一个页面动辄几百行 build 方法,AI 在补全时非常容易“就近取材”,把状态管理、网络请求、UI 布局全塞进同一个文件里。你让它写个登录页,它给你返回一个 400 行的 StatefulWidget,里面混着 http 调用、SharedPreferences 读写、表单校验和 SnackBar 提示。跑是能跑,但三天后你自己都不想看第二眼。

我接手过一个典型的“AI 生成后遗症”项目:三个开发者用不同的 AI 工具各写各的模块,结果项目里同时存在 Provider、GetX 和原生 setState 三套状态管理方案,目录结构按功能分和按类型分混着来,lib/下面既有pages/又有screens/,还有views/。这种项目最要命的不是跑不起来,而是每次加新功能都要先考古——搞清楚这个模块到底该往哪个目录放、该用哪套状态方案。

所以问题从来不是“AI 会不会写 Flutter”,而是AI 缺少一套稳定的工程约束。它每次生成代码都是“从零开始猜你的项目习惯”,猜对了是运气,猜错了就是技术债。Claude Code 和 Codex 这类工具本身能力足够,但它们默认不知道你的项目规范——除非你把规范显式地喂给它们,并且用工程手段强制它们遵守。

这篇文章要讲的,就是怎么用 Claude Code 配合 Codex,给 Flutter 项目搭一套“AI 写代码不翻车”的工程规范。核心思路有三层:用配置文件固化项目约定、用静态检查兜住 AI 的偷懒、用提示词模板约束生成风格。适合正在用或准备用 AI 辅助 Flutter 开发的团队,也适合个人开发者想让自己项目别越写越乱。

2. 先搞清楚 Claude Code 和 Codex 在 Flutter 场景下的分工

很多人把这两个工具当成同类产品对比,其实它们在 Flutter 工作流里的定位差别很大,用错了地方就是白费力气。

2.1 Claude Code 擅长“理解上下文后做重构”

Claude Code 的强项是长上下文理解和跨文件操作。你给它一个lib/目录,它能读完整个项目的结构,然后回答“这个 feature 应该放在哪一层”这类需要全局视野的问题。我实测下来,它在做这几件事时特别稳:

  • 把散落在多个文件里的同类逻辑抽取成统一的 service 层
  • 按照现有目录约定,把新写的页面放到正确位置
  • 识别出重复的 widget 并建议抽成公共组件

它的弱点是“生成速度”和“批量补全”不如 Codex 流畅,因为它的工作模式更偏向“读—想—改”,而不是“边写边补”。

2.2 Codex 擅长“在约束下快速产出”

Codex 在编辑器里的补全体验更顺,适合在你已经定好规范之后,让它按规范快速生成样板代码。比如你已经有了一个BaseRepository抽象类,Codex 能很快帮你写出符合这个模式的子类。但如果你没给它任何约束,它就会自由发挥——这就是“翻车”的源头。

2.3 两者配合的正确姿势

我的做法是:Claude Code 负责“定规矩和改结构”,Codex 负责“按规矩填内容”。具体流程是先用 Claude Code 把项目规范梳理成文档和配置文件,再用这些文件去约束 Codex 的生成行为。下面这张表是我总结的分工对照:

任务类型首选工具原因
梳理项目目录规范Claude Code需要读全项目后归纳
生成新页面骨架Codex有模板后补全快
重构混乱的状态管理Claude Code跨文件改动需要全局理解
补全单个方法实现Codex局部上下文足够
检查命名一致性Claude Code需要跨文件比对
写单元测试Codex模式固定,补全效率高

注意:不要指望任何一个工具“自动懂你的项目”。所有规范都必须显式写出来,否则 AI 只会按它训练数据里的“平均风格”来写,而那个平均风格往往就是最乱的那种。

3. 用 CLAUDE.md 把项目约定变成 AI 的“入职手册”

Claude Code 有一个很关键的能力:它会自动读取项目根目录下的CLAUDE.md文件,把它作为系统级上下文。这个文件就是你给 AI 写的“项目入职手册”。我见过太多人这个文件写得像 README,全是“本项目是一个 Flutter 应用”这种废话。真正有用的CLAUDE.md应该是一份可执行的约束清单。

3.1 目录结构必须写到“哪个文件放什么”

不要写“按功能模块组织目录”这种模糊描述。要写到具体路径级别。比如:

## 目录约定 - lib/core/ 全局基础设施:网络、存储、主题、常量 - lib/features/ 按业务功能划分,每个 feature 一个目录 - lib/features/xxx/ feature 内部固定四层: - data/ 数据源、DTO、repository 实现 - domain/ 实体、repository 接口、usecase - presentation/ 页面、widget、状态管理 - xxx_feature.dart 对外导出文件 - lib/shared/ 跨 feature 复用的 widget 和工具

这样写的好处是,当 Claude Code 要新建一个文件时,它能明确知道该放哪。我实测过,写了这段之后,AI 把文件放错目录的概率从大概三成降到了几乎为零。

3.2 状态管理只允许一种方案

这是 Flutter 项目最容易乱的地方。你必须在CLAUDE.md里写死:

## 状态管理 - 统一使用 Riverpod(或你选的方案),禁止混用其他方案 - 页面级状态用 StateNotifier,全局状态用 Provider - 禁止在 widget 里直接写业务逻辑,必须通过 notifier 调用

我踩过的坑是:只写“使用 Riverpod”不够,AI 还是会在某些场景下用 setState,因为它觉得“这个场景很简单”。必须加上“禁止”类的硬约束,它才会收敛。

3.3 命名规范要给出正反例

AI 对命名的理解很依赖示例。与其写“使用有意义的命名”,不如直接给对照:

## 命名规范 - 文件:snake_case,如 user_profile_page.dart - 类:PascalCase,页面类以 Page 结尾,如 UserProfilePage - 变量:camelCase,布尔值以 is/has/can 开头 - 反例:禁止使用 data1、temp、helper 这类无意义命名

3.4 把“禁止事项”单独列一节

这一节是防止 AI 翻车的核心。我通常会写:

## 禁止事项 - 禁止在 build 方法里做网络请求或数据库操作 - 禁止在 widget 里直接 new 一个 repository - 禁止使用 print,统一用 logger - 禁止硬编码颜色和尺寸,必须走 theme - 禁止一个文件超过 300 行,超了必须拆分

这些“禁止”不是给人类看的,是给 AI 看的。Claude Code 在生成代码前会参考这些约束,Codex 在补全时也会受编辑器里的项目上下文影响。实测下来,写了禁止事项之后,AI 生成print语句的概率大幅下降。

4. 用 analysis_options.yaml 把规范变成“编译期强制”

CLAUDE.md是“软约束”,AI 可能遵守也可能忽略。真正能兜底的是 Dart 的静态分析。Flutter 项目自带的analysis_options.yaml如果只开默认规则,基本拦不住 AI 的坏习惯。你需要把它配置成一套“AI 代码质检器”。

4.1 开启严格模式

analyzer: language: strict-casts: true strict-inference: true strict-raw-types: true errors: avoid_print: error prefer_const_constructors: warning always_declare_return_types: error

strict-casts和strict-inference这两个开关特别重要。AI 生成的代码经常出现隐式类型转换和推断失败,开了严格模式之后,这些问题会在分析阶段就暴露出来,而不是等到运行时才崩。

4.2 用 lint 规则堵住 AI 的常见偷懒

我整理了一份专门针对 AI 生成代码的 lint 清单:

lint 规则拦截的 AI 坏习惯
avoid_printAI 爱用 print 调试
prefer_const_constructorsAI 不写 const,导致性能差
always_declare_return_typesAI 省略返回类型
avoid_dynamic_callsAI 用 dynamic 绕过类型检查
prefer_final_localsAI 爱用 var 且不 reassign
sort_constructors_firstAI 构造函数位置随意
require_trailing_commasAI 不写尾逗号,格式化后乱

4.3 把分析命令接进 AI 的工作流

光配置还不够,要让 AI 每次生成后自动跑分析。Claude Code 支持在CLAUDE.md里写“工作流指令”:

## 生成后必做 1. 运行 flutter analyze,修复所有 error 2. 运行 dart format .,统一格式 3. 如果新增了文件,检查是否超过 300 行

我实测下来,加上这三步之后,AI 生成的代码“一次通过率”从大概一半提升到了八成以上。剩下两成主要是逻辑问题,不是规范问题,那属于正常范围。

5. 给 Codex 配一套“生成模板”,让它照着填

Codex 在编辑器里的补全行为,很大程度上受“当前文件上下文”和“项目内相似文件”影响。所以最有效的约束方式不是写提示词,而是在项目里放一批标准模板文件,让 Codex 有样学样。

5.1 建一个 templates 目录

我在项目里会放一个templates/目录(不参与编译),里面是各种标准骨架:

// templates/feature_page_template.dart import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; class XxxPage extends ConsumerWidget { const XxxPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final state = ref.watch(xxxNotifierProvider); return Scaffold( appBar: AppBar(title: const Text('Xxx')), body: state.when( data: (data) => _buildContent(data), loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => Center(child: Text('Error: $e')), ), ); } Widget _buildContent(dynamic data) { return const SizedBox.shrink(); } }

这个模板的价值在于:当 Codex 要补全一个新页面时,它会优先参考项目里已有的相似结构。你放了这个模板,它生成的页面就会自动带上ConsumerWidget、when分支、const构造这些规范。

5.2 模板要覆盖高频场景

我一般会准备这几类模板:

  • 页面模板(带状态管理三态)
  • Repository 模板(带异常处理)
  • UseCase 模板(带参数校验)
  • 测试模板(带 mock 和 group 结构)

每类模板都放在templates/下,文件名以_template结尾。这样 Codex 在补全时,会把这些文件当作“项目内风格参考”。

5.3 用注释锚点引导 Codex

Codex 对注释很敏感。你可以在模板里写特定格式的注释,作为“生成锚点”:

// @generate: repository // 按照本文件结构生成 UserRepository

当你在新文件里写// @generate: repository时,Codex 有较大概率会参照模板结构来补全。这个技巧不是百分百生效,但配合模板文件一起用,效果比纯提示词稳定得多。

6. 实测中 AI 最容易翻车的五个场景与应对

规范搭好之后,不代表就高枕无忧了。我在实际项目里记录了 AI 最常翻车的几个场景,每个都配了应对方案。

6.1 场景一:状态管理“就近偷懒”

AI 在写一个简单页面时,倾向于用setState而不是项目规定的状态管理方案,理由是“这个页面很简单”。应对方式是在CLAUDE.md里明确写“任何有异步数据的页面都必须用 notifier”,并且在模板里只提供 notifier 版本的页面骨架。没有 setState 的模板可参考,AI 就不会往那个方向走。

6.2 场景二:异常处理“假装不存在”

AI 生成的网络请求代码经常不写 try-catch,或者 catch 了之后只写个print。应对方式是在 Repository 模板里强制包含异常转换逻辑,并且在 lint 里开启avoid_catches_without_on_clauses,逼着 AI 写明确的异常类型。

6.3 场景三:硬编码“随手就来”

颜色、尺寸、间距,AI 特别爱直接写Color(0xFF123456)和SizedBox(height: 16)。应对方式是在CLAUDE.md里写死“所有颜色走 AppColors,所有间距走 AppSpacing”,并且在 analysis_options 里开启avoid_hardcoded_values类的自定义规则(需要配合自定义 lint 插件)。

6.4 场景四:文件膨胀“不知不觉”

AI 不会主动拆文件,它会把所有东西往一个文件里塞。应对方式是在CLAUDE.md里写“单文件不超过 300 行”,并且在生成后工作流里加一步行数检查。我一般会写个简单的 shell 脚本,超过 300 行的文件直接报出来。

6.5 场景五:测试“形同虚设”

AI 写的测试经常是“为了覆盖率而写”,断言很弱。应对方式是在测试模板里强制包含“至少一个边界条件断言”,并且在CLAUDE.md里写“每个 usecase 必须有对应的测试文件”。

7. 把规范接进 CI,让 AI 的产出必须过闸

前面所有规范,如果只靠开发者自觉执行,迟早会松掉。真正让规范“活下来”的办法是接进 CI。我的做法是在 CI 里加三道闸:

7.1 第一道:静态分析闸

flutter analyze --fatal-infos --fatal-warnings

--fatal-infos这个参数很关键。默认情况下 info 级别的提示不会让 CI 失败,但 AI 生成的代码里大量问题都是 info 级别。加上这个参数,任何不规范都会直接卡住合并。

7.2 第二道:格式闸

dart format --set-exit-if-changed .

AI 生成的代码格式经常不统一,这道闸保证所有代码在合并前都被格式化过。

7.3 第三道:自定义规范闸

我会写一个简单的 Dart 脚本,检查几件事:

  • 单文件行数是否超过 300
  • 是否存在print调用
  • 是否存在硬编码颜色值
  • 新增文件是否在正确的目录下

这个脚本不需要很复杂,用正则匹配就能覆盖大部分场景。关键是它把“软规范”变成了“硬门槛”。

提示:CI 闸门不要设得太严,否则开发者会想办法绕过。我的经验是先把最关键的几条(print、硬编码、文件行数)卡住,其他的用 warning 提示,逐步收紧。

8. 几个我踩过的坑和对应的经验

最后分享几个实际踩过的坑,都是文档里不会写的。

第一个坑:CLAUDE.md写太长反而失效。我一开始把规范写了两千多字,结果 AI 反而不遵守了。后来发现,Claude Code 对CLAUDE.md的有效注意力大概在前 800 字左右。所以现在我只把最关键的约束放前面,详细的规范拆到单独的docs/文件里,在CLAUDE.md里用链接引用。

第二个坑:模板文件太多会干扰 Codex。我一度放了二十多个模板,结果 Codex 补全时经常“串味”,把 repository 的结构套到页面上。后来精简到每类只留一个最标准的模板,效果反而更好。

第三个坑:lint 规则不是越多越好。我开过一百多条 lint,结果 AI 生成的代码全是 warning,开发者看麻木了就不管了。现在只保留二十条左右最关键的,确保每条 warning 都值得修。

第四个坑:AI 会“学习”你的坏习惯。如果项目里已经有一批不规范的旧代码,AI 会优先模仿这些旧代码。所以搭规范的第一步不是写新规则,而是先把旧代码清理一遍,至少让 AI 看到的都是正面例子。

这套规范搭下来,大概花了我两天时间,但后续每个功能的开发效率提升很明显。最直观的变化是 code review 的时间缩短了——以前要花大量时间纠正命名、目录、状态管理这些低级问题,现在这些问题在 AI 生成阶段就被约束住了,review 可以聚焦在业务逻辑上。如果你也在用 AI 写 Flutter,建议先从CLAUDE.md和analysis_options.yaml这两个文件开始,投入最小,见效最快。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询