多易必多难:AI 真的让事情变得容易了吗?

我最近越来越强烈地感觉到,AI 并不是简单地让事情变容易了。

更准确地说,AI 让“做出一个东西”变得容易了,却没有让“想清楚一个东西”变得容易。它降低了局部实现的成本,却没有降低系统设计、需求澄清、边界定义、异常处理和长期维护的成本。甚至在某些时候,正因为局部实现太容易,反而会让人误以为整体问题也很容易。

这就是老子说的:“轻诺必寡信,多易必多难。”

这句话放在 AI 时代,几乎有一种新的技术含义:当我们越来越容易承诺、越来越容易实现、越来越容易生成 demo、越来越容易把一个想法变成页面、接口和代码时,真正的困难并不会消失。它只是从开发阶段转移到了设计、测试、生产和维护阶段。

而且,藏得更深。

一、从 WebDAV 同步说起

我之前给一个 Web 应用引入 WebDAV 同步时,一开始觉得这件事很简单。

不就是同步吗?

本地有一份数据,远端有一份数据。远端新,就拉下来;本地新,就传上去。再加一点时间戳判断,似乎事情就结束了。

但真正做起来才发现,完全不是这么回事。

第一次实现时,逻辑看起来对,但同步结果不稳定。有些场景下本地覆盖远端,有些场景下远端覆盖本地,某些修改会被错误判断为旧数据。后来我又改,改完以后看似解决了一个问题,却在另一个场景引入新的问题。再后来,甚至因为错误实现丢过数据。

最后我不得不把之前的实现撤销。

这个过程给我的感受非常深:我以为同步很简单,是因为我把“同步”这个问题想得太粗了,只作为消费者感受过,但从未自己实现过。我只看见了上传和下载,却没有想清楚同步真正要解决的状态问题。

同步不是两个文件之间的简单复制,而是三个状态之间的关系判断:

本地现在是什么?

远端现在是什么?

我上一次确认过的共同基准是什么?

如果没有这个基准,就无法判断一个变化是“本地新增”,还是“远端删除”;无法判断一个冲突是“应该覆盖”,还是“应该提示用户”;无法判断一个失败是“可以重试”,还是“必须中止”。

这就是后来我才做出来的三相同步。

它不是某个 if else 写得更漂亮,而是重新定义了问题。同步不是“比较本地和远端”,而是“基于共同基准,判断本地变化、远端变化和冲突关系”。有了这个模型,再去写代码才有意义。没有这个模型,AI 可以帮我写出很多看起来合理的代码,但每一版都可能只是在局部场景下成立。

这件事让我意识到:很多软件问题的难点,不在于代码本身,而在于“问题到底是什么”。

AI 很擅长根据一个已经清晰的问题生成实现,但它很难替你承担“问题尚未澄清”时的系统判断。尤其是当你自己也没想清楚时,AI 生成的代码往往会非常流畅、非常像样、非常有迷惑性。

它不是不会写。

它是太会写了。

会写到让你误以为事情已经想清楚了。

二、AI 让 demo 变容易,也让混乱变容易

过去,产品经理提出一个想法,常常会被实现成本挡住。

“加个图吧。”

“加个状态吧。”

“加个按钮吧。”

“这里能不能智能一点?”

以前开发可能会说:时间不够,要排期,接口还没有,数据来源不明确,先别做。

这些话听起来像阻力,但它们客观上也起到了一种过滤作用。很多未经澄清的想法,会因为实现成本高而停留在讨论阶段。它们没有立刻变成承诺,也没有立刻进入系统,这些想法反而因为更长时间的思考和澄清而变得健壮,成为真正可落地的工程实践。

但 AI 出现之后,这道过滤变弱了。

前端可以很快做出页面,后端可以很快补出接口,CRUD 可以生成,图表可以生成,字段可以生成,甚至连需求说明、测试用例、接口文档都可以生成。

于是一个危险的错觉出现了:

既然 demo 已经出来了,正式功能应该也差不多。

但这两者之间隔着很远。

demo 证明的是“这件事看起来可以发生”,正式功能要求的是“这件事在真实世界中稳定、可解释、可回滚、可维护地发生”。

前者只需要局部成立,后者需要系统成立。

AI 降低的是前者的成本,不是后者的成本。

