最近和一个后端团队聊他们的 LLM 使用体验,对方说了一句让我印象很深的话:“我们现在代码写得比以前快很多,但项目并没有比以前交付得更快。”
这句话背后是一个正在被大量团队忽视的现象:代码生成速度上去了,项目演进速度却卡住了。不是模型不够强,也不是提示词写得不好,而是整个开发流程的时间结构发生了改变——写代码的时间急剧缩短,但读代码、改代码、确认“这段代码为什么是对的”的时间,正在以更快的速度膨胀。
如果你正在用 LLM 辅助开发,或者你的团队已经大面积使用 AI 编程工具,这篇文章值得你停下来思考一个问题:我们是不是正在一边享受生成速度,一边为“读不懂、不敢改、不能演进”支付更高的隐性成本?
这篇文章会先解释一个概念——Programmatic Stagnation(程序化停滞),然后分析它为什么在 LLM 时代被放大,最后给出工程侧的应对思路。重点不是让你少用 LLM,而是让你知道,在什么条件下,LLM 是在帮项目加速,在什么条件下,它其实是在把项目一步一步拖进停滞。
1. 从“代码生成快”到“代码理解慢”:一个被忽视的时间差
先还原一个非常典型的开发场景。
需求很简单:给订单模块加一个“批量导出”接口。你熟练地打开 LLM 对话框,描述了接口路径、入参、出参、分页方式和导出格式,模型在几十秒内生成了一段看起来完整的 Java 代码。你复制粘贴,启动应用,测试通过,提交。
问题出在哪里呢?出在接下来的一段时间里。
你可能需要花十几分钟读这段代码,确认它和项目里现有的返回结构一致;你需要检查它有没有正确处理事务边界;你需要确认异常会不会被全局兜住;你还要判断它是不是和现有某个工具方法重复了。如果这段代码是模型生成的,你还需要额外确认一件事——它有没有用到项目里那些约定俗成的东西,比如统一返回体、日志规范、DTO 转换规则、本地缓存还是 Redis 缓存。
“生成代码”可能只需要 30 秒,“理解并确认代码”却可能需要 15 分钟。
这不是某一个人的问题,而是 LLM 辅助开发模式带来的结构性时间差。过去,写代码的过程本身就包含了对上下文的理解:你要先找到现有的 Service,看看它的写法,了解依赖注入的方式,再开始写。这段“慢”的过程其实是在积累上下文。现在,LLM 帮你跳过了这个过程,但并没有帮你积累上下文——它只是帮你绕过了上下文。
于是,一个此前不存在的成本项出现了:代码读不懂,或者读懂了但不敢确认它是对的。
从很多团队的真实反馈看,这个时间差正在变成主要瓶颈:
- 写代码时间:从原来占总时间的 40% 下降到 20% 左右;
- 读代码与理解代码时间:从 20% 上升到 35% 以上;
- 修改与调试时间:因为代码不是自己写的,理解成本上升,往往从 20% 涨到 30%;
- 验证与确认时间:由于对代码没有“拥有感”,验证变得更加谨慎,从 10% 涨到 15%。
这不是精确统计,但方向是明确的:LLM 降低的是“写”的成本,而软件开发的下一个瓶颈,正在变成“读”和“改”的成本。
如果你只是写一次性脚本,这个时间差根本不重要。但如果你是在维护一个需要长期演进的业务系统,这个时间差就是项目停滞的开始。
2. 什么是 Programmatic Stagnation:概念、信号与判断标准
Programmatic Stagnation,字面意思是“程序化停滞”。它描述的是一种工程状态:项目依然能持续产出代码,功能看起来也在增加,但系统整体的可理解性、可修改性和可演进性正在下降,最终进入一种“能运行但不能成长”的状态。
这里要特别强调一个容易弄混的地方:Programmatic Stagnation 不是传统的代码质量差,也不是代码写得烂导致的重构困难。它更像是一种认知层面的停滞——代码库在物理体积上是增长的,但在心智层面上是停滞的。
我再用一个类比帮助你理解。
想象你在一张草稿纸上写一篇长文章。以前你是边想边写,虽然慢,但每一段你都清楚它为什么在那里。现在有人帮你把每一段都快速写出来了,但你没有通读,或者读了一遍但理解不深。每个段落单独看都还行,但你不知道第二段和第五段之间有没有重复,也不知道如果删掉第三段,后面的推理链会不会断掉。文章越来越长,但你越来越不敢改动它。
这就是停滞。代码能跑,但没有一个人能完整解释它为什么能跑;功能能加,但没有一个人能准确评估“改这里会不会影响那里”。
如何判断你的项目是否已经进入或正在进入这种状态?以下信号如果有三条以上命中,基本可以判断项目遇到了程序化停滞:
| 信号 | 表现 |
|---|---|
| 改动一个功能,需要让 LLM 重新生成整段代码 | 说明人类已经无法在现有代码基础上做局部修改 |
| 没有人能完整解释某段核心逻辑的设计原因 | 代码失去了“决策上下文” |
| 测试覆盖率跟不上代码量增长速度 | 代码生成速度远超验证速度 |
| Code Review 演变成“读代码大会” | 评审者主要时间花在理解代码,而不是判断设计 |
| 新需求到来时,第一反应是“问 LLM 怎么写”,而不是“看现有代码怎么扩展” | 上下文基础已经断裂 |
| 代码重复率明显上升 | 同一个功能在不同位置被以不同方式实现 |
判断标准其实很简单:如果为了加一个小功能,你必须理解一片巨大的相关代码;如果为了改一行逻辑,你不敢保证其他调用方不会出问题;如果代码库里大量存在“我也不知道为什么要这样,但不要动它”的代码——你就在停滞状态里。
传统意义上,我们说一个项目“烂”,更多是指代码不规范、结构混乱、技术债高。而 Programmatic Stagnation 指的是一种动态过程:项目的产出速度没有下降,但你能安全改动的范围越来越小。很多团队在没有 LLM 的时候,写代码慢,但每写一段代码都对系统有更深的理解;有了 LLM 之后,每写一段代码,反而可能对系统更陌生——因为你写的代码不是你设计的。
这也是这个概念和传统“写烂代码”最本质的区别:过去写烂代码的人,至少知道自己写的是烂代码;现在用 LLM 的人,可能根本不知道这段代码哪些地方是危险的。判断力没有跟上生成速度。
3. 为什么 LLM 会放大这种停滞:五个技术成因
理解了概念之后,需要回答一个更关键的问题:为什么恰好是 LLM 放大了这种停滞?换成传统编程,即使代码写得再乱,至少写的人还有机会理解自己的代码。LLM 的介入改变了几个底层机制。
3.1 成因一:快速生成与缓慢理解的剪刀差
这是最核心的结构性原因。
LLM 把“写代码”从一种需要全神贯注的智力活动,变成了接近瞬时输出的操作。但**“理解一段代码”所需的认知成本,并没有因为代码是 AI 生成的而减少**,反而可能因为代码风格的陌生、生成过程中对项目上下文的不完全掌握而增加。
写代码和读代码之间出现了剪刀差:生产速度是线性或指数增长的,消费速度(理解速度)几乎不变。如果团队没有专门留给“理解代码”的时间,那么理解债务就会越积越多,直到某一个节点,项目彻底无法被安全修改。
3.2 成因二:上下文盲区——LLM 没有读过你的项目历史
LLM 生成一段代码时,它掌握的上下文来自你的提示词、当前打开的代码文件,以及它训练数据中的通用编程知识。它不知道你的项目为什么采用这样的分层架构,不知道这个模块经历过哪些需求变更,不知道哪些代码是历史遗留的“不要去动”的边界条件。
这就导致一个典型现象:LLM 生成出来的代码,在局部看是自洽的,在全局看往往是“失忆”的。它不认识项目里的隐性约束,不遵守项目里的潜在约定,甚至可能在毫无察觉的情况下,在一个已经有工具类的地方重新造了一个实现。
人类开发者在写代码时,潜意识里携带了大量项目历史。LLM 不具备这个信息,除非你显式地提供给它——但大多数开发者不会这么做,因为把项目历史整理出来本身就需要很多精力。
3.3 成因三:局部正确掩盖全局混乱
LLM 擅长生成“在标准环境下看起来正确”的代码。一个方法单独放在那里,逻辑是对的;一个函数单独跑,输出是符合预期的。
但大型软件系统的问题从来不在“局部对错”,而在“局部与局部之间的关系”。LLM 没有能力审视这种关系,因为它没有完整的全局模型。
于是,我们看到一种新的问题形态:每一段代码都是“对的”,但代码段之间的关系是混乱的。传统坏味道是明显的代码异味,现在的新坏味道是“每个片段都太正常了,以至于你无法通过阅读单个片段发现问题”。这种问题更容易被 LLM 放大,因为它可以快速生成大量“局部正常”的代码,以极低成本将全局问题掩盖掉。
3.4 成因四:验证环路被拉长
传统写代码,你写一行,心里验证一行。逻辑在脑子里同步跑过一遍,错误在生成阶段就被大量过滤。
LLM 生成代码后,你面对的是一段没有经过“内部心理模拟”的代码。你需要先读,再在脑子里运行一遍,再判断它是否符合项目里的约束,然后才敢跑测试。如果你的项目测试覆盖不足,你甚至只能靠“看起来没问题”来判断。
这意味着验证环路变得更长、更慢、更依赖人的注意力。代码生成速度越快,一次性生成的代码量越大,验证路径就越长。如果不刻意缩小单次生成代码的范围,验证债务会迅速堆积。
3.5 成因五:连续生成导致的结构性“失忆”
人类的记忆虽然不是完全可靠的,但至少有一个特征:你在模块 A 里写过一个工具函数,下次在模块 B 里写类似功能时,大概率会回忆起“模块 A 里好像有个工具函数”。LLM 没有这种自然记忆。它每次生成都是“重新开始”。
所以一个常见的后果是:同一个项目中,同一个逻辑可能存在多个不同版本,分布在不同的服务、不同的类、甚至不同的目录里。这不是故意的重复,而是 LLM 每次生成都是独立的、无记忆的一次行为。
这种结构性失忆带来的后果是,系统的重复率上升、概念数量膨胀,最终让任何一次“我要重构这个逻辑”都变成一场灾难。
从以上五个成因可以看到,Programmatic Stagnation 不是某个人的错误,而是 LLM 生成式编程模式与软件长期演进需求之间的结构性矛盾。要解决它,不能靠“换更强的模型”,而要靠工程侧建立新的防护机制。
4. 从“反应式修复”到“预防式治理”:上下文管理与 LLM Wiki 范式
既然成因中最核心的一条是“上下文盲区”,那么工程侧最重要的应对方向,就是有意识地为 LLM 和人类开发者共同建立一个可读、可维护、可更新的项目上下文层。
过去我们写代码,默认上下文在人的脑子里。现在有了 LLM 介入生成流程,上下文必须变成显式的、写在仓库里的、可被检索的文档。这不是传统的“写文档”任务,而是为了让 LLM 在生成代码时“读到”项目背景,让人类在审查代码时“找回”项目记忆。
从公开讨论看,Andrej Karpathy 提出的 LLM wiki 范式是一个很有代表性的思路:在代码仓库里建立一个专门的“知识文件”或“Wiki 文件”,把仓库中分散的意图、设计、技术债务、限制、决策记录等信息系统化地整理进去,让 LLM 在生成或修改代码时能访问这些上下文。这个思路虽然以 LLM 为出发点,但它的价值并不只服务机器——人类新成员加入项目时,读这份文件同样受益。
社区里也出现了类似的约定,比如llms.txt,在项目根目录放一个文本文件,指向对 LLM 有帮助的信息。具体形态可以灵活选择,核心原则是一致的:让项目上下文从“隐性存在人的脑子里”变成“显性写在仓库里”。
4.1 一个仓库级上下文文件示例
下面是一个仓库级上下文文件的骨架。你不需要照抄,但你可以从中看到“应该放哪些信息,以及为什么放这些信息”。
# 文件路径:/docs/LLM_WIKI.md(也可以叫 llms.txt,放在项目根目录) # 项目:order-service 订单履约服务 ## 技术栈与目录结构 - 语言/框架:Java 17 + Spring Boot - 存储:MySQL 8 + Redis - 消息队列:RocketMQ - 核心目录: - order-core:领域模型与业务规则 - order-infra:数据库、外部客户端等基础设施 - order-app:应用服务与接口层 ## 编码约定(LLM 生成代码时尤其需要) 1. 所有对外接口返回统一使用 Result<T>,禁止出现 Map 或裸对象返回 2. 订单状态变更必须走 OrderStateMachine,禁止直接修改 status 字段 3. 数据库操作统一使用 MyBatis-Plus,禁止在业务代码中写原生 JDBC 4. 日志统一使用类名 Logger,禁止在静态工具类中使用实例 Logger ## 关键业务规则 1. 订单状态变更链路:CREATED -> PAID -> SHIPPED -> COMPLETED 2. 只要订单进入 PAID,库存必须已经预占,回滚顺序是先释放库存再取消订单 3. 退款流程不允许直接删除订单记录,只能标记状态位 ## 已知技术债与限制 - order_history 表数据量接近亿级,分表方案已排期 - payment 模块目前依赖旧版内部 API,迁移期间不要改变现有接口签名 - 定时任务统一使用 XXL-Job,新任务不要引入独立调度框架 ## 修改代码前必读 - 改动领域实体前,先阅读 order-core/domain/model/Order.java 顶部注释 - 新增外部接口时,需要同步在 docs/api/contract.md 登记 ## 典型负面案例 - 曾经有 PR 绕过状态机直接修改 status 字段,导致订单和支付状态不一致 - 曾经有代码直接调用支付网关查询接口查订单,导致数据库连接池被打满这份文件的关键在于:它写的不是“文档”,而是代码生成器最缺少的那部分上下文。如果你把这份文件内容作为系统提示词的一部分注入到 IDE 的 Agent 配置中,或者每次请 LLM 生成代码前先让它阅读这个文件,你会发现生成结果在项目契合度上有明显提升。
4.2 模块级上下文:给每个模块一份 HEADER.md
仓库级上下文解决整体问题,但大型项目建设中,一个仓库可能有几十个模块,每个模块有自己的设计决策和坑。更细粒度的做法是:在关键模块目录下放置一个HEADER.md,描述本模块的边界、设计决策和注意事项。
# 文件路径:order-core/src/main/java/com/example/order/core/HEADER.md # 模块:order-core 领域层 ## 职责边界 - 只承载订单、支付、履约的领域模型与状态机 - 不允许出现 MyBatis-Plus 的 BaseMapper 相关代码 - 不允许依赖任何外部 HTTP 客户端 ## 关键设计决策 - 2024-06:订单状态机由硬编码 if/else 重构为 StateMachine 原因:原实现存在状态分支漏处理,导致重复支付问题 替代方案:直接使用状态枚举 + switch,被否绝 影响:新增订单状态时必须同步修改状态机定义 ## 已知问题与注意点 - Order.paidAt 时间戳由支付回调写入,不要在本地事务中更新,否则对账可能不一致 - 状态机的 guard 方法不要做 IO 操作,只做内存判断,避免在锁内持有数据库连接 ## 扩展建议 - 如果需要增加新的订单状态,先看 OrderStateMachine 的 TRANSITIONS 定义,不要通过新增 if 分支实现对 LLM 来说,这种模块级上下文的效率远高于只有一个大而全的仓库文档。你想让 LLM 生成 order-core 里的代码,就应该让它先读 order-core 的 HEADER.md,而不是读整个项目的全部 README。
4.3 上下文管理的三条组织原则
有了这些文件之后,如何维护它们就成了新的工程问题。这里有三条原则比较重要:
第一,信噪比优先,而不是大而全。上下文文件的目的是让 LLM 快速抓取关键约束,而不是让它读一篇万字长文。每一条信息都要经过筛选:这条信息会不会影响代码的生成方向?如果不会,就不要放进去。
第二,稳定性优先。上下文文件应该描述那些不容易变化的内容:架构约定、业务规则、技术债、设计决策。不要把所有频繁变化的细节都塞进去,否则每次小改动都要更新文档,文档最终会被抛弃。
第三,让上下文文件本身接受 Code Review。当有人新增了一个重要的业务规则或架构约束时,应该要求同步更新对应的上下文文件。这个动作应该被纳入开发流程,而不是可有可无的加分项。
5. 可落地的工程实践:如何让项目保持可演进
有了上下文管理这个基础,还需要配合几项具体的工程实践,才能把项目从“生成快、理解慢”拉回“生成快、理解也跟得上”的轨道。
5.1 实践一:在所有文件顶部提供“为什么”级别的上下文
普通的注释告诉别人“这段代码做了什么”,更好的注释告诉别人“这段代码为什么要存在,以及它为什么不能随便删”。
在使用 LLM 生成代码时,这个区别尤其重要。因为如果你自己都没有理解一项设计的“为什么”,你就无法让 LLM 在后续修改中保留这个“为什么”。所以,一种值得推广的做法是:在关键类、关键方法的注释中,显式写出业务意图和边界条件。
// 文件路径:order-core/src/main/java/com/example/order/core/Order.java public class Order { private OrderStatus status; /** * 标记订单为已支付。 * 为什么需要有这个方法:支付回调走这里触发状态机迁移,禁止绕过状态机直接调用。 * 已知边界:如果订单已退款成功,不允许再次支付成功,由状态机 guard 控制。 * 历史教训:早期直接修改 status 字段导致订单与支付状态不一致,见 docs/decisions/2024-06-order-state.md。 */ public void markPaid(PaidEvent event) { orderStateMachine.fire(OrderTransition.PAID, event); } }这段注释的“为什么”部分,直接降低了未来改动的风险。就算这个类将来被 LLM 重构,如果上下文文件还在,LLM 仍然有机会保留这段边界逻辑。
5.2 实践二:限制单次生成代码的规模
很多开发者遇到的问题是 LLM 一次性生成了一整个 Service 类的所有方法,几百行代码一次性粘贴进来。此时即使你逐行读一遍,也很难发现其中某个方法和项目现有工具类重复,更难发现某个方法的事务边界不对。
更稳妥的做法是:把大规模任务拆成小任务,让 LLM 每次只生成一个方法、一个函数、一个配置项,生成后立即人工确认。这看起来更慢,但实际上是更快的路径——因为小片段的验证成本低、心智负担小、错误定位容易。
换句话说,不要把 LLM 当成“一次写完整模块的人”,而要把 LLM 当成“一个打字速度极快但需要频繁确认的结对程序员”。
5.3 实践三:建立自动化的验证闭环
如果代码是 LLM 生成的,你对它的信任度天然应该低于自己手写的代码。那么,如何在不依赖人力的前提下验证?答案只有一条:自动化测试和静态检查。
LLM 生成代码后,最有效的验证方式不是多次阅读,而是让测试去说话。你需要一个能在 CI 中运行的验证流程,至少覆盖编译、单测、静态检查、变更影响模块测试。
#!/usr/bin/env bash # 文件路径:scripts/verify_llm_changes.sh # 说明:在 CI 中,对 PR 变更的代码执行定向编译、测试和静态检查 # 使用方式:把该脚本接入 CI 的 Pull Request 流水线 set -euo pipefail # 1. 获取变更涉及的顶层模块 CHANGED_DIRS=$(git diff --name-only origin/main...HEAD | xargs -I{} dirname {} | sort -u) echo "检测到变更目录:" echo "$CHANGED_DIRS" # 2. 编译检查:保证所有变更至少在编译层面是安全的 mvn compile -DskipTests # 3. 对变更模块运行测试,不跑全量,避免把 CI 拖慢 for dir in $CHANGED_DIRS; do if [ -f "$dir/pom.xml" ]; then echo "==== 运行模块测试:$dir ====" mvn -pl "$dir" test fi done # 4. 静态检查:对可能影响架构约束的地方重点扫描 mvn -DskipTests spotbugs:check checkstyle:check || echo "静态检查未通过,请先本地执行 mvn verify"这套脚本不依赖具体模型或 IDE,适配现有 Java/Maven 项目。如果你的项目技术栈不同,核心思想是一样的:LLM 生成代码越多,越需要自动化的质量门禁来兜底。
5.4 实践四:用决策记录对抗项目“失忆”
项目为什么会演进出怪异的边界逻辑?很多时候是因为过去某次故障、某个性能瓶颈、某个临时方案留下了影响。这些信息如果只存在于某个人的大脑里,随着人员流动和 LLM 代码介入,很快就会丢失。
推荐的做法是引入轻量级的决策记录(ADR,Architecture Decision Record)。不要求长篇大论,只要把“背景、决策、放弃的方案、影响”四段写清楚,就能给未来的修改提供足够的判断依据。
# 文件路径:docs/decisions/2025-03-order-cache.md # 决策:订单查询引入本地缓存 ## 背景 订单查询 QPS 持续上涨,数据库压力增大,读写比例约 20:1。 ## 决策 在 order-app 层引入 Caffeine 本地缓存,过期时间 5 分钟。 不缓存已取消、已退款订单,避免用户看到脏数据。 ## 放弃的方案 - Redis 缓存:运维成本和一致性成本更高,当前 QPS 场景不需要。 - 直接查询从库:存在复制延迟,不适用于订单这种强一致性场景。 ## 影响与后续 - order-service 启动时会加载热数据,启动时间预计增加 0.3 秒。 - 需要增加缓存命中率监控,连续低于 70% 时重新评估该方案。这些决策记录同时服务两个对象:人类开发者靠它找回项目记忆,LLM 靠它理解“为什么系统长成了这样”。如果上下文文件是静态地图,ADR 就是地图上的版本演进记录。
5.5 实践五:控制 AI 生成代码的引入边界
这不是说“禁止 AI 生成代码”,而是说应该区分哪些代码适合 AI 生成,哪些代码不适合。
适合的:样板代码、DTO 转换、基于明确接口定义的实现、文档注释、SQL 查询、配置文件、单元测试骨架、一次性脚本。
需要谨慎的:核心领域逻辑、状态机迁移、涉及事务边界和并发控制的代码、算法复杂度高且不易验证的代码、与外部系统交互的边界代码。
一个可参考的标准是:如果这段代码出错,最坏后果是线上故障还是仅仅功能不生效?如果是线上故障级别,请至少做一次完整的人工 review。通过限制 AI 生成代码进入敏感模块的路径,可以在保留生产力的同时,避免让不必要的风险进入系统核心。
6. 传统工程手段在 LLM 时代的价值回归
当大家都在讨论 LLM 如何改变编程时,容易被忽略的一点是——LLM 的出现并没有推翻传统工程手段,而是让其中一部分手段变得更有价值,另一部分手段的方法论需要调整。
代码评审的价值比以往更高了,但评审的重点需要从“检查错误”转向“确认意图”。过去评审员看的是语法、风格、边界条件有没有漏;现在面对 LLM 生成的代码,评审员首先要问的是“这段代码为什么存在”“它为什么这样实现”“它和项目现有的设计约束是否一致”。你需要把评审变成一次“上下文对齐”,而不是“挑错大会”。
模块化与接口边界的意义也被放大了。LLM 对项目整体上下文掌握不足,因此模块边界越清晰、接口契约越明确,AI 生成代码就越容易“落在正确的位置上”。一个分层清晰的模块,AI 生成的代码更容易自动适配模式;一个没有边界的系统,AI 生成的代码就是一场混乱的加速器。
自动化测试的地位空前提高。以前测试是为了防回归,现在测试是人类对机器生成代码唯一高效的事实核查手段。如果一段 LLM 生成的代码没有测试保护,那它本质上就是个未经验证的黑盒。保持测试覆盖率,尤其是对核心链路的覆盖,是 LLM 时代最重要的投资之一。
技术债治理也没过时。只是在 LLM 时代,技术债的定义发生了变化:除了传统的代码结构问题,还需要加上上下文缺失、决策丢失、重复实现等新形式的债务。定期清理上下文文件,定期核对 ADR 和代码现状的一致性,也应该变成迭代节奏的一部分。
7. 常见误区与排查思路
很多团队在遇到 Programmatic Stagnation 时,第一反应是“换一个更强的模型”或“写更长的提示词”。以下四个误区尤其值得警惕,我把它整理成一张表,方便你自己对照排查。
| 误区 | 为什么无效 | 正确做法 |
|---|---|---|
| 换个更强的模型就能解决停滞 | 模型变强提升的是局部生成质量,但你缺的是项目级上下文和验证能力 | 先建立上下文管理文件,把项目约定显式提供给模型 |
| 上下文越长越好,把所有文档塞给 LLM | 上下文过长会导致信息噪声过大,关键约束反而被淹没 | 上下文要短、精、稳,只放影响生成方向的信息 |
| 代码注释写详细就能避免失控 | 注释解决的是“这段代码在干什么”,但停滞的核心是“为什么它存在”和“改了会怎样” | 在注释中显式写意图、边界、历史原因 |
| 要求 LLM“不要改其他代码”就行 | LLM 在生成代码时天然会忽略项目隐性约束,这是机制问题,不是指令能解决的 | 通过模块边界、接口契约和自动化测试,把不确定性隔离起来 |
如果你判断项目已经陷入停滞,有三个自救步骤可以立即执行。
第一步,停止生成新代码,先补齐上下文。为当前正在开发的模块建立 HEADER.md,把关键业务规则、状态机、技术债写进去。这一步不需要覆盖整个系统,先覆盖你接下来要动的模块。
第二步,挑出项目中最核心、最容易被改错的 3 到 5 个类,为它们补上“为什么”级别的注释。同时写一条 ADR,记录项目当前面临的最主要架构约束。目标是让任何新成员(人类或 AI)在第一次修改这些代码时,至少能理解背后的关键决策。
第三步,在 CI 中加入一个自动化的最小验证门禁:编译、受影响模块测试、核心静态检查。没有这套门禁,LLM 生成代码的每一次引入都在扩大未知风险,项目会加速滑向停滞。
8. 总结与后续学习方向
Programmatic Stagnation 不是一句耸人听闻的口号,而是 LLM 辅助开发时代一个正在变成普遍现象的问题。它的核心机制是:LLM 大幅降低了代码生成成本,却没有降低代码理解成本,也没有提升人们对代码的“心智所有权”。当生成速度远远超过理解速度,项目就会进入一种表面繁荣、实则难以演进的停滞状态。
应对这个问题的关键不在模型选择,而在工程治理。你可以从三件事做起:第一,为项目建立显式的上下文管理层,让 LLM 在生成代码时能读到业务规则和架构约束;第二,把开发流程从“生成-粘贴”改为“生成-理解-提交”,尤其是限制单次生成规模、写清楚关键代码的意图注释;第三,用自动化验证闭环对抗“机器生成代码无法被信任”的结构性问题。
后续值得深入的方向有三个:一是 LLM 应用的代码库治理,这个方向会逐渐形成新的工程规范,包括上下文文件格式、Agent 缓存设计、代码生成与验证的自动化链路;二是 Agent 与长期记忆,当 Agent 能基于持久化的项目知识执行更长周期的任务时,上下文管理会更加重要;三是团队 LLM 使用规范,它不只是“怎么提问”,还包括“哪些模块允许 AI 生成”“哪些代码必须人工评审”“决策记录如何沉淀”。
最后想说一句真心话:代码生成的速度已经不再是稀缺资源,对代码的理解和演进能力才是。如果你希望项目在 AI 辅助下越走越健康,现在就可以打开你的项目仓库,为它补上第一份上下文文件。