$catMANUAL||~37 分钟

代码整洁度影响 AI Agent 吗?660 次 Claude Code 实测告诉你答案

advertisement

最近翻 Hacker News 的时候看到一篇很有意思的论文,标题叫《Does Code Cleanliness Affect Coding Agents? A Controlled Minimal-Pair Study》(arXiv:2605.20049)。作者是 SonarSource 的 Olivier Schmitt。HN 上 139 分,评论里吵得不可开交。

我读完论文 + 翻完所有评论区之后,结论跟标题一样直接:clean code 不让 Agent 更聪明,但确实让它更省心。具体省多少?7-8% 的 token 节省,34% 的文件重读次数减少。这不是口胡,是 660 次实测跑出来的数据。

今天聊聊这个研究本身,再聊聊评论区里一些真材实料的工程经验,比论文本身还精彩。

这个研究到底干了啥

简单说,作者在问一个问题:AI 编程 Agent 写代码/改代码的效率,跟它所在的代码库"干不干净"有没有关系?

这个问题看起来简单,但真要做实验就特别难。难点在哪?你得找到两个除了"干净程度"以外一模一样的代码库。这种代码库在现实里根本不存在——自然生长的代码库之间,架构、依赖、风格、年龄全都不一样,根本没法直接比较。

作者搞了个叫 minimal pairs 的设计:先准备 6 对代码库,每对都是从同一个项目"变形"出来的,结构、依赖、行为完全一样,唯一不同的就是 SonarQube 报告的代码问题数量。

变形方式分两种方向:

  • Slopify(变脏):从一个本来就干净的代码库出发,让 Agent 故意往里塞死代码、重复逻辑、长函数、深度嵌套
  • Vibeclean(变干净):从一个本来就是历史包袱重的代码库出发,让 Agent 按照 SonarQube 的规则清单一项一项清理

变形后的两个版本,外部行为完全一致(测试通过率相同),但内部代码质量天差地别。然后给每一对构造 33 个编程任务,总共 6 对 × 33 个任务 = 33 个独立任务 × 2 个版本 × 10 次重复 = 660 次实测。

任务分三类:

  • 13 个 cognitive-hotspot 任务:都在单文件/单类里那种几千行 god method 上做改动
  • 14 个 multi-module 任务:要跨多个模块改
  • 6 个 calibration 任务:故意设计成跟"整洁度"无关,验证实验本身没有系统性偏差

Agent 用的是 Claude Code + Claude Sonnet 4.6,跑在隔离的沙箱里,token、文件读取、对话轮数、改动行数全部记录。

核心数据:clean code 不改变结果,但改变过程

最核心的发现一句话能讲完:

整洁度不影响 Agent 能不能把活儿干完,但显著改变它干完这个活儿的过程。

具体数据(基于 33 个任务的汇总,cleaner 相对 messier):

  • 通过率(pass rate):0.913 vs 0.921,差 -0.9 个百分点。基本一致
  • 输入 token:-7.1%
  • 输出 token:-8.5%
  • 推理字符数:-11.1%
  • 对话轮数:-7.0%
  • 首次编辑前消息数:-3.6%
  • 文件重读次数-33.8%(这是最显眼的)

通过率没差多少说明:Agent 拿到的任务能不能做对,跟代码整不整洁基本没关系。但是 token 少用了 7-8%,文件重读少了三分之一——这意味着 Agent 在干净代码上跑得更顺。

为啥文件重读会差这么多?论文里有一个特别生动的 case study。commons-bcel 这个项目里有一对 250 行的 switch 巨无霸(god method),控制着 JVM opcode 的 dispatch。Messy 版本里 Agent 要么一头扎进 250 行里找入口,要么反复回看自己之前的修改。在 Cleaner 版本里,这个 dispatch 被拆成了十几二十个具名 helper,每个名字都能直接 grep 到。Agent 第一次读就能锁定位置,改完直接走人,不用回来复查。