更麻烦的是,当所有人都能快速做 demo 时,组织中的问题会被放大。原来由于对需求思考不足导致的需求混乱、边界不清、评审走形式、验收口径缺失,现在都可以被 AI 暂时掩盖。大家看起来都在推进,页面也出来了,接口也出来了,材料也出来了,好像效率很高。

但这些东西如果没有经过真正的澄清,只是在堆积未来的风险。

AI 被用来弥补对需求思考不足导致的生产力低效,但它也会埋下新的祸端:它让没有被想清楚的东西,更快地进入系统。

三、软件项目里的“多易必多难”

这在软件项目中尤其明显。

一个需求来了,AI 可以帮你拆需求。前端可以让 AI 生成页面。后端可以让 AI 生成接口。数据库表可以让 AI 设计。联调问题可以让 AI 修。甚至测试用例也可以让 AI 补。

于是大家都觉得:这不挺快的吗?

但真正的问题往往不在这里。

真正的问题在于:

这个需求到底要解决什么问题?

这个字段的含义是什么?

这个状态从哪里来?

状态之间能不能互相推导?

异常时如何展示?

用户看到这个状态后会采取什么动作?

这个动作会不会反过来改变系统状态?

旧数据怎么兼容?

失败怎么回滚?

并发怎么处理?

后续谁维护?

这些问题不澄清,代码越快,风险越高。

AI 生成代码还有一个更隐蔽的问题:它往往让代码在局部看起来更完整,却让系统在整体上更难维护。

因为 AI 通常是在有限上下文中工作。它看到一个函数,就倾向于把这个函数补完整;看到一个接口,就倾向于把这个接口补完整;看到一个页面,就倾向于把这个页面补完整。它很擅长让眼前这块逻辑自洽,却未必知道系统中已经存在的抽象、约定、边界和历史包袱。这种特性是 LLM 的先天缺陷,不会因为 RAG、Skill、Prompt 和 Loop 上下文工程而有所改变,反而会把问题藏的更深。

于是,一个需求可能被快速实现出来,但实现方式并不真正嵌入原有系统。

该复用的逻辑被重新写了一遍。

该统一的错误处理被局部特殊化。

该抽象成状态机的流程被几个布尔值拼起来。

该沉到服务层的规则被写进了 handler 或页面组件。

该依赖数据库事实的判断被前端临时推导。

该由统一模型表达的概念,被不同模块用不同字段名、不同语义各自实现了一份。

这些代码短期都能跑,甚至看起来很清楚,但它们会逐渐把系统切碎。每一处局部实现都像是合理的补丁,但补丁之间没有共同的中心。等后续再改需求时,开发者会发现真正困难的不是改代码,而是先判断:这个逻辑到底散落在哪里?哪个才是事实源?哪个是历史兼容?哪个是当时为了跑通局部场景临时生成的?

这就是 AI 代码难维护的根源。

它不是因为 AI 写得一定差,而是因为 AI 很容易在局部上下文中写得太顺。顺到每一段都像对的,合起来却没有整体结构。人类写烂代码时,常常烂得很明显;AI 生成的问题代码,反而常常烂得很体面。命名合理,结构完整,注释齐全,错误处理也有,但它可能仍然偏离了系统真正的抽象。

四、测试也很难发现错误抽象

AI 时代软件开发最危险的地方在于:缺陷不再表现为粗糙,而表现为完整。

页面完整,接口完整,代码完整,文档完整,测试也完整。

但整个东西可能仍然是错的。

比如一个字段被快速补上,看起来只是多返回一个状态;但这个状态可能和已有状态语义重叠,后续就会出现两个相似字段并存。

比如一个前端图表被快速做出来,看起来只是展示性能数据;但它可能默认了错误的采样周期、聚合口径和空值含义,用户看到以后会形成错误判断。

比如一个同步逻辑被快速生成,看起来已经处理了上传、下载和冲突;但如果它没有共同基准的概念,就无法真正区分本地修改、远端修改和删除冲突,最后就可能在某个边界场景下丢数据。

这些 Bug 往往不是单点 Bug,而是抽象 Bug。

单点 Bug 可以通过测试发现,抽象 Bug 却很难。因为测试通常验证的是“这个实现是否符合当前预期”,但如果当前预期本身就是错的,测试只会把错误固定下来。AI 甚至可以继续根据错误抽象生成更多测试,让整个系统看起来更完整。

测试可以覆盖路径,却很难覆盖错误的抽象。

