一个工程 AI 产品,为什么越接近交付,越要主动停下来重构

过去一段时间,我们在筑见合规、筑见图形和筑见求解器三个项目里,先后做了规模不小的架构调整。

这些工作耗费的精力,比继续增加几个功能大得多。很多时候,原来的代码还能运行,新需求也不是做不出来。我们仍然选择停下来。

原因并不复杂:AI 编程把写代码变快了,却不会自动让系统更容易理解。一个边界不清的设计,以前可能一个月才积累成问题;现在,AI 可以在几天内沿着这个设计继续生成状态、分支、适配器和测试,把局部的不合理迅速扩散到整个系统。

代码产量提高以后,架构判断反而更值钱。

这篇文章不想讨论怎样把文件拆得更漂亮。我们更关心一个接近交付的工程 AI 产品,怎样判断自己已经到了必须暂停功能增长、先恢复系统可控性的时刻。

AI 编程降低了实现成本,也降低了堆叠成本

传统开发里,一个想法从需求进入代码,要经过理解系统、设计接口、手工实现和调试。这个过程很慢,却会迫使开发者反复接触现有边界。

AI 编程改变了速度。只要给出局部上下文,它很快就能增加一个状态、补一条分支、接一个接口,再生成相应测试。对于边界清楚的系统,这是生产力;对于边界已经松动的系统,这也是技术债的加速器。

我们在实践中反复看到四种情况。

第一,局部修改完全正确,系统整体却更难理解。AI 能把当前函数改对,却未必知道另一个模块已经保存了同一份状态。

第二,复制一个相似流程比抽出业务边界容易。于是保存、恢复、错误处理和兼容逻辑逐渐出现多个版本。

第三,测试会跟着现有结构增长。新增用例证明这次修改可以运行,却可能顺便把不合理的依赖固化下来。

第四,生成速度掩盖了理解成本。功能一天就能做完,下一次修改却需要同时阅读页面、Hook、运行时、IPC 和导出链路。

问题不在 AI。问题在于团队是否仍然掌握设计权。AI 可以沿着一个方向高速施工,但依赖应该朝哪里指、哪份数据才是事实、什么接口必须长期兼容,仍然要由人决定。

需要暂停的信号,不是文件大,而是修改开始失去边界

大文件不一定危险。稳定的数据定义、兼容映射和生成代码,即使行数很多,只要变化少、责任单一,风险仍然可控。

更值得警惕的是“高频变化”和“多重职责”同时出现。我们通常检查五个信号:

  1. 热点仍在净增长。 新功能继续进入同一入口文件、控制器或服务。
  2. 同一事实有多个副本。 页面状态、持久化对象、接口响应和缓存各自保存一份相似数据,再靠同步逻辑维持一致。
  3. 依赖方向开始反转。 领域逻辑为了复用功能,反过来依赖 HTTP 路由、UI 组件或具体运行时。
  4. 一次小修改跨越多层。 调整一个面板,需要同时触碰业务状态、保存、导出和异常恢复。
  5. 测试失败难以归层。 界面、业务转换、进程编排和验收脚本混在一起,出错以后只能沿整条链路排查。

这不是通用量表,而是我们在这轮治理中给自己设的经验阈值:出现两个信号,就安排治理;出现三个以上,而且产品正在进入交付,就不宜再把“功能还能做”当作继续增长的理由。

图 1 从功能持续流入到局部架构治理的转折
图 1 从功能持续流入到局部架构治理的转折

筑见合规:真实文档交付把隐藏复杂度全部带了出来

筑见合规是这次文章的主案例。

演示阶段的技术标工作台,只要证明资料能够进入、AI 能生成章节、页面能够显示结果。进入真实文档流程以后,系统面对的是另一种复杂度:原始 DOCX、项目事实、章节状态、AI 候选、人工采纳、证据复核、分页、写回和最终交付必须保持一致。

