第7回:翻訳LLMの選定 — DeepSeekからChatGPTへ

はじめに

ここまでの連載ではLLMファインチューニングによる株価予測の話を中心にお伝えしてきましたが、千里眼サービスにはもう一つ重要なLLM活用ポイントがあります。多言語対応(翻訳) です。

日本語で収集したニュースと予測結果を英語に翻訳し、海外のユーザーにもサービスを提供したい。そのために翻訳用LLMプロバイダを選定する過程で、コストに惹かれてDeepSeekを導入した結果、予想外の問題に直面した経験をお伝えします。

「安いからといってLLMプロバイダを選ぶと、品質面で痛い目を見る」——これが本記事の結論です。


多言語化の動機

千里眼サービスは当初、日本語のみで運用していました。しかし、ユーザー層を広げるために英語対応を進めることにしました。

翻訳が必要な項目は主に3つです。

  1. ニュースタイトル: 株式ニュースの見出し
  2. ニュース要約: ニュース本文の要約
  3. 予測理由: AIがなぜその予測をしたのかの説明文

これらは毎日発生するデータで、量も相当あります。手動翻訳は現実的ではなく、LLMによる自動翻訳が不可欠でした。


DeepSeekを選んだ理由

最初に選んだ翻訳LLMプロバイダは DeepSeek でした。選定理由は明快です。

  1. コストが安い: OpenAIと比較して大幅に安価
  2. OpenAI互換API: APIインターフェースがOpenAIと互換。既存のコードを少し修正するだけで使える
  3. 推論能力: deepseek-reasonerモデルは高い推論能力を持つと評判だった

特にコストの安さは魅力的でした。毎日数十〜数百件のニュースを翻訳する必要があるため、1件あたりのコストは長期的に大きな差になります。

APIの呼び出しコードはこのような形で、OpenAIとほぼ同じです。

// DeepSeek API呼び出し
$url = 'https://api.deepseek.com/chat/completions';
$data = [
    'model' => 'deepseek-reasoner',
    'messages' => [
        ['role' => 'user', 'content' => $prompt]
    ],
    'stream' => false,
    'max_tokens' => 2000
];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_TIMEOUT, 300); // タイムアウト300秒

OpenAI互換のおかげで、URLとモデル名を変えるだけで動きました。導入はスムーズでした。

しかし、問題はここからでした。


問題1: 処理が遅すぎる

最初に気づいた問題は、レスポンスの遅さでした。

翻訳リクエストを送ると、レスポンスが返ってくるまでに数十秒〜数分かかることがありました。cURLのタイムアウトを300秒(5分)に設定しても、それでも間に合わないケースが発生しました。

curl_setopt($ch, CURLOPT_TIMEOUT, 300); // 300秒でも足りないことがある

さらに深刻だったのは、タイムアウトした場合に翻訳文が途中で切れることでした。「この企業は第2四半期の決算において…」で終わっていて、肝心の結論がない翻訳が生成されてしまいます。

バッチ処理で数百件のニュースを翻訳する場合、1件あたり数分かかるとバッチ全体の処理時間が膨大になります。crontabで定期実行しているため、前のバッチが終わらないうちに次のバッチが起動してしまうリスクもありました。


問題2: 中国語が混入する

2つ目の問題は、翻訳結果に中国語が混ざるというものでした。

日本語→英語の翻訳を依頼しているのに、出力の一部が中国語になることがありました。特に金融用語で顕著でした。

例えば、日本語の「経常利益」を英語にする際に、“ordinary profit” ではなく中国語の表現が混在するような出力がありました。

これはDeepSeekのモデルが中国語のデータで大量に学習されていることに起因すると考えられます。日本語と中国語は漢字を共有しているため、金融用語のような専門用語でモデルが「中国語モード」に引きずられてしまうのでしょう。

翻訳結果をそのままサービスに表示するわけにはいきません。中国語が混ざった英語翻訳は、ユーザーにとって意味不明です。手動で確認して修正する作業が発生し、自動化の意味が薄れてしまいます。


問題3: 入力データの漏洩

3つ目の問題が最も深刻でした。

千里眼サービスでは、予測理由の生成時に「市場の注目テーマランキング」というデータを入力に含めていました。この情報は予測の文脈を豊かにするために使っていたのですが、DeepSeekがこの入力データをそのまま出力してしまう問題が発覚しました。

つまり、「この情報を参考にして予測理由を生成してください」と渡したデータが、そのまま予測理由の一部として出力されてしまったのです。内部的に使っているランキングデータがユーザーに見える形で表示されてしまう。

