Vibe Coding 下个阶段:代码的“熵管理” Max 版

99 阅读1小时+

零、摘要

如果未来三年的代码,大部分都是 AI 帮你写的,你今天的代码库会变成什么样?

很多团队已经在用所谓 vibe coding:用自然语言跟模型聊天、让模型刷刷刷产出代码,人只在高层说需求、看效果、再让它改。短期是“写得飞快”,长期呢?这篇文章的核心观点是:从“熵”的视角看,vibe coding 正在系统性地把代码库推向一种高熵状态——结构越来越像随机图,命名和状态越来越分裂,行为越来越难预测,知识和责任越来越模糊。

文章先用“熵”把这些现象拆开:结构熵(分层与依赖)、语义熵(业务概念与状态)、行为熵(接口与错误)、演化熵(历史轨迹)、认知熵(谁懂什么、谁负责什么)……并解释为什么这不是个别团队“写得不够规范”,而是由模型的目标函数、生成方式、数据分布和多工具协作机制共同决定的“物理属性”。接着,从项目、团队、可观测性、开源生态、合规和商业几个层面,展开高熵代码的后果:它长得怎样、闻起来怎样、以及有哪些早期“红灯信号”在提醒你——“再这么写下去,未来任何改动都会非常痛”。

后半部分,文章尝试把“熵管理”升级成一套可操作的能力体系:个人层面从 coder 变成 constraint designer,团队层面用架构模板、Glossary、低熵内核 / 高熵外壳分区来收紧空间,工具层面用 repo 画像、重构/规范 bot、熵热力图和量化指标,把“代码味道”变成可观测、可规划的工程对象。最后,视角推到模型训练和 AI coding 工具设计:讨论如何在对齐 / RL 中把熵 proxy 写进奖励,如何基于重构轨迹训练专门的 Refactorer 模型,如何通过 house-style / repo-style 先验与“契约先行 + 分层生成”降低生成层自由度,以及如何在 agent / 搜索层引入熵成本和熵预算。与其纠结“要不要用 vibe coding”,这篇文章更想回答的是:在一个本性高熵的 AI 开发世界里,我们还有多少主动空间,可以设计出真正 AI-native、带熵预算的工程体系,让“模型写代码、人管熵和抽象”变成一种可持续的分工,而不是一场迟早要还的技术债。

本文初版构思、创作于2025年4月,西双版纳。第二版修订于2025年12月,上海。 本文的出发点并不是为了描述这种现象又或是给大家推荐某些好用的工具,而是从熵的视角为大家拆解这个现象,阐述其必然性,并尝试给出一个长期有效的解决方案脉络。

一、vibe coding 和“高熵”整体图景

本文中,“vibe coding / ai coding”不是一个具体工具,而是一种范式

  • 我用自然语言跟模型描述我想要的东西;
  • 模型给我产出大段代码、甚至整个项目;
  • 我不再逐行写代码,而是通过:“看运行结果”、“看整体体验”、“再聊几句让它改”来驱动整个开发过程。

在这个范式下,使用者越来越不直接操控“代码符号”,而是在高层操控“需求 + 感觉 + 迭代方向”。

于是,一个核心现象就出现了:

在 vibe coding 里,代码和项目的“熵”非常高。

这里的“熵高”,在我心里不是一句吐槽,而是一个结构性的特征,几乎可以当成这个范式的“物理属性”:

  • 从技术视角来看,高熵来自于模型的生成方式、目标函数、上下文限制、采样策略……
  • 从工程和行业视角来看:高熵会倒逼出新的角色、新的工具、新的规范体系,专门用来管理和驯服这些熵

为了避免“熵”这个词太抽象,先把我要讲的主线说清楚:

我会把“代码熵”拆成几个维度,

说明 vibe coding 为什么在每一维上都有把数值拉高的趋势,

再讨论:我们如何在模型、工具、工程流程这些层面有意识地给它“压熵”。


二、在 vibe coding 里,“熵高”具体体现在哪些维度?

为了不让“熵”变成一个玄学词,我会先把它拆成几条主轴来看:

  • 结构熵轴:分层、依赖关系、演化路径是不是有清晰模式;
  • 语义熵轴:业务概念、状态、领域模型是不是统一、稳定;
  • 行为熵轴:系统在各种输入/环境下的行为是不是一致、可预测;
  • 认知 / 知识熵轴:谁懂什么、谁负责什么、需求和规格究竟长在哪儿。

“风格熵”(命名/写法/格式风格的无序)我会放在这几条主轴之上,作为一个放大器:它本身是一条轴,但更重要的是,它会把其他轴上的熵进一步放大。

下面按这几条主轴展开。


2.1 结构熵轴:分层、依赖和演化路径

结构熵关注的是:这个系统在“结构上”是不是有一套稳定的模式。

大概包括三层:

  • 静态形状:目录、模块、层级;
  • 依赖方向:谁可以依赖谁;
  • 时间维度上:这些结构是怎么演化过来的。

2.1.1 静态结构:项目“长得像什么”

低结构熵的项目:

  • 目录结构基本一眼能看出层次:UI / API / Application Service / Domain / Repository / Infra / Test 等;
  • 同类功能聚在一起:用户相关逻辑在用户模块;订单相关逻辑在订单模块;
  • 每层的职责边界比较清晰。

高结构熵的 vibe 项目很容易变成:

  • 同一类功能散在乱七八糟的目录里;
  • 前端 js / ts 直接去调数据库,跳过 service 和 domain;
  • 某个功能在 A 模块已经有代码了,另外一个地方又另起炉灶来一遍;
  • util, common, helpers 这类目录体积膨胀成“黑洞”,谁都能 import 一口。

从依赖图的角度看,就是:

依赖关系越来越接近“随机图”,而不是“分层明显的有向无环图(DAG)”。

2.1.2 依赖和循环:谁都能调谁 vs 有明确的上下游

低结构熵的依赖图上:

  • 从 UI 出发,依赖关系大多是「向下」:UI → App Service → Domain → Repo → Infra;
  • 反向依赖(比如 Domain 反过来调 UI)要么没有,要么是少数特例;
  • util / common 只提供少量真正底层、无业务语义的基础能力。

高结构熵的情况:

  • 大号强连通子图(SCC)很多:A 调 B,B 调 C,C 又调回 A;
  • util / common 像“垃圾场”:所有层都有对它的依赖,它也反过来引用各种上层逻辑;
  • 你从一个模块往外顺着依赖走,很难停下来——到处都能走到。

这种时候,“我们再拆一拆结构”这件事,本身就很困难,因为:

  • 你不知道一刀下去会牵连多少地方;
  • 你也讲不清楚: “现在从结构上,它到底有什么天然层次?”

2.1.3 演化路径:历史是不是看起来像一个可叙述的故事

结构熵还有一个容易被忽略的维度:时间 / 演化

低熵演化大概是这样的:

  • 每次大的改动,背后都有一个可以讲清楚的 story:“因为 X,我们把原来的 Y 拆成 A/B/C”;
  • commit / PR 粒度比较稳定,一个 PR 做一件事;
  • 你可以顺着 git log 把“结构为什么长成今天这个样子”复盘出来。

高熵演化长什么样?

  • 目录结构一会儿大改,一会儿又被新生成的代码半推翻;
  • 某个模块被“重写”了三遍,旧逻辑还残留在角落;
  • commit message 像:fix, update, try again, temp 这种;
  • 你很难用自然语言说清楚:“过去一年的架构演化路线是什么?”

这意味着:

不只是“当下的结构”是高熵的,“它是怎么演化成这样的”这个故事,在时间维度上也失去了秩序感。


2.2 语义熵轴:业务概念、状态和领域模型

语义熵关心的是:这套代码在业务层面到底在表达什么,它是不是有一个清晰、一致的业务语义模型

在 vibe coding 里,这一轴的熵特别容易被忽视。

2.2.1 概念命名:同一概念 N 种叫法

典型的高语义熵现象:

  • 同一个业务对象:

    • 有的地方叫 user
    • 有的地方叫 member
    • 有的叫 accountprofilecustomer
    • 甚至还混着缩写 usr, acct
  • 对“组织”、“团队”、“租户”、“空间”这种抽象,各自有各自的说法和字段。

表面看只是命名不统一,实际是:

在代码里没有“官方的业务语言”,每一块生成出来的代码都在创造自己的方言。

这会让后续所有的抽象、复用、重构都变得非常痛苦。

2.2.2 状态和枚举:同一状态,多套表达

进一步的语义熵是“状态模型”的混乱:

  • 同一个业务状态在不同模块用不同枚举 / 不同字段表达;

  • 某些状态只有在特定模块里才存在,比如:

    • API 层有一套 status 字符串;
    • DB 有另外一套 int 枚举;
    • 前端还有一份自己维护的 map。

结果就是:

  • 任何人想回答“这个实体有哪些合法状态、允许如何迁移”时,都要读好几份代码;
  • 任何新逻辑的新增状态,都很难保证所有地方同步升级。

2.2.3 状态机散落四处:没有一个真正的“单一真相”

更进一步的高语义熵,是状态机逻辑散落在各处

  • 一部分转移逻辑写在 API handler 里;
  • 一部分埋在某个 service 的 if/else;
  • 还有一部分藏在前端或 batch job 里。

没有一个显式的、可被引用的“状态机定义”,结果是:

从行为上看,这套系统“凑合能跑”;但从语义上看,你很难说清楚:“这个业务对象在概念上到底是什么?哪些状态是允许的?它的生命周期模型是什么?”

低语义熵的项目往往会有:

  • 集中的领域模型定义(Domain Model);
  • 明确的状态机 / 有限状态自动机;
  • 清晰的 invariants(业务不变量),写在明显的位置。

在 vibe 项目里,如果不刻意压这一轴,很容易变成:

业务逻辑都散在代码里,“业务模型”只存在于一些人的脑子和若干聊天记录里。


2.3 行为熵轴:系统在真实世界里的行为是否可预期

行为熵看的是:这套系统在面对各种输入 / 环境 /错误时,实际表现出来的行为是不是统一、可预期的。

相比结构和语义,这是更“运行态”的视角。

2.3.1 API 和错误模型:同样错误,N 种返回

高行为熵的一些典型症状:

  • 同样的错误类型(比如权限不足):

    • 某些 API 返回 HTTP 403 + 标准错误码;
    • 某些返回 200 + { success: false, message: "no permission" }
    • 某些直接抛一个“看起来像 debug 信息”的字符串。
  • 错误 payload 的结构到处分裂:

    • 有的用 code + message + details
    • 有的只有一个 message;
    • 有的场合连语言都混着用(中英掺杂)。

这会导致:

  • 调用方需要大量 ad-hoc 的 error handling 逻辑;
  • 系统内部很难构建统一的“错误语义”。

2.3.2 边界条件和兼容行为:每一块都有自己的“小九九”

高行为熵的另一个来源是:

  • 同样的边界情况,不同模块做了不一样的处理:

    • 有的地方没数据时返回空数组;
    • 有的地方返回 null;
    • 有的地方抛异常;
    • 有的地方悄悄“兜底成默认值”,还不打日志。
  • 对一些“看起来差不多”的输入,系统行为在不同路径下完全不同:

    • 某个参数缺失时,API A 会默认补上;
    • API B 会报错;
    • API C 会默默忽略。

这让全局行为的推理成本急剧上升:任何人想认真回答“这个系统在某个极端场景会怎么表现”,都需要把很多局部实现拼起来脑补。

2.3.3 环境差异:本地 / 测试 / 生产像三套系统

高行为熵还有一个很现实的来源:环境差异。

  • 本地、staging、生产的配置、依赖版本、开关策略不一致;
  • 某些“临时兜底逻辑”只在一个环境里开启,后来没人记得关;
  • 监控和日志在各环境里信息粒度不同。

结果是:

你以为你在“测试一个系统”,实际上在测试三四套“看起来差不多但关键细节不同”的系统。

低行为熵的系统往往会:

  • 有统一的错误模型和 API 契约;
  • 对同类边界情况有明确、被文档化的处理策略;
  • 通过配置管理 / infra,把环境之间的行为差异压到最小且可见。

2.4 认知 / 知识熵轴:谁知道什么、需求在哪、谁说了算?

认知 / 知识熵关心的是:人和文档这一层,到底有多混乱。

直白一点讲,就是:

“谁真正理解这个系统?系统应该做什么”的正本到底写在哪?

2.4.1 所有权和知识分布:没有“代码之父/之母”

在 vibe coding 场景里,很多代码是“我和模型聊着聊着写出来的”:

  • 没有明确的“owner”或“作者群”;
  • 很多决定是当时在对话里临时拍板的,事后没有沉淀成规范。

时间一长,就变成:

  • 某些模块只有一两个人“勉强看得懂”,但他们也说不清楚这是“设计”还是“模型临时发挥”的产物;

  • 新人接手看到的是:

    • 一堆 AI 生成的代码;
    • 一些已经过期的 docs;
    • 一大堆散乱的聊天记录;
    • 很难建立稳定的心智模型。

换句话说:

“知识”本身变成了高熵的,分布在模型、代码、文档、对话记录、个人记忆里的一个云。

2.4.2 需求 / 规格熵:系统“该做什么”这件事本身就不清楚

传统工程流程里,至少在理想状态下,会有:

  • 相对稳定的需求文档 / 规格说明;
  • 对“系统应该在这些场景下做什么”的统一描述。

在 vibe coding 里,常见模式是:

  • 一边想、一边说、一边生成代码;
  • “需求”散落在 prompt、对话历史、脑子里;
  • 很多细节是在“模型写代码”的过程中临时决定的。

结果就是:

  • 同一个行为,在不同模块的描述和约束不完全一致;
  • 出现 bug 时,很难判断:是代码错了?还是一开始对需求理解就不一致?

当“系统应该做什么”本身是高熵的,“系统最终怎么做的”熵只会更高。

2.4.3 责任边界:事故发生时,很难划清“谁的锅”

高认知熵还有一个很现实的后果:事故复盘困难

  • 这个模块大部分代码是 AI 写的;
  • 需求是某段对话历史里“揉”出来的;
  • 中间几手 relay 的人说不清楚当时是怎么约定的。

那出问题时:

  • 是写 prompt 的那个人的锅?
  • 还是最后 review 没看仔细?
  • 还是“AI 写的”可以当作抽象挡箭牌?

如果没有明确的 ownership、清晰的需求和设计记录,团队会在事后纠结在“谁该背锅”,而不是在“系统怎么改得更低熵”。


2.5 风格熵:作为几条主轴上的“噪声放大器”

前面几条轴是我觉得最核心的:结构;语义;行为;认知 / 知识。

风格熵(命名风格、代码风格、错误处理风格、日志习惯等)本身当然也是一条轴:

  • getUser, fetch_user, loadMember 混在同一层;
  • 一些函数极度函数式,另一些很 OOP,还有一些纯过程式;
  • 有人用异常,有人用 error code,有人静默返回 null;
  • 有人写 structured logging,有人只写一个 print("error")

