LLM-vägledningslinjer i praktiken: Vad som faktiskt fungerar

Kontrollera risken, inte bara modellen.

Sidinnehåll

LLM:er är oförutsägbara. De hallucinerar, läcker data, genererar skadligt innehåll eller vägrar legitima begäran. Skyddsnivåer (guardrails) begränsar modellens beteende utan att offra kapacitet.

Nyckeln är att veta vilka skyddsnivåer som är viktiga och vilka som bara är brus.

Skyddsnivåer handlar inte om att kontrollera modellen. De handlar om att kontrollera risken.

LLM-guardrails i praktiken

Inmatningsvalidering

Den viktigaste skyddsnivån. Dålig inmatning ger dålig utmatning, och dålig inmatning kan också prompt-injicera ditt system.

Strategi 1: Prompt-sanitering

Sanitera farliga mönster tidigt:

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

Detta är inte bulttätt. Motståndarliga inmatningar är kreativa. Men det fångar de uppenbara, och de uppenbara är de vanligaste.

Strategi 2: Begränsningar för inmatningslängd

Längdbegränsningar förhindrar token-slöseri och tidsöverskridningar:

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"

Strategi 3: Innehållsfiltrering

Innehållsfiltrering blockerar policyöverträdelser. Mönstren här beror på din domän:

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"

Enkel strängmatchning är snabb men imprecis. För produktion, använd en klassificeringsmodell — även en liten som Qwen2.5-1.5B — för att upptäcka policyöverträdelser. Det är mer exakt och svårare att kringgå.

Utmatningsfiltrering

Modellens utmatning behöver också kontrolleras. Struktur, innehåll och fakta.

Strategi 1: Svarvalidering

Validera strukturen först. Om du förväntar dig JSON, kontrollera efter 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"

Strategi 2: Innehållsfiltrering

Filtrera skadligt innehåll:

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"

Strategi 3: Faktagranskning

Faktagranskning är svårare. Du kan inte validera varje påstående, så välj de som är viktiga:

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"

För riktig faktagranskning behöver du ett hämtningssystem (retrieval pipeline). Kontrollera påståenden mot en kunskapsbas, inte ett hårdkodat ordbok.

Säkerhetsmekanismer

Strategi 1: Begränsning av begäranstakt

Begränsning av begäranstakt förhindrar missbruk:

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

Strategi 2: Tokenbudgettering

Tokenbudgettering sätter tak för kostnader per begäran:

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"

Strategi 3: Hantering av kontextfönster

Hantering av kontextfönster förhindrar överflöd:

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)

Skjutande fönsterklippning är enkel men förlorar tidig kontext. Bättre metoder använder sammanfattning eller uppmärksamhetsbaserad kompression, men dessa lägger till latens.

Efterlevnad

Företagssystem behöver skyddsnivåer för efterlevnad. Två som är viktigast:

Mönster 1: Dataresidens

Dataresidens — säkerställ att data stannar inom krävda geografiska gränser:

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"

Mönster 2: Revisionsloggning

Revisionsloggning — logga alla modellinteraktioner:

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")

Revisionsloggar är kritiska för felsökning och efterlevnad. Gör dem strukturerade, append-only och lagrade säkert.

Sätta ihop det

Mönster 1: Enkla skyddsnivåer

En enkel skyddsnivåpipeline:

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

Mönster 2: Avancerade skyddsnivåer

Avancerade skyddsnivåer lägger till sanitering, begränsning av begäranstakt och tokenbudgeter:

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

När skyddsnivåer är viktiga

Skyddsnivåer är viktiga när du bygger användarförsystem, hanterar känslig data eller kör i produktion. De är också viktiga när du har efterlevnads krav — GDPR, HIPAA, SOC 2.

De är inte viktiga när du prototypar, använder modeller endast för interna verktyg, eller inte hanterar känslig data. Hoppa över dem tills du behöver dem.

Kompromissen är alltid kapacitet mot säkerhet. Fler skyddsnivåer betyder färre fel men också färre kapaciteter. Hitta balansen som fungerar för ditt system.

Kompromisser

Strategi Säkerhet Kapacitet Latens
Inga skyddsnivåer Lägst Högst Lägst
Inmatningsvalidering Hög Medel Låg
Utmatningsfiltrering Hög Medel Låg
Säkerhetsmekanismer Högst Lägst Högst
Efterlevnad Högst Lägst Högst

Relaterat

Prenumerera

Få nya inlägg om system, infrastruktur och AI-ingenjörskonst.