芥末
发布于 2026-05-08 / 0 阅读
0
0

Vibe Coding 时代程序员的核心能力:上下文、验证与成本控制

人工智能(Artificial Intelligence,AI)编程工具越来越强以后,程序员面临的问题变了。

以前可以说:“复杂业务逻辑 AI 写不好”“并发代码 AI 容易出错”“安全代码还是得人写”。但现在,Claude Code、Codex、Cursor 这类工具已经能处理不少真实工程任务:跨文件修改、状态机实现、异常处理、单元测试补齐、代码审查、接口联调,很多都不再是演示级能力。

所以,程序员的优势不应该建立在“AI 做不了”上。

更准确的说法是:AI 能写很多代码,但它需要人把问题定义清楚、把上下文组织好、把结果验证明白,并对上线后的结果负责。

这才是 Vibe Coding 时代真正有竞争力的工程能力。

Vibe Coding 和 AI 辅助编程不是一回事

Vibe Coding 这个词通常指一种非常松散的开发方式:开发者把需求交给 AI,让 AI 生成代码,然后不仔细理解、不认真审查,直接接受结果。

它和正常的 AI 辅助编程差别很大。

维度Vibe CodingAI 辅助编程
需求输入模糊描述,依赖 AI 猜测明确业务规则、边界条件和技术约束
代码生成AI 负责大部分实现AI 参与实现,人负责方向和约束
代码审查粗略扫一眼甚至直接接受按业务语义、安全性、性能、可维护性审查
报错处理把错误粘给 AI 继续修先定位根因,再决定自己修还是让 AI 辅助
责任归属容易把问题归因给工具谁接受代码,谁对代码负责

真正的问题不在于“有没有用 AI 写代码”,而在于:你是否理解自己接受的代码,以及是否能为它负责。

一段 AI 生成的代码进入代码仓库后,就不再是“AI 的代码”,而是团队系统的一部分。线上出问题时,用户不会关心这段代码是谁生成的,只会关心系统为什么不可用、数据为什么错了、钱为什么退错了。

AI 辅助编程的合理流程应该是这样的:

flowchart LR
    A[模糊需求] --> B[拆解业务规则]
    B --> C[整理上下文]
    C --> D[让 AI 生成候选实现]
    D --> E[人工审查代码]
    E --> F[补充测试与验证]
    F --> G[发布上线]
    G --> H[监控与复盘]

    E -->|不符合预期| C
    F -->|测试失败| D

AI 在这个流程里承担的是“候选实现生成器”和“效率放大器”的角色,不能替代需求澄清、技术判断和结果负责。

程序员的优势不在于手速,而在于工程控制力

如果把 AI 当成一个很强的初级工程师,它的能力很明显:写得快、知识面广、不怕重复、能快速给出多个方案。但它也有明显限制:不知道业务背后的真实规则,不知道团队的历史坑,不知道某个看起来普通的字段其实是财务对账关键字段。

程序员的核心优势可以拆成五类。

flowchart TB
    A[程序员的工程控制力] --> B[问题定义]
    A --> C[上下文构建]
    A --> D[结果验证]
    A --> E[技术决策]
    A --> F[成本控制]

    B --> B1[把一句需求拆成可执行规格]
    C --> C1[给 AI 足够但不冗余的信息]
    D --> D1[判断代码行为是否符合业务语义]
    E --> E1[结合业务阶段和团队约束做取舍]
    F --> F1[控制 Token、时间和审查成本]

1. 问题定义能力:把一句话变成可执行规格

“加一个退款功能”不是一个可直接编码的需求。

AI 可以根据这句话写出一个退款接口,但它不知道这些问题的答案:

问题为什么重要
是否支持部分退款影响订单金额、库存、优惠分摊和财务对账
多次退款如何处理影响幂等性和退款状态流转
优惠券、积分、余额如何退回影响资金规则和用户权益
退款失败是否重试影响任务调度和异常补偿
退款超时如何关闭影响状态机和定时任务
已发货订单能不能退影响售后规则和履约系统

