ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI写代码为何总卡局部最优?架构师把三类隐性知识喂给它

AI写代码为何总卡局部最优?架构师把三类隐性知识喂给它 1. AI 写代码为什么总是卡在局部最优先讲个我自己的观察。最近半年我一直在用 AI 辅助写业务代码、重构老模块、补测试项目推进速度确实快了不少但每次代码评审的时候总有一种说不出来的别扭。单看每个函数逻辑清晰、命名规范、注释到位甚至单元测试都给好了可一旦放回整个系统里看就会发现它跟周围的模块像是两个世界观的人硬凑在一起——旧的幂等方案被绕过去了本该复用的公共方法变成了复制粘贴异常处理风格跟团队惯例完全不在一个频道上。这种状态用架构师圈子里的话说就是局部最优。每一段 AI 生成的代码都像是一个聪明人在短视地解一道局部难题成绩单上写的全是A等拼进整个系统的大拼图里发现颜色对不上、边缘卡不住。我把这个困惑发到了合肥同盟架构师群里本来只想吐个槽结果话题一下子炸了。几十个人聊到凌晨我随手统计了一下光那一个话题就跟了 421 条消息。群里有个老哥说得特别到位AI 写代码的局部最优本质上是它的世界只有眼前的上下文。架构师的价值恰恰在于我们脑子里有一套它永远看不到的东西。这句话点了题。我把那 421 条消息翻了三遍结合自己带团队、做架构评审、用 AI 写生产代码的实际经验把群里提到的、大概率从未被系统写进任何文档和论文的隐性知识梳理成了三大类。这篇文章就围绕这三类知识展开顺便把如何把隐性知识喂给 AI这件事的实操方法也一并写了。不管你是正在用 AI 提效的资深开发还是刚接手老系统的新人这些东西都应该能帮你少走不少弯路。1.1 训练机制决定了 AI 天然倾向于交差理解 AI 为什么总在局部最优得先理解它的训练目标。大模型训练的核心逻辑是给定上文预测最合理的下文而这个最合理在语料里被统计成了高概率的 token 序列。换句话说AI 生成代码的过程本质是在模仿大多数人在类似情况下会怎么写而不是整个系统在当前约束下最该怎么做。这两个目标差别大了。大多数人的代码——包括 GitHub 上的开源代码、Stack Overflow 上的回答——本身就是在信息不完整的情况下写出来的天然带有局部性。AI 从这些语料里学到的不是系统的整体架构也不是业务的发展脉络而是一个函数该怎么写才像样的模式。于是我们看到了典型的场面给出一个需求AI 能在几秒内生成一个结构完整、逻辑自洽的实现。但它不会问你这个函数是要跑在分布式环境里还是单机进程里有没有并发访问数据一致性要求到什么级别历史数据兼容不考虑吗这些问题不在提示词里它就从统计规律里拿一套默认假设而那套默认假设通常是教科书级的理想环境。群里有个做支付系统的兄弟举的例子特别直观他让 AI 写一个订单号生成器模型给出了一串看起来无懈可击的规则——时间戳加随机数加机器号。单看每个字符都合理但放到他那套日均几千万单的系统里时间戳精度不够、随机数冲突概率集中在毫秒窗口、机器号没有全局分配机制这些全是致命的。AI 哪懂这些它只知道绝大多数的订单号都是这么生成的。1.2 局部最优的三种典型表现把群聊里散落的吐槽归拢一下AI 写代码陷入局部最优的表现可以归纳成三类。第一类是沿用表象丢掉约束。AI 会从已有代码里提取样式——比如命名风格、缩进习惯、注释格式——但很难理解这些样式背后的约束。你们的项目里到处是xxxService、yyyManager这种分层命名AI 就能照着编出一堆新类名可你那个OrderManager其实是历史包袱新代码应该走OrderService的流程它看不出来。第二类是本地正确全局冲突。AI 生成的新模块在自身接口上挑不出毛病参数校验、返回值、异常抛出都合理。但它的数据流跟现有系统的存储方案、消息队列、缓存结构搭不上。最典型的就是事务边界AI 会在一个新方法里顺手开启事务而那套方法实际是被外部定时任务分页调用的每页一条事务的开销直接拖垮性能。这种冲突跑测试往往测不出来等上了生产才爆发。第三类是追求通用忽略演进。AI 看到用户就生成一套完整的 CRUD 接口看到配置就塞一个字典表。这没错但它不会判断这些场景到底需不需要扩展性。很多内部工具型的配置一套枚举加常量就够用了AI 偏偏给你建四张表、三层抽象、五种缓存策略。结果是过度设计替掉了应有的克制代码量翻倍维护成本也被动抬高了。这三类表现背后的共性是 AI 缺少两样东西系统的全局视图以及团队的演进历史。前者可以通过给它更完整的上下文来缓解后者则几乎只能靠人来补。而这正是那 421 条群聊里大家反复讨论的从未被写下来的知识。2. 从 421 条群聊里捞出来的三类未被写下来的知识架构师这个群体工作里产出最多的其实不是代码而是判断。判断背后的依据很少写在系统设计文档里更不会进接口注释。它们散落在评审会议录音、聊天记录、个人笔记和大脑皮层的皱纹里。我把那个晚上以及后来翻完的 421 条群聊消息做了归因分析剔除掉情绪输出、表情包和寒暄之后剩下的有效信息基本都指向三类隐性知识。这三类知识从来没有被写进任何公开教程——因为写下来的那一刻它就已经过时了。但正是它们决定了架构师和 AI 在同样输入下的输出质量差异。2.1 第一类演进约束——为什么当初没这么写群里有个兄弟抛出一个灵魂拷问你去翻任何一个项目的 Git 历史能看到每一次提交改了什么但你永远看不到开发者当时为什么不做那个看起来更优的方案。这话太真实了。我们看老代码常常会觉得这写得真烂为什么不这样那样重构一下——等真正动手才知道当时不重构是因为线上跑着一个不能停的旧协议或者核心团队里没人会那个新技术栈或者重构方案评审了三个月被老板一句先把功能上了再说给压了下来。这类知识我称为演进约束。它记录的不是系统是什么而是系统为什么长成现在这样。AI 在训练语料里能学到海量应该怎么做的范式却学不到你的系统里这里不能这么做的禁令。群里一位做制造执行系统的架构师讲了一个例子AI 帮他生成了一段代码用 Redis 分布式锁保护库存扣减从技术上无懈可击。但他们那条产线的上位机系统跟调度系统之间用的是内部 UDP 协议根本没有稳定连接Redis 锁在极端断连场景下反而会永久卡死流程。这种约束在哪本技术书里能学到只存在于当年事故复盘时写下的一行备注库存模块禁用外部依赖。2.2 第二类边界共识——这是谁的代码别乱动第二类隐性知识更微妙它跟组织有关。每个中型以上的项目代码库里都藏着隐性的领地——哪些模块是核心团队的心头肉哪些模块是实习生练手的遗迹哪些模块看着没人维护但动一下就会炸出三个负责人。这种边界共识平时不会写进 ADR架构决策记录也不会出现在代码注释里。它存在于团队老成员的脑子里靠的是我问过张三这类口头传承。AI 完全感知不到这一层。群里一个搞电商中台的兄弟贡献了一个经典案例他们的促销模块和订单模块之间有一个隐藏约定——促销模块的返回值里永远附带一个traceId虽然是冗余字段但下游报表系统直接拿它当分组键。AI 在重构促销接口时按照常规优化思路把这个字段标记为 deprecated 并移除结果第二天报表组的人就找上门来了。代码在接口层面没有任何问题问题出在代码之外的协作默契。这类知识的本质是组织的记忆。它不在代码库里而在组织流程和人际网络中。你用 AI 重构任何一块代码如果只盯着代码本身就一定会踩进这种非代码炸弹。2.3 第三类风险偏好——能跑和能扛是完全两回事第三类知识最难量化也最容易被技术出身的人忽视。我称之为风险偏好——团队在做对的事和少惹麻烦之间的真实取舍。教科书上说技术债要还架构要演进代码要重构。但真实系统里很多团队选择的策略是核心链路能不碰就不碰非核心模块能不动就不动因为每一次改动都是事故概率窗口的一次放大。这个偏好写在任何一个规范文档里都显得不太专业但它才是大多数系统多年稳定运行的真相。AI 没有这种偏好。你让它优化一段老代码的性能它会大刀阔斧地把一万行的历史遗留模块拆成五个新类然后自信满满地告诉你测试全过了。但你的团队评估下来这次改动引入的风险远高于它能带来的收益。群里一位做保险核心系统的老哥说得很直白在我们这能不能上线不看测试过了没看的是负责这个模块的老刘敢不敢签那个字。这类隐性知识直接影响了我们在实践里怎么用 AI不是让它帮你做冒险式重构而是让它在你划好的安全边界里做增量优化。把风险偏好写成约束条件AI 才能真正帮你干活而不是帮你制造事故。3. 把隐性知识变成 AI 的上下文我的实操方案这三类知识说完了问题来了怎么把它们系统性地喂给 AI光在提示词里写注意保持全局一致性是没用的AI 会把这句话当成装饰词处理。我在项目和团队里试了大概一个月的不同方案踩了不少坑最后沉淀下来两套可复用的方法。3.1 用 ADR 给 AI 补历史课第一套方法其实特别朴素把你们项目的架构决策记录ADR从人看的文档变成 AI 能消费的上下文。ADR 本身不是什么新概念就是一张卡片记录一次重要的架构决策背景是什么、当时有哪些可选方案、为什么选了现在这个、放弃了哪些备选、后果是什么。很多团队写了 ADR 就束之高阁没人看。但 AI 时代ADR 的价值被重新激活了——它成了 AI 理解系统约束的最佳载体。我做的很简单把项目里所有 ADR 整理成一个ai-context目录每个文件用统一的模板控制在 300 字以内专门给 AI 读。核心字段是三条约束范围这个决策管哪些模块、禁选方案哪些路走不通、技术债状态哪些地方欠着账暂时别碰。prompt 里直接引用这个目录的做法是我在跟 AI 协作时最顺畅的模式。它会显著降低 AI 生成代码后跟既有架构打架的概率。比如我参与的一个物联网项目设备接入模块有一个延续了三代的 adr。第一代选了 MQTT 作为主协议第二代在边缘节点加了本地缓存第三代明确放弃了对设备端 SDK 的加密改造。AI 在帮我们写新的设备监控模块时如果上下文里有这三条 ADR它就不会顺手给设备端加一个根本不存在的加密握手流程。我给出的标准提示词结构是这样的你是这个项目的资深架构师。实现以下需求前先阅读 /ai-context/ 目录下的所有 ADR 文件 把你认为与本需求相关的约束提取成 checklist。每个 check 对应一条 ADR 原文编号。 只有在 checklist 内不冲突的前提下你才可以开始写代码。 如果发现 ADR 之间互斥立即停止列出冲突项不要自行裁决。这个指令的核心不是让 AI 做事而是让 AI 暂停。它用 ADR 建立了一个先校验、再动手的防线把隐形知识从人的脑子里搬到了 AI 的决策路径上。3.2 三层提示词模板让 AI 在约束内做推理第二套方法是把群聊里大家提出的各种喂上下文技巧整合成一个可复用的三层提示词模板。我用了很长时间可靠度比裸提问高出太多。三层结构简单说就是背景层、禁触层、目标层强制 AI 在本就局部最优的推理路径上先建立全局约束的边界。背景层写系统的基本面核心业务逻辑、模块血缘关系、运行环境。这段的目的是让 AI 知道自己在哪个宇宙里工作避免拿默认软件工程假设直接套到你们项目上。禁触层是整个模板的核心。把第一类演进约束和第二类边界共识里提到的内容原话写进去。这个位置我推荐写得凶一点以下模块禁止做接口签名变更历史数据格式保持只读不要为促销模块的任何返回值引入新依赖诸如此类。AI 对负面指令的敏感度远高于它对请保持兼容性这类模糊要求的理解。目标层再写清楚当前要干的活尽量只用一句话收束任务本身不给 AI 太多自我发挥的空间。我来贴一段我在生产项目里实际用过的模板做了脱敏处理【背景层】 这是一个航空货运结算系统核心链路订舱 - 配载 - 报关 - 结算。 运费计算模块位于结算端依赖上游订舱系统的运价快照快照不可变更。 系统部署在内部私有云数据库为 Oracle 11g不允许引入新的中间件。 【禁触层】 1. 订舱接口货物类型字段 (cargoType) 的枚举值、含义、顺序均不可修改 已有 5 个下游服务按当前顺序做分支判断。 2. 报关模块与海关对接使用加密报文任何涉及报文结构的修改一律忽略。 3. 运价快照按天分区历史分区已有 1.2 亿行数据不得触发全表扫描改造。 【目标层】 实现一个运价试算函数输入订舱单号返回运费估算列表允许误差 ±2%。 要求使用 Python 实现只新增一个模块不修改任何现有文件。这套模板跑了几周最直观的变化是 AI 生成代码被评审打回的次数直接少了六七成。原因不难解释它把架构师脑子的隐形边界硬编码成了 AI 眼里不可逾越的红线。AI 的推理能力虽然没有本质提升但它的视野里终于有了边界局部最优就不再那么容易跑偏成整体离谱。维度裸提问无上下文带三层模板提问编译/单元测试通过率高高代码评审一次通过率低约 20%高约 75%与既有架构冲突概率很高明显降低触碰历史约束概率高极低需要人工返工的工作量大明显减少4. 实战对比同一个需求两种写法的差距光讲方法论有点虚我拿最近帮朋友团队处理的一个真实需求来跑一遍对比。这个场景足够典型需求本身简单但项目里布满了隐性约束正是 AI 最容易翻车的类型。4.1 场景给结算系统加一个限流能力项目背景一个 B2B 电商结算系统订单提交后会触发一系列内部服务调用。最近运营搞了个大促瞬时订单量暴增结算入口偶尔被冲垮。需求是给结算入口加一个简单的限流要求超出的请求直接丢弃不要让内部服务排队。这个需求如果裸丢给 AI十有八九会得到一段基于 Spring 的RateLimiter或 Redis Lua 的限流实现。单看代码正确、优雅、常见。但我在这家公司的架构师朋友用了一个下午跟我梳理出四条隐性约束硬生生把这活儿从20 分钟的 AI 任务变成了需要四个小时打磨的架构改造。第一条约束是结算入口是单实例部署的限流状态存在 JVM 本地就行引入 Redis 反而多一个故障点。第二条入口调用链路过一层加密网关网关有独立限流策略代码层的限流阈值必须跟网关阈值联动否则网关先限流了你还在傻乎乎地放行。第三条现有的错误响应结构里没有定义限流拒绝这个分支下游重试逻辑会把任何非 200 响应都当成系统故障而触发告警。第四条最要命之前某一版架构文档里明确写过结算链路不允许新增任何外部依赖。这条约束写在一份没人看的旧文档里但它是红线。这四条约束AI 看到第一条会踩引入分布式组件看到第二条会忽略双层限流的协调看到第三条会产出会造成误告警的实现看到第四条直接犯规。没有架构师把隐性知识显性化这个需求交到 AI 手里就是一次完美的局部最优表演。4.2 效果复盘带了上下文的 AI 能做到什么程度我用上面那套三层模板把四条约束全部写进禁触层再一次让 AI 实现这个限流需求。这次它给出的方案完全变了个样限流器用了本地ConcurrentHashMap加令牌桶思路不碰 Redis阈值做成配置项标注需要跟网关侧同步配置错误响应新增了一个LIMIT_EXCEEDED分支同时给出了下游重试逻辑的适配建议说明为什么不能复用旧错误码。更让我意外的是它主动在代码注释里标了一行根据禁触层约束第 4 条本实现未引入任何外部依赖。这说明约束真的进入了它的推理路径而不只是提示词里的装饰。这两个版本的差距完全不在编码能力上。裸版本的单测一样能写、能过甚至性能表现也不差。差的是它踩了三条隐性约束上线后轻则误告警重则拖跨结算链路的可用性。而带上下文的版本代码质量是我们作为架构师能签字的水平。这个对比也回答了一个群里反复争论的问题AI 到底能不能替代架构师我的答案是AI 能替代架构师做编码实现但前提是架构师先把脑子里那堆隐性知识结构化地喂到 AI 的上下文里。AI 配合得好不好反过来考验的就是架构师显性化隐性知识的能力。5. 常见问题与排查技巧实录方法讲完落在实操里还是有一堆坑。我自己试错的过程中也总结了一些排查思路这里直接整理成速查表方便你在实际用的时候对照排查。5.1 提示词加了一堆背景输出反而更飘了这是我最早踩的坑。一开始我为了让 AI 有充分的上下文往提示词里塞了十几条背景描述包括项目历史、团队规模、代码风格偏好、技术栈选型原因。结果 AI 的输出质量不仅没提升反而开始各种端水——处处都想照顾到处处都显得虚。后来我发现问题出在背景层的颗粒度上。AI 是概率模型你给的信息越多它的注意力越分散越容易跑偏到某个高频模式的轨道上。背景层应该像拍立得抓关键特征而不是像纪录片事无巨细。我的经验是把背景层控制在三四句话以内且只描述系统事实不描述价值判断。比如结算链路是单实例部署是事实项目组非常看重系统稳定性是价值判断。前者 AI 能直接转化为约束后者只是噪音。5.2 上下文一长最关键的约束反而被稀释跟上面的问题类似但表现形式不同当你用 ADR 目录作为上下文时如果项目里的 ADR 写得太长太全AI 会五五开地对待每条约束结果轻量级的代码风格约束和重量级的架构红线被一视同仁关键信息反而得不到优先响应。解决思路是在 ADR 目录里额外增加一个PRIORITY标记。我给每份 ADR 标注了 P0 或 P1在提示词里明确要求 AI 优先保障 P0 约束。实测下来加了这个标记之后AI 在生成代码时对 P0 约束的遵守率提升非常明显而且几乎不会误判 P1 约束的优先级。5.3 常见问题速查表现象可能原因排查思路AI 生成的代码与既有模块风格脱节缺少边界共识类信息在禁触层加入模块血缘说明标注哪些模块存在协作默契AI 反复推荐被否决过的方案ADR 里的禁选方案记录不完整每份 ADR 增加否决原因字段并在提示词中强调忽略被否方案约束提了但 AI 仍踩线约束描述过于抽象把A 模块禁止改接口改成A 模块的 xxx 方法签名禁止变更这类可检测的硬规则上下文超长引发性能下降ADR 数量太多按本次需求相关度过滤目录只保留关联模块的决策记录AI 生成的测试用例覆盖不到历史坑点缺少演进约束测试用例把历史线上事故对应的回归用例原样加入 ADR 的测试段提示 AI 一并执行最后再说一个我最近才总结出来的技巧。如果你在给 AI 补背景时拿不准哪些隐性知识值得写可以先做一件事把项目里过去半年线上事故的复盘记录翻一遍找出责任人不是写代码的人而是改代码的人的那几类事故。这些事故背后基本都藏着一条从未被写下来的知识。把它们补进上下文里AI 踩坑的概率会以肉眼可见的速度降下来。说白了AI 从来不是不会写代码它缺的是我们脑子里那层为什么不能这么写的分寸感。架构师和 AI 协作得最好的状态不是谁替代谁而是架构师把隐性知识显性化AI 在这个边界里把效率拉满。这大概就是我在那 421 条群聊里感受到的最强烈的东西知识的力量不在于被写下来而在于被用起来。
返回列表