但更关键的是——风格熵会把前面几条轴上的问题统统放大。

  • 本来结构已经有点乱,加上一堆不统一的写法,从视觉上会显得更乱;
  • 语义上命名已经不太统一,再叠加不同风格的 state handling,更难一眼看出哪些变量其实代表同一概念;
  • 行为上本来就不一致,再叠加错误处理风格的差异,调用方要处理的分支数翻倍;
  • 认知层面,没有统一风格,会让新人更难在脑子里建立“代码→语义”的映射。

所以我会把风格熵理解成:

几条主轴上的高熵已经够危险了,风格熵是一层额外的高频噪声,让所有高熵现象变得更不透明、更难被人类察觉和修复。


2.6 小结:vibe coding 让哪些熵轴特别容易被拉高?

简单收个口:

  • 结构熵轴:在 vibe coding 里,模型倾向于在局部 patch,缺少全局重构;目录、模块、依赖、演化路径都容易向“随机图”漂移。
  • 语义熵轴:对话式开发让命名、状态机、领域模型更容易随场景漂移;缺乏一个被严格维护的“业务语言”和“状态机单一真相”。
  • 行为熵轴:快速堆功能、临时兜底逻辑多;错误模型和边界情况的处理往往 ad-hoc,环境差异又进一步加剧不一致。
  • 认知 / 知识熵轴:需求、决策、设计散落在对话、代码和个人记忆中;ownership 模糊,事故复盘和长期演化缺乏清晰的“认知 backbone”。
  • 风格熵:作为一层高频噪声,把上述所有问题的可见性和修复难度再抬一档。

后面几章会沿着这几条主轴去看:

为什么 vibe coding 的“物理属性”,会让这些熵自然往上走,以及我们在模型、工具、团队流程这些层面,能不能把其中一部分熵压回去。


三、为什么 vibe coding 天然倾向于高熵?

前一章我把“代码熵”拆成了几条主轴:

  • 结构熵轴:分层 / 依赖 / 演化路径;
  • 语义熵轴:业务概念 / 状态 / 模型;
  • 行为熵轴: API / 错误 / 边界条件 / 环境一致性;
  • 认知 / 知识熵轴:所有权 / 需求 / 规格;
  • 再加一层:风格熵作为“噪声放大器”。

这一章想回答的问题是:

在 vibe coding 这个范式下,哪些机制会系统性地把这些轴上的熵往上推?

我们来从以下几层看:

  • 模型本身在优化什么;
  • 我们是怎么用它的(交互方式 / prompt);
  • 工具生态是怎么拼起来的;
  • 反馈机制在鼓励什么、忽略什么。

3.1 模型本质是“条件概率机器”,不是“全局架构师”

先从最底层说起:模型在数学上是在干什么?

大致就是这件事:

给定上下文 CC,预测下一个 token 的分布 p(tokenC)p(\text{token} \mid C)

优化目标是:

  • 在训练数据分布上,让“下一个 token”的负 log-likelihood 尽量小;
  • 换人话讲:在局部上下文里,生成“看起来最合理”的下一段东西。

它并不直接关心的是:

  • “这个项目的整体结构是不是简洁优雅?”
  • “这个代码库未来 3 年是不是好演化?”
  • “这个系统的语义模型是不是最小、统一、可压缩?”

所以它擅长的是:

  • 在有限上下文里,补一段“看起来对”的代码;
  • 模仿“统计上常见的写法和套路”。

但它不会:

  • 主动停下来给你先画一份架构图;
  • 再做一轮“最小描述长度(MDL)”意义上的全局设计优化;
  • 然后才开始填细节实现。

结果就是:局部看着都挺聪明,整体并不保证收敛到一个低熵结构。

在结构轴上,就是:局部 patch 越来越多,全局规划始终缺位。


3.2 目标函数错位:优化的是“似乎合理”,不是“长期可维护”

再往上一层看训练目标。

大多数 coding model / chat model 的对齐和评估指标,基本围绕:

  • pass@k;
  • 编译/测试通过率;
  • 代码风格是否“像人写的”;
  • 对话满意度(主观感受上“有帮助”“好用”)。

这些目标里基本没有:

  • “三个月后的维护成本”;
  • “新功能接入时需要动多少地方”;
  • “命名 / 抽象 / 依赖是不是在收敛”;
  • “整个 repo 的熵是不是在持续上升”。

所以模型学到的是:

“写一段当下看起来合理、能跑、不太偏离常见写法的代码”。

而不是:

“在既有约束下写出最便于未来演化、整体冗余最低、熵最小的实现”。

换成前两章的语言:

  • 在结构轴上:更偏向“能工作就行”的结构,而不是“最可演化”的结构;
  • 在语义轴上:更偏向随场景现起名字,而不是压缩成统一领域语言;
  • 在行为轴上:更偏向局部能跑,而不是系统级的行为一致性。

也就是说:

模型本身的目标函数,在信息论意义上是有“偏向高熵”的。“低熵”这件事,如果我们不在系统外加目标,它自己不会帮你管。


3.3 prompt 驱动:约束本身在漂移

传统工程里,很多约束是“硬编码”的:

  • 目录结构;
  • style guide;
  • 领域模型;
  • 错误模型;
  • 日志规范;
  • 架构文档和 ADR(Architecture Decision Record)。

在 vibe coding 里,很多东西变成了 prompt 里的自然语言:

  • “写得简单一点”;
  • “更 pythonic 一点”;
  • “方便以后扩展”;
  • “按我们之前说的那个架构来”;
  • “用之前那种 style”。

问题是:

  • 这些描述是模糊的
  • 随时间漂移的(今天心情好和心情不好,说法可能都不一样);
  • 团队里每个人说话方式也不一样。

于是,约束这件事本身就变成了高熵的:

  • 你很难说清楚:“系统当前被哪些约束支配着?”
  • 没有一个稳定的“项目宪法”;
  • 模型每次生成时看到的约束,是一小段当时的自然语言。

结果就是:

约束空间是模糊的、漂移的,在这个空间里采样出来的代码,自然熵也高。

这直接投影到:

  • 语义轴:业务概念 / 命名 / 状态在不同阶段、不同人 prompt 下漂移;
  • 结构轴:不同人对“分层”“解耦”的理解不太一样,模型就学着所有人轮流来一遍;
  • 行为轴:错误模型、边界处理方式,随着 prompt 语气和例子改变而偏移。

3.4 生成过程是“局部补丁式”的,而不是“全局重构式”的

人类手写代码时,比较成熟的工程实践通常是:

  1. 先写一个粗糙版本;
  2. 看着不顺眼,就立刻重构一轮(拆模块、统一命名、重画抽象边界);
  3. 再写新功能,发现又开始乱了,再重构一轮。

这本质上是一个“写 + 重构”交替进行的 主动熵减过程

而典型 vibe coding 的常见模式则是:

  1. 我:“加个导出 CSV 功能。”
  2. 模型:在原文件里堆一段新逻辑。
  3. 我:“再加个筛选条件。”
  4. 模型:继续往刚才那段逻辑里塞 if/else。
  5. 我:“再支持一个新的排序方式。”
  6. 模型:在已有逻辑上再 patch 一层。

模型很少主动说:

“这块已经过于复杂,我建议先把它拆成 A/B/C 三个函数或模块。”

除非你明确说“帮我 refactor 一下”,而:

  • 多数人只在“看不下去”的时候才提;
  • 而且每次 refactor 自己又是一个新的随机生成过程:命名、抽象、边界可能再次大变样。

所以在结构轴上,你会看到:

  • 功能一切一切地往同一块地方堆;
  • 高圈复杂度函数越来越多;
  • 中间偶尔有几次半截重构,把大块逻辑撕开一半就丢在那儿。

长期来看,这是一个**持续注入随机扰动但几乎没有“系统性熵减”**的过程。


3.5 训练数据本身就是“高熵 + 混杂风格”

再看训练数据这一层。

对 coding model 来说,训练数据大多来自:

  • 不同年代的开源项目;
  • 不同行业 / 不同成熟度的代码库;
  • 写法风格严重不统一的代码(有的很现代,有的还停留在十年前);
  • 各种临时脚本 / demo / side project。

从统计上讲,模型看到的是一个本身就高熵的工程生态:

  • 命名风格:snake_case / camelCase / 全大写 / 简拼 / 拼音混杂都有;
  • 抽象方式:DDD 味道的、非常 OOP 的、非常过程式的,都有;
  • 错误模型:各种 return code、异常、返回 null 混在一起;
  • 结构:有的 repo 分层极度清晰,有的就是一坨 scripts 加几个 util。

模型学到的是“这些东西的统计平均”,而这个平均本身并不是:

  • 某一家公司内部统一风格;
  • 某一种极度干净、架构极简的 codebase。

所以在没有额外约束的情况下,它会:

  • 有时候给你非常现代的写法;
  • 有时候给你看起来像是十年前 Java/PHP 的套路;
  • 然后这些东西混在同一个项目里。

在语义轴和风格轴上,这个效应尤为明显:你等于请来了一位“全球开源平均风格”的外包工程师。


3.6 解码策略(采样)本身在注入随机性

为了避免模型每次输出都一模一样,我们通常会做一些采样:

  • 设置 temperature / top-p;
  • 不满意就 regenerate;
  • 再不满意就换个 prompt 再来。

这些表面上是:

  • 提高“多样性”;
  • 避免陷入某种死板模式;
  • 多试几个版本,说不定能有惊喜。

从熵的角度看,其实就是:每一次生成,都向代码库里注入了一点随机噪声。这些噪声不会自己消失,而是:

  • 沉淀在命名里,变成同义不同写法;
  • 沉淀在控制流里,变成各种 if/else 的排列组合;
  • 沉淀在结构里,变成新模块 / 新 util / 新 helper。

随着项目演化,这些随机扰动累积,就变成了我们在结构轴、语义轴、行为轴上看到的高熵现象。


3.7 上下文窗口有限:模型视野是局部的

即便上下文窗口越来越大,它也不可能完整覆盖整个系统

  • 一个中大型服务的所有文件、所有历史设计决策,不可能全塞进 prompt;
  • 多数时候,模型看到的是几个文件 + 一点说明;
  • 而且是任务局部的上下文,不是全局视角。

这意味着:

  • 它在补代码时,对全局依赖图是一知半解的;
  • 对领域模型也只看到局部切片;
  • 对已有模式(比如统一的错误封装、工具函数)也不一定能完整对齐。

可以把它想象成:

一个非常聪明,但又高度近视的实习生,眼前这一块看得特别清楚,全局结构只能靠猜。

结果就是:

  • 在结构轴上:

    • 它可能在本地又多加一层 abstraction,而不知道别处已经有类似封装;
    • 也可能直接跨层调用,因为没看到“正确的跳板服务”。
  • 在语义轴上:

    • 它可能给已有概念再起一轮新名字,因为不知道项目里已经有了唯一命名;
  • 在认知轴上:

    • 历史演化信息只在 git log 和脑子里,而不在它能看到的上下文里。

局部聪明 + 全局近视,在没有额外架构约束和工具辅助的情况下,非常容易走向高熵。


3.8 多模型 / 多工具 / 多 Agent 带来的“协议熵”

现实中的工程环境,往往不是“一个大模型统治一切”,而是:

  • IDE 内置一个本地/远程补全模型;
  • 代码生成用另一个对话式大模型;
  • PR 上面挂着 linter bot、format bot、refactor bot;
  • CI 里还可能有专门检查依赖 / 安全 / 性能的工具。

它们可能:

  • 训练语料不同;
  • 系统 prompt 不同;
  • 对“好代码”的偏好不同;
  • 有的甚至风格对立(一个偏函数式,一个偏 OOP)。

在没有统一“项目宪法”的情况下,这等于:

给同一个项目请了好几家外包团队,

每家都在自己的视野里“帮你优化一下”。

结果:

  • 风格轴上:不同 bot 和模型轮流在同一片代码上打自己的标签;
  • 结构轴上:有的 bot 会建议多抽象,有的建议 inline 回去;
  • 语义轴上:有的模型喜欢用某种命名模式,有的喜欢另一套。

我把这一层叫“协议熵”:

不同模型 / 工具之间,对于“这套项目的协议/约束”的理解并不一致

除非你把:

  • 仓库画像(风格 / 结构 / 领域模型);
  • 架构规则;
  • 命名规范;

统统变成共享的、机器可读的“协议层” ,让所有模型和 bot 都在这上面协作。否则,工具越多,“协议熵”越高。


3.9 反馈机制偏向“短期可用”,而不是“长期健康”

最后是反馈层面。

现在无论是模型训练时的信号,还是产品层面的用户反馈,大多都在看:

  • 这次能不能跑;
  • 输出是不是“有用”;
  • 编译 / 测试能不能过;
  • 用户是不是觉得“方便、好用、爽”。

很少有:

  • 三个月后的维护成本;
  • 新需求接入的 friction;
  • refactor 难度;
  • 新人上手的心智负担。

这会带来两件事:

  1. 模型在训练时,根本没办法感受到“长期高熵带来的痛苦”,它只会被鼓励去做短期上看起来聪明的事;
  2. 工具和产品设计也会自然倾向于“能让功能尽快跑起来”的场景,而不是“能让系统十年后还好维护”。

所以我们现实里看到的是:

  • 写功能时:AI 加速很明显;
  • 系统长期健康度:如果不刻意设计压熵机制,反而加速滑向“高熵沼泽”。

3.10 “熵”到底和复杂度、技术债有什么不一样?

说到这里,有些高阶读者可能会问的问题是:

“你说的这些熵,和我们平时讲的复杂度、技术债,有什么本质区别?”

简单对比一下:

3.10.1 复杂度(complexity)

  • 通常指的是局部或特定维度的复杂度:

    • 某个函数的圈复杂度;
    • 调用链深度;
    • 某个模块的配置项数量;
    • 某个算法的时间/空间复杂度。
  • 更偏“点状”和“线段级”的刻画。

更多是:

  • 在多个维度上,观察整体状态分布是不是“散得很开”:

    • 命名多样性;
    • 依赖图像不像随机图;
    • 行为模式是不是高度碎片化。
  • 它既可以覆盖“点状”复杂度,也涵盖结构、语义、行为和认知层面的无序度。

简单讲:

复杂度是“有多难懂/多难算”,熵更接近“这个系统在多少种风格和状态之间摇摆”。

3.10.2 技术债(technical debt)

  • 强调的是“有意欠债”,比如为了赶进度,先写个简单版本;暂时不抽象、不解耦、不补齐边界;未来要花时间还。
  • 带有意图、时间和权衡:我们知道这里不完美,只是“先这样”。

的很多来源并不是“有意欠债”,而是:

  • 在高度自由的生成空间里,
  • 在没有强约束的前提下,
  • 自动沉淀出来的随机性和无序度。

例子:

  • 同一个概念被起了 N 个名字,不一定是为了赶进度“故意乱起”的,可能只是不同人、不同模型在不同时间“顺手一写”;
  • 三种错误返回方式混杂,也不一定是“有意欠债”,可能只是采样和补丁自然飘过去的结果。