测试可以发现 bug,却很难发现一个需求从定义开始就是半成品。

这也解释了为什么 AI 时代的软件风险会更晚暴露。很多问题不是在开发时暴露,而是在联调、转测、生产、用户真实使用、下一次需求变更时才暴露。那时问题已经不再是“改一段代码”,而是要推翻前面的假设、承诺、设计和测试。

这就是“民之从事,常于几成而败之”。

几成而败,最伤。

因为这时所有人都已经投入了成本,所有人都觉得快完成了,所有人都不愿意承认前面的问题。于是纠偏不再只是改代码,而是推翻承诺、推翻认知、推翻进度、推翻情绪。

这时再改,就难了。

五、不是反 AI,而是反轻易

我并不是反对 AI。

恰恰相反,我自己长期使用 AI,也承认 AI 对软件开发的巨大价值。很多过去需要大量体力劳动的东西,现在确实可以更快完成。很多过去因为实现成本太高而无法尝试的想法,现在可以先做原型验证。这是好事。

但问题在于,AI 不能替代“犹难之”。

AI 可以让我们更快地写代码,但不能替我们决定什么不该写。

AI 可以让我们更快地做 demo,但不能替我们判断 demo 是否应该进入正式版本。

AI 可以让我们更快地补字段,但不能替我们定义字段语义。

AI 可以让我们更快地生成测试,但不能替我们澄清什么才是正确行为。

AI 可以让我们更快地响应需求,但不能替我们判断这个需求是否已经成熟。

真正的问题不在 AI,而在“轻易”。

把没有想清楚的问题交给 AI,很容易得到一个看起来已经想清楚的答案。这才是危险所在。

老子说:“图难于其易,为大于其细。”

这句话很容易被误解成:趁事情简单的时候赶紧做。

但我现在越来越觉得,它不是鼓励轻易动手,而是提醒我们在问题还没有膨胀时,先找到真正的线头。

所谓“易”,不是看起来容易的实现,而是问题尚未复杂化时的澄清机会。

所谓“细”,不是随手补一个细节,而是系统中最小但最关键的约束。

就像 WebDAV 同步,真正的“细”不是上传下载函数怎么写,而是三相同步中的基准状态。这个东西很小,甚至一开始看不见,但它决定了整个同步逻辑是否成立。

就像一个软件项目,真正的“细”不是某个按钮、某个字段、某个图表,而是需求边界、状态模型、数据口径、异常语义和验收标准。

这些东西如果早期不澄清,后面就会变成大问题。

所以,AI 时代的工程纪律,可能不是更快,而是在某些地方故意慢一点。

需求进入开发前,慢一点,问清楚它解决什么问题。

demo 进入正式版本前,慢一点,问清楚它缺哪些系统约束。

接口新增字段前,慢一点,问清楚这个字段的语义、来源和生命周期。

状态展示前,慢一点,问清楚用户看到它以后会做什么。

AI 生成代码后,慢一点,问清楚它是不是只满足了局部上下文。

这不是保守,也不是反效率。

这是为了避免把难题推迟到生产环境。

真正成熟的 AI 使用方式,不是“想到什么就让 AI 做什么”,而是先用人来守住问题边界,再用 AI 提高实现效率。

换句话说:

AI 应该放在“执契”之后,而不是放在“定契”之前。

契约未定,AI 越快,越乱。

契约已定,AI 越快,越强。

六、结语:容易不是问题,轻易才是问题

AI 当然让很多事情变容易了。

但它没有让复杂系统本身变简单。

它没有让需求天然清楚。

它没有让业务自动合理。

它没有让状态模型自然正确。

它没有让测试覆盖错误抽象。

它没有让组织管理能力自动提升。

它只是让想法更快显形,让代码更快生成,让 demo 更快出现。

如果我们因此以为事情真的变简单了,那就是“多易”。

而多易,必多难。

真正应该追求的,不是因为 AI 而轻易,而是因为 AI 更要犹难。

开发越容易,越要想清楚什么不该开发。

生成越容易,越要想清楚什么不该生成。

demo 越容易,越要想清楚什么不能因为 demo 像样就进入承诺。

AI 时代最重要的能力,可能不是会不会使用 AI,而是能不能在 AI 让一切看似容易的时候,仍然守住那一点难。

因为真正能避免后患的,不是更快地做出东西。

而是在东西尚未成形时,就知道它为什么难。