Article

Complexity Is Software's Enemy: Engineering Restraint In The AI Era

AI increases software output speed and also amplifies complexity. Mature product judgment treats complexity as a budget tied to visible user value.

Jun 08, 2026 Updated Jun 08, 2026
  • Engineering
  • Product judgment
  • AI PM
  • Agent

The full article body is currently published in Chinese. English titles, summaries, and site navigation are available first; full translations can be added article by article.

软件系统最危险的敌人,往往不是性能,不是技术选型,也不是某一个没有修掉的 bug。

更危险的东西是复杂度。

复杂度很少以“我要毁掉这个系统”的样子出现。它通常披着合理性的外衣:

  • 为了可用性,我们加一个兜底流程;
  • 为了稳定性,我们加一个确认握手;
  • 为了可靠性,我们加一个回调补偿;
  • 为了兼容更多场景,我们加一个配置项;
  • 为了避免极端错误,我们再加一个状态。

每一步看起来都对。

每一个局部决策都有理由。

但系统就是这样一点点变重的。

在 AI 时代,这个问题会更严重。因为 AI 让“继续加一点东西”变得更便宜了。写一个分支、补一个状态、生成一个配置面板、加一层 fallback、再写一段兼容逻辑,都比过去更快。

于是,新的瓶颈不再只是能不能做出来,而是:

人能不能审得过 AI 生成和推动出来的复杂度。

复杂度通常是合理地积累出来的

复杂度不是工程师无能的结果。

很多时候,它恰恰来自工程师的责任心。

一个功能上线后,系统会遇到异常输入、网络抖动、用户取消、第三方超时、权限变化、状态不同步、重复请求和并发冲突。

为了让系统更稳,我们开始补流程:

  • 请求失败了,要不要重试?
  • 用户取消了,要不要回滚?
  • 对方没响应,要不要超时?
  • 超时后又成功了,要不要补偿?
  • 补偿失败了,要不要告警?
  • 告警太多了,要不要分级?
  • 分级以后,要不要再做自动恢复?

于是,一个原本简单的流程开始长出分支。

分支之间再长出状态。

状态之间再长出同步协议。

最后,系统从“做一件事”变成“管理一堆可能发生的事”。

复杂度最隐蔽的地方在于,它往往不是被一次性设计出来的,而是被合理地积累出来的。

复杂度的代价不是代码多

复杂度最直接的代价,是理解成本。

一个简单系统,工程师可以在脑子里模拟它的运行。

输入是什么,状态怎么变,失败会怎样,基本能想清楚。

一个复杂系统则不行。你必须依赖日志、链路追踪、状态表、回调记录、重试队列和人工排查,才能拼出当时发生了什么。而且经常拼不完整。

这会进一步带来几个问题。

第一,失败路径爆炸。

成功路径通常只有一条,但失败路径可能有十几条。每增加一个状态,失败路径都可能成倍增长。

第二,测试成本上升。

复杂流程不能只测 happy path。它必须测试状态组合、超时组合、取消组合、恢复组合和重复执行组合。组合一多,测试就会失控。

第三,修改变得危险。

一个超时策略、重试机制、状态字段或兼容分支,都可能影响隐藏路径。团队会逐渐不敢动系统,只能继续在外围打补丁。

第四,系统出现多个局部真相。

这在涉及双方通信、握手、确认、取消和补偿的系统里尤其常见:

A 认为任务已经取消
B 认为任务还在等待确认
C 收到了成功回调
用户界面显示处理中
后台任务已经进入重试队列

这不是单个 bug,而是系统存在多个局部真相。

当系统无法稳定回答“现在到底发生了什么”,复杂度就已经从实现问题变成了治理问题。

成熟软件不可能真正简单

当然,不能天真地说所有复杂度都不好。

成熟软件很难保持真正的简单。因为成熟软件要面对真实世界。

真实世界有不同用户、不同设备、不同网络、不同权限、不同历史数据和不同业务规则。