桌面端还要处理窗口生命周期、本地文件权限、进程通信、错误恢复和不同显示环境。一个章节的修改可能同时影响证据状态、分页和导出内容;窗口关闭后重新打开,草稿和工作区又必须回到正确位置。

早期为了快速跑通流程,我们也把不少能力集中在少数入口里。这种做法在探索阶段有效,到了交付前却开始制造风险:主界面既掌握界面状态,又处理业务命令;主进程既负责窗口生命周期,又承载 IPC 和验收编排;AI 操作、错误恢复、侧栏状态和文档逻辑持续进入同一批热点。

我们没有宣布整个项目停止开发,而是对热点设置了“局部 HOLD”。这些位置只允许四类变化:修复缺陷、补足测试、向外迁移职责,以及维持现有接口所需的兼容调整。新业务必须进入新的责任边界,不能继续回填巨石。

随后,拆分沿着业务发生,而不是沿着行数发生:

这里最难的工作不是移动代码,而是决定什么不能变。IPC 名称、持久化结构、DOCX 写回、草稿恢复和既有用户操作都属于兼容边界。每次迁移只能移动一类职责,并用原有行为证明这次移动没有改变产品语义。

所以我们拒绝了推倒重写。旧系统看起来不够整齐,却保存着真实使用形成的隐性约束。一次性重写很容易得到一张漂亮的新架构图,同时丢掉最难重新发现的交付细节。

筑见图形:运行时状态不能污染长期项目事实

筑见图形面对的是另一类压力。大模型导入、单构件编辑、GIS、视口交互、缓存和 WebGPU 验收同时增长时,短暂的渲染状态很容易混入长期项目文档,模型导入成本也会和渲染器生命周期互相放大。

读者可以通过筑见图形在线工作台理解这里所说的 BIM、GIS 与视口运行场景;核心实现不作为开源项目公开。

这轮治理没有按行数拆渲染器,而是先区分两类数据:项目文件只保存稳定的几何与场景事实;加载进度、临时渲染对象和资源释放状态留在运行时。模型编辑改为按对象 ID 提交变化,导入过程使用统一加载会话,GIS、视口、缓存和测试 runner 分别进入自己的 policy、runtime 或 catalog 边界。

另一个容易被忽略的问题是测试控制面。若生产代码为了让 smoke 好测而不断增加特殊入口,测试本身也会反向侵入架构。我们把场景断言留在领域 runner,把进程生命周期、硬件证据和报告协议放进共享运行时,再用 AST、行为契约、真实模型和物理 GPU 证据约束边界。

这类重构没有直接增加一个用户按钮。它保护的是下一种模型格式、下一个 GIS provider 和下一轮渲染能力进入系统时,不必重新穿过整条图形管线。

筑见求解器:开源代码可以直接检查我们是否这样做了

ArchSight Solver 是三个项目中唯一开源的。仓库采用 Apache-2.0 许可,代码、测试和发布记录都可以在 GitHub 查看,也可以直接打开在线演示

在 v1.6.2 发布前,求解器也暂停了功能扩张,完成了一轮架构稳定性治理。问题很典型:内部求解与归一化模块出现反向依赖,领域逻辑借用了 HTTP API;同一份计算结果同时以 canonical solution、历史顶层字段和结果投影持久化;前端运行结果又在 Hook 与工程对象之间同步。

这意味着一次“计算成功”,背后可能存在几份需要保持一致的结果。对象切换、异步保存或宿主接入一旦改变时序,陈旧结果就可能被继续展示或导出。

治理的第一步是恢复依赖方向。公共假定、类型、诊断和响应契约进入 Common / Contracts,计算编排进入 Application,HTTP 只保留边界职责。旧导入路径没有粗暴删除,而是作为兼容 facade 保留。

第二步是恢复唯一事实源。Job Store 只持久化带版本的 canonical result,HTTP、异步读取和其他调用方式在边界生成兼容视图;前端结果直接按对象 ID 提交到工程文档,不再依赖运行时副本之间的双向同步。

