一个 Hook 让 AI 每次写文件前自动检查编码规范,违规代码再也提交不进来

AI 生成代码有个问题:它偶尔会忘记你的规范。尤其是对话轮数多了之后,之前 steering 里的约束可能被"稀释"。

我写了一个 preToolUse Hook,每次 AI 要写文件时自动检查。相当于给 AI 装了个"写之前先 lint"的闸门。从此 AI 产出的代码合规率从 85% 到接近 100%。

问题场景

arduino 复制代码
第 1 轮对话:AI 老老实实用 dayjs
第 5 轮对话:AI 突然用了 moment(上下文稀释)
第 8 轮对话:AI 用了 class 组件(忘了你说只用函数组件)

你发现的时候:
├── 要么在 CR 时才看到 → 已经提了 MR
├── 要么在构建时 lint 报错 → 要来回改
└── 总之:发现越晚,修复成本越高

解决方案:preToolUse Hook

json 复制代码
{
  "name": "Code Standards Check",
  "version": "1.0.0",
  "description": "AI 写文件前自动检查是否符合编码规范",
  "when": {
    "type": "preToolUse",
    "toolTypes": ["write"]
  },
  "then": {
    "type": "askAgent",
    "prompt": "在写入文件前,请检查以下编码规范:\n1. 是否引入了 moment?应使用 dayjs\n2. 是否使用了 class 组件?应使用函数组件\n3. 是否使用了 var?应使用 const/let\n4. 日期格式化是否用了 dayjs 而非 new Date\n5. 样式文件是否使用 .m.less 后缀(CSS Modules)\n6. import 路径是否使用了 @ 或 @@ 别名\n\n如果有违规,请修正后再写入。如果全部合规,继续执行写入。"
  }
}

工作原理

markdown 复制代码
AI 准备写文件
      ↓
preToolUse Hook 触发
      ↓
AI 自我审查即将写入的内容
      ↓
┌─────────┐     ┌────────────┐
│ 发现违规 │     │ 全部合规    │
└────┬────┘     └─────┬──────┘
     ↓                 ↓
  修正代码           继续写入
     ↓
  再次写入

实际拦截案例

案例 1:moment 引入被拦截

AI 在第 6 轮对话中准备写入:

typescript 复制代码
import moment from 'moment'

const formatDate = (date: string) => moment(date).format('YYYY-MM-DD')

Hook 触发后 AI 自动修正为:

typescript 复制代码
import dayjs from 'dayjs'

const formatDate = (date: string) => dayjs(date).format('YYYY-MM-DD')

案例 2:样式文件后缀

AI 准备创建 styles.less,Hook 提醒后改为 index.m.less

案例 3:路径别名

typescript 复制代码
// 准备写入
import { Button } from '../../../components/Button'

// Hook 修正后
import { Button } from '@@/Button'

为什么不只靠 Steering

erlang 复制代码
Steering(软约束):
├── 写在配置文件里
├── AI "应该"遵守
├── 上下文长了可能被忽略
├── 效果:~85% 合规率
└── 类比:贴在工位上的规范海报

Hook(硬约束):
├── 每次写文件都触发
├── AI "必须"通过检查
├── 不受上下文长度影响
├── 效果:~99% 合规率
└── 类比:门禁刷卡,不符合进不去

两者结合效果最好:Steering 让 AI 一开始就按规范写,Hook 在最后关口兜底。

进阶:按文件类型差异化检查

不同文件的规范不同,可以在 prompt 里加判断逻辑:

json 复制代码
{
  "then": {
    "type": "askAgent",
    "prompt": "检查即将写入的文件:\n\n如果是 .tsx/.ts 文件:\n- 检查 import 规范(别名、dayjs、函数组件)\n- 检查导出方式(优先 named export)\n\n如果是 .m.less 文件:\n- 检查是否使用了全局选择器(应该都是局部类名)\n- 检查是否有 !important(尽量避免)\n\n如果是 services/ 下的文件:\n- 检查请求函数是否有返回类型\n- 检查是否使用了统一的 request 实例"
  }
}

性能影响

arduino 复制代码
每次写文件额外耗时:约 1-2s(AI 自检)
每天写文件次数:约 30-50 次
每天总额外耗时:约 1-2min

vs 不用 Hook 的代价:
├── CR 发现规范问题 → 来回改:15min/次
├── lint 报错 → 回去修:5min/次
├── 按每天 3 次规范问题计算:45min/天

ROI:每天省 40+ 分钟,值。

配置建议

javascript 复制代码
建议放进 Hook 的规则:
├── 高频违规的(moment、var、class 组件)
├── 机械性的(路径别名、文件后缀)
└── 难以事后修复的(全局样式污染)

不建议放的:
├── 主观性强的("这个变量名不够语义化")
├── 需要全局上下文的("这个组件应该提取出去")
└── 频繁变化的规则(每周都在调整的)

💬 你们有没有遇到 AI 生成代码"偶尔出格"的问题?用什么方法来兜底?


🔗 完整 Skills 源码已开源github.com/sleepyccat/...,欢迎 Star ⭐ 和 PR。

相关推荐
恋猫de小郭2 小时前
Android 17 + OkHttp 5.5.0 ,全新 ECH 下你的 HTTPS 域名可以请求时被安全隐藏
android·前端·flutter
NingBo3 小时前
让非技术人员也能一键使用 DeepSeek Harness
ai编程·deepseek
后除3 小时前
从零到一: 创建一个 TypeScript 7 项目
前端·webpack·typescript
lerhxx3 小时前
我用 R3F 手搓了一个能走进去的 3D 迷宫简历(上):从选型架构到迷宫生成算法
前端·javascript·three.js
全栈弄潮儿3 小时前
真实案例:用 AI 重构一段难维护的旧代码
aigc·openai·ai编程
还有多久拿退休金3 小时前
不调多模态,纯文本大模型如何给系统操作配上截图
前端·llm·aigc
hunterandroid4 小时前
HarmonyOS WebSocket 实战:断线重连、心跳保活与连接状态机设计
前端
hunterandroid4 小时前
StateFlow 与 SharedFlow 的边界:状态与事件的正确建模
android·前端
心念科技4 小时前
1、搜索表单 xnSearch(基于:心念后台,后端 Java 21 + Spring Boot 4 + Spring Cloud,前端提供 ReactVue3+TS、Vue3+JS、Vue2+JS
前端