英語論文をMarkdownにして翻訳して読んでいる話のアップデートとして、TranslateGemmaによる翻訳を試してみた。いろいろつまづいたので笑 その記録を残した方がいいかと思い、今回はLM Studioで動かすまでを紹介する。
冷静に考えると、APIで利用したり、Ollamaなどを使うとそもそもこういう詰まり方をしないかもしれないので、LM Studioを使ったことがそもそも問題だったのかも。。とはいえ、自分の勉強にはなったのでよかった。
はじめに
TranslateGemmaはGoogleが公開している翻訳向けのモデルで、調べる限り 4B、12B、27Bのモデルが用意されている。2026年の1月公開だが、9月現在も特に変わってはいない。タイミング的にGemma 3をベースに翻訳特化に改良したモデルという位置付けのはず。
今回はMacBook Air M2、メモリ16GBの環境で試すため、12Bの4bit量子化されたMLXモデルを使うことにした。モデルはHugging FaceにあるバージョンをLM Studioからダウンロードし導入した。ライセンスについてはGemma Terms of Useが適用される。この点は最新のGemma 4の方が扱いやすいかも。
実行環境
今回の環境は以下。
- MacBook Air
- チップ: M2
- メモリ: 16GB
- macOS: 26.6.2
- LM Studio: 0.4.23+1
- 2026年9月現在、特にLM Studio自体を商用的に使うこと自体はCommercial Licenseを必要としない規約に変更はないようだ。
- モデル:
mlx-community/translategemma-12b-it-4bit
LM StudioでTranslateGemmaを動かす
そのまま試してみる
まずはLM Studioでモデルをロードして、普通にチャットUIから英文を入力してみた。
今回も以前と同じ文章を使うことにして。Ollamaのガイドなどにもあるが、プロンプトの最初に指示を入れ、
日本語への翻訳指示 I tried to cook pasta yesterday, but I accidentally made enough for ten people.
以前の翻訳でも使った文章で、まあ「パスタを10人分も作ってしまった」くらいになれば良さそう。しかし…

TranslateGemmaではこの英文をそのまま入力しても返答がなかった。
Prompt Templateを変更する
LM Studioのモデル設定を見ると、Prompt Templateという項目がある。表示されていない場合、空きスペースで右クリックし、表示させる。
TranslateGemmaではここのJinjaのタブにかなり長いテンプレートが設定されている。あとで細かい話は後で確認するとして、LM Studioの通常のチャットUIから使う場合、このテンプレートが利用されるが、エラーが出る原因はここになる。
そこで、今回は英語と日本語の翻訳に固定して、通常のチャットUIから使えるようにPrompt Templateを変更した。
英語から日本語の場合は以下。
{{ bos_token }}
{%- for message in messages %}
{%- if message['role'] == 'user' %}
{{ '<start_of_turn>user\n' }}
{{ 'You are a professional English (en) to Japanese (ja) translator. Your goal is to accurately convey the meaning and nuances of the original English text while adhering to Japanese grammar, vocabulary, and cultural sensitivities.\n' }}
{{ 'Produce only the Japanese translation, without any additional explanations or commentary. Please translate the following English text into Japanese:\n\n\n' }}
{{ message['content'] | trim }}
{{ '<end_of_turn>\n' }}
{%- elif message['role'] == 'assistant' %}
{{ '<start_of_turn>model\n' }}
{{ message['content'] | trim }}
{{ '<end_of_turn>\n' }}
{%- endif %}
{%- endfor %}
{%- if add_generation_prompt %}
{{ '<start_of_turn>model\n' }}
{%- endif %}
Prompt Templateに貼り付けて保存した後、先ほどと同じ英文を入力すると、今度は日本語で返答されるはず。

