这篇文章解决什么问题
很多开发者用 AI 编码助手写代码很快,但上线前往往只做了「跑通测试」这一步。这篇教程给出一套最小可执行的 5 道验证关,帮你在提交 PR 前把 AI 代码里常见的隐患挡在门外。
- • 适合谁看:日常用 Cursor、Copililot、Claude Code 等 AI 编码工具的开发者
- • 看完能做到什么:建立一套可复用的提交前自检流程,不靠运气,靠清单
背景
AI 编码助手现在能生成看起来很正确的代码,但常见问题包括:
- • 看起来跑通了,边界条件没覆盖
- • 引入了项目里没有的依赖或不兼容的 API
- • 安全问题(SQL 注入、路径遍历、硬编码密钥)
- • 风格不统一、命名不规范、缺乏必要注释
- • 生成了「幻觉」代码:调用不存在的函数、错误的参数顺序
这 5 道关不是要你全人工审,而是把最容易出问题、后果最重的项固化成清单,配合工具自动化,几分钟跑完,心情踏实再提交。
前提条件
- • 已在项目里配置基础工具链:
eslint/ruff/golangci-lint等(按语言) - • CI 里跑单测 + 类型检查(TypeScript 用
tsc --noEmit,Python 用mypy,Go 用go vet) - • 有基础的安全扫描工具:
semgrep、bandit、gosec、npm audit/pip-audit/govulncheck - • Git hooks 工具:
lefthook或pre-commit(可选,用于本地拦截)
第一关:静态检查与类型检查 —— 拦住语法与类型错误
做什么:跑项目配置的 linter + 类型检查器。
为什么:AI 最容易犯的低级错是类型不匹配、未使用变量、导入路径错、弃用 API。这些全是静态工具能秒查出来的。
命令示例:
# TypeScript / JavaScript
npm run lint # eslint
npx tsc --noEmit # 类型检查
# Python
ruff check .
mypy .
# Go
golangci-lint run
go vet ./...预期结果:零报错、零警告(或仅剩已知可接受的 legacy 警告)。
出错先查什么:
- • 报错文件是否为 AI 新增/修改的文件
- • 错误类型是否为类型不匹配、未定义符号、弃用 API
- • 如果是第三方库类型缺失,补
@types/xxx或types-xxx,别直接any
第二关:单测覆盖率与核心路径跑通 —— 拦住逻辑漏洞
做什么:跑全量测试,重点看新增/修改代码的覆盖率。
为什么:AI 生成的代码往往「主流程跑通」,边界条件、异常分支、空值处理全靠运气。覆盖率能量化暴露这些盲区。
命令示例:
# JavaScript / TypeScript (jest/vitest)
npm test -- --coverage --collectCoverageFrom='src/**/*.ts'
# Python (pytest)
pytest --cov=your_package --cov-report=term-missing
# Go
go test -coverprofile=coverage.out ./...
go tool cover -func=coverage.out | grep -E '(new_file|modified_file)'预期结果:
- • 全量测试通过
- • 新增/修改文件的行覆盖率 ≥ 80%(核心业务逻辑建议 ≥ 90%)
- • 关键分支(错误处理、空值、边界值)有对应测试用例
出错先查什么:
- • 哪个函数/分支没覆盖到 → 补测试,或确认该分支真不可达
- • 测试失败是否为 AI 生成的测试代码本身有问题(常见:mock 不全、断言写反)
第三关:安全扫描 —— 拦住显性安全隐患
做什么:跑语言对应的安全扫描器,专门查 AI 易引入的问题。
为什么:AI 训练数据里有大量不安全代码片段,容易生成:拼接 SQL、直接用用户输入拼路径、硬编码密钥、用弱随机数、未校验重定向目标。
命令示例:
# 通用(多语言)
semgrep scan --config=auto .
# Python
bandit -r .
# Go
gosec ./...
# 依赖漏洞
npm audit # Node.js
pip-audit # Python
govulncheck ./... # Go预期结果:
- • 无 High/Critical 级别漏洞
- • Medium 级别漏洞需人工评估:是否为误报、是否可通过升级依赖修复、是否需加防护代码
- • 依赖漏洞:无未修复的 Critical/High CVE
出错先查什么:
- • 报警代码是否为 AI 新增
- • 是否为误报(如:参数化查询被误判为拼接 SQL)
- • 依赖漏洞能否直接升级修复,还是需加缓解措施
第四关:代码风格与规范一致性 —— 拦住「看起来不像团队写的」代码
做什么:跑格式化工具检查,对比团队约定的命名、注释、结构规范。
为什么:AI 生成的代码风格常与项目既有代码不一致:命名风格混用、注释缺失或过度、错误处理模式不统一。这会增加后续维护认知负荷。
命令示例:
# 格式化检查(不修改,只报差异)
prettier --check . # JS/TS/JSON/MD
black --check . # Python
gofmt -l . # Go
# 命名/结构规范(需团队自定义规则)
# 例如:eslint-plugin-import-order、pylint-naming、golint 自定义规则预期结果:
- • 格式化检查通过(或仅有极少量可自动修复的差异)
- • 关键函数/类有必要的文档注释(公共 API 必须有)
- • 错误处理模式与项目既有代码一致(如:统一用
Result类型、统一try/catch位置)
出错先查什么:
- • 直接跑
prettier --write/black/gofmt -w自动修复格式问题 - • 命名不规范手动改,顺便确认语义是否清晰
- • 缺注释的公共接口补上:做什么、参数含义、返回值、副作用
第五关:依赖与构建产物检查 —— 拦住「本地跑通,CI 挂了」的坑
做什么:确认 lockfile 变更合理、构建产物无异常、无多余文件提交。
为什么:AI 容易随手加依赖、改包版本、甚至生成不需要的文件(调试脚本、临时文件、巨大二进制)。这些上 CI 才发现,浪费时间。
命令示例:
# 检查 lockfile 变更
git diff package-lock.json # npm
git diff uv.lock / poetry.lock # Python (uv/poetry)
git diff go.sum # Go
# 构建验证
npm run build # 前端
python -m build # Python 包
go build ./... # Go
# 检查暂存区有无异常文件
git status --porcelain | grep -E '^\?\?' # 未跟踪文件
git diff --cached --name-only | xargs file | grep -v text # 二进制文件预期结果:
- •
lockfile变更仅包含必要的新增/升级依赖,无无关版本抖动 - • 构建成功,产物体积无异常膨胀
- • 暂存区无调试脚本、
.DS_Store、巨大二进制、本地配置文件
出错先查什么:
- • 多余依赖:确认是否真需要,不需要则 revert
- • 版本抖动:锁定到兼容版本,避免
^/~导致 CI 不稳定 - • 异常文件:
git reset HEAD <file>移出暂存区,加入.gitignore
常见问题
Q1:这 5 关跑下来要多久?会不会太慢?
A:配合缓存和增量检查,典型中型项目 2-5 分钟。建议接入 lefthook 或 pre-commit 做本地预检,只在提交时跑轻量版(lint + 类型检查 + 单测),推送到 CI 再跑全量版(含安全扫描、构建验证)。
Q2:AI 生成的测试代码自己也可能有 bug,怎么办?
A:把「测试代码也要过 lint 和类型检查」加入第一关。核心逻辑测试建议人工复核断言逻辑,边界条件测试让 AI 生成后人工补全。
Q3:安全扫描误报太多,每次都要人工看不现实。
A:建立团队级 semgrep 规则集 / bandit 基线文件,把已确认的误报加入忽略列表。新代码只看新增的报警,存量不处理。
Q4:覆盖率达标但核心逻辑还是有 bug?
A:覆盖率是必要不充分条件。关键业务逻辑必须补充变异测试(如 stryker / mutmut / go-mutesting)或关键路径人工 Review。这 5 关是「最小可执行」,不是「唯一」。
Q5:项目没配这些工具,从零搭太麻烦?
A:从「 lint + 类型检查 + 单测」三件套起步,半天能跑通。安全扫描和变异测试后续补上。哪怕只有前三关,也能拦住 80% 以上的 AI 代码低级问题。
总结
这 5 道关的核心思想:把「靠经验、靠运气、靠仔细看」变成「靠工具、靠清单、靠自动化」。
| 关卡 | 核心工具 | 拦住什么 | 建议执行时机 |
|---|---|---|---|
| 1. 静态+类型 | eslint/ruff/golangci-lint + tsc/mypy/go vet | 语法错、类型错、弃用 API | 本地 pre-commit / CI |
| 2. 测试+覆盖率 | jest/pytest/go test + coverage | 逻辑漏洞、边界未测 | 本地 pre-push / CI |
| 3. 安全扫描 | semgrep/bandit/gosec + audit | 注入、遍历、硬编码、CVE | CI(每夜/每推送) |
| 4. 风格规范 | prettier/black/gofmt + 自定义规则 | 命名混乱、注释缺失、模式不统一 | 本地 pre-commit / CI |
| 5. 依赖构建 | lockfile diff + build 验证 | 多余依赖、版本抖动、异常文件 | 本地 pre-push / CI |
下一步能做什么:
- • 把这 5 关写成项目的
CONTRIBUTING.md或AI_CODING_CHECKLIST.md - • 接入
lefthook自动化本地拦截 - • 在 CI 里把安全扫描和覆盖率设为合并门禁
- • 团队内做一次 15 分钟分享,统一执行标准
这篇教程属于「工具实战 / 上手教程」栏目。下一期预告:如何让 AI 编码助手生成的测试代码也靠谱——一套测试代码自检清单。
夜雨聆风