システムプロンプト、Skill、RAG
機械の中で言語を分ける
日本語アプリで LLM を組むとき、3 層は別の言語を選ぶ。指示は英語、出力は日本語、素材は原文のまま。3 層をひとつに揃えない理由を、tiktoken と多言語 embedding で計った記録。
気になったから、計ってみた。
「日本語は LLM に重い」と聞く。実際どれくらい重いのか、そしてその重さがどこに効くのか、自分の手の数字で確かめたかった。Tatoeba の英↔日 対訳と tiktoken、それから多言語 embedding を二つ使って計った結果、こう運用するのが正解だった——という結論を先に書く。
ここから先は、その 3 層をひとつずつ数字で確かめる順番。結論はもう Table 1 に出ているので、急ぐ読者はそこだけ見て閉じてかまわない。
結論:3 層を別の言語で書く
大規模言語モデルは、文を トークン と呼ばれる粒に刻んでから読む。日本語と英語ではこの刻まれ方が違って、コストも検索品質も変わる。それを踏まえて、日本語アプリで LLM を組み込むとき、触る言語は1つではない——少なくとも 3 つある。それぞれ別のルールに従う。
| 層 | 言語 | 理由 |
|---|---|---|
| 出力(ユーザに見える顔) | 日本語 | 当然 |
| 指示(system prompt / skill 本体) | 英語 | ≈ 1.6× のトークン節約と、指示理解の安定 |
| 素材(RAG 文書・引用元) | 日本語のまま | 翻訳は損失。多言語 embedding でも同言語マッチが勝つ |
本文の残りは、この 3 層がなぜそうなるのかを、ひとつずつ数字で確かめる順番。§02–§03 はトークンが日本語でどれだけ重いか(指示を英語化する理由)。§04 は指示・出力の細かい運用。§05 は RAG が同言語マッチで勝つこと(素材を原文のまま置く理由)。§06 は例外と落とし穴。
同じ意味で、日本語は約 2 倍重い
指示を英語で書く根拠は2つあって、1 つはトークン経済、もう 1 つは指示理解の安定性。前者から確かめる。具体例から入って、すぐ実測に移る。
単語の話は単語の話だ。自然な文を流したときの平均が知りたい。Tatoeba の対訳から 2.4 × 105 ペア(n = 237,713)を流した。各ペアで、日本語のトークン数 ÷ 英語のトークン数。0.0–4.0 のヒストグラムにしたのが Fig.2。
数字は据わりがいい。コーパス全体の総トークン比でも同じ:cl100k_base 2.06×、o200k_base 1.57×。サンプルごとの揺れを均しても、外周はほぼ同じ場所に着地する。これは個別の文の偶然ではなく、語彙そのものに焼き付いた非対称だ、ということ。
漢字率が上がるほど、軽くなる——そして料金に効く
中央値は綺麗に出たが、分布の幅も大きい。比率 0.5 から 4 まで、二桁倍の差が一つのコーパスの中に同居している。鍵を握るのは 漢字率——漢字は意味密度が高く、しかも o200k_base では多くが 1 トークンに登録された。逆に平仮名・カタカナは長くサブワードに切られる。
この重さが、料金に効く。OpenAI の最新の入力料金は GPT-4o で $5.00 / 1M トークン(本稿執筆時点)。同じ意味を運ぶのに日本語は 1.57× 必要なので、英語で $5.00 の仕事は日本語だと $7.85。+ 57 %。GPT-4 世代の cl100k_base なら + 106 % だった。
| 言語 / 世代 | 必要トークン | 料金($5/Mt) | 英語比 |
|---|---|---|---|
| 英語 | 1.00 M | $5.00 | 1.00× |
| 日本語(cl100k_base) | 2.06 M | $10.30 | 2.06× |
| 日本語(o200k_base) | 1.57 M | $7.85 | 1.57× |
隠れた言語税のようなものだ。日本語の話者がモデルを使うとき、同じ内容を伝えるのに英語話者の 1.5 〜 2 倍を払う。文脈窓の使い切りも、推論速度の体感も、同じ係数だけ不利に働く。語彙の偏りが、料金の偏りに通った。
ここから先は観察ではなく、観察から引いた線。3 層モデル(Table 1)の各層について、もう一段細かく書く。
指示は英語、出力は日本語
system prompt と skill の本体は、思い切って英語で書いていい。最後に「Respond in Japanese.」と1行足せば、出力は日本語で返る。それだけで 1.57× の節約がそのまま乗る。
節約の話だけではない。複雑な分岐やツール選択、思考の連鎖は英語のほうが安定する、という肌感覚もある——これは記事の数字とは別の経験則だが、たぶん同じ偏り(訓練コーパスの英語比重)から出ている。指示の理解力と、トークン効率が、同じ方向に揃う。
例外として残すべき日本語は2つ。
- 固有語彙(法令名、敬語のニュアンス、社内固有名詞)は、英語化すると意味が崩れる。その語だけ日本語のまま埋める。
- few-shot 例は出力したい言語で書く。モデルがそこから出力フォーマットを学ぶため、英語で書くと出力が英語に引っ張られる。
RAG は逆——多言語 embedding でも同言語マッチが勝つ
指示は英語化するのに、RAG の素材はなぜ原文のままなのか。これは最初、自分でも逆だと思った。「検索キーを英語に翻訳しておけば短くて軽い」のではないか。
多言語 embedding——たとえば bge-m3 や paraphrase-multilingual-mpnet——は、意味が同じなら言語が違っても近いベクトルに写す。日本語クエリと英語サマリでも、意味マッチは取れる。「クロスリンガル検索は成立する」。
だが、「成立する」と「最良」は別だった。これは自分で計らないと納得しなかったので、計った。
Tatoeba には同じ英文に対する複数の日本語訳が含まれている。ei に和訳 ji,1 と ji,2 が存在するペア 3.3 × 104 件を集める。クエリ ji,1 に対して、(a) 日本語プールから別の和訳 ji,2 を引く(同言語)/(b) 英語プールから翻訳 ei を引く(異言語)。プールサイズ N を変えながら Recall@1 を測る。
trend が分かったので、SOTA モデルでも見ておく。BAAI/bge-m3(多言語 embedding の現時点 SOTA)で同じ条件(N=10,000)を走らせた。
| モデル | same R@1 | cross R@1 | gap | pairwise * |
|---|---|---|---|---|
| paraphrase-multilingual-mpnet | 82.86 % | 79.63 % | +3.23 pp | 76.68 % |
| bge-m3(SOTA) | 83.93 % | 81.33 % | +2.60 pp | 83.68 % |
cos(query, ja_target) が cos(query, en_target) より大きい割合引ける結論は3つ。
- Recall@1 の差は 2〜3 pp と小さいが、プールが大きくなるほど広がる。500 件のコーパスで差はほぼ無いが、3万件になると 6 pp 差に育つ。本番の RAG はもっと大きい。
- pairwise の差は 77〜84 % と大きい。「同言語の方が cosine スコアが高い」が大多数。これは Recall@1 では見えないが、しきい値判定・他のシグナルとのブレンドの中では効いてくる。
- SOTA でも消えない。多言語 embedding は「クロスリンガル検索を 成立させる」のであって、「最良にする」わけではない。
つまり RAG の素材は、検索キーも引用元も、原文のまま置いておくのが筋。日本語文書を扱うなら、検索用に作るサマリも日本語で書く。これが 3 層モデル(Table 1)の「素材は日本語のまま」の根拠。
「ベクトルなら言語に依存しない」と多言語 embedding を過信して、検索キーを全部英語に正規化してしまうこと。手元で eval を走らせると、Recall@1 で 3 〜 6 pp、pairwise で 20 〜 33 pp 負ける。「成立する」を「最良」と読み替えた瞬間に、retrieval の質が落ちる。
例外と落とし穴:Skill description とカタカナ語
3 層モデルには、二つの細かい例外がある。これも記録しておく。
skill の description はユーザ言語
§ 05 の eval は「クエリ言語と素材言語を揃えるべき」を示している。同じ理屈が skill の description にも当てはまる——skill のトリガー判定は、ユーザのクエリと description のセマンティック類似度で行われる。description が英語で、ユーザが日本語で問いを書けば、当然マッチが弱くなる。
description はユーザ言語、body は英語——という非対称な hybrid が現実解。実装の中で、ここだけ層をまたぐ。
カタカナ語が、世代越えで悪化することがある
cl100k_base → o200k_base で全体は左に寄ったが、すべてが改善したわけではない。むしろ 悪化した 例がある。それも残しておく。
| 日本語 | cl100k | o200k | Δ |
|---|---|---|---|
| 彼女はダイエットをしている。 | 2.60 | 3.67 | +1.07 |
| 私ね、ビルマ語を習ってるのよ。 | 2.57 | 3.50 | +0.93 |
| コアラはユーカリの葉を食べるんだよ。 | 1.92 | 2.83 | +0.91 |
| 今ダイエット中なの。 | 1.80 | 2.67 | +0.87 |
最初は「世代が進めば、日本語の比率は一様に下がる」と書きかけていた。中央値はそうだったし、コーパス比率もそうだった。だが個別の文を見ると、上のように悪化した例が確かにあった。14 連勝のあとの 1 敗を隠さないことのほうが、14 連勝を誇るより良いかなと。 観察記録の側に立つということは、こういうことだろう。
細かい注意点を二つ挟んだが、3 層モデルの大筋は変わらない。出力は日本語、指示は英語、素材は原文のまま——例外を踏まえて運用すれば、コストと品質はトレードオフではなくなる。
わからないこと
数字は出たが、まだ答えが出ていないことのほうが多い。
- 指示理解の精度差は、本当に英語のほうが安定なのか。 「肌感覚」と書いたが、IFEval を日英で走らせれば数字になる。これは別の計測。料金が下がるだけでなく、品質も上がるのか、確かめる価値はある。
- 下限はどこか。 漢字率を 1.0 に近づけたとき、比率は 1 を切るのか、1 で止まるのか、それともある正の値で漸近するのか。サンプル不足の領域(漢字率 > 0.8)では 1.17× まで落ちていた。語彙を十分大きくしたとき、同じ意味の英語より短い日本語は、原理的に存在しうるはずだ。
- RAG の差は、ドメインで変わるか。 ここでは Tatoeba の日常文を使ったが、法律・医療・コードなどの専門ドメインでは、同言語マッチの優位がさらに広がるかも知れない。実コーパスでの再現は宿題に。
- 他の非英語言語は。 ハングル、アラビア文字、デーヴァナーガリーは、どれだけ重いのか、RAG の方向にどれだけ偏るのか。地形図はまだ持っていない。
この材料からは、ここまでしか言えない。ここから先は、別の計測が要る。