LLM は日本の方言にどの程度対応できるのか?
先日、ある開発現場で、掲題のような質問を受けました。「対応」って一言で言っても、方言を理解できるのか?方言で返せるのか?とかいろいろあるよなぁと、まず、そこから考えないといけないのかぁとちょっと辟易しながら、実際どうなんだろうという疑問もあったので試してみたのでその備忘録です。
アプローチ
LLMがある程度方言理解できることは分かっていました。掲題の質問を受けて「ある程度対応できます」みたいな投げやりな回答しようかとも思ったんですが、今後、同じような質問を受ける可能性もあるので、ざっと、どんなアプローチで実験しようか考えてみました。
問題のブレイクダウン
まず、「対応」の意味を決めてやらないといけない。質問者に逆質問しても、そもそも問題を丸投げするような人の場合、それ以上のモノは出てこないことが多いので、こちらで推測して定義するのが一番効率的だと思います。
| やりたいこと | 確認すること |
|---|---|
| 方言を読んで理解する | 発言の意味や意図を正しく取れるか |
| 標準語に直す | 意味・ニュアンスを落とさず変換できるか |
| 方言で返答する | 地域や場面に合った自然な表現になるか |
| 音声で扱う | 方言の発話を文字起こしできるか |
| 業務処理に使う | 方言の入力から、分類・検索・回答などを正しく実行できるか |
範囲を広げすぎると永久に終わらなくなるので、まずは、「方言の理解能力」「標準語に直す」 について評価する方向で進めます。
正しい方言
評価をするといっても、そもそも「正しい方言」「正解データ」って存在するのかな?と考えたときに、こちら(CPJD)のデータを使用させていただきました。
CPIDは、
- 標準語
- 各地域の方言
が一対になっているデータセットです。
例えば
標準語:
それゆえ、私なりに、それを使わなくてはならないのですが、これがまた厄介でした。
広島弁:
じゃけんうちなりに、それを使わにゃならんのじゃけど、これがまた厄介じゃった。
こういう感じです。
CC BY-SA 4.0ライセンスで配布されています。
ここから、各方言から5件ずつ、計100件のデータを作成しました。元になる標準語文は10種類5問 x 20方言。
例 :
"cases": [
{
"case_id": "CPJD-001",
"set": 1,
"sentence_rank": 1,
"sentence_id": 7,
"dialect_ja": "福岡弁",
"dialect_cpjd": "fukuoka-ben",
"speaker_id": "F002",
"speaker_gender": "f",
"birth_place": "fukuoka",
"dialect_text": "それやけん私なりに、それを使わんとあかんかったんですが、これがまた厄介でした。",
"standard_gold": "それゆえ、私なりに、それを使わなくてはならないのですが、これがまた厄介でした。",
"mean_dialect_ned": 0.490016,
"task_prompt": "次の方言文を、意味を変えずに自然な標準語へ直してください。余計な説明はせず、変換結果だけを出力してください。"
},
{
"case_id": "CPJD-002",
"set": 1,
"sentence_rank": 2,
"sentence_id": 3,
"dialect_ja": "福岡弁",
"dialect_cpjd": "fukuoka-ben",
"speaker_id": "F002",
"speaker_gender": "f",
"birth_place": "fukuoka",
"dialect_text": "じゃあお前の紹介文いらんやろ",
"standard_gold": "じゃあお前の紹介文いらないよ",
"mean_dialect_ned": 0.427169,
"task_prompt": "次の方言文を、意味を変えずに自然な標準語へ直してください。余計な説明はせず、変換結果だけを出力してください。"
},
比較(各社LLM)
「各社のモデルを比較しろ」とは言われてないんですが、なんとなく面白そうなので、各社の LLM に同じデータを入力して、どんな結果になるか試してみます。
中心を OpenAI でと考えたとき、用途とかを限定せずに現時点(2026年9月時点で)汎用的でそれなりのコスト感ということで gpt-6-sol を選んでみました。(異論は認めます!)
gpt-6-solと同じぐらいのコスト感だと下記当たりが同等の製品になるかと思います。コストだけで考えるべきではないという意見もあるかとは思いますが、まずはやってみます。
| 役割 | モデル | 標準API料金(入力/出力 注1) |
|---|---|---|
| 基準 | gpt-6-sol |
$2/$10 |
| Anthropicの主比較 | claude-sonnet-5 |
$2/$10 |
| Googleの主比較 | gemini-3.1-pro-preview |
$2/$12(注2) |
注1 : 100万トークン
注2 : 入力20万トークン以下
表は各社の標準API公表単価(2026年9月時点)の比較です。記事の実行にはOpenGatewayを使っているため、実際の請求額や各モデルの消費トークン数は異なる場合があります。
比較方法
今回、同じコードで比較できるように、弊社 Sionic AI が提供する OpenGateway を使用しました。
OpenGateway については、別途記事を書きましたので、そちらを参照してください。
import json
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv("OPENGATEWAY_API_KEY"),
base_url="https://apis.opengateway.ai/v1"
)
models = [
"openai/gpt-6-sol",
"anthropic/claude-sonnet-5",
"google/gemini-3.1-pro-preview"
]
def evaluate_case(case: dict, model: str) -> dict:
converted_response = client.responses.create(
model=model,
input=[
{"role": "system", "content": case["task_prompt"]},
{"role": "user", "content": case["dialect_text"]},
],
)
return converted_response.output_text
def main():
with open("data/japanese_dialect_llm_benchmark_v3_cpjd_core100.json", encoding="utf-8") as f:
cases = json.load(f)["cases"]
print(f"{len(cases)} cases loaded")
results = []
for case in cases[:]:
print(f"Evaluating case {case['case_id']}... {case['dialect_text']}")
output = case.copy()
ouput_texts = []
for model in models:
result = evaluate_case(case, model)
ouput_texts.append({"model": model, "output_text": result})
output["outputs"] = ouput_texts
results.append(output)
output_path = f"results/compare.json"
with open(output_path, "w", encoding="utf-8") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f"saved to {output_path}")
if __name__ == "__main__":
main()
OpenGateway を使用することで、一つのコードで複数のLLM Model をまたいで使用することが可能です。
テスト結果は、下記のように出てきます。
{
"case_id": "CPJD-003",
"set": 1,
"sentence_rank": 3,
"sentence_id": 207,
"dialect_ja": "福岡弁",
"dialect_cpjd": "fukuoka-ben",
"speaker_id": "F002",
"speaker_gender": "f",
"birth_place": "fukuoka",
"dialect_text": "ただ、作るとき裏ごしをせんといかんんでとても大変です",
"standard_gold": "ただ、作るときに裏ごしをしなくてはいけないのでとても大変です。",
"mean_dialect_ned": 0.390282,
"task_prompt": "次の方言文を、意味を変えずに自然な標準語へ直してください。余計な説明はせず、変換結果だけを出力してください。",
"outputs": [
{
"model": "openai/gpt-6-sol",
"output_text": "ただ、作るときに裏ごしをしなければならないので、とても大変です。"
},
{
"model": "anthropic/claude-sonnet-5",
"output_text": "ただ、作るとき裏ごしをしないといけないのでとても大変です"
},
{
"model": "google/gemini-3.1-pro-preview",
"output_text": "ただ、作るとき裏ごしをしないといけないのでとても大変です"
}
]
}
評価
方言 -> 標準語 への変換は、gpt-6-sol/claude-sonnet-5/gemini-3.1-pro-preview の3つで行いました。
評価基準:
5: 意味・ニュアンスとも完全に同等で、自然な標準語
4: 意味は同等だが、軽微な不自然さや方言の残存がある
3: 大筋は合っているが、一部の意味が欠落・誤訳されている
2: 重要な意味の誤りがある
1: 意味が大きく異なる、または変換になっていない
評価については、現時点での最上位モデル gpt-6-astra を使用してみました。gpt-6-astra一つによる採点には、そのモデル固有の判断傾向が出るかもしれませんが、とりあえずやってみましょう。
import json
import os
from collections import defaultdict
from openai import OpenAI
client = OpenAI(
api_key=os.getenv("OPENGATEWAY_API_KEY"),
base_url="https://apis.opengateway.ai/v1"
)
JUDGE_MODEL = "openai/gpt-6-astra"
SYSTEM_PROMPT = """あなたは日本語の方言と標準語の専門家です。
以下の方言文を標準語に変換した「標準語への変換結果」が、「正解」と比べてどの程度意味を保っているか評価してください。
表記ゆれや語順・言い回しの違いは、意味とニュアンスが保たれていれば減点しないでください。
方言文: {dialect_text}
正解: {standard_gold}
標準語への変換結果: {output_text}
評価基準:
5: 意味・ニュアンスとも完全に同等で、自然な標準語
4: 意味は同等だが、軽微な不自然さや方言の残存がある
3: 大筋は合っているが、一部の意味が欠落・誤訳されている
2: 重要な意味の誤りがある
1: 意味が大きく異なる、または変換になっていない
JSON のみで出力してください: {{"score": <1-5の整数>, "reason": "<簡潔な理由>"}}"""
def judge(case: dict, output_text: str) -> dict:
prompt = SYSTEM_PROMPT.format(
dialect_text=case["dialect_text"],
standard_gold=case["standard_gold"],
output_text=output_text,
)
response = client.responses.create(
model=JUDGE_MODEL,
input=[{"role": "system", "content": prompt}],
)
return json.loads(response.output_text)
def main():
with open("results/compare.json", encoding="utf-8") as f:
cases = json.load(f)
scores = defaultdict(list)
for case in cases:
print(f"Judging case {case['case_id']}... {case['dialect_text']}")
for output in case["outputs"]:
output.update(judge(case, output["output_text"]))
scores[output["model"]].append(output["score"])
output_path = "results/compare_judged.json"
with open(output_path, "w", encoding="utf-8") as f:
json.dump(cases, f, ensure_ascii=False, indent=2)
print(f"saved to {output_path}")
for model, s in scores.items():
print(f"{model}: {sum(s) / len(s):.2f}")
if __name__ == "__main__":
main()
結果
| モデル | 平均点 | 5点 | 4点以上 | 3点以下 |
|---|---|---|---|---|
| GPT-6 Sol | 4.63 | 79件 | 85件 | 15件 |
| Claude Sonnet 5 | 4.44 | 68件 | 81件 | 19件 |
| Gemini 3.1 Pro Preview | 4.65 | 79件 | 87件 | 13件 |
結果から言う 4.5 ぐらいで、ある程度対応できます と、アホのフリすればギリ乗り切れそうな回答にはなりました。
乗り切れない状況では
CPJDから抽出した20方言・計100件のテキストを標準語に変換したところ、単一のLLM判定器による平均点はGPT-6 Solが4.63、Claude Sonnet 5が4.44、Gemini 3.1 Pro Previewが4.65だった。SolとGeminiの差は今回のデータでは小さい。ただし、元の共通文は10種類に限られ、正解文と方言文の表現差による減点例もある。この結果は、今回の文に対する標準語変換の暫定評価である。また、方言での応答、音声認識、会話での意図理解ではありません。
こんな感じでしょうか。
ちなみに、うまく変換できなかったと思われる例は下記です。
| ケース | 方言文・正解の要点 | 低評価の出力と理由 |
|---|---|---|
| CPJD-027(諸県弁) | 「じゃったらわいの紹介文ないらんやろ。」/正解は「お前の紹介文はいらない」 | 3モデルとも2点。「俺の」「私の」と訳し、紹介文が誰のものかを取り違えました。 |
| CPJD-056(秋田弁) | 「最悪の結果、でねばいな」/正解は最悪の結果にならないことを願う表現 | Sonnet 5:1点。「最悪の場合、出るかもしれない」と訳し、意味が大きく変わりました。SolとGeminiは5点です。 |
| CPJD-053(津軽弁) | 裏ごしが必要なので、作るのが大変という文 | Sonnet 5:2点。「作るとき」を「凍らせるとき」と訳しました。SolとGeminiは、強調の欠落により3点です。 |
| CPJD-072(北海道弁) | 「昨夜はゆるくなくて、更新することもなく爆睡したさ。」/正解は疲労で更新せず寝たという内容 | Sonnet 5:2点。「ゆるくなくて」を「暇がなくて」と訳し、理由を疲労から時間不足に変えました。SolとGeminiは3点です。 |
今回の実験と結果に対する補足
まず、評価するモデルが gpt-6-astra 一種類であり、OpenAI の特性が出ている可能性や、評価が一回のみなので、本来は複数回実施して揺らぎを確認した方がよさそうです。
また、データは、100件ですが、各方言から5件ずつ、計100件。元になる標準語文は10種類 で、実質的には限定された文章に対する評価なので、本格的な調査をするには、対象とする件数を増やす必要がありそうです。
今後の実験
追加で調査するかどうかはわかりませんが、
- 対象となる文章をN増し
- 変換・評価ともに複数回実施
- 一文ではなく、ある程度の長文
- 音声も含めた方言(イントネーション・抑揚)
等をやってもいいのかな?と思います。
また、このような LLMを実験する際に、弊社の OpenGateway は便利に使えますので、ご興味ある方は使ってみてください。
データ出典・ライセンス
本記事では、高道慎之介・猿渡洋による CPJD: Crowdsourced Parallel Speech Corpus of Japanese Dialects(CC BY-SA 4.0)から文を抽出・整形し、LLMによる標準語への変換結果と評価を追加しました。掲載したCPJD由来の文とその翻案部分は、CC BY-SA 4.0に従います。分析・考察は筆者によるものです。