☰
数据审计Claude Code:从日志与token消耗中重构AI编程效率
2026/10/9 8:16:50 网站建设 项目流程

把 Claude Code 用了一年多,我一直凭感觉觉得它很能打:问什么答什么,让它重构就给重构,甚至一度在团队里吹过“有这个工具,我每天能多写两小时代码”。结果上个周末临时起意,把电脑里所有和它相关的日志、历史记录、todos 翻出来拉了张表,才发现自己被打脸了。数据不会顾及面子,它只会告诉你实话。

这篇记录的就是我这次“自我审计”的完整过程:数据从哪来、怎么统计、哪些结论让我意外,以及我最后据此改掉的几个工作习惯。如果你也在重度使用这类 agent 式编程工具,并且想知道自己到底有没有把它用好,这篇应该对你有用。

1. 数据取样:我是怎么把 Claude Code 的日志翻出来的

1.1 数据源:会话日志、终端历史、以及我自己的碎片笔记

Claude Code 有个容易被忽略的习惯:它会把每一次会话里的完整交互,包括你说了什么、它调了什么工具、读了多少文件、每一步的 token 消耗,全部以 JSONL 格式追加写入本地。默认位置在~/.claude/projects/下面,按项目路径编码分目录存放,每个目录里是一堆不带扩展名、以会话 ID 命名的 JSONL 文件。

所以第一步不是去开什么统计后台,而是直接把本目录扫一遍:

# 看看自己到底有多少会话记录 find ~/.claude/projects -type f | wc -l # 看每个会话文件多大,最大的那几个大概率藏着马拉松式会话 find ~/.claude/projects -type f -exec ls -lh {} \; | sort -k5 -rh | head -20

除了 Claude Code 自己的日志,我还补了两个数据源。第一个是终端 history,用来还原我到底在什么时间点、以什么频率敲下claude启动命令;第二个是我自己平时随手记的碎片笔记,比如“今天让 AI 重构了鉴权模块”“昨天 ask 它解释一个报错”。这些笔记不精确,但能帮我给数据做定性标注。

我最后拿到的是连续 22 天、共 247 个有效会话的完整日志。这里有两个筛选原则:去掉半小时内重复启动、没有实质交互的死会话;去掉那些跨越凌晨、实际上挂着没关的空长时间段。筛选后,我按sessionId聚合,再对每一天、每一类工具调用做了统计。

1.2 为什么不用官方统计,非得自己翻本地日志

可能有人问:Claude Code 不是自带/cost命令吗?直接看成本统计不就行了。我一开始也是这么想的,但真去用就会发现,/cost给的是非常粗粒度的汇总,它告诉你“这个会话花了多少钱、用了多少 token”,但没有告诉你“这钱具体花在哪一步”。到底是花在反复读同一批文件上,还是花在生成了三版都没用的重构代码上,光看汇总看不出来。

本地 JSONL 的颗粒度完全不同。每一行事件都带type、timestamp、tool_use、usage这些字段,我可以还原出完整操作链路:它先 Grep 了哪个目录,又 Read 了哪个文件,中间调了几次 Bash 命令,最后才落笔 Edit。这才是真正能反映行为的数据。

我的统计脚本很简单,核心逻辑就是逐行解析 JSONL 再按 key 聚合:

import json from pathlib import Path from collections import Counter session_dir = Path.home() / ".claude" / "projects" tool_counter = Counter() session_durations = [] for log_file in session_dir.glob("*/*"): if not log_file.is_file(): continue lines = log_file.read_text(encoding="utf-8", errors="ignore").splitlines() timestamps = [] for line in lines: try: evt = json.loads(line) except json.JSONDecodeError: continue ts = evt.get("timestamp") if ts: timestamps.append(ts) if evt.get("type") == "assistant": msg = evt.get("message", {}) content = msg.get("content") if isinstance(content, list): for block in content: if isinstance(block, dict) and block.get("type") == "tool_use": tool_counter[block.get("name", "unknown")] += 1 if len(timestamps) >= 2: start = min(timestamps) end = max(timestamps) session_durations.append((start, end, len(lines))) print("工具调用分布:", tool_counter.most_common()) print("有效会话数:", len(session_durations))

