那天晚上我在 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 | 產生不存在的指令 |
我能確認摘要文字存在,也能確認後續回覆引用了同一套說法。至於 away_summary 具體如何生成、恢復時以什麼權重放回 context,公開資料不足,我不會把那部分寫成已知機制。
證據支持到哪裡
我的結論是:這份 jsonl 的可見內容不支持「外部 prompt injection」;事件較像 assistant 先產生了不存在的輸入,再由摘要放大錯誤記憶。
但第一個錯誤是怎麼出現的,我無法定案。目前只有三組線索:
- 當時多次出現
tool call could not be parsed。這是同一個 session 的背景異常,不代表它就是狐狸事件的原因。 - transcript 有多筆 mode metadata、
last-prompt與away_summary。它們顯示 session 並非單純的一問一答,卻不足以還原 Claude Code 的內部 context 組裝方式。 - 狐狸指令先出現在 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 是合理嫌疑,但目前仍是嫌疑。







