Skip to content

Thiết kế Prompt & API — Tự động tạo đánh giá bằng AI

Hạng mụcNội dung
Trạng thái🟡 Đang thảo luận
Liên quan#10 Tự động tạo đánh giá AI

1. Thiết kế Prompt

1.1 Danh sách Prompt

#Tên PromptMục đíchLLM sử dụngGọi từ
1generate_reviewTạo full review từ mục có sao cao nhất (1 lần gọi)Claude Sonnet 4ReviewGeneratorService
2quality_checkKiểm tra chất lượng (phần LLM)Claude Haiku 4.5ReviewGeneratorService
3regenerate_with_feedbackTái tạo khi NG kèm feedbackClaude Sonnet 4ReviewGeneratorService
4regenerate_with_toneTái tạo khi đổi toneClaude Sonnet 4AiReviewController@regenerateReview

1.2 Prompt tạo đánh giá (generate_review)

Tạo full review 200-400 ký tự từ duy nhất mục có số sao cao nhất. Gọi 1 lần duy nhất, không có bước preview.

Logic chọn mục đánh giá (xử lý ở backend trước khi gọi LLM):

  • Lấy mục có số sao cao nhất trong các câu hỏi sao
  • Nếu có nhiều mục cùng số sao cao nhất → ưu tiên theo thứ tự câu hỏi gốc (VD: 接客 → 清潔感 → 満足度, nên 3 mục cùng ★5 thì chọn 接客)
  • Chỉ gửi duy nhất tên mục + số sao vào prompt. Không gửi các câu trả lời khác của khảo sát (các mục sao còn lại, câu text, câu có/không)

Biến đầu vào:

BiếnKiểuMô tảVí dụ
top_itemobjectMục có sao cao nhất (sau tie-break){ name: "接客", rating: 5 }
tonestringTone đánh giáMặc định 丁寧
shop_namestringTên cửa hàng銀座ヘアサロンA
store_keywordsstringKeyword cửa hàng (phân cách bằng dấu phẩy)丁寧な接客, 駅近, 清潔感

Không có survey_answers. Không gửi các mục sao khác hay nội dung câu trả lời khác — giúp prompt gọn (~150 tokens input thay vì ~800).

System Prompt:

あなたは実際の顧客として口コミを書くアシスタントです。
指定された1つの高評価項目を中心に、完全な口コミ文を生成してください。

【トーン】{tone}

【トーン別の文体ガイド】
- 丁寧: 敬語を使用。「〜していただきました」「大変満足しております」。30〜50代の落ち着いた印象。
- カジュアル: 友人に話すような口調。「〜だった!」「めっちゃ良かった」。20〜30代の明るい印象。
- ビジネス: 客観的で簡潔。「サービスの質が高い」「費用対効果が良い」。ビジネスパーソンの印象。

【生成ルール】
1. 文字数: 200〜400文字
2. 焦点: 指定された1つの項目を中心に書く。他の話題に広げすぎない
3. 構成: 来店のきっかけ → 指定項目の体験詳細 → 感想・まとめ
4. キーワード: 指定キーワードを文脈に合わせて自然に1〜3個含める。無理に全て入れる必要はない
5. 自然さ: 以下を避ける
   - 箇条書き形式
   - 「まず」「次に」「最後に」のような明確な段落構成語
   - 過度な褒め言葉の連続
   - 全てのキーワードを機械的に詰め込む
   - 「〜がおすすめです」のような宣伝口調
6. 人間らしさ: 小さな感想や個人的なエピソードを含めて、実体験感を出す

Human Prompt:

以下の情報を元に、200〜400文字の完全な口コミ文を生成してください。

【店舗名】{shop_name}
【中心にする項目】{top_item.name}(★{top_item.rating})
【店舗キーワード】{store_keywords}
【トーン】{tone}

Tham số LLM:

Tham sốGiá trịLý do
modelclaude-sonnet-4-20250514Chất lượng tiếng Nhật tốt
temperature0.8Tạo văn phong đa dạng
max_tokens800400 ký tự (~600 tokens) + dư

Ví dụ đầu ra:

Mục được chọn: 接客 (★5)

初めて銀座ヘアサロンAを利用いたしました。スタッフの方がとても親切で、カウンセリングも丁寧に対応してくださり、初めてでも安心して任せられる雰囲気でした。髪の悩みをしっかり聞いた上で、似合うスタイルを提案してくださり、仕上がりも想像以上でした。駅から近く通いやすい立地も魅力で、次回もぜひお願いしたいと思います。