一个玩具项目可以简单,因为它可以拒绝大多数场景。一个成熟产品不能这样做。

支付系统需要幂等。

权限系统需要审计。

文件系统需要恢复机制。

Agent 产品需要记录工具调用、权限边界、上下文变化、执行状态、用户确认和失败恢复。

这些复杂度很昂贵,但它们守住了稳定性和用户信任。

问题不在于系统能不能复杂。

问题在于:

复杂度有没有被管理,能不能被解释,是否真的换来了用户价值。

抽象不是免费的

更好的抽象可以减少复杂度。

把散落的回调变成事件流,把多方状态同步变成单一事实源,把临时判断变成明确的领域模型,这些抽象都可能让系统更清楚。

但抽象本身也是复杂度。

一个抽象需要命名,需要边界,需要学习成本,也需要维护。

如果一个抽象没有降低总体复杂度,只是把复杂度换了一个更高级的名字,它就是新的负担。

很多架构问题并不是“有没有抽象”,而是“抽象到底替谁降低了复杂度”。

  • 如果它降低了用户理解成本,它是产品价值。
  • 如果它降低了工程定位成本,它是工程价值。
  • 如果它降低了系统恢复成本,它是可靠性价值。
  • 如果它只是让架构图更漂亮,它可能只是复杂度转移。

这也是 AI 产品里很重要的一条判断标准。

不要因为一个概念听起来高级,就把它引入系统。

概念必须有治理对象。

复杂度是一种预算

我们通常会把 CPU、内存、磁盘、网络、LLM 上下文和用户注意力看成资源。

资源是有限的,使用它就有成本。

复杂度也应该被看成一种资源。

系统能承载的复杂度是有限的。

团队能理解的复杂度是有限的。

用户能感知的复杂度更是有限的。

每增加一个状态、一个配置、一个分支、一个异步回调、一个补偿流程,都在消耗系统的复杂度预算。

所以每个复杂设计都应该回答三个问题:

  • 它解决的是高频问题,还是低频焦虑?
  • 它降低了用户复杂度,还是只把复杂度转移给了系统?
  • 它会让系统更可解释,还是制造更多失败路径?

如果一个复杂设计消耗了大量预算,却没有明显提升用户满意度、稳定性、可恢复性或业务能力,它就是亏的。

Agent 产品会天然放大复杂度

Agent 产品比普通应用更容易复杂。

因为 Agent 不是一次请求一次响应。

它通常会经历一个长链路:

用户目标
  -> 任务理解
  -> 上下文组装
  -> 计划生成
  -> 工具调用
  -> 文件或数据变更
  -> 中间结果观察
  -> 失败恢复
  -> 用户确认
  -> 最终交付

这里每一段都可能产生状态。

每一个状态都可能失败。

每一次失败都可能需要解释、回滚、重试或人工接管。

Agent 产品还会额外面对几个难题:

  • 用户目标经常是模糊的;
  • 模型输出并不总是稳定的;
  • 工具执行会受到权限、环境和外部服务影响;
  • 长任务会积累大量上下文;
  • 用户需要知道 AI 做了什么,但又不想阅读所有细节;
  • 系统要让用户有掌控感,同时不能把所有复杂度都暴露出来。

这意味着 Agent 产品经理不能只关心“模型能不能完成任务”。

还要关心:

  • 用户如何提出任务;
  • 系统如何约束执行;
  • 中间过程如何展示;
  • 风险如何被阻断;
  • 失败如何恢复;
  • 结果如何被审查;
  • 信任如何被建立。

Agent 的核心挑战,不是把自动化做满,而是在自动化、控制感和可理解性之间找到平衡。

控制面和信任面不是为了增加概念

在 Plato 里,我把 Agent 产品拆成三个平面:

启发面
  帮助用户发现 AI 能做什么,并把模糊意图转化为任务包

控制面
  把任务变成可执行、可约束、可验证的流程

信任面
  让执行过程可见、可审计、可恢复、可解释

