一、为什么“试用很爽,上线就崩”?——我的三次翻车现场实录

2024.03.12 上午10:23 —— CI流水线突然卡死在 claude-plugin:run 步骤。本地 npx claude-gen --component Header 三秒出结果,CI里却卡住 90 秒后被 Kubernetes OOMKilled。日志最后一行是:

[claude-plugin] timeout after 60s waiting for Claude API response (retry=3)

没人想到,我们给插件配的 CLAUDE_TIMEOUT=60 是硬编码进 Dockerfile 的,而 CI 环境 DNS 解析慢了 200ms,叠加重试逻辑直接超时。更讽刺的是,本地 .env 里写了 CLAUDE_TIMEOUT=120,但插件根本没读——它只认环境变量,不读文件。

2024.04.05 下午16:47 —— 生产监控告警:useEffect dependency warning 爆发式增长。React DevTools 里一切正常,但 Sentry 报出上千条:

Warning: React has detected a change in the order of Hooks called by MyDataGrid.
This will lead to bugs and errors if not fixed.
   at MyDataGrid (src/components/MyDataGrid.tsx:42:3)
   at useEffect (react.development.js:2439)

翻代码才发现:Claude生成的组件里,useEffect(() => { loadData(); }, [searchTerm]) 被写成了 useEffect(() => { loadData(); }, []) —— 因为 prompt 里我只写了“加个搜索功能”,没明确说“依赖项必须包含 searchTerm”。开发时 searchTerm 恰好是全局常量,所以没报错;生产环境它是从 URL 参数动态解析的,一变就崩。

2024.05.18 凌晨03:12 —— Airflow DAG etl_user_enrichment 连续失败,Pod 内存飙升到 16GB,OOMKilled。脚本开头赫然写着:

# Generated by Claude 3.5 Sonnet on 2024-05-17
import pandas as pd
df = pd.read_csv("/data/raw/users.csv")  # 23GB file
df = df.merge(pd.read_csv("/data/raw/profiles.csv"), on="user_id")
# ... 7 more .read_csv() calls

它甚至没加 chunksize,也没做类型推断优化。我们以为只是“小数据清洗”,结果它把整个用户库全 load 进内存——而 Airflow worker 只配了 4GB。

当时我以为只是配置疏忽,后来才懂:这不是 bug,是人机协作的系统性断层——AI 在“解题”,而我在“交作业”。

CI流水线超时日志截图

二、别再把AI当‘高级Ctrl+C/V’——工程化前必须划清的三条红线

我们踩坑后开了三次复盘会,最终把血泪教训焊进流程:

「不可绕过Code Review」:现在每份 PR 必须带 AI-REVIEW 标签,且强制填写:

  • [ ] 人类确认:第12行 fetchUsers() 是否应加 loading 状态?
  • [ ] 人类确认:第28行 handleError(e) 是否覆盖了网络超时场景?
    PR 模板已固化进 GitHub repo settings,未填满不许提交。Git 钩子还会扫描 // AI-GENERATED 注释,自动插入 checklist。

「禁止直连生产数据源」:上周 Claude 在 SQL 脚本里偷偷加了 SELECT * FROM users WHERE created_at > '2024-01-01'。幸亏我们接入了 mockdb-schemadiff 工具——它比对了开发环境 MockDB Schema 和线上 prod schema,发现 users 表多了 password_hash 字段(本地 mock 里没这列),立刻阻断 CI,并在 PR 评论里贴出差异:

- columns: [id, name, email]
+ columns: [id, name, email, password_hash, updated_at, ...]

现在所有 SQL 必须先跑 sqlc generate 生成 type-safe query,再喂给 Claude 补充业务逻辑。

「函数级隔离」:所有 AI 产出必须封装进 /ai-generated/ 目录,且对外暴露接口必须通过 OpenAPI 3.0 校验。比如这个 Claude 写的支付回调处理函数:

# /ai-generated/payment/handler.yml
post:
  summary: Handle Alipay async notification
  requestBody:
    required: true
    content:
      application/x-www-form-urlencoded:
        schema:
          type: object
          required: [notify_id, sign, trade_status]
          properties:
            notify_id: { type: string }
            sign: { type: string }
            trade_status: { enum: [TRADE_SUCCESS, TRADE_CLOSED] } # ← Claude漏写了这个枚举!校验器当场报错

Swagger UI 自动生成的接口文档,和实际代码强绑定。OpenAPI校验对比图:左侧AI生成未校验版,右侧通过校验的终版

三、我的Claude工作流:不是“提问→粘贴”,而是“预埋→验证→缝合”

我现在的工作流像搭乐高:先铸模具,再灌浆,最后拧螺丝。

  • 前端组件生成
    周一 10:00 → 手写 UserCardProps.ts interface 和 Storybook CSF 文件(含 3 个状态);
    10:15 → 喂给 Claude 的 prompt 是:

    基于以下 TS 接口和 Storybook CSF(已提供),生成 React 组件:
    - 必须用 TypeScript + Emotion CSS;
    - 禁止使用任何第三方 UI 库;
    - 所有 props 必须显式声明,不得 any;
    - 加载态需显示 skeleton,错误态显示 fallback。
    

    10:22 → npm run lint && npm run storybook:test 全绿;
    10:28 → 提 PR,标题带 [AI] UserCard v1.2

  • 后端API补全
    Postman Collection 里已定义好 /v1/orders/{id}/refund 的全部请求头、参数、响应体结构;OpenAPI Schema 里约束了 refund_reason 必须是 enum: ["damaged", "wrong_item", "cancelled"]。Claude 只能在这个框里填逻辑,不能改契约。

  • 运维脚本
    所有 .sh.py 文件提交前必跑:

    shellcheck -s bash deploy.sh && \
    pylint --errors-only --disable=all --enable=E1101,E0602,E1123 ./scripts/cleanup.py
    

    一次 pylint 报出 E1123: Unexpected keyword argument 'timeout' —— 原来 Claude 给 requests.get() 加了 timeout=30,但脚本用的是 urllib3,根本没这参数。

