UGC 리뷰 AI 모더레이션: 악성 리뷰 자동 필터링과 신뢰도 설계

이커머스

리뷰 시스템UGC 모더레이션AI 필터링신뢰도 설계어뷰징 방지

이 글은 누구를 위한 것인가

  • 가짜 리뷰와 어뷰징으로 리뷰 시스템 신뢰도가 떨어진 팀
  • 리뷰 모더레이션을 수동으로 하다가 CS 팀이 지친 상황
  • 셀러의 리뷰 조작을 감지하고 싶은 마켓플레이스 운영팀

들어가며

리뷰는 전환율에 직결된다. 하지만 가짜 리뷰, 비방 리뷰, 스팸이 섞이면 오히려 신뢰를 잃는다. AI 기반 자동 모더레이션으로 품질 좋은 리뷰만 노출하면 전환율이 올라간다.

이 글은 bluefoxdev.kr의 이커머스 리뷰 시스템 설계 를 참고하여 작성했습니다.


1. 리뷰 신뢰도 점수 설계

[리뷰 신뢰도 신호]

구매 검증:
  실구매자 리뷰: +30점
  반품 후 리뷰: -20점

리뷰 품질:
  50자 이상: +10점
  사진 첨부: +15점
  동영상 첨부: +20점
  구체적 키워드(사이즈, 색상, 소재): +5점

작성자 신뢰도:
  계정 생성 30일 이상: +10점
  리뷰 이력 5개 이상: +10점
  평균 별점이 3-4점대(1점/5점만 주는 계정 의심): +5점

어뷰징 패턴:
  동일 IP 복수 리뷰: -50점
  작성 시간 < 5분: -30점
  동일 셀러 상품만 고평점: -40점
  복사-붙여넣기 텍스트: -50점

2. AI 모더레이션 파이프라인

import anthropic
from dataclasses import dataclass

@dataclass
class ReviewModerationResult:
    approved: bool
    confidence: float
    flags: list[str]  # 'spam', 'fake', 'inappropriate', 'competitor_attack'
    reason: str
    action: str  # 'auto_approve', 'auto_reject', 'human_review'

client = anthropic.Anthropic()

async def moderate_review(review: dict) -> ReviewModerationResult:
    """LLM 기반 리뷰 모더레이션"""
    
    prompt = f"""다음 이커머스 리뷰를 분석해서 JSON으로 응답하세요.

리뷰 내용: {review['content']}
별점: {review['rating']}점
상품명: {review['product_name']}

판단 기준:
1. spam: 광고성, 무관한 내용, 반복 텍스트
2. fake: 지나치게 완벽한 칭찬, 자연스럽지 않은 표현
3. inappropriate: 욕설, 비방, 개인정보
4. competitor_attack: 경쟁사 홍보, 의도적 별점 테러

JSON 형식:
{{
  "approved": true/false,
  "confidence": 0.0-1.0,
  "flags": [],
  "reason": "판단 이유 한 줄"
}}"""

    response = client.messages.create(
        model="claude-haiku-4-5-20251001",  # 빠르고 저렴한 모델
        max_tokens=200,
        messages=[{"role": "user", "content": prompt}]
    )
    
    import json
    result = json.loads(response.content[0].text)
    
    # 신뢰도에 따른 액션 결정
    if result["confidence"] > 0.9:
        action = "auto_approve" if result["approved"] else "auto_reject"
    else:
        action = "human_review"
    
    return ReviewModerationResult(
        approved=result["approved"],
        confidence=result["confidence"],
        flags=result.get("flags", []),
        reason=result["reason"],
        action=action,
    )

async def calculate_trust_score(review: dict, user: dict) -> int:
    """리뷰 신뢰도 점수 계산"""
    score = 0
    
    # 구매 검증
    if review.get("is_verified_purchase"):
        score += 30
    
    # 리뷰 품질
    content_len = len(review.get("content", ""))
    if content_len >= 50:
        score += 10
    if review.get("images"):
        score += 15
    if review.get("video"):
        score += 20
    
    # 작성자 신뢰도
    from datetime import datetime
    account_age = (datetime.now() - user["created_at"]).days
    if account_age >= 30:
        score += 10
    if user.get("review_count", 0) >= 5:
        score += 10
    
    # 어뷰징 패턴
    if review.get("same_ip_reviews_today", 0) > 1:
        score -= 50
    if review.get("write_duration_seconds", 999) < 30:
        score -= 30
    
    return max(0, min(100, score))

3. 셀러 리뷰 조작 탐지

async def detect_seller_manipulation(seller_id: str) -> dict:
    """셀러의 리뷰 조작 패턴 탐지"""
    
    # 최근 30일 리뷰 분석
    reviews = await db.fetch("""
        SELECT r.*, u.created_at as user_created_at,
               u.review_count, u.ip_address
        FROM reviews r
        JOIN users u ON r.user_id = u.id
        JOIN order_items oi ON r.order_id = oi.order_id
        JOIN products p ON oi.product_id = p.id
        WHERE p.seller_id = $1
          AND r.created_at > NOW() - INTERVAL '30 days'
    """, seller_id)
    
    flags = []
    
    # 1. 신규 계정 집중 리뷰
    new_account_ratio = sum(
        1 for r in reviews 
        if (r["created_at"] - r["user_created_at"]).days < 7
    ) / max(len(reviews), 1)
    
    if new_account_ratio > 0.3:
        flags.append({
            "type": "new_account_flood",
            "severity": "high",
            "detail": f"신규 계정 리뷰 비율 {new_account_ratio:.0%}"
        })
    
    # 2. 동일 IP 클러스터
    ip_counts = {}
    for r in reviews:
        ip_counts[r["ip_address"]] = ip_counts.get(r["ip_address"], 0) + 1
    
    suspicious_ips = {ip: cnt for ip, cnt in ip_counts.items() if cnt >= 3}
    if suspicious_ips:
        flags.append({
            "type": "ip_clustering",
            "severity": "critical",
            "detail": f"동일 IP 반복 리뷰: {len(suspicious_ips)}개 IP"
        })
    
    # 3. 별점 분포 이상
    ratings = [r["rating"] for r in reviews]
    five_star_ratio = ratings.count(5) / max(len(ratings), 1)
    if five_star_ratio > 0.85:
        flags.append({
            "type": "rating_manipulation",
            "severity": "medium",
            "detail": f"5점 비율 {five_star_ratio:.0%} (정상 40-60%)"
        })
    
    risk_level = "critical" if any(f["severity"] == "critical" for f in flags) \
        else "high" if any(f["severity"] == "high" for f in flags) \
        else "medium" if flags else "normal"
    
    return {"seller_id": seller_id, "risk_level": risk_level, "flags": flags}

마무리

리뷰 시스템은 자동화와 인간 검토의 조합이 핵심이다. 신뢰도 높은 리뷰(실구매 + 사진 + 상세 텍스트)를 상단에 노출하고, AI로 명백한 어뷰징을 자동 차단하며, 경계선에 있는 리뷰만 운영팀이 검토하는 구조가 효율적이다. 셀러 조작 탐지는 상품 단위가 아닌 셀러 단위로 패턴을 봐야 한다.