Skip to content

フロー&ガードレール設計 — AI口コミ生成

項目内容
ステータス🟡 検討中
関連AI口コミ生成

1. ガードレール概要

システムには品質と安全性を確保する5層の保護がある:


2. ① Rate Limit — 頻度制限

設計

項目内容
制限100回生成/日/店舗
カウント対象generate-review + regenerate-review (Sonnet呼び出し、コスト発生)
適用方法mappy_review_generation_logsのDBカウント
リセット日次(サーバー日付基準)

ロジック

実装

php
private function checkRateLimit(int $shopId): void
{
    $todayCount = ReviewGenerationLog::where('shop_id', $shopId)
        ->whereIn('generation_type', ['initial', 'regenerate', 'tone_change'])
        ->whereDate('created_at', today())
        ->count();

    if ($todayCount >= config('services.review_generator.daily_limit', 100)) {
        throw new RateLimitExceededException();
    }
}

なぜ100/日なのか?

店舗規模アンケート/日生成/アンケート合計/日
小(1店舗)5-10約2回(1生成 + 1再生成)10-20
大(5店舗)20-50約2回40-100

100は大規模店舗に十分。調整が必要な場合 → .envREVIEW_DAILY_LIMIT


3. ② Promptガードレール — Prompt内の制約

LLMが望ましくない出力を生成するのを防ぐため、制約をsystem promptに直接埋め込む:

品質の制約

#制約Prompt内の記述目的
1文字数200-400文字数: 200〜400文字短すぎ/長すぎを防止
2固定構成来店のきっかけ → 体験の詳細 → 感想・まとめロジックの確保
3キーワードの自然さ無理に全て入れる必要はないキーワード詰め込み防止
4多様性毎回異なる書き出し・構成・表現を使う口コミ間の重複防止

AI検出防止の制約

#制約Prompt内の記述目的
5箇条書き禁止箇条書き形式を避けるAIは箇条書きを生成しがち
6機械的な接続詞禁止「まず」「次に」「最後に」を避ける典型的なAIの特徴
7過度な賞賛禁止過度な褒め言葉の連続を避ける不自然
8宣伝口調禁止「〜がおすすめです」を避けるGoogleポリシー違反
9人間的な要素の追加小さな感想や個人的なエピソードを含める実体験感を演出

toneの制約

TonePrompt内の制約
丁寧敬語を使用。30〜50代の落ち着いた印象
カジュアル友人に話すような口調。20〜30代の明るい印象
ビジネス客観的で簡潔。ビジネスパーソンの印象

4. ③ 品質チェック — ハイブリッド品質検査

フロー概要

ステップ1: ルールベース(即時、無料)

#基準最大点ロジック早期失敗
1文字数 (200-400)20mb_strlen()100未満または600超 → LLMスキップ
2キーワード反映 (1-3語)15str_contains()
ステップ1合計35< 15 → LLMスキップ、即座にリトライ

判定マトリクス:

文字数キーワード検出ルール点数アクション
280 (OK)2/330→ LLMチェックへ
150 (NG)1/35→ LLMスキップ、即座にリトライ
350 (OK)0/320→ LLMチェックへ
50 (NG)0/30→ LLMスキップ、即座にリトライ

ステップ2: LLMチェック (Haiku 4.5)

#基準最大点チェック内容
3自然さ(AIっぽくない)30構成、接続詞、多様性
4不適切な表現20宣伝、誇張、事実と異なる
5焦点の反映(選択された項目)15指定された最高星数の項目に口コミが集中しているか
ステップ2合計65

点数の集計

最大最低合格点
ステップ1 (ルール)35
ステップ2 (LLM)65
合計100>= 70

quality_breakdown JSONフォーマット

合格(LLMチェックあり):

json
{
  "rule_based": {
    "char_count": { "score": 20, "detail": "280文字。範囲内。" },
    "keywords": { "score": 10, "detail": "2/3 keyword found" }
  },
  "llm": {
    "naturalness": { "score": 25, "detail": "概ね自然。" },
    "inappropriate": { "score": 20, "detail": "問題なし。" },
    "topic_reflection": { "score": 12, "detail": "指定項目(接客)が中心に反映されている。" },
    "feedback": ""
  },
  "total": 87,
  "passed": true
}

