人是尺度:AI 时代软件工程中不可让渡之物

摘要:AI 编程正以令人眩晕的速度普及,但来自 METR、DORA、GitClear、斯坦福大学和多家大型企业的实证数据,呈现出一个与营销叙事不同的模式:AI 显著降低了"写出代码"的成本,却没有、也不可能降低"对系统负责"的成本。本文从 1969 年阿波罗 11 号的一次警报讲起,用软件工程史上的经典事故与抽象跃迁说明:品味、抽象、责任与灵感这四样东西,在结构上无法外包给概率模型;并逐一回应"只留高级工程师 + AI"“代码以后不用人读"等流行说法,最后给出一条在成熟工程实践之上稳健演进的路线。本文不是反 AI 的宣言,而是一份清醒使用 AI 的建议书。

一、引子:月亮上方的 1202 警报

1969 年 7 月 20 日,登月舱"鹰"号正在向月面下降。距离月面只剩几千英尺时,制导计算机突然连续报警:1202、1201——执行区溢出,计算机算不过来了。休斯敦任务控制中心一片寂静。26 岁的制导员 Steve Bales 盯着数据,几秒后回答:“继续。”

计算机没有死机。它自动丢弃低优先级任务,把资源集中到制导、导航和姿态控制上,然后重启自己。这套容错机制,是 Margaret Hamilton 带领的软件团队在事故发生前好几年,就一行一行设计进系统里的——他们想象过一个当时没有人见过的故障场景,并提前写好了对策。

那是人类第一次让飞船在另一个天体上着陆。救场的不是机器的临场发挥,而是人在多年前的一次判断:当资源耗尽时,什么最重要。

半个多世纪后,当我们争论 AI 能替程序员写多少代码时,这个故事仍然是最好的坐标系:决定软件系统命运的,从来不是写字的速度,而是判断、品味和责任。

二、一场猝不及防的狂热

先承认事实:这一轮变化是真实的。

  • Google 2025 年 DORA 报告显示,约 90% 的开发者已在工作中使用 AI,每天使用时长的中位数达到 2 小时,约占工作日的四分之一;
  • “氛围编程”(vibe coding)成了柯林斯词典 2025 年度词汇;
  • 科技公司高管们公开讨论"初级工程师岗位是否还会存在”,一些团队把"AI 转型"直接变成了裁员的同义词。

这种速度让大量团队猝不及防。领导层急于跟上,于是跳过了软件工程最古老的纪律:先理解问题,再改变方法。很多团队不是"采用了一个新工具",而是在没有任何防护的情况下,改变了代码的生产方式。

三、数据泼下来的几盆冷水

狂热需要对照数据。以下几项研究,方法和立场各不相同,拼在一起却出现了同一个形状。

1. METR:资深开发者用 AI 反而慢了 19%,却以为自己快了 20%。 2025 年,研究机构 METR 做了一项随机对照试验:16 名资深开源开发者,在自己平均深耕了 5 年的成熟项目上完成 246 个真实任务,每个任务随机决定是否允许使用 AI。结果出人意料:允许用 AI 的任务多花了 19% 的时间。更值得玩味的是认知偏差——他们事前预期能快 24%,事后仍坚信自己快了约 20%。人在"速度感"上骗自己,比想象中容易。

2. 三家大公司 4,867 人的试验:收益几乎全在新人一边。 MIT 与微软、埃森哲等合作的 RCT(2025 年 2 月工作论文)覆盖近 5,000 名开发者:使用 Copilot 使完成任务数平均提升约 26%,但增益主要来自新入职者和初级岗位,资深开发者没有显著变化。这个结论和客服领域的著名研究一致:AI 是新手的脚手架,不是老手的替身。它拉平了下限,没有抬高上限。

3. DORA:吞吐在涨,不稳定也在涨。 2024 年 DORA 报告曾发现 AI 采用率提高 25%,伴随着交付吞吐下降 1.5%、稳定性下降 7.2%;2025 年报告显示吞吐指标翻正了,但交付不稳定性仍在同步上升——约 30% 的开发者明确表示不信任 AI 生成的代码。原因并不神秘:生成太快,批量变大,评审和系统消化跟不上。详见 DORA 的专题分析 Balancing AI tensions。