※ Toàn bộ review tập trung vào 1 mục "接客" — không đề cập tới các mục sao khác trong khảo sát

Response time: 5-10 giây (Sonnet + output ~400 ký tự)

1.4 Kiểm tra chất lượng — Hybrid

Kiểm tra chất lượng chia thành 2 bước (hybrid):

Bước 1: Rule-based (tức thì, miễn phí)

#Tiêu chíĐiểmCách kiểm traFail sớm?
1Số ký tự (200〜400)20 điểmmb_strlen()Dưới 100 hoặc trên 600 → retry ngay
2Phản ánh keyword (1〜3 từ)15 điểmstr_contains()
  • Nếu tổng bước 1 < 15 điểm → bỏ qua bước 2, retry ngay (tiết kiệm 1 lần gọi LLM)
  • Nếu tổng bước 1 >= 15 điểm → tiếp tục bước 2

Bước 2: LLM (chỉ cho tiêu chí cần ngữ nghĩa)

#Tiêu chíĐiểmCách kiểm tra
3Tự nhiên (không có cảm giác AI)30 điểmClaude Haiku 4.5
4Biểu đạt không phù hợp20 điểmClaude Haiku 4.5
5Phản ánh đúng trọng tâm (mục đã chọn)15 điểmClaude Haiku 4.5

Model sử dụng: Claude Haiku 4.5 (temperature: 0.1 — để kết quả đánh giá ổn định)

Tiêu chuẩn đạt: Tổng (bước 1 + bước 2) >= 70 điểm → Đạt / Dưới 70 → Tái tạo (tối đa 3 lần)

Prompt cho LLM quality check (bước 2):

以下の口コミ文を評価してください。JSON形式で回答してください。

【評価項目】
1. naturalness (0〜30点): AI生成と分かる表現がないか。箇条書き・過度な褒め・均一な構成を減点
2. inappropriate (0〜20点): 不適切表現・誇大広告・事実と異なる表現がないか
3. topic_reflection (0〜15点): 指定された項目({top_item.name})が中心に反映されているか

【口コミ文】
{review_text}

【中心にすべき項目】{top_item.name}(★{top_item.rating})

JSON形式で回答:
{"naturalness": 点数, "inappropriate": 点数, "topic_reflection": 点数, "feedback": "改善点(なければ空文字)"}

Quality check chỉ nhận tên mục + số sao, không nhận toàn bộ survey answers — đồng nhất với cách prompt generate chỉ tập trung 1 chủ đề.

Định dạng JSON đầu ra:

json
{
  "naturalness": 25,
  "inappropriate": 20,
  "topic_reflection": 12,
  "feedback": "「まず」「次に」の接続詞が目立つ。もう少し自然な流れに。"
}

JSON parse safety

LLM có thể trả text thừa trước/sau JSON. Cần extract JSON bằng regex trước khi parse:

php
// Extract JSON từ response (LLM có thể trả text thừa)
private function parseJsonResponse(string $response): array
{
    // Tìm JSON object đầu tiên trong response
    if (preg_match('/\{[^{}]*\}/', $response, $matches)) {
        $decoded = json_decode($matches[0], true);
        if (json_last_error() === JSON_ERROR_NONE) {
            return $decoded;
        }
    }
    // JSON parse fail → coi như quality check fail, trigger retry
    return [
        'naturalness' => 0,
        'inappropriate' => 0,
        'topic_reflection' => 0,
        'feedback' => 'Quality check JSON parse failed, retrying...',
    ];
}

Khi JSON parse fail, không throw exception mà trả điểm 0 → trigger retry tự nhiên trong flow.

1.5 Prompt tái tạo

Khi chất lượng NG (regenerate_with_feedback)

System Prompt: Giống generate_review (mục 1.2)

Human Prompt:

以下の情報から口コミ文を生成してください。
前回の生成は品質チェックで不合格でした。フィードバックを参考に改善してください。

【前回のスコア】{previous_score}/100
【改善フィードバック】{feedback}

【店舗名】{shop_name}
【中心にする項目】{top_item.name}(★{top_item.rating})
【店舗キーワード】{store_keywords}
【トーン】{tone}

※ 前回と異なる書き出し・構成で書いてください。
Tham sốGiá trịLý do
modelclaude-sonnet-4-20250514Giữ chất lượng
temperature0.9Cao hơn để tạo văn khác lần trước
max_tokens800

Khi đổi tone (regenerate_with_tone)