如果你自己也想做同样的分析,强烈建议先把这份脚本跑通,哪怕只统计最基础的 tab 利。因为你很快会发现,本地数据比你脑子里的“感觉”可靠得多。

1.3 统计口径里的坑:别急着下结论

第一次统计我差点把一个关键结论搞错。当时我发现“会话平均时长只有 6 分钟”,顿时觉得自己的使用方式是不是碎得离谱。后来仔细看时间戳才发现,Claude Code 的会话日志里包含大量“服务端心跳”,如果客户端开着不操作,时间戳会被拉得很长,中位数会被严重扭曲。

所以我最后采用的时长口径是“首次用户消息时间”到“最后一次助手工具调用结束时间”,中间去掉超过 10 分钟的空窗。这样过滤后,中位数是 9.4 分钟,比裸统计多了三分钟,但依然比我“主观感知”的半小时短得多。另外,按天聚合时要注意时区问题,JSONL 里存的大多是 UTC 时间,不转成北京时间,你看到的“凌晨四点高频使用”就是错了。

2. 先看结果:我的使用数据说了哪几句实话

2.1 我的大部分会话是短命的“问一句就跑”

把 247 个会话按时长排序后,最扎眼的是分布形态:一半以上的会话在 10 分钟以内结束,真正超过 40 分钟的长会话占比不到 8%。我原来以为自己是“开一次会话就深度工作两小时”,数据却告诉我,大部分 session 是“丢一段报错进去让它解释”“问一个 API 参数”“让 AI 看看这个测试为什么红”。

这些短会话本身不一定没用,问题在于它们几乎都不产出代码变更,而且每次开启新会话都要重新灌注项目上下文。翻译成成本语言就是:我用大量“起步 token”换回了一堆“哦我知道了”式的回答。举个例子,我统计到有 17 个会话都让 AI 重新解释了同一个项目的目录结构,每次解释都要重新 Read 一遍入口文件和配置文件,这 17 次加起来消耗的 token,足够我正常重构三个小模块。

数据还暴露了一个尴尬的事实:我至少 6 次在同一个项目里开启新会话,去问“这个项目的鉴权逻辑在哪”这类本应该写进文档、或者沉淀进项目记忆文件的问题。AI 每次都答得很耐心,但这本质上说明我没有把已知信息沉淀下来,而是让 AI 每次从头猜一遍。

2.2 70% 的 token 花在了“理解项目”而不是“改代码”

我统计了所有工具调用事件,分布大概是这样的:Read 相关占 34%,Grep/Bash 这类探索性命令占 22%,真正的 Edit 只有 18%,Write 新文件只占 6%,其余是任务管理、汇报、权限确认等。这意味着我委托 AI 做的事,本质上大量发生在我和它“对齐上下文”的阶段,真正落在代码上的产出比例低得吓人。

打个生活化的比方:这就像你请了一个很贵的外援,结果外援进门之后,你有大半天时间在给他介绍项目背景、带他看办公室、回答他“你们数据库在哪里”“这个接口是干嘛的”之类的问题。真正干活的时间反而没多少。

再往深挖了一层,我把“一次会话是否产生非空 git diff”作为成功标志,发现只有 37% 的会话“成功”了。其余会话要么是纯问答,要么是 AI 改到一半我主动放弃,要么是它反复修改但没有形成有效提交。后来我把统计里“被用户手动中断”的事件也拉出来看了一眼,这种场景占了约 23%,中断点基本都集中在 AI 连续尝试了三四次同一处修改、但方向始终不对的时候。

2.3 长上下文会话不是高效,而是昂贵的赌博

另一个让我意外的是 token 消耗分布。按会话消耗 token 排序后,前 10% 的会话吃掉了总消耗的 44%。这些长会话通常是从“帮我优化一下这个模块”开始,然后我在同一 session 里不断追加需求:“顺便把这里也改一下”“这里报错了再处理一下”“这样改会不会影响另一个功能”,最终上下文堆到几十万 token,Claude 开始 auto-compact,早期信息被压缩,行为明显变得飘。

