你只搭了一半安全网,就宣布大功告成
老实说,现在大多数 AI 代码流水线到底是什么样子。
你用 Cursor 或 Claude Code 生成代码。你运行 tsc --noEmit,因为 TypeScript 严格模式能捕获类型不匹配。你运行 ESLint,因为没人想在合并请求里争论分号问题。也许你还会运行 dependency-cruiser,因为循环导入很丢人。测试通过了。你就发布了。
然后你以为这就是确定性栈。
事实并非如此。它只是一个类型与风格栈。你确实阻止了无效状态并强制了导入边界,这本身很有用。但你对下面这个事实完全无动于衷:LLM 刚刚生成了一个 180 行的函数,其圈复杂度高到能让图论学者落泪。你没发现三个不同的 module 复制了同一个辅助函数,只是变量名略有不同。你也没注意到错误处理只是一个孤零零的 catch (e) { console.log(e) },像个懒散的保安一样挂在 promise 链的末端。
代码能编译通过。架构很干净。但代码本身仍然烂得无可辩驳。
这就是缺口所在。而且它很重要,因为 AI 生成的代码特别擅长制造这种垃圾:结构合法、架构合规,却从内部悄悄腐烂。
缺失的那一层到底是什么
想想一栋通过结构工程师验收的大楼,和一栋住起来舒服的大楼之间的区别。结构验收检查的是楼会不会塌。它不检查淋浴排水会不会流进厨房水槽。两者都重要。但它们是不同的工作。
你现有的确定性栈就是那个结构工程师。它检查的是:
- 类型:这个值以这种形态存在是否合理?
- 代码风格审查:语法是否符合基本规范?
- 架构规则:导入是否尊重边界?
- 测试:主流程能否顺利执行而不崩溃?
它不检查的是:
- 复杂度:这个函数的分支是否多到没人能正确理解?
- 重复代码:LLM 是否在四处生成了相同的逻辑,只是略有变动?
- 命名:
data是个有意义的变量名吗,还是相当于编程世界里的耸肩? - 错误处理:错误真的被处理了吗,还是仅仅被捕获然后无视?
- 结构:文件组织是否合理,还是只是个垃圾场?
- 注释:复杂的地方有解释吗,还是下一个开发者得开降灵会才能看懂?
- 体量:这个文件有 400 行是因为确实需要,还是因为没人让模型停下来?
这些不是审美偏好。复杂度与缺陷密度正相关。重复代码保证了你未来的改动会不一致。糟糕的命名增加了每次后续修改的认知负担。拙劣的错误处理意味着生产环境故障时没有诊断线索。
这方面的研究结论很明确。我们自己的跨维度分析发现,分层可靠性架构只有在每一层都能捕获前一层漏掉的缺陷时才有效。如果你的第一层是类型检查,第二层是测试,但没人检查代码是否是一场可维护性灾难,那你的栈上就有一个洞。而 AI 生成的代码特别喜欢从这个洞里掉下去,因为模型非常擅长生成看起来合理、实际上却惨不忍睹的实现。
登场:那个名字粗鲁的工具
有一个叫 fuck-u-code 的工具——没错,这就是命令名——它只做一件事,而你的流水线里没有任何其他工具在做这件事。它对十四种语言运行基于 AST 的确定性代码质量分析,用与实际缺陷高度相关的指标,精确告诉你你的代码有多烂。
以下是它的检查项:
- 复杂度:圈复杂度和认知复杂度评分。如果一个函数有十七个分支,它会标出来。
- 体量:文件和函数的代码行数。那个生成了 250 行函数的 LLM,不会因为类型正确就得到豁免。
- 注释:注释密度和质量。不是因为注释本身有多高尚,而是因为没有解释的复杂逻辑是一个维护陷阱。
- 错误处理:错误是被捕获、重新抛出、记录,还是被默默吞掉。
- 命名:变量和函数名的质量。
data、temp、handler和process都过不了关。 - 重复代码:跨文件的重复代码块。LLM 最喜欢的小花招:复制粘贴,然后查找替换。
- 结构:文件组织和 module 内聚性。
它输出一个 0 到 100 的总分。越高越好。它还会输出每个文件的「shit-gas index」——越高越烂——这样你就能精确知道哪些文件需要优先处理。分析完全离线运行,通过 tree-sitter 的 AST 解析完成。你的代码永远不会离开你的机器。在大多数项目上,耗时不到一秒。
而这一点应该让你气恼自己为什么没早就开始用它:它一分钱都不花。
这个工具本身就是这种哲学的体现
fuck-u-code 有趣的地方不止在于它检查什么。还在于它的内部架构方式,因为这个工具本身就是它所属流水线的完美缩影。
这个工具有两个命令:
fuck-u-code analyze . # Deterministic AST analysis. Offline. Fast. Free.
fuck-u-code ai-review . -m gpt-4o # AI review of the worst-scoring files. API call. Costs tokens.
注意顺序。注意默认行为。确定性分析始终最先运行,因为它不需要 API 密钥,不花钱,而且每次运行结果一致。AI 审查是可选的第二步,只看最烂的 Top-N 个文件。
这正是你的流水线应该具备的架构。
你不会把每个合并请求都发给 Greptile 或 Claude Code 做完整的语义审查。那既费钱又耗时,而且——正如我们在之前的文章里已经论证过的——会产生概率性输出,连续运行时不一定能标出同样的问题。你先运行确定性关卡。以零成本、毫秒级、完全可复现的方式,把结构性灾难过滤掉。然后,而且只有在这之后,你才把幸存者送去昂贵的 AI 审查,做确定性工具无法完成的语义、架构和行为分析。
fuck-u-code 的内部实现正是如此。analyze 命令是你的第一层质量过滤器。ai-review 命令是你的第二层语义深度挖掘。这个工具就是它自己所倡导原则的最佳演示。
经济层面的论证简直令人愤怒
我们花点时间谈谈钱,因为这才是行业现状真正令人恼火的地方。
AI 代码审查平台按合并请求或按审查的代码行数收费。成本不算巨大——也许每个合并请求一两美元——但它不是零,而且会随着团队的速度而增长。如果你用 AI 生成代码,你的速度比以前更高,这意味着你的审查成本也比以前更高。
与此同时,fuck-u-code 能在不到一秒内分析你的整个 codebase,横跨十四种语言,而且完全不收你一分钱。它会标出真正有问题的那 20% 文件。它会生成 JSON 或 Markdown 报告,供你的 CI 使用。如果平均分低于你配置的阈值,它还会让构建失败。
如果你在每次合并请求上都运行 AI 审查,却不在前面设置确定性质量关卡,那你就是在花 API token 去发现某个函数太复杂了。这就像雇一个结构工程师来告诉你家里很脏。工程师当然有这个资质,但你在浪费他们的时间和你的钱。
经济上理性的流水线是:
- AI 生成代码
- 类型检查、代码风格审查和架构规则(你现有的栈)
- fuck-u-code analyze(缺失的质量关卡——零成本,不到一秒)
- AI 审查(Greptile 等——但只针对第三步中幸存的文件,或者只在第三步标出有趣模式时才运行)
这不是理论。这是算术。确定性关卡捕获的是确定性工具设计用来捕获的那类问题。AI 审查捕获的是需要语义理解的那类问题。每个工具都做自己擅长的事。没有人会把 token 浪费在结构性卫生上。
MCP 集成:为工作流而生,非事后拼凑
如果你真的认真对待 AI 辅助开发,还有一个细节很重要。
fuck-u-code 自带一个 MCP 服务器。如果你使用 Claude Code、Cursor 或任何其他支持 MCP 的工具,你可以直接从你的智能体调用 fuck-u-code analyze。智能体不需要了解 AST 解析或圈复杂度。它调用一个工具。工具返回结构化报告。智能体据此采取行动。
这很重要,因为它闭环了。生成代码的同一个 AI,现在可以收到关于代码质量的确定性反馈,格式是它能够理解和执行的。智能体可以看到 src/auth/login.ts 的 shit-gas index 是 87 分(满分 100),然后在人类看到合并请求之前就决定 refactor。
我们之前在文章中写过,CI 是让规范驱动开发成真的 enforcement 层。MCP 集成意味着 fuck-u-code 不只是一个 CI 关卡。它是一个智能体可访问的质量预言机,生成流水线可以实时查询它。
实际接入是什么样子
你不需要迁移计划。你只需要五分钟。
npm install -g eff-u-code
fuck-u-code analyze . # See your current scores
fuck-u-code config init # Generate .fuckucoderc.json
配置你的阈值。选一个最低总分。为单个文件选一个最高的 shit-gas index。把它加到你的 pre-commit hooks 里:
# .husky/pre-commit
fuck-u-code analyze . --format json --output quality-report.json
或者加到 CI 里:
# .github/workflows/quality.yml
- name: Code Quality Gate
run: |
npm install -g eff-u-code
fuck-u-code analyze . --format markdown -o quality.md
# Parse the JSON and fail if overall score < threshold
权重是可配置的。如果你的团队更关心复杂度而不是注释,就在 .fuckucoderc.json 里调整指标权重。如果你想排除测试文件,用 --exclude。如果你想看最烂的 20 个文件而不是默认的 10 个,用 -t 20。
然后,当你过滤掉结构性灾难之后,把那些有趣的文件送去 AI 审查:
fuck-u-code ai-review . -m gpt-4o -t 5 # Review only the 5 worst files
这就是流水线。生成。类型检查。质量关卡。幸存者接受 AI 审查。发布。
老实说的最终结论
我不会假装 fuck-u-code 能解决你 codebase 里的所有问题。它捕获不了竞态条件。它不会告诉你你的认证逻辑存在微妙的定时攻击。它不会取代 property-based testing、mutation testing、形式化验证或者我们在之前的文章里讨论过的其他任何层级。
它能做的是捕获那些无聊、可预测、代价高昂但目前没人管的问题。它会告诉你,你的 AI 生成的 API 处理函数长达 300 行且没有任何错误处理。它会告诉你,三个不同的服务复制了相同的验证逻辑。它会告诉你,你一半的变量都叫 data 或 result,你应该为此感到羞愧。
这些不是边界情况。这是一个没有质量反馈环的快速代码生成流水线的默认输出。LLM 不会累,但它也不会感到羞愧。它会以生成好代码时同样的自信生成烂代码,而你当前的确定性栈会放行它,因为你的栈不是为检查质量而设计的。它是为检查有效性而设计的。
有效性和质量是两回事。两者你都需要。
fuck-u-code 不是完整的答案。它回答的是一个具体问题:「阻止 AI 生成的结构性垃圾进入代码审查,最便宜、最快、最确定性的方法是什么?」
答案是:解析 AST,评估指标,让构建失败,然后让模型重试。
它不花一分钱。耗时不到一秒。而且它堵上了你安全栈上一个你可能都不知道自己有的洞。