4. GitClear:代码库正在进入"只写模式"。 GitClear 分析了 2023–2026 年间 6.23 亿次代码变更,发现维护性指标全线恶化(Write-Only Mode, 2026):

指标 变化
重构(代码移动)占比 21%(2022)→ 3.8%(2026),崩塌约 70%
复制粘贴占比 9.4%(2022)→ 15.7%(2026 上半年)
重复代码块密度 较 2023 年 +81%,创历史新高
一年以上旧代码的更新占比 下降 74%(1.7% → 0.46%)
新代码与既有函数的连接度 下降 35%

换句话说:加代码变成了一次击键,而理解、合并、整理旧系统的工作正在消失。代码库不断向外长出"全新的 v1 功能",老地层却在钙化。

5. 安全:更不安全的代码,配上更强的安全感。 2021 年的研究 Asleep at the Keyboard? 发现 Copilot 在 89 个安全相关场景中生成的程序约 40% 含可利用漏洞;2023 年斯坦福 CCS 论文进一步发现,使用 AI 助手的开发者在 5 个任务里有 4 个写出了更不安全的代码,却更加相信自己的代码是安全的。错误不会单独出现,它总是和自信一起来。

6. 市场自己的回调:Klarna。 2024 年,瑞典金融科技公司 Klarna 高调宣布其 AI 客服抵得上 700 名员工。2025 年 5 月 8 日,CEO Sebastian Siemiatkowski 对彭博社承认"走得太远了":质量下降、复杂问题处理不了,公司重新招聘人工客服。他说,过度把成本当成唯一标尺,会损伤品牌与信任。

7. 连"氛围编程"的发明者本人都留了注脚。 Andrej Karpathy 2025 年 2 月创造 vibe coding 一词时,明确说它适用于"一次性的周末项目",并自嘲"有时 LLM 修不好一个 bug,我就绕过去,或者随机要求改动直到它消失"。这个限定条件在传播中被普遍忽略了。

把这些证据放在一起,模式非常清楚:在上下文小、边界清晰、可丢弃的任务上,AI 收益巨大;在需要全局理解、长期维护、权衡取舍的真实系统上,净收益迅速递减,而风险以复利累积。 感觉自己变快,和系统真的变好,是两件事。

四、为什么银弹永远不存在

1986 年,Fred Brooks 在 No Silver Bullet 中把软件的复杂度分成两种:

  • 偶然复杂度(accidental complexity):表达方式带来的麻烦——样板、语法、胶水代码;
  • 本质复杂度(essential complexity):问题本身的复杂——业务规则、用户心智、并发、失败模式、利益权衡。

AI 空前擅长消除偶然复杂度,但它对本质复杂度无能为力,因为本质复杂度来自现实世界,不来自代码。更微妙的是:AI 生成的海量新代码,本身又在制造新的偶然复杂度——更多体积、更多重复、更多无人理解的分支。

Brooks 在《人月神话》里还讲过另一条定律:向延期项目加人只会让它更晚。今天这句话的新版本是:向项目里灌入 AI 生成的代码,并不能增加理解,只会增加需要被评审、集成和维护的表面积。 软件工程追求的概念完整性(conceptual integrity)——让一个系统看起来像由一个头脑设计——在更多产出面前反而更难维护。

还有一个常被遗忘的常识:代码是负债,不是资产。 它在运行时提供价值,在其余所有时间里制造成本。优秀工程师的很多功夫花在删除代码、让特例消失上。AI 被优化的目标是"生产代码的成本",而工程师要优化的是"拥有代码的成本"。这两个目标,方向并不总是相同。

五、人不可让渡的四样东西

5.1 品味(Taste):让特例消失的能力

2016 年,Linus Torvalds 在 TED 访谈中用一段链表删除代码讲什么叫"好品味"。

平庸的版本会把"删除头节点"当成特殊情况:

if (entry == list->head) {
    list->head = entry->next;      // 特殊情况
} else {
    prev->next = entry->next;      // 普通情况
}

有品味的版本用一个"指向指针的指针"遍历,于是头节点不再特殊:

void remove_entry(Node **indirect, Node *entry) {
    while (*indirect != entry) indirect = &(*indirect)->next;
    *indirect = entry->next;       // 没有任何特殊情况
}

