看 Spring I/O 2026《Claude Code for Spring Developers》:从 vibe coding 翻车到 agentic engineering
目录
Thomas Schilling(tschuehly,PhotoQuest 创始人,Spring/Kotlin/HTMX 圈常客,做过 Spring ViewComponent)在 Spring I/O 2026(巴塞罗那)做了一场 Claude Code for Spring Developers。主张很冲:2026 年还不用 Claude Code,你就在白白错过一次巨大的效率提升。
但这场 talk 真正的价值在它的结构:他用同一个功能反复迭代——先演示「什么都不配」的 vibe coding 怎么翻车,再一层层加上 Context、Skills、Hooks、MCP、Workflows,最后收拢成一套可复用的 “agent stack”。他自己的 Claude Code 使用数据也为这套方法背书:3,700+ commits、1,700+ sessions、11k+ prompts、提交速度约 5×——连这些 slides 本身都是用 Claude Code 做的。
本文以他的 slides 八个板块为骨架;其中
/interview和 Gradle 代理 hook 两处,参考了他配套的两篇博客(见文末)补全细节。
主线:一个功能,从翻车到工程化#
Demo 是 PhotoQuest 里的一个照片表情投票游戏(库表就叫 ranking_game):大屏轮播照片,宾客扫码加入,每人有一份固定的表情额度(3❤️ + 3😂 + 3😮)投给喜欢的照片,限时参与,最后揭晓每个表情类别下票数最高的前三张。同一功能他做了很多遍,每遍都比上一遍多给 Claude 一层支持。
agent 的工作循环是 Read → Plan → Act → Observe → Repeat。顺的时候很顺:给计时加上 1–30 分钟校验,它新建 InvalidTimerDurationException、加上 if (timerSeconds < 60 || timerSeconds > 1800)、确认编译通过,全程 1 分 24 秒。
但 Iteration 1(vibe coding 基线,不写 CLAUDE.md、不配 skill、不规划,直接让它"把游戏做出来")很难看:
| 指标 | Iteration 1(裸跑) |
|---|---|
| 测试 | 0 |
| 人工抓出的 bug | 8 |
| 漏掉的关键状态 | 整个 REVEAL(揭晓)状态被跳过 |
| 其它 | JSON 直接渲染到页面上、图片重叠、票数算错 |
| 上下文占用 | 98%(202,719 tokens) |
他给这页留了贯穿全场的一句:
The agent only knows what’s in context.
后面每个板块,本质都在解决同一个问题:怎么把"该进上下文的东西"可靠地喂进去(也及时移出去)。 加了 onboarding 之后,同一个功能:
| 指标 | Iteration 1 | Iteration 2 |
|---|---|---|
| 测试 | 0 | 37 |
| 设计决策 | 0(Claude 自己猜) | 20(interview 逼出来的) |
| CLAUDE.md 规则 | 0 | 8 |
| 子代理会话 | 0 | 3 |
基础:把 Claude Code 当一个"最快的同事"#
- 接口任选:CLI、VS Code / IntelliJ、桌面端、Web、手机,甚至 Slack 和 GitHub Actions。
- 挑模型、调力度:简单高频用 Sonnet(便宜,适合跑大量 subagent);复杂架构、跨文件重构、规划、调试用 Opus。再叠
/effort档位(low/medium/high/max)。 - 安全网 checkpoints:
/rewind回退、/branch开实验分支——“experimentation is free”,跑歪了 rewind 回去就行。 - subagent:开独立上下文去调研,主会话保持精简。例如让 subagent 摸清 SSE 通知链路(
Guest 上传 → pg_notify → NotificationService → Reactor Sink → SSE),主会话不被淹没。 - headless:
claude -p "..."跑无界面;PR 评论里@claude触发 GitHub Actions。
他特意点出 “The Spring advantage”:强约定降低歧义、编译期校验早抓错、内建可测试性、可预测的结构让 agent 易于导航——“Your stack is your advantage.” 平时嫌弃的"框架太有规矩",恰恰是 agent 最能稳定发挥的环境。
Context:每一次会话都是"第一天"#
Every session is day one.
Claude 每开一个会话都是失忆的新同事,上下文就是你给它做 onboarding 的唯一手段。翻车的典型:一次没开规划、用手机随口提需求,结果它把卡片排成"A4 一页 6 张",而真实要求是"A6 一页 1 张"。
工程化手段分几层:
CLAUDE.md 是长出来的,不是写出来的。 先放 5 行最关键信息,正常用,每出现一次不想要的行为就补一条规则,直到稳定:
Every rule needs to earn its place through a real failure.
里面的规则很 Kotlin/Spring:改完 Kotlin 必须 ./gradlew compileKotlin compileTestKotlin;没跑测试/演示证明正确前不许标完成;多实例下别用内存去重,要用 DB 检查和 AdvisoryLock.kt 做分布式一致。
按路径加载的 scoped rules(.claude/rules/),碰到对应目录才加载,主上下文保持干净:
.claude/rules/
├── kotlin-conventions.md (src/main/kotlin/**)
├── viewcomponent.md (src/main/kotlin/page/**)
├── tailwind-daisyui.md (src/**/*.html)
├── testing.md (src/test/**)
└── payment.md (src/**/payment/**)
记忆三层:CLAUDE.md(最关键、进 git)→ .claude/rules/(按路径条件加载)→ auto-memory(跨会话个人笔记,本地不进 git)。
管好上下文预算:/context 看占用、/compact 手动压缩。但他更推荐主动收尾、开新会话——上下文越满表现越退化。做法:把状态记进 markdown 计划文件,手动结束当前会话,给下一个会话写一段 continuation prompt。
Skills:把资深工程师会"口述"的东西写下来#
If a senior dev wrote down how they approach architecture, git flow, and domain knowledge — that’s a skill.
CLAUDE.md 与 skill 的根本区别是 always-on 还是 on-demand:
- CLAUDE.md(常驻):会话一开始就加载,适合"永远要做 X";代价是一直占上下文、注意力会从当前任务漂走。
- Skills(按需):开始只加载描述,调用时才载入完整内容,适合参考文档和可复用工作流。
他的核心 skill:/interview(AI 主导的结构化访谈)、/tdd-task(严格 RED→GREEN→REFACTOR)、/test(跑测试、只报失败)、/commit(按功能分组提交,SKILL.md 就 8 行)。skills 库见 jvmskills.com,专为 JVM 生态精选整理(Spring Boot、jOOQ、PostgreSQL、Kotlin、testing)。
/interview 是这节重头,直接针对 Iteration 1 的"瞎猜":subagent 先探索代码库,再用决策树逐项 interview——入口放哪、照片来源、宾客怎么加入、提交流程、反作弊(选了服务端强制)、存储模型、最少照片数、宾客交互。一轮产出 171 行 spec、8 轮决策点。
他还演示怎么 review spec:通读,用 % 标可疑决策,对 10+ 处追问,逐条判断价值——Claude 主动提的 10 个改动里 8 个被判定不必要。
最有冲击力的反例是 “missing nav link” 问题:7 个阶段都实现了、17 个测试全绿,但功能根本点不进去——没人问过"用户怎么走到这儿"。结论是 “Fix the process, not just the bug”:于是他迭代了 /interview 这个 skill 本身——把强制话题固定为"入口、用户从头到尾的旅程、边界情况、状态转移、终止态与死胡同",并要求导航类 user story 排最前。结果:26 条 user story,零遗漏入口。
他博客里用 AskUserQuestionTool 规划 Spring Security 7 迁移是同一套
/interview打法:两轮 interview 把"给 JWT 加字段"问成"整体迁离 Supabase Auth、删 ~700 行鉴权代码",产出 900 行实现级 spec。先把问题问清楚再写代码是这套方法的内核。
Hooks:让规则真正"粘住"#
CLAUDE.md 和 skill 是软约束,模型可能漂走;hook 提供确定性。生命周期:SessionStart → PreToolUse → PostToolUse → SessionEnd;四种类型:command/http/prompt/agent。
他实际在用的:
| 事件 | 工具 | 脚本 | 作用 |
|---|---|---|---|
| PreToolUse | Bash | git-guardrails.sh |
拦危险 git 命令 |
| PreToolUse | Bash | pre-commit-gate.sh |
lint/编译没过不许提交 |
| PostToolUse | Edit/Write | post-edit-lint.sh |
把 lint 违规反馈回去 |
| SessionEnd | — | stop-uncommitted-check.sh |
有未提交改动就告警 |
PreToolUse 用 exit code 2 硬拦截(Claude 无法继续):
DANGEROUS_PATTERNS=("git push" "git reset --hard" "git clean -fd" \
"git branch -D" "git checkout ." "git restore .")
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
if echo "$COMMAND" | grep -qE "$pattern"; then
echo "BLOCKED: '$COMMAND' matches '$pattern'" >&2
exit 2
fi
done
他甚至用 hook 强制走 skill 而非裸命令——拦下 gradlew test,提示 “Use the /test skill instead”。PostToolUse 是自纠错闭环:导入了 Jackson 2 的 ObjectMapper,hook 立刻拦下并提示改用 Jackson 3 的 JsonMapper——这个错以后再也不会犯了。一句总结:
Anything you can put in a hook — put it in a hook.
他那个 Gradle 代理 hook 是 JVM 实战:Claude Code Web 沙箱走 HTTP 代理,但 Java 的
HttpURLConnection无视https_proxy,Gradle 每次UnknownHostException;用PreToolUsehook 把代理写进~/.gradle/gradle.properties并预热依赖缓存解决。
MCP:让 agent 把 IDE 当 API 调用#
MCP 是连接 AI 与外部工具的开放标准。他接了 Sentry(错误监控)、Linear(任务)、JavaDoc Central(最新 JVM 库文档)、IntelliJ(reformat_file、rename、execute_run_configuration),还用 Spring AI 自己写 MCP server。
最让 Spring 开发者有共鸣的,是 agent 自身的开发体验对比:
| 没有 MCP | 有 IntelliJ MCP |
|---|---|
用 sed 重排格式 |
reformat_file |
| 手动修 import | 自动优化 import |
| 靠 Gradle 启动 | execute_run_configuration |
The IDE becomes an API that agent calls.
落地时他不直接暴露裸 MCP,而是包进 skill:/restart = 先停掉旧应用 → 用 MCP 启动(execute_run_configuration())→ 等就绪 → 查错误日志。
Workflows:五个层级,按问题匹配打法#
核心:不是每个任务都用同一套流程,要按问题类型匹配。
- Human in the loop:描述、看着做、随时纠偏。适合范围还小、盯得过来的时候。
- Plan Mode(Shift+Tab 或自发进入):探索、原型、迭代,不需预先写 spec。适合它老猜错、需求只在你脑子里的时候。
- Spec-Driven:先和领域/UX/产品敲 spec 再写代码。适合 What 不明显、只有 Why 的时候。
- Drift Problem:跨 7 个阶段时,各 skill 触发得越来越不稳定——agent 不是确定性机器,上下文越满,注意力越容易跑偏。
- The Ralph Loop:每个阶段开一个全新 agent(不累积漂移),Interview → Spec → Plan → Phase 1 Agent → Phase 2 Agent → …。
两条配套纪律:
- 从 checklist 到 contract:用扁平 markdown 清单(纯文字、无强制)时只产出 39 个测试;改用
TodoWrite把任务变成可跟踪的状态后,涨到 60 个。让"指令"变成"被跟踪的状态"。 - 多模型 review:同分支同 prompt 让两个不同模型当 reviewer,Claude 抓出计时器挂死/预算竞态,另一个模型抓出 manager 控件暴露/脚本注入——不同模型盲区不同。
配套工具#
- 隔离 blast radius:
/sandbox在 OS 层围住文件系统和网络;更彻底的做法是 Docker microVM——一次性、隔离,agent 跑飞了直接丢掉。 - 语音输入:handy.computer(开源、本地),说话比打字快,而且"说出来"会暴露你的推理。
- 并行不打架:Worktrunk——每条分支配独立 git worktree、专属 Postgres、专属 LocalStack,多 agent 并行零冲突。
- 整干净历史:
/rebase-commit把 46 个调试提交整成 10 个"功能+对应测试"的原子提交。
落点:你的"新工作"——一套会复利的 agent stack#
talk 最后把一切收拢成四层:
| 层 | 是什么 | 关键点 |
|---|---|---|
| CLAUDE.md | 项目上下文 | 因"真实失败"一条条长出来;下次会话从上次终点开始 |
| skills/ | 你早该写的文档 | /interview、/tdd-task、/test、/commit、/restart;按你的栈定制 |
| hooks/ | 真正粘住的规则 | PreToolUse/PostToolUse;约束叠加、错误不复发 |
| workflow | 五个层级 | 按问题类型匹配;改 bug ≠ 做复杂功能 |
他用 Thoughtworks 一句话点题:
Engineering quality doesn’t disappear when AI writes code. It migrates to specs, tests, constraints, and risk management.
以及几句很冲的收尾:当实现变便宜,瓶颈挪到判断力——建什么、对不对、谁担后果;“Building bad software has never been easier”,速度免费、纪律得你自己上;“You will fall behind” 不是因为 AI 取代你,而是因为用它的工程师每天都在积累复利。
几点笔记(个人观点)#
-
这场 talk 最聪明的是它的"对照实验"结构。 它没吹 AI 多神,而是先摆出 Iteration 1 的难看数据(0 测试、8 bug、漏掉整个 REVEAL 状态、98% 上下文),再让你看着同一功能在加了 Context/Skills/Hooks 后变成 37→60 个测试。它证明了收益不来自模型,而来自你给它搭的脚手架。
-
“The agent only knows what’s in context” 几乎是整套方法的公理。 CLAUDE.md、scoped rules、skills、hooks、subagent、Ralph loop 拆开是六件事,合起来只解决一个问题:在正确时刻,把正确的东西放进、并及时移出上下文。 想清楚这点,就能自己判断一个新
/xxx该属于哪一层。 -
对 Spring 开发者,“你的栈就是你的优势"要敢信。 强约定、编译期校验、可预测结构、内建可测试性,正是 agent 最需要的护栏。把
./gradlew compileKotlin、AdvisoryLock.kt、Jackson 3 import 检查这类很具体的 JVM 规则塞进 hook,等于把 Spring 的确定性直接喂给不确定的模型——这点是 Python 那种弱约定栈学不来的。 -
/interview这条线最值得直接借鉴。 它的关键不只是"先问后写”,而是当流程出问题时去改 skill 本身,而不是改这次的代码(“fix the process, not the bug”)。“missing nav link”——17 个测试全绿但功能点不进去——是对"测试覆盖 ≠ 需求覆盖"最生动的提醒。 -
Hooks 是最被低估的一层。 CLAUDE.md 和 skill 都是软约束,模型心情不好就漂了;只有 hook(PreToolUse 硬拦截 + PostToolUse 自纠错)是真确定性。我打算先做两个最低成本的:
git-guardrails(拦push/reset --hard)和pre-commit-gate(编译/lint 不过不许提交)。 -
几点保留:Ralph loop、Worktrunk 这类重型工作流对个人 SaaS 划算,搬到有合规和数据边界的团队前得先算清权限和成本;“不用就落后/每天复利"有 FOMO 成分,能复用的是他的 stack,不是焦虑;他给的数字(171 行、26 user story、60 测试)是单项目体感,别当 KPI——真正要学的是**“每条规则都因一次真实失败而生"这条克制原则**,否则 CLAUDE.md 很快膨胀成没人看的垃圾场。