これは即座に対処が必要でした。

// 20250329: 廃止(deepseek が表示してしまうため)
// $themes = get_market_themes($db, $date_only);
$themes = [];

市場テーマランキングの入力そのものを廃止しました。根本的な解決ではなく、問題を回避するための措置です。


ChatGPTへの統一

3つの問題が重なり、DeepSeekの利用を断念する判断に至りました。

全LLM処理をOpenAI(ChatGPT)に統一しました。

// DeepSeek → コメントアウト
// $api_result = call_deepseek_api($db, $prompt, $result);

// ChatGPT に統一(リトライ付き)
$summary = call_chatgpt5($prompt, LLM_TYPE_CHATGPT_5NANO);

ChatGPTに切り替えた結果、3つの問題はすべて解消されました。

  • 処理速度: レスポンスが数秒〜十数秒に改善。タイムアウトの心配がなくなった
  • 中国語の混入: 一切発生しなくなった
  • 入力データの漏洩: プロンプトの指示に忠実に従い、入力データをそのまま出力することはなくなった

現在の翻訳パイプライン

ChatGPTへの統一後、以下のモデル構成で運用しています。

処理モデル用途
予測理由生成gpt-5-nanoニュースの分析と株価予測理由の生成
ニュース翻訳gpt-5-miniタイトル・要約・予測理由の日英翻訳
MSIニュース要約gpt-5-mini市場センチメント指標のニュース要約
株価予測gpt-4o-mini(FT済み)ファインチューニング済みモデルによる予測

gpt-5-nanoとgpt-5-miniの使い分けは、処理の重さとコストのバランスで決めています。予測理由生成は比較的軽い処理なのでnano、翻訳や要約はより高品質な出力が求められるのでminiを使っています。

翻訳処理の流れ

翻訳バッチ(translate_english)は、以下の流れで動きます。

// 翻訳対象のニュースを取得(未翻訳のもの)
$sql = "SELECT code, target_date, type, title, contents_summary, predict_reason
        FROM v_firestore_news
        WHERE COALESCE(is_translated_news, 0) = 0";

foreach ($rows as $row) {
    // タイトルを翻訳
    $title_en = call_chatgpt5(
        $row['title'],
        LLM_TYPE_CHATGPT_5MINI,
        $system_prompt_title
    );

    // 要約を翻訳
    $contents_summary_en = call_chatgpt5(
        $row['contents_summary'],
        LLM_TYPE_CHATGPT_5MINI,
        $system_prompt_summary
    );

    // 予測理由を翻訳
    $predict_reason_en = call_chatgpt5(
        $row['predict_reason'],
        LLM_TYPE_CHATGPT_5MINI,
        $system_prompt_reason
    );

    // 翻訳結果をDBに保存
    // ...
}

タイトル、要約、予測理由をそれぞれ個別に翻訳し、結果をMySQLに保存しています。


プロバイダ切り替えの仕組み

DeepSeekからの移行を経験したことで、将来また別のプロバイダに切り替える可能性を考慮し、プロバイダの切り替え機構を実装しました。

// 環境変数で翻訳プロバイダを切り替え
$provider = getenv('TRANSLATE_PROVIDER');
if ($provider !== 'openai' && $provider !== 'ms' && $provider !== 'both') {
    $provider = 'openai'; // デフォルトはOpenAI
}

TRANSLATE_PROVIDER環境変数で以下の3つを切り替えられます。

動作
openaiOpenAI(ChatGPT)で翻訳(デフォルト)
msMicrosoft Translator APIで翻訳
both両方で翻訳し、OpenAIの結果を優先保存

Microsoft Translatorも検討した

LLMベースの翻訳だけに依存するのはリスクがあると考え、Microsoft Translator APIも検討しました。Microsoftは伝統的な機械翻訳の蓄積があり、安定性が高い。

ただし、Microsoft Translatorは文脈を考慮した意訳が苦手です。金融ニュースの翻訳では、単純な逐語訳よりも文脈を踏まえた自然な訳文が求められます。「上方修正」を機械的に訳すのではなく、投資家が読んで意味が通る英語にする必要があります。

最終的に、品質面でOpenAIが優れていたため、現在はOpenAIのみを使用しています。Microsoft Translatorはフォールバック用として仕組みだけ残してある形です。


コストの現実

DeepSeekからChatGPTに移行したことで、翻訳コストは上がりました。しかし、品質問題への対処コスト(手動確認、修正作業、バグ対応)を含めると、トータルコストではChatGPTの方が安い可能性すらあります。