行数的差异不是重点。重点是:边界情况从来不内生于问题,它只是对问题的表示方式的产物。换一种数据结构,整类特例就蒸发了。Linus 说,好品味就是"换个角度重写问题,让特殊情况变回普通情况"。

这种"让特例消失"的判断,不只出现在内核代码里。下面三个日常例子,几乎每个团队的评审中都能遇到。

例 1:箭头型嵌套 vs 卫语句。 左边是 AI 补全最爱产出的形状——它"正确",但读者的视线要一路向右缩进,每个返回值都要和嵌套层级绑定:

# 平庸:正常路径被层层包裹,"未知"这个答案散落三处
def get_city(user):
    if user is not None:
        if user.address is not None:
            if user.address.city is not None:
                return user.address.city
            else:
                return "未知"
        else:
            return "未知"
    else:
        return "未知"

# 有品味:先排除异常,正常路径只剩一条直线,且只有一个出口返回真实值
def get_city(user):
    if user is None or user.address is None:
        return "未知"
    return user.address.city or "未知"

例 2:去重——又是"换表示"。 先用列表 membership 写一版 O(n²) 的,看起来天经地义;换一个数据结构,查找从线性扫描变成常数时间,循环本身也整个消失了:

# 平庸:用错了容器,于是不得不用循环补偿
def distinct(items):
    out = []
    for x in items:
        if x not in out:      # 每一次 in 都是一次线性扫描
            out.append(x)
    return out

# 有品味:去重是集合的定义,直接说出意图
def distinct(items):
    return list(set(items))  # 无需保序时;需保序可用 dict.fromkeys

例 3:类型码 + if 链 vs 多态。 区别不在行数,而在"将来新增一种图形时,要改几个地方、可能漏改几处":

# 平庸:每加一种图形,都要回来修改 area()——以及所有其他按 type 分支的函数
def area(shape):
    if shape["type"] == "circle":
        return pi * shape["r"] ** 2
    if shape["type"] == "rect":
        return shape["w"] * shape["h"]
    raise ValueError(shape["type"])

# 有品味:把行为放回数据自身,area() 对未来的新图形保持封闭
class Circle:
    def area(self): return pi * self.r ** 2

class Rect:
    def area(self): return self.w * self.h

def area(shape):
    return shape.area()

这里要补一句体现品味之"难"的注脚:多态不是永远正确的答案。如果图形种类稳定、而变化的方向是"不断增加新操作"(周长、序列化、碰撞检测……),那么 Rust 式的枚举加 match 反而是更优的表示——编译器还会在你漏处理一个分支时直接报错。品味不是背诵某条设计模式,而是判断"变化将沿哪个方向发生",让数据结构与变化方向对齐。 这个判断需要理解业务的演化趋势,训练语料里没有答案。

这种能力的背后是审美。Donald Knuth 在 1974 年图灵奖演讲《计算机程序设计作为艺术》中说:编程是一门艺术,因为它需要技巧与独创,尤其因为它产生美的对象。圣埃克苏佩里也有一句被工程师反复引用的话:“完美,不是在没有什么可以增加时达到的,而是在没有什么可以删减时达到的。”

为什么这恰恰是 AI 的结构性短板?因为大语言模型的工作机制,是在训练分布上采样"最可能出现的下一段文本"——它被设计成写出平均水平的、看起来像那么回事的代码。而品味的本质,是对平均数的偏离:大多数人会写 if,少数人会回去换数据结构。模型可以模仿风格的统计特征,但它没有立场、没有不适感,不会在丑陋面前坐立不安,不会在洗澡时突然想去重构。

值得深思的是:幻觉和平庸代码是同一个机制的两个出口。 “流畅"既不等于"正确”,也不等于"美"。AI 从不为丑陋付出代价,所以它学不会厌恶丑陋。

5.2 抽象的跃升:让一整类问题消失