如果这些规则没有定义清楚,AI 生成的代码大概率只是“看起来像退款功能”。它可能有接口、有数据库操作、有状态更新,但关键业务语义不一定对。

一个可执行的退款规格至少要包含这些内容:

需求:创建退款申请接口

输入:
- orderId:订单 ID
- refundAmount:退款金额,单位为分
- reason:退款原因

业务规则:
- 只允许已支付且未全额退款的订单发起退款
- 支持部分退款,但累计退款金额不能超过实付金额
- 同一个 requestId 重复请求必须返回同一结果,不能重复退款
- 使用优惠券支付的订单,退款时优惠券不退回,只退现金部分
- 调用支付渠道失败时,退款单进入 RETRY_PENDING 状态

异常规则:
- 订单不存在:返回 ORDER_NOT_FOUND
- 订单状态不允许退款:返回 ORDER_STATUS_INVALID
- 退款金额非法:返回 REFUND_AMOUNT_INVALID

验收标准:
- 重复请求不会产生多笔退款
- 部分退款后订单保持 PARTIAL_REFUNDED 状态
- 全额退款后订单进入 REFUNDED 状态

当需求被拆到这个粒度,AI 才有可能生成接近可用的代码。否则,AI 只是在补全一个模糊想法。

2. 上下文构建能力:给足信息,但不要把代码库全塞进去

AI 输出质量高度依赖上下文质量。

同样是“实现退款接口”,两种输入会得到完全不同的结果:

输入方式可能结果
只写一句“帮我写退款接口”AI 根据通用经验生成代码,和当前系统不匹配
提供订单状态机、退款表结构、支付渠道接口、异常码规范AI 能生成更贴近工程现状的实现
把整个项目都丢给 AIToken 消耗暴涨,无关代码还可能干扰判断

上下文构建不是“给得越多越好”,而是“给得刚好够用”。

一份高质量上下文通常包括:

信息类型示例
业务规则哪些订单可退、金额如何计算、状态如何流转
数据结构订单表、退款表、关键字段含义
依赖接口支付渠道退款接口、库存回补接口
代码规范错误码、日志格式、事务边界、异常处理方式
边界条件重复请求、超时、失败重试、并发退款
禁止事项不要改公共接口、不要引入新依赖、不要改变旧字段含义

可以把上下文组织成固定模板,减少每次临时拼凑的成本:

## 背景
当前系统已有订单模块和支付模块,需要新增退款申请能力。

## 目标
实现 RefundService#createRefund 方法,并补充必要的单元测试。

## 相关代码
- OrderService:用于查询订单
- RefundRepository:用于保存退款单
- PaymentClient:用于调用支付渠道退款

## 业务规则
1. 只有 PAID、PARTIAL_REFUNDED 状态允许退款
2. 累计退款金额不能超过订单实付金额
3. requestId 必须保证幂等

## 技术约束
1. 不修改现有数据库字段
2. 不引入新的第三方库
3. 保持当前异常码风格
4. 事务只包裹本地数据库操作,不包裹外部支付调用

## 输出要求
1. 给出核心实现代码
2. 给出单元测试用例
3. 标出你认为需要人工确认的业务点

这类模板的价值不只是让 AI 更容易理解任务,也方便团队沉淀使用规范。

3. 结果验证能力:代码能跑,不代表业务是对的

AI 生成的代码最危险的地方不是语法错误,而是“合理但错误”。

这种代码通常具备几个特征:

  • 命名看起来正确;
  • 流程看起来完整;
  • 单元测试可能也能通过;
  • 但业务语义和真实需求不一致。

例如退款场景里,下面几类问题都不一定能靠简单测试发现:

问题表面现象实际风险
退到了错误账户接口返回成功资金损失
幂等键用错字段单次测试正常重复请求产生多笔退款
金额用浮点数计算小额测试正常对账出现精度误差
权限校验只查登录态普通用户可退别人的订单严重越权
支付调用放进数据库事务本地锁占用过久高并发下性能下降