因此我会这么看:

  • 技术债更多是“我们本来能做得更好,但出于现实约束暂时没做”;
  • 熵则是“如果你不做刻意管理,即使没‘欠债’,随机噪声也会不断累积”。

在 vibe coding 环境下:

即使你不打算欠债,也会自然地、有机地长出一堆“高熵结构”。

这也是为什么我在这篇文章里刻意用“熵”而不是只说“复杂度 / 技术债”——它更准确地描述了:

vibe coding 默认态下,在模型机制 + 使用方式 + 工具生态叠加的情况下,系统会自然演化到哪种“高无序度”的状态。


这一章的结论可以非常粗暴地总结成一句话:

如果你什么都不做,vibe coding 默认会把代码库推向一个“局部聪明、整体高熵”的形态。

后面几章,我会基于这个默认态来讨论:

  • 这对项目 / 团队 / 生态意味着什么;
  • 以及在个人、团队、工具、模型这些层面上,
  • 我们有哪些“熵管理手段”可以用来对抗这条自然趋势。

四、高熵代码对项目、团队和行业意味着什么?

前面三章更多是在描述:

  • vibe coding 下熵是怎么起来的
  • 以及它在结构、语义、行为、认知几条轴上是怎么表现的。

这一章换个角度:

假设我们不刻意做熵管理,让系统顺着这条“高熵默认轨迹”一路走下去,它会把项目、团队、生态推到什么位置?

先用两个极端场景做个“上界 / 下界”的对照。


4.0 两个极端场景:高熵沼泽 vs 有熵管理的 AI-native 团队

场景 A:高熵沼泽

  • 三年前,一个小团队 + 强大模型,用 vibe coding 在几周内做出一个很能打的 MVP;
  • 功能快速叠加,模型写了大量代码,目录和命名“顺手就来”;
  • 重构基本靠“谁看不下去了就改两下”,没有系统性压熵机制。

三年后:

  • 产品线扩展成 N 个子系统,代码量翻了十倍;
  • 每一层都有多种风格、多套命名、多种错误模型;
  • 任何中等规模改动都伴随巨大的不确定性成本;
  • 大部分人对这套系统的真实行为,只能靠日志 + 线上真相来理解。

这个系统的状态可以概括为:

“能跑,但没人想碰。”

结构熵高、语义熵高、行为熵高、认知熵更高——它是一块可运行但不可演化的高熵沼泽

场景 B:有熵管理的 AI-native 团队

另一边,是一个从 day 1 就自觉“AI-first + 熵管理”的团队:

  • 同样 heavily 使用模型,但从一开始就定义了:

    • 清晰的分层架构和依赖规则;
    • 项目级 glossary 和领域模型;
    • 自动化的重构/规范 bot 和熵仪表盘;
  • coding 流程是:

    • 先更新/维护 machine-readable 的设计 / 契约 / 计划;
    • 再在设计约束下做 codegen;
    • 每一次功能交付,都伴随着一小步的结构熵 / 语义熵压缩。

几年后,这个系统:

  • 功能复杂度不比场景 A 小多少;
  • 但结构演化路径清晰、语义抽象稳定,行为在不同组件间相对一致;
  • 新需求接入和重构的风险可控,新人上手成本可预期。

它不是“完美架构”,但可以被描述为:

“高自动化、可持续演化、熵被控制在合理区间的系统。”

这两头是“上限 / 下限”。现实大部分团队会落在中间,但:

  • 越靠近高熵沼泽,长期维护成本和组织风险会疯狂上升;
  • 越靠近“有熵管理”的一侧,AI 带来的加速效应越能持续,而不是早早透支掉。

带着这两幅对照图,下面分几层看高熵的影响。


4.1 对单个项目:从“写难”变成“维护难”

传统工程时代,难点更多在“写”:

  • 如何抽象业务;
  • 如何设计合理的数据结构和状态机;
  • 如何把复杂度控制在脑子能 hold 得住的范围内。

vibe coding 把写出一段能跑的代码这件事的难度显著拉低了:

  • 普通工程师可以在短时间内做出以前需要资深工程师才能搞定的原型;
  • 人机配合写功能时,局部看起来甚至比人类更细致(边界、参数、样板逻辑)。

但是,随着结构熵、语义熵、行为熵和认知熵几条轴上的数值被不断拉高:

  • 写功能这一步变轻了;
  • 调试、重构、接手别人代码的难度被成倍放大。

典型表现:

  • 任意改动都牵一发动全身,因为依赖图接近随机图;
  • 很多功能在代码层面只找到“影子”,找不到一个清晰的、可抽象的位置去修改;
  • 新逻辑要么复制粘贴一份,要么硬塞到已有的复杂函数里。

于是项目很容易落在这样一种状态:

“代码库不是不能动,是不敢动。”

在这状态下,“功能开发速度”不再是瓶颈,“系统能否持续演化”变成了瓶颈。写难 → 维护难 / 演化难,是单项目层面最直观的相变。


4.2 对团队:知识沉淀和责任归属都变得模糊

高熵在认知轴上的直接后果是:

“到底谁真正理解这套系统?” 这个问题变得越来越难回答。

因为以下几个原因叠加:

  • 很多模块是“人 + 模型对聊聊出来的”,设计决策散落在对话记录和临时 prompt 中;
  • 需求和规格并没有被稳定固化在文档或契约里,而是悬浮在历史对话、脑补和“当时的习惯”里;
  • 代码本身风格混杂,很难从中读出清晰的领域模型和演化路径。

结果就是:

  • 很多模块没有强烈的 ownership——大家都知道是“AI 写的”,但谁也说不清算“自己的作品”;

  • 复杂模块的理解被少数几位“老住户”垄断,他们对系统的理解既不完全可转移,也很难形式化表达出来;

  • 新人 onboarding 时不是读一套结构清晰的文档,而是:

    • 从日志/监控里猜行为;
    • 从散乱代码中反推概念;
    • 靠口口相传了解“这里本来是想这样设计的”。

事故发生时,这种高认知熵会放大事故成本:

  • 难以定位根因:问题到底是规格不清?模型写错?还是后续改动破坏了某个隐含不变量?

  • 责任边界模糊:

    • prompt 设计者的责任?
    • 审阅者的责任?
    • 工具/模型本身的责任?

这会倒逼团队在几个方向上变得更形式化:

  • 对关键领域的架构和模型,用更严肃的形式(ADR、schema、契约)固定下来,而不是只存在于聊天里;
  • 对“谁是哪个子系统的 steward / owner”有更明确的定义;
  • 事故复盘时,把“熵的演化轨迹”纳入讨论,而不是只看单次 bug。

4.3 对系统可观测性:监控和日志变成“第二套源代码”

随着结构熵、语义熵和行为熵都上去,单看代码这一层,很难回答一个关键问题:

“这套系统在真实世界里到底是怎么行为的?”

在高熵项目里,很多“真相”只剩三种途径可以看:日志(Logging)、指标(Metrics)、链路追踪(Tracing)。这会带来一个挺有意思的翻转:

Observability 不再只是“辅助工具”,而是理解系统行为的“第二套源代码”。

具体表现:

  • Debug 行为问题时,看代码只是辅助,主战场是日志和 trace;
  • 架构图很难准确,也没人有信心更新,只能通过 trace 来反推“逻辑拓扑”;
  • 线上 dashboard 上的指标/trace 拓扑,成了团队默认相信的“系统现状”。

这有两个后果:

  1. 可观测性本身变成“关键基础设施”

    • 日志结构、指标命名、trace ID、采样策略这些东西,必须系统设计;
    • 否则,高行为熵 + 弱 observability = 对真实行为彻底失明。
  2. 熵管理一部分要在运行态做

    • 只看静态代码已经不足以评估系统熵;

    • 需要结合运行时行为:

      • 哪些错误路径很热;
      • 哪些边界条件处理分裂严重;
      • 哪些调用拓扑已经变成“随机图”。

可以这么理解:

高熵代码 → 低可预期性 → 对 observability 的依赖指数级增加,监控 + 日志 + tracing 逐渐长成“运行态的领域模型”。


4.4 对用人标准:程序员的核心能力在迁移

在 vibe coding 盛行的环境下,“会写代码”这件事的门槛确实在下降:

  • 会用模型 + 会基本调试,已经可以完成相当多的功能开发;
  • 很多重复性逻辑、样板代码和框架 glue,可以放心交给模型。

那还需要人干什么?如果把这篇文章前面的熵轴都放进来,会发现下一代工程师更需要的是这几类能力:

  • 设计低熵架构的能力

    • 把需求和领域模型压缩成干净的抽象;
    • 定义清晰的分层、依赖边界和错误模型;
    • 把“允许高熵”与“必须低熵”的区域划清楚。
  • 在高熵代码堆里建立心智模型的能力

    • 读高熵代码时,快速抽出“骨架”和关键路径;
    • 通过日志/trace 补全行为上的认知;
    • 判断哪些熵是可接受的噪声,哪些必须被压下去。
  • 从写具体代码,升级为设计规则和工具的能力

    • 用 prompt 模板、架构约束、工具链来指挥和约束模型写代码;
    • 设计“熵管理机制”:重构策略、规范 bot、熵指标仪表盘;
    • 为团队选择和定制 AI 工具,让它们在统一协议下协同工作。

换句话说:

程序员越来越像“系统设计者 + 熵管理者”,而不仅仅是“代码生产者”。

从招聘/评估角度看:

  • 简单的“写题 / 手撕算法 / 写小功能”会越来越不能区分候选人;
  • 对“复杂系统建模”、“架构演化”、“在高熵环境下建立清晰 mental model”的能力会越来越被看重。

4.5 对开源和生态:会出现大量“AI 分叉”的变种

高熵不仅存在于单个项目内部,还会在生态层面显现出来。

一个可以预见的趋势是:

大量“AI 改写版 / AI 分叉版”的开源项目会出现。

典型模式:

  1. 某个开源项目 X 很热门;

  2. 有人把 X 整个丢给模型,让它:

    • 改语言(比如从 JS → TS,从 Java → Go 等);
    • 改框架(换 Web 框架、ORM、依赖注入方案);
    • 加一堆业务定制;
  3. 得到一个“看起来结构更现代、风格更统一”的 fork Y。

问题在于:

  • Y 的结构和命名虽然在局部看更统一,但和原项目的结构/语义偏差会越来越大;
  • bug 报告、patch、PR 很难再直接回流到上游;
  • 上游版本升级时,Y 很难低成本地跟上——迁移成本高得离谱。

在生态层面,这就意味着:

  • 不兼容变种的数量爆炸;
  • “某某库的 AI 改写版”遍地都是,但彼此之间不可组合;
  • 社区的集中维护力量被分散在大量小而乱的变种上。

可以说:

模型极大降低了 fork 和“自定义演化”的成本,同时也在生态层面制造出一层新的“熵雾”。

长期来看,这会逼迫生态去发明新的:

  • “AI 友好的上游 / 下游协作模式”;
  • 更强的 API 稳定层和协议层(让 fork 变种在高层协议上至少保持兼容);
  • 工具化的“跨分叉对齐 / 自动迁移”能力。

4.6 对合规与安全:需要新的规范和工具

在一些敏感领域:

  • 金融 / 证券;
  • 医疗 / 制药;
  • 合约 / 法律相关系统;
  • 关键基础设施(电力、交通、通信等),

高熵代码会被直接视为高风险资产。监管和合规部门通常不会接受这样的回答:

“这块是模型写的,我们也不太清楚它内部为什么这么设计,总之现在是能跑。”

这会带来几类刚性需求:

  • 可审计性

    • 哪些模块是 AI 生成的,哪些是人工手写的;
    • 生成过程有没有留存足够的审计信息(prompt、上下文、版本号等);
    • 关键改动有没有经过明确的人工 review 和批准。
  • 可证明性

    • 对关键逻辑,可能需要形式化验证 / model checking;
    • 对安全相关模块,可能要有独立的“低熵内核”,禁止模型随意改写;
  • 可追责性

    制定明确的责任边界:

    • AI 工具本身的责任;
    • 使用方(prompt、配置、流程)的责任;
    • 审核/决策者的责任。

这意味着:

高熵区域和“关键合规区域”要被严格区分看待,后者必须被锁在低熵、强审计、强约束的框架里。

相关的新工具 / 标准会出现,比如:

  • “AI 参与程度标识”:代码级别标出哪些段是 AI 生成 / 修改的;
  • 针对 AI 生成代码的合规审核 workflow;
  • 对高风险模块强制要求“形式化规格 + 限制性 codegen”。

4.7 对商业模式:维护成本会进入计价体系

最后一层是

在“写代码变得更快、更廉价”的世界里,一个自然的问题是:

外包 / SaaS / 工程服务将来怎么定价?

如果大家都能用模型快速堆出一套能跑的东西,那么:

  • 仅仅按“功能点数量”和“开发工时”计价,越来越说服力不足;
  • 甲方会越来越关注两件事:未来 X 年的维护成本&替换/迁移成本。

这意味着:

  • 高熵代码(即使短期交付很快)会在经济上被惩罚;
  • 能够持续控制熵、维护长期可演化性的团队和平台,会有竞争优势。

可以想象出现这样的条款:

  • 合同中写明“技术债和维护成本预算上限”;
  • 对“代码熵指标”的某些阈值做约定(超出就触发额外 refactor 任务或罚款);
  • 把“系统演化能力”变成一个可以谈判和计价的指标。

在这种生态下:

“快写一坨能跑的”不再是终点,“在高自动化的前提下,保持长期低熵”才是有定价权的能力。


本章可以总结成一句话:

高熵不是一个“审美问题”,它会在项目、团队、生态、合规和商业层面,都表现为非常具体的、可以量到的钱和风险。

后面的章节,就会从“怎么观测熵”“怎么量化熵”开始,再往前走一步:

在模型训练和工具设计上,能不能把“熵管理”变成一等公民。


五、既然“高熵是本性”,那我怎么考虑“驯服”它?

前面几章基本都在说一件事:

在 vibe coding 这个范式下,“高熵”是默认态。不管是结构、语义、行为还是认知,如果你什么都不做,数值都会自然往上跑。

对我来说(从使用者的视角),“驯服高熵”的思路从来不是指望熵消失,而是:

承认生成层高熵,但在更高层和工具层建立“压熵机制”。

换句话说:

  • 生成层:让模型尽情 vibe、尽情出手;
  • 约束层 & 工具层:负责持续压熵,把系统拉回一个可演化的状态。

下面从四个角度来讨论这件事:个人实践、团队工程、工具系统、生态和角色


5.1 个人层面:从 coder 变成 constraint designer

在 vibe coding 场景里,如果你还把自己定位成“写代码的人”,会有一点吃亏:

  • 大量“写”的工作已经可以交给模型;
  • 人更应该把精力放在定义约束、设计空间、管理熵上。

我自己写代码(更准确说:和模型一起写代码)时,会刻意做几件事。


1)固定生成语法,降低自由度

不随意聊天,而是习惯性按模板提需求。大致类似:

明确:

  • 输入/输出类型;
  • 错误处理策略(抛异常 vs 返回 Result vs error code);
  • 日志要求(在哪些路径打什么级别的 log);

严格限制:

  • “只写一个函数 / 一个类,不要额外逻辑”;
  • “不得访问除 X/Y 以外的模块”;
  • “只允许调用这几个 API”。

其本质是:

不是问模型“你能帮我写点什么吗?”,而是“我帮模型设计一个尽量小、尽量有边界的状态空间”。

在前面那些熵轴上,这可以直接:

  • 降低结构熵:减少随意跨层依赖和巨型函数的概率;
  • 降低行为熵:把错误处理和日志行为收紧在几个固定模式里;
  • 给后面的 refactor 留出空间——因为粒度更可控。

2)把重构变成“每回合的默认动作”

很多人用模型写代码的流程大概是:

  1. 让模型加功能;
  2. 功能看起来能跑——不错不错;
  3. 若干轮之后,代码烂到看不下去,才想起 refactor。

我自己的偏好是:

每加完一个功能,就默认为这回合还有一步:“请检查刚才改动,结合项目风格,给出重构建议并实现。”

具体可以是:

  • 让模型自己找重复逻辑 / 可以抽象的地方;
  • 让它统一一下命名 / 错误处理方式;
  • 让它拆出小函数、小模块。

这有两个好处:

  1. 把“熵减”变成高频小动作,而不是低频大手术;
  2. 人可以主要审一件事: “这次 refactor 是不是让结构更收敛、语义更清晰?”

长远看,这是在结构轴和语义轴上,持续做“小步压熵”。


3)刻意培养“熵感知”

这一点比较“软”,但我觉得是高阶开发者在 vibe coding 时代非常重要的能力:

你要能在阅读/修改代码时,感受到“这里开始变乱了”。

我自己会刻意问一些问题:

结构轴:

  • “这里是不是开始出现巨型函数 / 巨型模块了?”
  • “依赖方向是不是开始乱穿了?”

语义轴:

  • “这里是不是引入了一个本来就有的概念,只是换了个名字?”
  • “状态枚举是不是又多了一种和现有定义类似的写法?”

行为轴:

  • “这里的错误处理是不是和别处不一样?”
  • “这个边界条件是新 invention,还是已经有标准模式?”

一旦发现某个局部的熵开始上升,就尽早处理,而不是心里默念一句:“算了先这样吧,能跑就行。”

熵感知其实就是一个 feedback loop 的起点:没有意识到熵在涨,就不会触发后面的压熵动作。


5.2 团队 / 项目层面:用框架和契约把空间锁死一部分

个人可以做很多事,但一旦上升到团队 / 项目级别,仅靠个人习惯不够,需要更硬的东西:

框架、规则、契约,最好都变成“可被工具理解”的形式。

我会建议重点盯以下几块。


1)强约束的架构模板:给结构轴画边界

一个典型的做法是明确规定:

  • 层次结构:UI -> Application Service -> Domain -> Repository -> Infra
  • 每一层职责边界:谁只是 orchestration,谁承载业务语义,谁只负责 IO;
  • 合法依赖方向:UI 不直接调 Repo,Domain 不依赖 Infra,禁止跨模块随意互调。

关键是:

不只是写成文档,还要写成 linter 配置 / 架构规则 / 静态分析脚本。

然后在使用模型时,把这些约束写进系统 prompt 或调用规范里:

“所有新增代码必须遵守上述分层和依赖规则。”

这会显著降低结构熵和依赖图熵,把模型的自由度锁在一个比较干净的结构子空间里。


2)把命名 / Glossary 升级为项目的“一等公民”:压语义熵

很多团队会有“术语表”这一类东西,但常常停留在 wiki 里没人看。

在高熵项目里,我认为需要更激进一点:

做一份明确的 glossary:

  • 核心业务概念的官方命名;
  • 禁用别名列表(比如禁止再引入 member/customer 等新叫法);
  • 各个状态 / 枚举的统一定义。

把 glossary 变成:

  • 模型的 long-term context / system prompt 的一部分;
  • 静态分析的输入:发现“新名词”时报警;
  • review checklist 的一部分:新 PR 有没有违反 glossary。

这可以明显压低语义熵和命名熵:“你不能随手起一个新名词,你必须在这本词典里选一个词。”


3)划清“低熵内核”和“高熵外壳”:分区管理熵

现实里不可能所有地方都低熵,否则工程成本会被拉爆。

我会更倾向于显式做分区:

低熵内核(core domain / 合规关键路径 / 安全相关模块):

  • 尽量由人写或人主导;
  • 严格 review;
  • 和模型交互时,使用最保守的生成策略(小范围修改、禁止大规模重写);
  • 架构规则、命名规范、错误模型都执行最严标准。

高熵外壳(UI、适配层、集成 glue、demo / 实验区):

  • 模型可以更自由发挥;
  • 允许更多样化实现和实验性改动;
  • 但和内核之间要有清晰 API / 协议边界。

这相当于在系统里画了一个圈:

里面那圈必须低熵,外面那圈可以相对高熵,

但外圈的东西随时可以整体丢掉重来。在团队层面,还可以进一步给不同目录 / 模块配置不同的:

  • lint 严格程度;
  • 测试覆盖要求;
  • AI 生成策略(temperature、是否允许大段 rewrite)。

5.3 工具层面:做“熵的画像、可视化和持续压缩”

仅靠习惯和规则,还不够。真正要把熵管住,需要工具层面持续做三件事:

  1. 画像:让系统知道“自己长什么样”;
  2. 可视化:让人一眼看到“哪里在变红”;
  3. 压缩:有机制去持续收缩高熵区域。

1)Repo 画像器:自动提取“家族风格”和“结构骨骼”

具体想象一个“Repo 画像器”,它自动扫描整个仓库,生成一些画像:

  • 命名风格画像:常见前缀/后缀、大小写习惯、领域词汇表;
  • 架构模式画像:常用分层方式、常见调用路径、典型依赖结构;
  • 依赖层次与边界:哪些模块天然更底层,哪些是上层 orchestrator;
  • 常用 Helper/Util 模式:哪些函数/类被广泛复用。

然后,AI coding 工具在生成代码时:

  • 把这份画像作为系统 prompt / adapter 的一部分;
  • 不再从“全球开源平均风格”的分布采样,而是从“这个仓库的家族分布”采样。

本质上,就是告诉模型:“你现在是在这个家的传统下写代码。”

这会明显降低风格熵、语义熵,并对结构熵起到“收敛到已有模式”的作用。


2)常驻的重构 bot / 规范 bot:把熵减变成后台进程

不是一时兴起地 refactor,而是:

有一支“后台进程级”的 bot 队列,持续在仓库里做熵减工作。

比如:

  • 去扫重复代码 / 语义相似实现,建议抽象或复用;
  • 检测违反依赖规则 / 架构约束的地方;
  • 发现“新名词 / 新错误模型 / 新返回格式”,判断是否违反 glossary / 协议;
  • 自动发 PR 做修复和归一化。

人类的工作从“亲自做重构”变成:

  • 审核这些熵减 PR;
  • 决定哪些合并、哪些重跑、哪些要更大范围调整。

这相当于在仓库门口放了一台“熵泵”:

只要仓库一闲下来,它就会默默抽一点熵出来。

长周期看,这类 bot 会显著减缓结构熵 / 语义熵 / 风格熵的恶化速度。


3)依赖图 + 熵热力图:直接把高熵区域点亮

最后是**可视化,**我会很希望有这样一块面板:

  • 一张依赖图(可能按模块 / 子系统聚合);

  • 每个节点带一些熵指标:

    • 结构熵:循环依赖、util 依赖、出入度分布等;
    • 语义熵:内部命名多样性、概念簇数量等;
    • 行为熵:错误模型多样性、返回格式变体数等;
    • 演化熵:最近 N 次改动的分布、PR 粒度等。
  • UI 上用颜色标出高熵区域(像热力图一样)。

这样有几个直接收益:

  • 团队在开 sprint / 规划 refactor 工作时,有一个直观的“靶子”;
  • 任何人都能看到“哪些模块已经到了危险区”;
  • 工具也可以据此排队:优先对高熵区域发起重构/规范 PR。

从“看代码感觉哪儿乱”进化到“有一张熵地图”,是从个人熵感知 → 团队级熵管理的关键一步。


5.4 生态 / 角色层面:新职业、新框架、新计价方式

最后一层,是整个生态和组织角色怎么因为“熵问题”发生迁移。


1)新角色:架构牧羊人 / 熵管理工程师

我觉得未来团队里,会越来越需要一种角色,可能会叫做:

架构牧羊人 / 熵管理工程师。

它和传统的架构师 / tech lead 有点像,但关注点不太一样:

传统架构师 / tech lead:

更关注大的技术路线和关键决策:比如选型、拆服务、核心技术方案等。

架构牧羊人 / 熵管理工程师:

更关注这套系统在时间轴上的整洁度和可演化性;换句话说:盯着“熵轴”看。

具体可能包括:

  • 设计和维护架构规则、依赖边界、错误/日志模型等“项目宪法”;
  • 维护 glossary 和领域模型,把业务语义熵压在一个可接受区间;
  • 负责熵指标体系和熵仪表盘:定义指标、监控趋势、拉响红线;
  • 规划重构和技术债偿还的节奏:决定在哪些地方、以多大力度压熵;
  • 维护和调教各种 AI coding 工具、重构 bot、规范 bot,让它们在统一协议下工作。

可以把这个角色理解为:

一位“系统园丁”,每天的工作就是修枝剪叶、清理杂草、维持整个代码花园的秩序。

在 vibe coding 时代,这种“园丁”会非常稀缺。

致敬环节,这个想法其实启发于年轻的时候看的一篇博文,具体哪家公司(依稀记得是一家电商公司)分享的意见不记得了。大概讲的是,在他们公司业务快速发展的时候,CTO把公司的team分成两部分,一部分快速做业务支撑,这部分人员的代码不会特别考虑系统健壮性、抽象度、测试覆盖率等;另一部分的人就像履带一样,不断地去对前面人的代码,做重构、补测试等。以支撑公司业务的快速发展需要的快速迭代+系统稳定性。


2)新一代 “AI-native、低熵框架”

从工具/框架视角看,我非常看好这样一种东西:

专门为“AI 参与开发”设计的、低熵友好型框架。

它可能有这些特征:

  • 强限定目录结构和模块边界:

    • 比如约定俗成的 ui/app/domain/repo/infra 目录;
    • 自动生成 skeleton 和依赖规则配置。
  • 内置一套统一的错误模型 / 日志模型 / 响应封装:

    • 所有 API 都用同一套 envelope;
    • 所有错误都走同一套枚举和结构。
  • 有明确的领域层抽象方式:

    • 比如默认支持 entity / value object / aggregate root;
    • 把这些都做成模板和约束。

AI 在这样的框架里写代码:

  • 自由度少了(熵空间被大量裁剪);
  • 但输出更统一、更可控,
  • 项目长期健康度也更容易被维持。

可以类比一下:

从“在原始荒地上自由建房子”,变成“在一个规划良好的社区里装修”。

致敬环节:在做本文的二次修订时,发现我原来的这个观点,好像和我某boss的观点还挺一致的,且某boss已经在着手实践这套系统,respect!


3)按维护成本计价的服务模式

最后是商业层面。

如果软件开发越来越多地是“模型 + 人”的合作,而且“写代码”本身越来越廉价,那么:

维护成本和演化能力,很自然会进入计价体系。

一些可能的演进:

  • 外包 / SaaS 合同里不只是写“交付这些功能”,还会写:

    • 约定未来 N 年内的技术债/熵预算;
    • 约定某些熵指标的上限(超出则需要专门 refactor);
    • 把“可演化性”写进 SLA。
  • 客户在选供应商时,不再只问“你多久能做完”,还会问:

    • “你们的代码在三年后还好维护吗?”
    • “你们怎么管理熵?”
    • “你们的工具链和框架是怎么保证长期可演化的?”

在这样的生态里:单纯“写得快”不再构成核心竞争力;“写得快 + 熵管理能力强”的团队,才有溢价空间。


这一章本质上是在回答:

在一个本性高熵的生成过程上,人和团队还有什么主动空间?

我的答案是:

  • 个人:从 coder 变成 constraint designer,培养熵感知;
  • 团队:用架构模板、glossary 和分区策略,把低熵内核保护好;
  • 工具:给仓库做画像、熵可视化和常驻熵泵;
  • 生态:让“熵管理”成为一个显式的角色、一类框架、一种可计价能力。

后面第六章,我们会更具体地聊一件事:

如果把“代码熵”当成一个指标,怎么给它一个可量化、可上 dashboard 的定义?


六、如何给“代码熵”做一个可量化的定义?

前面一直在说“熵高”“熵低”,这章干脆正面回答一个问题:

如果我想量一量这个项目的“熵”,到底在工程上能怎么算?

从信息论的视角看,熵的大致意思是:

在某个维度上,如果“系统处于各种状态的概率分布 p(s)p(s)”很平均 → 熵高,如果高度集中在少数几种状态 → 熵低。

搬到代码世界里,就是:

在某个维度上(命名、结构、依赖、行为…),系统到底有多少种“写法 / 模式 / 状态”,分布是不是散。

我不会去追求一个教科书级别严谨的“全局 Shannon 熵”,而是采用一个更工程化的做法:

  • 在结构、语义、演化、行为这些维度上,
  • 各自定义一些可计算的分布
  • 用这些分布的熵作为 proxy,构造出若干“熵指数”。

为了不和太多公式搏斗,我们做一些简单的几号约定:

  • H()H(\cdot) 表示某个具体分布的熵(local entropy),比如“从 UI 层发出的依赖分布”的熵、“某个语义簇内部命名分布”的熵;
  • Estruct,Esem,Eevo,EbehE_\text{struct}, E_\text{sem}, E_\text{evo}, E_\text{beh} 这类符号表示由多个局部熵聚合出来的“熵指数” ,更接近工程上会放到 dashboard 上看的健康度分数,而不是单一的 Shannon 熵。

你可以把它理解成:

  • HH:某个局部维度“有多散”;
  • EE:把一堆 HH 拼起来之后,这条熵轴整体“有多乱”。

下面按维度来拆。


6.1 总体思路:不是算一个“真熵”,而是建立一族“熵指标”

我们把“代码熵量化”拆成三步:

  1. 选维度

    围绕前面几章的熵轴,主要盯四块:

    • 结构:分层、依赖关系、拓扑形状;
    • 语义:命名、概念、状态机;
    • 演化:改动粒度、改动范围、节奏;
    • 行为:错误模型、返回格式、边界行为。
  2. 在每个维度上,定义一个或几个具体可算的分布

    比如:

    • “UI 调哪几类层”的分布;
    • “同一个语义簇包含多少命名变体”的分布;
    • “最近 100 个 PR 改动了哪些模块”的分布。
  3. 对这些分布计算熵或类似的离散度指标

    • 分布越散 → 该维度熵越高;
    • 分布越集中 → 该维度熵越低。