比写好代码更稀缺的能力,是抬高整个系统的抽象层次。回看软件工程史,每一次真正的跃迁,都是某个人(通常是一小群人)在看清反复出现的痛点后,提出了一个让整类问题不再存在的模型:

  • 1958 年,John McCarthy 设计 Lisp:代码即数据、垃圾回收、用一个 eval 统一起一切——60 多年后仍在滋养着语言设计;
  • Dahl 与 Nygaard 的 Simula 引入对象;Alan Kay 在 Smalltalk 中把它推进为面向对象与个人计算的愿景;
  • Ken Thompson、Dennis Ritchie 与 Doug McIlroy 的 Unix 管道哲学:“写只做一件事、并把它做好的程序”;
  • 1970 年,Edgar Codd 用关系代数重新定义数据,让程序员不必再手工导航存储结构;
  • Tim Berners-Lee 用 URL + HTTP + HTML 统一了文档的互联;
  • 2005 年,Linus Torvalds 大约十天写出 Git,用内容寻址的对象模型让分布式版本控制里的一整类冲突消失;
  • MapReduce、Rails 的"约定优于配置"、React 的"界面是状态的函数"、Docker 的集装箱式隔离……

这些跃迁有一个共同结构:它们不是在现有代码上"再生成一段",而是退后一步说,“这一整类问题根本不应该存在。”

同样的结构缩小到日常代码里也成立。先看小处:“计算所有偶数的平方和”——

# 在低层抽象里手写循环:读者要在脑中模拟累加器的状态变化
total = 0
for n in numbers:
    if n % 2 == 0:
        total += n * n

# 抬高一层:过滤、变换、归并各归其位,代码读起来就是需求本身
total = sum(n * n for n in numbers if n % 2 == 0)

再看一个真实评审场景。给 AI 三个需求——“把订单、发票、客户全部翻页拉下来”,它往往会忠实地生成三个函数,happy path 全部能跑:

# AI 的典型产出:每个资源一份,结构几乎相同——它在响应三次请求,而不是在看一个系统
def fetch_orders(client):
    results, page = [], 1
    while True:
        batch = client.get("/orders", params={"page": page}).json()
        results.extend(batch["items"])
        if page >= batch["total_pages"]:
            break
        page += 1
    return results

def fetch_invoices(client):
    results, page = [], 1
    while True:
        batch = client.get("/invoices", params={"page": page}).json()
        results.extend(batch["items"])
        if page >= batch["total_pages"]:
            break
        page += 1
    return results

# fetch_customers(client) ——第三个一模一样的副本,通常出现在另一个文件里

有经验的工程师读到第二个函数就会坐直:这里存在两个东西,而不是三个——“分页遍历协议"和"一个路径参数”。 于是抽象一层:

# 人看见的东西:一个生成器把翻页协议封装一次,之后新增资源只是一行声明
def iter_pages(client, path):
    page = 1
    while True:
        batch = client.get(path, params={"page": page}).json()
        yield from batch["items"]
        if page >= batch["total_pages"]:
            return
        page += 1

def fetch_orders(client):   return list(iter_pages(client, "/orders"))
def fetch_invoices(client): return list(iter_pages(client, "/invoices"))

差别要到第三年才显现:当 API 改成游标分页、要加限流重试、或者某一页返回 500 时,右边改一处,左边要在三个(实际项目里可能是三十个)副本里逐一打捞——而且总有副本藏在没人读的目录中。这正是 GitClear 数据里的世界:复制粘贴 +41%、重复代码块 +81%、重构 -70%。

需要说句公道话:AI 不是写不出第二个版本——如果你明确要求"抽象成一个分页迭代器",它写得很好。它缺的是在无人提示时"看见第二个和第一个是同一件事"的那一下皱眉。 识别重复、给重复命名、决定值不值得抽象,这组动作依赖对整个代码库演化方向的感觉,而这恰恰是站在范式之外的人才站得住的位置。

AI 始终站在当前抽象层的内部工作——它在给定范式内插值。而抬高范式本身,需要一个既持有全局上下文、又被痛点持续折磨、还愿意为简洁放弃便利的人。Rich Hickey 在经典演讲 Simple Made Easy 中区分过:“easy"是手边顺手,“simple"是不纠缠(uncomplected);AI 极其擅长让事情变得 easy,但选择 simple 需要人的判断力。