第三步才是拆热点。Schema Registry、结构模型归一化、工作台编排和画布交互按照契约族和业务职责进入深模块,原来的公共接口继续稳定。拆分完成后,后端 562 项测试、前端 400 项单元测试以及浏览器、容器、版本、Schema 和安全门禁共同参与了发布验收。

v1.6.2 Release 已固定这次代码基线。它没有宣称所有架构债务已经清零,剩余巨型文件仍被列为后续热点。这一点也很重要:架构治理可以阶段完成,但不能用一次测试通过宣布系统从此没有技术债。

有效重构不是“拆文件”,而是同时完成五件事

三个产品的技术栈和业务不同,最后采用的治理顺序却很接近。

先画出修改地图。 不急着动代码,先统计高频热点、状态所有者、依赖方向、公共接口和验证入口。文件行数只是线索,提交频率和修改半径更能说明问题。

冻结必须兼容的行为。 API、项目文件、文档写回、用户操作和命令行报告,先由回归测试锁住。没有行为基线,重构就会悄悄变成重新设计。

一次只迁移一种职责。 先建立目标模块的输入和输出,再移动逻辑,保留原接口,验证通过后才处理下一个边界。这样失败时可以撤销,也更容易判断回归属于哪一层。

把架构决定写成可执行门禁。 “以后不要再往这里加代码”不是规则。依赖方向、公开导出、状态唯一性、热点净增长、包体预算和报告协议,需要进入测试或静态检查。

按证据层级收口。 单元测试证明局部行为,类型检查和构建证明组合关系,浏览器或 Electron 证明真实运行,真实文件与硬件验证外部环境,独立 UAT 再证明普通使用者能够完成交付。前一层通过,不能替后一层签字。

图 2 架构治理如何转化为用户可感知的交付可靠性
图 2 架构治理如何转化为用户可感知的交付可靠性

AI 适合做重构助手,但不能替团队决定边界

AI 在架构治理中非常有用。它可以扫描依赖、统计热点、寻找重复状态、生成回归测试,并在一轮迁移后快速检查遗漏。面对数万行代码,这种速度过去很难获得。

但 AI 最容易给出的方案,往往是“把这段代码抽到另一个文件”。这只能改变目录,不能自动形成模块。

一个模块是否成立,要看它有没有稳定的输入输出,是否拥有自己的业务规则,调用方是否不再理解内部细节,以及修改能否停留在这个边界以内。这些判断来自产品语义、兼容承诺和长期演进方向,不来自代码相似度。

我们的做法是让 AI 承担搜索、迁移和验证的重活,人负责以下决定:哪份数据是事实源,依赖允许朝哪个方向流动,哪些接口不能破坏,哪些失败必须阻止发布。

AI 写代码越快,这个分工越不能含糊。

怎样判断这轮重构可以停下来

文件变小,不是完成标准。我们更看重下面几个变化:

达到这些条件,说明系统重新获得了继续演进的能力。它不代表架构已经完美,也不代表生产 UAT 和商业验证已经完成。

筑见合规、筑见图形和筑见求解器的本轮主要架构治理已经基本收口,仍有热点会进入后续阶段。我们花了不少精力做这件事,因为工程 AI 产品最终要处理真实文件、真实模型、真实计算和真实责任。靠功能数量建立的领先,很容易被一次不可解释的修改耗尽。

如果你也在用 AI 编程,可以在下一次接受生成代码前多问一句:这次修改是在强化边界,还是只是在让一个已经拥挤的入口继续增长?

会使用 AI 写代码,正在成为基本能力。知道什么时候让 AI 停下来,重新设计系统,才是更难替代的能力。


关注我们

欢迎搜索并关注 筑见实验室,获取更多建筑 AI、工程软件与数字化工作流实践: