問題
Claude(claude-fable-5-1)に日本語の文書を書かせると、「4 つの語は答える問いが異なる」「例外は仕様の内側にある」のような、英語の言い回しをそのまま日本語にしたような文が出ることがあります。
Claude と会話する中で、「thinking(推論)を英語で行い、本文を出すときに日本語へ訳している」ことが原因という仮説が出てきたので、本稿はこの仮説を 2 つに分けて検証します。
- A. thinking ブロックの文字列は英語で書かれているのか
- B. 英語の情報から日本語の文を作る工程はあるのか。あるなら、それはどこで起きているのか
Claude API (サーバーサイド) での出来事の為、完全な証明は難しいです。
多分に推測を含む記事であることをご了承ください🙏
結論
Claude は、thinking の前半で何を書きどう論証するかを英語で決め、後半でその内容を日本語の文にしています。
| 問い | 答え |
|---|---|
| A. thinking ブロックの文字列は英語で書かれているのか | 前半は英語、後半は日本語です。 前半では、何を書きどう論証するかを英語で決めています。 後半では、決まった内容を日本語の本文にして直しています |
| B. 英語の情報から日本語の文を作る工程はどこで起きているのか | 指示によります。 thinking の後半から日本語を生成するケースもあるし、一方 thinking は全て英文で、text 応答生成から日本語のケースもあります |
この 2 点から、冒頭に挙げた不自然な文は次のように説明できます。英語の推論で使った枠組みの語(層、軸、問い)が、日本語の文を作る時点でそのまま日本語に入っています。
根拠は thinking の要約です。推論文の全文は Claude API から返らないため、確認できるのは要約までです。
前提 1: 応答は 1 本のトークン列です
Claude API の応答は thinking ブロックの後に text ブロックが並びます。この形から、次の 2 工程を想像しがちです。
実際は、モデルは 1 回の Claude API 呼び出しの中で、推論から応答の本文まで 1 本のトークン列として続けて生成しています。thinking ブロックと text ブロックは、その列をクライアントに返すときの形式にすぎません。
この形から、2 つのことが言えます。
- thinking の中身に「推論だけ」という制約はありません。モデルは本文そのものを thinking の中で書き、直すことができます。
- text ブロックの本文は、thinking の結果として、その続きに生成されます。
前提 2: 推論結果の要約
Claude API のリクエストで thinking: {type: "adaptive", display: "summarized"} を指定すると、応答の thinking ブロックの thinking フィールドに、Claude API が生成した推論の要約が入ります。推論文の全文は呼び出し元のクライアントには返りませんが、この通り要約は返すことができるため、今回の検証ではこの要約から全文の構成を推測することにしました。
今回の実行 1 回目の応答は次の形でした。
{
"model": "claude-fable-5-1",
"stop_reason": "end_turn",
"content": [
{
"type": "thinking",
"thinking": "I'm outlining the article structure in です・ます調, ... 全体の分量を1500字程度に収めるよう整える。",
"signature": "..."
},
{
"type": "text",
"text": "# 例外と障害を区別して、障害を確実に通知する(骨子)\n\n## 1. 四つの用語は..."
}
],
"usage": {
"output_tokens": 5549,
"output_tokens_details": { "thinking_tokens": 3955 }
}
}
content[0].thinking が要約です。usage.output_tokens_details.thinking_tokens は、モデルが実際に生成した推論のトークン数です。
display |
thinking フィールドの中身 |
|---|---|
"omitted"(既定) |
空文字が入ります |
"summarized"(今回の実験で使用) |
Claude API が生成した推論の要約が入ります |
"updates"(ベータ) |
ツール呼び出し直前の進捗メモだけが入ります。推論の要約は含みません |
検証 1: thinking の要約出力が英文か?
検証1の方法
Claude API を直接呼び、display: "summarized" で、Qiita 記事の骨子を日本語で書く課題を投げました。要約の言語の切り替わりと、要約が指す作業の内容を観察しました。同じ課題を 2 回実行し、要約の構成が 1 回限りでなく再現するかを確かめました。
| 実行 | 課題 | effort | thinking_tokens | 要約の文字数 |
|---|---|---|---|---|
| 1 回目 | 骨子を 1500 字で書く(5 項目) | xhigh | 3,955 | 3,297 |
| 2 回目 | 同上 | xhigh | 6,784 | 4,432 |
根拠: 要約は英語で始まり、途中から日本語になります
2 回とも、要約の冒頭は英語で、途中から日本語に切り替わります。1 回目の要約の抜粋を示します。
I'm outlining the article structure in です・ます調, planning to clarify how each of the four terms originates from a different field — requirements/test design giving us normal/semi-normal/abnormal cases, and programming languages giving us exceptions …
Then I'm designing a two-axis table for the second section, crossing "normal case vs. otherwise" with "code matches spec vs. bug," …
Next I want to note that exceptions are a cross-cutting mechanism, showing up in all four cells …
正常系×仕様通りは定義上サービスが提供できている、それ以外×仕様通りも処置が成功すれば準正常系として提供できている、処置が尽きたときだけ障害になる。だから Sentry の通知判断は例外発生ではなく障害という結果で判断すべきで …
DB接続失敗の例として四つのセルを具体的に示している。正常系×仕様通りはDB稼働中に接続成功、正常系×バグは接続文字列の誤りで失敗 …
長さのバランスや「握りつぶす」のような比喩表現を避けるべきかを確認し、「経路」という表現も含めて言葉選びを見直している。
切り替わる位置は 2 回とも同じです。「何を書き、どう論証するかを決める」部分が英語で、「実際の日本語の文を作り、文字数や語の選び方を点検する」部分が日本語です。要約は推論文の全文ではありませんが、要約の途中で言語が変わる理由は、元の推論文の言語が変わったこと以外に考えにくいため、推論文の全文も同じ構成だと推測します。
要約から読み取れる thinking の構成を、前提 1 の図に重ねると次のようになります。青は英語、橙は日本語で書かれている部分です。
thinking の中で作られた本文が text ブロックに出ていることは、語の一致からも確認できます。2 回目の要約に「握りつぶすを捕捉して無視するに置き換える」とあり、同じ応答の text ブロックに「例外を捕捉して無視し null を返す」と出ています。
検証 2: claude.ai の Claude Opus 5 に自己申告させる
検証 1 は Claude API 経由の claude-fable-5-1 を、要約越しに観測したものでした。検証 2 では条件を変え、claude.ai のチャット上の Claude Opus 5 に、自身の thinking が何語で書かれているかを直接申告させました。
根拠の強さは検証 1 に劣ります。モデルの自己申告しかないためです。本人が thinking を参照して答えたのか、それらしい文を生成しただけなのかは、モデル自身にも区別できません。ただし、申告の対象が要約ではなく thinking のテキストそのものである点は検証 1 と違うため、対照として記録します。
方法
claude.ai の通常のチャットで、日本語だけで質問を重ねました。各ターンの末尾で、直前の thinking ブロックが何語で書かれていたかを Claude 自身に報告させています。Claude Opus 5 は claude.ai 上で thinking を無効にできないため、全ターンで thinking が有効です。effort は既定値のままにしました。
モデルは、自分が生成し終えた thinking ブロックを、同じターンの本文を書く時点ではコンテキスト上に参照できます。一方、前のターンの thinking はコンテキストから除かれており、後から見直すことはできません。そのため各ターンの申告は、そのターン限りの観測です。
結果
| 問い | 答え |
|---|---|
| thinking は何語で書かれていたか | 全ターンで英語でした。途中で日本語に切り替わることはありませんでした |
| 言語が切り替わる位置はどこか | thinking ブロックの終端です。text ブロックの 1 文字目から日本語になっていました |
| thinking の中に日本語の下書きはあったか | ありませんでした。thinking の中身は、質問の意図の整理、何を書くかの方針、事実の確認でした |
検証 1 では thinking の後半が日本語になりましたが、検証 2 では最後まで英語のままでした。
差が出た理由の推測
課題の性質が違います。検証 1 は日本語で 1500 字の骨子を書く課題で、字数の配分や語の選び直しといった、日本語の文を作って直す作業が必要でした。thinking_tokens も 3,955 と 6,784 で、その作業にあてられる分量があります。
検証 2 の各ターンは数百字の応答で、その作業がほとんど発生していません。effort も既定値で、検証 1 の xhigh より低い設定です。
この対比からは、thinking に日本語が現れるかどうかは、モデルや環境の固定的な性質というより、日本語の文を作って直す工程が発生するかどうかに依存している、と読めます。ただし検証 2 の根拠は自己申告のみのため、差があること自体を確定はできません。
なお、検証 2 の環境である claude.ai のシステムプロンプトは全文が英語で、数万語の規模でした。検証 1 の「確認できないこと」に挙げた、長い英語のシステムプロンプトを前提に置く環境という条件に当てはまります。
確認できないこと
- 推論文の全文は確認できません。claude-fable-5-1 はどの設定でも全文を返しません。
- 英語と日本語の比率が環境でどう変わるかは確認できません。今回の実験は短いプロンプト 1 つで行いました。長い英語のシステムプロンプトやツール定義を前提に置く環境(コーディングエージェントなど)では、推論が英語に寄ると考えられますが、測っていません。