这也解释了那些传奇的杠杆:WhatsApp 被收购时约 55 名员工服务着 4.5 亿用户;Instagram 被收购时只有十几名员工、数千万用户。他们的杠杆不是代码产量,而是抽象、克制和品味——用更少、更好的结构承担更大的世界。

5.3 责任:凌晨三点谁接电话

品味可以讨论,责任无法分摊。软件工程史用最惨痛的事故反复教这一课:

  • Therac-25 辐射治疗仪(1985–1987):一个竞态条件导致至少 3 名患者死亡、多人重伤。机器移除了硬件联锁,盲目相信软件,而相关代码没有经过独立评审。
  • 阿丽亚娜 5 型火箭 501 次飞行(1996):起飞 37 秒后自毁,约 3.7 亿美元化为火球。根因是一段从阿丽亚娜 4 型复用的代码把 64 位浮点速度值塞进 16 位整数,溢出后异常处理同时关闭了两套惯导系统。代码在旧环境里是对的,但它携带的假设没有人重新追问。
  • Knight Capital(2012):一次部署失误激活了废弃代码,45 分钟亏损约 4.4 亿美元。

这些事故的共同点不是"没人写代码”,而是没有人对"代码在真实世界意味着什么"负全责。

这种疏忽在日常代码里有一个微型标本——缓存的"先检查再操作”:

// 单看每一行都"合理",测试也通常是绿的——因为测试很少制造并发
if (!cache.containsKey(key)) {
    cache.put(key, loadFromDb(key));  // 10 个线程同时 miss:10 次打库、互相覆盖
}
return cache.get(key);

这是 AI 最容易流畅产出的形状:它根据"最可能的下一行"补全,而 happy path 里确实没有问题。但在真实流量下,这段代码意味着缓存击穿、数据库被瞬时打满,最坏情况下返回一个被覆盖到一半的对象。看见这个风险不需要更聪明的模型,需要的是在脑子里运行系统的能力——想象十个线程同时到达,想象凌晨两点的流量洪峰。修法同样是把"检查—加载—放入"这组复合动作变成一个原子概念:

// ConcurrentHashMap 保证:对同一个 key,加载函数在映射层面只执行一次
return cache.computeIfAbsent(key, this::loadFromDb);

一行对一行,字符数差不多,但右边有人为并发世界负了责。Therac-25 和阿丽亚娜 5 离日常很远,“先检查再操作"离日常很近——它们是同一种思维方式的不同结局。

AI 时代,责任的边界正在被刻意模糊,但社会接口并不买账:2024 年加拿大不列颠哥伦比亚省民事仲裁庭裁定,加拿大航空必须为其聊天机器人给出的错误退票政策赔偿旅客——航司辩称"那是一个独立的法律实体在说话”,被驳回。2023 年,美国律师 Steven Schwartz 因引用 ChatGPT 编造的六个不存在的判例,被处以罚款并公开训诫。法庭和事故调查不接受"是 AI 干的"这个答案。

责任是人类社会的系统接口,你无法把它委托给下一个 token。 鉴权、支付、医疗、飞行控制、数据迁移——凡是错误会伤害真实人生的地方,每一行代码都必须有一个愿意在凌晨三点接电话的人。

5.4 灵感:跨领域的、带着痛感的连接

Hamilton 当年在 NASA 不得不发明一整套做软件的方法,“软件工程"这个词最初甚至是她们半开玩笑造出来的;Alan Kay 在儿童与 Seymour Papert 的 LOGO 实验中看见了个人电脑的未来;Douglas Engelbart 从"增强人类智力"的宏大命题出发,最终拿出了鼠标和超文本。米开朗基罗说,他只是看见大理石中的天使,然后一路雕琢,直到把它释放出来。

灵感不是凭空的联想,而是带着身体经验和切身之痛的跨域连接。它要求一个人长期与问题共处,在乎它,被它折磨。AI 可以重新组合人类写过的一切,但它没有 stakes——它不会为一个设计失眠,不会在评审会上被反对而脸红,也不会因为系统宕机而内疚。没有痛感,就没有真正的创造冲动。

