ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Claude Code烧Token?2条Prompt+2条命令管好上下文

Claude Code烧Token?2条Prompt+2条命令管好上下文

如果你用Claude Code写过几天代码,大概率经历过这么一幕:你让它改一个模块的日志格式,它没直接动手,而是先Grep全仓库搜“logger”,读了一堆无关的配置文件,翻了半天又问“我找到了三个日志实现,你指的是哪个”。等你回答完,上下文窗口里已经被塞了无数文件片段,Token预算烧掉几万,代码却一行没碰。

这个问题在大型仓库里会被无限放大。Claude Code确实能自己“找路”,但找路的代价是工具调用次数爆炸、上下文被无关内容挤占、重要信息被截断,最后AI开始答非所问,甚至擅自改到别的模块。我在实际项目里踩过这个坑之后,总结出一套组合打法:2条Prompt + 2条命令。思路很简单——强制你喂给AI什么,它就只看什么;禁止它碰什么,它就绝不越界。这篇文章把完整配置、背后的原因、以及实测对比全部展开,适合那些已经在用Claude Code、但觉得Token消耗太快、任务经常跑偏的开发者参考。

1. 项目概述:为什么Claude Code总在“烧钱式找路”

先说结论:Claude Code不是笨,而是它默认的策略就是“先探索,再回答”。当你提出一个任务,它手里没有项目地图,唯一的办法就是调用各种工具去猜——Grep搜关键词、读文件、看目录结构、再试错。这套流程在小型demo里没问题,但放到一个几千文件的工程里,探索成本是灾难级的。

1.1 乱Grep的代价:Tokens是怎么悄悄烧光的

要理解“烧Token”的本质,先要看清一次工具调用到底花了多少钱。以Grep为例:每次调用,AI要生成工具名和参数,这是基础开销;工具返回匹配结果时,每一行命中内容都要进入上下文窗口;如果匹配到一个200行的大函数片段,这段代码就直接吃掉几百上千Token。AI看了结果后还要“理解”,这又是一轮生成。一次看起来不起眼的搜索,实际开销经常是几千Token。

更可怕的是,这种搜索不是一次就结束。AI会先Grep一次确认位置,读文件确认内容,发现不对再换关键词Grep,再读下一个文件。我观察过几次翻车现场,一个“改日志格式”的需求,AI前前后后做了近20次工具调用,消耗的Token足够写好几版代码。这还没算上最隐蔽的损失——早期读进来的关键信息,因为上下文满了被系统截断。

打个比方,这就像你请了个能力很强但完全不认路的实习生。他干活的热情没得说,问题是他每次都先把整栋楼翻一遍才肯动手。你烧的是时间,在Claude Code这里烧的是Token。所以,省钱的核心不是少用AI,而是不让它干那些本可以由你一次性交代清楚的事情。

1.2 所谓“无限上下文”,其实是精准上下文

标题里说的“无限上下文”,严格来讲不是技术上的无限,而是让你把AI的上下文全部用在刀刃上。上下文窗口是有限的,但如果你能让AI不用花Token去探索、不用反复试错、不用读无关文件,那么有限的窗口对你来说就像无限一样——因为它只装着和当前任务相关的信息。

我把它拆成三步,形成一个闭环:

  • 预置地图:把项目结构、关键路径、命名规范、禁区说明一次性打包,喂给AI。它不用猜,不用搜。
  • 划定边界:明确告诉它能动什么、不能动什么,从源头上掐断“随手改别的文件”的冲动。
  • 按需注入:需要某个模块的细节时再补充,绝不一次性把所有代码都塞进去。

这套组合下来,AI的上下文窗口里全是有效信息,而不是搜索过程中产生的“思考垃圾”。它不是知道了更多,而是浪费得更少。

1.3 两条命令的设计思路:加载与清场

2条命令解决的是“怎么把上述思路变成肌肉记忆”。如果每次开新任务都要手打一段长Prompt,你大概率用两次就放弃了。所以我把最常用的两个动作做成了shell函数。

  • cc-load:一键把当前项目的“项目地图”喂给Claude,附带你要开工的初始任务。它的作用是“加载”,让AI从第一句话开始就处于有地图的状态。
  • cc-reset:一键结束当前会话、清掉上下文,开启一个干净的新会话。它的作用是“清场”,防止上一个任务的残留信息污染下一个任务。

