导读:知乎上"作为大学生几乎丧失手搓代码的能力,需要焦虑吗"有 122 万浏览,掘金 AI 热榜第二是"AI 正在蚕食我们的编码能力"。Claude Code 自带一个 Learning 输出风格,官方说它会把有取舍的那几行代码留给你写。我拿同一个 Java 小需求在 2.1.299 上跑了 9 次:内置 Learning 一次都没留,自己写一个 20 行的风格文件才稳定生效。这篇讲怎么配、实测结果和该怎么用。
一、先说清楚:输出风格是什么,Learning 想解决什么
输出风格(output style) 是一段写给 Claude 的固定指令,决定它整场会话怎么跟你说话、怎么干活。默认风格就是"把活干完";Claude Code 另外内置了四种:
| 风格 | 变化 |
|---|---|
| Proactive | 不问琐碎决定,直接开工 |
| Concise | 先给结果,少说过程 |
| Explanatory | 写代码时附带 ★ Insight 解释块,讲为什么这么写 |
| Learning | 在 Explanatory 基础上,把有设计取舍的几行用待写标记留给你写,然后停下等你 |
Learning 针对的就是"AI 全写了、自己越来越不会写"这件事:样板代码 AI 写,业务判断、边界处理这种真正练手的部分留给人。留给人的位置,文件里会是这样一行注释(下文统一叫"待写标记"):
// TODO(human): 按业务规则算出实付金额:满 200 减 20、叠加折扣券、保留两位小数、不能小于 0
这不是空担心。Anthropic 2026 年 1 月发过一项随机对照实验:52 名(大多是初级)工程师学一个没用过的 Python 库,用 AI 助手的一组事后测验平均 50 分,手写的一组 67 分,差距最大的是调试题;完成时间两组差不多。研究也提到,用 AI 时多追问、多让它解释的人,分数没掉那么多。
什么时候值得动它:
- 在学新框架、新语言,或者带新人,想保留"自己动手"这一环
- 觉得 AI 写的代码自己已经看不太懂了
- 日常赶工期、只要结果的时候,不用开,默认风格就好
二、测试方法
| 项 | 值 |
|---|---|
| Claude Code | 2.1.299(/output-style 命令要 2.1.269 及以上) |
| 运行方式 | claude -p 非交互模式,--setting-sources project,只读项目自己的 .claude/settings.json,排除我全局配置的干扰 |
| 模型 | Sonnet 7 次,Opus 1 次 |
| 需求 | 同一句话:给 CouponCalculator.calculate 实现"满 200 减 20,可叠加折扣券,保留两位小数,不能小于 0",再写 Main 跑三个例子 |
这个需求故意带着没说清楚的取舍:先减后折还是先折后减(250 元配 9 折分别是 207 和 205)、"满 200"含不含 200、在哪一步舍入。按官方文档的说法,这正是 Learning 应该留给人写的地方。
起始代码只有一个空方法:
package demo;
import java.math.BigDecimal;
public class CouponCalculator {
/**
* 计算订单实付金额。
*
* @param orderAmount 订单原价
* @param discountRate 折扣券折扣率,例如 0.9 表示 9 折;没有折扣券时传 null
* @return 实付金额
*/
public BigDecimal calculate(BigDecimal orderAmount, BigDecimal discountRate) {
throw new UnsupportedOperationException("not implemented");
}
}
三、怎么开 Learning
三种方式,效果一样:
# 1. 会话里输入(2.1.269 起支持,不区分大小写)
/output-style learning
# 2. 终端里 /config,选 Output style
第三种是直接写配置文件,项目级放 .claude/settings.json 或 .claude/settings.local.json,想所有项目都生效就写进 ~/.claude/settings.json:
{
"outputStyle": "Learning"
}
⚠️ 配置文件里的值区分大小写,要写
Learning。官方文档说写成learning会静默退回默认风格,不报错。/output-style命令则不区分大小写。
四、实测:内置 Learning 4 次,一次都没留待写标记
先跑默认风格做对照,再跑 Learning:
| 第几次 | 风格 | 模型 | 文件里有待写标记 | 回复里有 Insight | 花费(美元) |
|---|---|---|---|---|---|
| 1 | Default | Sonnet | 无 | 无 | 0.180 |
| 2 | Learning | Sonnet | 无 | 有 | 0.195 |
| 3 | Learning | Sonnet | 无 | 有 | 0.096 |
| 4 | Learning | Sonnet | 无 | 有 | 0.115 |
| 5 | Learning | Opus | 无 | 有 | 0.370 |
风格确实生效了:4 次 Learning 的回复末尾都有 ★ Insight 块,讲了先减后折和先折后减的差别、new BigDecimal("0.9") 和 new BigDecimal(0.9) 的区别。但 calculate 每次都被 Claude 直接写完了,编译运行通过,然后告诉我"这几处需求没写明,我按下面的方式定了"。Opus 那次最接近"教学",结尾补了一句建议我自己加个例子、改改先后顺序看结果怎么变,但代码还是它写的。
所以 Learning 在我这个场景下,实际效果只等于 Explanatory。
为什么不留?我没找到确切原因,只能说两个可能:
- 官方文档自己就写了,输出风格只是给 Claude 的指令,不保证某件事一定发生
- 我的需求里写了"编译运行验证",等于要求它交付能跑的结果,和"留一半给人写"冲突。另外我只测了
claude -p,交互式会话里它能停下来等你,表现可能不一样,这个我没测
不管原因是哪个,结论是:想稳定地让 AI 把代码留给你,别指望内置 Learning 自己判断,把规则写死。
五、自己写一个输出风格:3 次都留了
输出风格就是一个 Markdown 文件,放在项目的 .claude/output-styles/ 下(个人全局放 ~/.claude/output-styles/)。我写的这个只有 20 行,规则写得很具体:哪些行留给人、留下后说什么、然后停下:
---
name: Java练手
description: 业务规则和边界处理留给我自己写,其余照常完成
keep-coding-instructions: true
---
每次实现功能时,把包含业务规则判断的那几行(金额计算顺序、边界条件、异常处理)留给用户自己写:
1. 在文件里写好方法签名、调用方和测试代码,只在需要用户写的位置放一行 `// TODO(human): <要写什么>`,不要替用户写出这几行
2. 在回复里说明:已经做好了什么、用户要写哪几行、要考虑哪些取舍(不给答案)
3. 然后停下来,等用户说写好了再继续:编译运行、检查用户的写法、指出问题
样板代码(getter、main 方法、编译命令)照常直接写完。
keep-coding-instructions: true 一定要加,它保留 Claude Code 默认的软件工程指令,否则 Claude 就不按写代码的方式工作了。
启用时 outputStyle 填 frontmatter 里的 name:
{
"outputStyle": "Java练手"
}
同一句需求跑 3 次(Sonnet):
| 第几次 | 文件里有待写标记 | Main 写好了 | 花费(美元) |
|---|---|---|---|
| 1 | 有 | 有 | 0.084 |
| 2 | 有 | 有,每个例子打印 OK / FAIL | 0.080 |
| 3 | 有 | 有 | 0.083 |
每次 calculate 里都只剩一行待写标记加一个占位的 throw,回复里列出要写的几行和要权衡的点。第 3 次给的提示我觉得最有用:
恰好 200 算不算满?用
compareTo,不要用equals,因为200.0和200.00的equals是 false。
它只给提示、不给答案,这正是规则里第 2 条要的。顺带一提,因为少写了业务代码,这 3 次每次只花 0.08 美元左右,比 Learning 和默认风格都便宜。
六、写完交回去:它抓出了我故意埋的边界 bug
接着在第 1 次的会话里,我自己把待写标记填上,故意把"满 200"写成大于(应该是大于等于):
public BigDecimal calculate(BigDecimal orderAmount, BigDecimal discountRate) {
BigDecimal amount = orderAmount;
if (amount.compareTo(new BigDecimal("200")) > 0) { // 故意写错:恰好 200 元不会减
amount = amount.subtract(new BigDecimal("20"));
}
if (discountRate != null) {
amount = amount.multiply(discountRate);
}
return amount.max(BigDecimal.ZERO).setScale(2, java.math.RoundingMode.HALF_UP);
}
然后用 --resume 接上原来的会话,只说一句"写好了,你检查一下":
# 在项目目录执行,<session-id> 是第一次运行时 JSON 输出里的 session_id
claude -p "写好了,你检查一下" --resume <session-id> --model sonnet
它的回复(节选):
编译通过,三个例子的结果都对,但有一个边界 bug。
订单=200, 折扣券=null -> 实付=200.00 ← 有问题
最后一行是我在 Main 里新加的边界例子,恰好 200 元。
CouponCalculator.java:16 用的是 compareTo(...) > 0。"满 200" 应该包含 200 元,
所以订单恰好 200 元时应该减 20,实付 180.00,现在却是 200.00。把比较改成"大于等于"就行。
原来的三个例子都碰不到这个边界,是它自己往 Main 里加了一个 200 元的用例跑出来的。另外它没有动我写的代码,只指出问题让我自己改,还提了两个"不影响结果"的点:RoundingMode 可以 import,orderAmount 为 null 没处理。
这一轮花了 0.135 美元。整个"AI 搭架子、人写关键几行、AI 跑测试挑错"的循环是通的。
七、怎么用才不变成摆设
几条建议:
- 规则写具体。"留给用户写"太模糊,写清楚哪类代码留(业务规则、边界、异常)、哪类不留(样板、main、编译命令),以及留下后要说什么
- 按项目放,不要全局开。练手的项目放项目级
.claude/output-styles/,赶工的项目用默认风格;全局开着很快就会被你关掉 - 留的量要小。一次留一个方法里的几行最合适,留整个类就变成你在写、它在看
- 交回时要它跑边界用例。这次它是主动加的,你也可以把"检查时补边界用例"写进风格文件第 3 条
- 团队带新人可以把风格文件提交到仓库,新人在项目里打开 Claude Code 就是这个模式
输出风格做不到的事也要知道:它是"建议"不是"强制"。要保证每次都发生的事(比如编辑后必须跑格式化、禁止某个命令),官方建议用 hook,不是输出风格。
八、速查表
| 要做的事 | 怎么做 |
|---|---|
| 临时切换风格 | 会话里 /output-style learning(2.1.269+) |
| 项目里固定风格 | .claude/settings.json 写 "outputStyle": "Learning"(区分大小写) |
| 所有项目默认 | ~/.claude/settings.json,项目配置优先级更高 |
| 自定义风格 | .claude/output-styles/java-practice.md,frontmatter 写 name、description、keep-coding-instructions: true |
| 只要解释不要留代码 | 用 Explanatory |
| 换回默认 | /output-style default 或删掉 outputStyle |
九、常见问题
Q:会话中途切风格,什么时候生效?
官方文档说从下一条消息开始生效(2.1.251 之前要 /clear 或开新会话)。文档另有一节讲切换后第一条消息对提示词缓存的影响,这部分我没测花费。
Q:Learning 在交互模式下会不会表现好一些?
可能会,我只测了 claude -p。如果你在交互会话里用 Learning 稳定看到过 ● Learn by Doing 和待写标记,欢迎在评论区说一下你的版本和需求类型。
Q:自定义风格会不会让 Claude 写代码变差?
加了 keep-coding-instructions: true 的话,默认的工程指令保留,只是追加你的规则。我这 3 次搭的架子(Main、编译命令、例子)都能直接用。
Q:桌面版 App 里怎么设置?
桌面版里 /config 会打开设置页而不是菜单,文档建议直接在 .claude/settings.local.json 里写 outputStyle。
参考链接
- Claude Code 文档:Output styles
- Anthropic Research:How AI assistance impacts the formation of coding skills
- Claude Code CHANGELOG
你用 AI 写代码时,会刻意留一部分自己写吗?留的是哪类代码:业务逻辑、SQL,还是测试?评论区说说,我把好的做法整理进风格文件里。
觉得有用的话点个赞、收个藏,下次想练手时翻得到。