审查 AI 代码时,不能只看“有没有编译错误”,还要检查三层含义:

flowchart TB
    A[AI 生成代码审查] --> B[业务语义]
    A --> C[安全风险]
    A --> D[工程质量]

    B --> B1[状态流转是否正确]
    B --> B2[金额、对象、权限是否符合业务规则]
    B --> B3[幂等和补偿是否完整]

    C --> C1[输入校验]
    C --> C2[权限控制]
    C --> C3[敏感信息处理]

    D --> D1[事务边界]
    D --> D2[性能风险]
    D --> D3[代码风格和可维护性]

测试也要围绕业务语义设计,而不是只覆盖主流程。

@Test
void shouldNotCreateDuplicateRefundWhenRequestIdRepeated() {
    // given
    String requestId = "refund-req-001";
    RefundCommand command = new RefundCommand(orderId, requestId, 1000);

    // when
    RefundResult first = refundService.createRefund(command);
    RefundResult second = refundService.createRefund(command);

    // then
    assertEquals(first.getRefundId(), second.getRefundId());
    assertEquals(1, refundRepository.countByRequestId(requestId));
}

这类测试表达的是业务约束:同一个幂等键只能产生一笔退款。AI 可以帮忙写测试,但测试目标必须由理解业务的人来定义。

4. 技术决策能力:AI 能列方案,不能替你拍板

AI 很擅长列出方案对比。例如“用 Redis 还是本地缓存”“用同步调用还是消息队列”“拆微服务还是保持单体”,它可以快速给出优缺点。

但真实技术决策不只看技术优点,还要看具体约束:

决策因素AI 不一定知道的信息
团队能力团队是否有维护消息队列、缓存集群、分布式事务的经验
历史事故过去是否因为缓存不一致、消息堆积、接口超时出过问题
业务阶段当前更需要快速交付,还是更需要长期稳定
运维成本是否有人值守、是否有监控、是否有回滚方案
合规要求数据能否上传外部服务,日志是否能记录敏感字段

例如,AI 可能建议“高并发读场景可以使用缓存”。这个建议本身没错,但如果团队过去因为缓存穿透和缓存不一致出过线上事故,那么新的缓存方案就必须同时设计降级、限流、空值缓存、监控告警和数据修复脚本。

技术决策可以用简单的架构决策记录沉淀下来:

# ADR-012:退款查询接口是否引入 Redis 缓存

## 背景
退款查询接口 QPS 上升,数据库读压力增加。

## 备选方案
1. 直接优化 SQL 和索引
2. 引入 Redis 缓存
3. 增加只读副本

## 决策
短期先优化 SQL 和索引,不引入 Redis。

## 原因
1. 当前慢查询主要来自缺失组合索引,缓存不是根因
2. 退款状态一致性要求高,缓存会增加一致性维护成本
3. 团队近期缺少缓存一致性监控

## 后续观察指标
- 接口 P95 延迟
- 数据库 CPU
- 慢查询数量

AI 可以辅助生成这份记录,但真正的取舍来自工程上下文。

5. 成本控制能力:AI 编程也有工程成本

Token 是大模型处理文本时使用的基本单位,输入的代码、提示词、历史对话、模型输出都会消耗 Token。很多 AI 编程工具按 Token 或请求量计费,长上下文、多轮对话、反复生成都会抬高成本。

AI 编程成本不只是账单,还包括:

成本类型说明
Token 成本输入、输出、缓存写入、工具调用带来的费用
时间成本等待模型生成、多轮修改、人工审查
认知成本理解 AI 改了什么,判断是否符合系统约束
风险成本错误代码进入仓库后带来的排查和回滚成本

所以,AI 编程不是“能用就用”,而是要判断综合成本。

Token 成本控制的五个策略

