1. 为什么“让 AI 写代码”这件事在 Flutter 项目里格外容易翻车先说一个我观察到的现象很多团队在引入 AI 辅助编码之后头两周效率确实肉眼可见地涨了但到了第三周代码库开始出现一种很微妙的味道——不是编译不过而是“能跑但没人敢改”。这个问题在 Flutter 项目里尤其明显因为 Flutter 同时牵扯三套东西Dart 语言本身的风格约束、Widget 树的组织方式、以及跨端场景下平台通道和状态管理的边界。AI 在单文件里写一个StatefulWidget通常没问题但一旦让它跨文件、跨层去改翻车概率就上来了。我自己踩过最典型的一次是让 AI 帮忙重构一个列表页。它很“聪明”地把setState换成了某个状态管理库的写法逻辑上没错但它顺手把dispose里的控制器释放给删了理由是“新方案不需要”。结果页面来回切换几次之后内存曲线就开始往上爬。这种错误人写代码时也会犯但 AI 犯得更隐蔽因为它写得太顺、太自信Review 的人容易放松警惕。所以这篇要聊的不是“怎么用 AI 写 Flutter”而是怎么给 AI 划一条工程规范的线让它在线的内侧干活。核心思路是两层一层是 Claude Code 负责“理解项目上下文、按规范生成和修改”另一层是 Codex 这类补全型工具负责“在编辑器里实时兜底”。两者配合再加上一套写死的规范文件才能把“翻车率”压下来。这套东西适合已经有一定 Flutter 项目规模、开始多人协作、并且已经在用 AI 辅助编码的团队如果你只是写个 Demo其实用不上这么重。下面我会把整套搭建过程拆开讲包括规范文件到底写什么、Claude Code 的项目记忆怎么配、Codex 的补全怎么和规范对齐、以及我实测下来最容易出问题的几个环节。2. 先想清楚AI 在 Flutter 项目里到底会在哪些地方“越界”在动手搭规范之前得先知道敌人长什么样。我把过去半年里 AI 在 Flutter 项目里翻的车归了归类大致是四种理解了这四类后面写规范才有靶子。2.1 状态管理与生命周期的“自作主张”这是最高频的一类。Flutter 的状态管理方案太多setState、Provider、Riverpod、Bloc、GetX各有各的写法。AI 在训练数据里见过所有这些方案所以它不会“忠于”你项目当前用的那一种而是倾向于选它觉得最优雅的那个。更麻烦的是生命周期initState、didChangeDependencies、dispose这三个钩子的调用时机和职责AI 经常混着用。比如它会在build里创建TextEditingController这在人看来是低级错误但 AI 在补全时如果上下文不够真的会这么写。2.2 Widget 拆分粒度的“随性发挥”Flutter 里一个build方法写多长算合理没有硬性标准但团队一般会有约定比如超过 80 行就抽成独立 Widget。AI 不知道你的约定它可能把一个 200 行的build原封不动塞给你也可能把本该内联的三行Padding抽成一个新类。这种“粒度漂移”单次看无所谓积累起来就是代码风格的分裂。2.3 平台通道与条件编译的“想当然”涉及MethodChannel、Platform.isAndroid、kIsWeb这些跨端逻辑时AI 容易忽略边界。我见过它写出在 Web 上调用只有移动端才有的插件的代码编译能过运行时才炸。这类问题在纯 Dart 逻辑里不明显一旦碰到原生交互就暴露。2.4 依赖与 API 版本的“时空错乱”Flutter 和 Dart 的 API 迭代很快withOpacity被标记废弃、MaterialStateProperty改名成WidgetStateProperty这类变化AI 的训练数据里新旧混杂。它可能给你一个在你pubspec.yaml锁定的版本里根本不存在的 API或者用一个已经废弃但还能编译的写法埋下未来升级的雷。把这四类问题列出来之后你会发现它们有个共同点都不是语法错误而是“约定”和“上下文”的缺失。语法错误编译器会拦但约定错误只有规范能拦。这就是为什么单纯靠“提示词写得好一点”解决不了问题必须把规范固化下来。3. 规范文件怎么写把“团队约定”翻译成 AI 能读懂的规则规范文件是整个方案的地基。我的做法是在项目根目录放一个AI_RULES.md名字随意关键是 Claude Code 和 Codex 都能读到内容不是给人看的风格指南而是给 AI 看的“硬约束”。区别在于给人看的指南可以写“尽量”“建议”给 AI 看的规则必须写“必须”“禁止”并且给出可判定的条件。3.1 状态管理锁死一种方案写清禁用清单第一条规则就是状态管理的唯一性。假设团队用 Riverpod那就明确写## 状态管理 - 本项目统一使用 Riverpod禁止引入 Provider、Bloc、GetX 等其他方案。 - 所有跨 Widget 共享的状态必须通过 Provider/Notifier 暴露禁止用全局变量。 - 局部 UI 状态如输入框内容、展开收起允许使用 StatefulWidget setState。 - 禁止在 build 方法内创建任何 Controller、Stream、Timer。最后一条特别重要它直接堵住了 2.1 里那个TextEditingController的坑。规则要写成“禁止在 build 内创建 X”而不是“建议在 initState 创建 X”因为前者是可判定的AI 生成后你能一眼看出违规后者是模糊的。3.2 Widget 组织给出可量化的拆分阈值粒度问题必须量化否则 AI 没法执行。我用的规则是## Widget 组织 - 单个 build 方法超过 60 行必须拆分为独立 Widget 类。 - 可复用的 UI 片段出现 2 次以上必须抽成独立 Widget放在 widgets/ 目录。 - 私有 Widget 类命名以 _ 开头放在使用它的文件底部。 - 禁止在 build 内使用匿名函数包裹超过 10 行的 UI 逻辑。“60 行”这个数字不是拍脑袋是我统计了团队现有代码后取的中位数偏上值。你可以根据自己的代码库调整但一定要有数字因为 AI 对数字的遵守度远高于对形容词的遵守度。3.3 跨端与平台通道强制边界检查针对 2.3规则要写成条件判断的形式## 跨端与平台通道 - 任何调用 MethodChannel 的代码必须先用 kIsWeb 和 Platform 判断当前平台。 - 涉及平台差异的逻辑必须封装在独立的 platform/ 目录禁止散落在 UI 层。 - 使用 dart:io 前必须确认目标平台支持Web 端禁止直接 import dart:io。这里的关键是“必须先用……判断”把检查动作前置成强制步骤。AI 在生成平台相关代码时看到这条规则会倾向于先写判断再写逻辑。3.4 依赖与 API绑定版本标注废弃针对 2.4规则里要带上版本信息## 依赖与 API - 当前 Flutter SDK 版本3.22.xDart 版本3.4.x。 - 禁止使用已废弃 API包括但不限于withOpacity改用 withValues、 MaterialStateProperty改用 WidgetStateProperty。 - 新增依赖前必须检查 pubspec.yaml 中是否已存在同类库。把版本号写进去AI 在生成代码时会参考这个约束。实测下来明确写了版本之后AI 给出不存在 API 的概率明显下降。3.5 一个容易被忽略的点规则文件本身要“短而硬”我一开始把规则写了两千多字结果发现 AI 对后面的规则遵守度下降——上下文太长注意力被稀释了。后来压缩到八百字以内只保留最硬的约束遵守度反而上来了。所以规则文件的原则是宁可少写几条也要每条都能被判定。那些“代码要优雅”“命名要清晰”之类的话删掉它们对 AI 没有约束力。4. Claude Code 的项目记忆配置让它“记住”规范而不是每次重讲Claude Code 这类工具的核心能力是读取项目文件、理解上下文、然后按指令修改代码。它的“项目记忆”机制是整套方案里最省事的一环——配置一次之后每次对话它都会自动带上规范。4.1 把规范挂到项目记忆里Claude Code 一般支持在项目根目录放一个约定文件不同版本叫法可能不同有的叫CLAUDE.md有的通过配置文件指定把AI_RULES.md的内容引入进去。我的做法是直接在项目记忆文件里写一句引用# 项目规范 本项目所有代码生成和修改必须遵守 AI_RULES.md 中的全部规则。 在修改任何文件前先阅读该文件确认约束。这样每次启动对话规范就自动进入上下文了。注意不要把所有规则复制两遍引用一次就够避免上下文冗余。4.2 用“任务模板”约束它的工作方式光有规范还不够还得约束 AI 的工作流程。我在项目记忆里加了几个任务模板比如重构类任务## 重构任务流程 1. 先阅读目标文件及其直接依赖列出受影响的文件清单。 2. 说明重构方案等待确认后再动手。 3. 修改时保持公开 API 不变除非明确要求。 4. 修改完成后列出所有改动点标注哪些地方可能影响现有测试。这个模板的价值在于“等待确认后再动手”这一条。AI 默认是直接改的加上这条之后它会先给方案你能在它动手前拦下错误方向。我实测下来这一步能拦掉大概三成的方向性错误。4.3 让它先“读”再“写”Flutter 项目里一个 Widget 往往依赖好几个文件状态定义、数据模型、工具函数。AI 如果只看到当前文件就动手很容易用错类型。所以我在记忆里强制要求## 修改前必读 - 修改任何 Widget 前必须读取其引用的 Provider/Notifier 定义。 - 修改任何数据模型前必须读取其序列化相关代码fromJson/toJson。 - 不确定某个 API 是否存在时先搜索项目内是否有同类用法。“先搜索项目内是否有同类用法”这条特别实用。Flutter 生态里同一个功能往往有多种实现让 AI 先看看项目里别人怎么写的它就会倾向于复用现有模式而不是自创一套。4.4 一个实测有效的技巧把“反例”写进记忆除了正面规则我还在项目记忆里放了一小段“反例清单”就是过去 AI 犯过的典型错误。比如## 历史错误禁止重犯 - 禁止在 dispose 中遗漏 Controller.dispose()。 - 禁止把 async 逻辑直接写在 build 内。 - 禁止用 ! 强制解包可能为 null 的 Provider 返回值。这段东西看起来有点“记仇”但效果很好。AI 看到具体的反例比看到抽象的规则更容易避开。这其实符合它的工作方式——它是在做模式匹配给它具体的负面模式它就能绕开。5. Codex 补全的规范对齐编辑器里的实时兜底Claude Code 管的是“大块修改”Codex 这类补全工具管的是“你敲代码时的实时建议”。两者如果不一致就会出现“Claude 按规范改完Codex 又给你补一个违规写法”的尴尬。所以补全工具也要做规范对齐。5.1 补全工具的配置入口Codex 类工具通常支持项目级配置文件放在项目根目录用来指定代码风格、禁用某些模式。我的做法是把AI_RULES.md里的硬约束翻译成补全工具能识别的配置项。比如禁用withOpacity可以在配置里加一条自定义规则让补全时不建议这个 API。不同工具配置格式不一样但思路一致凡是规范里写“禁止”的补全配置里也要禁凡是规范里写“必须”的补全配置里设成默认。两边对齐才不会互相打架。5.2 用代码片段Snippet固化常用模式补全工具一般支持自定义代码片段。我把项目里最常用的几个模式做成了片段比如 Riverpod 的 Notifier 模板、带平台判断的 MethodChannel 调用模板。这样敲几个字母就能展开成符合规范的骨架AI 补全时也会优先参考这些片段。这一步的收益比想象中大。因为 AI 补全有个特点它会参考当前文件里已有的模式。如果文件里到处都是符合规范的片段它补出来的东西自然就规范了。反过来如果文件里混着好几种风格它就会随机挑一种。5.3 处理“补全和规范冲突”的情况有时候补全工具会给出一个违反规范的写法比如它建议用setState而规范要求用 Riverpod。这种情况不要直接接受但也不用每次都手动改。我的做法是如果某个冲突反复出现就说明规范文件里对应的规则写得不够“显眼”回去把它加粗、提前或者补一个反例。规则的位置和措辞会影响 AI 的遵守度这是个需要迭代的过程。5.4 补全工具的“上下文窗口”要喂饱补全质量高度依赖它能看到多少上下文。如果它只能看到当前几行补出来的东西就容易脱离项目实际。所以我会确保补全工具能读取到当前文件、同目录的相关文件、以及AI_RULES.md。有些工具支持配置“上下文文件”把规范文件加进去补全时就会带上约束。6. 实测中翻车的几个环节规范搭好了也不代表万事大吉规范搭好、两个工具都配好之后我以为可以高枕无忧了结果还是踩了几个坑。这几个坑比较隐蔽单独拎出来说。6.1 规范文件被 AI “选择性遗忘”第一个坑是对话轮次多了之后AI 会“忘记”规范。尤其是长对话里前面聊了十几轮规范文件虽然在上下文里但权重被稀释了。表现就是它开始给出违反规范的代码而且看起来很自然。解决办法有两个一是定期开新对话把任务拆小别在一个对话里干太多事二是在关键修改前手动提醒一句“请遵守 AI_RULES.md”。后者听起来很笨但实测有效一句话就能把规范的权重拉回来。6.2 两个工具对“同一件事”的理解不一致第二个坑是 Claude Code 和 Codex 对某个规范的理解有偏差。比如规范写“单个 build 超过 60 行必须拆分”Claude 会严格按 60 行拆Codex 补全时可能觉得 70 行也还行。这种偏差会导致代码风格在“Claude 改过的文件”和“Codex 补全的文件”之间摇摆。我的处理方式是把量化规则写得更死比如“超过 60 行必须拆60 行以内不强制”把边界说清楚。同时在 Codex 的配置里也加上同样的阈值。两边用同一个数字偏差就小了。6.3 规范本身也会“过时”第三个坑最容易被忽略Flutter 升级之后规范里的某些 API 建议可能就过时了。比如某个之前推荐的写法新版本里有了更好的替代。如果规范不更新AI 会一直按旧规范生成反而拖后腿。所以我把“规范维护”也写进了流程每次 Flutter SDK 升级同步检查AI_RULES.md里的 API 相关条目该改的改该删的删。这件事花不了多少时间但不做的话规范会慢慢变成负资产。6.4 排查链路当 AI 生成的代码出问题时怎么定位最后说一个排查思路。当 AI 生成的代码出问题时不要急着改代码先按这个顺序查先看这段代码是否违反了AI_RULES.md里的某条规则。如果违反了说明是规范没被遵守问题在规范传达不在代码本身。如果没违反规则看规则本身是否覆盖了这个场景。没覆盖说明规范有漏洞补规则。如果规则覆盖了但 AI 还是写错看是不是上下文不足比如它没读到某个依赖文件。以上都不是才考虑是 AI 能力边界问题这种场景就人工兜底。这个链路我用了几个月大部分问题都能在前两步定位到。它的价值在于把“AI 写错了”这个模糊的问题拆成了“规范问题”“上下文问题”“能力问题”三类每类的解法完全不同。7. 把这套东西跑顺之后我的几点真实体会整套方案跑顺之后最直观的变化不是“AI 写得更多了”而是“Review 的时间降下来了”。以前 Review AI 生成的代码得逐行看有没有埋雷现在大部分雷被规范挡在了生成阶段Review 更多是看业务逻辑对不对。另一个体会是规范的价值不在于限制 AI而在于把团队的隐性知识显性化。很多约定以前只存在于老员工的脑子里新人来了得靠口口相传。写成AI_RULES.md之后不光 AI 能读新人也能读反而顺带解决了文档缺失的问题。还有个反直觉的点规范越严AI 反而越好用。我一开始担心规则太多会束缚 AI 的发挥实测下来恰恰相反——规则清晰的时候AI 不用猜你的意图生成的东西更贴近预期来回改的次数明显减少。模糊的提示词看似给了 AI 自由实际上让它更容易跑偏。最后分享一个小技巧如果你不确定某条规则该不该加就先不加观察一段时间。如果 AI 在这个点上反复出错再把规则补上。规则是长出来的不是一次性设计出来的。我现在的AI_RULES.md里大概有一半的条目都是后来根据实际翻车情况补的这些“用血换来的”规则比一开始拍脑袋写的那些管用得多。
阅读完成 · 觉得有帮助?