失敗(LLMスキップ):

json
{
  "rule_based": {
    "char_count": { "score": 0, "detail": "52文字。範囲外。" },
    "keywords": { "score": 5, "detail": "1/3 keyword found" }
  },
  "llm": null,
  "total": 5,
  "passed": false
}

5. ④ リトライ戦略

フロー

リトライ詳細

回数Temperature特徴
1 (初回)0.8通常の生成
2 (リトライ1)0.9高く設定 → より異なる出力
3 (リトライ2)0.9前回からの具体的なフィードバック付き

リトライに渡す情報

【前回のスコア】52/100
【改善フィードバック】「まず」「次に」の接続詞が目立つ。箇条書き的な構成を避け...
※ 前回と異なる書き出し・構成で書いてください。

予測統計

結果割合
1回目で合格~80%
リトライ1後に合格~15%
リトライ2後に合格~4%
失敗(3回で終了)~1%

6. ⑤ エラーフォールバック — エラー処理

原則

AIが失敗した場合、常にGoogle Reviewボタンにフォールバック。 顧客のフローを決してブロックしない。

判定マトリクス

エラーHTTPフロントエンド表示フローをブロック?
Anthropic APIタイムアウト503通常のお礼画面 + Google Reviewボタンしない
生成失敗(3回リトライ終了)500"生成に失敗しました" + "もう一度試す"ボタン + Google Reviewボタンしない
Rate limit429"本日の生成上限に達しました" + Google Reviewボタンしない
無効なtone400発生しない(UIが3つのオプションのみ提供)
アンケートが存在しない404発生しない(送信直後のデータを使用)
JSONパース失敗(quality-check)自動リトライ(スコア0)しない

フロントエンドフロー


7. Googleポリシー対策

GoogleがAI口コミを検出する方法

#方法システムでの対策
1テキストパターン分析 — 同一店舗で繰り返しtemperature 0.8 + 実際の評価項目に基づく内容 + "毎回異なる構成"
2投稿時間分析 — 連続投稿1件/フロー、バッチ生成なし
3IP/デバイス分析 — 同一IPから複数投稿顧客が自身のデバイス/アカウントから投稿
4NLP AI検出 — 文体が完璧すぎるPromptで箇条書き・過度な賞賛を禁止、人間的要素を追加
5キーワード密度 — SEOスパム"1〜3個"、"無理に入れない"
6一般的な内容 — 実体験がない実際のアンケートデータから生成

UIでの必須対策

口コミ画面(必須):

⚠ この文章はお客様のアンケート回答をもとにAIが作成した下書きです。
投稿される口コミはお客様ご自身の感想として公開されます。
実際のご体験に合っているかご確認のうえ、必要に応じて編集してからご投稿ください。

投稿ボタン押下後:

口コミの下書きが保存されました。
下記のリンクからGoogleマップを開いて、ご自身のアカウントで投稿してください。
[Googleマップで口コミを書く →]

コンプライアンスチェックリスト

#対策設計済み?
1顧客が自分で投稿(自動投稿なし)✅ Submit → Google Mapsにリダイレクト
2編集を推奨✅ AI警告 + textareaで編集可能
3多様な文体✅ temperature 0.8 + 評価項目に基づく内容 + トーン変更
4自然なキーワード✅ "1〜3個" + "無理に入れない"
51件/フロー✅ バッチ生成なし
6品質チェックでAI検出✅ naturalness score (30点)
7全ログ記録mappy_review_generation_logs

8. モニタリング & メトリクス

監視すべきメトリクス

メトリクスクエリアラート条件
1回目合格率WHERE retry_count = 0 AND quality_score >= 70< 70%
完全失敗率WHERE retry_count >= 3> 5%
日次コストSUM(cost_yen) GROUP BY DATE> ¥1,000
平均レイテンシリクエスト → レスポンスの時間> 15s
Rate limitヒット数429レスポンスのカウント> 10/日

既存のログテーブル

全メトリクスはmappy_review_generation_logsからクエリ可能:

  • quality_score, retry_count → 合格/失敗率
  • cost_yen → コスト
  • input_tokens, output_tokens → usage
  • created_at → レイテンシ(リクエストログと組み合わせ)