Token 成本控制的目标不是一味省钱,而是在质量、速度和费用之间找到合适平衡。复杂重构用强模型是合理的,一行配置修改却让 AI 扫完整个项目,就很浪费。

策略一:模型路由,不同任务用不同级别模型

不是所有任务都需要最强模型。简单补全、格式调整、注释生成通常不需要深度推理;架构设计、跨模块重构、复杂缺陷分析才更依赖强模型。

任务类型推荐模型级别原因
代码补全、变量改名、格式调整小模型任务模式固定,低成本即可完成
单个函数实现、常规缺陷修复中模型需要理解局部上下文
跨文件修改、状态机、复杂重构大模型需要更强推理和更长上下文
代码解释、文档生成小模型或中模型主要是归纳和表达
安全审查、架构评审大模型 + 人工复核错误代价高,需要深度分析

模型路由可以做成一条简单规则链:

flowchart TD
    A[开发任务] --> B{是否涉及跨模块影响}
    B -->|是| E[大模型]
    B -->|否| C{是否需要业务推理}
    C -->|是| D[中模型]
    C -->|否| F[小模型]
    E --> G[人工严格审查]
    D --> H[常规审查]
    F --> I[快速确认]

不同模型的价格差距可能很大。大量日常任务如果都交给最高级模型,账单会很快膨胀;反过来,复杂任务强行用小模型,可能产生更多返工和审查成本。

策略二:上下文管理,只给相关信息

上下文窗口是 Token 消耗的大头。把整个项目交给 AI,让它“自己找”,看起来省事,实际会带来两个问题:

  1. 无关代码增加 Token 消耗;
  2. 噪音信息干扰模型注意力,生成质量可能下降。

更合理的做法是按需组织上下文。

做法说明
只给相关文件修改用户模块时,只提供用户模块及其直接依赖
用摘要代替全文长配置文件、长接口文档可以先给摘要
分阶段加载先给接口和业务规则,需要实现细节时再补充文件
清理历史对话长会话积累大量旧上下文,任务切换时应开启新会话
排除敏感目录密钥、核心算法、生产配置不进入 AI 上下文

可以把上下文分成三层:

flowchart LR
    A[任务目标] --> B[必要上下文]
    B --> C[可选上下文]
    C --> D[禁止上下文]

    B --> B1[业务规则]
    B --> B2[相关代码]
    B --> B3[接口定义]

    C --> C1[相似实现]
    C --> C2[历史设计说明]

    D --> D1[密钥]
    D --> D2[生产配置]
    D --> D3[无关模块源码]

高质量上下文通常比大上下文更重要。给 AI 一堆无关文件,不如给它一份准确的业务规则和两三个关键代码片段。

策略三:Prompt 写清楚,减少反复来回

模糊 Prompt 最大的问题是会制造多轮返工。

低质量输入通常是这样:

帮我写一个退款接口。

AI 会自己猜技术栈、参数、状态、异常、权限、幂等规则。生成结果不符合预期后,又要继续补充条件、重新生成、继续审查,Token 和时间都会被消耗掉。

更好的输入是这样:

请在现有 Spring Boot 项目中实现退款申请功能。

目标:
- 新增 RefundService#createRefund(RefundCommand command)
- 不需要写 Controller,只写 Service 和单元测试

业务规则:
- 只有 PAID 和 PARTIAL_REFUNDED 订单允许退款
- 累计退款金额不能超过订单实付金额
- requestId 用于幂等,同一个 requestId 重复调用返回同一退款单
- 支付渠道调用失败时,退款单状态为 RETRY_PENDING

技术约束:
- 使用现有 RefundRepository,不新增依赖
- 本地数据库操作需要事务
- 外部支付调用不能放在数据库事务内
- 使用项目已有 BusinessException 和 ErrorCode

输出:
1. RefundService 核心代码
2. RefundServiceTest 单元测试
3. 标出需要人工确认的业务点

