실무에서 적용하는 LLM 가드레일: 실제로 효과적인 전략

모델이 아닌 위험을 관리하십시오.

Page content

LLM은 예측 불가능합니다. 할루시네이션(환각)을 일으키거나, 데이터를 유출하거나, 해로운 콘텐츠를 생성하거나, 정당한 요청을 거부하기도 합니다. 가드레일(Guardrails)은 모델의 기능을 희생하지 않으면서도 모델의 행동을 제한합니다.

핵심은 어떤 가드레일이 중요한지, 어떤 것은 그저 잡음인지 파악하는 것입니다.

가드레일은 모델을 통제하는 것이 아닙니다. 위험을 통제하는 것입니다.

실무에서의 LLM 가드레일

입력 검증

가장 중요한 가드레일입니다. 잘못된 입력은 잘못된 출력을 초래하며, 시스템에 프롬프트 인젝션을 유발할 수도 있습니다.

전략 1: 프롬프트 정제(Prompt Sanitization)

위험한 패턴을 조기에 정제하세요:

import re

class PromptSanitizer:
    def __init__(self):
        self.dangerous_patterns = [
            r"ignore\s+previous\s+instructions",
            r"system\s+prompt",
            r"you\s+are\s+now\s+free",
            r"break\s+out\s+of",
        ]

    def sanitize(self, prompt: str) -> str:
        for pattern in self.dangerous_patterns:
            prompt = re.sub(pattern, "[REDACTED]", prompt, flags=re.IGNORECASE)
        return prompt

이는 불투명하지 않습니다. 적대적 입력은 창의적이기 때문입니다. 하지만 명백한 공격은 잡아내며, 명백한 공격이 가장 흔합니다.

전략 2: 입력 길이 제한

길이 제한은 토큰 낭비와 타임아웃을 방지합니다:

class InputValidator:
    def __init__(self, max_length: int = 10000):
        self.max_length = max_length

    def validate(self, prompt: str) -> tuple[bool, str]:
        if len(prompt) > self.max_length:
            return False, f"Input too long: {len(prompt)} > {self.max_length}"
        return True, "OK"

전략 3: 콘텐츠 필터링

콘텐츠 필터링은 정책 위반을 차단합니다. 여기서 사용되는 패턴은 도메인에 따라 다릅니다:

class ContentFilter:
    def __init__(self):
        self.blocked_topics = [
            "violence", "hate speech", "self-harm",
            "sexual content", "illegal activities",
        ]

    def filter(self, prompt: str) -> tuple[bool, str]:
        prompt_lower = prompt.lower()
        for topic in self.blocked_topics:
            if topic in prompt_lower:
                return False, f"Blocked: {topic}"
        return True, "OK"

간단한 문자열 매칭은 빠르지만 부정확합니다. 프로덕션 환경에서는 정책 위반을 감지하기 위해 분류기 모델을 사용하세요. qwen3-1.7b와 같은 작은 모델이라도 괜찮습니다. 더 정확하고 우회하기 어렵습니다.

출력 필터링

모델의 출력도 확인해야 합니다. 구조, 콘텐츠, 사실 관계 모두입니다.

전략 1: 응답 검증

먼저 구조를 검증하세요. JSON을 기대한다면 JSON을 확인하세요:

class ResponseValidator:
    def __init__(self):
        self.required_fields = ["answer", "confidence"]

    def validate(self, response: dict) -> tuple[bool, str]:
        for field in self.required_fields:
            if field not in response:
                return False, f"Missing field: {field}"
        return True, "OK"

전략 2: 콘텐츠 필터링

해로운 콘텐츠를 필터링하세요:

class OutputFilter:
    def __init__(self):
        self.blocked_patterns = [
            r"kill\s+someone",
            r"bomb\s+recipe",
            r"hate\s+speech",
            r"self-harm",
        ]

    def filter(self, response: str) -> tuple[bool, str]:
        for pattern in self.blocked_patterns:
            if re.search(pattern, response, re.IGNORECASE):
                return False, f"Blocked: {pattern}"
        return True, "OK"

전략 3: 사실 확인

사실 확인은 더 어렵습니다. 모든 주장을 검증할 수는 없으므로, 중요한 것을 선택하세요:

class FactChecker:
    def __init__(self):
        self.known_facts = {
            "capital of france": "Paris",
            "population of usa": "330 million",
            "speed of light": "299,792,458 m/s",
        }

    def check(self, claim: str) -> tuple[bool, str]:
        claim_lower = claim.lower()
        for fact, truth in self.known_facts.items():
            if fact in claim_lower and truth not in claim_lower:
                return False, f"Fact check failed: {fact}"
        return True, "OK"

진정한 사실 확인을 위해서는 검색 파이프라인이 필요합니다. 하드코딩된 사전이 아닌 지식 베이스와 주장을 비교해야 합니다.

안전 메커니즘

전략 1: 속도 제한(Rate Limiting)

속도 제한은 남용을 방지합니다:

import time
from collections import deque

class RateLimiter:
    def __init__(self, max_requests: int = 10, window: int = 60):
        self.max_requests = max_requests
        self.window = window
        self.requests = deque()

    def allow(self) -> bool:
        now = time.time()
        while self.requests and self.requests[0] < now - self.window:
            self.requests.popleft()

        if len(self.requests) >= self.max_requests:
            return False

        self.requests.append(now)
        return True

