代码能编译通过,和代码能留在线上跑三年,是两回事。最近我越来越觉得,AI写代码的问题不是它不够聪明,而是它总在局部最优上打转——单看它生成的那段代码,逻辑严密、注释规范、甚至性能都挑不出大毛病;可一旦把它放进真实的系统里,你就会发现它根本不认识那些写在人与人聊天记录里的、从未被写进文档里的约束。为了搞清楚这个现象到底卡在哪,我花了两周时间,把合肥同盟架构师群里过去半年值得翻的聊天记录全部过了一遍,筛出421条有效讨论,从这些讨论里整理出了三类几乎不会出现在任何正式文档里的知识。这篇文章就把这三类知识摊开来讲,顺便给出一套把它们喂给AI、让模型跳出局部最优的具体做法。适合正在做代码助手落地、或者对AI生成代码质量头疼的架构师和团队技术负责人,也适合那些好奇“为什么AI写单点功能很强、写系统方案却很轴”的读者。
1. AI的评分标准被你定义了,这就是局部最优的根源
先说清楚“局部最优”在AI写代码这个语境下到底指什么。任何一个大模型,本质都是一个根据输入序列预测输出序列的系统。你给它的提示词,就是它的损失函数;提示词里写了什么,它就认为什么重要。就像你给一个实习生派活,如果只说“把这个限流组件写了”,他会写一个非常好的限流组件——算法正确、边界齐全、异常处理周到——但他不会问你在什么系统里跑、和现有的网关中间件是否重复、压测数据从哪来、超限之后该降级到哪套老逻辑。不是他不负责任,是你给的信息就只能支撑到这个颗粒度。
我把这种现象叫作“局部最优”,其实是借了优化算法里的词。对于一个凸优化问题,梯度下降总能找到全局最优点,但现实中我们面对的几乎都是非凸问题,初始位置、约束条件、步长都会把你带到某个局部极小值。AI写代码也一样:它能在一个“被明确定义的子问题”上做到极致,但系统架构本身就是那个非凸空间,里面充满了没法写进函数签名里的隐式约束。你让AI写一个定时任务,它写得完美;你让AI在存量支付系统里加一个限流组件,它大概率会忽略现有中间件选型、运维上的口径、灰度发布的节奏、以及和已有监控告警的联动方式——这些恰恰是决定一个改动能不能活下去的关键。
更扎心的是,很多团队在用AI的时候,实际是在“强化局部最优”。代码评审只看函数实现,单元测试只验证逻辑正确性,AI写出来的东西只要能过CI就合入。但系统级的问题从来不会在单测里暴露:限流算法没问题,可它把本该由网关统一处理的逻辑散落到各个服务里了;缓存代码没问题,可它无视了已有的缓存一致性方案,自己又发明了一套;重构代码没问题,可它把三年前为了兼容某次紧急需求留下的特殊处理当成“坏味道”给删了。这些都是我在翻那421条聊天记录时反复看到的场景。
所以,要解决AI的局部最优,第一步不是换更强的模型,而是承认一个事实:AI不是不知道全局约束,而是你根本没有把全局约束传给它。全局约束在哪儿?不在PRD里,不在接口文档里,甚至不在架构图里。它在一个完全不被AI看见的地方——在那些老工程师的脑子里,在群聊的争论里,在一次次架构评审的“为什么不行”里。
2. 文档写的是结论,群聊记的是代价:我如何从421条记录里筛出有效信息
我为什么会去翻群聊记录?起因是一次架构评审。我们准备用一个AI代码助手辅助存量系统的改造,最初效果惨不忍睹:它能重构单点代码,但每次都会破坏某个隐式约定。后来我让新人把所有能找到的架构文档都喂给AI,结果还是不行。那天晚上我在群里吐槽了一句“AI根本不认识我们这个系统”,立刻有十几个人跳出来讲了自己团队一模一样的遭遇。当时我就想,问题可能不在AI身上,而在我们的知识形态上。
于是我做了一个实验:把群里过去半年的聊天记录全部导出来,按一套标准筛出有效信息。筛选规则很简单:
| 筛选维度 | 具体条件 | 备注 |
|---|---|---|
| 时间范围 | 最近6个月 | 太老的技术选型参考价值低 |
| 主题关键词 | 选型、方案、降级、重构、兼容、回滚、事故、最优、不可行、不建议、坑 | 用正则批量打标 |
| 议题类型 | 走查、方案评审、踩坑复盘、技术选型争论 | 不含闲聊与资源分享 |
| 排除项 | 招聘、广告、八卦、纯情绪发泄、无技术细节的水聊 | 这些对知识沉淀没有贡献 |
按这个标准筛下来,从几万条消息里共得到421条有效讨论。这些讨论有一个共同特征:它们几乎都是在讲“为什么某个方案不行”。正式文档里写的是“选型A,理由一二三”,群聊里聊的是“我们用B的时候炸了,炸得很难看,原因是什么”。前者告诉你什么是对的,后者告诉你什么是错的,而AI真正缺的是后者——因为模型在训练阶段被灌入了海量的“最佳实践”,却很少有数据教它“这个最佳实践在什么条件下会变成灾难”。
我统计了一下这421条消息的“反对型内容”占比,大约有73%的消息里包含明确的否定判断,比如“这个方案不行”“这里别用XX”“我当时就反对这么搞”。剩下的27%是在否定之后补充的替代方案或补救措施。这个比例让我很惊讶,也让我意识到:真正保命的经验,恰恰长在“反对”里。
还有一个细节值得说。群聊里的高手从来不直接给结论,他们给的是“触发条件”。比如有人问“Redis集群的Slot迁移卡住怎么办”,大多数人会回答重试或者重启,但群里一个老哥的回答是“你先看看是不是有个大Key在迁移,如果有,你重启多少次都没用,得先拆Key”。这句话没有出现在任何Redis手册里,但它是真实场景里最有价值的那类知识。我把这类知识叫作“条件性经验”,它必须附着在一个具体的触发场景上才有意义。后面要讲的三类知识,本质上都是它的变体。
3. 三类从未被写下来的知识,恰恰是AI最缺的上下文
把421条有效讨论反复读了几遍之后,我做了聚类。所有真正有价值的经验,不管表现形式是什么,最终都落进三个筐子里。这三类知识有一个共同点:它们全都不属于“怎么做”,而属于“为什么不那样做”——而这恰恰是AI掌握得最差的部分。
3.1 反选知识:记录“为什么不用B”的排除性决策
群里讨论中最高频出现的结构是:有人提出一个方案,然后一堆人出来阻止。最有意思的是,那些阻止理由极少出现在公开资料里。
举一个典型的例子。有人问“XX中间件最近风头很足,我们在新项目里可以直接上吗?”如果只看官网和社区,答案几乎全是正面的:吞吐高、生态好、社区活跃。但群里紧接着出现了七条回复,每一条都来自真实踩过坑的人:
- “它的吞吐数据是跑在特定硬件上的,你普通虚拟机跑不出那个数。”
- “读写分离的配置很恶心,主从切换有概率丢消息,我们线上遇过一次。”
- “监控面板和现有的告警体系对不上,运维不接受,最后还得自己写Exporter。”
最后这个老哥用了一句话收尾:“东西不差,但你得想清楚你有没有那个团队去填它挖的坑。”这个判断没法从产品文档里获得,因为它是一种“反选知识”:把一个技术在具体组织、具体业务、具体运维条件下会暴露的代价全部列清楚。正式文档只会写“我们选型了A”,没人会把“曾经在B和C上栽过跟头”写进架构说明——因为写文档的目的是证明决策的正确性,而不是记录被否掉的候选方案。
要让AI具备这种知识,得把它结构化。我在团队里建了一张“反选清单”,格式如下:
| 技术项 | 表象优点 | 真实代价 | 触发条件 | 替代方向 |
|---|---|---|---|---|
| XX消息队列 | 吞吐高、社区活跃 | 主从切换丢消息、监控口径不兼容 | 业务量在十万级TPS以下时优势不明显,却要承担运维复杂度 | 用现成的业务数据库队列或云托管MQ |
这张表一旦积累起来,就可以直接变成AI的知识库。你让AI设计方案的时候,加上一句“请参考反选清单中关于XX的条目,避免重复踩坑”,它就能避开那些只看官网资料时很容易掉进去的陷阱。
反选知识为什么值得单列一类,我的体会是:它是三类知识里结构最稳定、最好整理、也最容易量化的。你不需要记录“怎么做”,只需要记录“不做什么”和“为什么不”。这种东西对AI来说是天然的高质量训练语料,因为它的判定边界比“最佳实践”清晰得多。
3.2 取舍知识:没有标准答案的“分寸感”
第二类知识更难整理,因为它根本没有唯一解。群里讨论里最典型的例子是分布式系统的高可用设计。
有人问:“我们订单服务要不要上多活?”群里给出的第一个回答不是“要”或“不要”,而是一个反问:“你一年因为单机房故障损失多少钱?你的团队能扛住多活架构的运维复杂度吗?”这句话背后是一种真实的架构权衡逻辑:高可用不是免费的,它的成本是金钱和人的精力。文档里只会写“系统需要保证99.99%可用性”,但这个数字从哪来、凭什么定这个而不是99.9%、达到这个目标需要投多少人,文档没有答案。
再举一个群里的例子。有人晒出自己的降级方案:为了防止缓存击穿,他准备把所有热点Key的过期时间打散,再把穿透请求全部挡在布隆过滤器前面。听完这套方案,群里一个老哥只回了一句:“你这个量级,把过期时间打散就够了,上布隆过滤器是给自己找麻烦。”这句“够了”就是取舍知识——它的本质是在告诉你:方案的优劣不取决于技术本身多先进,而取决于它跟你的量级、团队、故障容忍度是否匹配。
我把这类知识的特征总结成这样几句话:
- 它没有标准答案,只有“在什么前提下,什么更重要”。
- 它强烈依赖具体参数(业务量级、团队人数、运维能力、故障代价)。
- 它通常以“够了”“不用”“简单点”“先别上”这种口语化判断出现,语气越轻,背后的权衡越大。
要把取舍知识喂给AI,不能只给结论,必须连前提条件和决策标准一起给。比如我整理过这么一段决策基准,直接放到AI检索用的知识库里:
| 业务类型 | 数据规模 | 建议基准 | 理由 |
|---|---|---|---|
| 读多写少的资讯类 | 日均QPS低于1万 | 99.9%可用性,缓存打散过期时间即可 | 故障损失有限,不值得为多余9天可用性投入多活 |
| 交易支付类 | 日均订单10万+ | 99.99%可用性,必须设计降级链路 | 故障损失与客诉成本远超多活投入 |
这段内容本身没有一句是“标准技术知识”,但AI读了之后,它在给你方案建议时就会多一个维度:它不会再无条件地给你“最佳实践”,而是会先问你的量级和承受力。
3.3 系统记忆:现网模块是怎么变成今天这个样子的
第三类知识让我最意外,也是我认为未来AI辅助开发里价值最大的:系统的“历史负债”。
群里有一类讨论特别值得玩味。每次有人吐槽某个老模块代码“写得像屎山”,总有知情者跳出来说一句“这地方写成这样是有原因的”。然后就会带出一段尘封往事:三年前双十一前夜紧急扩容,为了应对流量直接把缓存穿透给关了;两年前一个客户要求定制功能,为了不改表结构硬编码了一个特判;半年前因为某个版本升级兼容性问题,临时在启动脚本里加了一个环境变量开关。
这些原因,永远写不进代码注释里。代码注释最多写“这里逻辑比较绕,请谨慎修改”,但没人敢写“这里改崩过两次,第二次直接线上事故”。架构图只画现状,不画现状是怎么一步步变成这样的。你让AI读代码,它读到的是一堆“看起来不合理”的判断,它就忍不住要“修复”它们。可一旦它修了,就把当年的应急补偿措施给拆了。
群里有个老哥分享过最惨的一次事故:团队用了AI辅助重构,AI发现一个模块里有一段“永假判断”,判定为dead code,自动删掉了。结果那段“永假判断”是专门用来短路一个被弃用但还在线上运行的第三方接口的,删了之后每次请求都会白白等一次超时,线上响应时间直接翻了倍。这个案例在这421条消息里被转述了好几次,每次都会引来一片“我们也遇过”的附和。
针对这个问题,我在团队里做了一个轻量级的“系统记忆”记录:不写在代码注释里,而是按模块建时间线,记清楚每个关键设计决策和应急改动的“起因、当时的约束、现在的状态、解除条件”。比如:
模块:order-service - 2024.03:为兼容XX渠道的订单回调,在handler层增加特判; 解除条件:该渠道迁移到新接口后删除; 注意:AI重构时极易误删,需人工确认。这玩意儿不是给程序员看的文档,是给AI吃的资料。我在做代码生成和重构实验时,把这份“系统记忆”塞进知识库后,AI生成代码时的行为发生了非常明显的改变:它不再贸然删那些“看起来没用”的代码,而会在方案里写明“这段逻辑疑似有历史原因,建议人工确认后再调整”。这个变化,比换什么模型都管用。
4. 把三类知识变成AI能消费的资产:三条实操路径
讲完为什么,总得说怎么办。我踩了不少坑之后,总结出三条实操路径,按投入产出比排序,你可以从最低成本的那条开始试。
4.1 路径一:给AI喂“反选清单”,阻止它踩已知的坑
对现有AI工作流改动最小、见效最快的一条路,是维护一张反选清单,然后把它写进提示词的系统指令里,或者放进RAG检索库中。做法很简单:建一个markdown表格,列出你团队已经排除掉的方案、被排除的原因、触发条件、替代方向。在使用AI生成技术方案或代码时,明确告诉它“以下条目为已知禁区,引用时必须给出依据,不要触碰”。
我贴一个提示词模板供参考:
你是本项目的架构师助手。项目背景与约束如下: 1. 技术栈:Java 17 + Spring Boot + Redis + 自研网关; 2. 反选清单(以下技术/方案已知有坑,禁止默认采用): - XX消息队列:主从切换有概率丢消息,且监控口径与现有告警不兼容; - 布隆过滤器:当前业务量级不需要,会给缓存链路增加不必要的复杂度; - 双机房多活:当前团队规模与业务损失模型不支持; 3. 输出要求:任何方案必须明确引用项目背景中的约束,若你的建议与反选清单冲突,需要先解释理由再输出方案。这一步的本质是给AI定义一个“负向边界”。模型在训练语料里见过太多“某某技术很好”的正面描述,它天生倾向于正面推荐。反选清单的角色,就是强行在它的输出分布上增加一层否定约束。实测下来,加入反选清单后,AI方案中和已知坑位相关的建议减少了70%以上。
4.2 路径二:用“决策基准”替代“最佳实践”,让AI学会提条件
比反选清单更进一步的做法,是把你团队成员脑中的“分寸感”结构化。这件事不需要做到100%准确,做到能回答“我这个场景该不该用某个方案”就够了。
操作上,我建议按“业务类型 + 数据规模 + 团队约束”三个维度来建决策基准表。你不必一开始就建一个完整的大表,而是每次架构评审时,把讨论中反复被提到的权衡点补进去。比如,这周评审定了一件事:“针对读多写少且QPS不到1万的服务,统一不做本地缓存,直接走Redis。原因是本地缓存的一致性维护成本大于它的收益。”把这句话拆成结构化条目,放进决策基准表里,AI下次提方案时就会以它为默认约束。到这一步,你建立的其实是一个“上下文先验”——AI不再是每周一蠢的实习生,而是越来越像一个“知道你们团队口味”的老人。
4.3 路径三:用“系统记忆”对抗AI重构的冲动
第三条路成本最高,但收益也最大,它就是前面提到的系统记忆。我从AI误删dead code事故之后,做了一个强制约定:任何模块,AI介入重构前必须先读一份“模块记忆文档”,里面记录了这个模块的关键历史决策和为什么代码长这样。文档格式不用复杂,按时间轴记流水账就行,关键是记清楚“为什么”。
具体执行上,跟路径一、二相比最大的差别,是它建议单独给AI一个文档作为检索上下文。通常做法是,把“模块记忆”放进代码仓的docs/architecture/auto-memory/目录下,然后在你调用AI的时候,让它先把这个文档加进上下文处理。我会在提示词里加这么一条规则:
你正在对order-service模块进行重构。每次遇到看起来“不合理”的代码时,先检索/读取模块记忆文档,确认是否存在历史约束。只有在确认无历史原因时,才允许修改。你的重构说明里必须包含一条“历史约束核对结果”。加了这条之后,AI“负面行为”次数大幅下降。我的测试里,重构时AI擅自修改可疑代码的概率从之前的60%降到了15%左右。它不会完美,但至少它学回了“先搞清楚再动手”这个最基本的工程素养。
5. 我在实操中的体会:421条记录,最后有用的其实是这些东西
两周翻完这些记录之后,我最大的一个感受是:一个几百人的架构师群,本质上就是一本永远不会出版的、活的架构书。里面每一句“这不行”背后,都至少意味着有人烧过钱、熬过夜、背过一次锅。文档负责记录“我们走了哪条路”,群聊则在私下里记录“我们为什么没走那条路”。这两种知识缺一个,都不是完整的上下文。而AI如果想真正成为可靠的协作者,它缺的恰好就是后者。
跟同组的人讨论这个结论时,有人问我:既然群聊里藏着那么多好东西,那我们干脆以后直接拿聊天记录训练一个专用模型不就行了?我的回答是:方向没错,但别走捷径。群聊里大量消息是语境化的、碎片化的、带情绪和夸张口吻的,直接当训练语料用就是灾难。真正靠谱的做法是先花力气把那三类知识结构化——反选清单、决策基准、模块记忆——然后再把它们纳入AI的提示词或RAG知识库。结构化一次之后,它们就有了自己的生命周期:可以在新项目里复用,可以在新人入职时当教材,也可以让AI遵守。421条聊天记录,最后被我浓缩成30多张表格和40多个词条。这个过程很费工夫,但收益持久。
如果在看的你暂时没精力做完整套,那就先从最简单的一条开始:下次架构评审完之后,花5分钟做一个决策复盘,写三行字——今天放弃了什么方案、为什么放弃它、什么条件发生之后我们要重新考虑它。攒上三个月,你再把这份记录丢给你的AI助手试试,你大概率会看到它的输出在质量上有一个肉眼可见的跳变。AI从来不怕你的知识少,它怕的是你的知识从来没被表达过。