这其实就是我们写代码时天天在说的"取个好名字"。只不过现在不只是为了人看着舒服,Agent 看着也省力。

但是!这个研究争议也很大

我看 HN 评论的时候,第一条高赞评论就把论文的实验设计给锤了:

"They used Opus 4.6 to synthetically produce 'degraded' or 'cleaned' code bases for relative comparison in the experiment. Worse, they don't control for breaking the application's tests. Any conclusions with respect to token consumption seems pretty meaningless if we're not controlling for the quality of the final output."

这位 commenter 提的核心问题是:你让 AI 制造的"干净代码"或者"脏代码",跟真实世界里人写的"干净代码/脏代码"根本是两码事。让 Opus 4.6 去清理代码,它能清理成什么样?会不会清完反而更烂,只是看起来更整齐?这点论文没说清楚。

论文作者(看 ID 是 Olivier 自己)在评论区回了,原话大意是:"你说得对,我们确实没控制 agent 改完之后会破坏多少原有的、跟当前任务无关的测试。在生产里用 Sonnet 4.6 的时候我倒是没看到太多 regression,因为 Agent 一般会自己跑测试再交活儿。但你说得没错,我们不知道。"

这条回复很坦率,但确实承认了方法论上的硬伤——只测了 Agent 在新任务上的通过率,没看它有没有把别的地方搞坏。

另外还有一条评论挺关键:

"Research done by SonarSource, a company that sells static analysis products. This explains the focus on static analysis, among other things."

SonarSource 就是 SonarQube 的母公司,这篇论文的整个评估体系就是用 SonarQube 的规则在做"干净/脏"的定义。这跟研究本身是不是有效是两回事,但确实有点"卖瓜的说瓜甜"的味道。

我个人看完觉得:研究的方向是对的,数据也是真实的(660 次跑出来的),但解读要留点余地。代码整洁度对 Agent 有影响,这事儿方向没错;具体多大影响、多大可推广性,得打折扣看。

比论文本身更精彩:HN 评论区里的真材实料

评论区里吵吵归吵吵,但真有好几个高水平讨论,给的全是实战经验,比论文里写的还接地气。

1. AGENTS.md 配 "// LEGACY CODE" 注释是真实可用的

有位老哥说,他们项目里有一大堆历史遗留代码,Agent 跑过去就乱学,学完之后产出的代码混着新风格和旧风格,特别难看。LLM 上下文里抓到啥就用啥,不挑食。

他的解法是:让 Agent 主动给遗留代码加注释,写明这段代码是 legacy 的、不能当参考、不能清理。然后 AGENTS.md 里再写一条规则:当看到带 // LEGACY CODE 标记的代码段时,不要照搬它的风格。

markdown
1
// LEGACY CODE, per docs/legacy_rules.md §14, §19

这条评论下面又有人回:"我们就这么干,把 rules 集中放在 docs/legacy_rules.md 一份,注释里直接 link 过去,比写在 AGENTS.md 里好维护。" 确实是,老把规则塞 AGENTS.md 那文件就爆了。

2. Pre-commit hook 是 LLM 编程的真正护城河

好几条评论都在聊一个事:linter + pre-commit hook 比 LLM prompt 更管用。

核心观点:LLM 写的代码会"飘",同样的 prompt 跑两次结果可能差很远。但是 linter 是 deterministic 的,只要你写得出规则,它就一定能检查出来。所以搞 CI / pre-commit hook 的 ROI 远高于调 prompt。

yaml
1
# pre-commit-config.yaml
2
repos:
3
  - repo: https://github.com/astral-sh/ruff-pre-commit
4
    rev: v0.5.0
5
    hooks:
6
      - id: ruff
7
        args: [--fix, --exit-non-zero-on-fix]
8
  - repo: https://github.com/pre-commit/mirrors-mypy
9
    rev: v1.10.0
10
    hooks:
11
      - id: mypy
12
        additional_dependencies: [pydantic]
13
  - repo: https://github.com/hatchhq/tach
14
    rev: v0.9
15
    hooks:
16
      - id: tach
17
        # 强制 import 边界,防止跨模块依赖

hatchhq/tach 这个工具我之前没注意过,看了下是用 Python AST 强制 import 边界的,意思是 A 模块不准直接 import B 模块,CI 里如果违反就 fail。这种"架构级"约束光靠 linter 写不出来,但用 hook 卡住之后,Agent 写到一半就自动纠正了。

评论区里有位 ID 没看清楚的老哥说:"我让 Agent 自己 commit,pre-commit 跑挂了它会自己重试。这种机制下结构规则就跟在 LLM 上面装了一根缰绳一样。" 听起来有点夸张,但实际用起来确实是这种感觉。

3. "// Do not use your own knowledge." 这条 prompt 真有人用

HN 上有位说:"我最爱的 prompt 是 'Do not use your own knowledge.' 让 Agent 必须去查 docs 或在线资源,不要靠预训练。"

下一条立刻有人回:"这句话本身就是 incoheret。LLM 解释任何 instruction 都得用 prior knowledge,不然连你要它干啥都理解不了。"

接着又有人补:"不是这个意思。是让它优先去 grep / fetch docs,不是禁止它'思考'。你测试一下就知道。"

这个争论挺有意思的。我自己的体感是:如果 LLM 是在一个它训练时没见过的库里干活(大概率是新 API 或者内部库),"不要靠训练知识"这条提示确实有点用。问题是大多数情况下 Agent 会自动平衡"查 doc"和"靠记忆",你强行 push 它查 doc,反而会让一些简单任务变慢。属于"看你具体场景"。

4. 一个反向 case:messier 反而更好

论文自己都承认,他们发现一个反例:genie 项目里有一个任务,cleaner 版本反而多了 8% 的 token 消耗。

为啥?因为 cleanup pipeline 干了一件事:把 2800 行的 god class 拆成了"主逻辑 + 一堆 helper"。主逻辑没变长多少,但周围的环境变复杂了——Agent 找入口变容易了,但要确定自己改的版本跟别处的依赖是否兼容,得在更多文件之间跳来跳去。

这条 case study 我觉得最有价值:它说明"clean"不是一个绝对目标。过度抽象也是 dirty。论文里的 cleanup pipeline 用的是 SonarQube 默认规则集,但 SonarQube 不懂业务,只能告诉你"这个函数太长了"或"这个 if 嵌套太深",至于拆完之后业务上是不是更清晰,它管不了。

5. 一个特别欢乐的 sub-thread

有人开玩笑说:"你试过告诉 Agent 'write perfect code, make no mistakes' 吗?经典 prompt 神技!它不是不会,就是你没告诉它!"

下面立刻有人接梗:"所以你到底告诉它了没有?这不就是程序员经典的 '一改就崩,不改就不知道崩在哪' 吗?"

这种 chat 在 HN 上很常见,但其中隐含的工程观点其实是对的:写不出可执行规则的 prompt 永远是 LLM 的死穴。什么是 clean code?每个人的定义不一样。什么是 perfect code?更没法定。但"linter 通过 + test 通过 + 命名规范"是定的。能用工具卡的就别靠 prompt 提示。

论文的几个真实局限

论文作者自己列了 6 个 limitations,整理一下我看完印象比较深的:

  1. 单模型 + 单框架:只测了 Claude Sonnet 4.6 + Claude Code,没测 GPT、Gemini,也没测别的 harness。作者明说 transferability 是"猜想"不是结论。
  2. 只测 token 不测钱:token 是 cost proxy,但实际美元成本跟 cache 命中率、queue 等待时间、模型版本都有关。论文里的 7-8% 不能直接当 7-8% 的钱省。
  3. 没测 Agent 输出的"整洁度":一个很自然的 follow-up 是,clean code 喂进去之后,Agent 输出的代码是不是也变 clean 了?论文没跑这个。
  4. "clean" 是构造的,不是原生的:论文里的 cleaner 版本是 SonarQube 工具定义出来的"干净",不是真实世界里被资深工程师 review 过的那种"干净"。这两个可能差得很远。
  5. 短期测试:每个任务都是单次 task,没测长期演化。如果 Agent 在一个项目上跑一年,cleanliness 的影响是会累积还是会自我抵消?论文的实验设计回答不了这个问题。

