烧完100亿Token才明白:AI编程时代,值钱的从来不是代码

发布时间:2026/10/30 7:47:33
烧完100亿Token才明白:AI编程时代,值钱的从来不是代码

1. 100亿Token烧完,我才看懂“Code is cheap”这句话的陷阱

“Code is cheap”——代码便宜了,写代码不值钱了。这句话在过去一年里被反复提起,几乎成了AI编程时代的口头禅。配合着各种演示视频里“一句话生成一个App”“三分钟搭完一个后台”的画面,很多人真的信了:既然AI能写代码,那写代码这件事本身就不值钱了,程序员的核心价值要转移到别的地方去了。

我一开始也这么觉得。直到我自己在几个真实项目里,把Token用量堆到了接近100亿这个量级,我才发现这句话是个彻头彻尾的谎言——或者说,是一个被严重误读的半真半假的判断。

先把这个数字说清楚。100亿Token听起来很吓人,但拆开看并不夸张。一个中等复杂度的项目,如果全程用AI辅助开发,包括需求澄清、方案讨论、代码生成、测试用例编写、Bug排查、重构、文档撰写,单日消耗几百万到上千万Token是很正常的事。几个月下来,几个项目叠加,累计到几十亿甚至上百亿Token,对于重度使用者来说完全可能。我身边做AI编程工具链的朋友,团队级别的月消耗量早就过了这个数。

但真正让我警觉的,不是Token烧了多少,而是烧完之后回头看,我发现真正值钱的东西,从来就不是“代码”本身。AI确实让“敲代码”这个动作变便宜了,但它同时让另外一些东西变得极其昂贵——昂贵到你如果没有这些能力,AI生成的代码就是一堆需要你花更多时间去收拾的烂摊子。

这篇文章我想聊的就是这件事。我会从Token消耗的真实结构讲起,拆解为什么“Code is cheap”是一个危险的误判,然后落到具体的方法论上:SDD(Specification-Driven Development,规格驱动开发)到底怎么落地,CLAUDE.md这类上下文文件为什么关键,Lint和测试在AI编程里扮演什么角色,以及一个普通开发者怎么在AI时代重新找到自己的价值锚点。

适合谁看?如果你正在用AI写代码,或者准备把AI编程引入团队流程,或者你只是隐约觉得“AI来了我该怎么办”,这篇文章里的经验应该对你有用。我不讲虚的,只讲我烧掉真金白银之后换来的教训。

2. Token消耗的真实结构:钱到底花在哪了

2.1 大部分人低估了“上下文”的Token成本

很多人算AI编程的成本,算的是“生成一个函数要多少Token”。这个算法从根上就错了。

在实际项目里,生成代码的Token消耗往往只占总量的很小一部分。真正的大头是上下文维护。什么叫上下文维护?就是每一次你让AI改一个功能,它需要知道:这个功能在哪个文件里、依赖了哪些模块、被哪些地方调用、数据库表结构是什么、接口约定是什么、之前的对话里有没有相关决策。

这些信息,你不可能每次都手动贴给AI。你需要一套机制,让AI在需要的时候能自动获取到正确的上下文。而获取上下文这件事,本身就是Token消耗大户。

我做过一个粗略的统计,在一个中等规模的后端项目里,如果使用Agent模式的AI编程工具,Token消耗的大致分布是这样的:

消耗类型占比说明
上下文加载40%-55%读取文件、搜索代码、理解项目结构
方案讨论与澄清15%-25%来回确认需求、比较方案、修正理解
代码生成10%-15%实际写出代码的部分
测试与验证10%-20%生成测试、跑测试、分析失败原因
重构与修复5%-15%修Bug、调整结构、处理边界情况

你看,真正“写代码”的部分,占比可能连15%都不到。剩下85%以上的Token,花在了“让AI理解要写什么”和“验证写出来的东西对不对”上。

这个结构说明了一个关键问题:AI编程的瓶颈不在生成,而在理解和验证。而理解和验证,恰恰是传统意义上“程序员的核心能力”所在。AI把生成变便宜了,但理解和验证的成本并没有同步下降,甚至因为AI生成速度太快,验证环节反而成了新的瓶颈。

2.2 为什么“一句话生成App”的演示不可复现

网上那些“一句话生成一个App”的演示,之所以看起来神奇,是因为它们通常满足几个隐藏条件:项目是全新的、没有历史包袱、需求极其简单、不需要考虑边界情况、不需要和现有系统集成、不需要考虑性能和安全性。