为什么一定要有reset?因为Claude Code的上下文是连续累积的。连续做三四个任务之后,早期对话内容、旧文件内容、中间的一些无关讨论,都在窗口里占着位置。你下一个任务可能和它们毫无关系,但AI还是会参考这些残留信息,导致“跑偏”的概率直线上升。reset就是翻篇,一张干净的白纸永远比涂满旧字迹的纸好写。

2. 两条Prompt:先和AI“约法三章”

很多人用Claude Code的时候,Prompt写得太随意——“帮我改一下订单逻辑”这种话扔出去,AI当然只能靠猜。它猜的过程,就是你烧Token的过程。下面这两条Prompt是经过我多轮调整后沉淀下来的版本,一个管“认识项目”,一个管“干活边界”。

2.1 Prompt 1:项目宪法——一次性把地图塞进上下文

这条Prompt的作用,是让AI在动手前就掌握它需要的全部背景信息。我的建议是,第一次使用某个项目时,把它当成一个模板去填充,之后所有会话都复用同一份内容。标准格式如下:

请把以下内容作为本次工作的【项目地图】,所有任务优先基于该地图行动: - 项目根目录:/Users/dev/app - 核心模块: - src/core/auth.py 用户认证与登录逻辑 - src/core/payment.py 支付处理,允许改动 - src/utils/logger.py 统一日志封装,禁止修改 - 命名规范:函数使用snake_case,常量使用UPPER_SNAKE_CASE - 环境配置:本地使用config/dev.yaml,禁止读取生产配置 - 禁止区域:tests/ 目录只读,不修改;vendor/ 忽略 如果地图信息与代码实际不符,请停下来说明差异,不要自行猜测。

这里有几个关键设计。

第一,给绝对路径,不给描述性路径。很多AI跑偏,是因为它以为自己知道“日志模块”在哪,结果是另一个同名文件。你直接告诉它src/utils/logger.py,它就不需要Grep了。

第二,明确“禁止区域”。这一点比告诉它能做什么更重要。AI的默认行为是尽可能完成任务,所以它会倾向于改动任何它认为相关的文件。你如果不说“tests/目录只读”,它可能在改业务逻辑的同时顺手改坏一个测试文件。这个边界,必须写死。

第三,强制校验机制。我加了一句“如果地图信息与代码实际不符,请停下来说明差异”。这一句看着简单,实战里能救你很多次。因为项目是演化中的,地图可能过期。与其让AI带着错误地图乱来,不如让它停下来问你。

2.2 Prompt 2:任务边界条款——让它埋头苦编不越界

如果说Prompt 1解决的是“认路”,Prompt 2解决的就是“守规矩”。每次具体任务开工前,我都会在项目地图后直接接上任务边界条款。模板如下:

本次任务范围: 1. 只修改 src/core/payment.py 中 create_order 函数 2. 为它补充失败重试逻辑,最多重试3次 3. 不得改动其他函数、其他文件 4. 不得引入新的第三方依赖 5. 不执行测试、不改动测试用例,只输出代码变更说明 验收标准: - 代码可编译,逻辑符合注释中的业务规则 - 输出变更diff摘要,不超过200字 边界以外的一切工作,请直接拒绝,或告知需要额外授权。

先说清楚为什么需要一个单独的“任务边界”Prompt,省事的人可能会把边界直接写进项目地图,但效果并不好。项目地图是长期存在的,它描述的是项目“是什么”;而任务边界是临时的,它定义的是这一次“要干什么、不能干什么”。混在一起会让AI混淆信息的优先级,它做事的时候不知道哪些是全局规则、哪些是当前任务的限制。

关于越界。我见过三种最常见的翻车方式:一是擅自加依赖,用到一个功能就pip install一个新库;二是顺手重构,明明让你改一个函数,它“好心”把整个模块的风格统一了;三是扩大修改面,改A文件的bug时,顺手“修正”了B文件类似的问题。对付这三种情况,最有效的措辞不是“不要乱改”,而是把这些行为一条条列出来,点名“不得改动其他文件”“不得引入新依赖”。AI对于明确的禁令执行得很好,但对模糊的“注意分寸”执行得很差。