第 5 条特别关键。论文里有个数据我印象很深:ckan 那个项目里有一个任务,cleaner 比 messier 少 24% 的 input tokens;同一个项目的另一个任务,cleaner 比 messier 反而多 44% 的 input tokens。同一个项目,不同任务,方向相反

这跟实际工程经验是吻合的:cleanliness 是必要不充分条件。你把代码搞整洁了,Agent 不一定更快;但你把代码搞得一团糟,Agent 一定会更慢。

我自己的总结:怎么看这个研究

如果让我用一句话给这个研究定个性:这是一个方向对、证据有限、但踩到了一个真问题的研究

说它方向对,是因为它在用一个别人没用过的实验设计回答一个真问题——代码库的"健康程度"对 AI 编程 Agent 来说到底算不算一回事?答案是算的。

说它证据有限,是因为它只测了 Claude 一个家族、一种 harness,cleanliness 的定义也比较狭窄(SonarQube 规则),实验规模(660 次)算中等但不算特别大。

说它踩到真问题,是因为 HN 评论区里那些实战派讨论,几乎都在绕着这个问题的不同侧面转:AGENTS.md 怎么写、pre-commit hook 怎么配置、命名规范怎么 enforce、legacy 代码怎么隔离。这些问题没一个论文能直接回答,但每个都是真在用 Claude Code / Cursor / Aider 的人每天在踩的坑。

回到实际操作,我看完这个研究之后给自己定的几条规矩(不一定对,欢迎评论区打脸):

  • 项目里没 AGENTS.md 的,先补上,哪怕只写三行
  • Pre-commit hook 必须配 ruff/mypy/tach 这些,不用纠结具体规则,先配了再说
  • 历史遗留代码如果改不动,就加个 // LEGACY CODE 注释 + 一份 docs/legacy_rules.md,让 Agent 自己看着办
  • 别迷信"完美 prompt",Linter 能卡的规则别让 LLM 来判断
  • 接受 LLM 代码有"漂移",定期(每个 sprint 末尾?)跑一次 SonarQube 看趋势,cleanliness 在变好还是变坏要心里有数

写到这里我突然想起评论区里的一句话,挺适合当结尾的:

"AI code is instant legacy code. You take on a lot of tech debt. Then you need to do the same work you would do with any legacy app."

AI 写出来的代码就是"即时的历史包袱"。你写得多快,债就欠得多快。区别是,AI 写的债比人写的债长得更难看,欠得更快,所以治理工具比 prompt 更重要。

后面打算试试 tach 这个 import boundary 工具,用一段时间再来写一篇。看有人说它在 LLM 编程场景下比 linter 更管用,号称"AI 时代的架构师"。

有啥问题评论区聊。论文地址在 arXiv:2605.20049,HN 讨论在 item?id=48798815

扩展阅读:跟这篇研究相关的三篇论文

读完这篇论文我又顺藤摸瓜翻了几篇相关的,正好可以做个简短对比。

SlopCodeBench:长期任务下 Agent 输出的"漂移"

这篇研究的是另一个问题:Agent 写代码写到第 N 轮的时候,它自己产出的代码会变成什么样?答案不太好看——Agent 自己迭代出来的代码,到最后长度是人工维护代码的 2.3 倍。也就是说,Agent 在一个项目里干得越久,代码越啰嗦。

这跟上面那篇研究是天然互补的:上面那篇研究说的是"输入端的代码有多干净"影响"Agent 干活的效率",这篇说的是"输出端的代码有多干净"受 Agent 行为模式影响。两篇合在一起看,cleanliness 在 Agent 编程场景下确实是双向问题——既要治理输入,也要防止输出。

