ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

懂底层是AI时代工程师的底牌:从写代码到代码审查员的实战指南

懂底层是AI时代工程师的底牌:从写代码到代码审查员的实战指南 这篇文章从去年开始在技术社区传得很广OpenAI Codex 负责人 Karin Choi 在访谈里说AI 时代工程师唯一的底牌是“懂底层”而顶尖工程师的终局会变成“代码审查员”。最初我看到这个观点第一反应是这不就是给“代码审查”换个好听的说法吗审代码这件事我们不是一直在做但这一年里我用 Codex、Claude Code 这类工具写了大量代码也审了大量 AI 生成的代码我发现自己对这句话的理解完全变了。它不是让你去当更严格的 QA也不是让你背更多底层八股而是在说当 AI 能把“看起来对”的代码以极高密度生产出来时只有真正理解底层运行机制的人才有能力分辨哪些代码是“恰好能用”哪些代码是“埋着雷能跑”。这篇文章我会从自己实际碰到过的故障、审查过的 diff、设计过的训练路径出发聊聊我对“懂底层”这三个字的理解以及“代码审查员”这个角色到底变成了什么样的工作。顺带附上我觉得比较靠谱的实操方法希望能给正在转型期的工程师一点参考。1. AI 写代码的真实处境它能写得像对的但“看着对”和“真的对”之间隔着整个底层1.1 大模型生成代码的本质是“模式匹配”而不是“验证正确”我记得有一次让 Codex 帮我重构一个支付通知服务的配置加载逻辑。它给出来的代码结构非常漂亮职责划分清晰、命名规范、注释也写得恰到好处。如果你只看 diff 不看运行逻辑几乎挑不出毛病。但我在 review 的时候发现它把旧代码里的volatile关键字给去掉了理由是“该字段由不可变配置初始化无需 volatile”。这就是最典型的“AI 式错误”模型是根据训练语料里的代码模式来推理的它知道“不可变配置不需要 volatile”但它不知道我们这个类里其实有一个隐藏的回调路径配置加载之后会通过事件总线再次触发读取。在 JMM 的规则下缺少volatile意味着另一个线程可能在配置对象构造完成之前就看到其部分初始化的状态——标准的double-checked locking发布问题。你让 AI 解释它为什么这样改它能给你列出一二三四条逻辑。问题是那些逻辑成立的前提条件在它的“心智模型”里而真实系统的前提条件在物理机器的内存模型里。它是靠统计概率生成的不是靠执行和验证生成的。1.2 一个我真实踩过的底层事故AI 优化 HashMap 引发的并发地狱这里说一个我亲自处理过的线上事故特别能说明“懂底层的人在 AI 时代到底在干什么”。当时我们有一个指标聚合服务每次从上游拉取一批设备状态按设备 ID 聚合后推送给前端。代码原本用的是ArrayList因为上游本身按 ID 排过序聚合时只需要顺序扫描后合并相邻记录。后来团队用 Codex 做性能优化AI 建议把所有查询都换成HashMapLong, Item理由是“平均 O(1) 查询优于线性扫描”。审查的时候团队的同事其实是有点犹豫的因为单看每个接口改成 HashMap 确实更快。但当时我多看了一眼调用链发现在某些极端场景下这个“只读”的 Map 其实会被放入一个共享缓存并被多个回调线程同时执行put。JDK 8 的 HashMap 在并发写入时不仅会丢数据扩容的resize()过程在多线程同时触发时甚至可能因为链表成环而导致 CPU 100%。单线程测试、压测都过了因为触发扩容的边界条件恰好没有被覆盖到。改回ConcurrentHashMap或者加锁之后问题就消失了。整个过程 AI 不会告诉你它错在哪它只会给你一个看着很合理的 diff。而那个能指出“这里必须考虑并发可见性和扩容安全”的人靠的就是对 HashMap 底层实现的理解。1.3 为什么“代码审查”必然成为终局角色我不太认同“AI 会取代程序员”这种说法但我越来越认同AI 会让“不做深度审查的编程方式”变得极其危险。过去我们团队一个 PR 大概是 200 到 400 行代码Reviewer 有时间仔细看每一行。现在用 AI 辅助开发后一个 PR 动辄几千行而且大部分代码写得“非常规范”。这种规范本身就是陷阱它降低了人的警惕心。你可能已经不会去质疑 AI 为什么这样写因为注释、命名、结构都在暗示你“这是对的”。所以审查员这个角色正在从一个“挑代码风格毛病”的人变成整个生产链路里最后一道真正意义上的安全网。这个人不需要写最多代码但他必须能一眼看穿代码和物理世界之间的错配内存怎么用、并发怎么排、网络超时怎么断、状态怎么迁移。这就是为什么 Codex 的负责人会说懂底层是没被淘汰的唯一底牌。2. 底层的边界到底在哪从 HashMap 到智能指针再到事件循环2.1 我心目中的“底层知识地图”长什么样很多人一说“懂底层”第一反应是把《深入理解计算机系统》从头啃一遍。这当然对但在工程实战里我建议按“审查时需要什么就深挖什么”来构建知识结构。以下是我自己整理的核心地图未必全面但覆盖了我日常审查 AI 代码时最常需要调用的底层知识领域典型知识点常见 AI 盲区语言运行时JMM、GC、逃逸分析、volatile 语义V8 的隐藏类、事件循环容易忽略可见性和发布安全过度相信“性能优化”基础数据结构HashMap 扩容、ConcurrentHashMap 分段、跳表、B 树只考虑平均复杂度忽略并发、扩容、退化场景并发模型锁、CAS、原子变量、线程池饱和策略帮你去锁却不帮你识别可见性问题网络栈TCP 状态机、TIME_WAIT、连接池、epoll/IO_URING只处理业务异常忽略连接耗尽和队列堆积存储引擎WAL、页分裂、LSM-Tree、redo/undo推荐了索引却不关心磁盘 IO 与崩溃一致性编译与链接ABI、静态链接顺序、模板展开、内联与分支预测去掉看似冗余的代码结果破坏二进制契约这张表里每一行我都在真实 review 中踩过 AI 挖的坑。举几个具体例子。2.2 HashMap别只背结构要理解它会在什么情况下“死给你看”上面说的 HashMap 事故不是孤例。很多工程师都知道 HashMap 底层的数组加链表加红黑树被问到时都能画出结构图。但在审查 AI 生成的代码时你要关注的不是“它是不是数组加链表”而是三个边界行为第一扩容阈值是 0.75当数据量超过当前容量时resize()会重新计算所有元素的位置这个过程在单线程下代价已经不小在并发下直接出大事第二JDK 8 的尾插法虽然解决了 7 的成环问题但put时的数据覆盖问题依然存在第三红黑树的退化并不是立刻发生的要连续多批冲突才触发而 AI 写的代码通常只会创建默认容量 16 的 HashMap却完全不检查实际数据规模。所以我现在审查代码时会专门看一件事所有被多线程共享的 Map有没有做同步控制。AI 给出的解释往往很充分但理由里从来不会提“指令重排”和“可见性”这回事。2.3 C 智能指针所有权模型里的循环引用是隐形杀手搜索热词里经常出现“C 智能指针底层原理”说明大家都意识到这是个重点。我在审查 AI 写的 C 代码时最常看到的问题是AI 倾向于把裸指针全换成shared_ptr这确实是安全感的来源但它不理解shared_ptr的底层是控制块、引用计数和原子操作更不理解当对象之间互相持有shared_ptr时引用计数永远不会归零内存永远无法释放。我之前审过一段 AI 生成的图算法代码简单来说class Node { std::string name; std::vectorstd::shared_ptrNode neighbors; }; void buildGraph() { auto a std::make_sharedNode(a); auto b std::make_sharedNode(b); a-neighbors.push_back(b); b-neighbors.push_back(a); // a 和 b 形成一个引用环 }单测过跑起来也正常。但是只要这个图的生命周期一长内存就被这个环给锁死了。审查时我不需要去推导算法我只需要看到“两个对象互相持有 shared_ptr”就直接要求改成裸指针加作用域管理或者用weak_ptr去打破环。这种判断靠的就是对底层所有权模型的理解而不是靠代码规范。2.4 从 async/await 到事件循环AI 看不懂“状态机”里的坑另一个高频热词是“generator/async await 底层原理”这个我太有感触了。JavaScript 里的async/await底层是协程状态机每一个await都是一个状态划分点变量在状态切换之间要么被保存到闭包里要么被共享在上下文里。AI 写这种异步代码时特别容易出问题因为它擅长把同步逻辑“翻译”成异步写法却不关心状态转换之后变量是否仍持有预期值。举一个很常见的例子AI 生成一个循环异步发送通知的代码for (var i 0; i 3; i) { await sendNotification(i); }表面上看这段代码没问题但如果sendNotification是按批次异步合并发送的i可能已经变成3了而所有通知都拿到的是同一个3。这个时候审查员如果不懂事件循环的时间片机制就会以为这只是“闭包变量绑定”的小问题实际上它是状态机切换时机的问题它的根因在 V8 的微任务队列和事件循环里。我自己的经验是凡是看到 AI 生成异步代码一定要先画出它的状态流——哪些变量在 await 之前被赋值哪些在 await 之后被读取如果两者有交错就要特别警惕。这不是算法能力这是底层心智模型。2.5 网络编程与系统虚拟化的底层视角再顺便说说搜索词里另外两个例子“C 网络编程底层原理”和“VMware workstation 底层去虚拟化”。我审过一个 AI 生成的服务间调用代码它把原来的同步阻塞 IO 改成了非阻塞模式但完全没有处理连接池耗尽的问题。在 TCP 层面非阻塞 IO 只是让线程不再挂起但连接仍然占用着文件描述符和内核缓冲区。当上游服务响应变慢时积压的连接会迅速打满epoll的等待队列最终整个进程的 IO 都开始排队。这种问题从上层看是“超时设置不合理”从底层看是“你没有理解连接的生命周期管理”。至于虚拟化去虚拟化的知识同样重要但不一定每个人都用得上。我的看法是只有当你真的在搞虚拟化、调试性能计数器或者分析 Intel VT-x 的行为时才需要去抠 VMXON/VMEXIT 这些细节。底层知识的深度取决于你正在审查的系统所在的层级但“底层思维”本身是通用的——你要永远追问这一行代码在物理机器上到底是怎么执行的。3. 代码审查员的工作从“看 diff”到重建运行模型3.1 新时代审查和传统审查的最大区别传统代码审查审的是“这段代码是否符合规范、是否有效率问题、是否有逻辑漏洞”你可以逐行看也可以借助工具的静态分析。但 AI 时代审查对象不再是一个开发者有意识写出的代码而是一个从海量语料中概率生成的产物它最大的特点是局部逻辑高度自洽但整体假设经常和系统实际行为脱节。所以现在我做审查流程完全变了。我不会第一时间去看每一行代码而是先做这几件事读 PR 描述和对应的需求文档搞清楚“这段代码为什么存在”而不是“这段代码写了什么”。在脑子里重建整个调用链的状态模型哪些状态被读、哪些状态被写、状态转换的触发条件是什么。把 AI 这次改动涉及到的假设列出来例如“该 Map 只在单线程中访问”“该对象不会有循环引用”“超时之后对端一定关闭连接”。这些假设往往隐藏在代码里AI 不会主动说明。针对每一条假设反向构造突破口。这一套流程看起来简单但大部分人没有执行的原因只有一个太相信 AI 生成的代码了。你把它当同事写的代码潜意识里会觉得“人写的代码有自己的逻辑”但 AI 的代码没有“自己的逻辑”它只有“全体训练语料的逻辑”。3.2 我审查 AI 代码时的完整检查清单上面说的方法论可能偏抽象我把它拆成我真正在用的 checklist。现在团队里每一位新晋技术骨干我都会要求他们按这个清单来审 AI 生成的代码检查维度具体动作常见风险信号并发安全找出所有共享的容器和变量确认各自的线程边界AI 经常忽略发布安全、指令重排、可见性生命周期确认对象所有权的建立和释放路径一一对应引用环、重复释放、资源不归还失效路径不只是看正常路径还要看异常、超时、重试后的状态AI 生成的错误处理往往是“象征性 try-catch”性能假设对每一个所谓的优化问“优化了什么放弃了什么”用复杂度骗人忽略常数、GC、IO 和锁竞争三方依赖检查新引入的库、系统调用、环境变量引入不兼容版本、调用了废弃接口数据一致性思考如果进程崩溃或机器断电数据还在不在忽视刷盘、异步提交、缓冲丢失每次审查我至少要找到两到三个风险点否则我不会点“通过”。这不是为了找茬而是因为统计上 AI 生成代码的潜在风险密度就是高。你要是每次都能轻松通过说明你还没有触及到它的脆弱层。3.3 具体案例一次由“AI 自作聪明”引发的索引选择灾难再讲一个最近发生的具体案例。我们的订单查询服务最近要加一个“按用户维度查询最近订单”的接口。AI 看到数据库表里有一列user_id就自动加了一个普通索引然后把查询 SQL 写成了SELECT * FROM orders WHERE user_id ? ORDER BY created_at DESC LIMIT 20。从任何静态分析的角度看这都没问题。但审查时我看了执行计划发现 MySQL 优化器选择了user_id索引做回表排序而不是走覆盖索引。原因是 AI 没有意识到这个表里 90% 的数据量都集中在少数几个高频用户身上对这些用户来说走user_id索引过滤出来的行数可能是几万行排序加上回表查询耗时直接从 5 毫秒涨到 800 毫秒。这时候需要的底层知识不是“索引是什么”而是理解 InnoDB 的索引组织方式聚簇索引是数据本身二级索引需要回表而回表意味着随机 IO。AI 不会告诉你它没有考虑数据分布但审查员必须能自己发现这一点。你把 SQL 改成FORCE INDEX (created_at)或者改索引设计之后响应时间立刻回到几十毫秒。这背后是存储引擎的底层逻辑而不是代码注释能解释的。4. 普通工程师怎么练“底层”这项基本功一套我验证过的策略4.1 不要按目录啃书要按“审查场景”建立知识树很多人一听要补底层就买一本《深入理解计算机系统》从头开始逐章读。这当然有效但周期太长而且和实际工作脱节。我自己更推荐的方法是从你最近被 AI 代码坑过的地方开始往下挖一层形成一棵以实际场景为根的树。举个例子你用 Node.js那就先搞清楚“Node.js 底层是不是用的 V8”。答案当然是“是”但这只是起点。你继续往下挖V8 的事件循环在哪个线程运行异步文件 IO 和定时器又是怎么被处理的答案会引到 libuv引到操作系统的.io_uring引到线程池调度。这个过程中你会发现自己逐渐能解释“为什么 Node 在处理 CPU 密集任务时会卡住整个进程”而这正是审查 AI 写的异步代码时最需要的能力。这不是说不要系统学习了。我的建议是主线靠实际场景牵引支线用经典书补齐不要一上来就想成为全栈底层专家。4.2 用“高成本调试”倒逼底层感知底层知识最烦人的地方在于它往往在不出问题时显得毫无用处。你很难通过读文档来获得真实感知你只能靠踩坑、看堆栈、追系统调用来建立直觉。我分享一下我的训练方法遇到线上问题先不急着查资料而是自己动手做一轮“底层观察”。如果是 Java 服务我会jstack看线程栈查每个线程在等什么锁如果是 CPU 飙升我会perf top看热点函数看看是不是 JIT 编译后的代码在忙转如果是网络问题我会用strace跟踪系统调用看send、recv和epoll_wait的返回状态。这些工具一开始用起来很陌生但一旦你掌握了“应用层行为到底映射到哪些内核调用”你再看 AI 生成的代码就会有完全不同的感觉。你会自动去想这段代码执行时会产生多少系统调用线程是挂起还是自旋内存分配是在堆上还是栈上我印象深刻的是有次一个服务无端高延迟AI 给出的优化建议是“增加线程池大小”。但我用jstack一看线程池 80 个线程全部卡在对数据库连接池的等待上真正的问题是连接池太小而不是线程不够。底层观察直接纠正了 AI 的错误方案。4.3 大量进行“对 AI 代码的深度审查”是最高效的训练很多人觉得“底层”是艰深理论但我的经验正好相反它是极度依赖实操反馈的技能。而 AI 时代恰好提供了大量的训练材料——AI 每天都在生成成千上万行“看着对但实际有问题”的代码这正是最好的练习题。我建议团队里每个季度挑一个 AI 生成的模块做一次专项深度审查。把 AI 产出的代码当成代码审计对象不允许任何一个人“只看 diff 不看上下文”。每个人必须画出一张完整的状态流图对象什么时候创建、什么时候引用、什么时候释放数据在哪些线程之间流动异常和超时路径上状态会不会错乱。这种训练做三个月以后团队成员再看 AI 代码会自动产生“审查员视角”。就像老医生看 X 光片一样哪里密度不对、哪里边界模糊一扫就出来了。5. 用“审查者思维”重塑日常工作节奏5.1 减少“只管生成”的时间增加“验证运行模型”的时间以前每天的工作节奏里写代码占了一半。现在有了 AI真正手写代码的时间大幅缩减但这并不代表工作变轻松了。把同样的时间转移到审查环节读 AI 生成的代码、验证它的假设、构造边界测试、重构它写得不顺滑的部分。我发现一个很实用的技巧让 AI 产出代码之后先别急着让它跑测试而是把代码打开一行行看专门找“它假设了什么”。它是不是假设Map.get永远不会返回null它是不是假设某个回调只会在一个线程里执行它是不是假设内存足够大所以无所谓复制每找到一个假设就用一行注释写下来。你会发现 AI 代码里充满了未言明的假设而所谓底层能力就是把这些假设识别出来的能力。5.2 你甚至会因此获得比写代码更高的商业回报这个话题我愿意多说一点因为它让我真正意识到“代码审查员”不是一句口号。今年有个新闻报道过Airbnb 在招 AI 基础架构方向的高级工程师开出了千万美元级别的年薪。单看“写代码”这个动作任何工程师的产出都会在 AI 工具的加持下加速趋同。但“为 AI 生成的系统级代码做深度审查与兜底”的能力并没有趋同反而越来越稀缺。我自己在这个方向上的体会是当你成为一个能判断“这段代码是能跑还是能抗”“这个系统是能用还是能守住数据一致性”的人你的价值就不是按代码行数衡量而是按风险覆盖范围衡量。在一个 AI 生产代码高度密集的系统里一个能兜住底层风险的人价值确实比写代码的人更大这就是公司愿意为“审查者”付高价的原因。5.3 我建议你现在就开始做的小事如果你也想往这个方向转型我的建议不是马上去报课而是先做三件小事第一把自己最近写的代码里凡是 AI 生成的部分集中拿出来重审一遍从底层视角找 3 个可能的问题哪怕最后证明是虚惊一场这个思考过程也值回票价。第二选一个你日常开发中高频使用的技术点比如HashMap、async/await、或shared_ptr花一个下午把它的源码和底层机制彻底读透然后写一篇记录给自己。不是给别人看是为了逼自己建立完整的解释框架。第三在团队内部发起一次“AI 代码找茬”活动每个人带一段自己遇到的 AI 代码问题互相讲解根因。你会发现“能讲清楚底层原因”比“能改对”更能提高团队整体水位。第四也是我个人最推荐的一点学会自己构造验证实验。看不懂某个底层行为时不要停在文档推理而是写一个最小复现程序去观察它。比如你不信 HashMap 并发会丢数据那就写十个线程同时 put 一万条记录实际跑一下。这类实验做多了你对底层的信任度就建立起来了这是任何课程都给不了的经验。我自己过去半年明显感觉到工作重心已经从“生产代码”变成了“审查代码、审查设计、审查假设”。AI 承担了书写层的工作而人类要向上移动到概念层和物理层。谁先适应这个移动谁就站在了这一轮技术演变的有利位置。回到开头那句话懂底层是不是唯一底牌我不敢把话说死但代码审查员这个方向确实是我看到的、最确定的价值出口。你要是还没开始往这个方向挪现在就可以从第一批 AI 生成的代码里找三个问题出来看看。
返回列表