验收标准也别省。让AI每轮任务结束输出一段200字以内的diff摘要,一方面方便你检查它有没有越界,另一方面也能避免它罗里吧嗦地给一堆报告,白白烧掉生成Token。

2.3 Prompt写作的两条心法

讲完模板,再说说那些模板背后的通用心法,你以后写自己的版本时用得上。

心法一:写路径,不写描述。举个例子,与其说“修改用户认证模块”,不如直接说“修改src/core/auth.py”。倒不是说Claude Code理解不了“用户认证模块”,而是这种描述会触发它的搜索行为——它得先确认哪个文件是认证模块。路径是确定性信息,描述是概率性信息。你给路径,它零成本开工;你给描述,它需要烧Token来验证猜测。

心法二:否定列表比肯定列表更有效。只告诉AI“你可以改payment.py”,它仍然可能基于“让代码更好”的逻辑去动其他文件。但如果你同时列出“不要碰tests/、不要碰config/、不要动logger.py”,它的行为边界就清晰得多。AI本质上是一个大模型,它对“能做什么”有很强的主动性,对“不能做什么”的约束反而记得更牢。原因很简单:明确的禁止项在语义上更突出,相当于经营上的“高压线”,而肯定列表只是“允许区”。

3. 两条命令:把Prompt变成一键执行

Prompt写得再好,每次手打一遍也不现实。真正的爽点是把它们固化成一键执行的命令。下面这套配置是我在自己环境里跑的,你可以直接抄,也可以按自己习惯改名。

3.1 命令一:cc-load——把项目地图喂进新会话

我把每个项目的“项目地图”存成一个独立Markdown文件,放在~/.cc-maps/目录下,文件名和项目根目录同名。这样任何项目都能复用同一套加载逻辑。对应的shell函数长这样:

# 一键加载当前项目的项目地图,并启动新会话 cc-load() { local map_file="$HOME/.cc-maps/$(basename "$(pwd)").md" if [ ! -f "$map_file" ]; then echo "未找到地图文件:$map_file" echo "请先创建,可参考以下模板:" echo " - 项目根目录" echo " - 核心模块与绝对路径" echo " - 命名规范与禁止区域" return 1 fi { echo "【项目地图已加载】" cat "$map_file" echo "" echo "请基于以上地图开始工作。" } | claude }

这段脚本的逻辑很简单:切到项目目录后,执行cc-load,它会自动去~/.cc-maps/目录下找同名地图文件,然后拼接成一段初始Prompt,交给claude命令启动新会话。这样你每次开任务,第一句话就已经带着完整地图,AI不需要从零开始探索。

我在实际使用中的两个调整建议。

第一个,地图文件也要维护。项目结构一变,地图文件就得跟着更新。我自己的习惯是每两周花五分钟检查一遍,把新增的核心模块标记进去,删掉已经废弃的路径。这个维护成本很低,但如果放任不管,地图过期后AI会被误导,反而不如没有地图。

第二个,如果你用的是已有会话而不是新会话,可以改成把内容复制到剪贴板。我再补一个别名,遇到“不重启会话、只注入地图”的场景直接用:

alias cc-load-paste='cat "$HOME/.cc-maps/$(basename "$(pwd)").md" | pbcopy && echo "地图已复制到剪贴板,直接粘贴到会话中即可"'

pbcopy是macOS的命令,Linux环境可以换成xclip -selection clipboard。这样即使不走命令行启动,也能手动完成注入。

3.2 命令二:cc-reset——切断上下文防污染

cc-reset的设计目标是:一键结束当前会话状态,回到一个干净的起点。有人可能会问,直接退出终端再重开不行吗?行,但如果做成了命令,你就不用每次手动清理一堆临时状态了。

# 重置当前会话,开启干净的新会话 cc-reset() { echo "当前会话上下文即将清理,开始新会话..." # 根据你使用的终端工具,清掉当前进程并重启 claude }