慢下来,反而每天多交付 2 个模块。因为返工少了。

四、那些没人告诉你的‘幽灵坑’——环境、权限、可观测性的暗礁清单

这些坑不报错,但会让你半夜爬起来修:

Docker Alpine 版本陷阱
Claude 默认写 FROM alpine:latest,但 alpine:latest 是 3.20,而我们基础镜像用 glibc 2.38,它只兼容 alpine:3.19。检测命令:

docker run --rm alpine:latest ldd --version  # 输出 ldd (GNU libc) 2.39
docker run --rm alpine:3.19 ldd --version      # 输出 ldd (GNU libc) 2.38 ✅

一键修复:sed -i 's/alpine:latest/alpine:3.19/g' Dockerfile

VS Code Remote-SSH 环境变量黑洞
Claude 插件在远程 SSH 里读不到 .env.local,但本地 IDE 可以。debug 命令:

echo $CLAUDE_API_KEY  # 远程返回空,本地有值

修复:在 ~/.bashrc 里加 export CLAUDE_API_KEY=$(cat .env.local | grep CLAUDE_API_KEY | cut -d= -f2)

K8s tmpfs 临时文件失效
Claude写的 tempfile.mkstemp() 生成的文件,在 Pod 重启后消失,但清理逻辑假设文件还在。检测:df -h /tmp 显示 tmpfs 100M 0 100M 0% /tmp。修复:改用 os.makedirs('/mnt/shared/tmp', exist_ok=True)

Sentry Source Map 错位
AI生成代码经 Webpack 打包后,Sentry 显示错误在 index.js:12345,但实际在 Header.tsx 第 12 行。用 source-map-explorer dist/static/js/main.*.js 发现 map 文件缺失 ai-generated/ 目录映射。修复:Webpack config 加 new webpack.SourceMapDevToolPlugin({ include: [/ai-generated/] })

Lambda 冷启动埋点遗漏
Claude生成的初始化函数:

if (process.env.NODE_ENV === 'development') {
  initSentry();
}

但 Lambda 环境 NODE_ENV 永远是 production,导致 Sentry 完全没加载。修复:显式判断 process.env.LAMBDA_TASK_ROOT

Source Map Explorer 分析图:左侧错位,右侧修复后精准定位

五、给技术Leader的硬核建议:别考核‘用了多少AI’,要盯死这四个数字

我们把 AI 协作指标接入 Grafana 实时看板,拒绝模糊评价:

指标当前值目标数据来源
AI代码MR平均评审时长18min≤20minGitHub API + 自研 parser
CI中AI代码额外检查失败率2.1%<3%grep -c "AI-GENERATED" .gitlab-ci.yml | wc -l
AI模块P99延迟增幅+3.2ms≤5msDatadog APM tracing
手动重写频次0.8次/周≤1次/周Git log 统计 git log --oneline --grep="REWRITE-AI"

看板 SQL 示例(Datadog):

SELECT 
  percentile(duration_ms, 0.99) AS p99_latency,
  tag:service AS service_name
FROM traces 
WHERE tag:ai_generated = 'true' 
  AND timestamp > now() - 7d
GROUP BY service_name

告警规则:IF ai_module_p99_latency_increase > 5ms FOR 15m,触发 Slack 通知 + 自动创建 Jira issue。

Grafana 看板截图:四指标仪表盘,绿色达标,红色预警

六、最后掏心窝的话:AI不是替代者,是那个总爱抄近路的实习生

新同学小张用 Claude 三天搭完管理后台,UI 漂亮,路由丝滑。上线前无障碍测试(axe-core)一跑,全挂:所有操作按钮都是 <div onclick="...">,没有 role="button",没有键盘焦点,屏幕阅读器完全失语。Claude 懂 HTML 语法,但不懂 WCAG 2.1 的“可操作性契约”。

还有一次,Claude 生成的支付对账核心逻辑:

def reconcile_payments():
    for tx in get_pending_transactions():  # 按时间顺序取
        bank_callback = fetch_bank_callback(tx.id)  # 假设一定实时
        if bank_callback.status == "SUCCESS":
            mark_as_confirmed(tx)

它没考虑银行回调可能乱序到达。真实场景里,tx_id=1002 的回调先到,tx_id=1001 后到,导致账单状态错乱。我重写了整块逻辑,加了幂等锁和状态机,不是因为 Claude 写得丑,而是它根本没站在业务水位线上思考——它只看见“代码怎么跑通”,看不见“钱怎么算清楚”。

所以现在我跟团队说:

让AI搬砖,但你得亲自画施工图、盯地基、验承重墙。
它可以给你钢筋水泥的规格表,但决定承重多少吨、打几根桩、留几个逃生通道的,永远是你。