还有一层更隐蔽的风险:思想的单一作物。当所有人都向同一个神谕提问,答案会趋同,缺陷也会相关。农业史上,单一品种的规模化种植曾让爱尔兰在 1845 年的土豆晚疫病中,于数年间因死亡和迁徙损失约四分之一人口。当全行业的代码都从少数几个模型中采样,我们第一次可能拥有"相关系数接近 1 的代码缺陷组合”——同一个模型特有的盲点,会同时出现在成千上万个系统里。多样性本身,就是工程韧性的来源。

六、两个驾驶舱:为什么不能只留机长

2009 年 6 月 1 日,法航 447 航班在大西洋上空遭遇空速管结冰,自动驾驶断开。右侧驾驶杆落在资历最浅的副驾驶 Bonin 手中——他几乎全程把侧杆向后拉到底,飞机失速坠落三分半钟,228 人遇难。调查中最令人心寒的细节是:驾驶舱里没有人真正理解飞机当时处于什么状态。

同年 1 月 15 日,全美航空 1549 航班起飞后一分钟在 3,200 英尺高度撞鸟,双发停车。Sullenberger 机长——40 年飞行经验、两万小时、飞过滑翔机——在短短几分钟内决定迫降哈德逊河,155 人全部生还。自动驾驶算不出这条航线,是人的经验和判断救了场。

两个故事合在一起,正是自动化时代最深刻的悖论。1983 年,Lisanne Bainbridge 在经典论文 Ironies of Automation 中就指出:自动化接管了常规操作,于是人越来越少练习;可一旦自动化退出,剩下的恰恰是最罕见、最棘手、最需要人手的时刻。航空界后来把过度依赖屏幕上洋红色指引线的一代飞行员称为"洋红色线的孩子"(Children of the Magenta Line)——自动飞行让他们安全,直到自动飞行不能用的那一秒。

“裁掉初级工程师,只留高级工程师用 AI"这个方案,本质上就是在培养一代没有摸过杆的机长。资深工程师的判断力,是一千次亲手犯错的存款;你不能跳过存款阶段,直接要求他们在雷暴夜接班。外科医生不能跳过住院医师生涯,建筑师不能在没画过节点详图的情况下设计大桥。能力只在重复的、笨拙的、亲手做的练习中长出来。 今天被裁掉的初级岗位,就是十年后无人可用的资深岗位——再加上对少数骨干和单一 AI 的双重依赖,整个行业的巴士因子(bus factor)会急剧恶化。

七、“只写不读"的代码库:最坏的终局

我们因此有一个担忧:如果大家相信"以后代码不需要人读了,AI 自己会维护”,最终会得到一个没有人读得懂的代码库。

GitClear 的 2026 数据证明这不是假想,而是正在发生的结构变化:旧代码更新减少 74%、重构崩塌 70%、新代码与既有代码的连接度下降 35%——人们确实不再回去读旧代码了。

问题在于,这个赌注有一个技术上的硬约束:上下文窗口。真实的大型代码库,迟早会长到超出任何单一模型的上下文。届时 AI 只能看见局部碎片,却仍以全知的口吻输出补丁;人因为从未读过底层,无法判断补丁是否正确。于是补丁叠着补丁,同一个错误以 +81% 的速度复制到更多地方。系统每天都在"能运行"和"无人理解"之间扩大裂缝,直到一次事故——那时模型受限于上下文无法收拾,人受限于从未阅读也无法接手。

你无法维护一个你读不懂的系统。读不懂,就意味着你并不拥有它——你只是在替它值班。

八、对四种流行说法的回应

说法一:“我用 AI 明明更快了。” 很可能是真的——尤其是在学习新 API、写样板、补测试、查资料、做可丢弃原型时。证据也一致:新手和常规任务收益最大。但请把"我打字更快了"和"我的系统更好了"分开度量。METR 和 DORA 提醒我们:前者是感受,后者要用变更失败率、事故率、返工率来验证。

