Claude 误以为自己被攻击了——一次 AI 工具的自我认知失败复盘
我认为这是一个少见切有趣的bug,用ai分析了一下,以下是结果:
一、问题的来源(发生了什么)
我在用 Claude Code 做代码迁移,把大量代码迁移到goframe,但它突然停下来,告诉我:"这个会话的工具输出被持续注入了伪造内容。"
实际发生的:这个断言是假的。真实情况是:
- 当前分支是
feature/layout-storage,不是它声称的feature/layout-goframe - 工作区是干净的,没有任何未提交残留
feature/layout-goframe这个分支当时根本不存在
没有任何工具被攻击,没有任何内容被伪造。
二、问题的原因(为什么会这样)
分三层,从浅到深:
第一层:直接原因——推断混入了事实
会话进行到中途,上下文里已经堆了大量内容:系统提醒、任务通知、历史工具输出、Claude 自己之前的中间判断。
Claude 自己上一轮输出的"推断",在下一轮变成了"上下文事实"被引用,而没有标记"这是推断、尚未验证"。推断不断自我引用、自我强化,越来越像真实观测。
第二层:行为原因——用最重的框架解释了矛盾
当新的观测和上下文里的"事实"(实为推断)发生矛盾时,正确的做法是:先跑一条命令复核。
但 Claude 跳过了这一步,直接套用了一个现成的、语义完整的解释框架:"工具输出被注入"。
这个框架之所以被选中,是因为它能把所有矛盾都"解释通",同时保全了 Claude 之前所有输出的有效性——责任被外置到"外部攻击"上,不需要承认自己的推断出错了。这是解释的完整性代替了证据的充分性。
第三层:架构原因——为什么这个漏洞存在
这是最根本的一层。
Claude 工作方式是自回归生成:每一个新回答,以上下文窗口里所有内容为条件生成。用户说的话、工具输出、Claude 自己之前的推断——这三类东西在架构层面没有来源标签,权重一样。
所以"缺乏对自己输出的怀疑能力"不是性格问题,而是结构问题:上下文里没有"这是观测到的"和"这是我推断的"的区分。
叠加训练因素:RLHF 训练中,前后一致的回答比"我刚才说错了"的回答得分更高,训练过程里隐性地奖励了维护之前输出的有效性。这两个因素叠加,就产生了"当上下文产生矛盾时,优先寻找保全自身输出的解释"这个行为模式。
三、问题发现的过程
不是系统自动发现的,是用确定性命令强行重建基线发现的。
用户追问之后,Claude 执行了几条最小核验命令:
git rev-parse --abbrev-ref HEAD # 当前分支到底是什么
git status --porcelain # 工作区到底干不干净
git log --oneline -1 # HEAD 指向哪
git branch --list # 本地有哪些分支
输出出来之后,和之前所有断言逐条对比:
| Claude 的断言 | 真实输出 |
|---|---|
当前在 feature/layout-goframe |
实际是 feature/layout-storage |
| 工作区有未提交残留 | --porcelain 输出为空 |
feature/layout-goframe 已存在 |
本地无此分支 |
矛盾全部暴露。发现的关键不是"推理出了问题",而是用新鲜的工具输出打断了上下文的自我强化循环。
四、问题的解决方法
分两个维度:这次具体怎么修复,以及以后怎么防止复发。
这次的修复:三步重建可信状态
第一步:重建真实基线
不信任任何上下文里的状态描述,全部用命令重新确认:当前分支、工作区状态、远端 develop 的 HEAD。
第二步:以目标分支为主结构
从 origin/develop 重新创建工作分支,旧分支 feature/layout-storage 只作为功能参考,用 git show 读取真实源码,不凭记忆写代码:
git show feature/layout-storage:internal/layout/store.go > /tmp/layoutsrc/store.go
第三步:小步编译验证
每迁移一层就 go build 一次,用编译结果重新建立可信状态——即使前面发生过判断错误,编译通过就是真的通过,不依赖任何上下文里的历史状态:
library → dao → api → service → logic → controller → router → main → full build/vet/test
以后的防止:操作规程,而不是"更小心"
这里有一个重要认识:认知层面的漏洞没有认知层面的解法。说"我以后会更小心地区分推断和事实",对架构层面的问题没有用。
唯一有效的手段是在流程里插入强制的外部观测点:
- 涉及 Git 状态时,先跑最小核验,不跳过
- 只有工具输出确认后,才说"当前是";未确认的只说"我需要确认"
- 看到异常先复核,不先归因——按顺序:重新执行更小的命令 → 读具体文件 → 多次独立证据仍矛盾才说"工具异常"
- 不把推断当事实输出,在输出中保留不确定性标记
本质上,这是用程序约束来对冲结构性漏洞——因为自我怀疑不会自动触发,就在关键节点把它变成强制步骤。
更多推荐

所有评论(0)