一旦你把这些条件去掉,换成真实项目,情况就完全不一样了。我试过让AI在一个有两年历史、几十万行代码的项目里加一个功能。结果AI花了大量Token去读代码、理解现有模式,然后生成的代码虽然能跑,但风格和项目其他地方不一致,命名习惯不同,错误处理方式也不对,日志打得乱七八糟。最后我花在调整和统一风格上的时间,比我自己写还多。

这不是AI不行,而是真实项目的复杂度,远远超出了“生成代码”这个动作能覆盖的范围。代码生成只是整个工程活动中的一环,而且是很小的一环。把这一环变便宜了,不等于整个工程活动变便宜了。

2.3 Token账单背后的隐性成本

除了直接的Token费用,还有几项隐性成本经常被忽略。

第一是等待成本。AI生成代码需要时间,Agent模式下的多轮工具调用更慢。你等它读完文件、搜完代码、生成完方案,可能几分钟就过去了。如果方案不对,再来一轮,又是几分钟。一天下来,大量时间花在了等待和来回确认上。

第二是审查成本。AI生成的代码你必须看,而且要比看人写的代码更仔细,因为AI会“自信地犯错”。它生成的代码看起来往往很合理,命名规范、注释齐全、结构清晰,但可能在一个微妙的边界条件上处理错了。这种错误比明显的语法错误更危险,因为它不容易被发现。

第三是上下文切换成本。用AI编程,你的工作模式会发生变化。你不再是一口气写完一个模块,而是不断地在“描述需求—等待生成—审查代码—反馈修正”之间切换。这种切换对专注力的消耗很大,很多人用了一段时间AI编程之后会觉得比以前更累,原因就在这里。

3. SDD为什么突然变得重要:从“写代码”到“写规格”

3.1 SDD到底是什么,为什么现在被反复提起

SDD,Specification-Driven Development,规格驱动开发。这个概念本身不新,但在AI编程的语境下,它被赋予了新的意义。

传统开发里,规格文档往往是写给人的,而且经常是“写完就扔”——真正干活的时候大家还是直接看代码。但在AI编程里,规格变成了给AI的输入。你给AI的规格越清晰、越结构化、越无歧义,AI生成的代码质量就越高,来回修正的次数就越少,Token消耗就越低。

我自己的体会是:在AI编程的工作流里,写规格的时间应该占到整个开发时间的30%到40%。这个比例远高于传统开发。但换来的是生成环节的一次通过率大幅提升,以及后续修复成本的显著下降。

SDD的核心思想是:先把“要做什么”和“怎么做”用结构化的方式定义清楚,再让AI去生成实现。规格不是文档,而是可执行的约束。它应该包含:功能描述、输入输出定义、边界条件、错误处理策略、依赖关系、验收标准。

3.2 一份能用的规格应该长什么样

我试过很多种规格格式,最后稳定下来的是一种接近“结构化自然语言”的写法。它不需要严格的语法,但需要严格的逻辑结构。

举个例子,假设我要让AI帮我实现一个“用户登录失败次数限制”的功能。一份能用的规格大概是这样:

功能名称:登录失败次数限制 背景:防止暴力破解,同一账号连续登录失败达到阈值后锁定一段时间。 输入: - userId: 用户唯一标识 - loginResult: 本次登录结果(成功/失败) 输出: - 如果登录成功:重置该用户的失败计数 - 如果登录失败:失败计数加一 - 如果失败计数达到5次:锁定该账号15分钟 边界条件: - 锁定期间即使密码正确也拒绝登录 - 锁定到期后自动解锁,失败计数重置 - 不同用户的计数互相独立 - 计数存储需要设置过期时间,避免无限增长 错误处理: - 存储层不可用时,记录日志并放行(不能因为限流组件故障导致正常用户无法登录) 验收标准: - 连续5次失败后第6次登录被拒绝 - 等待15分钟后可以正常登录 - 并发场景下计数准确

这份规格没有用任何特殊语法,但它的结构是清晰的。AI拿到这份规格,生成代码的准确率会远高于你只说一句“帮我做个登录失败限制”。

3.3 规格写得好,Token省一半

我做过对比实验。同一个功能,用两种方式让AI实现。

方式A:直接说“帮我实现登录失败次数限制,用Redis存计数,失败5次锁定15分钟”。结果AI生成了代码,但边界条件处理不完整,锁定逻辑有并发问题,错误处理缺失。来回改了四轮才基本可用。

方式B:先写上面那份规格,再让AI按规格实现。AI一次生成的代码就覆盖了所有边界条件,只有一处命名需要调整。

两种方式的Token消耗差距大概是3到4倍。方式A看起来“省事”,但实际上把成本转移到了后续的反复修正上。方式B前期多花了时间写规格,但整体效率高得多。

这就是SDD在AI编程里的价值:它把不确定性前置消化了。你在写规格的时候,其实是在做需求分析和方案设计,这些工作本来就要做,只是以前可能是在脑子里做、在白板上做、在会议里做。现在把它显式地写出来,直接喂给AI,省掉了“人理解需求再翻译成代码”这个中间环节的损耗。

4. CLAUDE.md和上下文工程:让AI真正理解你的项目

4.1 CLAUDE.md不是可选项,是必选项

如果你在用Claude Code或者其他支持项目级上下文文件的AI编程工具,CLAUDE.md这个文件的重要性怎么强调都不过分。

CLAUDE.md的本质是项目级的系统提示词。它告诉AI:这个项目是做什么的、代码结构是怎样的、有哪些约定、用什么技术栈、有哪些禁忌。没有这个文件,AI每次都要从零开始理解你的项目,Token消耗大不说,理解还经常出错。

我见过很多人用AI编程工具,从来不写CLAUDE.md,然后抱怨AI生成的代码不符合项目规范。这就像你招了一个新员工,不给他任何项目文档,然后怪他写的代码风格不对。问题不在AI,在于你没有提供必要的上下文。

一份好的CLAUDE.md应该包含哪些内容?我的经验是这几块:

  • 项目概述:一句话说清楚项目是干什么的,主要用户是谁,核心功能有哪些。
  • 技术栈:语言、框架、数据库、缓存、消息队列、部署方式,全部列清楚。
  • 目录结构:关键目录的用途说明,让AI知道该把代码放哪里。
  • 代码规范:命名习惯、错误处理方式、日志规范、注释要求。
  • 常用命令:怎么跑测试、怎么启动本地环境、怎么构建、怎么部署。
  • 禁忌事项:哪些库不能用、哪些模式不能引入、哪些文件不能改。
  • 当前重点:最近在做什么功能,有哪些已知问题,下一步计划是什么。

这个文件不需要写得很长,但需要写得准。我自己的CLAUDE.md大概在200到400行之间,根据项目复杂度调整。写一次,后面每次AI编程都会受益。

4.2 上下文工程的核心:在正确的时间给AI正确的信息

CLAUDE.md解决的是“项目级上下文”的问题。但具体到每一次任务,你还需要“任务级上下文”。

任务级上下文的核心原则是:只给AI当前任务需要的信息,不多不少。给多了,Token浪费,而且可能干扰AI的判断;给少了,AI理解不到位,生成质量下降。

怎么做到“不多不少”?我的做法是分三步:

第一步,在CLAUDE.md里定义好项目的整体结构和约定,这是常驻上下文。

第二步,每次任务开始时,用简短的文字说明任务目标和范围,让AI知道这次要做什么。

第三步,让AI自己去读取相关文件。Agent模式的工具通常支持文件读取和代码搜索,你只需要告诉它“相关代码在src/auth目录下”,它自己会去读。

这里有个关键技巧:不要让AI一次性读太多文件。有些工具默认会把整个项目加载到上下文里,这在项目小的时候没问题,项目大了就是灾难。你要学会控制AI的上下文范围,让它按需读取。

4.3 上下文污染的危害和避免方法

上下文污染是AI编程里一个很隐蔽但很致命的问题。什么叫上下文污染?就是AI的上下文里混入了不相关、过时、或者错误的信息,导致它的判断出现偏差。

常见的污染源包括:过时的需求描述、已经废弃的代码、不相关的讨论记录、错误的示例。这些信息一旦进入上下文,AI可能会把它们当成有效信息来使用,生成出不符合当前实际情况的代码。

避免上下文污染的方法有几个。一是定期清理对话历史,一个任务做完就开新对话,不要把不相关的任务混在一起。二是保持CLAUDE.md的更新,废弃的约定要及时删掉,不要让它一直留在那里误导AI。三是在任务描述里明确范围,告诉AI“只关注X模块,不要考虑Y模块”,减少它去读取不相关代码的概率。

