中級 16 分Support

ローカルLLMによる多言語カスタマーサポート:6言語に対応し、 cloud

サポートチームがフランス語、英語、スペイン語、ドイツ語、イタリア語、アラビア語のチケットを受け付ける場合、それぞれのメッセージをクラウドAPIに送信することは、メールアドレス、注文番号、あるいは個人情報が第三者に漏洩するリスクをもたらし、トークン単位で費用が発生します。本ガイドでは、Qwen 3.8 27Bを採用した、100%ローカルなマルチ言語チャットボットを構築し、自動言語検出、各文化に適したトーン、およびZendeskまたはFreshdeskへのWebhookによる直接統合を実現します。

著者 Marie L.·更新 2026-08-27·Windows・macOS・Linuxでテスト済み

#多言語サポートにローカル LLM を使う理由

クラウドAPI(GPT-4o、Claude、Gemini)はトークン単位で課金され、クライアントメッセージのEU域外転送を強制します。1日5,000件のチケットを処理するB2Cサポートの場合、月額請求額はすぐに1,500ユーロを超え、チケット本文にIBANや社会保険番号が送信されると、GDPR(一般データ保護規則)への準拠は極めて困難になります。

ローカルLLMは2つの問題を一度に解決します。Qwen 3.8 27B(Alibaba、2026年8月14日リリース)は、100を超える言語に標準で対応しています。要件書に記載された6つのヨーロッパ言語を、入門クラスのクラウドモデルに匹敵する品質で処理でき、RTX 4090を1枚搭載したマシン、またはMac M4 Maxで動作します。問い合わせ1件あたりの限界費用はゼロです。

i
なぜQwen 3.8 27Bなのか
これは2026年のAlibabaの主力汎用モデルです。262,000トークンのコンテキストウィンドウと画像認識機能を備え、ライセンスはApache 2.0(商用利用自由)です。サポート業務では、この巨大なコンテキストにチケットの全履歴を切り詰めずに入力でき、多言語対応の品質も同クラスで最も優れています(Q4で18GB、24GBのグラフィックカードに収まります)。知っておきたい設定として、推論にかける労力を「low」にしてください。デフォルトでは考えすぎるため、サポートの回答では無駄に応答時間が長くなります。

#前提条件

企業向けローカルAIキット

職場でのローカルAI導入:GDPR、AI Act、マルチユーザーアーキテクチャ、コスト、経営陣向けメモ。

  • 永久に利用できるオンラインスペース
  • PDF + ファイル
  • 生涯アップデート
VRAMが最低24 GBあるGPUが必要です
RTX 3090、4090、5090、または Mac M3/M4 Max(32GBの統合メモリ搭載)。Qwen 3.8 27B は Q4_K_M で約 18GB を消費します。
Ollama インストール済み
Qwen 3.8(画像認識と長いコンテキスト)をネイティブにサポートする新しいバージョン。
Zendesk または Freshdesk のアカウント
Webhook連携とトリガーを作成するための管理者権限があること。
HTTPSでアクセス可能なエンドポイント
VPSを介して Ollama にリバースプロキシを設定するか、ngrok / Cloudflare Tunnelでローカルサーバーを公開するかのいずれか。
Python 3.11以上
言語検出層とWebhookルーターに使用します。FastAPI + langdetectで十分です。

#1. OllamaでQwen 3.8 27Bをインストールする

このモデルはOllamaのライブラリから直接入手できます。ダウンロードを開始し、簡単な動作テストを行ってください:

ターミナル
ollama pull qwen3.8:27b
ollama run qwen3.8:27b "Réponds en une phrase : qu'est-ce qu'un LLM open-weight ?"

pull操作では約18 GBをダウンロードします。RTX 4090では、Q4での推論速度は40〜60トークン/秒で、サポートの回答を3〜5秒で生成できます。推論の労力を「low」に設定すると、応答までの遅延はさらに短くなります。

→
多言語対応をすぐにテスト
ollama runを使い、同じ質問を6言語で順番に尋ねてください。Qwen 3.8は、以前の世代のLlamaがときどき英語に流れてしまったのとは異なり、言語間で暗黙の切り替わりが起きません。これはまさに、サポート用途で求められる挙動です。

ネットワーク上に Ollama を公開し、Webhookがアクセスできるようにしてください:

systemdオーバーライド
sudo systemctl edit ollama
# Ajoutez :
[Service]
Environment="OLLAMA_HOST=0.0.0.0:11434"
Environment="OLLAMA_KEEP_ALIVE=30m"

sudo systemctl restart ollama

OLLAMA_KEEP_ALIVE=30mは、最後のリクエストから30分間モデルをVRAMに保持します。これにより、問い合わせの少ない時間帯でも、チケットごとにコールドスタートが発生するのを避けられます。

#2. 言語の自動検出

Qwen3にメッセージを送信する前に、適切なシステムプロンプトを選択するためにその言語を特定します。fast-langdetectライブラリ(MetaのfastTextに基づく)は、1リクエストあたり5 ms未満で176言語を検出でき、50文字を超えるメッセージでは99%を超える精度を誇ります。