这里有一点要说明:不同版本的Claude Code、不同的终端环境,具体重置指令会有一点差异。这个函数的核心目的是把你“手动关掉旧会话、再手动开新会话”的两个动作,压缩成一个。你只需要保留“新会话启动”这句,前面的通知文字可以随意改。

为什么要强调reset?因为我发现很多人没有这个习惯。如果你连续在同一个会话里做了三四个不相关的小任务,AI的上下文里堆满了旧对话记录。这时候你让它做第五个任务,它大概率会参考前面几个任务的模式,哪怕那些模式完全不适用。重置成本几乎为零,但它能从根本上解决“上下文污染”带来的跑偏问题。

3.3 CLAUDE.md的配合使用:把行为锚点固化成默认值

除了两条命令,Claude Code还有一个官方支持的记忆机制——CLAUDE.md。这个文件会被自动加载进会话,相当于AI的“默认人格”。很多人用CLAUDE.md的方式是把整个项目说明塞进去,这是误区。CLAUDE.md应该只放“行为习惯”和“长期约束”,比如:

- 回答时先给结论,再给解释 - 所有涉及修改代码的任务,必须先检查项目地图文件 - 不允许读取生产环境配置 - 代码注释使用中文,代码提交信息使用英文 - 涉及删除操作之前,必须列出影响范围并征求确认

为什么建议把行为习惯放CLAUDE.md,而把项目地图放cc-load里?因为两者刷新频率完全不同。CLAUDE.md是全局的、长期稳定的,适合放那些“永远成立”的东西;项目地图是易变的,项目重构一次就要更新一次,适合按需加载。如果你把地图塞进CLAUDE.md,每次启动会话它都会自动加载,哪怕你只是过去写个README,这些Token也照烧不误。更合理的方式是让CLAUDE.md只承担“引导AI去找地图”的角色,地图本身留给cc-load按需注入。

4. 实测效果:改造前后的Tokens消耗对比

方法讲完,必须看点实证。否则你很难相信,这两条Prompt和两条命令的组合,能在真实项目里带来多大差异。

4.1 改造前的经典翻车现场

我之前在一个中型后端项目上做过一次记录。任务内容是:给订单模块的“创建订单”接口加一个失败重试逻辑,最多重试三次。这是一个应该几分钟搞定的活,但由于当时项目仓库里文件很多,AI不知道订单逻辑的具体位置,于是上演了完整的“烧钱式找路”:

  • 第一轮:搜索“create_order”,返回了6个文件路径。
  • 第二轮:逐一读取前两个文件,发现只有引用没有实现。
  • 第三轮:换关键词搜“order”,加载了很多无关的订单展示代码。
  • 第四轮:终于定位到src/core/payment.py,但此时上下文里已经混入了无关代码片段。
  • 拖到最后,AI开始犹豫:要不要看下测试文件确认行为?是不是还有别的实现?

按我当时的粗略估算,整个定位过程消耗了大约4.5万Token,工具调用接近20次。更麻烦的是,由于上下文里塞了很多无关文件,AI最后的实现方案里出现了一个多余的判断分支——“因为我在order模块里看到一个类似的状态字段”,实际上那个字段和本次任务毫无关系。

4.2 改造后:同样的任务走了另一条路

后来我把项目地图维护好,用cc-load启动会话,然后附带任务边界条款。同一个任务,同样的仓库,AI的行为路径完全不同。

它拿到项目地图后,直接定位到src/core/payment.py,没有再搜索任何其他文件。因为它知道所有订单相关的逻辑都在这个文件里,也知道测试目录是只读的,不需要“顺手看看”。整个任务只经历了三次核心动作:读取目标文件、修改函数、输出diff摘要。

我同样做了记录,Token消耗大约1.2万,工具调用3到4次。两者的差距不是一点半点。我把这个对比整理成一张表,你可以直观感受一下:

对比维度改造前改造后
工具调用次数约18次3至4次
定位阶段Token消耗约4.5万约1.2万
是否出现无关文件污染是否
生成代码的准确性出现多余分支与需求一致
平均任务耗时约8分钟约2分钟