好的 Prompt 不只是“说得更详细”,而是减少模型猜测空间。模型猜得越少,返工越少,审查也更容易。

策略四:缓存和复用,不要每次从零开始

很多团队的业务代码有大量重复模式,例如增删改查(Create、Read、Update、Delete,CRUD)、参数校验、分页查询、权限检查、异常封装、日志格式。每次都让 AI 从零生成,既浪费 Token,也容易生成风格不一致的代码。

可以复用三类资产:

复用方式适合场景
Prompt 模板固定代码风格、固定输出结构、固定审查要求
代码模板CRUD、表单校验、消息消费、定时任务
上下文摘要模块职责、核心数据结构、接口约定

例如团队可以维护一个标准 CRUD 模板:

## CRUD 生成规范

请基于已有代码风格生成资源管理接口,要求:
1. Controller 只做参数接收和响应封装
2. Service 负责业务校验
3. Repository 负责数据访问
4. 所有列表接口必须分页
5. 创建和更新接口必须校验字段合法性
6. 删除接口使用逻辑删除
7. 补充单元测试,覆盖正常、参数非法、资源不存在三类场景

如果使用支持 Prompt Caching 的模型服务,相同前缀还可以命中缓存,减少重复计算成本。即使不直接使用缓存能力,模板化也能减少沟通成本和审查成本。

策略五:判断任务是否真的适合交给 AI

有些任务让 AI 做更贵。

例如线上出现一个 NullPointerException,日志已经明确指向 OrderService.java 第 127 行,原因是 user.getAddress() 没有判空。熟悉代码的人手动加一行空值判断,可能几十秒就能完成。

如果交给 AI,流程可能变成:

sequenceDiagram
    participant Dev as 开发者
    participant AI as AI 工具
    participant Repo as 代码仓库

    Dev->>AI: 粘贴异常日志
    AI->>Repo: 读取相关文件
    AI->>AI: 分析调用链路
    AI-->>Dev: 生成修复方案
    Dev->>Dev: 审查是否改对位置
    Dev->>Repo: 应用修改

这个流程会消耗 Token,还可能引入额外修改。对于已经定位清楚、修改点明确的小问题,直接手写往往更快、更便宜。

可以用一张表判断是否适合交给 AI:

场景更适合 AI更适合手写
大量样板代码
多方案探索
不熟悉框架的入门代码
已定位的一行修复
业务风险极高的核心逻辑可辅助,但必须严审
已有模板复制即可完成

判断标准不是“AI 能不能做”,而是:AI 做完之后的生成、等待、审查、返工成本,是否低于自己完成的成本。

AI 生成代码的团队治理

个人使用 AI 写代码,只要自己负责即可;团队规模变大后,必须有明确规范,否则代码质量和安全边界会失控。

代码归属:谁接受,谁负责

AI 生成的代码不能成为责任真空区。一个简单规则足够清晰:

谁把代码提交进仓库,谁负责理解、审查和维护。

这意味着开发者不能用“这是 AI 写的”解释线上问题。AI 可以参与生成,但提交者必须能解释代码行为、边界条件和失败处理。

审查流程:AI 代码走同样的 Review

AI 代码不应该绕过正常 Code Review。相反,部分 AI 代码更需要重点审查,因为它可能写出“看起来很合理但业务不对”的实现。

审查清单可以固定下来:

审查项关注点
业务语义金额、状态、对象、权限是否符合规则
安全风险输入校验、越权访问、敏感数据泄露
幂等处理重复请求、重试、并发是否安全
事务边界本地事务和外部调用是否混在一起
性能风险是否出现 N+1 查询、全表扫描、大对象加载
可维护性是否符合项目分层、命名和异常规范
测试覆盖是否覆盖主流程、异常流程和边界条件

N+1 查询指的是先查询一批主数据,再对每条主数据单独查询关联数据,最终产生大量数据库请求。AI 生成列表查询时很容易写出这类代码,需要特别检查。

