ChatGPT APIとLaravelを連携し、顧客からの問い合わせ内容をAIが自動で分類・担当者に振り分ける仕組みを実装ガイドとともに解説します。
こんな悩みありませんか?
「毎日届く問い合わせメールを手動で振り分けるのが限界になってきた」「担当者への連絡が遅れてクレームになったことがある」「問い合わせ内容をカテゴリ別に管理したいが、人手が足りない」——。
Webサイトへの問い合わせが増えるほど、その仕分け作業がボトルネックになります。特に中小規模の開発チームでは、専任のオペレーターを置くことも難しく、営業・技術・総務が兼務で対応しているケースも珍しくありません。結果として、返信の遅延・担当ミス・対応漏れが発生し、顧客満足度の低下につながってしまいます。
この記事では、ChatGPT APIとLaravelを組み合わせて、問い合わせ内容をAIが自動で分類し、適切な担当者へ割り当てる仕組みを実装する方法を、実案件での経験を踏まえながら解説します。コード例も交えた実践的な内容です。
なぜ「手動仕分け」がボトルネックになるのか
問い合わせフォームに届く内容は、一見シンプルに見えて、実際には多種多様です。技術的な質問、見積もり依頼、クレーム、採用問い合わせ、提携の打診……これらを担当者が毎回目で読んで判断するのは、件数が少ない時期には問題になりにくいですが、月100件を超えたあたりから確実に崩壊し始めます。
あるクライアント(神奈川県内のBtoB製造業)では、問い合わせフォームへの月間投稿が120件ほどあったにも関わらず、仕分けを総務の担当者一人が行っていました。その方が有給取得時や繁忙期には数日間対応がストップし、営業機会を失ったことが複数回あったといいます。
課題を整理すると、次のような構造になります。
flowchart TD
A[顧客が問い合わせフォームを送信] --> B[メールで担当者へ一括通知]
B --> C{担当者が内容を読んで判断}
C -->|技術系| D[開発チームへ転送]
C -->|見積もり| E[営業チームへ転送]
C -->|クレーム| F[管理職へ転送]
C -->|担当者不在| G[対応遅延・漏れ発生]
G --> H[顧客満足度の低下]このフローの「C」の部分をAIに任せることで、属人的な業務を自動化できます。
実装の全体像
今回構築するシステムの概要は次の通りです。
- 問い合わせフォームから送信されたデータをLaravelが受信
- 問い合わせ本文をOpenAI APIへ送信し、カテゴリ分類と優先度を取得
- 分類結果に基づいて担当者をDBから自動選択
- 担当者へメール通知し、管理画面に記録
実装ガイド:ステップバイステップ
Step 1:OpenAI APIクライアントの準備
まず、openai-php/laravelパッケージを導入します。
composer require openai-php/laravel
php artisan vendor:publish --provider="OpenAI\Laravel\ServiceProvider"
.envにAPIキーを追加します。
OPENAI_API_KEY=your-api-key-here
OPENAI_ORGANIZATION=your-org-id
Step 2:問い合わせ分類サービスの実装
分類ロジックを専用のサービスクラスに切り出すのがポイントです。Controllerに直書きすると、テストが難しくなり後々の保守でつまずきます。
<?php
namespace App\Services;
use OpenAI\Laravel\Facades\OpenAI;
class InquiryClassifierService
{
/**
* 問い合わせ内容を分類し、カテゴリと優先度を返す
*/
public function classify(string $body): array
{
$prompt = <<<EOT
以下の問い合わせ内容を分析し、JSON形式で返答してください。
【分類カテゴリ】
- technical : 技術的な質問・サポート依頼
- sales : 見積もり・料金・営業関連
- complaint : クレーム・苦情・不満
- recruitment: 採用・提携・パートナー
- other : 上記以外
【優先度】
- high : 緊急または強い不満を含む
- medium : 通常対応
- low : 急がない問い合わせ
返答形式(JSONのみ、説明不要):
{"category": "カテゴリ名", "priority": "優先度", "summary": "30文字以内の要約"}
問い合わせ内容:
{$body}
EOT;
$response = OpenAI::chat()->create([
'model' => 'gpt-4o-mini',
'messages' => [
['role' => 'system', 'content' => 'あなたは問い合わせ管理の専門家です。指定のJSON形式のみで返答してください。'],
['role' => 'user', 'content' => $prompt],
],
'temperature' => 0.2,
'response_format' => ['type' => 'json_object'],
]);
return json_decode($response->choices[0]->message->content, true);
}
}
temperatureを0.2に設定しているのは意図的です。値が高いほど創造的な返答になりますが、分類タスクでは一貫性・再現性が重要なため、低めに固定しています。
Step 3:担当者割り当てロジック
分類結果をもとに、DBから担当者を自動選択します。
<?php
namespace App\Services;
use App\Models\Staff;
use App\Models\Inquiry;
class InquiryAssignmentService
{
// カテゴリと担当部門のマッピング
private const CATEGORY_MAP = [
'technical' => 'development',
'sales' => 'sales',
'complaint' => 'management',
'recruitment' => 'hr',
'other' => 'general',
];
public function assign(Inquiry $inquiry, array $classification): Staff
{
$department = self::CATEGORY_MAP[$classification['category']] ?? 'general';
// 対象部門の中で、担当件数が最も少ないスタッフを選択(負荷分散)
$staff = Staff::where('department', $department)
->where('is_active', true)
->withCount(['inquiries' => fn($q) => $q->whereDate('created_at', today())])
->orderBy('inquiries_count', 'asc')
->firstOrFail();
$inquiry->update([
'staff_id' => $staff->id,
'category' => $classification['category'],
'priority' => $classification['priority'],
'ai_summary' => $classification['summary'],
]);
return $staff;
}
}
Step 4:Controllerから呼び出す
<?php
namespace App\Http\Controllers;
use App\Http\Requests\InquiryRequest;
use App\Models\Inquiry;
use App\Services\InquiryClassifierService;
use App\Services\InquiryAssignmentService;
use App\Notifications\NewInquiryAssigned;
class InquiryController extends Controller
{
public function store(
InquiryRequest $request,
InquiryClassifierService $classifier,
InquiryAssignmentService $assigner
) {
// 問い合わせを保存
$inquiry = Inquiry::create($request->validated());
// AI分類(失敗しても処理を止めない)
try {
$classification = $classifier->classify($inquiry->body);
$staff = $assigner->assign($inquiry, $classification);
$staff->notify(new NewInquiryAssigned($inquiry));
} catch (\Throwable $e) {
// 分類失敗時はデフォルト担当者へ
logger()->error('AI classification failed', ['error' => $e->getMessage()]);
// fallback処理
}
return redirect()->back()->with('success', 'お問い合わせを受け付けました。');
}
}
ポイントはtry-catchでAI処理を囲んでいる点です。APIが一時的にダウンしても問い合わせの受付自体は止まらないよう設計しています。
よくある失敗パターンと対処法
❌ 失敗1:プロンプトが曖昧で分類が安定しない
「分類してください」だけでは、AIの返答がカテゴリ名だったり文章だったり、毎回バラバラになります。返答形式を厳密に定義し、response_format: json_objectを必ず指定しましょう。また、カテゴリの定義が曖昧だと「技術」と「その他」に揺れが生じます。自社でよくある問い合わせパターンを5〜10件用意し、プロンプトに具体例として含めると精度が格段に上がります。
❌ 失敗2:API呼び出しを同期処理で行ってしまう
OpenAI APIのレスポンスには0.5〜3秒程度かかります。これをリクエストの同期処理に組み込むと、フォーム送信後にユーザーが数秒待たされます。Laravelのキュー(dispatch(new ClassifyInquiryJob($inquiry)))を使って非同期処理にするのが正解です。ユーザーへは即座に「受け付けました」を返し、バックグラウンドで分類・割り当てを行います。
❌ 失敗3:コスト管理を忘れる
gpt-4oをそのまま使うと、月間500件の問い合わせで数千円の費用になるケースもあります。分類タスクはgpt-4o-miniで十分な精度が出るため、用途に応じてモデルを選択することが重要です。また、LaravelのRateLimiterやOpenAIのUsage制限を設定し、想定外のコスト増を防ぎましょう。
導入後の変化:実案件から
冒頭で紹介した製造業のクライアントでは、このシステムを導入した結果、問い合わせへの初回返信までの平均時間が6.2時間から1.8時間に短縮されました。担当者の振り分けミスはほぼゼロになり、総務担当者の日次対応工数も約40分の削減を実現しています。
AIの分類精度は最初から100%ではありません。最初の2週間は分類ログをレビューし、プロンプトを3回調整しました。「提携依頼なのにsalesに分類される」「製品クレームがtechnicalと判定される」といった揺れは、プロンプトの定義文を具体化することで解消できました。AIは設定して終わりではなく、運用しながら育てるものという認識が大切です。
このAI技術、御社の業務にも導入できます
AI導入・業務自動化
ChatGPT活用や業務自動化など、最新のAI技術を御社に合わせてご提案します
※ 通常1営業日以内にご返信します
まとめと次のステップ
ChatGPT APIとLaravelを組み合わせた問い合わせ自動仕分けは、正しく設計すれば1〜2週間のスプリントで実用レベルに到達できる施策です。ただし、プロンプト設計・非同期処理・コスト管理・フォールバック設計をセットで考えないと、途中で運用が崩れる可能性があります。
まず取り組むべきアクションは以下の通りです。
「実装してみたけど分類精度が上がらない」「どのモデルを選べばいいか判断できない」という場合は、ぜひFivenine Designへご相談ください。Laravelを中心としたAI連携システムの設計・実装を、神奈川を拠点に20年以上の経験でサポートします。