Claude Code 远程连接的坑之「以为是 1M 上下文,它却偷偷给我用了 200k」

🚀 省流助手

  • 现象:在手机上通过cc-connect远程桥接用 Claude Code,长对话里它突然"答非所问"------不是变水,而是凭空冒出我没说过的前提(我说"一个 git 仓",它非要论证"两个 git 仓怎么隔离")。
  • 关键反差 :我平时一直用 1M 上下文 ,本不该撞墙;但通过 IM 桥接拉起的会话,悄悄回落成了 200k 默认------不是我以为继承的 1M。坑就在这层"配置预期错位"。
  • 根因 :jsonl 日志实锤------出错那刻占用 ≈177k(200k 窗口的 88%) ,全程贴着 200k 天花板跑。逼近上限触发了"虚构"(confabulation),所以飘。不是工具 bug
  • 解决 :把上下文切回 1M ,回答当场恢复正常;长对话用一行 jq 监控占用,逼近 80% 就开新会话/精简。

一、现象:它不是答得差,是答得"不在一个频道"

先说清楚,这次的毛病和大家常吐槽的"AI 降智"不一样。

降智是:答案变水、变浅、变笼统,但还在聊同一件事 。而这次是另一种病------答非所问、驴唇不对马嘴。我管它叫"飘"。

具体场景:我在跟 Claude Code 讨论一个方案,核心设定从头到尾就一句话------"把所有邮件文件放进一个 git 仓,再用软链接打到各个目录"。聊了十几轮后,它突然来了这么一段(原文摘录):

结论:物理上确实是两个独立的 git 仓(项目 git + 邮箱 git),这是"邮件不能进业务仓"的必然结果......

我当场懵了:哪来的第二个 git?从头到尾都是一个 git。 它凭空造了一个我没提过的前提,还煞有介事地论证"两个 git 怎么隔离、会话怎么不背认知负担"。

这里有个细节,也是我一开始根本没往"上下文满了"上想 的原因:我平时用 Claude Code 都是开着 1M 上下文的,这点长度的对话连窗口的零头都占不到,从没撞过墙。所以第一反应是"工具是不是有 bug 串台了",而不是"上下文是不是满了"。真相比这两个猜测都更有意思------也更值得每个用 AI 协作的人记一笔。


二、排查路径:三个假设,逐个验

我没有靠感觉下结论,而是把这次会话的原始日志捞出来对质。Claude Code 每次会话都会在本地存一份 jsonl:

bash 复制代码
# 会话日志位置(按项目路径编码成目录名)
~/.claude/projects/<your-project>/<session-id>.jsonl

每行一个 JSON 事件,包含 type(user/assistant)、message.content、以及最关键的 message.usage(token 用量)。下面三个假设逐个验。

假设 1:是不是消息桥接工具串了上下文?

我不是在终端裸用 Claude Code,而是通过一个 IM 桥接在手机上跑长对话------很自然先怀疑它把别的对话混进来了。

验证:把"两个 git"这串字第一次出现的位置揪出来,看它来自谁。

bash 复制代码
jq -r 'select(.type=="user") | (.message.content | if type=="string" then . else (map(select(.type=="text")|.text)|join(" ")) end)' "$F" \
  | grep -n "两个\|第二个"

结果:用户消息里"第二个 git"只出现过一次,而且是我事后的否定句 ------"哪来的第二个 git,都是一个 git"。它第一次出现是在 AI 自己的回复 token 里,没有任何外部内容引入。

假设 1 排除:单线程、无注入、无串台。桥接工具只负责传消息,不改内容。

假设 2:是不是触发了自动压缩(compact)?

长对话超长时,有些工具会自动把前文摘要压缩,摘要失真就可能丢主线。

验证

bash 复制代码
grep -c "isCompactSummary\|compact_boundary\|\"type\":\"summary\"" "$F"
# 输出:0

假设 2 排除:全程 0 次压缩事件。不是摘要把信息揉丢了。

假设 3:是不是上下文逼近窗口上限了?

这是最后、也最该量化的假设。注意一个关键区分:模型本身(Opus)支持 1M 上下文,但 Claude Code 客户端默认只给会话开 200k 这一档,用满 1M 要显式切到 1M 档位。会不会是聊太长、撞上了这个 200k 默认档的天花板,把我早期说的"一个 git 仓"那几轮"挤"出了有效注意力?

这个假设不能靠猜,得算出出错那一刻的上下文占用


三、关键证据:一条 token 曲线把真相焊死

上下文占用不是单看 input_tokens,而是三项之和:

ini 复制代码
ctx = input_tokens + cache_read_input_tokens + cache_creation_input_tokens

一行 jq 把每条回复的占用按时间拉出来,再定位"两个 git"那条:

bash 复制代码
jq -r 'select(.type=="assistant" and .message.usage)
  | .message.usage as $u
  | (($u.input_tokens//0)+($u.cache_read_input_tokens//0)+($u.cache_creation_input_tokens//0)) as $ctx
  | "\($ctx)\t\(.timestamp[11:19])"' "$F"

把结果和"漂移点 / 我察觉问题 / 切换 1m"几个节点对齐,曲线长这样:

事件 上下文占用 状态
"两个 git" 漂移发生 ≈ 177k = 200k 的 88%,危险区
我回怼"哪来的第二个 git" ≈ 190k 95% 满
漂移后最后一条 197,435 死贴 200k 天花板
紧接着下一条 206,606 首次突破 200k
会话尾段 ≈ 320k 平滑增长,无回落

这张表是整个排查的 turning point。读它:

整个对话------包括漂移点、以及漂移后约 17 分钟------上下文一直死贴在 200k 以下(177k → 190k → 197k),然后才"破墙"冲到 206k,最后一路涨到 32 万。

这是一条教科书式的签名:前半段被 200k 卡着贴边跑,我察觉不对劲后把模型上下文升到 1m,墙一拆,占用立刻越过 200k 往上走。日志的曲线,独立印证了"先撞墙、后升级"的全过程------不是我先入为主,是数字自己对上的。


四、根因:窗口快满时,最先"糊掉"的恰恰是早期锚点

一句话根因:上下文逼近 200k 上限时,模型对"很早之前已确立的事实"的注意力衰减最严重,于是它凭空脑补来填洞------这就是 confabulation(虚构)。

为什么是"飘"而不是"降智",关键就在这里:

  • "一个 git 仓 + 软链"这个核心设定,是我在很靠前的几轮说的。
  • 窗口贴满时,最该被参照的早期锚点,恰好是有效注意力里最先被稀释的那部分。
  • 模型不会"空着"------它会用一个看似合理的前提("两个 git")把洞补上,并自信地往下论证。

降智是均匀变笨(注意力够、但深度不足);飘是局部失锚(早期关键信息掉出有效注意力,被虚构替代)。两者根子不同,处方也不同。

但故事还有更值得记一笔的一层------为什么偏偏是我撞上了

我平时用 Claude Code 全程开着 1M 上下文 ,这点对话长度连零头都占不满,理论上永远撞不到墙。我一直默认:桥接工具拉起的会话,自然也继承我平时这套 1M 配置。结果它没有。

我以为 实际
交互式终端会话 1M 上下文 1M(对的)
桥接工具拉起的会话 以为继承 1M 悄悄回落成 200k 默认

这就是真正的坑:非交互方式(桥接、自动化、定时任务)拉起的 AI 会话,往往不继承你交互式终端里的个性化配置,而是回落到工具的出厂默认值。 这里要分清两层:Opus 模型本身 支持 1M 上下文,但 Claude Code 客户端 默认只给会话开 200k 这一档,用满 1M 要显式切档(在模型 id 上体现为 [1m] 这样的后缀变体)。我平时终端里开着 1M 档,却没想到桥接拉起的会话回落到了 200k 默认档。于是我在"自以为有 1M"的错觉里,一头撞上了 200k 的墙------窗口比我以为的小了 5 倍,撞墙当然猝不及防。

所以这不是"我不会管理上下文/不会压缩",而是"我以为的配置和实际跑的配置错位了"。 这种错位最阴险的地方在于:它不会报错、不会提示,只会让回答悄悄开始飘。


五、解决方案

临时救火

发现答非所问、且确认上下文已经很长时,别跟它继续掰扯------它只会在错误前提上越陷越深。两个动作二选一:

text 复制代码
1. 直接开新会话,把核心设定重新喂一遍(最干净)
2. 把会话上下文档位从 200k 切到 1m(Opus 模型本身支持 1M,客户端显式切档即可)

我当时选了切 1m。效果立竿见影:同样长度的对话,从占满 200k 变成只用了 1m 的 ~20%,彻底离开危险区,后续回答恢复正常。

永久习惯

把"看一眼 token 占用"做成长对话里的肌肉记忆。一行命令看当前会话最新占用:

bash 复制代码
F=$(ls -t ~/.claude/projects/<your-project>/*.jsonl | head -1)
jq -r 'select(.type=="assistant" and .message.usage) | .message.usage
  | (.input_tokens//0)+(.cache_read_input_tokens//0)+(.cache_creation_input_tokens//0)' "$F" \
  | tail -1

占用逼近窗口的 80% 就是黄线------要么开新会话,要么升上下文,别硬撑到撞墙。


六、预防建议

  • 别假设"配置会被继承",去核实实际值:这次最大的教训。凡是非交互方式(桥接、自动化脚本、定时任务、CI)拉起的 AI 会话,别默认它继承了你交互式终端里的个性化设置------它很可能回落到出厂默认(如 200k 而非你平时的 1M)。第一时间确认它实际跑的上下文窗口有多大。(这条是基于本次实测 + 日志佐证的工程经验,不同工具/版本的继承行为可能不同------所以重点不是"记住某个默认值",而是"用日志核实实际窗口"这个动作本身。)
  • 长对话定期"重锚":关键设定每隔一段主动复述一遍,把它顶回近端上下文,别指望模型一直记得几十轮前的话。
  • 重要结论落盘:把定稿的设计/约定写进文件,让模型对着文件改,而不是对着几十轮的对话记忆改------文件是稳定锚点,对话不是。
  • 区分"飘"和"降智"再处置:答案变水 → 可能要换更强模型或拆解任务;答非所问/捏造前提 → 先查上下文是不是快满了,对症的是开新会话/升上下文,换模型没用。

七、知识点提炼

① Claude Code 的会话日志在哪、长什么样

每次会话都本地落盘成 jsonl:~/.claude/projects/<编码后的项目路径>/<session-id>.jsonl。每行一个事件,type 区分 user/assistant,message.usage 记录 token 用量。它是排查 AI 行为最硬的一手证据------比回忆"它当时好像说了啥"可靠一万倍。

② 上下文占用怎么算

别只盯 input_tokens。真实窗口占用是三项和:

复制代码
input_tokens + cache_read_input_tokens + cache_creation_input_tokens

prompt caching 会把绝大部分历史塞进 cache_read,只看 input 会严重低估占用。

③ confabulation:模型失败模式里最迷惑的一种

它不报错、不卡顿、不空白,而是流畅、自信、看起来合理地 生成没有依据的内容,甚至能把自己捏造的前提反过来归到你头上。它是模型机理决定的固有现象,能靠流程压制(重锚、落盘、监控上下文),但没有"修复"开关。所以遇到 AI 答非所问,第一反应不该是"这工具有 bug",而是"我的上下文是不是出问题了"。


写在最后:这次排查最大的收获不是"修好了一个 bug",而是建立了一个习惯------AI 表现异常时,先去翻它的日志,让证据说话。猜测谁都会,但一条 token 曲线能把"到底是工具的锅还是上下文的锅"焊得死死的。

相关推荐
ytAnck2 小时前
傻傻分不清OpenAI 与 Anthropic 接口协议差异
openai·ai编程
妙码生花2 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十五):优化细节、网络请求封装
前端·后端·ai编程
小白鼠幻想家2 小时前
Devin:从"取代你的AI程序员"到"AI不会取代人类"——这家CEO的嘴,比AI还快
ai编程
AlbertZein3 小时前
从“看图说话”到“动手干活”:看看国产多模态模型在生产场景下的真实表现
aigc·openai·ai编程
JavaGuide4 小时前
推荐 3 个 Vibe Coding 中文开源教程,从入门到实战
ai编程·vibecoding
plainGeekDev4 小时前
别再说 Claude Code 上下文不够用了,是你没管好
aigc·ai编程
牛奶4 小时前
AI 能赚钱了——但赚的不是你
人工智能·ai编程·nvidia
ZJPRENO7 小时前
美团 LongCat-2.0 完整发布解读(2026.6.30 正式发布)
ai编程