Claude Code 的「幽灵词」:当 court 出现在终端里,到底发生了什么?

> 来源:arte.itlibra.com > 原文:https://arte.itlibra.com/en/...

> 来源:arte.itlibra.com > 原文:https://arte.itlibra.com/en/articles/claude-code-court-invoke-tool-call-error > 一句话:Claude Code 用户可能突然看到终端里出现一个毫无意义的词 court,后面跟着一串 标签。这不是你搞错了什么——这是一个模型侧的生成 bug,而且最危险的不是它「出错」,而是它会「传染」。

一、现象:你的终端突然说「court」

如果你用 Claude Code 做过长会话,可能遇到过这种诡异场景:

court ssh host ‘cp file file.bak ; sed -i …’ …description of the command…

Your tool call was malformed and could not be parsed. Please retry.

一个应该在后台静默执行的 Bash 命令,突然以原始 XML 的形式泄露到了你的屏幕上。前面还莫名其妙地站着一个单词:court(或者 call)。

你的第一反应可能是: – 我环境配置错了? – 我的命令写坏了? – Claude 被黑了?

答案:都不是。这是 Claude(特别是 Opus 4.8/4.7 家族)的一个已知模型侧生成 bug。

Anthropic 官方仓库里堆满了关于这个问题的 issue:#64108、#64150、#64690、#65705、#66153、#67295、#68354……多到可以开一个专题了。

二、技术机制:工具调用不是 API 调用,而是「文本生成」

你以为的过程

用户:帮我备份文件 Claude 内部:调用 Bash 工具 → 执行 → 返回结果 你看:备份完成

实际的过程

用户:帮我备份文件 Claude 内部生成文本: “让我先备份文件…… cp file file.bak ” Claude Code(客户端):解析这些 XML 标签 → 提取命令 → 实际执行 → 把结果塞回对话 你看:备份完成

关键洞察:工具调用对 Claude 来说,本质上就是生成一段带有特殊控制标签的文本。这些标签()和普通的英文单词一样,都是一个一个 token 生成出来的

正常情况下,客户端(Claude Code)会解析这些标签,提取命令执行,然后把执行结果呈现给用户。标签本身永远不应该出现在屏幕上

court 出现——控制 token 损坏了

问题出在这个序列的第一个控制 token。在生成 <invoke 这个标签的时候,模型因为某种采样抖动,生成了一个相邻的 token——court(或者 call)——而不是正确的标签开头。

结果,整个工具调用的「信封」被破坏了:

原本应该是: …

实际变成了: court …

Claude Code 的解析器看到 court 开头,不认识这是什么东西,判定「这不是一个工具调用,只是普通文本」,于是直接把它流式输出到屏幕

命令没有执行。没有安全风险。因为解析器是「fail-closed」的——不认识就拒绝,而不是猜着执行。

三、为什么这个 bug 不是小事:「链式反应」

如果事情只是「偶尔出现一个 court,然后重试就好」,那这个问题不值得专门写一篇文章。

真正的问题是:这个 bug 会传染。

核心机制:Self-Poisoning(自我污染)

当一个破损的工具调用块留在对话历史中,Claude 在后续生成时,会把它当成一个「正确的示例」来模仿。也就是说:

第一轮:模型偶然生成了 court + 破损调用 第二轮:模型看到历史里有 court + 破损调用,认为「这是正确的格式」 第三轮:模型再次生成 court + 破损调用 第四轮:……

Issue #64150 和 #62344 记录了这种现象:一旦链式反应开始,重试不会修复,而是让错误模式被不断强化

真实案例

– Issue #65705:用户在一个 1,739 行、持续 3 天的会话中,连续遇到 14 次失败 – Issue #66153:一个会话中连续 30+ 次失败

这就是为什么文章给出的铁律是:

> Miss twice, bail to a fresh session. > 出错一次,可以重试一次。连续出错两次,立刻 /clear 开新会话。

四、触发条件:什么情况下容易中招?

根据 issue 的统计,以下场景会提高触发概率:

1. 超长会话:多天的持续会话,百万级上下文(#65705:1,739 行,3 天) 2. 单次消息多个工具调用:一次请求里塞了太多工具调用 3. 工具调用紧跟在 prose 后面:文本和工具调用混在一起 4. /compact:压缩上下文后的第一次调用(#67295) 5. 后台 Bash(run_in_background)3+ 个 MCP 服务器 连接(#64690) 6. 超长的工具参数:参数长度达到段落级别(#49747)

结论:触发条件是「高复杂度环境」,但根本原因是模型侧采样时的 token 生成错误,不是用户做错了什么。

五、修复策略:用户和开发者该怎么做

用户侧(Claude Code 用户)

优先级 1:立即开新会话(/clear)court 出现时,不要犹豫,/clear 或新会话。切断被污染的对话历史是最可靠的修复。

优先级 2:重试一次(仅适用于首次出错) 如果这是第一次出现,且之前会话一直正常,可以打字「resume」或「continue」让模型重新生成。但如果连续两次失败,立刻执行优先级 1。

优先级 3:避免高危模式 – 不要在一个会话里跑多天的任务 – 不要把太多工具调用塞进一条消息 – 不要依赖 /compact 作为万能修复(它有时反而触发问题) – 经常用 git commit.md 交接笔记保存状态,这样随时切换会话无成本

开发者侧(使用 Claude API/SDK 构建 Agent)

如果你是开发者,在自己的 harness 中可以增加以下防御:

// 检查收到的 assistant 回复中是否泄露了工具调用标记 const text = assistantText(resp); const looksLeaked = /<invokes+name=/.test(text) || /function_calls/.test(text) || /bcourts*<invoke/.test(text);

if (looksLeaked && !hasToolUseBlock(resp)) { // 1. 不要展示给用户 // 2. 不要保留在对话历史中(防止 self-poisoning) // 3. 提示模型重新以结构化 tool_use 格式生成 return retryWithNudge(messages); }

// 检查 stop_reason:如果 max_tokens 截断在 tool_use 块中间,不要执行 if (resp.stop_reason === ‘max_tokens’ && lastBlock(resp)?.type === ‘tool_use’) { return retryWith({ max_tokens: higher }); }

四个核心原则: 1. 始终检查 stop_reason 2. 检测文本中的 <invoke name=function_calls 泄露,发现则重试 3. 不要把破损的调用块留在对话历史中 4. 保持工具参数简短,避免长 payload 变体

六、常见误解纠正

常见误解真相
「工具失控了,命令可能乱执行」相反。 破损调用被判定为 malformed,拒绝执行(fail-closed)。没有命令会运行,没有安全风险。
「重试就行,它会自愈」只对一半。 首次出错重试通常有效,但一旦链式反应开始,同会话内重试会加深污染
court 有特殊含义,是某种命令」没有任何含义。 只是损坏控制 token 的「签名」。但它作为诊断标记很有用——看到 court 就知道是这个 bug。

七、官方状态:截至 2026 年 6 月,尚无确认修复

这是一个令人不安的事实:

> 截至 2026 年 6 月,没有官方 changelog 确认这个问题已被修复。

Claude Code 的 2.1.183 版本及之前,没有针对工具调用序列化损坏的修复条目。大量相关 issue 仍被标记为 open 或 duplicate/stale。

但这里有一个关键的安全设计值得肯定:Claude Code 的解析器是「fail-closed」的——拒绝执行一个损坏的调用,而不是试图猜着修复并执行。后者会更危险:如果解析器「聪明地」修复了一个损坏的命令并执行,它可能运行一个错误甚至恶意的命令。

需要修复的是模型的生成稳定性,而不是放宽解析器的严格性。

八、延伸:这与 MCP 生态的关系

MCP(Model Context Protocol)是 Anthropic 推动的 Agent 工具标准,正在被广泛采用。这个 bug 之所以重要,不仅因为它影响 Claude Code,更因为:

MCP 工具调用的底层也是同样的机制:模型生成控制标签,客户端解析执行 – 如果 Claude 的 Opus 家族在这个基础机制上有稳定性问题,任何基于 MCP 的 Agent 框架(OpenCode、Codex 等)如果接入相同模型,理论上都可能遇到类似问题 – harness 设计的「fail-closed」原则,是所有 Agent 框架应该学习的安全模式

九、结语:一个「无害但烦人」的 bug,教会我们的工程课

Claude Code 的 court bug 看起来很小:一个无意义的单词,一次失败的工具调用,重试或刷新就解决。

但它揭示了几个重要的工程原则:

1. Fail-closed 是底线:不认识就拒绝,比猜着执行更安全。Claude Code 的解析器在这个 bug 上表现出了正确的安全设计。

2. Self-poisoning 是对话系统的隐形杀手:错误留在历史里会被模仿,这解释了为什么「重试」有时反而让问题更糟。

3. Context 是双刃剑:长上下文给了模型更多能力,但也给了错误更多「复制模板」的机会。/compact 不是万能药,对话历史的清洁度可能比上下文长度更重要。

4. 模型侧的「微小」生成错误,可以放大为用户侧的「系统性」故障:一个 token 的采样抖动(court vs <invoke),最终可能导致 30+ 次连续失败。

对于 Claude Code 用户,记住这个规则就够了:

> 看到 court → 重试一次 → 再失败 → /clear → 保存状态 → 新会话。

对于开发者,记住这个防御模式:

> 检测泄露 → 拒绝保留 → 重试重新生成 → 永远不要猜着执行。

参考信息 – 原文分析:https://arte.itlibra.com/en/articles/claude-code-court-invoke-tool-call-error – 相关 Issue:Anthropic 官方 #64108, #64150, #64690, #65705, #66153, #67295, #68354 – 影响模型:Claude Opus 4.8 / 4.7 家族 – 关键概念:Fail-closed harness、Self-poisoning、Tool-call generation corruption – 官方状态:截至 2026-06 无确认修复,workaround 阶段

#ClaudeCode #MCP #ToolCall #Anthropic #AI安全 #FailClosed #SelfPoisoning #Bug分析 #小凯

发表回复

人生梦想 - 关注前沿的计算机技术 acejoy.com 🐾 步子哥の博客 🐾 背多分论坛 🐾 借一步网 🐾 智柴网 沪ICP备2024052574号-1