System Prompt: Giống generate_review nhưng {tone} thay đổi

Human Prompt:

以下の情報から口コミ文を生成してください。
前回は「{previous_tone}」トーンで生成しましたが、今回は「{tone}」トーンで新しく生成してください。

【店舗名】{shop_name}
【中心にする項目】{top_item.name}(★{top_item.rating})
【店舗キーワード】{store_keywords}
【トーン】{tone}

※ 前回の文章「{previous_review_snippet}」の言い回しを流用しないでください。
Tham sốGiá trịLý do
modelclaude-sonnet-4-20250514Giữ chất lượng
temperature0.8Đa dạng nhưng ổn định
max_tokens800

previous_review_snippet: 50 ký tự đầu của bản trước, để LLM biết cần tránh lặp lại.

1.6 Giá trị cấu hình tuning

Cài đặtGiá trị mặc địnhPhạm vi điều chỉnh
Điểm đạt7050〜90
Số lần retry tối đa31〜5
Số ký tự tối thiểu200100〜300
Số ký tự tối đa400300〜600

Quản lý hằng số trong config/anthropic.phpreview_generator. Sau này có thể thay đổi từ màn hình quản lý.

php
// config/anthropic.php
'review_generator' => [
    'pass_score' => env('REVIEW_PASS_SCORE', 70),
    'max_retries' => env('REVIEW_MAX_RETRIES', 3),
    'min_chars' => env('REVIEW_MIN_CHARS', 200),
    'max_chars' => env('REVIEW_MAX_CHARS', 400),
],

2. Thiết kế API (Laravel trực tiếp)

2.1 Cấu trúc hệ thống

Frontend (Vue.js) → Laravel API (hiện có) → Anthropic API (HTTPS)
  • Frontend → Laravel: Xác thực/quản lý session xử lý bên Laravel hiện có
  • Laravel → Anthropic API: Gọi HTTPS trực tiếp bằng Guzzle HTTP client
  • Không cần Python FastAPI, không cần service riêng

2.2 Endpoint Laravel API (Guest — không cần đăng nhập)

Các endpoint dưới đây được gọi từ màn hình khảo sát (guest), nằm trong group route guest hiện có.

POST /guest/questionnaires/generate-review — Tạo full review từ mục sao cao nhất (1 lần gọi)

Request:

json
{
  "questionnaireId": 201,
  "answerSet": 42,
  "hash": "abc123"
}

answerSet là giá trị trả về từ saveAnswers response. Phải truyền giá trị cụ thể để tránh race condition (nhiều khách submit cùng lúc).

Không cần selected_preview, selectedItem hay survey answers — backend tự chọn mục có sao cao nhất từ answerSet.

Luồng xử lý backend:

  1. Lấy câu trả lời khảo sát từ questionnaireId + answerSet
  2. Lọc các câu hỏi dạng đánh giá sao (★), chọn mục có số sao cao nhất
  3. Tie-break: ưu tiên theo thứ tự câu hỏi gốc (VD: 接客 → 清潔感 → 満足度)
  4. Lấy store_keywords: mappy_review_keywords → fallback mappy_keywords
  5. Lấy shop_name từ cửa hàng
  6. Xây prompt chỉ với top_item (name + rating) + keywords + tone (mặc định 丁寧). Không gửi survey answers khác.
  7. Gọi Anthropic API (Sonnet 4) tạo full review
  8. Kiểm tra chất lượng hybrid (rule-based → LLM)
  9. Retry nếu NG (tối đa 3 lần)
  10. Trả kết quả về frontend

Response:

json
{
  "status": "success",
  "data": {
    "review_text": "初めて銀座ヘアサロンAを利用いたしました。スタッフの方がとても親切で、カウンセリングも丁寧に対応してくださり...",
    "top_item": { "name": "接客", "rating": 5 },
    "char_count": 280,
    "quality_score": 85,
    "tone_used": "丁寧",
    "retry_count": 0
  }
}

top_item được trả về để frontend gửi lại ở các request regenerate tiếp theo (tránh query DB lại).

Timeout: 30 giây

POST /guest/questionnaires/regenerate-review — Đổi tone / tái tạo

Request:

json
{
  "questionnaireId": 201,
  "answerSet": 42,
  "hash": "abc123",
  "tone": "カジュアル",
  "top_item": { "name": "接客", "rating": 5 },
  "previous_review": "初めて銀座ヘアサロンAを...",
  "previous_tone": "丁寧"
}