最后,对每个维度做一点加权 / 归一化,就得到几个“熵指数”;不追求数学上的绝对精确,更多是为了:

  • 能稳定反映趋势
  • 能标出高熵区域

6.2 结构熵:结构熵指数 EstructE_\text{struct}

结构熵想回答的问题是:

“这个仓库,从结构和依赖上来看,是更像有层次的建筑,还是一团 random graph?”

我会从“角色标签 + 依赖分布 + 拓扑形状”三块来刻画。

6.2.1 给每个模块打“角色标签”

第一步是给每个文件 / 模块打一个“角色”标签:

  • UI / API / AppService / Domain / Repo / Infra / Util / Test / Script …

标签可以通过目录结构、命名规则、简单 AST 规则来推断,比如:

  • /ui 下的大概率是 UI;
  • 访问 HTTP / gRPC 的是 API / Client;
  • 只做 DB 访问的倾向于 Repo;
  • 只有纯函数、不依赖业务语义的倾向于 Util。

6.2.2 “谁依赖谁”的分布:H(A)H(A)

然后,看在依赖图里:

  • 从某个角色 AA 出发,它的出边都指向哪些角色 BB
  • 比如:从 UI 出发,统计“调用到 AppService / Domain / Repo / Util 的比例”。

对某个角色 (A),定义:

H(A)=Bp(BA)logp(BA)H(A) = - \sum_B p(B \mid A) \log p(B \mid A)

直觉上:

  • 如果 UI 几乎只调 AppService,则 H(UI)H(\text{UI}) 很低(依赖模式集中);
  • 如果 UI 乱调各种层(Repo、Infra、别的 UI…),则 H(UI)H(\text{UI}) 很高。

对所有角色做一个加权平均:

Estruct(1)=AwAH(A)E_\text{struct}^{(1)} = \sum_A w_A \cdot H(A)

wAw_A 可以按模块数 / 行数 / 重要性加权。这个量越高,说明分层边界越模糊,结构熵越高。

6.2.3 度分布和循环:random graph vs 有 spine 的图

结构熵的另一部分来自拓扑本身。

  1. 度分布熵

    • 统计节点出度 / 入度的分布;
    • 如果大部分节点出度都不大,只有少数“核心模块”出度较大,通常结构比较健康;
    • 如果度分布很扁平,大家都互相乱依赖,很接近 random graph。

    对这一分布可以算一个 HdegreeH_\text{degree}

  2. 随机游走熵

    • 从任意节点随机往外走几步,看“最后落在哪类节点”的分布;
    • 如果很快收敛到某几类节点(比如 domain / repo),说明结构有 backbone;
    • 如果近似均匀分布在各类节点上,结构近乎随机。

    这里可以得到一个 HwalkH_\text{walk}

  3. 强连通子图(SCC)分布

    • 大量大号 SCC = 循环依赖严重,结构塌缩;

    • 少数小 SCC 通常可以容忍(例如几个互相调用的 util 函数)。

      可以定义一个 HSCCH_\text{SCC} 来度量“强连通子图规模分布”的离散度。

综合起来,我会把结构熵指数写成:

Estruct=αEstruct(1)βHdegreeγHSCCδHwalkE_\text{struct}= \alpha \cdot E_\text{struct}^{(1)} \beta \cdot H_\text{degree} \gamma \cdot H_\text{SCC} \delta \cdot H_\text{walk}

不需要纠结精确公式,关键是定义稳定,然后随着时间看它是上升还是下降,在哪些子系统特别高。


6.3 语义熵:语义熵指数 EsemE_\text{sem}(命名 + 状态机)

语义熵想回答的问题是:

“这套系统的业务概念和状态,是不是被统一表达了?”

这里我会拆成两块:命名熵状态机熵

6.3.1 命名熵 EnameE_\text{name}:同一概念有多少种叫法?

大致步骤:

  1. 把所有标识符收集出来:类名、方法名、变量名、枚举项等;

  2. 用 embedding / 规则 / 词向量把它们聚成若干“语义簇”:

    • 一簇是“用户相关”:user, member, account, profile, customer
    • 一簇是“组织/团队相关”;
    • 一簇是“订单/交易相关”……
  3. 对每个簇,统计名字分布,并计算熵:

Hname(cluster)=nnamesp(n)logp(n)H_\text{name}(\text{cluster})= - \sum_{n \in \text{names}} p(n) \log p(n)

然后对所有簇做加权平均:

Ename=clusterwclusterHname(cluster)E_\text{name} = \sum_{\text{cluster}} w_{\text{cluster}} \cdot H_\text{name}(\text{cluster})

含义很直观:

  • 某个业务概念几乎只用一个名字 → 该簇熵低;
  • 同一概念被各种名字切来切去 → 该簇熵高;
  • 整体 EnameE_\text{name} 越高,说明领域语言越分裂

6.3.2 状态机熵 EstateE_\text{state}:是不是有“单一真相”

另一个重要源头是“状态定义”的混乱,可以做一件事:

  1. 在代码里找出所有“看起来像状态枚举”的东西:名字带 Status, State, Phase 的 enum / 常量 / 字段;
  2. 按语义把这些状态集分组,看哪些其实在描述同一类业务状态;
  3. 在每一组里,衡量这些状态集的“差异度”:比如彼此的 Jaccard 相似度分布;
  4. 对“状态集版本”的分布计算一个熵 Hstate-groupH_\text{state-group}

如果某个业务实体(如订单)只有一份权威的状态枚举,所有地方都引用它,那么:这个语义域上的状态机熵非常低。

如果到处都有一份差不多的状态集,各自名字略不同,含义略不同,甚至值也不兼容,那:状态机熵就非常高。

综合命名和状态两个维度,我会定义:

Esem=λEname+(1λ)EstateE_\text{sem} = \lambda \cdot E_\text{name} + (1 - \lambda) \cdot E_\text{state}

语义熵指数越高,说明:

同一业务语义在代码中的“投影”越多样,越缺乏一个稳定、可引用的“单一真相”。


6.4 演化熵:演化熵指数 EevoE_\text{evo}

演化熵关心的是:

“这套系统的演化故事是连贯的,还是一种高熵 random walk?”

我会主要从 git / PR 记录里挖一些分布出来。

6.4.1 改动范围和粒度的分布

几个简单但很有用的统计:

  • 单次 PR / commit 动到多少文件、多少模块;
  • 最近 N 个 PR 分别动到了哪些模块。

可以算两种熵:

  1. 改动粒度熵

    • 统计“每个 PR 改动的模块数量”的分布;
    • 有的项目 PR 粒度相对稳定(比如大多在 3–10 个文件之间),有的项目则随机得多。

    对这个分布求熵,得到 Eevo(1)E_\text{evo}^{(1)}

  2. 模块触达熵

    • 统计最近一段时间内,各模块被改动的频率分布;
    • 如果有少数模块是演化中心(比如核心 domain 模块),其他模块相对稳定 → 熵较低;
    • 如果所有模块被均匀修改 → 演化路径接近 random walk。

    对这一分布求熵,得到 Eevo(2)E_\text{evo}^{(2)}

6.4.2 改动类型的混杂度

还可以粗暴地给 PR / commit 打标签:

  • feature / refactor / bugfix / chore / infra / doc 等;
  • 标签可以基于 commit message 模式 / diff 类型自动推断。

如果一个项目的演化是“成片的 refactor + 成片的 feature”的节奏,改动类型在时间轴上的分布会有一定结构;如果永远是混合 patch,演化节奏会更加混乱。对“改动类型随时间”的分布求熵,得到 Eevo(3)E_\text{evo}^{(3)}

综合起来,我会定义演化熵指数:

Eevo=μ1Eevo(1)μ2Eevo(2)μ3Eevo(3)E_\text{evo}= \mu_1 E_\text{evo}^{(1)} \mu_2 E_\text{evo}^{(2)} \mu_3 E_\text{evo}^{(3)}

越高说明改动粒度、改动范围和改动类型越“无故事性”;演化轨迹越难被人类压缩成一个清晰 narrative。


6.5 行为熵 / 接口熵:行为熵指数 EbehE_\text{beh}

行为熵真正要量的是“系统面对各种输入 / 环境时的行为多样性”,这个很难完全自动化,但至少可以在**接口层(API / 错误模型)**给出一些可算指标。

6.5.1 错误模型多样性:EerrE_\text{err}EerrcodeE_\text{errcode}

对某一组 API,可以观测两件事:

  1. 错误结构多样性

    • 不同接口在错误时返回的 payload 形状:

      • {code, message, details}
      • {error: string}
      • 直接文本 / HTML;
      • 甚至 200 + {success: false, ...}
    • 对这些“错误 payload 形状”的分布求熵,记为 EerrE_\text{err}

  2. 错误码多样性

    • 所有错误码(HTTP status + 业务错误码)的分布;
    • 如果一直在一小撮规范内打转,熵就低;
    • 如果错误码四散,很多只出现一次,熵就高。
    • 这个分布的熵记为 EerrcodeE_\text{errcode}

6.5.2 返回格式和边界行为:EresponseE_\text{response}

类似地可以看:

  • 返回结构(schema)的多样性;
  • 同类边界情况(比如没数据、权限不足、参数缺失)下,返回模式的分裂程度。

可以构造一个“响应形状熵” EresponseE_\text{response},综合不同接口在同一类场景下 schema 的一致性。

把这些揉在一起,我会定义行为熵指数:

Ebeh=ν1Eerrν2Eerrcodeν3EresponseE_\text{beh} = \nu_1 E_\text{err} \nu_2 E_\text{errcode} \nu_3 E_\text{response}

行为熵越高,说明:

对调用方来说,这套系统的“接口宇宙”越碎片化,越难在脑子里形成一个统一的 mental model。


6.6 如何收敛成一个可以上 dashboard 的“熵面板”?

到这一步,已经有一堆 HHEE 了。实际落地时,我不会让团队面对十几个指标,而是收敛成:

“几条主指标 + 一张热力图”。

一个可能的收敛方式是:

6.6.1 三个总体指数

  1. 结构熵指数 EstructE_\text{struct}

    • 来自:角色依赖熵 + 度分布熵 + SCC 熵 + 随机游走熵;
    • 反映分层是否干净、依赖图是否接近随机图。
  2. 语义熵指数 EsemE_\text{sem}

    • 来自:命名熵 + 状态机熵;
    • 反映业务概念和状态是否统一、是否存在单一真相。
  3. 演化 + 行为熵指数 Eevo+behE_\text{evo+beh}

    • 来自:演化熵 + 接口 / 错误模型熵;
    • 反映演化轨迹是否连贯、接口行为是否一致、可预测。

这三个数字不需要特别“绝对值有含义”,更重要的是:

  • 定义稳定;
  • 趋势可靠;
  • 和团队的体感高度相关。

6.6.2 一张“熵热力图”

除此之外,我会配一张按模块 / 子系统聚合的热力图:

  • 横轴:模块 / bounded context / 子系统;
  • 纵轴:结构 / 语义 / 行为几条熵轴;
  • 颜色:该模块在这个维度上的相对熵水平(比如 0–100 归一化)。

这样可以一眼看出:

  • 哪些模块结构熵特别高(依赖乱、循环多);
  • 哪些模块语义熵特别高(命名分裂、状态机分裂);
  • 哪些模块行为熵特别高(错误模型乱、返回格式乱)。

这张图,在规划 refactor / tech debt 偿还时非常好用——它直接告诉你:先从哪里下手最划算。

6.6.3 真正的用法:看“趋势”和“热点”,不要执着于精度

最后强调一句:

这些“熵指标”,本质上是健康度信号,不是要在数学上复现热力学。

我更在意的是:

  • 这个季度 vs 上个季度,结构熵是上去了还是下来了?
  • 上一次大规模 refactor 之后,语义熵有没有真正下降?
  • 某几个模块在最近半年熵是否一直在爬高?
  • 哪些地方应该优先被纳入“熵减计划”?

只要指标设计得足够稳定、和体感有对应关系,它就有价值。


这一章到这里,基本把“怎么量熵”讲清楚了:

  • 信息论提供了一个概念框架;
  • 工程上,我把它拆成结构 / 语义 / 演化 / 行为几个轴,给出了一套可算的 proxy;
  • 最后收敛成“几条指数 + 一张熵热力图”的面板,用来观测趋势、标记高熵区域,为后面的“压熵动作”提供依据。

下一步,就是结合这些信号,去看:

在典型的 vibe 项目里,哪些具体的“红灯”会告诉我们——“如果现在不做点什么,未来维护会非常痛?”


七、典型 vibe 项目里,哪些信号在提醒“未来维护会很痛”?

前面几章我们一直在从“熵轴”的角度讲概念:

  • 结构熵:分层 / 依赖 / 演化;
  • 语义熵:概念 / 状态 / 命名;
  • 行为熵:API / 错误 / 边界行为;
  • 认知熵:所有权 / 需求 / 规格;
  • 风格熵作为噪声放大器。

这一章,我们换成诊断视角

“如果我现在有一个典型的 vibe 项目,有哪些肉眼可见的信号在告诉我:—— 再这么玩下去,未来维护会非常痛?”

我先给一个快速自查表,然后按维度展开解释。


7.1 快速自查表:10 个红灯信号

可以把下面这张表当成一个 “5 分钟体检”:

维度信号对应主要熵轴典型后果
代码大量超长函数 / 超长文件结构熵 ↑任意改动都牵一大片,重构风险巨大
代码any / 动态类型 / map<string, any> 滥用语义熵 ↑,行为熵 ↑类型语义丢失,边界行为不可预测
代码明显重复逻辑一再出现(实现不同但语义类似)语义熵 ↑,结构熵 ↑同一需求 N 种实现,修 bug 要改一堆地方
代码TODO / FIXME 满天飞,“未处理边界情况”的注释遍地行为熵 ↑边角行为靠运气,线上才是规范
结构大号循环依赖(强连通子图)很多结构熵 ↑无法局部重构,模块边界名存实亡
结构util / common / helpers 目录疯狂膨胀,几乎所有模块都依赖结构熵 ↑,语义熵 ↑语义下沉到“万能工具箱”,任何地方都可能藏逻辑
行为同类错误在不同接口上用完全不同的返回格式 / 错误码行为熵 ↑调用方逻辑爆炸,故障分析困难
测试 / 流程测试覆盖率低,且几乎只测 happy path行为熵 ↑,认知熵 ↑没人知道系统面对极端输入会如何表现
流程PR 动辄上千行,频繁 “重写一大片”;Review 主要看能不能跑结构熵 ↑,演化熵 ↑演化轨迹变成一堆“大爆炸”,难以追踪设计意图
流程 / 认知没有稳定的 prompt 模板、架构约束文档和 glossary,每个人都 freestyle 和模型说话语义熵 ↑,认知熵 ↑约束本身高熵,模型每次在不同“宇宙规则”下写代码

如果你勾中了其中一半以上,而且这些问题长期存在 / 被忽略,那基本可以判断:

这个项目已经在向“可运行但不可演化”的高熵沼泽滑行。

下面按维度细化一下这些信号背后的含义。