我踩过的一个坑是:在一个项目里,我早期用了一种错误处理模式,后来改成了另一种。但CLAUDE.md里没有更新,AI读到旧模式之后,新生成的代码又用回了旧模式。结果项目里两种模式混用,维护起来很痛苦。从那以后,我养成了习惯:每次架构调整,第一件事就是更新CLAUDE.md。

5. Lint和测试:AI编程的质量守门员

5.1 为什么AI生成的代码更需要Lint

AI生成的代码有一个特点:表面看起来很规范,但细节上经常出问题。命名可能符合规范,缩进可能很整齐,注释可能很完整,但在类型使用、边界处理、资源释放这些地方,容易出疏漏。

Lint工具的价值在这里就体现出来了。它不关心代码“看起来”怎么样,它只关心代码“实际上”有没有问题。未使用的变量、可能的空指针、类型不匹配、循环依赖、安全漏洞,这些Lint能查出来的问题,AI自己往往查不出来。

我的做法是:在AI编程的工作流里,Lint必须是自动化的。AI生成代码后,自动跑Lint,把问题反馈给AI,让它自己修。这个循环跑几轮,代码质量会明显提升。

具体配置上,不同类型的项目用不同的Lint组合。TypeScript项目用ESLint加typescript-eslint,Python项目用Ruff加mypy,Go项目用golangci-lint。关键是要把Lint配置得足够严格,让它能抓住AI容易犯的那些错误。

5.2 测试是AI编程的“验收规格”

比Lint更重要的是测试。Lint抓的是语法和风格问题,测试抓的是逻辑和功能问题。

在AI编程的语境下,测试的角色发生了变化。传统开发里,测试是“验证代码对不对”。AI编程里,测试更像是“规格的可执行版本”。你写的测试用例,实际上是在告诉AI:这个功能在这些情况下应该有这样的行为。

我现在的习惯是:先写测试,再让AI写实现。测试用例本身就是规格的一部分。AI拿到测试用例,知道要通过这些测试,生成实现的时候就有了明确的目标。而且测试跑通之后,我就有了一定的信心说这个功能是对的。

这个做法有个额外的好处:测试用例是给AI的“约束”,它限制了AI的自由度,减少了AI“自由发挥”导致偏离需求的可能性。AI很擅长在约束下工作,你给的约束越明确,它的输出越可靠。

5.3 构建“生成—检查—修复”的自动化闭环

单独用Lint和测试还不够,关键是要把它们串成一个自动化闭环。

理想的工作流是这样的:AI生成代码 → 自动跑Lint → 有问题就反馈给AI修 → Lint通过后跑测试 → 测试失败就反馈给AI修 → 测试通过后跑构建 → 构建通过后进入人工审查。

这个闭环里,人工只在最后一步介入。前面几步都是自动的,AI自己迭代。这样既保证了质量,又减少了人工干预的成本。

我实测下来,这个闭环能把AI生成代码的可用率从大概60%提升到85%以上。剩下的15%需要人工介入,通常是需求理解偏差或者架构层面的问题,这些是自动化工具解决不了的。

搭建这个闭环需要一些工程投入,但非常值得。你可以用CI/CD工具来编排这个流程,也可以用简单的脚本。关键是让“生成—检查—修复”这个循环尽可能自动化,减少人工在中间环节的介入。

6. 常见问题与排查技巧实录

6.1 Token消耗异常排查

问题:Token消耗突然暴涨,但感觉没做什么复杂操作。

排查思路:先看是不是上下文加载出了问题。常见原因是AI在搜索代码时进入了某个大目录,把大量不相关文件读进了上下文。检查你的工具配置,看看有没有排除node_modules、dist、.git这些目录。另一个常见原因是对话历史太长,每次请求都把之前的全部历史带上。解决办法是定期开新对话,或者用工具提供的上下文压缩功能。

问题:同一个任务,Token消耗波动很大。

这通常和AI的“探索行为”有关。Agent模式的AI在不确定的时候会反复搜索、读取文件,消耗大量Token。减少波动的方法是:在任务描述里给更明确的指引,告诉AI相关代码在哪个目录、参考哪个文件。你给的指引越具体,AI的探索行为越少,Token消耗越稳定。

6.2 AI生成代码不符合项目规范

问题:AI生成的代码能跑,但风格和项目其他地方不一致。