这个数据不是实验室里造出来的理想值,而是我几次项目中截取的典型样本。核心差距就来源一件事:AI到底是把Token花在“找路”上,还是花在“编码”上。

4.3 收益最大的三类场景

这套方案在所有场景下都有效,但收益最大的是下面三类。你可以评估一下自己的使用场景是否在其中。

第一类,大型仓库的早期探索。新加入一个项目时,你对结构还不熟,AI也一样。如果你上来就让它干一个具体任务,它只能靠搜索猜路径。提前写好项目地图,等于把你摸索的过程一次性固化下来,后面所有人都能受益。

第二类,多文件重构任务。重构的难点在于“影响范围控制”。没有边界条款时,AI重构完目标模块,还可能顺手把依赖它的几个文件一起改了,结果就是diff大得吓人。有了“不得改动其他文件”的约束,它就只能规规矩矩干活。

第三类,批量流水线式的小任务。比如连续修五个小bug,这种场景最容易被上下文污染坑。如果你每修一个bug就cc-reset一次,每个bug都会在干净上下文里开工,不会带上之前bug的残留信息。虽然多了一个写命令的动作,但每个任务的Token消耗反而更少。

5. 常见问题与排查技巧

方案讲了,效果也看了。接下来是这几天我被问到最多的问题,以及我自己排查时的经验。

5.1 Prompt注入了但AI还是乱Grep,怎么办

这是最让人崩溃的情况:地图喂了,边界划了,AI还是到处搜。遇到这种问题,先别急着骂AI,按下面三个方向排查。

第一,检查CLAUDE.md里有没有互相冲突的指令。如果CLAUDE.md写着“遇到不清楚的信息时,先去搜索确认”,那它当然会触发Grep。全局指令的优先级往往会压过单次Prompt里的建议,因为它是长期的“人格设定”。

第二,确认Prompt有没有被上下文截断。如果项目地图写得太长,超过了某个阈值,后半段的边界条款可能根本没有被AI看到。所以我在前面强调:地图文件只写关键路径,不写解释性长文。越精简,越不容易被截断。

第三,检查任务描述是否模糊。如果你在边界条款里写“处理订单模块”,AI仍然有权自己决定“处理”到底是什么意思。更合理的写法是“修改src/core/payment.py的create_order函数”,路径明确到文件级,它就没有搜索的空间了。

5.2 项目地图本身太大怎么办

几十个模块都写进地图,地图文件本身就会变成一大坨,加载进去反而烧Token。我的解法是分两级:总地图只放目录骨架,也就是一级模块名和一句话职责;每个核心模块的细节,放到单独的子地图文件里,等需要动手处理某个模块时,再人工粘贴或按需加载。

举个例子,总地图里写“src/core/payment.py——支付处理,负责订单创建与支付回调”,这就够了。等真正开始改支付模块的代码时,我再把payment.py的内部结构描述通过追加Prompt传进去。这样地图既可用,又不会词不达意。

5.3 什么时候该用cc-reset

我自己的判断标准有三个。一是对话开始出现明显的重复确认,AI反复问“你刚才说的是不是这个文件”,说明上下文里已经堆了太多旧讨论。二是AI开始引用早期对话中的内容作为当前决策依据,比如“根据刚才讨论的日志方案,这里也这么做”——如果当前任务和“刚才讨论”已经不是一回事,这就是污染信号。三是任务领域发生了切换,比如刚改完前端样式,马上要写后端接口,这时候毫不犹豫reset,各干各的。

5.4 两条命令的最佳实践组合

最后给一套我每天早上开工时的固定流程。到项目目录,执行cc-load,把地图喂进去;第一个任务做完后,检查输出、确认diff,然后cc-reset;第二个任务如果不是同一模块,依然是cc-reset后重来。这样一天下来,每一个任务都从干净起点开始,AI不会把上一个任务的行为模式带进下一个任务,Token消耗也更可预测。

这套流程跑顺之后,我最大的感受是:Claude Code不是用不起,前提是你得管理它的上下文,而不是让它自己乱逛。2条Prompt负责约束行为,2条命令负责管理状态,搭配起来,AI就真的能按你所想埋头苦编,绝不越界。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进