说法二:“等下一代模型就好了。” 模型当然会继续进步。但有三样东西不会随模型参数增长而转移:责任(社会只向人追责)、本质复杂度(系统越大,理解问题越难)、以及规格本身的难度(最难的从来不是"怎么写”,而是"该做什么")。工具史也不必悲观:1952 年 Grace Hopper 拿出第一个编译器时,没人愿意碰它,人们说"计算机只会做算术";后来 4GL、CASE、低代码每一轮都预言程序员消亡,结果是软件吃掉了更多世界,开发者数量持续增长——只是每一次,门槛都向"判断与品味"上移一层。相机普及没有消灭摄影,它让"眼睛"成为稀缺品;国际象棋引擎没有杀死象棋,反而催生了水平更高的"半人马"棋手。

说法三:“只留高级工程师 + AI,人力成本最低。” 短期省下的是工资,长期失去的是人才管线、组织记忆和冗余。骨干工程师脑子里的隐性知识——为什么这个地方必须这么设计、当年踩过什么坑——是公司真正的资产,也是 AI 训练不出来的上下文。而且资深者一旦长期脱离代码地面,也会产出自己的"架构幻觉"。

说法四:“代码不用人读,AI 自己维护就行。” 调试的本质是建立对系统的心智模型;事故处置的本质是接管。不能被人理解的代码,在风平浪静时是黑盒,在风暴中是炸弹。把 AI 代码当作外部陌生人提交的 PR 来对待——先读懂,再合并——这是底线。

九、稳健演进的路线:保留什么,改变什么

AI 是放大器:它放大团队的品味,也放大团队的混乱。先有好工程,才有好放大。基于前面的证据,建议团队沿着既有实践做十件事,而不是推倒重来:

  1. 人类对每一次合并负责。 把 AI 输出当成"一个极快、博学、过度自信、且永远不必值班的实习生"写的代码:先读后合,逐行判断。
  2. 保留并加强经典实践。 设计评审、架构决策记录(ADR)、代码评审、人写的测试(测试是可执行的规格)、持续集成、on-call 与事故复盘——它们在 AI 时代不是过时了,而是更重要了。
  3. 给重构和旧代码维护留出固定预算。 GitClear 的建议:为重复代码块设置告警 tripwire,把重构占比、旧代码更新率纳入团队指标。
  4. 保护新人的训练道。 采用"驾照模式":先证明能手写、能读懂,再逐步授予"自动驾驶"权限。让 AI 成为副驾,而不是代驾。
  5. 按风险分级使用。 探索、样板、文档、测试生成可以放开;鉴权、支付、并发、加密、数据迁移等高危区,必须人写或逐行复核。
  6. 度量结构,而不是产量。 盯重复率、两周内返工率、评审缺陷逃逸率、变更失败率、事故恢复时间——不要盯"接受了多少条补全"“新增了多少行”。
  7. 刻意做知识传承。 结对、评审时的讲解、把隐性知识写进 ADR——AI 时代信息越多,组织化的理解越稀缺。
  8. 保持多样性。 关键设计至少有一个"不依赖 AI 的大脑"完整想过一遍;允许多个模型、多种人工方案并存,避免全系统共享同一个盲点。
  9. 慢半步采用,深一层理解。 把省下的打字时间,投到问题定义、用户访谈和边界条件上去——那才是本质复杂度居住的地方。
  10. 留住骨干,也留住讲得出道理的人。 评估工程师时,把"能向人解释清楚为什么这样设计"重新放回核心标准——能被传承的判断,才是组织的能力。

十、结语:把人放大,而不是把人换掉

让我们回到"鹰"号上。1202 警报之所以是虚惊一场,是因为在那之前的许多年里,有一群人决定了什么任务值得在过载时被保留下来。机器执行了人的价值观——快得不可思议,但价值观是人的。

软件工程的历史,从来不是工具替代人的历史,而是人把重复劳动一层层交给机器、把判断和审美一层层留给自己的历史。汇编器、编译器、IDE、搜索引擎、Copilot 都是这条路上的台阶。AI 是迄今为止最高的一级台阶,但台阶的意义,是让人站得更高,而不是让人从建筑上消失。

所以,真正该问的问题不是"AI 能替代多少程序员",而是:

我们要用 AI 放大什么?是放大产量,还是放大品味、责任与人对人的关切?

最好的 AI 时代团队,会像 Sullenberger 与电传飞控的配合:机器处理它能处理的,人在不可预见之处接手;而那只稳住侧杆的手,来自无数次亲手飞行的沉淀。

人是尺度。过去是,现在是,AI 越强,就越是。


参考资料与延伸阅读

实证研究

经典文献与案例