我拿代码 diff 的可用率做统计后发现,比较理想的窗口是 4 万到 6 万 token 以内。超过 8 万以后,它经常出现“记错旧代码”“重复实现已经存在的方法”“改坏之前已经改好的部分”等退化现象。而且这种退化很难察觉,因为它回复时语气依然很自信,你不核 diff 根本发现不了。

一句话总结这段数据:长会话不是高效,而是昂贵的赌博。赌赢了也就省一次上下文切换,赌输了要回滚、要重新来过、要浪费更多 token 擦屁股。

3. 数据背后的行为分析:我为什么把 AI 助手用成了高级 grep

3.1 说出实话的不是 AI,是我输入指令的方式

看完上面的统计,我第一反应是怪工具不够好。但冷静下来重刷了一批会话日志,发现真正该背锅的是我自己的提问方式。我统计了所有用户消息,发现一半以上是“为什么这样不行”“这个报错什么意思”“帮我看看这里是什么情况”这类诊断型请求,真正明确说“目标是什么、范围在哪、约束有哪些”的指令少得可怜。

这种指令风格就等于把判断权完全交给模型,它只能通过一遍遍 Read 和 Grep 去自己摸索上下文。结果当然不稳定。后来我做了个实验:同样一个“给分页接口加上游标”需求,直接说,它要读 5 个文件、试探两次才能动笔;我把范围限定到“只需要改 service 层和 repository 层,不要动 controller”,它 Read 的文件数直接降了一半,第一次给出的 diff 就能用。

说白了,我的使用数据里显示的“模型能力不稳定”,很大程度上是我给的自由度太大了。你给它一个模糊任务,它只能用模糊的探索来应对。这不是它在摸鱼,而是指令熵太高。

3.2 “让我看看”类操作成了最大的时间黑洞

我按操作类型细分了耗时,发现 Read 文件操作不只是次数多,累计耗时也排第一。这不奇怪,因为每个大文件读进来要占用上下文、要重新解析、要影响后续生成。我挑了一个典型的失败会话做了复盘:我让 AI 优化某个老模块的性能,它花了 11 分钟、读了 14 个文件和 3 万多 token,最后给出的方案是把两个已经废弃的方法删掉了。如果我一开始就告诉它“这个模块只有两个入口文件是活跃的,其他不用看”,这个过程至少能省一半时间。

后来我把这种“探索黑洞”做了个显式对策:在项目根目录维护一份 CLAUDE.md,把哪些目录可以忽略、哪些文件是核心、业务规则写在哪些位置全部写清楚。CLAUDE.md 是 Claude Code 的官方记忆机制,每个会话启动时都会自动读入,等于给模型发了一张项目地图。这个文件我写了大约一上午,但随后两周的统计显示,平均每个会话的 Read 次数下降了约 28%,Edit 使用率从 18% 提到 29%。

3.3 我没有利用好“会话隔离”,而是把项目压成了一个大杂烩

统计里还有个有意思的现象:我在“前端项目”目录下开过一个会话问后端接口逻辑,在后端项目目录里问过样式问题。这本身没问题,但问题在于 Claude Code 是按项目目录隔离上下文的,我跨项目提问时,它经常需要花大量 token 去理解一个根本没读过的代码库。

正确做法应该是:把每个独立任务拆到对应项目目录里开新会话,并且只带必要上下文进去。跨项目的问题要么自己先查清楚,要么在提问时主动粘贴关键代码片段,不要奢望它能自动索引整个工作区。我在第 4 节会细讲这个调整,这里想强调的是,数据告诉我,会话隔离不是用来束缚你的,它恰恰是帮你省钱的机制。

4. 根据数据调整后的新用法,以及实测收益

4.1 用任务卡把给 AI 的自由度收窄

数据最直接的教训是:模糊提问 = 高成本探索。所以我现在每次开会话前,会在项目目录下先写一个简短的“任务卡”,不一定提交到仓库,但一定要让 AI 读到。格式大致是:

## 任务 给订单列表接口加分页,使用游标方式,每页默认 20 条。 ## 范围 - 改 service 层:OrderService.java - 改 repository 层:OrderRepository.java - 不要动 controller 层 ## 约束 - 沿用现有异常处理风格 - 不要引入新的依赖 ## 验收 - 首次请求返回游标 nextCursor - 空结果时 nextCursor 为 null

