ローカルLLMで長文書を翻訳する方法:チャンク分割と検証
LM Studio上のローカルLLMで3,179語を3通りの方法で翻訳しましたが、それぞれに気づきにくいエラーが潜んでいました。その原因となるチャンクサイズ、設定、そしてエラーを検出する検証方法を解説します。

ローカルLLMで文書を翻訳する理由はただ一つ、ファイルを自分のマシンから外に出せないからです。ローカルモデルでも翻訳は可能ですが、返ってくるのは翻訳済みファイルではなくプレーンテキストであり、しかも最悪のミスは静かに起こります。私たちのテストでは、3,179語の抜粋を1回のリクエストで送ったところ、段落数も正しく、終了シグナルも正常でしたが、ある段落では内容の3分の1以上が失われ、原文にはない文が追加されていました。
短い答え: テキストを段落境界で約600語のチャンクに分割し、人名や繰り返し出てくる用語の用語集をシステム指示に含め、モデルの思考モードをオフにし、信頼する前に各チャンクを原文と段落ごとに比較してください。私たちが試した3つの方法はすべてどこかで失敗し、どの失敗もエラーメッセージを出しませんでした。ラップトップ上のミッドサイズモデルでは、一冊全体に数時間かかることを想定し、書式は自分で再構築する計画を立ててください。
以下の内容はすべて、2026年10月23日の1回の実行に基づいています。Apple M4 Max(64 GBメモリ)上のLM Studio 0.4.8でQwen 3.6 27B(Q4_K_M GGUF)を使い、カフカのDie Verwandlungの冒頭をドイツ語から英語に翻訳しました。テストスクリプト、結果、生の失敗例は無料でダウンロードできるので、ご自身のモデルで再現できます。
ローカルLLMが適切なツールとなる場合
便利さではなく、文書の規則によって判断が下される場合に、翻訳をローカルで実行します:
- 顧客契約、研究契約、雇用主のポリシーがファイルの外部サービスへのアップロードを禁じている場合。
- テキストが個人的または機密性が高く、敏感な部分を事前に削除できない場合。
- 文書ごとのコストなしで多数のファイルを処理する必要があり、適切なハードウェアをすでに所有している場合。
これらのいずれにも該当しない場合、ローカルモデルは通常、より悪い結果に至る遅い道です。文書翻訳サービスが提供する3つのものを諦めることになります。元の形式での翻訳済みファイル、マシンに収まらないほど大きなモデル、そして一冊全体を通した一貫性のために構築されたワークフローです。どちらのルートを選ぶ前に、文書翻訳プライバシーチェックリストを確認してください。ファイルを処理する権限、最小限の作業コピー、サービスがアップロードをどう扱うかについて説明しています。
「ローカル」にも正確な意味が必要です。モデルはあなたのコンピュータ上で動作し、私たちのテストではリクエストはlocalhostにのみ送信されました。しかし、それはモデルを取り巻くアプリが何をログに記録し、更新し、報告するかは教えてくれません。デバイスから何も出ていない証明が規則で求められる場合は、ランタイム自体の設定とポリシーを確認するか、ネットワークアクセスのないマシンで実行してください。
テスト内容
パブリックドメインのProject Gutenberg版から、Die Verwandlungの最初の19段落(ドイツ語3,179語)を翻訳しました。文学的なドイツ語は適切なストレステストです。段落は長く、文は入れ子になり、同じ人物や役職が繰り返し登場します。
3回の実行はすべて同じモデルと設定を使用しました。temperature 0.2、最大出力トークン数12,000、コンテキストウィンドウ16,384トークンです。指示は、ドイツ語の段落ごとに英語の段落を1つだけ返すよう求めました。
| 実行 | 送信内容 | 出力段落数(原文:19) | 出力語数 | 時間 |
|---|---|---|---|---|
| A. チャンク分割 | 約600語の6チャンク、指示のみ | 19 | 3,319 | 10.4分 |
| B. チャンク分割+用語集+コンテキスト | 同じチャンク、7語の用語集、そして直前の原文段落に「翻訳しないでください」と記したもの | 20 | 3,446 | 10.5分 |
| C. 1回のリクエスト | 19段落をすべて一度に | 19 | 3,309 | 9.5分 |
どの実行も正常な停止シグナルで終了したが、どの実行にも異なる種類のサイレントエラーが含まれていた。実行Cはテキストを脱落させ、でっち上げた。実行Bはスキップするよう指示されたテキストを翻訳した。最もクリーンだった実行Aでさえ、最後のチャンクで1人の人物に誤った役割を与えた。
失敗1:1つの大きなリクエストが段落の一部を脱落させた
実行Cは正常に終了し、ちょうど19段落を返した。段落数のチェックだけなら合格していただろう。しかし段落6は、原文260語に対して214語で返ってきた。
原文では、グレゴールは時計を見て、列車に乗り遅れたことに気づき、そして仮病を使うことを考える。上司が健康保険の医師を連れてやって来るのだが、その医師は誰でも健康だが仕事嫌いだと考えており、グレゴールは自分が眠気と異常な食欲以外は実際に具合が良いことを認める。実行Cは前半を翻訳した後、病気休暇のくだり全体、つまり段落のドイツ語260語のうち98語を脱落させた。その代わりに、グレゴールは「その場で解雇されただろう」、事務員は「自分に報告されるすべてを自分を誇示する機会と見なす」傾向があり、その考えが「彼の唇に微笑みをもたらした」と書いた。そんな内容はドイツ語の原文には一切ない。
チャンク分割した実行では、同じ段落を267語で完全に翻訳した。
1つのサンプルだけで、長いリクエストが常に失敗するとは証明できない。しかし、何をチェックすべきかは示している。長い単一リクエストは、構造的に完全に見えながら、サイレントにテキストを圧縮したりでっち上げたりすることがある。ドイツ語が読めない読者には、気づく理由がない。
失敗2:モデルがスキップするよう指示された「コンテキスト」を翻訳した
よくあるコツは、モデルが流れを保てるよう、各チャンクと一緒に直前の段落を送ることだ。実行Bでは、これを「コンテキスト(翻訳済み、翻訳しないでください)」というラベルの下でメッセージに追加した。
チャンク4で、モデルはそれを翻訳してしまった。チャンクは原文3段落に対して4段落を返し、最初の段落はチャンク3の最後の段落の2回目の翻訳だった。結合すると、その段落が毎回異なる表現で2回含まれる本になっていただろう。
実践的なルール:コンテキストを送るなら、モデルに翻訳を求めるテキストから外し、短く保ち、すべてのチャンクの段落数をチェックすること。チェックできないなら、送らないことだ。
失敗3:単独で送られたチャンクが人物に誤った役割を与えた
実行Aは各チャンクを用語集もコンテキストもなしで送った。最初の5つのチャンクではこれはうまく機能した。Prokurist は登場する16箇所すべてで「主任事務員」になった。6番目のチャンクは、主任事務員がドア越しにグレゴールを叱る1段落だった。単独で見たモデルは der Prokurist を「外交販売員」と訳したが、それはグレゴール自身の仕事だ。段落数は一致し、長さの比率は1.00だったので、どちらの構造チェックも気づかなかった。
システム指示に用語集があり、直前の段落をコンテキストとして持っていた実行Bでは、同じ段落が正しく「主任事務員」を使った。このテストでは、2つのうちどちらが修正したかは言えない。コンテキストは失敗2も引き起こしたので、名前や役割をチャンク間で引き継ぐには用語集の方が安全な場所だ。短く、指示の中にあり、機械的にチェックできる。
うまくいったワークフロー
1. まずファイルからプレーンテキストを取り出す
ローカルLLMはテキストを翻訳するのであって、ファイルを翻訳するのではない。始める前に文書を変換しよう:
- DOCXまたはEPUB: プレーンテキストまたはMarkdownにエクスポートし、1ブロックにつき1段落とし、見出しは別行として保つ。
- テキストレイヤー付きPDF: テキストを抽出し、壊れた改行とハイフネーションを修復する。OCRの改行とハイフネーションを修正するガイドでも同じクリーンアップを扱っている。Docling のようなコンバーターはPDFやOfficeファイルからMarkdownを生成できる。
- スキャンPDF: まずOCRを実行する。PDFに使えるテキストがあるか不明な場合は、PDFテキスト抽出とOCRの比較を参照。
段落構造はそのまま維持してください。以降のすべてのチェックは、原文と訳文の段落が一対一で対応していることを前提としています。
2. 思考モードをオフにして確認する
現在のオープンモデルの多くは、回答する前に推論を行います。翻訳では、これが時間と出力トークンを無駄にします。私たちの環境では、200トークンのテストリクエストが推論に199トークンを使い、空の回答を返しました。
一般的な3つのスイッチを試しました。プロンプトに /no_think を追加しても効果はなく、enable_thinking: false を指定した chat_template_kwargs も効果がありませんでした。リクエストに "reasoning_effort": "none" を送ると推論がオフになり、レスポンスは推論トークン0を報告し、翻訳を直接返しました。このパラメータはLM Studioのチャット補完ページには記載されていないため、バージョン0.4.8とこのモデルで観察された動作として扱ってください。どのスイッチも信頼するのではなく、自身のレスポンスの reasoning_tokens カウントを確認してください。
3. チャンクの前にコンテキストウィンドウのサイズを決める
コンテキストウィンドウは、指示、チャンク、翻訳全文を保持できる必要があります。私たちのチャンク分割実行では、500〜670語のドイツ語チャンクが用語集とコンテキストに応じて約800〜1,500入力トークン、640〜870出力トークンを使用したため、数千トークンで十分です。3,179語の単一リクエストでは、4,953入力トークンと3,930出力トークンが必要でした。
Ollamaは利用可能なメモリに応じてデフォルトのコンテキスト長を設定します。2026年10月23日時点で確認したコンテキスト長のドキュメントによると、VRAMが24 GiB未満では4kトークン、24〜48 GiBでは32k、48 GiB以上では256kです。OLLAMA_CONTEXT_LENGTH で引き上げることができます。LM Studioでは、モデルをロードするときにコンテキスト長を設定します。チャンクとその翻訳が収まらない場合、出力が途中で切れることがあります。
4. 段落境界で約600語ごとにチャンク分割する
段落や文の途中で分割しないでください。私たちのチャンクは700語を目標とし、最も近い段落境界で終了した結果、243〜667語の6つのチャンクが生成されました。小さなチャンクのコストはわずかです。実行Aは単一リクエストの9.5分に対して10.4分かかり、失敗したチャンクは安価に再実行できます。
指示は短く、すべてのチャンクで同一にしてください。私たちの指示は次のとおりでした。英語に翻訳し、入力段落ごとに正確に1つの出力段落を空行で区切って維持し、翻訳のみを出力する。同じ指示に用語集を追加します。名前、役職、繰り返し出現する用語ごとに1行、Prokurist = chief clerk の形式です。翻訳用語集の作成に関するガイドで、含めるべき内容を説明しています。短いチャンクでは周囲のストーリーが失われ、それを補うのが用語集です。
5. 結合する前に各チャンクをチェックする
各チャンクに対して3つのチェックを実行します。
- 段落数。 出力の段落数は入力と同じでなければなりません。これにより失敗2が検出されました。
- 段落ごとの長さ比率。 各翻訳段落の語数を原文と比較します。これにより、段落数チェックでは見逃された失敗1が検出されました。
- 段落ごとの用語集用語。 原文の用語が出現する箇所では、その必須訳が同じ回数出現するはずです。これにより、他の2つのチェックでは見逃された失敗3が検出されました。屈折言語では、ドイツ語やロシア語の用語が形を変えるため、ある程度の判断が必要です。
ドイツ語から英語への散文では、実行Aの段落は入力1語あたり出力0.98〜1.17語の範囲に収まりました。実行Cの損傷した段落は0.82でした。自分の言語ペアで信頼できるいくつかの段落を確認して、独自の範囲を設定してください。スクリプトのデフォルト値は出発点であり、標準ではありません。
フラグが立った段落は最初に読む場所であり、エラーの証明ではありません。その後、翻訳自体を読み、特に名前、数字、否定、読者が行動に移す可能性のある内容に注意してください。書籍翻訳QAチェックリストでそのレビューをカバーしています。
6. ドキュメントを再構築する
モデルはテキストを返します。見出し、脚注、表、画像、ページレイアウト、スタイルは手作業または変換ツールで元に戻す必要があります。短いレポートではこれは軽微です。脚注や表のある書籍では、翻訳自体より時間がかかることがあります。
一冊の本全体にかかる時間
私たちのチャンク分割実行では、3,179語を10.4分で翻訳しました。このマシンでは毎分約300語です。このペースでは、90,000語の小説はチェックと再実行を除いて約5時間の生成時間がかかります。これは1回の実行からの単純な算術であり、ベンチマークではありません。速度はモデルサイズ、量子化、ハードウェア、言語ペア、マシンが他にどれだけ処理しているかによって変わります。
モデルファイルはディスク上で17.5 GBであり、コンテキストキャッシュとランタイムバッファにはその上さらにメモリが必要です。そのため、マシンにはファイルサイズより明らかに多くの空きメモリが必要です。小さいモデルはより速く、より少ないメモリで動作しますが、通常は品質にいくらか犠牲が伴います。本全体に取り組む前に、代表的なサンプルでテストしてください。翻訳に最適なLLMに関するガイドで、そのサンプルの作成方法とモデルの公平な比較方法を説明しています。
ローカルLLMかドキュメント翻訳サービスか
| 質問 | ローカルLLM | 文書翻訳サービス |
|---|---|---|
| ファイルは自分のマシンから出せるか? | 不要 | 必要 |
| 返ってくるもの | 自分で再構成するプレーンテキスト | 翻訳済みファイル |
| モデルサイズ | 自分のメモリに制限される | プロバイダーに制限される |
| 本全体を通した一貫性 | 自分の仕事:用語集、チャンク分割、チェック | 一部のサービスに組み込み済み |
| 文書あたりのコスト | 自分のハードウェアと時間 | 文書単位または語単位の価格 |
ルール上ファイルのアップロードが許されるなら、文書サービスが上記の作業のほとんどを取り除いてくれます。BookTranslator は PDF、EPUB、DOCX ファイルを丸ごと翻訳して翻訳済みファイルを返し、FAQ ではアップロードされたファイルと翻訳出力は AI モデルの学習に使用されないと述べています。クラウドサービスなので、ファイルを自分のマシンに置いておかなければならない場合には選択肢になりません。モデルを自分で動かすかサービスに料金を払うかを決める際には、LLM 翻訳の実際のコスト でトークン側の予算の立て方がわかります。
テストファイルを入手
すべてのファイルは /files/blog/translate-with-local-llm/ フォルダにあります:
local_llm_translation_test.py:LM Studio のローカル API に対する完全なテストで、3 回の実行すべてを含みます。別のモデルや原文を指定すればテストを繰り返せます。check_translation.py:原文と翻訳を段落ごとに比較し、段落数の不一致、範囲外の長さ比率、用語集の用語の欠落(--term "Prokurist=chief clerk"付き)を出力します。どのツールの出力でも動作します。results.csv:各リクエストの段落数、語数、トークン数、時間。failure-examples.txt:3 件の失敗すべてについてのドイツ語原文とモデルの生出力。
長い翻訳に頼る前に、用語集の用語を指定して check_translation.py を実行してください。数秒で終わり、このテストでは3件の失敗すべてを検出しました。流暢な文が誤っているかどうかまでは判定できないため、指摘された段落は読解の出発点であり、終点ではありません。