Frontend gửi lại top_item đã nhận từ response generate-review trước đó, giữ nguyên trọng tâm của review.

Response: Cùng format với generate-review

POST /guest/questionnaires/submit-review — Lưu đánh giá + trả URL đăng Google

Request:

json
{
  "questionnaireId": 201,
  "answerSet": 42,
  "hash": "abc123",
  "review_text": "初めて銀座ヘアサロンAを...",
  "top_item": { "name": "接客", "rating": 5 },
  "tone": "丁寧",
  "edited": true,
  "quality_score": 85
}

Response:

json
{
  "success": true,
  "data": {
    "review_id": 789,
    "google_review_url": "https://search.google.com/local/writereview?placeid=XXXXX"
  }
}

Frontend sử dụng google_review_url cho nút gộp "Copy & đăng Google Review": copy review_text vào clipboard rồi window.open(google_review_url) trong cùng 1 click.

Việc đăng thực tế do người dùng tự thực hiện bằng tài khoản Google của họ (đối sách Google).

2.3 Cấu trúc code Laravel

app/
├── Http/Controllers/Mappy/
│   ├── Guest/
│   │   ├── QuestionnaireController.php    ← Sửa: saveAnswers trả answer_set
│   │   └── AiReviewController.php         ← MỚI: 4 endpoint AI review
│   └── ReviewKeywordsController.php       ← MỚI: CRUD keyword cho AI review
├── Services/Mappy/
│   ├── ReviewGeneratorService.php         ← MỚI: Logic tạo + quality check + fallback keyword
│   └── AnthropicApiService.php            ← MỚI: Wrapper gọi Claude API
├── Models/Mappy/
│   ├── Review.php                         ← MỚI
│   ├── ReviewGenerationLog.php            ← MỚI
│   └── ReviewKeyword.php                  ← MỚI
resources/js/mappy/views/
├── guest/
│   ├── Questionnaire.vue                  ← Sửa: gọi generate-review sau submit (không có Step chọn preview)
│   └── ReviewPreview.vue                  ← MỚI: Component hiển thị full review + chỉnh sửa + nút gộp Copy & đăng Google
└── keywords/
    └── ReviewKeywordSettings.vue          ← MỚI: Màn cài đặt keyword cho review
config/
└── anthropic.php                          ← MỚI: Anthropic API + review_generator config

AnthropicApiService — Gọi Claude API:

php
// app/Services/Mappy/AnthropicApiService.php
class AnthropicApiService
{
    /**
     * @param string $model      Model ID (sonnet/haiku)
     * @param array  $messages   [['role' => 'user', 'content' => '...']]
     * @param float  $temperature
     * @param int    $maxTokens
     * @param string $system     System prompt (Anthropic API yêu cầu gửi riêng, không trong messages)
     */
    public function call(string $model, array $messages, float $temperature = 0.8, int $maxTokens = 1024, string $system = ''): string
    {
        $payload = [
            'model' => $model,
            'max_tokens' => $maxTokens,
            'temperature' => $temperature,
            'messages' => $messages,
        ];

        // Anthropic API: system prompt là field riêng, KHÔNG nằm trong messages
        if ($system) {
            $payload['system'] = $system;
        }

        $response = Http::withHeaders([
            'x-api-key' => config('services.anthropic.api_key'),
            'anthropic-version' => '2023-06-01',
        ])->timeout(30)->post('https://api.anthropic.com/v1/messages', $payload);

        if ($response->failed()) {
            throw new AnthropicApiException($response->status(), $response->body());
        }

        return $response->json('content.0.text');
    }
}

Anthropic API format

System prompt phải gửi qua field system riêng, không phải {'role': 'system'} trong messages. Đây là điểm khác biệt so với OpenAI API.

1 API key (ANTHROPIC_API_KEY) dùng chung cho tất cả model (Sonnet, Haiku).

2.4 Thiết kế DB (Bảng mới)

Bảng mappy_review_keywords (MỚI):

CộtKiểuMô tả
idbigint (PK)
user_idvarcharUser ID
gbp_location_idbigintID location Google Business Profile
keywordvarchar(255)Nội dung keyword
sort_ordertinyintThứ tự hiển thị
created_at / updated_attimestamp

Không giới hạn số keyword (khuyến nghị 3-10). Tách riêng khỏi mappy_keywords (dùng cho scraping, tối đa 8) để tránh ảnh hưởng lẫn nhau.

Logic fallback khi lấy keyword:

php
// ReviewGeneratorService.php
private function getKeywords(int $gbpLocationId): array
{
    // 1. Ưu tiên keyword riêng cho review
    $reviewKeywords = ReviewKeyword::where('gbp_location_id', $gbpLocationId)
        ->orderBy('sort_order')
        ->pluck('keyword')
        ->toArray();

    if (!empty($reviewKeywords)) {
        return $reviewKeywords;
    }

    // 2. Fallback: kế thừa từ keyword scraping hiện có
    return Keyword::where('gbp_location_id', $gbpLocationId)
        ->orderBy('keyword_number')
        ->pluck('keyword')
        ->toArray();
}

Bảng mappy_reviews:

CộtKiểuMô tả
idbigint (PK)
questionnaire_idbigint (FK)ID khảo sát
answer_setintNhóm câu trả lời (liên kết mappy_questionnaire_answers)
shop_idbigint (FK)ID cửa hàng
review_texttextNội dung đánh giá cuối cùng
tonevarchar(20)Tone sử dụng
quality_scoreintĐiểm chất lượng
editedbooleanNgười dùng đã chỉnh sửa thủ công hay chưa
sms_log_idbigint (FK, nullable)Liên kết SMS tracking
submitted_attimestamp (nullable)Thời gian đăng lên Google
created_at / updated_attimestamp

Bảng mappy_review_generation_logs:

CộtKiểuMô tả
idbigint (PK)
questionnaire_idbigint (FK)ID khảo sát
answer_setintNhóm câu trả lời
shop_idbigint (FK)ID cửa hàng (dùng cho rate limit)
review_texttextNội dung đánh giá đã tạo
tonevarchar(20)Tone
quality_scoreintĐiểm chất lượng
quality_breakdownjsonChi tiết kiểm tra chất lượng (format bên dưới)
retry_countintSố lần retry
generation_typevarchar(20)initial / retry / regenerate / tone_change
llm_modelvarchar(50)Model sử dụng
input_tokensintSố token đầu vào
output_tokensintSố token đầu ra
cost_yendecimal(10,4)Chi phí (Yên)
created_attimestamp

Prefix bảng

Theo convention hiện tại của project, tất cả bảng dùng prefix mappy_. Tên bảng: mappy_reviews, mappy_review_generation_logs.

quality_breakdown JSON format:

Tách rõ 2 bước (rule-based + LLM) để dễ debug:

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
}

Khi rule-based fail sớm (bỏ qua LLM):

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

2.5 Thay đổi API hiện có

POST /guest/questionnaires (saveAnswers) — Thêm answer_set vào response

API hiện tại chỉ trả 200 OK không có body. Cần thêm answer_set để frontend truyền vào generate-review.

Response (thêm mới):

json
{
  "success": true,
  "answer_set": 42
}

Thay đổi trong QuestionnaireController@saveAnswers:

php
// Hiện tại: return response()->json([], 200);
// Đổi thành:
return response()->json([
    'success' => true,
    'answer_set' => $answerSet,
], 200);

$answerSet đã được tính trong logic hiện tại (max(answer_set) + 1), chỉ cần trả về.

2.6 Route mới

php
// routes/mappy/api.php — Guest routes (không cần login)
Route::post('/questionnaires/generate-review', 'Mappy\Guest\AiReviewController@generateReview');
Route::post('/questionnaires/regenerate-review', 'Mappy\Guest\AiReviewController@regenerateReview');
Route::post('/questionnaires/submit-review', 'Mappy\Guest\AiReviewController@submitReview');

// routes/mappy/api.php — Authenticated routes (cần login, dành cho admin cửa hàng)
Route::post('/review-keywords', 'Mappy\ReviewKeywordsController@get');
Route::post('/review-keywords/update', 'Mappy\ReviewKeywordsController@update');

2.7 Xử lý lỗi

Mã lỗiHTTPMô tả
SURVEY_NOT_FOUND404Khảo sát không tồn tại
LOW_RATING400Đánh giá thấp (dưới ngưỡng display_google_review_button_at)
GENERATION_FAILED500Tạo LLM thất bại (vượt giới hạn retry)
LLM_UNAVAILABLE503Anthropic API không phản hồi
RATE_LIMIT429Vượt giới hạn (100 lượt/ngày/cửa hàng)
INVALID_TONE400Tone không hợp lệ

2.8 Bảo mật & Hiệu suất