根因通常是CLAUDE.md没有写清楚代码规范,或者写清楚了但AI没有遵守。解决办法:第一,确保CLAUDE.md里有明确的规范说明,最好附上正例和反例。第二,在任务描述里再次强调规范要求。第三,用Lint工具自动检查,把不规范的地方反馈给AI修。

如果反复出现这个问题,可能是CLAUDE.md太长了,AI没有完整读取。试着精简CLAUDE.md,把最重要的规范放在前面。

6.3 AI陷入“修复—引入新问题”的循环

问题:让AI修一个Bug,它修好了这个,但引入了另一个,再修又引入新的。

这是AI编程里很常见的情况,通常是因为AI没有理解问题的根因,只是在表面打补丁。解决办法:停下来,不要让AI继续修。重新写一份清晰的规格,说明期望的行为和边界条件,然后让AI基于规格重新实现,而不是在原有代码上修补。

另一个技巧是:让AI先解释它打算怎么修,你确认方案没问题再让它动手。这样能避免AI在错误的方向上越走越远。

6.4 常见问题速查表

问题现象可能原因排查方向解决建议
Token消耗异常高上下文加载过多检查是否读取了大目录配置排除规则,限制读取范围
生成代码风格不一致规范未明确或未遵守检查CLAUDE.md规范部分补充规范说明,加Lint检查
反复修复引入新问题AI未理解根因检查任务描述是否清晰重写规格,基于规格重新实现
测试通过但功能不对测试用例覆盖不足检查测试用例的边界条件补充边界测试,先写测试再实现
AI理解偏差大上下文污染或不足检查对话历史和CLAUDE.md清理历史,更新上下文文件
生成速度慢任务范围太大检查任务描述的范围拆小任务,分步执行

6.5 几个我踩过的坑

第一个坑:过度依赖AI的“自信”。AI生成的代码往往看起来很确定,注释写得很肯定,但这不代表它是对的。我早期的时候看到AI生成的代码结构清晰、注释完整,就放松了审查,结果在一个边界条件上出了问题,上线后才发现。从那以后,我对AI生成的代码,审查标准比对人写的还严。

第二个坑:CLAUDE.md写得太长。我一开始觉得写得越详细越好,结果写到上千行,AI反而抓不住重点。后来精简到300行左右,只保留最关键的约定和禁忌,效果反而更好。上下文文件不是越长越好,而是要精准。

第三个坑:忽略测试的“规格”作用。我早期把测试当成事后验证,AI写完代码再补测试。后来发现,先写测试再让AI实现,效果好得多。测试用例本身就是最好的规格说明,AI拿到测试用例,生成实现的准确率明显提升。

第四个坑:在错误的抽象层级上让AI工作。有时候我让AI去改一个很底层的函数,但它不理解这个函数在整个系统里的角色,改出来的东西虽然局部正确,但破坏了上层的假设。后来我学会了:让AI在合适的抽象层级上工作,改底层的时候要告诉它上层的约束。

7. 重新理解“Code is cheap”:值钱的从来不是代码

回到标题那句话。“Code is cheap”之所以是谎言,是因为它把“代码”等同于“软件开发”。代码只是软件开发的输出物之一,而且不是最有价值的那部分。

在AI编程时代,真正值钱的是这些东西:把模糊需求转化为清晰规格的能力、设计系统架构和模块边界的能力、判断代码质量和对错的能力、在复杂约束下做取舍的能力、把AI工具链整合进工程流程的能力。

这些能力,AI目前还替代不了。AI可以帮你写代码,但它不能替你决定写什么、为什么这么写、写到什么程度算够。这些判断,需要人的经验、直觉和责任感。

我烧掉100亿Token之后最大的收获,不是学会了怎么用AI写代码,而是更清楚地看到了哪些事情AI做不了,哪些事情只有人能做好。这个认知,比任何工具使用技巧都值钱。

如果你也在用AI编程,我的建议是:不要把精力花在“怎么让AI写更多代码”上,而是花在“怎么让AI写对的代码”上。前者是量的积累,后者是质的提升。而后者,恰恰需要你具备那些AI替代不了的能力。

这个方向上的探索还远没有结束。我自己也在不断调整工作流,不断试新的工具和方法。但有一点我越来越确定:AI不会让程序员失业,但会让那些只会“写代码”的程序员失业。而那些能定义问题、设计规格、把控质量、整合工具的人,价值反而会越来越高。