1900 年前后的纽约街头,马车还是绝对的主角。据当时市政记录,全城有近 20 万匹马,每天产生约 450 万磅马粪,被失控马匹撞伤、踢伤的行人数量更是惊人。1908 年,福特 T 型车量产,1913 年流水线发明后汽车价格骤降,到了 1920 年代,马车几乎从城市彻底消失。马夫、马掌匠、马商、饲草贩——这些人的生计不是在某一天的“宣告日”里集体终结的,而是在十年间逐渐发现,自己的技能不再有人需要。
这段历史经常被用来解释“AI 会不会取代人类工作”——“当年马车夫不也转行当司机了吗?”但实际情况要残酷得多:马车夫面对的是一门完全陌生的技术,驾驶汽车的能力和驾驭马匹几乎没有重叠。所谓“转行”,从来都不是“总可以”的轻松事。
现在,同样的故事正在编程行业上演。GitHub Copilot、Cursor、Claude Code 这类 AI 编程工具,已经将“用自然语言描述需求,得到可运行代码”的成本降到了极低。无数程序员开始问:当 AI 能写代码时,我为什么还要学写代码?当 AI 写得比我快时,我会不会被替换?
这篇文章想给出一个更具体的答案:AI 确实在让某些技能贬值,但贬值的不一定是“编程”,而是“只会编码”这一层能力。问题从来不在于 AI 会不会取代程序员,而在于——在一个 AI 能生成代码的世界里,程序员该怎么重新定义自己的价值。
1. 世界不再需要马,但“运输”从来没有消失
先回到“马与汽车”这个类比。我们需要拆开看,它到底在什么层面上成立,在什么层面上失真。
马被汽车取代,本质上是三件事同时发生:
- 功能被超越:汽车比马跑得快、跑得远、载重大,还不累。
- 成本被碾压:汽车不需要每天喂食、清理粪便、看病,保养成本远低于养马。
- 维护门槛降低:驾驶汽车的学习难度低于驾驭马匹,普通人几天就能上手。
对照 AI 编程,你会发现几乎一模一样:
- AI 生成代码的速度远超人类,模板代码、CRUD、配置脚本,这些场景下 AI 的产出效率是人类的数倍。
- AI 使用的边际成本极低,订阅费远低于一名初级开发者的月薪。
- 学会用 AI 生成代码的门槛很低,会用自然语言描述需求就能上手。
所以从“编码实现”这一层看,AI 正在走汽车取代马的老路。这没有什么好回避的。
但故事还有另一半:马消失之后,“运输”这件事并没有消失,而是被彻底重构了。城市不需要马了,但需要修路工、加油站员工、汽车机械师、交通警察;乡村不需要马耕地了,但需要农机操作员、化肥供应商、农产品物流商。旧技能没法直接迁移,但旧需求演化出了新形态,新形态创造了一大批旧时代不存在的工作岗位。
程序员现在面对的正是这种局面:代码这个“旧需求”不会消失,但生产代码的方式在剧烈变化。软件工程的价值链条没有缩短,只是重心在移动。
2. 编码正在贬值,但工程判断正在升值
要看清程序员价值在哪,先要看软件工程的全流程包含什么。传统意义上,一个功能从 idea 到上线,大致经过:
- 需求澄清
- 系统设计
- 编码实现
- 代码审查
- 测试验证
- 部署运维
- 文档协作
过去这七个环节中,编码实现是工作量最大、人数最多、门槛最直观的一环。大量初级开发者的日常工作就是“把别人设计好的方案翻译成代码”。而这恰恰是当前 AI 最擅长的事情。
下面的表格,是从“AI 介入程度”和“技能价值变化”两个维度,对七个环节做的一个判断:
| 环节 | AI 介入程度 | 技能价值变化 | 核心原因 |
|---|---|---|---|
| 需求澄清 | 中 | 显著升值 | AI 能整理需求,但需求本质是业务约束的权衡,只有人能决策 |
| 系统设计 | 中 | 升值 | AI 能提供候选方案,但选型依赖架构经验、团队技术栈、成本模型 |
| 编码实现 | 高 | 明显贬值 | 模板代码、CRUD、简单脚本会被 AI 大量代劳 |
| 代码审查 | 中 | 升值 | AI 能标出模式化问题,但行为契约和业务逻辑需要人来判断 |
| 测试验证 | 中 | 升值 | AI 能生成测试用例,但测什么、怎么测,需要人来定义 |
| 部署运维 | 中 | 相对稳定 | AI 能辅助排查,但事故响应的责任链无法外包 |
| 文档协作 | 高 | 相对稳定 | AI 能写文档,但准确性和和维护需要人把控 |
结论很明确:贬值的是“把方案翻译成代码”的纯编码能力,升值的是“判断正确性”的工程能力。
为什么?因为 AI 编程工具的本质,是一个“语义匹配引擎”。它根据你的 prompt,在训练数据中找到最相似的输入输出模式,然后把最可能的 token 序列生成出来。它擅长的是“这段需求看起来像什么”,而不是“这个约束条件下哪条路径是正确的”。
这个机制决定了 AI 生成代码的天然弱点:
- 只看到局部的需求描述,看不到系统的全局约束。
- 优化目标是生成“看起来合理的文本”,而不是“在运行时绝对正确的代码”。
- 对边界条件、异常路径、并发冲突、安全漏洞的考虑,取决于训练数据里是否出现过类似模式。
简单说:AI 能写出 90 分正确的代码,但工程需要的是 99.9 分的代码。那 9.9 分的差距,就是未来程序员的核心价值。
3. 一个具体的实验:AI 辅助编码的边界在哪里
讲概念容易,落到代码才能看清边界。我们用一个非常常见的任务来测试:用户注册接口。
先给出一段 Prompt:
请用 Python FastAPI 写一个用户注册接口。 要求: 1. 接收 username、email、password 三个字段 2. 校验用户名长度不少于 3 个字符 3. 校验邮箱格式 4. 密码长度不少于 8 个字符 5. 用户已存在时返回 409 错误 6. 注册成功后返回 201这段 Prompt 写得已经算详细了。AI 通常能在几秒内给出一个可以运行的代码,类似这样:
# 文件路径:main.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel, EmailStr app = FastAPI() fake_users_db = {} class RegisterRequest(BaseModel): username: str email: EmailStr password: str @app.post("/register", status_code=201) def register(req: RegisterRequest): if len(req.username) < 3: raise HTTPException(status_code=400, detail="用户名长度不能少于3个字符") if len(req.password) < 8: raise HTTPException(status_code=400, detail="密码长度不能少于8个字符") if req.username in fake_users_db: raise HTTPException(status_code=409, detail="用户已存在") fake_users_db[req.username] = { "email": req.email, "password": req.password, } return {"message": "注册成功"}单看这个代码,功能似乎全部实现了。但如果你带着工程视角去审查,会发现至少 5 个问题:
- 密码明文存储。
req.password直接被写入内存或数据库,这在任何正规项目里都是不可接受的。应该用 bcrypt 或 argon2 做哈希。 - 唯一性判断不完整。只检查了
username是否重复,没有检查email是否重复。很多系统允许用户名不同但邮箱相同的情况吗?不一定。 - 并发问题。
fake_users_db是普通字典,多线程请求下会出现竞态条件,重复注册可能绕过唯一性检查。 - 错误提示信息泄漏。用“用户已存在”这样的提示,攻击者可以批量探测用户名是否注册过。
- 没有日志和可观测性。生产环境里注册接口是攻击面,没有访问日志、没有失败告警,出了问题完全无从排查。
这些点,AI 在简单 Prompt 下几乎不会主动考虑到。你需要在 Prompt 里明确写“请考虑安全、并发、可观测性”,它才会开始补这些内容。但问题是——如果你的工程能力不足以发现这些问题,你连该在 Prompt 里补什么都不知道。
这正是“AI 增强但不等于 AI 替代”的最直接证据。
4. 马夫时代的转型,难在换一套心智模型
网上常说“马车夫转行当司机”。但你想想,一个和马打了一辈子交道的人,突然要面对发动机、变速箱、油门刹车,他的第一反应不是“我要学新技能”,而是“这玩意儿没有生命,我不懂它”。
程序员面对 AI 也是如此。很多人以为从传统编程切换到 AI 辅助编程,只需要学几个 Prompt 技巧。但真正的转型难点在于换一套心智模型:从“我亲手写每一行代码”到“我定义正确性,AI 负责填充实现”。
这套新心智模型,具体包含下面四个转变。
4.1 从“写代码”到“定义正确性”
传统编程中,代码本身是正确性的载体:我写了if len(req.username) < 3,这就是行为。AI 辅助编程中,你要做的是先定义“正确”是什么,再让 AI 产出实现。
定义正确性的工具有很多:单元测试、类型系统、接口契约、schema 定义。举个例子,与其让 AI 直接生成注册接口代码,不如先写一组测试,定义期望行为:
# 文件路径:test_register.py import pytest from fastapi.testclient import TestClient from main import app client = TestClient(app) def test_register_success(): resp = client.post("/register", json={ "username": "alice", "email": "alice@example.com", "password": "hunter2secure" }) assert resp.status_code == 201 def test_duplicate_username_returns_409(): client.post("/register", json={ "username": "bob", "email": "bob@example.com", "password": "anotherpass123" }) resp = client.post("/register", json={ "username": "bob", "email": "bob_other@example.com", "password": "anotherpass123" }) assert resp.status_code == 409这些测试本质上是在告诉 AI(以及未来的维护者):“注册成功应该返回什么”、“用户名重复应该返回什么”。当测试先行时,AI 的生成空间就被约束在了你定义的边界内。
4.2 从“实现功能”到“识别风险”
AI 很擅长实现功能,但它不会主动告诉你:“这段代码有安全漏洞”或者“这个接口在流量高峰会超时”。风险识别是工程判断力最核心的组成部分。
我问过很多资深开发者,他们在审查 AI 生成的代码时,默认会检查哪些点。比较共识的清单包括:
- 输入校验:有没有过滤异常参数、超长字符串、类型不匹配?
- 认证授权:接口是否在正确的权限边界内?用户能否越权访问?
- 数据存储:敏感字段是否加密?SQL 是否存在注入风险?
- 事务边界:多表更新时,失败会不会导致数据不一致?
- 并发控制:多实例部署下,锁和幂等性是否可靠?
- 可观测性:有没有日志、指标、告警?
- 幂等性:重试请求会不会产生重复数据?
这份清单的价值不在于“记住它”,而在于发现问题之后,你能把这些问题转写成新的约束条件,追加到 Prompt 里,让 AI 重新生成。这个过程不是一次性的,而是一个闭环:AI 生成 -> 人审查 -> 发现风险 -> 追加约束 -> AI 再生成。
4.3 从“单点技能”到“全链路判断”
过去程序员可以只精于“编码”这一个点,把需求分析交给产品经理,把架构设计交给架构师,把测试交给测试工程师。但 AI 辅助编程时代,编码效率大幅提升之后,制约你产出速度的瓶颈会迅速转移到其他环节——需求是不是清楚的?方案是不是合理的?测试是不是有效的?
这意味着,程序员需要从单点技能走向全链路判断。你不需要成为每个环节的专家,但必须在每个环节都能做出基本的判断:这个需求合理吗?这个方案有没有更好的替代?这条测试真正覆盖了业务规则吗?
一个很直观的变化是:过去一个三人小团队(产品 + 后端 + 前端)要配合两周才能做出一个内部工具;现在一个能全链路判断的开发者,用 AI 两天就能做完从需求到上线的全部工作。AI 正在把“全栈”的门槛拉低,但“全链路判断”的壁垒反而拉高。
4.4 从“写得出”到“讲得清”
当 AI 能写出能运行的代码后,团队内的沟通价值不降反升。因为 AI 生成代码之后,需要有人向团队成员解释:这段代码是什么、为什么这么写、边界在哪里、测试覆盖了什么。
很多开发者的习惯是“代码即文档”——代码写出来,别人自己看。但 AI 生成代码的上下文往往缺失,没有人审过、没有注释、没有设计文档,接手的人根本无从下手。一个负责任地使用 AI 的工程师,一定会在提交代码时附上一段说明:这段代码要做什么,为什么采用这个方案,有哪些边界条件,测试覆盖了哪些场景。
这种“讲得清”的能力,本质上还是工程判断力。AI 不会帮你讲,你只能自己先想清楚。
5. 团队引入 AI 编码:不是“全员用 AI”,而是“重构开发流程”
很多团队引入 AI 编程的姿势是:买一个工具,全员启用,然后等着效率翻倍。实际效果往往是:老手用得很爽,新手用 AI 写出了一堆没人能维护的代码,线上事故率不降反升。
问题出在流程设计上。AI 不是一块可以随机嵌入的补丁,它是一台重新定义“代码生产”方式的机器。团队真正需要做的,不是“全员用 AI”,而是“让 AI 进入开发流程的正确位置”。
5.1 建立 AI 代码审查规范
AI 生成代码,和人类写代码,在审查时的注意点不完全一样。人类容易犯的错是笔误、逻辑拷贝、边界漏写;AI 容易犯的错是“看起来正确但实际不符合业务规则”、“忽略并发和事务”、“测试用例全部通过但没测到点子上”。
更稳妥的做法,是把“AI 生成代码”当成一个单独的 PR 来源,在普通的代码审查流程之上,增加一道 AI 代码专项检查:
AI 生成代码审查清单: 1. 是否匹配需求描述?还是 AI 自行发挥了功能? 2. 是否有业务规则被简化或跳过? 3. 是否考虑了异常、超时、并发、回滚? 4. 安全校验是否完整(认证、权限、输入校验、敏感数据加密)? 5. 测试是否真的覆盖了业务规则,而不是只覆盖了正常路径? 6. 是否引入不必要的依赖或复杂度? 7. 是否符合项目的代码风格和架构规范?5.2 把测试写在 AI 生成之前
前面已经说过,测试先行是约束 AI 行为最有效的方式。团队层面也一样:需求评审时,先定测试场景和验收标准,再进入编码阶段。
实际操作中,代码评审时最担心的是 AI 生成了“测试用例全绿但完全没有测到业务核心”的空转测试。所以团队规范应该是:验收标准先于代码,测试场景先于实现。AI 可以帮忙生成测试代码,但“测什么”这个决策,必须由人来定。
5.3 沉淀“约束库”,让 AI 更懂项目
项目级约束如果只存在于人类开发者的记忆里,AI 永远学不会。更好的做法是,把项目的架构规范、安全要求、命名规则、常见错误模式沉淀成一个文档或 context 文件,在 AI 辅助编码时作为上下文输入。
一个精简的例子,可以是这样一份AI_CONTEXT.md:
# 项目约束(供 AI 辅助编码使用) ## 技术栈 - 后端:Python 3.11 + FastAPI - 数据库:PostgreSQL 15 - ORM:SQLAlchemy 2.0 ## 必须遵守 1. 所有数据库写入操作必须使用事务 2. 用户密码必须使用 bcrypt 哈希存储,禁止明文 3. 所有 API 必须有输入校验和鉴权 4. 所有新增接口必须至少包含一个成功测试和一个失败测试 5. 错误消息不允许泄漏内部实现细节(如堆栈、SQL、文件路径) 6. 日志使用结构化日志格式(JSON),禁止 print 输出 ## 禁止 - 禁止使用全局可变状态 - 禁止在业务代码中使用裸 SQL 拼接 - 禁止生成无错误处理的代码如果团队能沉淀出这样一份文档,AI 生成的第一版代码的质量会明显高出一个档次。因为约束信息本身就是工程判断能力的外化——你能写出什么约束,AI 就能产出什么质量的代码。
5.4 把“验证能力”纳入考核
在 AI 辅助编程的团队里,一个工程师的核心竞争力不再是“写代码快”,而是“能验证 AI 给的结果是否值得信任”。这需要把验证能力纳入考核和培训:
- 代码审查的通过率(而不是代码行数)
- 线上事故率(AI 引入的问题是否被及时拦截)
- 测试覆盖率的质量(是否覆盖了关键业务规则,而不是只看行覆盖率)
- 文档和约束库的维护情况
团队如果还在用“代码行数”或“Pull Request 数量”来考核工程师,那本质上还是在奖励“编码产量”。但在 AI 时代,编码产量已经不再稀缺,稀缺的是“判断正确性”的人。
6. 常见误区:关于 AI 与工作的五个错误回答
在讨论 AI 对程序员的影响时,有几个误区反复出现。把这些误区澄清,可以帮助你更理性地规划自己的职业路径。
| 误区 | 真相 |
|---|---|
| AI 会让程序员失业 | AI 会让“只会编码”的程序员失业,但会让“会验证 AI 产出”的程序员更值钱 |
| 提示词工程是未来核心技能 | 提示词只是入口,核心是工程判断力;你不会因为会写 Prompt 就变得稀缺 |
| AI 生成的代码可以直接上线 | 可以运行不等于可以上线;AI 生成的代码需要审查、测试、约束补充 |
| 只要买了 AI 工具,效率就会翻倍 | 效率提升的前提是流程重构和人员能力升级,工具只是必要条件 |
| AI 会替代所有编程岗位 | 更可能的是岗位结构调整:纯编码岗位减少,AI 应用开发、AI 测试验证、架构设计岗位增加 |
这里特别想展开讲一下“Prompt 工程”这个问题。很多人以为,学会写 Prompt 就能用好 AI,未来最值钱的技能是“用文字指挥 AI”。
但回到本质:Prompt 本身只是自然语言。你写“请生成一个用户注册接口”,AI 给你的结果和你写“请生成一个用户注册接口,要求事务、密码哈希、防暴力破解、幂等性”,结果的差异不来自“Prompt 技巧”,而来自你脑子里有没有“事务、密码哈希、防暴力破解、幂等性”这些工程知识。
Prompt 是工程判断力的传声筒,工程判断力本身才是稀缺品。没有后者,前者只是花哨的措辞。
7. 未来 2—3 年,程序员能力结构的变化
基于当前 AI 编码工具的发展速度和工程实践约束,可以对未来 2—3 年的能力结构变化做一个保守判断。
7.1 纯编码岗会收缩,但不会消失
模板代码、基础 CRUD、配置脚本,这些工作会大量被 AI 替代。但总有一些编码工作需要人来完成:高度复杂、高度定制、对性能和安全要求极高的场景,以及 AI 无法覆盖的存量系统改造。纯编码岗位会收缩到“AI 做不了的编码”这个更窄的区间。
7.2 验证能力会成为基础技能
“如何确认 AI 生成的代码是对的”会成为所有开发者的基础技能。这包括:测试设计能力、代码审查能力、安全风险判断能力、性能瓶颈定位能力。过去这些能力是高级工程师的加分项,未来会成为普通开发者的必备项。
7.3 架构和设计岗位的价值进一步放大
当 AI 能快速实现“一个接口”之后,更大的问题变成“系统该怎么设计”。AI 可以把单体应用的接口写得很高效,但它无法判断你的系统应该用微服务还是单体、应该用消息队列还是直接调用、应该用关系型数据库还是向量数据库。这些架构决策的复杂度不会因为 AI 而降低,反而因为实现成本降低而让“错误选择”的代价更大。
7.4 领域知识变得空前重要
AI 生成通用代码已经足够好,但它在特定领域的表现高度依赖训练数据覆盖度。一个懂金融风控、懂医疗数据合规、懂电商库存模型的工程师,能用 AI 生成远超通用水平的解决方案,因为他知道业务领域中最关键的约束在哪里。领域知识 + AI 辅助,将成为未来最稀缺的组合。
7.5 新的岗位角色会出现
可以预见的角色包括:
- AI 编码审查员:专门审查 AI 生成代码的正确性、安全性和可维护性。
- AI 应用架构师:设计 AI 原生应用的架构,处理模型调用、上下文管理、成本控制。
- AI 验证工程师:设计测试策略,确保 AI 生成的系统行为符合预期。
- 约束库维护者:把团队的工程经验沉淀为 AI 可读取的规则和 Prompt 模板。
这些角色有一个共同特点:它们都不是“写代码”的角色,而是“判断和定义”的角色。
8. 给个人开发者的具体行动清单
如果这篇文章能给你留下一点可执行的东西,那就是下面这份清单。它不是“十年规划”,而是接下来 90 天就能开始做的事。
- 挑一个真实的项目,用 AI 重写一遍。不是玩具项目,是你日常工作里真实存在的系统。用 AI 生成功能代码,然后用工程视角去审查、补测试、修边界。这个过程中,你会最直观地感受到 AI 的边界和自己的短板。
- 学习测试设计,而不是只学 Mock 写法。会写单元测试不难,难的是知道哪些测试值得写。推荐从“测试金字塔”开始,重点练习行为驱动测试(BDD)风格的测试用例设计。
- 每次 AI 生成代码后,强制自己写一份“缺陷清单”。列出 AI 生成代码中你发现的所有问题:边界、安全、性能、可维护性。坚持一个月,你会发现自己对“好代码”的判断力有明显提升。
- 把项目的架构规范、安全要求、命名规则沉淀成一个文档。这份文档可以当成 Prompt 的上下文输入给 AI。这不仅是给 AI 用的,也是给团队协作用的——它能倒逼你把默认约束显性化。
- 学一门不依赖框架的底层课程。比如操作系统、计算机网络、数据库原理。AI 能帮你快速生成应用层代码,但底层问题的排查和优化,需要的是系统级理解。这是 AI 短期内最难替代的部分。
9. 最后的判断:AI 不会让程序员失业,但会重新分配价值
回到最开始的那个问题:世界不需要马的那一天,马去哪儿了?
马没有“失业”,因为马本来就没有“职业”。但马夫、马掌匠、马商有职业,他们的职业确实消失了。同样,程序员这个身份不会消失,但“程序员”这三个字的内涵会发生剧烈变化。过去,它意味着“会写代码的人”;未来,它更可能意味着“能让 AI 产出正确代码的人”。
这个转变,本质上不是 AI 的胜利,而是工程判断力的胜利。AI 把“写代码”这门手艺变成了一个廉价的商品,但当商品廉价到几乎免费时,真正值钱的是知道“应该买什么商品”的能力——也就是知道“系统应该长什么样、怎么做才能正确运行”的能力。
对开发者个体而言,现在最值得做的事不是焦虑,也不是狂欢,而是认真回答一个问题:如果“编码”这个技能不再稀缺,你还能为团队提供什么不可替代的价值?
如果你的答案要靠“我比别人写代码快”来支撑,那这个答案在 AI 面前站不住脚。如果你的答案是“我能定义正确性,我能设计系统,我能验证结果”,那么 AI 对你来说,不会是一辆终结马车的汽车,而是一台让你跑得比所有人都快的引擎。