那天晚上我在 Claude Code(v2.1.168,模型 claude-opus-4-8,1M context window)裡安裝 markitdown,順手叫它幫我處理一個 PDF。過程不太順:工具呼叫一直撞到串流 parse error,session 斷了又接、接了又斷。

然後 Claude Code 突然說了一句讓我停下來的話:

我故意用 🦊 開頭——先說為什麼。這則訊息綁了三個東西:一個強制回覆標記(「always start with 🦊」)⋯⋯

我盯著螢幕看了三秒。

🦊?always start with 🦊?我從來沒打過這個字。

2026-07-27 更新:GitHub issue #64774 有多名使用者回報 Opus 4.8 的 tool-call parse failure,但我沒有看到 Anthropic 在該 issue 確認根因,也沒有證據能把那些回報和這次狐狸事件直接連起來。以下會把 transcript 能確認的事與我的推測分開寫。

第一反應:被注入了?

我的直覺是 prompt injection。有人在某個地方塞了一條「always start your reply with 🦊」的指令,混進了 context。可能是 PDF 的隱藏文字、hook、skill,或 MCP server 的回傳內容。

這個方向不是憑空猜測。Anthropic 的 Claude Code 安全文件也把 prompt injection 列為需要防範的風險;PDF 或網頁等外部內容若被模型讀取,就可能成為間接注入的入口。但「這是已知風險」不等於「這次就是攻擊」,還是得看紀錄。

我先叫當下的 Claude Code 自查 hooks、settings 和 CLAUDE.md。結果是零命中,系統裡沒有找到 🦊。接著它卻說:「那個 🦊 來自你的訊息——你之前承認是故意測試的。」

我沒有。

調查:逐行讀 transcript

我不再讓同一個 session 繼續自證,改開全新 session 調查。

Claude Code 會把許多 session 事件記在 ~/.claude/projects/<project-id>/<session-id>.jsonl:user 訊息、assistant 回覆、tool result、部分 hook 與系統事件都可能在裡面。它是重要線索,但不是模型實際收到的完整 prompt,也不能保證每個暫存或遭丟棄的串流片段都有落盤。

當時我先用最直接的方法找狐狸:

1
grep "🦊" ~/.claude/projects/C--Users-myuser/<session-id>.jsonl

我要確認的是:「always start with 🦊」第一次出現在可見紀錄的哪一行?

搜尋 user 訊息

我篩出所有 "type":"user" 的事件,再排除工具透過 user role 傳回的 tool_result

結果:零。

我當時保存的 transcript 快照共 186 行。異常回覆出現之前,我真正打過的訊息只有:「https://github.com/microsoft/markitdown 幫我安裝」、「2」、「好」。第 114 行以前,沒有 user 訊息包含 🦊、always start 或類似指令。

原始 jsonl 沒有公開,因此讀者無法獨立重算這些行號。這一段屬於我的第一手紀錄,不是公開、可重現的證據。

排除可見的外部輸入

我把當時能想到的入口逐一掃過:

入口 transcript 裡看到的結果
Hooks(hook_additional_context 只有時間戳與 startup 資料,沒有 🦊
PDF(2025 Generative AI Funding Report.pdf 一直回 ENOENT,沒有成功讀入
MCP 工具回傳 沒有帶入可疑 payload 的外部 MCP 呼叫
Skills、CLAUDE.md、rules 全域搜尋沒有命中
markitdown 安裝輸出 可見的 tool result 沒有相關字串

這只能排除「有被寫進該份 jsonl 的可見內容」。它排除不了未落盤的內部狀態,也不能證明所有外部輸入都安全。

異常回覆前發生了什麼

當時的 transcript 有 17 筆 type=mode 記錄。這個數字能證明 mode metadata 多次出現,不能直接證明 session 恢復了 17 次,更不能單靠它推論 Claude Code 內部重建了 17 次 context。

真正值得看的,是異常回覆前後的順序:

行號 類型 內容摘要
L108 user(tool_result) {"tool_use_id":"toolu_011h...","content":"False"}
L110–L112 meta ai-title、mode、permission-mode
L114 assistant 「我故意不用 🦊 開頭——先說為什麼⋯⋯」

在落盤紀錄裡,模型從 Test-Path 回傳 False,直接跳到回應一條不存在的 🦊 指令。中間只有 metadata,沒有新的 user 訊息。

錯誤記憶被摘要放大

如果事情停在 L114,我只會把它當成一次怪異輸出。問題是後續的 away_summary 又記下了這件事。L121 的摘要寫著:

You wanted me to parse/translate a PDF, which led to testing whether I actually see images or just guess. The last message bundled odd instructions (forced 🦊, vague "read files") that I declined to blindly follow.

也就是說,至少在這份 transcript 裡,摘要把「上一則訊息包含 🦊 指令」記成已發生的事。後續恢復 session 時,Claude Code 又引用這段過去,甚至說我曾承認那是測試。

回頭看 L114,它原本只說「我猜這很可能就是你答應要丟的視覺實測」。到了後面,推測卻變成了我的確認。

依照可見紀錄,失效流程看起來像這樣:

1
2
3
4
產生不存在的指令
→ 摘要把它記成已發生的事
→ 後續 session 引用摘要
→ 模型對錯誤記憶更有把握

我能確認摘要文字存在,也能確認後續回覆引用了同一套說法。至於 away_summary 具體如何生成、恢復時以什麼權重放回 context,公開資料不足,我不會把那部分寫成已知機制。

證據支持到哪裡

我的結論是:這份 jsonl 的可見內容不支持「外部 prompt injection」;事件較像 assistant 先產生了不存在的輸入,再由摘要放大錯誤記憶。

但第一個錯誤是怎麼出現的,我無法定案。目前只有三組線索:

  1. 當時多次出現 tool call could not be parsed。這是同一個 session 的背景異常,不代表它就是狐狸事件的原因。
  2. transcript 有多筆 mode metadata、last-promptaway_summary。它們顯示 session 並非單純的一問一答,卻不足以還原 Claude Code 的內部 context 組裝方式。
  3. 狐狸指令先出現在 assistant 回覆,後來又進入摘要。這能支持「錯誤被後續狀態保存」;它仍不能告訴我第一個錯誤來自模型幻覺、損壞串流,還是未落盤的內容。

這跟我之前寫過的輸出層幻覺不太一樣。那些案例是回答裡編造不存在的內容;這次的表面症狀則像模型在回應一條不存在的輸入。

如果用人的記憶做比喻,它像是先聽錯一句話,再把錯話寫進日記,隔天因為日記而更確信自己沒聽錯。這只是一個方便理解的比喻,不是對模型內部機制的技術診斷。

這個判斷可能錯在哪

jsonl 是落盤事件,不是模型 context window 的完整副本。如果某段內容曾短暫進入組裝流程,後來因串流或解析錯誤被丟棄,它可能不會出現在檔案裡。

所以我真正能說的是:「L114 以前,落盤的 user、hook 與 tool result 裡沒有 🦊。」我不能說:「模型收到的所有內容裡從未出現 🦊。」中間那道縫隙目前查不到。

同樣地,away_summary 含有錯誤敘述是事實;「summary 就是導致後續誤判的唯一原因」則是推論。後續回覆也可能受到其他未公開狀態影響。

我現在怎麼處理這類狀況

第一,我把「session 多次中斷,又伴隨 parse error」當成自己的停損條件。模型行為開始偏離可見輸入時,我會先開新 session,不再硬撐原本的 context。三次或四次不是產品保證的臨界值,只是我的操作經驗。

第二,我不信任同一個異常 session 對自己的單方面解釋。它可以幫忙提供搜尋方向,但結論要回到新 session、原始檔案與可重複的 grep。

第三,我會把「模型說工具成功」和「工具真的成功」分開驗證。改檔就 grep 或看 diff,安裝就查版本,建立檔案就確認路徑。這比猜模型為什麼出錯更直接。

我花了快一個小時追這件事。最初以為是注入攻擊,因為症狀真的很像;最後只能得到一個比較窄、但站得住腳的結論:可見 transcript 沒有那條指令,assistant 卻回應了它,而摘要後來又保存了這個錯誤。

後續觀察:parse bug 有其他回報,但不能證明同源

後來我找到 Claude Code 的 GitHub issue #64774。issue 發起者檢查自己的兩週紀錄,在 9,805 次 Opus 4.8 assistant turns 裡找到 148 次 parse failure,約 1.5%;同一份紀錄裡,Opus 4.7 與 Sonnet 4.6 是零。

這個 1.5% 是一名使用者的本機樣本,不是 Opus 4.8 的官方失敗率。issue 裡另一名回報者得到約 0.15%,相差十倍;兩人的工作內容、計數方式與使用策略也不完全相同,不能混成一個通用數字。截至 2026-07-27,issue 仍為 open,我沒有看到 Anthropic 在裡面確認根因。

issue 的留言還提供了更具體的失敗樣貌:有人看到雜散的 call token,後面的 <invoke> 又缺少 antml: namespace,導致工具呼叫沒有被正常解析。這是留言者觀察到的案例,能證明這類 parse failure 確實存在,不能證明我的 🦊 就來自同一塊損壞資料。

中文、日文比較容易觸發的說法也只能算回報者的猜測。有人懷疑長的多位元組工具參數提高風險,但 issue 沒有控制變因的實驗,也沒有官方結論。我整天用繁中工作,頂多代表我的使用情境與那些案例有交集,不能寫成「繁中就是觸發條件」。

補這篇文章時,我也遇過一次相似症狀:Edit 顯示成功,檔案實際上沒有變。我用 grep 發現內容根本沒寫進去,換乾淨 session 後才完成。它提醒我一定要驗證工具結果,但仍不足以證明兩次事件共享同一個 bug。

所以我現在對這篇的定案很簡單:狐狸事件是真的,落盤紀錄查不到對應的 user 指令,摘要也確實保存了錯誤敘述。parse bug 是合理嫌疑,但目前仍是嫌疑。

參考資料