インストール
pip install fast-langdetect fastapi uvicorn httpx
detector.py
from fast_langdetect import detect

SUPPORTED = {"fr", "en", "es", "de", "it", "ar"}

def detect_language(text: str) -> str:
    text = text.replace("\n", " ").strip()
    if len(text) < 10:
        return "en"  # message trop court, fallback raisonnable
    result = detect(text, low_memory=False)
    lang = result["lang"]
    return lang if lang in SUPPORTED else "en"
!
複数の言語が混在するメッセージの落とし穴
フランス人の顧客が英語のエラーメッセージを貼り付けると、言語検出の結果が英語に切り替わることがあります。メッセージ全体ではなく、最初の段落だけ(最初の空行より前)を対象に言語を検出してください。そうしないと、フランス語を話す顧客に英語で回答してしまいます。

#3. 言語とトーンに応じたシステムプロンプト

優れた多言語サポートでは、フランス語のプロンプトを英語に翻訳するのではなく、言語に応じて文体を調整します。仕事で使うフランス語では丁寧な呼びかけの「vous」を使い、ビジネス英語ではより直接的な表現を用います。ドイツ語では明確に形式的な丁寧さが求められ、ラテンアメリカのスペイン語ではより温かみのある表現が受け入れられます。イタリア語はより表情豊かで、アラビア語ではメッセージの冒頭と末尾に礼儀にかなった定型表現が必要です。

prompts.py
SYSTEM_PROMPTS = {
    "fr": (
        "Tu es un agent de support client professionnel. "
        "Réponds en français, avec vouvoiement systématique. "
        "Sois concis, empathique, factuel. Ne promets jamais de remboursement "
        "sans validation. Si tu ne sais pas, propose une escalade humaine."
    ),
    "en": (
        "You are a professional customer support agent. "
        "Reply in English, business-friendly tone, direct and concise. "
        "Never commit to a refund without confirmation. "
        "Escalate to a human if uncertain."
    ),
    "es": (
        "Eres un agente de soporte profesional. Responde en español, "
        "trato de usted, tono cálido pero conciso. Nunca prometas reembolsos "
        "sin confirmación. Escala a un humano en caso de duda."
    ),
    "de": (
        "Du bist ein professioneller Kundensupport-Agent. Antworte auf Deutsch "
        "mit Sie-Form, höflich-formell, präzise und sachlich. Versprich nie eine "
        "Rückerstattung ohne Bestätigung. Eskaliere im Zweifel an einen Menschen."
    ),
    "it": (
        "Sei un agente di assistenza clienti professionale. Rispondi in italiano, "
        "forma di cortesia (Lei), tono cordiale e conciso. Mai promettere rimborsi "
        "senza conferma. Scala a un umano in caso di dubbio."
    ),
    "ar": (
        "أنت موظف دعم عملاء محترف. أجب باللغة العربية الفصحى، "
        "بأسلوب رسمي ومهذب يبدأ بتحية وينتهي بعبارة لطيفة. "
        "لا تعد بأي استرداد دون تأكيد. إذا لم تكن متأكدًا، اطلب تدخل موظف بشري."
    ),
}
→
プロンプトに組み込む業務上のガードレール
「返金は決して約束しない」「わからない場合はエスカレーションする」「割引をしない」という3行だけが、サポート業務でLLMが実害を引き起こすのを防ぎます。これらをすべての言語で入れてください。口調は変わっても、業務ルールは変わりません。

#4. ZendeskまたはFreshdeskのWebhookを統合

ZendeskとFreshdeskは、新しいチケットが作成されるたびにHTTP POSTのWebhookを送信します。FastAPIのエンドポイントを公開し、そのエンドポイントで言語を検出し、プロンプトを選び、Ollamaを呼び出して、応答をサポートシステムのAPIに返します。応答は内部コメントとして追加され、人間の担当者が送信前に承認します。

webhook_server.py
from fastapi import FastAPI, Request
import httpx
from detector import detect_language
from prompts import SYSTEM_PROMPTS

app = FastAPI()
OLLAMA_URL = "http://localhost:11434/api/chat"

@app.post("/webhook/zendesk")
async def handle_ticket(req: Request):
    payload = await req.json()
    ticket_id = payload["ticket"]["id"]
    message = payload["ticket"]["description"]

    lang = detect_language(message)
    system = SYSTEM_PROMPTS[lang]

    async with httpx.AsyncClient(timeout=60) as client:
        r = await client.post(OLLAMA_URL, json={
            "model": "qwen3.8:27b",
            "messages": [
                {"role": "system", "content": system},
                {"role": "user", "content": message},
            ],
            "stream": False,
            "options": {"temperature": 0.3, "num_ctx": 8192},
        })
    draft = r.json()["message"]["content"]

    # Ajoute la réponse en note interne sur le ticket
    await post_internal_note(ticket_id, lang, draft)
    return {"status": "ok", "lang": lang}