7.2 代码层面:看“局部复杂度”和“语义碎片化”

7.2.1 超长函数 / 超长文件大量出现

信号:

  • 函数动辄几百行,文件动辄上千行;
  • 同一个函数里兼顾了:参数校验;业务决策;DB 读写;API 组装;日志 / metrics。

对应熵轴:

  • 结构熵 ↑(局部结构塌陷成“大团块”);
  • 风格熵放大(不同风格混在同一个块里)。

后果:

  • 任意小改动都变成“在一坨屎山里找位置”;
  • 重构成本畏惧指数上升,大家更倾向于继续往里堆逻辑;
  • 久而久之,这块地方变成“没人敢动的神圣区域”。

7.2.2 动态类型和 “万能容器” 滥用

信号:

  • TypeScript 里到处是 anyunknown
  • Python 里类型标注形同虚设;
  • 频繁出现 map<string, any>Dict[str, Any]Map<string, object> 这种容器;
  • 大部分数据结构缺乏明确 schema,只在局部用“约定俗成”的字段。

对应熵轴:

  • 语义熵 ↑(类型不再表达稳定语义);
  • 行为熵 ↑(边界条件和数据不变量只能在运行时才知道)。

后果:

  • 静态分析优势全部丢失,工具很难帮你做熵减;
  • “这个字段在什么情况下存在 / 是什么类型”全靠人肉记忆和调试;
  • 任意新增/修改字段都有很大“破坏隐含约束”的概率。

7.2.3 可通过 embedding / AST 一眼发现的大量重复逻辑

信号:

用简单的 AST / embedding 搜索,就能找到:

  • 逻辑类似的小函数 N 份;
  • 结构几乎一样,只改了两个字段名的 handler;
  • 很多“复制粘贴再改两行”的代码片段。

对应熵轴:

  • 语义熵 ↑(同一语义对应多种实现);
  • 结构熵 ↑(没有收敛到 canonical 实现或抽象);
  • 演化熵 ↑(每个 copy 的演化轨迹独立漂移)。

后果:

  • 修一个 bug,要在所有类似 copy 里找一圈;
  • 新人难以判断哪个才是“正统实现”,哪个是历史遗留;
  • 想抽象 / 标准化时,成本已经远超一开始集中设计的代价。

7.2.4 TODO / FIXME 满天飞,尤其是“未处理边界情况”的注释

信号:

代码里到处是:

  • // TODO: 这里没有处理所有边界情况
  • // FIXME: 临时实现
  • // HACK: 先这么写能跑就行
  • 这类标记长期存在,没有被纳入任何计划。

对应熵轴:

  • 行为熵 ↑(边界行为定义不清、处理不一致);
  • 认知熵 ↑(没人知道“这些坑什么时候会踩到”)。

后果:

  • 线上行为实质上由“运气 + 输入分布”决定;
  • 某些 TODO 成为永恒 TODO,大家习惯性忽略;
  • 想系统性补边界时,已经无法分辨哪些 TODO 还 relevant。

7.3 结构层面:看“依赖图”和“垃圾场”

7.3.1 大号强连通子图(循环依赖)很多

信号:

做一张依赖图或跑 SCC 分析,发现:

  • 大量节点被卷入巨型 SCC;
  • Service A 调 Service B,B 调 C,C 又调回 A;
  • 不同模块间互相引用,几乎没有明确“谁在上游”。

对应熵轴:

  • 结构熵 ↑(图越来越像随机图);
  • 演化熵 ↑(任何改动都可能在 SCC 内产生连锁反应)。

后果:

  • 重构变成拆炸弹:你很难找到“小而局部”的改动单位;
  • 模块边界失去意义,“拆模块”退化成“在同一坨逻辑上人为画线”;
  • 设计讨论中,没人能说清楚“这块到底属于谁”。

7.3.2 util / common / helpers 等目录体积膨胀,依赖关系呈“黑洞态”

信号:

有一两个 util/common 目录:

  • 文件数爆炸;
  • 既被所有模块依赖,也反过来引用各种业务逻辑;
  • 任何新逻辑找不到地方放时,默认丢到这里。

对应熵轴:

  • 结构熵 ↑(从“底层库”演变成“横跨所有层的垃圾场”);
  • 语义熵 ↑(本应有明确业务语义的逻辑,被埋在 util 里);
  • 认知熵 ↑(任何人进 util 都不知道会看到什么)。

后果:

  • util 目录成为“高熵奇点”:所有结构和语义纪律到了这里都失效;
  • 任何试图“按领域拆模块”的努力都会被 util 偷偷绕过去;
  • 想清理时,不敢删、不敢动、不知道影响面,只能继续堆。

7.3.3 不同模块对错误处理、返回格式采用完全不同约定

信号:

  • 在同一服务 / 仓库里:

    • 有的模块对错误用异常;
    • 有的用 Result<T, E>
    • 有的用 null / undefined
  • API 返回格式:

    • 有的用统一 envelope {code, message, data}
    • 有的直接返回数据结构;
    • 有的连错误时的 schema 都不固定。

对应熵轴:

  • 行为熵 ↑(调用者面对的行为宇宙高度碎片);
  • 语义熵 ↑(错误类型和语义的统一建模失败);
  • 风格熵 放大。

后果:

  • 调用方不得不写大量 adhoc 分支;
  • 统一监控 / tracing / 错误聚合变得困难;
  • 错误链路分析时,你要不断在各种格式之间 mental parse。

7.4 工具 / 流程层面:看“工程节奏”和“反馈闭环”

7.4.1 测试覆盖率低,且大多只覆盖 happy path

信号:

  • 测试覆盖率长期处于“看不顺眼但大家习惯了”的水平;

  • 少量测试集中于:

    • 典型输入;
    • 成功路径;
    • demo 级用例;
  • 对边界条件、错误情况、并发场景缺乏系统性测试。

对应熵轴:

  • 行为熵 ↑(运行时行为基本靠猜 / 靠线上观察);
  • 认知熵 ↑(团队对“系统真正行为”的共同理解缺失)。

后果:

  • 每次改动都像在黑箱里摇骰子:检查完 happy path 就只能“上环境看运气”;
  • 无法用测试作为“压熵工具”:你不知道 refactor 后行为是否真保持不变;
  • 回归成本高,没人愿意做大规模结构调整。

7.4.2 PR 动辄上千行,混合 feature + refactor + format

信号:

  • PR 大小极不稳定,经常出现:

    • 几百上千行的改动;
    • 同时包含新功能 + 重构 + 格式化 + 随手顺便“修点别的东西”;
  • Review 文化偏向:

    • “先看能不能跑”;
    • 很少讨论结构 / 语义 / 行为一致性。

对应熵轴:

  • 结构熵 ↑,演化熵 ↑(演化单位过大,轨迹模糊);
  • 认知熵 ↑(很难从历史中复盘清楚“这次到底改了什么、为什么改”)。

后果:

  • 任何一次 PR 都有潜在的“系统性扰动”,熵猛涨但没人有空仔细看;
  • 事后排查问题时,很难找到“最小责任改动”;
  • 重构和功能开发纠缠在一起,不利于有意识地压熵。

7.4.3 没有固定的 prompt 模板和架构约束文档,每个人都 freestyle 和模型说话

信号:

  • 和模型交互完全靠个人习惯:

    • 有人习惯长篇大论;
    • 有人只给“写个 XX 功能”;
    • 有人会详细列约束,有人完全不提;
  • 项目没有统一的:

    • prompt 模板;
    • 仓库“宪法”(架构规则、错误模型、日志模型等);
    • 供模型参考的 glossary / 设计文档。

对应熵轴:

  • 语义熵 ↑(不同人对同一概念的表达和约束不一致);
  • 结构熵 ↑(对“分层 / 依赖规则”的强调程度随人而变);
  • 认知熵 ↑(系统当前到底在什么约束下演化,没人说得清)。

后果:

  • 同一个模型,对不同人、不同任务输出风格大幅波动;
  • 你没法对 AI 的行为建立稳定预期,也无法有系统地提升它的“贴合度”;
  • 项目的“规则层”变成高熵的口语共识,而不是低熵的正式契约。

7.5 认知 / 组织层面:看“谁懂什么”和“需求长在哪儿”

7.5.1 模块没有明确 owner,“这块是 AI 写的”成了默认回答

信号:

  • 问“这个模块谁最熟?”时,典型回答是:

    • “当时是我跟模型一起搞的,但我现在也说不太清楚”;
    • “这个是之前某某做的,现在人不在了”;
    • “就是模型写的,我们后来只修了几个 bug”。
  • Oncall / 事故处理时,大家围着某块代码看,但没人敢拍板“这是对 / 这是错”。

对应熵轴:

  • 认知熵 ↑(知识分布无序,责任边界模糊);
  • 结构 / 语义 / 行为上的高熵缺乏“长期维护者”。

后果:

  • 任意非 trivial 改动都需要先“考古式阅读”,极其耗人;
  • 事故复盘难以形成可执行的改进措施,因为没人对整体负责;
  • 工程文化容易滑向“出了问题怪 AI”,而不是正视设计和流程上的欠账。

7.5.2 需求和规格主要存在于聊天记录和脑子里

信号:

  • 需求变更主要通过 IM / 语音 / 会议口头达成,没有系统地沉淀;

  • 很多行为是“当时和模型互动时顺手决定的”,没有回写到任何正式规格中;

  • 新人问“为什么这里这样设计?”时,常见回答是:

    • “当时就是这么说的”;
    • “好像是之前某个需求的临时处理”。

对应熵轴:

  • 认知熵 ↑(团队对“系统应该做什么”的共识高度碎片);
  • 行为熵 ↑(实际行为受制于一堆历史临时决定)。

后果:

  • 指责“代码错了”之前,你得先花大量时间确定“需求到底是什么”;
  • 不同人脑子里的“系统应该做什么”版本不一致,争论焦点经常跑偏;
  • 想重构 / 重新建模时,发现连“地基(需求)”都不稳定。

7.6 小结:这些信号叠加起来,说明什么?

如果只出现一两个信号,可能还只是“正常工程噪声”;

但当你看到:

  • 大量超长函数 + util 黑洞 + 循环依赖;
  • 命名和状态高度碎片化;
  • 错误模型和返回格式到处不同;
  • 测试只测 happy path;
  • PR 动辄上千行;
  • 没有统一的 prompt 模板 / 架构约束 / glossary;
  • 模块 owner 模糊,需求主要存在于聊天里……

那从前几章的语言来说,就是:

结构熵、语义熵、行为熵、认知熵几条轴,同时在往高位跑,而且没有稳定的“熵泵”和“熵预算”在控制它们。

我会下意识给出一个非常具体的判断:

“这个项目未来任何中等规模的需求,都将以极高心智成本 + 极高风险的方式落地。”

这一章的这些“红灯信号”可以直接当成检查表用:你可以按维度做一次自检;也可以在规划工程改造 / 引入 AI 工具时,把它当作 baseline;

后面(第八 / 第九章),我们会从模型训练工具设计的角度,进一步问一句:

在一个本性高熵的生成过程中,能不能把“降熵”写进模型目标和系统设计里,而不是只靠工程师拿命顶?


八、从模型训练和工具设计的角度,怎么“压熵”?

前面几章更多站在工程使用者视角:

如何在 vibe coding 的高熵默认态之上,通过个人习惯、团队规则和工具,把系统拉回可演化区间。

这一章,我们把视角往下移一层:

如果你是做 coding model / IDE / agent / DevTool / 平台 的人,你手上的这套模型和工具,能做些什么来帮用户“压熵”?

我会分两块讲:

  • 从模型训练 / 推理流程的角度:让模型的默认偏好更低熵,而不是只追求“当下看起来合理”;
  • 从 AI coding 工具 / 系统设计角度:把“熵管理”变成一等公民的产品能力,而不是外挂的脚本。

8.1 从模型训练角度:让模型的默认偏好更“低熵”

大部分 coding model 今天还是在优化:

写出一段能跑、看起来正常的代码”。

如果我们承认“高熵是 vibe coding 的物理属性”,那训练侧能做的事情大致是:

在“功能正确”的前提下,把模型的偏好分布往“低熵区域”微调一点。

这里的“低熵区域”不等于“唯一正确答案”,而是:

  • 结构上更收敛(依赖图不乱飞);
  • 语义上更统一(命名 / 状态 / 错误模型更一致);
  • 行为上更可预测(边界和错误处理更标准);
  • 对同一语义,不再发散出太多彼此不兼容的写法。

下面是几个我觉得实践上可行、而且和前面熵轴高度对齐的方向。


8.1.1 多目标对齐:不只看“能跑”,还要看“会不会制造高熵结构”

现有的对齐 / RL 流程,大多在优化:

  • 编译 / 测试是否通过;
  • 任务是否完成;
  • 人类评分中的“有用 / 易懂 / 像人写”。

这里可以多加一层:

把一些“熵 proxy 指标”接到奖励里,让模型在功能正确的多个方案中,偏向那些结构 / 语义 / 行为更收敛的版本

这些 proxy 可以很工程化,比如:

结构侧

  • 新生成代码是否引入新的跨层依赖;
  • 是否增加了 util/common 的耦合度;
  • 是否打破了既有的架构规则(例如 Domain 依赖 Infra)。

语义侧

  • 是否重复造了轮子(已有函数 / 模块可以复用却没用);
  • 是否给已有概念起了全新的名字;
  • 是否引入了新的“状态枚举版本”。

行为侧

  • 是否遵守项目已有的错误模型 / 返回格式;
  • 是否在边界条件上引入了新的特殊处理路径。

这些东西本质上是:

  • 用静态分析 / 模式检测 / 小工具算出一套“熵罚分”;
  • 在 RL / 对齐阶段,把这套罚分接在 reward 的负号一侧。

不用追求指标绝对准确,只要它在大样本上有方向性

即便没法保证绝对“最优架构”,至少可以让模型对明显高熵的方案产生一点本能反感。


8.1.2 利用“重构对”数据:教模型什么叫“从高熵压回低熵”

今天 coding model 的数据,多数是“静态好代码”。但对降低熵这件事,有一类数据特别有价值:

“重构前 → 重构后”的代码对。

这种数据天生在教模型:

  • 什么叫“把耦合过高的模块拆开”;
  • 什么叫“抽象统一 / 去重”;
  • 什么叫“从混乱的错误处理收敛到统一模型”。

具体可以做的事情:

  • 构建 / 收集大规模的重构轨迹:

    • 从真实工程历史中挖出 refactor PR;
    • 或者人工 / 半自动生成一批“高熵版本 + 低熵版本”对。
  • 训练专门的 Refactorer 模型 / 模式

    • 输入:某块高熵代码(局部或模块级);
    • 输出:结构更清晰、命名更统一、依赖更干净的版本;
    • 并尽量保持行为不变。

这类模型可以:

  • 在训练时,帮主模型学“熵减操作”;
  • 在工具里,作为“持续熵泵”的主要执行者。

8.1.3 House-style / Repo-style Adapter:让模型“像这个家的人”