項目DeepSeekChatGPT
API利用料安いやや高い
処理速度遅い(バッチ処理時間増大)速い
品質チェック必要(中国語混入、文章途切れ)ほぼ不要
手動修正頻繁に発生ほとんど発生しない
運用の安定性低い(タイムアウト多発)高い

特に個人開発では、「安いが不安定」よりも「少し高いが安定」の方が圧倒的に楽です。品質問題の調査と修正に費やす時間は、そのまま開発リソースの損失です。


予測理由の生成

翻訳だけでなく、予測理由の生成にもLLMを活用しています。

千里眼サービスでは、株価の予測値だけでなく「なぜその予測をしたのか」の理由も表示しています。この理由は、ファインチューニング済みモデル(gpt-4o-mini FT)が出す予測結果を補完するものです。

// 予測理由の生成
$prompt = "以下のニュースと企業情報に基づいて、翌日の株価予測の理由を説明してください。\n\n"
        . "ニュース: " . $news_title . "\n"
        . "要約: " . $news_summary . "\n"
        . "企業: " . $company_name . "\n"
        . "業種: " . $industry;

$summary = call_chatgpt5($prompt, LLM_TYPE_CHATGPT_5NANO);

予測理由の生成にはgpt-5-nanoを使っています。予測そのものはファインチューニング済みモデルが行い、理由の説明は汎用モデルが担当するという分業です。

この予測理由も英語に翻訳されるため、翻訳パイプラインの品質は直接ユーザー体験に影響します。


リトライ機構

LLM APIは常に安定しているわけではありません。ネットワークの一時的な問題や、APIサーバーの負荷による遅延が発生することがあります。

そのため、API呼び出しにはリトライ機構を組み込んでいます。

// call_chatgpt5 で要約生成(最大3回リトライ)
$max_retries = 3;
for ($retry = 0; $retry < $max_retries; $retry++) {
    $summary = call_chatgpt5($prompt, LLM_TYPE_CHATGPT_5NANO);
    if ($summary !== false && $summary !== null && trim($summary) !== '') {
        break; // 成功したらループを抜ける
    }
    echo "リトライ {$retry + 1}/{$max_retries}...\n";
    sleep(2); // 少し待ってからリトライ
}

DeepSeek時代はタイムアウトが多発していたため、リトライ機構は必須でした。ChatGPTに移行してからはリトライが発生する頻度は大幅に減りましたが、安全策として残しています。


LLMプロバイダ選定の教訓

DeepSeekからChatGPTへの移行を通じて得た教訓をまとめます。

1. コストだけで選ばない

安さは魅力的ですが、品質問題への対処コストを含めたトータルコストで判断すべきです。特に翻訳のような品質が直接ユーザーに見える処理では、品質の妥協は致命的です。

2. 多言語処理ではモデルの学習データバランスが重要

DeepSeekの中国語混入問題は、モデルの学習データにおける言語バランスに起因していました。日本語と中国語の漢字の共通性が、予期しない言語切り替えを引き起こしていた可能性があります。多言語処理を行う場合、モデルがどの言語のデータで学習されているかは重要な選定基準です。

3. プロバイダの切り替え可能性を設計に組み込む

LLMの世界は急速に変化しています。今日の最適解が明日も最適とは限りません。プロバイダの切り替えが容易な設計にしておくことで、より良いモデルが登場した時にすぐに移行できます。

4. 本番データでの品質テストは必須

テスト段階では気づかなかった問題(中国語混入、入力データの漏洩)が、本番データの多様性の中で初めて顕在化しました。テストデータだけでなく、本番規模のデータで品質を検証することが重要です。


まとめ

翻訳LLM選定の経験から得たポイントです。

  • DeepSeekを翻訳用LLMとして採用したが、3つの問題(遅延、中国語混入、データ漏洩)が発生
  • ChatGPT(gpt-5-nano / gpt-5-mini)に統一して問題を解消
  • 翻訳プロバイダの切り替え機構(TRANSLATE_PROVIDER)を実装
  • Microsoft Translatorもフォールバックとして検討済み
  • LLMプロバイダはコストだけでなく、品質・安定性・多言語対応のバランスで選ぶべき

次回は最終回です。MySQLからFirestoreへのデータ移行と、千里眼サービスの本番運用の話をお伝えします。


次回: 第8回「MySQL→Firestore移行と本番運用 — RDBからNoSQLへの道」

この記事をシェア

関連記事