전략 2: 토큰 예산 관리(Token Budgeting)

토큰 예산 관리는 요청당 비용을 상한선으로 제한합니다:

class TokenBudget:
    def __init__(self, max_tokens: int = 1000):
        self.max_tokens = max_tokens

    def validate(self, response: str) -> tuple[bool, str]:
        token_count = len(response.split())
        if token_count > self.max_tokens:
            return False, f"Token limit exceeded: {token_count} > {self.max_tokens}"
        return True, "OK"

전략 3: 컨텍스트 윈도우 관리

컨텍스트 윈도우 관리는 오버플로우를 방지합니다:

class ContextManager:
    def __init__(self, max_context: int = 4096):
        self.max_context = max_context
        self.context = []

    def add(self, message: str):
        self.context.append(message)
        self.trim()

    def trim(self):
        while len(" ".join(self.context)) > self.max_context:
            self.context.pop(0)

슬라이딩 윈도우 트리밍은 간단하지만 초기 컨텍스트를 잃게 됩니다. 더 나은 접근법으로는 요약 또는 주의 기반(attention-based) 압축이 있지만, 이는 지연 시간을 증가시킵니다.

규정 준수(Compliance)

엔터프라이즈 시스템에는 규정 준수 가드레일이 필요합니다. 가장 중요한 두 가지가 있습니다:

패턴 1: 데이터 거주(Data Residency)

데이터 거주 — 데이터가 필요한 지리적 경계 내에 있도록 보장합니다:

class DataResidency:
    def __init__(self, allowed_regions: list[str]):
        self.allowed_regions = allowed_regions

    def validate(self, region: str) -> tuple[bool, str]:
        if region not in self.allowed_regions:
            return False, f"Region not allowed: {region}"
        return True, "OK"

패턴 2: 감사 로깅(Audit Logging)

감사 로깅 — 모든 모델 상호작용을 로깅합니다:

import json
from datetime import datetime

class AuditLogger:
    def __init__(self, log_file: str = "audit.log"):
        self.log_file = log_file

    def log(self, request: dict, response: dict):
        entry = {
            "timestamp": datetime.now().isoformat(),
            "request": request,
            "response": response,
        }
        with open(self.log_file, "a") as f:
            f.write(json.dumps(entry) + "\n")

감사 로그는 디버깅과 규정 준수에 중요합니다. 구조화되고 추가 전용(append-only)이며 안전하게 저장되도록 하세요.

통합하기

패턴 1: 간단한 가드레일

간단한 가드레일 파이프라인입니다:

class SimpleGuardrails:
    def __init__(self):
        self.input_validator = InputValidator(max_length=10000)
        self.output_filter = OutputFilter()

    def process(self, prompt: str) -> str:
        valid, message = self.input_validator.validate(prompt)
        if not valid:
            return f"Error: {message}"

        response = self.call_model(prompt)

        valid, message = self.output_filter.filter(response)
        if not valid:
            return f"Error: {message}"

        return response

패턴 2: 고급 가드레일

고급 가드레일은 정제, 속도 제한, 토큰 예산을 추가합니다:

class AdvancedGuardrails:
    def __init__(self):
        self.sanitizer = PromptSanitizer()
        self.input_validator = InputValidator(max_length=10000)
        self.content_filter = ContentFilter()
        self.output_filter = OutputFilter()
        self.rate_limiter = RateLimiter(max_requests=10)
        self.token_budget = TokenBudget(max_tokens=1000)

    def process(self, prompt: str) -> str:
        prompt = self.sanitizer.sanitize(prompt)

        valid, message = self.input_validator.validate(prompt)
        if not valid:
            return f"Error: {message}"

        valid, message = self.content_filter.filter(prompt)
        if not valid:
            return f"Error: {message}"

        if not self.rate_limiter.allow():
            return "Error: Rate limit exceeded"

        response = self.call_model(prompt)

        valid, message = self.output_filter.filter(response)
        if not valid:
            return f"Error: {message}"

        valid, message = self.token_budget.validate(response)
        if not valid:
            return f"Error: {message}"

        return response

가드레일이 중요한 시점

사용자 중심 시스템을 구축하거나, 민감한 데이터를 처리하거나, 프로덕션 환경에서 실행할 때 가드레일은 중요합니다. GDPR, HIPAA, SOC 2와 같은 규정 준수 요구 사항이 있을 때도 중요합니다.

프로토타이핑 중이거나, 모델이 내부 도구에만 사용되거나, 민감한 데이터를 처리하지 않는다면 중요하지 않습니다. 필요할 때까지 건너뛰세요.

Tradeoff는 항상 기능 대 안전성입니다. 더 많은 가드레일은 더 적은 실패를 의미하지만, 동시에 더 적은 기능도 의미합니다. 시스템에 적합한 균형을 찾으세요.

Tradeoffs

전략 안전성 기능 지연 시간
가드레일 없음 가장 낮음 가장 높음 가장 낮음
입력 검증 높음 중간 낮음
출력 필터링 높음 중간 낮음
안전 메커니즘 가장 높음 가장 낮음 가장 높음
규정 준수 가장 높음 가장 낮음 가장 높음

관련 자료

구독하기

시스템, 인프라, AI 엔지니어링에 관한 새 글을 받아보세요.