简单至上:使 AI 生成代码易于维护的架构约束
简而言之:人工智能代理可以生成通过测试且看起来熟悉的代码,但最后10%的理解、审查和维护工作却变得异常困难。通过应用Rich Hickey在其演讲“化繁为简”中提出的原则,我们的团队将架构限制为每个问题只保留一种解决方案,从而使人工智能生成的代码易于审查和维护。
两个月前,YouTube 的推荐算法向我推荐了 Rich Hickey 在 2011 年 QCon 大会上的演讲“简单易学”。
我们都经历过人工智能编码代理的这个问题,我现在称之为人工智能 90/10 问题:代理可以生成语法正确、通过测试的代码,让我们以惊人的速度完成 90% 的工作,但剩下的 10%,也就是人类必须理解、审查和维护代码的部分,却变得不可能完成。
正如希基所说:“我们只能希望把我们理解的事物变得可靠。”而且通常情况下,这其中存在权衡:当一个系统不断发展以使其更具可扩展性和动态性时,理解它并判断其是否正确可能会变得更加困难。
人工智能90/10难题:为什么速度会变成瘫痪
AI 代理是优化机器,在生成过程中倾向于选择阻力最小的路径,而不是在审查过程中选择阻力最小的路径。
AI代理生成代码时,会针对以下方面进行优化:
✅ 语法正确性
✅ 测试文章
✅ 熟悉的句型模式
✅ 只需少量提示
但你必须接受针对以下情况优化的代码:
❌ 人类理解能力
❌ 变更速度
❌ 可调试性
❌ 长期维护
这就造成了一个实际问题:人工智能代理生成代码的速度越快,团队审查代码的速度就越慢。
根本原因在于:我们没有用架构来约束人工智能。我们给了它无数种解决问题的方法,然后又纳闷它为什么会选择最复杂的路径。
简单与易用:人工智能友好型架构的基础
Hickey 的核心观点改变了我对 Agent 生成代码的看法:
简单:“一折,一编,一扭。”指事物之间没有交错或编织在一起。简单是客观的,你可以数出辫子的数目。正如希基解释的那样,“简单”一词的词根是“sim”和“plex”,意思是“一扭”,与“复杂”相反,“复杂”指的是“多扭”或“编织在一起”。
简单:“触手可及,近在咫尺。”指熟悉的事物,你已有的工具,与你目前的技能相符。简单是相对的,对你来说容易的事,对我来说可能很难。“简单”一词源于拉丁语,与“邻近”有关,意为“靠近”和“在附近”。
人工智能倾向于选择容易的方案而不是简单的方案,因为它优化的是生成速度,而不是维护清晰度。
我的智能体生成的是一些熟悉的模式(简单),却造成了错综复杂、环环相扣的局面(并不简单)。解决方案并非让智能体更智能,而是让我们的架构更具约束性。
可维护的代码有一个显著特点:非常容易审查。
当解决问题只有一种方法时,审查就变成了模式匹配,而不是考古学。
五项原则:希基的蓝图
从演讲中,我提炼出了五个核心原则,这些原则成为了我软件架构的约束条件:
原则一:避免冲突
“Complect”的意思是交织、缠绕、编织。“Complex”的意思是编织在一起、折叠在一起。“Simple”的意思是一次折叠、一次编织、一次扭转。
混淆是指将简单的组成部分交织在一起,形成复杂的关系。每次混淆两个概念,你就会失去独立思考它们的能力。正如希基所指出的:“混淆会导致糟糕的软件。”
🚀试试 AI Shell
您的智能编码助手,可无缝集成到您的工作流程中。
登录 Forge →
原则二:将状态与价值分离
“国家融合了价值和时间。”
当你把某物的本质(价值)和它的变化时间(时间)混为一谈时,你就会创造出一些无法单独进行推理的产物。
原则三:数据就是数据,而非对象
“信息很简单。你对信息唯一能做的就是毁掉它。”
对象包含状态、标识和值。它们将信息隐藏在方法和封装之后,使得无法对数据进行通用操作。
原则 4:函数优先于方法
“方法包含函数、状态和命名空间。”
方法将依赖项隐藏在它们所附加的对象中。纯函数则将所有依赖项显式化。正如希基所解释的,方法将函数逻辑与对象状态和命名空间问题交织在一起。
原则五:组合优于继承
“继承会使类型复杂化。它表明这两种类型是复杂的,这就是它的含义。”
继承意味着这些类型相互交织。组合功能允许你组合各种能力,而不会使它们相互冲突。
让建筑更具约束性:一种制胜之道
解决方案并非让AI更智能,而是让架构更具约束性。我们的团队没有给AI代理提供上千种实现功能的方式,而是设计出只留下一种显而易见的方法的系统。
这种方法改变了人工智能生成问题:当只有一个有效模式可遵循时,人工智能自然会生成可维护的代码,因为它别无选择。
以下是我们团队如何将每个原则转化为架构约束的:
约束条件 1:数据不可变,零异常
将状态与值分离。所有领域实体都是不可变的。当只有一种改变状态的方法(返回一个新值)时,人工智能就无法生成会使审查复杂化的隐藏变更。
约束条件 2:数据与行为分离
数据就是数据,而不是对象。数据结构只包含数据。行为存在于无状态服务中。
约束条件 3:显式错误上下文,不抛出异常
避免混淆。每个错误都必须完整地说明哪里出了问题。当错误明确且与上下文相关时,代理就无法忽略故障或创建掩盖问题的通用错误处理程序。
约束 4:纯函数相对于方法
函数优于方法。业务逻辑必须是纯函数,并且依赖关系必须明确。当所有依赖关系都明确时,人工智能就无法隐藏对象状态或方法链中的复杂性。
约束条件 5:组合优于继承
组合优于继承。能力通过聚焦特性进行组合,而非继承。当类型采用组合而非继承时,人工智能无法创建包含不相关关注点的复杂层级结构。
希基的建议很明确:“加个队列进去。队列是解决这个问题的办法。”他强调,队列通过将“何时”和“何地”分离来帮助解耦组件,从而避免对象之间直接连接带来的复杂性。
服务之间的协调只能通过事件队列来实现。当服务不能直接相互调用时,人工智能就无法创建时间耦合,从而避免了系统无法被推理的情况。
约束如何教会人工智能更好的模式
有趣的是,我们的架构约束不仅加快了代码审查速度,还能主动引导我们的智能体生成更优质的代码。每次智能体遇到我们的模式时,它都会学习并将其添加到内存中。在Forge中,我们称之为自定义规则。其他智能体则称之为内存、规则等等。
- 关注点分离可防止功能纠缠。
- 显式依赖关系使测试变得非常简单。
- 不可变数据可以消除整类错误。
- 纯函数可预测地组合
- 数据即数据,支持通用操作
人工智能已经通过自定义规则/内存将我们的限制条件内化。
如果你遇到了人工智能90/10问题,以下是我们总结的经验:
1. 约束生成,而非指导审查
不要试图教你的人工智能生成更好的代码。设计一种架构,让糟糕的代码根本无法表达。
2. 一种获胜方式
对于人工智能可能遇到的每一个问题,都应该只有一个显而易见的解决方案。多种有效方法会增加审查的复杂性。
3. 好的代码 = 可审查的代码
对于人工智能生成的代码来说,唯一重要的指标是:“人类能多快验证代码的正确性?”
4. 通过结构进行教学
你的AI更多地是从代码结构而非系统提示中学习。确保你的架构体现了你想要复制的约束条件。
结果:约束创造自由
我们实施的架构限制措施前期投入较高,但回报却非常丰厚:
- 审核速度提升:过去需要数小时才能完成的工作,现在只需几分钟的模式匹配即可完成。
- 加快了新成员入职流程:由于每个问题只有一种解决方法,新团队成员可以立即做出贡献。
- 人工智能学习能力提升:我们的智能体开始生成更优质的代码,因为我们的架构教会了它们良好的模式。
结论:解决90/10问题
AI 90/10 问题不是当前 AI 代理的局限性,而是架构设计的缺陷。
当你的架构通过设计限制 AI 的行为时,AI 就成为你构建可维护软件的伙伴,而不是造成技术债务的对手。
在人工智能时代,获胜的团队不会是那些拥有最复杂的人工智能代理的团队,而是那些拥有最严格的架构的团队。
好的代码有一个显著特点:易于审查。当你设计约束条件,使得每个问题只有一种解决方案时,代码审查就变成了模式匹配,而不是考古挖掘。
文章来源:https://dev.to/forgecode/simple-over-easy-architectural-constraints-that-make-ai- generated-code-maintainable-4o77