前面讲过:训练数据是“全球开源平均风格”,但真实项目往往有自己的“家族风格”和“结构骨骼”。从训练 /推理层面,一个很自然的做法是:

在基础模型上,再叠一层“house-style / repo-style adapter”。

大致可以这么玩:

对于大型、结构良好的代码库:

  • 用它们做 adapter 微调,

  • 让模型学会这家仓库特有的:

    • 命名模式;
    • 分层方式;
    • 错误模型;
    • 日志习惯;
    • 抽象套路。

推理时:

  • 针对某个用户的 repo 自动做“风格画像”;
  • 挑选 / 合成一个最接近的 adapter;
  • 或者干脆直接做 repo-specific adapter。

这对熵的影响是:

  • 风格轴:输出更统一,不再“全球随机风格”;
  • 结构和语义轴:更倾向沿用既有抽象,而不是另起炉灶。

简化理解:

基础模型提供“通用编程能力”,adapter 负责“你家里是这么干的”。


8.1.4 拆出 Planner / Coder / Reviewer 角色:把“写 + 降熵”拆开

前面讲工程实践时,我们说人类是通过“写 + 重构交替”来主动降熵的。在模型侧,其实也可以显式设计一个类似 pipeline,而不是“一个大模型从 0 到 1 全包”。

常见的拆法:

  • Planner(规划器)

    • 输入:需求 / 规格 / 上下文;
    • 输出:模块拆分、接口定义、数据结构 / 状态模型;
    • 重点为:结构熵 / 语义熵打基础。
  • Coder(实现者)

    • 输入:Planner 给的设计 + 相关代码片段;
    • 输出:具体实现;
    • 目标是:在给定结构 / 契约内填空,而不是自由发挥。
  • Reviewer / Refactorer(审查 / 熵减器)

    • 输入:新代码 + 仓库画像 + 架构规则;
    • 输出:改动建议 / 直接重构后的版本;
    • 负责控制:命名统一、依赖关系、重复度、高圈复杂度等。

这套拆分可以发生在:模型内部(多头 / 多 stage);或者系统层(多个调用链协作)。

它的关键点是:

不要指望一个“写代码模式”在一次 forward 里兼顾功能正确 + 结构优雅 + 全局熵减,而是明确有一个角色对“压熵”负责。

ps: 从第二版修正的时间点往回看,系统层的 Planner 已经越来越流行,比如 cursor、Claude code其实都已经实现了这些。


8.1.5 结构化解码 / 约束解码:把架构规则写进“可行域”

最后一个训练 / 推理侧的方向,是更激进一点的:

不只是“在 loss 里偏好低熵方案”,而是直接用 约束 / 结构化解码 把一部分高熵选项从搜索空间里砍掉。

比如:

  • 在生成 SQL / 配置 / API 定义时,使用语法约束(语法树级别的 decoder);
  • 在生成依赖关系敏感的代码时,禁止某些跨层调用模式;
  • 生成过程中实时查“即将调用的模块是否违反架构规则”。

这类东西本质上是在:

  • 结构轴上:把“非法依赖 / 不允许的调用路径”从一开始就 ban 掉;
  • 语义轴上:强制字段名 / 类型 / 状态取值只能来自既有 schema / glossary。

换句话说:

部分熵,不是靠训练慢慢拉低,而是靠“结构化的解码器 / 约束器”直接剪掉。


8.2 从 AI coding 工具设计角度:把“熵管理”做成产品能力

前面是“模型本身能做什么”;这部分是“围绕模型,我们能把哪些东西产品化,让工程团队拿来就用”。大致可以看成是:

把第 5–7 章里讲的“个人 / 团队 / 工具层实践”,压缩成一套 AI-native、可配置、可开关的“熵管理能力”


8.2.1 契约先行:先生成 / 维护设计,再允许写实现

第一个我非常看重的设计是:

把“设计 / 契约”从文档,升级为机器可读的一等公民,并强制走在实现前面。

一个典型的流程:

  1. 用户提出需求;

  2. 工具引导先生成:

    • 模块列表;
    • 接口定义(request/response 类型、错误模型);
    • 领域模型 / 状态机(至少是高层枚举 / 状态图);
  3. 这套设计落地成:

    • schema 文件;
    • interface / type 定义;
    • 架构规则配置;
  4. 之后的所有代码生成 / 修改,都必须在这套契约下进行

    • 新代码如果想引入新状态 / 新错误,需要先改契约;
    • 不允许出现“只改实现,不改契约”的飘逸操作。

这对熵的作用是很直接的:

  • 在语义轴上:

    • 领域模型和状态机有了“单一真相”;
    • 模型被迫围绕现有契约工作,而不是随写随定。
  • 在结构轴上:

    • 模块 / 层次先被框定,再填实现,减少“一写就穿层”的情况。

本质上就是:

让“规格 / 设计”不再只是 wiki 里的一堆字,而是系统里的“低熵内核”。


8.2.2 把 repo 画像塞进系统 prompt:让工具尊重“在地风格”

在第 5 章我们已经提过“仓库画像器”,在工具设计里,这一步可以做得非常系统化:

  1. AI coding 工具接入某个 repo 时,先跑一轮扫描:

    • 命名风格(snake / camel / prefix / suffix 等);
    • 领域词汇表(用户 / 订单 / 组织等词汇);
    • 分层 / 目录结构(UI / Domain / Infra 如何划分);
    • 错误模型和日志风格;
    • 常用 helper / util 以及它们的用途。
  2. 自动生成一份“仓库宪法”,包括:

    • 建议的默认命名模式;
    • 推荐 / 禁止的依赖方向;
    • 统一错误 / 日志模型;
    • 可复用的工具 / 抽象列表。
  3. 在每一次调用模型时:

    • 把这份宪法作为系统 prompt / adapter 的一部分;
    • 并且在生成后用静态分析 / rule engine 检查是否违反。

这会让工具在:

  • 风格轴上:输出更贴合“这个项目自己的一致性”;
  • 语义轴上:更倾向沿用既有命名和抽象;
  • 结构轴上:更少“凭空创造新层次”。

相当于告诉模型:

“你不是在抽象的互联网写代码,你是在一个有传统、有规矩的家里打工。”


8.2.3 强制集成 formatter / linter / type checker / tests:生成闭环

一个理想的 AI coding 工具,不应该只是“把模型输出贴到编辑器里”,而应该内置一个生成闭环

  1. 模型生成 patch;

  2. 工具自动跑:

    • 格式化(统一风格,免得风格熵乱飞);
    • lint(包括自定义架构规则、依赖规则、命名规则);
    • 类型检查(把动态类型“偷懒”揪出来);
    • 相关测试(至少跑受影响模块/路径的测试)。
  3. 如果任何一步不通过:

    • 把错误 / 违反规则的地方反馈给模型;
    • 让模型自己修到通过为止;
  4. 最终呈现给人类的是:

    • 已经通过基本规则和约束收敛过一轮的版本。

这等于在工具层面,帮用户把“熵减的一部分”自动化掉:

  • 很多低级的结构 / 风格熵,在这一步就被压掉;
  • 人类主要关注“业务语义”和“架构级的抽象”。

8.2.4 内置去重 / 复用引擎:先搜再生,减少语义熵

这一点我觉得现在很多工具还做得不够:

在生成之前,先把“复用”和“去重”当成第一选择,而不是默认写一份新的。

工具可以做的事包括:

  • 用户提新需求时,先在 repo 里查:

    • 有没有已有函数 / 类已经覆盖 80% 行为;
    • 有没有类似模式的实现可以抽象;
  • 然后给模型的指令是:

    • 尽量通过调用 / 组合已有 abstractions 来实现;
    • 只有在确实没有复用空间时,才生成全新实现。

这对语义熵的影响非常明显:

  • 避免“同一语义多种实现”;
  • 促使模型把“行为差异”压缩到少数地方,而不是到处复制粘贴小变体。

直白点说:

先问一句“我们家有没有类似东西”,再决定“要不要再生一个”。


8.2.5 按区域控制“创意度”:核心低熵,边缘高熵

最后一个很实用但常被忽略的设计是:

不要对整个代码库用同一套采样 / 创意策略,而是 按区域调“创意度”

比如:

  • 核心领域模型 / 安全敏感 / 合规关键路径

    • 使用接近 greedy 的解码;
    • 更严格的规则 / linter;
    • 更高密度的测试;
    • 更多“拒绝生成”而不是乱猜。
  • UI / 文案 / 动效 / demo / 实验区

    • 可以允许更高 temperature;
    • 更多样化的实现;
    • 允许写一些“临时实验性”东西。

这背后其实就是第 5 章说的分区策略,在工具层面的实现版本:

  • 在“低熵内核”区域,工具默认帮你挡掉很多高熵尝试;
  • 在“高熵外壳”区域,工具允许你尽情 vibe,快试快废。

用一句话概括就是:

该严肃的地方别 vibe,该玩耍的地方随便 vibe。


8.3 小结:如果我是做模型 / 工具的人,我会怎么把“降熵”写进 roadmap?

这一章可以总结成一个很工程化的问题:

“如果我今天在做 coding model / IDE / agent / DevTool,想要我的产品在‘写得快’之外,真的帮用户 控制长期熵,我 roadmap 上应该优先考虑哪些能力?”

我会把前面这些内容压缩成一个 checklist:

训练 / 模型侧

  • 在对齐 / RL 阶段,把结构 / 语义 / 行为相关的熵 proxy 接入 reward;
  • 利用“重构前后”数据,训练专门的 Refactorer / Reviewer 模式;
  • 做 house-style / repo-style adapter,让模型偏好“像这个家的人”;
  • 在系统 / 推理层拆出 Planner / Coder / Reviewer 角色;
  • 在关键场景用结构化 / 约束解码,把一部分高熵方案从一开始就剪掉。

工具 / 系统侧

  • 契约先行:先生成 / 维护 machine-readable 的设计 / 契约,再生成实现;
  • 接入 repo 时自动做“风格 / 结构 / 语义画像”,把宪法固定下来并喂给模型;
  • 把 formatter / linter / type checker / tests 串成生成闭环,自动做一轮熵减;
  • 内置去重 / 复用引擎:先搜再生,鼓励复用,减少语义碎片;
  • 按区域控制创意度:核心区域低熵严控,边缘区域允许高熵试验。

这些东西加在一起,才构成了一个真正 AI-native、带“熵管理内核”的开发栈

第九章会在这个基础上,站到更偏“模型 / 系统设计 / 研究”的视角,用更形式化的语言去重述同一套东西——把“降熵”不只当作工程实践,而当作一个可以明确建模、可以被优化、可以被讨论的目标。


九、进阶版:把“降熵”写进模型目标和系统设计

前面第八章更多在讲:

“如果我是做 coding model / DevTool / agent 的工程师 / PM,roadmap 上可以加哪些 降熵能力?”

这一章我们再往下深入,从一个更“模型 / 系统设计 / 研究”的视角,把同一件事重新表成一个更抽象的问题:

在一个本性高熵的生成过程中,怎么把“熵管理”写进目标函数、建模假设、系统架构?

可以粗暴地理解为:

  • 第八章 = 工程实践版的“降熵 checklist”;
  • 第九章 = 把这份 checklist 提升为一组可以明确讨论、优化、发表的设计问题

9.1 把 vibe coding 看成一个“带熵约束的生成过程”

先换一个视角看 vibe coding:

  • 状态:代码库GtG_t(graph / AST / 文件集合),包含结构 / 命名 / 依赖 / 行为等信息;
  • 输入:当前需求 StS_t(可能只是自然语言 + 少量契约);
  • 模型:根据 StS_t 和 G_t,生成一段 patch PtP_t,把代码库从 GtG_t 变成 Gt+1G_{t+1}

如果只看“能不能跑”,我们在优化的是:

对每一步 patch,让 “功能正确 / 任务完成” 的损失(TaskLoss)尽量低。

但从前几章的讨论你可以看到:

  • 每一步 patch 其实都在改变结构熵 / 语义熵 / 行为熵 / 演化熵
  • 如果完全不管这些轴的变化,累积出来的 GTG_T 大概率是一块高熵沼泽。

理论上更理想的 framing 是:

我们每一步不是只在意 “TaskLoss\text{TaskLoss}”而是在意 “TaskLoss + 熵代价”

抽象一点写,就是:

  • 当前状态:(Gt,St)(G_t, S_t)
  • 决策(模型输出):PtP_t
  • 目标:在整个演化过程中,最小化TaskLoss(GT)+λtΔE(GtGt+1)\text{TaskLoss}(G_T) + \lambda \cdot \sum_{t} \Delta E(G_t \to G_{t+1})这里 E()E(\cdot) 是我们在第 6 章里讨论过的“熵指标”,ΔE\Delta E 是某种“熵变化”。

换成白话就是:

不只是要“把活干完”,还要对“每一步在结构 / 语义 / 行为轴上制造了多少无序度”负责。

当然,现实里我们不会真的去解这个优化问题,但这个 framing 有几个好处:

  1. 它把第 6 章的那些熵指标,变成了显式的正则项 / 代价项,可以讨论“λ\lambda”多大合适;
  2. 它把第 8 章工程实践中那些“熵泵 / 规则 / 约束”,变成了对可行解空间和代价函数的塑形手段
  3. 它让“降熵”不再只是“工程师的审美 / 经验”,而是可以进入 loss / reward 的一类信号。

后面几节可以看成是:在不同层级(训练、系统、agent),我们如何近似实现上面的理想目标


9.2 在训练目标里显式引入“熵相关信号”

如果沿用上一段的抽象,一个自然的想法是:

把一些“结构 / 语义 / 行为熵的 proxy”,作为附加信号,进入训练 / 对齐阶段。

不是严格意义上的 Shannon entropy,而是一组我们在第 6 章里定义过的可计算指标:

  • 结构侧:依赖图的 role-deps 熵、SCC 分布、util 黑洞程度等;
  • 语义侧:命名熵、状态机熵;
  • 行为侧:错误模型多样性、返回格式多样性;
  • 演化侧:PR 粒度、改动模块分布、change type 熵……

在训练层面有几个常见的落地方式:

9.2.1 多目标 RL / 对齐:熵罚作为负 reward

场景:我们本来就有一条 RL / 对齐 pipeline,用于强化“任务完成 / 代码可执行 / 测试通过”。

可以做的事是:

  1. 在 roll-out 或离线样本上,额外跑一套熵评估器

    • 给 patch / 生成结果打出结构熵 / 语义熵 / 行为熵相关分;
    • 或者直接打一个“可维护性 / 可演化性”的合成得分。
  2. 把这些分数线性或非线性组合进 reward:

    • 功能正确 + 风格合理 → 高 reward;
    • 功能正确但引入高熵结构 / 命名混乱 / 行为不统一 → reward 折扣;
    • 功能不正确 → 非常低 reward。
  3. 在训练中让模型逐渐偏好那些:

    • 同样能完成任务,但在熵指标上更好看的样本。

这一步其实就是:

把“熵管理”从完全事后工程检查,提前到模型的行为偏好里。

9.2.2 训练“Refactorer / Reviewer”子模型:熵减作为学习目标