Hạng mụcNội dung
Xác thựcGuest route (không cần login), nhưng cần questionnaireId hợp lệ
Rate limit100 lượt generate/ngày mỗi cửa hàng (count bằng DB)
LogGhi log tất cả request vào mappy_review_generation_logs
Response tạo lần đầuTrong 10 giây (không retry)
Response tối đaTrong 30 giây (có retry)
API KeyANTHROPIC_API_KEY trong .env, quản lý qua config/anthropic.php
php
// .env
ANTHROPIC_API_KEY=sk-ant-xxx

// config/anthropic.php
'anthropic' => [
    'api_key' => env('ANTHROPIC_API_KEY'),
],

Rate limit — enforce bằng DB count:

php
// ReviewGeneratorService.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();
    }
}

Count theo generate-review + regenerate-review (kiểm soát chi phí LLM gọi Sonnet).


3. Đối sách chính sách đánh giá Google

3.1 Phương pháp phát hiện của Google và đối sách

Google phát hiện đánh giá AI bằng các phương pháp sau:

#Phương pháp phát hiệnMô tảĐối sách của hệ thống
1Phân tích mẫu văn bảnCùng cửa hàng có văn phong/cấu trúc lặp lạitemperature 0.8 + 3 tone + chỉ thị "mỗi lần khác nhau"
2Phân tích thời gian đăngNhiều đánh giá trong thời gian ngắnMỗi flow chỉ 1 bài, không tạo hàng loạt
3Phân tích IP/thiết bịNhiều đánh giá từ cùng IP/thiết bịKhách hàng tự đăng từ thiết bị/tài khoản Google của họ
4Phân tích hành vi tài khoảnTài khoản mới chỉ để đăng đánh giáSử dụng tài khoản Google hiện có của khách
5Xử lý ngôn ngữ tự nhiên (NLP)Văn phong đặc trưng AI (cấu trúc quá hoàn hảo)Prompt cấm "liệt kê", "khen quá mức", yêu cầu "giống con người"
6Phân tích mật độ keywordChèn keyword không tự nhiên (SEO spam)"Không ép buộc", "1〜3 keyword" trong prompt
7Tính nhất quán nội dungNội dung chung chung không dựa trên trải nghiệm thựcTạo từ dữ liệu khảo sát thực tế, phản ánh trải nghiệm cụ thể

3.2 Chính sách Google (thời điểm 2025)

Google Maps Content Policy cấm:

  • Nội dung giả mạo: Đánh giá không dựa trên trải nghiệm thực
  • Mạo danh: Đăng với danh nghĩa người khác
  • Spam: Lặp lại cùng nội dung, đăng với mục đích quảng cáo
  • Nội dung tự động tạo: Đăng tự động bằng bot hoặc script

Quan trọng: Google cấm "AI tự động đăng", không cấm rõ ràng việc "AI tạo bản nháp, người dùng xác nhận/chỉnh sửa rồi tự đăng". Tuy nhiên đây là vùng xám, nên phải thực hiện các đối sách dưới đây.

3.3 Đối sách bắt buộc

#Đối sáchCách triển khaiƯu tiên
1Khách hàng tự đăngSau submit hiển thị Google Review URL, khách tự đăng bằng tài khoản mình. Không tự động đăng qua APIBắt buộc
2Khuyến khích chỉnh sửaHiển thị nổi bật trên màn preview "Hãy chỉnh sửa bằng lời của bạn trước khi đăng"Bắt buộc
3Tạo văn phong đa dạngtemperature 0.8, 3 tone, prompt "mỗi lần cấu trúc khác"Bắt buộc
4Chèn keyword tự nhiên"Không ép buộc", "1〜3 keyword" trong promptBắt buộc
5Tạo từng bài mộtKhông làm tính năng tạo hàng loạt. Mỗi flow chỉ 1 bàiBắt buộc
6Khuyến nghị khoảng cách đăngHiển thị trên UI "Khuyến nghị đăng khoảng 1 bài/ngày"Khuyến nghị
7Tiêu chí phát hiện AI trong quality checkTrừ điểm "biểu đạt nhận ra là AI" trong quality_checkBắt buộc
8Ghi logGhi log toàn bộ tạo/đăng vào mappy_review_generation_logsBắt buộc

3.4 Hiển thị cảnh báo trên UI (bắt buộc)

Màn hình review (xem trước & chỉnh sửa):

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

Sau khi nhấn nút đăng Google Review:

Bản nháp đánh giá đã được lưu.
Vui lòng mở Google Maps từ link bên dưới và đăng bằng tài khoản của bạn.
[Viết đánh giá trên Google Maps →]