这三个平面不是为了堆概念。

它们的目标恰恰是收敛复杂度。

启发面降低用户表达复杂度。

用户不需要在空白输入框前独自想清楚所有上下文、目标、边界和验收标准。

控制面降低执行复杂度。

系统把任务拆成可追踪、可暂停、可确认、可恢复的步骤,而不是让 AI 在一个黑箱里自由漂移。

信任面降低信任复杂度。

用户不需要猜 AI 做了什么、为什么这么做、哪里可能有风险、失败后还能不能恢复。

所以,控制面和信任面并不是“让产品看起来更复杂”。

它们应该把必要复杂度封装在系统内部,并把用户真正需要理解的部分呈现出来。

如果一个 Agent 产品的控制面只是增加按钮,信任面只是增加日志,那它没有真正降低复杂度。

真正有效的治理平面,应该让用户更容易完成判断。

复杂度必须换来用户价值

一个实用判断标准是:

复杂度的提升,必须换来用户体验、稳定性、可信度或需求满足的提升。

这类提升可以是很多形式。

它可以让用户少犯错。

可以让失败更容易恢复。

可以让团队更快定位问题。

可以让系统状态更一致。

可以让用户更敢把重要任务交给 AI。

可以让复杂任务从“完全不可用”变成“可控地推进”。

这些复杂度是值得的。

但也有很多复杂度只是工程焦虑的产物。

我们害怕某个边界情况,于是设计一个完整机制。

害怕机制失败,再设计一个补偿机制。

害怕补偿机制不够,再设计一个监控机制。

最后,系统确实考虑得很全面,但已经没人能真正理解它。

这类复杂度不会增加用户信任,反而会降低系统可信度。

克制也是产品能力

克制不是少做事。

克制是知道什么复杂度值得保留,什么复杂度应该被砍掉。

在 AI 产品里,这种能力会越来越重要。

因为 AI 很擅长扩展方案。

它会补充边界、增加异常处理、设计更多状态、生成更多配置、提出更多二级能力。

这些能力有时有价值。

但产品负责人必须判断:

  • 当前版本真的需要吗?
  • 用户是否能理解?
  • 团队是否能维护?
  • 失败后是否能解释?
  • 这个复杂度是否服务主路径?
  • 有没有更简单的退化方案?

用户喜欢的产品,往往不是功能最多的产品,而是让人感觉轻松、稳定、可信的产品。

软件最终不是给架构图使用的,是给人使用的。

对 Plato 的启发

这篇文章对 Plato 的意义很直接。

Plato 不是要把 AI 工作台做成一个“功能越多越好”的系统。

它更应该成为一个复杂度治理产品。

启发面要减少用户不知道如何使用 AI 的复杂度。

控制面要减少 AI 执行过程不可控的复杂度。

信任面要减少用户无法判断结果是否可靠的复杂度。

文章、项目、任务、上下文、执行记录、用户确认、失败恢复,都不应该只是功能列表。

它们应该共同回答一个问题:

用户如何更稳定地把一个模糊目标,推进为可信结果?

如果一个设计不能帮助这个问题,它就应该被延后、简化或删除。

这不是保守。

这是让系统长期可迭代的前提。

结论

复杂度不是绝对的坏东西。

没有复杂度的软件,通常也没有足够的能力。

但复杂度必须被管理,必须被审计,必须被证明值得。

每一个复杂设计都应该回答一个问题:

它消耗了系统的理解力、测试力和维护力,换来了什么?

如果答案不清楚,就应该停下来。

软件工程最难的地方,不是把系统做复杂。

复杂很容易。

真实世界会推着我们走向复杂。

难的是在复杂不可避免的时候,仍然保持清醒。

少一点握手,多一点收敛。

少一点局部真相,多一点事实源。

少一点完美机制,多一点可理解的退化。

少一点架构炫技,多一点用户价值。

复杂度是软件的死敌。

而克制,是工程系统最稀缺的美德。