线上事故处理:先恢复服务,再分析 AI 使用流程

如果 AI 生成的代码导致线上问题,处理顺序不应该因为“代码来自 AI”而变化。

flowchart LR
    A[线上异常] --> B[止血]
    B --> C[定位影响范围]
    C --> D[追踪根因]
    D --> E[修复发布]
    E --> F[补测试]
    F --> G[调整 AI 使用规范]

关键动作包括:

  1. 止血:回滚、降级、关闭开关,先恢复用户侧服务。
  2. 定位影响范围:查看监控、日志、链路追踪和数据异常范围。
  3. 追踪根因:确认是需求理解错误、上下文缺失、审查遗漏,还是测试覆盖不足。
  4. 补流程:增加测试用例、更新审查清单、限制某类任务使用 AI 自动生成。

一次故障不可怕,真正危险的是同类问题反复发生。

代码安全:不要把敏感信息交给外部模型

AI 编程工具通常需要读取本地代码,并把上下文发送到模型服务端推理。即使供应商承诺不会用于训练,企业仍然需要考虑合规和数据安全。

常见做法包括:

措施说明
使用企业版获得数据隔离、权限管理和审计能力
敏感项目禁用外部 AI核心算法、密钥管理、交易策略等不上传
配置忽略文件防止工具读取密钥、配置、生产脚本
制定团队规范明确哪些项目可用 AI,哪些禁止
保留审计记录方便追踪谁在什么任务中使用了 AI

例如可以维护 .claudeignore 或类似配置:

# 密钥和证书
*.pem
*.key
*.p12
.env
.env.*

# 生产配置
config/prod/
deploy/secrets/

# 核心敏感模块
src/main/java/com/example/risk/core/
src/main/java/com/example/payment/secret/

# 大文件和无关产物
target/
build/
logs/

这类配置的目的不是降低 AI 能力,而是给 AI 设置边界。能用 AI 的地方充分用,不能上传的内容必须挡住。

面试中更稳的回答方式

当被问到“AI 越来越强,程序员的优势是什么”,不要把回答建立在“AI 写不了复杂业务”上。这个说法很容易被反问:如果给足上下文呢?如果模型再强一点呢?

更稳的回答可以围绕工程闭环:

AI 的代码生成能力已经很强,我不会把优势定义成比 AI 手写更快。我的优势在于控制 AI 编程的整个工程过程:把模糊需求拆成明确规格,给模型组织高质量上下文,审查生成代码的业务语义和安全风险,结合团队现状做技术决策,并控制 Token、审查和返工成本。AI 可以生成代码,但我负责让代码正确、可维护、可上线。

如果继续追问“哪些代码让 AI 写,哪些自己写”,判断标准可以这样表达:

判断维度处理方式
代码模式固定、风险低让 AI 生成,提高效率
需要多方案探索让 AI 辅助分析,再人工决策
修改点明确且很小直接手写
核心资金、安全、权限逻辑AI 可辅助,但必须人工严格审查
涉及敏感代码不上传外部 AI 工具

如果追问“AI 代码出问题怎么办”,回答重点是责任和流程:

不把问题归因给工具。先回滚或降级恢复服务,再通过监控、日志和链路追踪定位根因。确认问题后补测试、补审查规则,并调整 AI 使用边界。谁接受代码谁负责,AI 只是生成工具,不能替代工程责任。

真正的优势是让 AI 写得更可靠

Vibe Coding 的风险不在于使用 AI,而在于放弃理解和责任。

AI 编程越强,程序员越需要把精力从“逐行敲代码”转到“定义问题、组织上下文、验证结果、做取舍、控成本”上。手写能力仍然重要,因为 AI 修不了、线上等不了、复杂事故需要人接手;但更关键的是工程控制力。

一句话概括:

程序员的优势不是比 AI 更会补全代码,而是能让 AI 生成的代码更符合业务、更安全、更省成本,并且能为最终结果负责。


评论