芒格模型:能力圈 + 检查清单
模型决定上限,问题定义与验证决定下限
text
[读者] 用 Cursor 一类工具写生产代码的工程师与小组负责人
[痛点] 一句模糊指令换不来可交付代码,返工与无限试错在吃掉时间
[现在读] 工具和模型都到位了,缺的是把需求变成可验证契约的方法
[读完] 能把能力圈判断和检查清单落成一个能跑起来的校验脚本与 CI 门禁
text
[旧方案] 一句自然语言描述需求,直接让模型写代码
|
v
[新需求] 多模块、有外部依赖、要长期维护的生产代码
|
v
[冲突] 目标模糊时模型靠猜补全意图,越补越偏
|
v
[后果] 反复返工、缺陷外溢、评审成本高于手写
我是老李,带一个七八人的业务后端小组。去年开始我们把 Cursor 当主力编辑器,模型换过几轮,工具也换过,交付节奏却没有明显变快。真正让情况变化的,是两件很老的东西:芒格说的能力圈,和芒格用来避免犯错的检查清单。
能力圈说的是知道自己擅长什么、不擅长什么,不擅长的事要么避开,要么用别的方式兜住;检查清单说的是把容易漏的判断固化成条目,每次照做,不靠记性。
把这两件事搬到 AI 编程里,问题就变成下面三句。
需求描述模糊到什么程度,模型就开始靠猜?
是继续换更强的模型,还是先把问题定义写清楚?
如果清单只写在文档里没人执行,它跟没有有什么区别?
01、故事
场景是订单服务接入新的支付通道。任务是给下单接口加一个幂等键,让支付回调重试时不重复创建订单。
当时的做法很典型:我在对话框里敲了一句「给订单创建接口加上幂等支持,防止重复下单」,模型几秒内返回两百多行改动。它改了下单接口,改了仓储层,还顺手调整了库存扣减的调用顺序,并在注释里写下「保证并发安全」。
评审时暴露出三件事。第一,库存扣减不该在这次变更范围内,但没人提前说明;第二,幂等键存在哪里、多久过期,模型自己选了,跟我们既有的缓存约定不一致;第三,没有一条测试覆盖重复提交。
这次返工不是模型写错了代码,而是我们在开始之前就没说清要什么、不要什么、怎么算做完。
一句模糊话
十次重生成
边界无人问
返工已成舟
02、问题
旧方案失效点:自然语言提示里只有动作,没有约束和验收。模型只能用自己的先验去补全,而补全方向和我们仓库里的隐式约定并不一致。
业务影响:改动范围外溢到库存服务,评审要重新确认整条调用链;幂等键策略与既有缓存约定冲突,上线前还得二次设计。
技术表现:变更文件数超出预期、缺少并发与重复提交的测试、边界条件(缺 Header、键已过期)的行为没有定义。
这次改造的完成标准必须可验证:
- 同一幂等键重复提交只产生一条订单记录;
- 缺失或非法 Idempotency-Key 时返回明确的 4xx 与 error_code 字段;
- 幂等键过期后的行为有明确定义,拒绝或重新创建,二选一写死在需求卡里;
- 变更文件清单可枚举,且不包含库存服务;
- 至少一条自动化测试覆盖「同键重复提交」。
旧法已失效
影响在扩散
表现可观测
标准须可验
03、原理
判断一件事在不在能力圈内,看的是模型训练分布里有没有这类问题的密集样本。常见框架的 CRUD、有大量公开示例的写法、语言层面的惯用法,都在圈内;只存在于你仓库里的隐式约定、跨服务边界、压根没写进代码的业务规则,都在圈外。
反直觉判断:给模型更多上下文不等于更准。把整个文件、整个仓库塞进上下文,会让真正起约束作用的那几行被无关代码稀释,模型会在看起来合理的位置继续补全。有效上下文是约束,不是代码量。
反直觉判断:更强的模型不会抹平问题定义上的差距,反而会放大它。定义清楚时,强模型一次就能给出接近可交付的改动;定义模糊时,它会更快、更自信地朝错误方向走得更远。
检查清单的价值就在这里:把「我脑子里的验收标准」变成「可以逐条核对的断言」,把能力圈外的那部分工作,用普通人能执行的流程兜住。
七步清单是:需求澄清 → 任务拆分 → 接口与边界约定 → 测试用例 → 编码实现 → 结果校验 → 人工评审。
圈内可托付
圈外须设防
多给非多益
强模放差距
04、架构
text
[输入] 业务目标 + 范围约束 + 输入输出 + 验收标准
|
v
[模块] 需求卡校验器 / 任务拆分器 / 契约测试生成器
|
v
[数据/状态] task.json:goal、scope_in、scope_out、io、acceptance、risks
|
v
[处理] 清单逐项校验 → 提示骨架 → 模型编码 → 测试与静态扫描 → 人工评审
|
v
[输出] 边界内的变更 + 可追溯的验收证据
边界:这套结构管的是「问题定义与验证」,不管模型内部怎么生成代码。它默认任务可拆分、验收标准可观察;对于还没想清楚要什么的探索性任务,不要套这套东西。
收益:范围外溢变得可检测,因为 scope_out 是显式字段;验收标准从口头承诺变成条目;人工评审只需要处理机器判断不了的部分。
代价:开工前要多花十几分钟写卡;对「先写起来再说」的习惯是一道直接的摩擦。
适用条件:多人协作、有外部依赖、需要长期维护的任务。
输入先固化
模块各守界
状态可追溯
输出有凭证
05、实战一次
环境:Python 3.9+,只用标准库;Git;Cursor,其规则文件与版本能力需按当前官方文档核验。
依赖:无第三方依赖。
配置:仓库根目录放一份 task.json。
json
{
"goal": "为订单创建接口增加幂等键支持,重复提交不产生重复订单",
"scope_in": ["订单创建接口", "幂等键存储与过期策略"],
"scope_out": ["库存服务", "支付网关回调格式"],
"io": {
"input": "HTTP JSON body + Header Idempotency-Key",
"output": "JSON: order_id (string), status (string)"
},
"acceptance": [
"同一幂等键重复提交只创建一个订单",
"接口返回要合理"
],
"risks": ["幂等键过期后重复提交可能穿透"]
}
核心实现,一个完整可跑的校验脚本 V1:
python
#!/usr/bin/env python3
'''checklist_gate.py ------ 把需求检查清单变成可执行门禁(V1)'''
import json
import sys
from pathlib import Path
REQUIRED = ['goal', 'scope_in', 'scope_out', 'io', 'acceptance', 'risks']
def load_card(path):
with Path(path).open(encoding='utf-8') as fh:
return json.load(fh)
def validate(card):
result = []
missing = [key for key in REQUIRED if key not in card]
result.append(('字段完整性', not missing, '缺失: %s' % missing if missing else '必需字段齐全'))
goal = str(card.get('goal', '')).strip()
result.append(('目标可陈述', len(goal) >= 8, '目标长度 %d 字符' % len(goal)))
scope_in = card.get('scope_in') or []
scope_out = card.get('scope_out') or []
result.append(('范围双向定义', bool(scope_in) and bool(scope_out),
'in=%d, out=%d' % (len(scope_in), len(scope_out))))
io = card.get('io') or {}
result.append(('输入输出明确', bool(io.get('input')) and bool(io.get('output')),
'input=%s output=%s' % (io.get('input'), io.get('output'))))
acceptance = card.get('acceptance') or []
result.append(('验收标准齐备', len(acceptance) >= 2, '条数 %d' % len(acceptance)))
risks = card.get('risks') or []
result.append(('风险已识别', len(risks) >= 1, '条数 %d' % len(risks)))
return result
def render(result):
failed = 0
for name, ok, detail in result:
if not ok:
failed += 1
print('[%s] %s | %s' % ('PASS' if ok else 'FAIL', name, detail))
if failed:
print('\n%d 项未通过:先补需求卡,再让模型写代码。' % failed)
return 1
print('\n全部通过:可以生成任务拆分与提示骨架。')
return 0
def main():
if len(sys.argv) != 2:
print('用法: python checklist_gate.py <task.json>')
return 2
return render(validate(load_card(sys.argv[1])))
if __name__ == '__main__':
sys.exit(main())
启动与验证:
console
$ python checklist_gate.py task.json
未在当前环境实测,以下为预期结果。示例输出:
console
$ python checklist_gate.py task.json
[PASS] 字段完整性 | 必需字段齐全
[PASS] 目标可陈述 | 目标长度 27 字符
[PASS] 范围双向定义 | in=2, out=2
[PASS] 输入输出明确 | input=HTTP JSON body + Header Idempotency-Key output=JSON: order_id (string), status (string)
[PASS] 验收标准齐备 | 条数 2
[PASS] 风险已识别 | 条数 1
全部通过:可以生成任务拆分与提示骨架。
V1 跑通了,但它留下一个明显的洞:接口返回要合理 这样完全不可验证的条目,照样拿到了 PASS。
一卡定目标
一跑见缺口
一验知真假
一纸留痕
06、排查
现象一:需求卡校验全部 PASS,模型给出的代码仍在评审时被打回。
怀疑:问题出在验收标准的写法上,而不是模型的水平上。
检查:把 acceptance 单独打印出来,逐条读。
console
$ python -c "import json;print(json.load(open('task.json'))['acceptance'])"
['同一幂等键重复提交只创建一个订单', '接口返回要合理']
证据:第二条「接口返回要合理」没有任何可观察对象,既没说状态码,也没说字段名。
根因:V1 的验收检查只数条数,不做可验证性判断。清单校验停在结构层,没有进入语义层。
修复:把这个洞留给第 07 章的 V2。
现象二:换一个同事接手同一功能,把同样的坑又踩了一遍。
怀疑:需求卡没有进入版本库,只留在个人的对话记录里。
检查:
console
$ git log --oneline -- task.json
$ ls .github/
证据:git log 对 task.json 没有任何输出;仓库里也没有 PR 模板目录。
根因:清单停留在个人习惯,不是团队资产,交接和评审时无法复用。
修复:把校验脚本与需求卡一起纳入 PR 模板和 CI,见第 07 章。
错误尝试: 第一阶段我们想当然地认为是模型不够强,准备把主力模型换成当时最强的版本,甚至考虑换掉工具。为什么错:这次返工的根因在需求定义与验证机制上,模型能力上限不是瓶颈;在模糊目标下,更强的模型只会更快更自信地朝错误方向补全,返工成本并不会下降。
现象引怀疑
检查取证据
根因定一处
修复不越界
07、优化
根因有两条:V1 只校验结构、不校验可验证性;清单没有进入版本控制与自动化流程。
修改一,给验收标准加可验证性判断:
python
import re
VAGUE_WORDS = ('合理', '友好', '尽量', '差不多', '好看', '优化一下', '快一些', '稳定点')
OBSERVABLE = re.compile(r'\d|返回|拒绝|创建|校验|状态码|字段|日志|抛出|不再|只')
def verifiable(text):
vague = [word for word in VAGUE_WORDS if word in text]
if vague:
return False, '命中模糊词 %s' % vague
if not OBSERVABLE.search(text):
return False, '没有可观察对象'
return True, '可验证'
把 V1 里那一行验收检查替换为:
python
acceptance = [str(item) for item in (card.get('acceptance') or [])]
verdicts = ['%s -> %s' % (item, verifiable(item)[1]) for item in acceptance]
all_ok = len(acceptance) >= 2 and all(verifiable(item)[0] for item in acceptance)
result.append(('验收标准可验证', all_ok, '; '.join(verdicts)))
为什么这样改:模糊词表负责拦「说不清」的条目,可观察对象正则负责拦「没有落点」的条目,两者叠加,验收标准才从口号变成断言。
新行为:不可验证的条目会让整卡 FAIL。未在当前环境实测,以下为预期结果。示例输出:
console
$ python checklist_gate.py task.json
[FAIL] 验收标准可验证 | 同一幂等键重复提交只创建一个订单 -> 可验证; 接口返回要合理 -> 命中模糊词 ['合理']
验证过程:把 task.json 第二条改成「缺失 Idempotency-Key 时返回 400 且带 error_code 字段」,再跑一次,该项转为 PASS。
修改二,把校验接进流程:
yaml
name: vibe-gate
on: [pull_request]
jobs:
checklist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: python scripts/checklist_gate.py task.json
同时把 task.json 放进 PR 模板,评审时逐条对照,人工评审只处理机器判断不了的部分。代码规范、静态扫描、安全检查与 CI/CD 门禁并行执行,它们各自解决不同层的问题,谁也替代不了需求澄清这一关。
根因定方向
修改有依据
新行可复现
验证不造数
08、演进
text
[同一输入] 业务目标 + 范围约束 + 输入输出 + 验收标准
|
+--[V1] 结构校验:字段齐全、条数达标 / 代价:语义空洞也能通过
|
+--[V2] 结构 + 可验证性校验 + CI 门禁 / 代价:开工前的准备成本上升
|
[Trade-off]
得到:可验证契约、可追溯证据、可交接的团队资产
失去:一句话开工的即时快感
适用边界:多人协作、有外部依赖、需长期维护的任务;一次性脚本与探索性原型不适用
| 维度 | V1 | V2 |
|---|---|---|
| 正确性 | 只能保证字段存在 | 能拦下不可验证的验收标准 |
| 稳定性 | 依赖个人记性 | 依赖脚本与 CI,可重复 |
| 复杂度 | 单文件脚本 | 脚本 + 需求卡 + CI + PR 模板 |
| 成本 | 需求卡十几分钟 | 需求卡 + 维护词表与正则 |
| 适用范围 | 个人自用小任务 | 多人协作、长期维护任务 |
| 遗留问题 | 语义校验缺失、无版本化 | 词表靠人工维护,语义判断仍是启发式 |
同一份输入
两条路取舍
得失常相伴
边界自约束
09、洞见
9.1 能力圈的边界由上下文所有权决定
模型对公开知识的掌握很稳,对你仓库里的隐式约定一无所知。判断一个任务在不在圈内,看的是「约束有没有被写下来」:写下来的进圈,没写下来的出圈。
9.2 清单的价值在执行,不在书写
写在文档里没人跑的清单,和没有清单是同一件事。第 06 章里 task.json 没有进版本库、换人重踩同一个坑,就是这条判断最直接的证据。
9.3 反直觉判断:更强的模型会放大问题定义的质量差距
定义清楚时,强模型一次就能接近可交付;定义模糊时,它更快更自信地走偏。模型能力是乘法,问题定义是乘数,乘数为零时结果为零。
9.4 反直觉判断:上下文不是越多越好
把整个仓库塞给模型,关键约束会被无关代码稀释。有效上下文是约束、接口边界与验收标准,而不是代码体积。
9.5 验证机制决定下限,模型能力决定上限
第 05 章的 V1 证明了前半句:同一个模型,加上校验脚本之后,返工点被提前暴露出来。上限要靠模型,下限要靠机制,两者不能互相替代。
洞见出证据
判断落边界
反直觉处想
工程心自明
10、系统落地
原来有什么:一句自然语言提示、一次模型生成、一次人工评审,清单只存在于个人经验里。
本篇新增什么:一份 task.json 需求卡、一个 checklist_gate.py 校验脚本、一道可接入 CI 的门禁,以及一套七步清单------需求澄清 → 任务拆分 → 接口与边界约定 → 测试用例 → 编码实现 → 结果校验 → 人工评审。
现在能做什么:开工前能判断任务在不在能力圈内;开工时能把目标、范围、输入输出、验收标准固化成可校验的卡片;提交时能自动拦下语义空洞的验收标准。
还缺什么:可验证性判断仍是词表加正则的启发式,覆盖不了复杂业务语义;任务拆分与提示骨架生成还是手工步骤。
下一步如何演进:把验收标准自动转成契约测试骨架,让「验收标准 → 测试用例」这一步也可执行;对历史返工记录做归因,把高频缺失字段补进必填清单。
原有即起点
新增成能力
缺口是路标
演进步步实
11、小结
text
Q1 → 需求描述模糊到什么程度模型开始靠猜:只要目标、范围、输入输出、验收标准有一项缺失,模型就必须自行补全意图
Q2 → 先写清问题定义还是先换更强模型:先定义;模型决定潜在能力上限,问题定义与验证机制决定实际交付质量
Q3 → 清单没人执行等于没有:把清单做成脚本与 CI 门禁,检查才可执行、可追溯、可交接
状态 → 一份可校验的 task.json + 一个能跑通的 checklist_gate.py + 一道可接入 CI 的门禁
三问皆有答
一态可交付
清单在运行
能力在圈内
12、作业
12.1 理解题:为什么说更强的模型会放大问题定义的质量差距?
参考答案:模型能力是乘法关系。定义清晰时,强模型一次能给出接近可交付的结果;定义模糊时,强模型会更快、更自信地朝错误方向补全,返工成本反而更高。能力提升不会自动补上定义缺失。
12.2 实战题:给手上一个任务写 task.json,并让校验脚本通过。
参考答案:至少写出 goal、scope_in、scope_out、io、acceptance、risks 六个字段;acceptance 不少于两条,每条都要有可观察对象,比如状态码、字段名、记录数、日志关键字,不出现「合理」「尽量」「优化一下」这类模糊词。
12.3 排障题:校验全部 PASS,但模型产出的代码仍在评审被打回,先查什么?
参考答案:先查验收标准的可验证性,而不是先换模型。把 acceptance 逐条打印出来,找没有可观察对象的条目;同时确认 task.json 是否已进入版本库,避免同一个坑被重复踩。
12.4 架构判断题:把校验脚本接入 CI 门禁,会不会拖慢交付?
参考答案:会带来开工前的固定成本,同时把返工从评审阶段前移到开工阶段。判断依据是任务属性:多人协作、有外部依赖、需长期维护的任务收益更大;一次性脚本与探索性原型不适合套这套门禁。
理解见深度
实战验真知
排障练证据
判断定取舍
13、思考
回到最初那句判断:模型决定潜在能力上限,问题定义与验证机制决定实际交付质量。芒格的能力圈负责回答「这件事该不该交给模型」,检查清单负责回答「交出去之后怎么确保做对」。前者是边界,后者是流程,两者都不依赖模型换代。
模型有上限
定义定下界
清单守交付
圈内方致远