Tokenomics:代码评审阶段吃掉了一半的 token

另一篇是 Salim 等人 2026 年发的 MSR 论文。他们拆解了 ChatDev 在 GPT-5 上的 token 消耗分布,发现代码评审(code review)阶段一个就吃掉 59.4% 的总 token,其中 input token 占 53.9%。

这条数据有意思的地方在于:它解释了为什么文件重读次数这么重要。code review 阶段 Agent 大量的工作就是反复回看代码——这段改完了,跟原来的接口对不对得上?测试覆盖到了没?行为是不是变了?文件重读每次都要重新把文件内容拉进 context(input token 累积),次数越多,token 消耗越爆炸。

如果 cleanliness 能把文件重读降 34%,那 review 阶段省下来的 token 远不止 7-8%。论文的 7-8% 是个汇总数据,但具体到 review-heavy 的项目,节省可能更大。

SWE-bench 上的"expensive failures"

还有一篇 SWE-Effi 提了一个很反直觉的发现:失败的任务平均消耗的 token 是成功任务的 4 倍。失败不是"少花点 token 早早认输",失败是"反复尝试、反复回滚、反复改方案",比成功消耗更多。

这条跟我们的主题怎么连起来?很简单:clean code 不会让 Agent 更聪明(通过率没变),但它确实让 Agent 在做对任务时少绕弯路。如果 Agent 一次性能把活儿干对,那 7-8% 的 token 节省 + 34% 的重读减少就是实打实的 ROI。如果 Agent 反复失败,那 cleanliness 救不了你——失败的原因是任务本身或者模型能力,跟代码风格没关系。

这给我们的工程启示是:cleanliness 是一种"放大器",任务简单时放大正面效果,任务复杂时省不了太多。指望它"力挽狂澜"不现实。

实操:怎么给 AI 编程项目打分

看完论文之后,我顺手研究了 SonarQube 在 AI 编程项目里到底怎么用。结果发现:很多人装上 SonarQube 就跑了一次,然后放着不管。这其实挺浪费的。SonarQube 的真正价值在于趋势跟踪

下面是一个相对完整的 SonarQube 集成流程(基于我正在用的一个 Python + TypeScript 混合项目):

1. 装 SonarQube(自托管或云端都行)

自托管用 Docker:

bash
1
docker run -d --name sonarqube \
2
  - p 9000:9000 \
3
  - v sonarqube_data:/opt/sonarqube/data \
4
  - v sonarqube_logs:/opt/sonarqube/logs \
5
  - v sonarqube_extensions:/opt/sonarqube/extensions \
6
  sonarqube:lts-community

第一次访问 http://localhost:9000,admin/admin 登录,强制改密码。然后创建项目,生成 token。

2. 在 CI 里跑 SonarQube Scanner

GitHub Actions 配置:

yaml
1
name: SonarQube Analysis
2
on: [push, pull_request]
3
 
4
jobs:
5
  sonar:
6
    runs-on: ubuntu-latest
7
    steps:
8
      - uses: actions/checkout@v4
9
        with:
10
          fetch-depth: 0  # SonarQube 需要完整历史
11
      - name: SonarQube Scan
12
        uses: sonarsource/sonarqube-scan-action@v2
13
        env:
14
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
15
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

sonar-project.properties 配置:

