Axıs
技能目录

抽象层次:保留什么、丢弃什么

抽象层次:保留什么、丢弃什么

给 coding agent 的执行参考。每节结构:为什么 → 做法 → 判据 → 边界。

这一篇解决一个问题:一条从真实项目里来的经验,应该写成通则、写成项目文档,还是降权保留。判错层次的后果是双向的——抽象过度得到一堆没人照做的口号,具体过度得到一份换个项目就不成立的备忘录。


0. 目录

  1. 唯一判定法
  2. 三个落点的分配
  3. 正例反例对照
  4. 三种抽象失败
  5. 「单例,降权」
  6. 抽象到什么程度算够:两个方向的下压
  7. 把通用层做成可 grep 的
  8. 派生问题:项目文档该留什么
  9. 反例速查表

1. 唯一判定法

换一个项目还成立吗。

成立 → 通则。不成立 → 项目文档。可能在别处成立但本项目没证据 → 单例降权。

这条判定法之所以够用,是因为它把抽象层次从一个主观刻度变成了一次替换测试:**把你的项目换成另一个项目(比如换成做小说、做运营),这句话还读得通、还给出同样的指导吗?**读不通就是抽象不足。

判据:正文每条通则,代换测试都能通过。代换不通过的,移出去。

边界:这条判定法只管层次,不管强度。「原则该这么定」可以通用,但「原则必须这么定、违反即返工」需要更多案例支撑——那是强度问题,见 evals.md 里的断言强弱分级。


2. 三个落点的分配

落点 放什么 特征
通则(skill 正文) 原则 + 为什么成立 + 判据 代换测试通过,且带判据
项目文档 具体数值、实测结果、行号、被否决方案的细节 只在本项目可指认
专项附录(reference) 某个领域/工具的行为结论、扩展推导、反例表 需要时才读,含名词与版本行为

分配的唯一目标是让正文能被代换测试。 附录不是垃圾桶——它有自己的判据:一个条目该进附录,当且仅当它带着可 grep 的领域名词。

判据:正文里每条通则都能指出它为什么不在附录里;附录里每条都能指出它带哪个名词。


3. 正例反例对照

同一件事的三个抽象层次,并排看:

原始素材(具体层) 抽象过头(口号层) 合格(通则层)
某个进度条要 11.9 秒填满(实测值) 要注意节奏与反馈 状态变化必须在 1.5–2 秒内可见;用户需要一个能感到「它在动」的量
某类演出用逻辑状态冻结了世界却没弹暂停面板,导致界面盖住演出 界面与逻辑要保持一致 断言玩家可见结果,不是内部状态:只读逻辑状态的端到端断言会漏掉「界面盖住了演出」
用户两次推翻某个按键的默认行为,都没改机制层 要重视默认值 默认值与阈值是设计问题不是实现问题:反馈说「不好用」时,先查取值层与机制层是不是搞反了
某个数值调了好几轮都调不对,最后发现根因是函数在设定距离处直接归零 调参前先找根因 「某处 X」类反馈先变成一个可测量的量,再改;写不出这个量说明还没理解问题

对照的用法:拿一张空表,把手上每条素材填进「抽象过头」和「合格」两栏。凡是能填进「合格」栏却没填的,都是抽错了;凡是只能填进「抽象过头」栏的,都是它还不配进正文。

判据:表格填满,且「抽象过头」栏的条目全部能找到一句更好的说法。


4. 三种抽象失败

4.1 抽象成了口号

症状:「要重视一致性」「保持简单」「注意用户体验」。特征:删掉它,agent 的行为不会有任何变化。

原因:抽掉了推导,只留下了结论的修辞。修复:把推导加回来。每条原则应该是「因为 X 会导致 Y,所以做 Z」,不是「做 Z」。

判据:对每条正文原则问「删掉它,agent 会不会做错?」答不会就删——这条判据同时挡住口号和冗余。

4.2 抽象到了错误的层

症状:把取值问题升成机制问题(要求重写整个机制去修一个默认值),或把机制问题降成取值问题(调三轮参数去修一个根因在函数定义里的 bug)。

原因:材料里描述的表层动作是改数值,抽原则的人跟着表层走了。修复:回看第 2 节(从否决里挖分歧点)——那次否决实际动的是哪一层?把层数写进原则里。

判据:每条原则标了它约束的层;同一条反馈序列里的多次修复如果落在同一层,就是这条原则的证据。

4.3 为了通用而丢掉了 why

症状:抽掉了推导链里的关键一步,原则变成立不起来的一句话。