另一条线是专门训练:给一段高熵代码(结构/命名/依赖/行为混乱),产出一个更低熵的版本,同时尽量保持功能不变。

数据来源可以是:真实仓库历史中的重构 PR,人工构造的“高熵版本”(比如自动把好代码打乱命名、合并函数、引入 util 黑洞,再让模型学着修回来)。

这类模型的学习目标本身就是一个“熵减 operator”:

输入一个局部高熵状态,输出一个更低熵、同语义的状态。

之后它可以以几种方式被使用:

  • 作为大模型内部的一个“Refactor mode”;
  • 作为 agent 流程中的一个固定步骤(每次 patch 之后跑一轮熵减);
  • 作为人类开发者发起的“重构建议器”。

9.3 分层生成:把“设计 / 契约”当作 latent 层

在第 8 章,我们提了一个很工程向的点:

契约先行:先生成 / 维护设计文档,再生成实现。

在建模层面,可以把这看作一种分层生成(hierarchical generation)

  • 顶层 latent:设计 / 架构变量 ZZ(模块列表、依赖关系、接口、数据结构、状态机…);
  • 条件生成:给定 ZZ 和当前 repo,生成具体代码。

形式上就是:

  • Zp(Zspec,Gt)Z \sim p(Z \mid \text{spec}, G_t)
  • codep(codeZ,Gt)\text{code} \sim p(\text{code} \mid Z, G_t)

这里的关键点是:

  • 如果 ZZ 能捕获“低熵结构 / 统一语义 / 标准行为”的骨架;
  • 那么 code 层即使有一些噪声(局部风格 / 小差异),整体熵也会被压在 ZZ 的约束之内

这在理论上很接近:

  • 把“良好架构 / 清晰领域模型”当作一种 结构化先验 / latent 表达

  • 用最小描述长度MDLMDL的思路:

    • 先用尽量简短的 ZZ 描述系统结构和语义;
    • 再用局部 code patch 补完实现细节。

开放问题包括:

  • 怎么让模型学到“有用的 ZZ”而不是 trivially encode 所有代码?
  • 怎么设计 ZZ 的空间,让它容易解读 / 编辑 / 审查,而不是变成不可读 embedding?
  • 怎么在训练里鼓励 ZZ 的表达低熵、可重用,而不是“为每个小需求定制一份新架构”?

但方向上,这是把第 5 / 8 章的“契约先行 + 低熵内核”正式化的一个路子。


9.4 把“仓库宪法”当作结构化先验:从 prompt 到 param / prior

第 8 章里,我们把“repo 画像 + 仓库宪法”主要放在工具 / prompt 层来讲。从模型视角,可以把这看作是在引入一种“条件先验”:

“在这个仓库里,结构 / 命名 / 错误模型 / 日志风格 / 领域词汇都有一套相对稳定的先验分布。”

数据层面可以有几种实现方式:

  1. Adapter / LoRA 风格

    • 针对某个仓库 / 某类仓库,训练一个小 adapter;
    • 推理时加载对应 adapter,让模型在该 repo 上输出更低熵、贴合“家族风格”的代码。
  2. 条件编码器

    • 用一个 encoder 把“仓库宪法”(schema、规则、样例代码)编码成某种上下文向量;
    • 主模型在生成时把这个向量当作 condition;
    • 本质上是在学一个“per-repo prior”。

理论上,你可以把这个 prior 理解成:

  • 结构轴上的:“哪些依赖是正常的,哪些是禁止的”;
  • 语义轴上的:“一个概念应该叫什么名字”、“状态应该有哪些值”;
  • 行为轴上的:“错误应该怎么包装”、“日志应该怎么打”。

相比纯 prompt,这种 param-level 的先验可以:

  • 更稳定、更可压缩;
  • 在训练时就注入偏好,而不只是推理时临时约束。

9.5 把熵监控和 agent / 搜索结合起来:不是“一次性生成”,而是“带成本的多步搜索”

在第 3 章我们说过:vibe coding 本质是一个“局部聪明、全局高熵的 patch 流程”。如果换一个系统视角来看:你可以把 AI coding agent 看作在代码状态空间上的一种 多步搜索 / 策略优化。

  • 节点:不同版本的代码库 GtG_t
  • 边:一组 patch / refactor 操作;
  • 目标:在限定步数 / 预算内,找到一个既完成任务、又在熵指标上可接受的状态。

在这个 framing 里,熵管理可以融入到:

  • 价值函数 / 评估函数 里:一个状态的价值除了“任务达成度”,还要考虑“结构 / 语义 / 行为熵”;
  • 搜索策略 里:避免走那些会把熵急剧拉高的路径,或在高熵区域主动插入“熵减步骤”(Refactorer 调用)。

这打开了一些有趣的研究问题:

  1. 如何定义一个既便宜又有用的“局部熵评估器”?

    • 首先不可能每一步都全仓库扫描;
    • 需要局部、近似、增量的评估方法。
  2. 如何在 search / agent 框架里引入“熵预算”?

    • 比如:允许在短期内局部熵升高,但要求在若干步内偿还;
    • 或者为不同区域设置不同预算(低熵内核 vs 高熵外壳)。
  3. 如何让 agent 学到“先 refactor 再加功能”的策略?

    • 而不是永远“先把需求硬塞进去再说”。

这本质上是在把我们在第 5 章说的“人类的写 + 重构交替策略”,迁移到 agent / search 级别的策略学习里。


9.6 “熵管理”作为模型 / 系统设计中的一类一等约束

如果往更 meta 一点抽象,可以把全文的结构总结成一个三层框架:

  1. 第一层:codegen 作为条件生成问题

    • 传统视角:给定 spec + repo,生成代码片段,让它能跑、对、有用;
    • 我们可以引入额外视角:生成过程在结构 / 语义 / 行为 / 演化等轴上的熵不是免费的,它有代价。
  2. 第二层:熵作为正则 / 约束 / 先验

    • 在训练目标中:把熵 proxy 接入 loss / reward,训练熵减子模型(Refactorer / Reviewer)。
    • 在模型结构中:引入 latent 设计层 ZZ,用 repo prior / adapter 把“仓库宪法”写进参数。
    • 在推理 / agent 流程中:做 constrained decoding,把熵代价写进 search / policy 的目标。
  3. 第三层:熵管理能力,被产品化为工具 / 框架 / 角色

    • 对团队:有“架构牧羊人 / 熵管理工程师”这种角色;
    • 对工具:有“熵面板 + 熵热力图 + 常驻熵泵”;
    • 对框架:有专门为“AI-first”设计的低熵框架。

这三个层级不是三个世界,而是一条链:前两层给出一个可以严肃讨论和优化的理论框架,第三层是把这个框架落在组织 / 工具 / 工程实践上的样子


9.7 开放问题

最后留几个我觉得有意思、也确实没完全解开的问题——如果你是做模型 / 工具 / 研究的,这些地方可以当成“挖坑点”:

  1. 如何设计既可学习、又可被人类编辑的“架构 latent ZZ”?

    完全分布式的向量 latent 难以解释,完全手写 YAML / JSON 又过于刚性,中间有没有一种既易学、又可人类微调的形式(比如图 + schema + 约束)?

  2. 如何在不引入巨大训练成本的前提下,把“熵 proxy”接入大规模训练?

    全仓库级静态分析 / 熵评估很贵,有没有“增量 / 局部 / 近似”的指标,既便宜又方向正确?

  3. 如何评价“模型做了一次好的熵减”?

    除了结构 / 语义指标下降,还要考虑:功能是否保持,未来演化是否更容易,有没有办法用线上数据(比如后续 bug / PR 分布)反向验证某次 refactor 的价值?

  4. 如何把“熵预算”真正写进工程流程?

    不是只在仪表盘上看数字,而是:在 PR / 迭代计划 / SLA 里,把熵指标当成一类约束,工具 / agent 如何在预算内自主决策“什么时候该还债?”

  5. 在多模型 / 多工具 / 多团队协作的环境中,如何定义“全局熵”?

    单仓库内还好说,一旦跨服务 / 跨语言 / 跨组织,熵的定义需要更抽象的一层(业务图谱 / 事件流 / 合约层),这又会逼着我们往“全局知识图谱 / 全局行为模型”的方向走。

这些问题没有标准答案,但有一个共同点:

它们都不是在问“怎么让模型写代码更快”,而是在问“在一个默认高熵的生成世界里,怎么让系统在 3 年、5 年之后,仍然是可以演化的?”

如果前八章是在描述问题、分析原因、给工程实践,那第九章的角色,就是把同一件事翻译成:

一组可以被建模、被优化、被争论、甚至被投稿的设计空间。


总结一下这一章的立场:

我们不再把“熵管理”当作一个“工程师自己辛苦一点多 refactor”的事情,而是认为:

  • 它可以写进 loss;
  • 写进模型结构;
  • 写进系统和 agent 的目标函数;
  • 写进产品能力和组织角色里。

这样 vibe coding 才有可能从一个“短期爽、长期沼泽”的范式,变成一个 “高自动化、可持续演化、有熵预算的工程体系”


十、结语:活在高熵代码的世界里

写到这里,其实可以把全文压缩成一句话:

vibe coding 把“写代码”这件事推向了一个本性高熵的世界,而我们真正要学会的,不是如何否定它,而是如何把“熵管理”变成新的工程能力。

前面几章做的事情,大致可以分成三步。


10.1 第一步:承认“高熵”是 vibe coding 的物理属性

前 1–3 章在做一件事:

  • 把“代码熵”拆成结构 / 语义 / 行为 / 演化 / 认知几条轴;

  • 展示 vibe coding 如何在每一条轴上自然地推高无序度

    • 模型只在局部优化“看起来合理”,不是全局架构师;
    • prompt 本身是模糊、漂移的约束;
    • 生成是连续的局部 patch,而不是周期性的全局重构;
    • 训练数据本来就是“全球开源平均风格”的高熵混合物;
    • 多模型、多工具、多 agent 在没有统一协议时,自带“协议熵”。

这个视角有一个好处,我们不再把今天看到的那些乱象仅仅归咎于“工程师不自律”或者“工具还不够好”,而是接受一个更诚实的前提:

在 vibe coding 范式下,高熵不是异常,而是默认态。

如果不先承认这一点,后面所有“最佳实践”和“工具设计”都很容易流于空谈。


10.2 第二步:看清高熵会如何折腾项目、团队和生态

4–7 章其实是在回答一个问题:

“如果我们什么都不做,让系统沿着这条高熵轨迹自然演化,会发生什么?”

答案大致是:

  • 对单个项目:“写难”变成“维护难 / 演化难”,系统越来越像一块“能跑但没人敢动”的高熵沼泽。
  • 对团队:知识沉淀变成一团雾,所有权和责任边界模糊,事故分析时,大家更多在事后对齐认知而不是复盘设计。
  • 对系统可观测性:监控 / 日志 / tracing 逐渐变成“第二套源代码”,你读代码只是辅助,真正的行为模型藏在运行时数据里。
  • 对用人标准:单纯“会写代码”的价值下降,会设计低熵架构、在高熵代码堆里建立心智模型、会用规则和工具指挥 AI 写代码的人,价值上升。
  • 对生态 / 合规 / 商业:大量 AI 改写的 fork 拉高了开源生态层面的熵,在金融 / 医疗 / 基础设施这类领域,高熵代码被直接视为风险资产,维护成本和演化能力迟早会进入计价体系,“写得快但乱”会在经济上被惩罚。

这一部分的意思是:

如果你不主动做熵管理,高熵不会客气地停在“工程审美问题”这一层,它会最后变成非常具体的:人力成本、事故风险、商业议价能力。


10.3 第三步:把“熵管理”从个人习惯,一路抬到模型和系统设计

后面 5–9 章,则是沿着一条线往上搭东西:

个人层面:

  • 从 coder 变成 constraint designer;
  • 固定生成语法,限定作用域;
  • 把“写完就重构”变成默认动作;
  • 培养对“哪儿在变乱”的熵感知。

团队 / 项目层面:

  • 用分层架构和依赖规则给结构轴画边界;
  • 把 Glossary / 领域模型升级为“一等公民”;
  • 划清低熵内核和高熵外壳,在空间上分区管理熵。

工具层面:

  • 做 repo 画像,把“家族风格”和“结构骨骼”喂给模型;
  • 常驻重构 / 规范 bot,当作“熵泵”;
  • 用熵热力图把高熵区域点亮,让 refactor 有靶子;
  • 用一组可计算的“熵指标”,把原本模糊的“代码味道”变成 dashboard 上的数值。

模型 / DevTool / agent 设计层面(第 8、9 章):

  • 把熵的 proxy 指标接到训练的损失 / 奖励里,而不只对齐“能跑”“像人写”;
  • 利用“重构对”数据训练 Refactorer / Reviewer 子模型,显式学会熵减操作;
  • 通过 house-style / repo-style adapter,把“仓库宪法”变成条件先验;
  • 把契约 / 设计文档当成 latent 层,用分层生成减少实现层的自由度;
  • 在 agent / 搜索层引入熵成本和熵预算,不再把 codegen 看成“一步到位”,而是看成“带代价的多步决策过程”。

这条链路的核心态度是:

熵管理不应该只停留在“多写点文档、多 refactor 一下”这种人肉层面,它完全可以:

- 写进 loss 和 reward;

- 写进模型结构和解码器;

- 写进工具 / 框架 / 流程;

- 写进团队角色和商业契约。


10.4 vibe coding 不是“要不要用”,而是“怎样不被它反噬”

我不太想用“乐观 vs 悲观”的二分来收尾。对我来说,这篇文章更接近是:

站在一个“熵”的视角,诚实地描述 vibe coding 已经在发生的结构性变化,然后思考:在这条高熵默认轨迹上,我们还有多少主动空间?

我并不悲观——恰恰相反:

  • 我觉得“模型写代码、人管熵和抽象”这件事,是一个很自然的长期分工;
  • 我也觉得会诞生一代真正 AI-native、低熵友好的框架 / 工具 / 团队;
  • 只是这个过程中,谁先把“熵管理”当回事,谁就更不容易被这波浪潮反噬

如果你是工程师,可能可以带走的是:

  • 把自己从“代码生产者”挪到“约束设计者 + 熵管理者”的位置上;
  • 在每一个小决策里,多问一句:“这一步在往上堆熵,还是顺便压了一点?”

如果你是做模型 / 工具的人,可能可以带走的是:

  • roadmap 上不要只有“写得更快”“覆盖更多语言 / 框架”;
  • 把“长期熵管理”也当成产品能力加进去——哪怕一开始只是几条粗糙的规则和熵指标。

最后,如果你有机会设计团队、框架或组织流程,我会很想看到那样一种形态:

这套系统大量使用 AI 生成代码,但它有清晰的低熵内核,有稳定的领域语言,有可视化的熵面板,每一轮演化都在一套“有预算的熵管理”之下进行。

那时候,我们就不再把 vibe coding 只理解成“写代码很爽”,而是把它当成一套:在高熵世界里,重新分工、重新设计工程体系的机会。