properties
1
sonar.projectKey=my-ai-project
2
sonar.sources=src
3
sonar.exclusions=**/node_modules/**,**/dist/**,**/__pycache__/**
4
 
5
# Python
6
sonar.python.coverage.reportPaths=coverage.xml
7
 
8
# TypeScript
9
sonar.typescript.tsconfigPaths=tsconfig.json
10
sonar.javascript.lcov.reportPaths=coverage/lcov.info

3. 关键:把 SonarQube 接入 AI 编程工作流

光跑 SonarQube 没用,关键是让它影响 Agent 的行为。我用了两个办法:

办法 A:在 PR 流程里硬卡

yaml
1
# GitHub Actions - 阻断合并
2
- name: SonarQube Quality Gate
3
  uses: sonarsource/sonarqube-quality-gate-action@v2
4
  env:
5
    SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
6
- name: Block merge if quality gate fails
7
  run: |
8
    if [ "${{ steps.sonar-quality-gate.outputs.conclusion }}" != "success" ]; then
9
      echo "Quality gate failed, blocking merge"
10
      exit 1
11
    fi

办法 B:把 SonarQube 报告喂给 AGENTS.md

每周跑一次 SonarQube,把"质量趋势"那段同步到一个文件里,然后让 Agent 读这个文件作为"项目健康状况"参考:

bash
1
# 每周日 23:00 同步
2
0 23 * * 0 cd /home/user/project && \
3
  curl -s -u $SONAR_TOKEN: "https://sonar.example.com/api/measures/component?component=my-project&metricKeys=new_code_smells,new_bugs,new_vulnerabilities,coverage" \
4
  | jq '.component.measures' > reports/sonar_weekly.json

AGENTS.md 里加一段:

markdown
1
## 项目质量基线(每周日更新)
2
- 当前新代码 issue 密度:2.1 / kLOC
3
- 上周:2.4 / kLOC
4
- 目标:< 1.5 / kLOC
5
- 当前 coverage:78%
6
- 目标:> 85%
7
 
8
如果你的改动会显著恶化上述指标,请在 PR description 里说明原因。

这种"基线对比"的写法比"必须 clean code"这种空话有效得多。LLM 对具体数字有反应,对抽象口号没反应。

4. 一个我踩过的坑

第一次配 SonarQube 的时候,我把 quality gate 设在"零 issue 通过"(default quality gate 的最严一档),结果一个老项目 PR 全挂,团队直接怨声载道。后来改成"新增代码 issue 密度 < 5 / kLOC",并且只对新增代码设卡(不是历史代码),这才顺起来。

教训:cleanliness 是趋势指标,不是绝对指标。你不能拿论文里的"cleaner vs messier"来要求历史项目一夜之间变干净。把 cleanliness 治理当成"控制增量"的事来做,而不是"清理存量"的事。

跟 headroom 那个工具的关系

顺便说一下,之前我们聊过 headroom 这个工具(省 60-95% 上下文开销的那个),它解决的是"已经发生的 token 消耗怎么降"的问题。本文讨论的 cleanliness 解决的是"为什么会产生那么多 token 消耗"的问题。两个是上下游关系:

  • 治理好 cleanliness → 输入的 token 减少 7-8%(前端)
  • 上 headroom → 剩下的 token 进一步压缩 60-95%(后端)

两个都用上,能省下来的 token 是 1 - (1-0.075) × (1-0.7) ≈ 72% 起步。这数字对在 Claude Code / Cursor 上每月烧几千块的团队来说相当可观。

我个人现在的组合是:cleanliness 治理(pre-commit + AGENTS.md + SonarQube 趋势跟踪)做基础,headroom 兜底。两者都是基础设施类的工具,不是 prompt 调优那种"调一下可能好一点也可能没变化"的事。基础设施投入是有复利的。

常见问题 FAQ

最后回答几个我在读论文和评论区时想到的问题:

Q1:clean code 这个事到底是不是玄学?

不是。SonarQube 之类的工具把"干净"量化成了具体的规则:函数长度、嵌套深度、命名长度、重复行数、复杂度评分、注释覆盖率等几十个维度。每个规则都有具体的代码模式可以检查。这是 deterministic 的,不是主观判断。论文的实验也是基于这种 deterministic 量化做的。

Q2:那是不是说,只要 SonarQube 跑过零 issue,Agent 就一定最高效?

也不是。论文里有一个 case,cleaner 版本反而多花了 8% token。原因是 cleanup pipeline 把代码拆得太细,Agent 反而要在更多文件之间跳转。过度抽象本身就是另一种脏。SonarQube 测的是"模式合规",不是"结构最优"。

Q3:我自己写代码要不要为了 Agent 改变风格?

不用。论文的核心结论是"cleanliness 对 Agent 有正面影响",不是"必须改用某种风格来迁就 Agent"。如果你自己写的代码就是 human-readable 的,那大概率也是 agent-readable 的。这两者的判断标准重叠度很高:具名变量、小函数、清晰命名、适度抽象。

Q4:哪些代码风格对 Agent 特别不友好?

我看完论文 + 评论区总结了一下,Agent 最不喜欢的代码风格:

  • 匿名函数/lambda 链长到一屏装不下(Agent 要读 50 行才知道这玩意儿在干啥)
  • 命名不规范的缩写_xfm_q2 这种,Agent 没办法 grep 关联)
  • 循环依赖(A 改完要去 B 看看,B 改完要去 C 看看,C 改完又要回 A 看)
  • 大量 magic number(Agent 不知道哪些是相关的)
  • 被注释掉的旧代码(Agent 不知道是不是 dead code,可能去理解它)
  • 多语言混写但没有清晰边界(Python 文件里嵌 SQL,SQL 文件里嵌 Python)

这些听起来也都是"人不友好"的代码。所以 cleanliness 不是一个为了 Agent 单独设计的东西,它本来就是为可维护性设计的东西,Agent 顺便受益。

Q5:将来 Agent 自己写的代码会不会越来越脏?

SlopCodeBench 的数据说是的——2.3 倍长度。SlopCodeBench 测的是 Agent 反复迭代的代码长度变化,没测具体的"清洁度"指标,但 length 跟 complexity 是相关的。论文里也承认这是它们的 follow-up 问题之一:

"A natural follow-up question is whether agents working on cleaner code produce cleaner code in turn. We did not run SonarQube against the agent's final state, and cannot speak to whether cleanliness is self-reinforcing or self-eroding under agent work."

我的猜测:会。LLM 写代码的默认风格就是"啰嗦但不复杂",因为训练数据里这种代码最多。SonarQube 跑一轮能挡掉大部分问题,但"自然漂移"挡不住。这是为啥我觉得持续跑 SonarQube 比一次性刷干净重要

Q6:其他大模型(GPT-5.6 / Gemini 2.5)会有类似结果吗?

论文自己没测,所以严格来说不能下定论。但从机制上看,cleanliness 影响的是 Agent 的导航和重读行为,不是模型的"思考能力"。任何需要频繁 grep/读文件/确认修改的 Agent 都会受益,包括 GPT、Gemini、Qwen、Grok 系。机制普适,量级待验

写在最后

写到最后发现一个有点讽刺的事:SonarSource 发了一篇研究证明"代码整洁度影响 AI Agent",HN 上 139 分,评论区里最有价值的几条评论都在讲"pre-commit hook + AGENTS.md + 确定性 linter"——也就是说,大家看完论文的第一反应不是"我要让 LLM 写更干净的代码",而是"我要让 linter 帮我卡住 LLM"。

这其实就是过去十年我们写代码的剧情重演:人写得糙的时候,linter 来收尾;LLM 写得糙的时候,还是 linter 来收尾。工具换了,治理逻辑没变。

下一个要研究的问题可能是:**哪些 SonarQube 规则对 Agent 影响最大?**论文汇总了 7-8% 的整体数据,但没有按规则拆分。如果能跑出来"function length > 50 行的代码改一遍"或者"嵌套深度 > 4 的代码改一遍"具体对 Agent 的影响是多少,那对工程实践的指导意义就大得多了。

但那是另一篇论文要做的事了。后面打算把 tach 那个 import boundary 工具在 AI 编程项目里用一段时间,看看到底是不是像 HN 上吹的那么神,用完再写一篇。

有问题评论区聊。

  • 本文写于 2026 年 7 月 6 日,数据基于 arXiv:2605.20049 v1 + HN 评论区 + SonarQube 实际集成经验。论文地址 arXiv:2605.20049,HN 讨论 item?id=48798815。*

advertisement