日本語から英語へ翻訳したい場合は、以下のように逆向きのテンプレートにすればよい。
{{ bos_token }}
{%- for message in messages %}
{%- if message['role'] == 'user' %}
{{ '<start_of_turn>user\n' }}
{{ 'You are a professional Japanese (ja) to English (en) translator. Your goal is to accurately convey the meaning and nuances of the original Japanese text while adhering to English grammar, vocabulary, and cultural sensitivities.\n' }}
{{ 'Produce only the English translation, without any additional explanations or commentary. Please translate the following Japanese text into English:\n\n\n' }}
{{ message['content'] | trim }}
{{ '<end_of_turn>\n' }}
{%- elif message['role'] == 'assistant' %}
{{ '<start_of_turn>model\n' }}
{{ message['content'] | trim }}
{{ '<end_of_turn>\n' }}
{%- endif %}
{%- endfor %}
{%- if add_generation_prompt %}
{{ '<start_of_turn>model\n' }}
{%- endif %}
なお、変更したPrompt Templateはゴミ箱のボタンから削除し、デフォルトに戻せるので安心してください。まあ、デフォルトのままでは動かないのだが…設定を保存もできるので、もしLM StudioのチャットUIで翻訳をする場合、保存してもいいかもしれない。
あまり翻訳的には本質ではないが、今回はこのテンプレートの箇所を少し深掘りした結果を以下で紹介しようと思う。LM Studioで動かさない場合はどうでもいいところかもしれないので、必要な方向けが以下となる。
Prompt Templateとは
ここからはLM StudioのPrompt Templateを少し深掘り、動かなかった理由や、どう書けば動くのかを確認した結果を紹介する。
標準的な例
LM StudioのチャットUIに入力した文章は、たとえば
こんにちは
と入力した場合、内部的にはたとえば以下のようなメッセージになるようだ。だいぶシンプル版だが。
<start_of_turn>user こんにちは <end_of_turn> <start_of_turn>model
Prompt Templateは、チャットUIに入力した内容や、設定を変数的に入れ替えて変換するためのものだ。今回勉強したが、その際にJinja形式を使うのがLM Studioの標準機能として提供されている。先ほどの例はGemma 3の場合を超シンプル化したものにはなるが、当然モデルによって構造は異なると思ってほしい。Prompt Templateではroleやcontentを取り出しながら、この文字列を作っている。 role は設定のトグルにあったり、 content はチャットUIの中の文字列。
さも知っていたかのように書いているが、そういうわけではなく、今回Gemma 3などもベースに勉強してみたというところ。Jinja自体も、Flaskなどを触ってこなかったこともあり、今回はじめて勉強した。
たとえば、Gemma 3のPrompt Template(の正式版)は上記のようにチャットUIに書かれた内容を素直にというかそのままモデルに投げようとするので、もともと考えていた
日本語への翻訳指示 I tried to cook pasta yesterday, but I accidentally made enough for ten people.
こちらを入力してあげれば、そのまま
「昨日、パスタを作ろうとしたんだけど、うっかり10人分くらい作っちゃった。」 あるいは、もう少しカジュアルに: 「昨日、パスタを作ろうとしたんだけど、すごい量作っちゃった。10人分くらいかな。」 どちらの表現も「I tried to cook pasta yesterday, but I accidentally made enough for ten people」の意味を十分に伝えています。
こんな感じで翻訳をしてくれる。プロンプトをもっとちゃんとしてやれば、翻訳文のみを返答してくれるはずだ。
TranslateGemmaの場合
TranslateGemma、まあ今回 Hugging Face のMLX Communityからダウンロードしてきたモデルに標準で設定されているPrompt Templateを見る以下のような形式だった。
{%- set languages = { "aa": "Afar", ... "en": "English", ... "ja": "Japanese", "ja-JP": "Japanese", ... } -%} {{ bos_token }} {%- if (messages[0]['role'] != 'user') -%} {{ raise_exception("Conversations must start with a user prompt.") }} {%- endif -%} {%- for message in messages -%} {%- if (message['role'] == 'user') != (loop.index0 % 2 == 0) -%} {{ raise_exception("Conversation roles must alternate user/assistant/user/assistant/...") }} {%- endif -%} {%- if (message['role'] == 'assistant') -%} {%- if message['content'] is none or message['content'] is not string -%} {{ raise_exception("Assistant role must provide content as a string") }} {%- endif -%} {{ '<start_of_turn>model\n'}} {{ message["content"] | trim }} {%- elif (message['role'] == 'user') -%} {%- if message['content'] is none or message['content'] is not iterable or message['content'] | length != 1 -%} {{ raise_exception( "User role must provide `content` as an iterable with exactly one item. That item must be a " + "`mapping(type:'text' | 'image', source_lang_code:string, target_lang_code:string, " + "text:string | none, image:string | none)`." ) }} {%- endif -%} {%- set content = message["content"][0] -%} {%- set source_lang_code = content["source_lang_code"] | replace("_", "-") -%} {%- set source_lang = languages[source_lang_code] -%} {%- set target_lang_code = content["target_lang_code"] | replace("_", "-") -%} {%- set target_lang = languages[target_lang_code] -%} {{ '<start_of_turn>user\nYou are a professional ' + source_lang + ' (' + source_lang_code + ') to ' + target_lang + ' (' + target_lang_code + ') translator. Your goal is to accurately convey the meaning and ' 'nuances of the original ' + source_lang + ' text while adhering to ' + target_lang + ' grammar, ' 'vocabulary, and cultural sensitivities.\n' }} {%- if content["type"] == 'text' -%} {{ 'Produce only the ' + target_lang + ' translation, without any additional explanations or ' + 'commentary. Please translate the following ' + source_lang + ' text into ' + target_lang + ':\n\n\n' + content["text"] | trim }} {%- elif content["type"] == 'image' -%} {{ 'Please translate the ' + source_lang + ' text in the provided image into ' + target_lang + '. ' + 'Produce only the ' + target_lang + ' translation, without any additional explanations, ' + 'alternatives or commentary. Focus only on the text, do not output where the text is located, ' + 'surrounding objects or any other explanation about the picture. Ignore symbols, pictogram, and ' + 'arrows!\n\n\n<start_of_image>' }} {%- else -%} {{ raise_exception("User role `content` can contain either `text` or `image` data.") }} {%- endif -%} {%- else -%} {{ raise_exception("Conversations must only contain user or assistant roles.") }} {%- endif -%} {{ '<end_of_turn>\n' }} {%- endfor -%} {%- if add_generation_prompt -%} {{'<start_of_turn>model\n'}} {%- endif -%}
完全に追い切れてはいないが、LM Studioでは上記のJinjaテンプレートを埋め切ることができず、きちんとモデルに渡すテキストを生成できないため、エラーが出たのだと思う。
ただ、上記のテンプレートには翻訳を効率的に実施するための、プロンプトの例は載っており、OllamaのTranslateGemmaのページのPrompt Guideがわかりやすいが
You are a professional {SOURCE_LANG} ({SOURCE_CODE}) to {TARGET_LANG} ({TARGET_CODE}) translator. Your goal is to accurately convey the meaning and nuances of the original {SOURCE_LANG} text while adhering to {TARGET_LANG} grammar, vocabulary, and cultural sensitivities. Produce only the {TARGET_LANG} translation, without any additional explanations or commentary. Please translate the following {SOURCE_LANG} text into {TARGET_LANG}: {TEXT}
これを守ると翻訳がうまくいくということが書かれている。そのため、英語→日本語の方のPrompt Tamplateを以下にすることで
{{ bos_token }}
{%- for message in messages %}
{%- if message['role'] == 'user' %}
{{ '<start_of_turn>user\n' }}
{{ 'You are a professional English (en) to Japanese (ja) translator. Your goal is to accurately convey the meaning and nuances of the original English text while adhering to Japanese grammar, vocabulary, and cultural sensitivities.\n' }}
{{ 'Produce only the Japanese translation, without any additional explanations or commentary. Please translate the following English text into Japanese:\n\n\n' }}
{{ message['content'] | trim }}
{{ '<end_of_turn>\n' }}
{%- elif message['role'] == 'assistant' %}
{{ '<start_of_turn>model\n' }}
{{ message['content'] | trim }}
{{ '<end_of_turn>\n' }}
{%- endif %}
{%- endfor %}
{%- if add_generation_prompt %}
{{ '<start_of_turn>model\n' }}
{%- endif %}
チャットUIから渡されたmessage['content']をそのまま翻訳対象とすることができるというわけだ。
まとめ
今回はTranslateGemma 12BのMLXモデルをLM Studioで動かしてみた。モデルをロードして普通にチャットUIから英文を入力するだけでは返答がなかったが、Prompt Templateを変更することで英語から日本語への翻訳ができた。
Prompt Templateについても少し調べてみると、Jinjaテンプレートでモデルに渡す文字列がどのように生成されるかも理解することができた。最初は何で返事がないんだろう…という感じだったが、Prompt TemplateやJinjaについて確認する良い機会にはなった。今後、Pythonなどから呼び出す際にもよくJSONで指定している箇所になるので、なるほどなと思って活用できそうだ。
とはいえ、なんか…LM Studioのせいで時間がかかったところかもしれない。もし、同じようにLM StudioでTranslateGemmaを動かそうと思ったが、あれっ?、となった方が簡単に参考になってくれたら嬉しいと思う。