这个习惯看起来简单,但效果极其明显。调整后的一周里,我会话首次 Edit 成功前平均 Read 次数从 7.2 次降到了 3.1 次,第一次给出的代码能通过我检查的比例从大概四成升到了六成以上。关键是,这个改变完全不需要我多写多少字,只是把脑子里想的东西落成文本而已。

4.2 主动 compact,绝不拖到 auto-compact

之前我的错误习惯是让会话自然膨胀,直到上下文过载。现在的规则很简单:单个会话里每解决完一个子任务,我就手动敲/compact让模型压缩历史,或者干脆结束会话重新开一个。如果感觉自己还要追加第三个不相关的需求,我会直接停掉当前会话,新开一个。

从 token 消耗账本上看,这个改变带来的收益最直观:调整后的两周,日均 token 消耗比之前下降了约 35%。因为这个动作直接减少了模型需要“回忆”的信息量,也减少了 context 满了之后 auto-compact 导致的隐性错误。顺带一个技巧:如果会话还要继续,我就用/clear清空当前上下文再继续,但在清空之前让 AI 先输出一份“当前进度总结”存到临时文件,新会话开始时让它先读这个文件,信息不会丢。

4.3 强制 AI 交付“可验收变更”,而不是回答

我原来把 AI 当成搜索引擎加结对程序员,它说什么我就信什么。现在改成另一个心态:把它当成一个 junior dev。每次会话结束前,我会要求它输出三样东西:改了什么、为什么这么改、可能影响哪些地方。不需要很复杂,两三行就行,但这逼着模型把变更逻辑交代清楚,也逼着我自己去 review,而不是无脑接受。

这个习惯改变了“成功会话”的定义。以前我判断一次会话成不成功,取决于“AI 有没有听懂我的话”,现在判断标准变成了“diff 能否通过 review 并合入”。数据上,可以合入的变更比例从 37% 提到了 61%,虽然仍有一小半需要返工,但已经比之前好太多了。

4.4 用统计数据反推,调整每天的使用节奏

我还做了一个更粗粒度的观察:记录每天打开 Claude Code 的时段和对应会话的产出率。结果显示,我在下午 3 点到 6 点开的会话,产出代码变更的比例明显低于上午 10 点到 12 点。原因我也想明白了,下午那段时间我脑子本身已经累了,给 AI 的指令更敷衍,review 也更草率。

所以我现在把“让 AI 干活”这种事放在精力好的时段,下午只安排问答、解释报错这类低风险操作。这听起来跟 AI 工具没什么关系,但事实证明,工具效率的上限,是你自己的精力和判断力,所有模型都一样。

5. 安装配置与常见问题实录:从零到能跑,附踩坑记录

5.1 不同环境下的安装方式:macOS、Linux、WSL、VSCode

这次翻数据的过程里,我顺便把一套环境也重新搭了一遍。很多刚接触 Claude Code 的人卡在第一步,我先给出一套目前最省心的路径。核心依赖是 Node.js 18 以上版本,推荐先用 nvm 装 node,再通过 npm 全局安装:

# 安装 nvm 后,装一个 LTS 版本 node nvm install --lts # 全局安装 Claude Code npm install -g @anthropic-ai/claude-code # 验证是否安装成功 claude --version

如果你用的是 WSL,装好之后直接在 WSL 终端跑claude或者用 VSCode 的 Remote WSL 插件打开项目,在集成终端里启动,体验比较顺畅。Windows 裸机也能装,但路径兼容性和文件权限问题会多一些,我的实测体会是 WSL 里更省心。

VSCode 用户可以在扩展市场搜官方扩展,装好后,在命令面板里执行登录授权,然后在集成终端里启动claude就能开始用。我自己的习惯是开一个分屏终端,左边写代码右边挂 Claude Code,这样看 diff 和交互不用来回切换窗口。

5.2 自动更新失败:npm prefix 没有写权限

我一共踩过两次“auto-update failed: no write permission to npm prefix”这个报错。它通常发生在全局 npm 包安装到了系统级目录、但普通用户没有写入权限时。解决办法不是sudo硬刚,而是让 npm 把全局目录改到用户自己的目录下:

# 查看当前 prefix npm config get prefix # 改到用户目录(以 ~/.npm-global 为例) npm config set prefix ~/.npm-global # 把新目录加到 PATH echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.zshrc source ~/.zshrc # 重新安装 npm install -g @anthropic-ai/claude-code

如果已经装到系统目录了,用npm uninstall -g @anthropic-ai/claude-code先卸掉再重来。这个报错本身不影响旧版本使用,但会导致新版本装不上,建议一次修到位。

5.3 接入 DeepSeek 等兼容底座:用环境变量切换端点

很多不了解内部机制的人以为 Claude Code 是封闭的,只能连官方服务。它其实留了环境变量开关,可以接第三方兼容 Anthropic API 的服务。例如想换成 DeepSeek 的兼容端点,配置方式大致是这样:

export ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic export ANTHROPIC_AUTH_TOKEN=你的key

设置完之后直接运行claude,就不再走原先的登录授权流程,而是把请求发到你设置的端点。这样做的好处是可以用自己已有的第三方额度节省成本,但要注意兼容性:不同模型对工具调用、长上下文的处理方式不完全一致,我实测下来出现过某个工具名不支持、某个参数被忽略等情况,所以建议在非关键项目里先用一段时间,别一上来就切到生产环境。

5.4 如何让 Claude Code 直接执行终端命令,以及权限怎么把控

Claude Code 本身能执行 Bash 命令,比如跑测试、装依赖、查文件。默认情况下它每执行一条命令都会问你要权限,这在自动化流程里有点烦,所以有人会开--dangerously-skip-permissions,直接跳过所有确认。我必须给个提醒:这个模式只适合在容器、临时环境或你完全清楚风险的场景里用,别在本地开发机上裸奔,否则 AI 真的会执行出格命令。

我平时的做法是把常用命令白名单写进配置,让构建、测试这类低风险命令自动通过,高危操作仍然逐个确认。具体可以在项目启动时用权限模式控制,比如--permission-mode加上允许列表。这类配置看着费时间,但属于一次性投资,后期省心非常多。

5.5 其他常见问题速查表

问题现象可能原因处理方式
claude命令找不到Node 版本过低或全局目录没进 PATH先升级 Node,再用npm config get prefix检查路径
在线升级没反应npm prefix 权限不对重置 prefix 到用户目录,重装全局包
从 VSCode 集成终端启动失败扩展没登录授权,或终端 shell 环境不对检查扩展设置,重新执行登录授权
macOS 上无法下载安装常见于 Node 版本太老、npm 源缓存异常换 nvm 装新版 node,清 npm 缓存再装
输出乱码或日志打不开旧版本日志格式和新版不兼容直接用文本编辑器打开 JSONL,或者让脚本做容错
想绕过交互登录直接使用使用了第三方兼容端点但环境变量没生效确认ANTHROPIC_BASE_URL和ANTHROPIC_AUTH_TOKEN都已 export,再新开终端启动

我在翻日志时还注意到一个细节:不同版本 Claude Code 写日志的字段结构偶尔会变化,比如早期版本把usage放在 message 内部,新版挪到了事件顶层。如果你写脚本统计时发现字段对不上,不要怀疑自己手机子,先拿一条真实日志下来看结构。

结尾:数据不撒谎,但它会逼你承认自己偷懒

这次数据审计最大的收获,不是发现某个工具的好坏,而是我被迫承认了一个事实:所谓“AI 编程助手不够强”,很多时候只是我为自己的模糊指令和懒散 review 找的借口。工具不会撒谎,但它只能暴露你原本的工作习惯。

最后分享一个我目前在用的低成本法。你不需要像我一样写全套统计脚本,只需从这周开始,每次结束一个 Claude Code 会话时,随手用一个 markdown 文件记三件事:这个会话花了多长时间、有没有产出可合入的变更、如果没产出,卡在哪一步。一周后回看,你大概也会看到一些不太想承认的实话。根据我个人经验,只要愿意面对这些实话,你和工具的效率都会立刻上一个台阶。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询