原因:认为「项目名词是脏的」,于是连同名词旁边的推理一起删了。

修复:只删名词,不删推理。项目名词是脏的,那一步推理不是。

原始:「某项目里 UI 层可见性状态本身要有断言,否则会漏掉『界面盖住了演出』」 抽象后(合格):断言要断言玩家可见结果,不是内部状态。只读逻辑状态的端到端断言会漏掉「界面盖住了演出」。 抽象过头(失 why):要做端到端断言。

判据:每条原则旁边有一句「如果不这样,会发生什么具体的事」。


5. 「单例,降权」

计数为 1 的条目既不该升为通则,也不该删。删掉它,等于把一次真实发生的教训丢掉;升为通则,等于把一个孤例说成规律。

写法(三处,缺一不可):

  1. 正文里紧邻原则,带「单例」标注。
  2. 判据仍然写(但写成本项目可验的那一条)。
  3. CREATION-LOG 里记一条「此条未收敛,等 N 个案例可定强度」。

判据:正文里每条标了「单例」的,都能在 CREATION-LOG 里找到对应条目;反过来,CREATION-LOG 里列的未收敛项能在正文定位到它的单例标注。

边界:单例的代价极高时可以破例进正文且不标注——频次低但后果重。这时要在 CREATION-LOG 里写清为什么破例。


6. 抽象到什么程度算够:两个方向的下压

抽象不是单方向的稀释过程。两个方向都要主动压:

向下压:把「一次事件」压成「一类模式」

一条原则要能指认的不是某一次事故,而是「看到这类现象 → 是这个坑」。所以每条原则在成文时要做一次类别化改写:

原始(事件层):某照明照不亮,调参三轮无效,根因是衰减函数在设定距离处归零。 类别层:看到「某个地方很暗」且调参无效 → 先怀疑函数在阈值处有硬截断;判据是该现象在设定距离外必然发生。

事件层的写法在换项目时立刻失效;类别层的写法换项目也成立。

向上压:把「三个独立结论」压成「一条带边界的原则」

三件看起来不同的事,如果它们的判据能写成同一个检查,就合并。判据相同的条目是一个条目。

判据:正文里没有两条原则的判据是同一个检查(那说明是同一条被拆成了两条,agent 会执行得不一致)。


7. 把通用层做成可 grep 的

为什么:分层纪律靠自觉必然腐化。判定标准必须是机械的。

做法:写完正文跑一次 grep,检查两样东西:

  1. 技术栈名词:正文里出现具体框架名、平台名、版本号 → 泄漏(description、路由表、reference 来源小节是三个合法例外,因为它们分别是发现层、分发层、来源层)。
  2. 具体数值:正文里出现带单位的数字 → 泄漏(除非它是通则的一部分,例如「1.5–2 秒」这种不依赖具体项目的量)。

判据:grep 退出码 0(无命中)。跑完把结果写进 CREATION-LOG 的分层例外一节,连同例外位置一起记录——这是给后来者验证用的。


8. 派生问题:项目文档该留什么

剥离时容易矫枉过正:把具体层全部丢掉,结果留下的通则谁也用不了。具体层不是垃圾,是项目文档的职责。

项目文档至少要接住四样东西:

接住什么 为什么
具体数值与实测结果 换项目就不成立,但它在本项目里可验证
被否决方案的细节 复现「为什么错」需要它,通则只需要分歧点
单例降权条目 见第 5 节
推导链里的项目专有名词 通则里删掉的那些词,在这里还该在

判据:正文里的每条通据都能在项目文档找到它的具体实例版;项目文档不是被清空,而是换了职责。


9. 反例速查表

反例 为什么错 正确做法
「要重视一致性」 口号:删掉它行为不变 加推导,或删掉
把「默认值不合适」升级成「重写机制」 抽到了错的层 先标出那次否决动了哪一层
「某项目里 UI 可见性要有断言」 抽象过了头的反面:项目名词没删 删名词留推理
计数为 1 的条目直接删 丢真实教训 标「单例,降权」保留
计数为 1 的条目直接升通则 把孤例说成规律 找第二个案例,或降权
两条原则的判据其实是同一个检查 拆条导致执行不一致 合并
把所有具体内容都抽掉 通则谁也用不了 下沉到项目文档
靠印象判断有没有分层泄漏 必然腐化 跑 grep,把例外位置记进 CREATION-LOG
把具体数值也抽象成「适中」 抽象过头到空洞 具体值下沉,量级(秒级)留在通则