post_internal_note 関数は、Zendesk API(PUT /api/v2/tickets/{id}.json)または Freshdesk API(POST /api/v2/tickets/{id}/notes)を介して、下書きを非公開コメントとして投稿します。人間の担当者が読み直し、修正して「送信」をクリックします。ボットに単独で返信させることなく、返信文の作成時間を約60%削減できます。

  1. 01
    エンドポイントの公開
    Cloudflare Tunnelまたはngrokはhttp://localhost:8000を接続先とします。公開HTTPS URLを控えてください。
  2. 02
    Webhookの送信先を作成する
    Zendesk Admin → Apps & intégrations → Webhooksで、ご自身のURLとPOSTメソッドを指定してターゲットを作成してください。
  3. 03
    トリガーを接続する
    Triggersで、条件を「Ticket Created」、アクションを「Notify webhook」に設定し、{ticket: {id, description, requester}}を含むJSONペイロードを指定します。
  4. 04
    仮のチケットでテスト
    ドイツ語でチケットを作成してください。エンドポイントがイベントを受信し、"de" を検出して、内部メモにドイツ語の下書きを投稿することを確認してください。
  5. 05
    本番環境で段階的に有効化する
    単一のキュー(例:スペイン語キュー)から始めてください。1週間品質を測定し、キューごとに拡張してください。
!
顧客に対して直接回答しないでください
LLMが文章を作成し、人間が確認して承認します。これが原則です。Qwen 3.8 が存在しない注文番号を生成したり、返金ポリシーをでっち上げたりすれば、Trustpilotで星1つのレビューにつながります。言語ごとに6か月分の品質測定がそろうまでは、下書きモードを維持してください。

#5. 言語ごとに品質を測定する

Qwen 3.8の品質は、6つの言語で同じではありません。フランス語と英語は非常に優秀で、スペイン語とイタリア語もかなり良好、ドイツ語はまずまずです。アラビア語は方言によって差があり、現代標準アラビア語(MSA)には十分対応できますが、マグレブの方言では品質が劣ります。運用を適切に管理するには、品質を測定する必要があります。

初日から、言語ごとに記録すべき3つの指標:

修正なしで承認された割合
担当者が下書きをそのまま送信する割合です。最もシンプルで、状況を把握しやすい指標です。3か月時点の目標は40~60%です。
編集率(変更された単語数 / 生成された単語数)
最終回答と下書きの差分を取って測定してください。編集率が30%を超える言語では、その言語のプロンプトを見直す必要があります。
言語別CSAT
解決後の満足度調査とチケットの言語を組み合わせます。ドイツ語が3.5/5に落ちる一方でフランス語は4.5を維持している場合、トーンの問題があります。
i
実際の調整事例
ドイツにも展開したフランスのEC事業者での実際の導入では、ドイツ語での承認率が18%で頭打ちになっていました。特定された原因は、直訳したプロンプトに「共感的であれ」と書かれていたことです。ビジネスで使うドイツ語では、「empathisch」はセラピストのように聞こえます。「verbindlich und lösungsorientiert」(相手にしっかり向き合い、解決を重視する)に置き換えたところ、2週間で45%になりました。

#よくある落とし穴

ボットが誤った言語で応答しています
ほぼ常に、複数の言語が混在するメッセージが原因です(フランス語の問い合わせの下に英語の署名が付いている場合など)。最初の段落で言語を判定するか、システムプロンプトに加えて「Reply in {lang}」という明示的な指示を与え、返信の下書きの言語を指定してください。
遅延 > 10秒
OLLAMA_KEEP_ALIVEが有効で、モデルがVRAMに保持されていることを確認してください。ollama psには「100 % GPU」と表示される必要があります。そうでなければ、短いチケットを扱う場合はnum_ctxを4096に下げてください。
アラビア語の回答が正しくフォーマットされていない(RTL)
Qwen3はアラビア語を適切に生成できますが、一部のサポート用インターフェースでは、右から左への表示(RTL)が自動的に適用されません。Zendesk/Freshdesk側の回答ブロックにdir="rtl" lang="ar"を追加してください。
存在しないキャンペーンを捏造するハルシネーション
temperatureを0.2に下げ、プロンプトに「チケットに記載されている場合を除き、プロモーションや割引コードには一切言及しないでください」と明記してください。LLMは、実際には存在しないプレゼントを提供したがる傾向があります。
複数回再実行されるWebhook
タイムアウトが発生すると、Zendeskが再試行することがあります。冪等性を確保するため、ticket_idをRedisに保存し、TTLを10分に設定してください。そうしないと、同じチケットに対して下書きを3件生成してしまいます。

#さらに詳しく

基盤が安定したら、二つの拡張によって回答の承認率を大幅に高められます。一つは、ナレッジベース(FAQ、返品ポリシー、保証条件)にローカルRAGを接続し、回答を事実に基づかせることです。もう一つは、数千件の解決済みチケットを使ったLoRAファインチューニングを追加し、自社らしい語調に合わせることです。複数の端末で本番運用する場合、Nginxの背後でイントラネットにデプロイすることで、ネットワークと認証に対応できます。

このガイドは役に立ちましたか?

ご意見、誤りのご指摘、補足はありますか?ぜひお知らせください。皆さんにとってより良いガイドにするために役立ちます。