技术思考问题2:AI 编程高效的关键,是更强模型还是更清晰的问题定义?

芒格模型:能力圈 + 检查清单

模型决定上限,问题定义与验证决定下限

text 复制代码
[读者] 用 Cursor 一类工具写生产代码的工程师与小组负责人
[痛点] 一句模糊指令换不来可交付代码,返工与无限试错在吃掉时间
[现在读] 工具和模型都到位了,缺的是把需求变成可验证契约的方法
[读完] 能把能力圈判断和检查清单落成一个能跑起来的校验脚本与 CI 门禁
text 复制代码
[旧方案] 一句自然语言描述需求,直接让模型写代码
    |
    v
[新需求] 多模块、有外部依赖、要长期维护的生产代码
    |
    v
[冲突] 目标模糊时模型靠猜补全意图,越补越偏
    |
    v
[后果] 反复返工、缺陷外溢、评审成本高于手写

我是老李,带一个七八人的业务后端小组。去年开始我们把 Cursor 当主力编辑器,模型换过几轮,工具也换过,交付节奏却没有明显变快。真正让情况变化的,是两件很老的东西:芒格说的能力圈,和芒格用来避免犯错的检查清单。

能力圈说的是知道自己擅长什么、不擅长什么,不擅长的事要么避开,要么用别的方式兜住;检查清单说的是把容易漏的判断固化成条目,每次照做,不靠记性。

把这两件事搬到 AI 编程里,问题就变成下面三句。

需求描述模糊到什么程度,模型就开始靠猜?

是继续换更强的模型,还是先把问题定义写清楚?

如果清单只写在文档里没人执行,它跟没有有什么区别?

01、故事

场景是订单服务接入新的支付通道。任务是给下单接口加一个幂等键,让支付回调重试时不重复创建订单。

当时的做法很典型:我在对话框里敲了一句「给订单创建接口加上幂等支持,防止重复下单」,模型几秒内返回两百多行改动。它改了下单接口,改了仓储层,还顺手调整了库存扣减的调用顺序,并在注释里写下「保证并发安全」。

评审时暴露出三件事。第一,库存扣减不该在这次变更范围内,但没人提前说明;第二,幂等键存在哪里、多久过期,模型自己选了,跟我们既有的缓存约定不一致;第三,没有一条测试覆盖重复提交。

这次返工不是模型写错了代码,而是我们在开始之前就没说清要什么、不要什么、怎么算做完。

一句模糊话

十次重生成

边界无人问

返工已成舟

02、问题

旧方案失效点:自然语言提示里只有动作,没有约束和验收。模型只能用自己的先验去补全,而补全方向和我们仓库里的隐式约定并不一致。

业务影响:改动范围外溢到库存服务,评审要重新确认整条调用链;幂等键策略与既有缓存约定冲突,上线前还得二次设计。

技术表现:变更文件数超出预期、缺少并发与重复提交的测试、边界条件(缺 Header、键已过期)的行为没有定义。

这次改造的完成标准必须可验证:

  1. 同一幂等键重复提交只产生一条订单记录;
  2. 缺失或非法 Idempotency-Key 时返回明确的 4xx 与 error_code 字段;
  3. 幂等键过期后的行为有明确定义,拒绝或重新创建,二选一写死在需求卡里;
  4. 变更文件清单可枚举,且不包含库存服务;
  5. 至少一条自动化测试覆盖「同键重复提交」。

旧法已失效

影响在扩散

表现可观测

标准须可验

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、思考

回到最初那句判断:模型决定潜在能力上限,问题定义与验证机制决定实际交付质量。芒格的能力圈负责回答「这件事该不该交给模型」,检查清单负责回答「交出去之后怎么确保做对」。前者是边界,后者是流程,两者都不依赖模型换代。

模型有上限

定义定下界

清单守交付

圈内方致远

相关推荐
小虎AI生活2 小时前
AI 替掉重复劳动后,把人转向获客侧的实操方法(附提示词模板)
aigc·ai编程
金銀銅鐵2 小时前
[Java] 用GUI展示class文件顶层的 access_flags
后端·python·ai编程
ajassi20006 小时前
AI语音智能体开发日记(十八)智能体服务器xiaozhi-esp32-server源码部署指南
运维·服务器·人工智能·ai·ai编程
9i编程7 小时前
9. 教 AI 上班:带出我的数字同事 —— 部署到本机再大回归:组织架构又错,被我叫停先改树
人工智能·openai·ai编程
jam2817 小时前
你让 AI 帮你写代码,攻击者把偷密钥的指令藏进了一张 PNG
ai编程
粥里有勺糖8 小时前
安利一下最近用的桌面“Agent” | T3 Code
前端·github·ai编程
粥里有勺糖9 小时前
视野修炼第136期 | 前端小恐龙"Deno"被收购
前端·github·ai编程
六维空间9 小时前
筛了 40 多个信源,最后只留 29 个:一份「AI 日报」信源选型笔记
ai编程