메인 콘텐츠로 건너뛰기
가드레일은 LLM 평가자(LLM judges)의 점수에 따라 LLM 애플리케이션의 동작에 능동적으로 개입합니다. 출력이 사용자에게 전달되기 전에 실시간으로 동작하며, 점수가 임계값을 초과하면 응답을 차단하거나 수정할 수 있습니다. 가드레일을 사용해 유해한 콘텐츠를 차단하고, 응답에서 개인 식별 정보(PII)를 필터링하거나, 사용자로부터의 악성 입력을 차단할 수 있습니다.

Weave 가드레일이 동작하는 방식

Weave 가드레일은 인라인 Weave Scorers를 사용하여 사용자 입력 또는 LLM 출력물을 평가하고, 실시간으로 LLM 응답을 조정합니다. 사용자 정의 스코어러를 구성하거나 기본 제공 스코어러를 사용하여 다양한 목적에 맞게 콘텐츠를 평가할 수 있습니다. 이 가이드는 두 종류의 스코어러를 모두 가드레일로 사용하는 방법을 보여 줍니다. 애플리케이션의 제어 흐름을 수정하지 않고 운영 트래픽에 대해 패시브하게 점수를 매기고 싶다면, 대신 monitors를 사용하십시오. monitors와 달리, 가드레일은 애플리케이션의 제어 흐름에 영향을 주기 때문에 코드 변경이 필요합니다. 하지만 가드레일에서 생성되는 모든 스코어러 결과는 자동으로 Weave 데이터베이스에 저장되므로, 추가 설정 없이도 가드레일이 monitors처럼 동작합니다. 스코어러가 처음 어떻게 사용되었는지와 관계없이 과거의 스코어러 결과를 분석할 수 있습니다.
Weave TypeScript SDK는 가드레일을 설정하는 데 필요한 도구를 지원하지 않습니다.

Weave guardrail 성능 최적화

guardrail은 애플리케이션의 제어 흐름을 가로막고 응답 방식을 바꿀 수 있기 때문에, 지나치게 복잡하면 성능에 부정적인 영향을 줄 수 있습니다. 최적의 성능을 위해 다음을 권장합니다:
  • guardrail 로직을 단순하고 빠르게 유지하기
  • 자주 사용되는 결과 캐싱하기
  • 비용이 큰 외부 API 호출 피하기
  • guardrail 초기화를 메인 함수 바깥에서 수행해 반복 초기화 비용 피하기
guardrail을 메인 함수 바깥에서 초기화하는 것은 다음과 같은 경우에 특히 중요합니다:
  • scorer가 ML 모델을 로드하는 경우
  • 지연 시간이 중요한 로컬 LLM을 사용하는 경우
  • scorer가 네트워크 연결을 유지하는 경우
  • 트래픽이 많은 애플리케이션인 경우

예제: 내장 moderation scorer를 사용하여 guardrail 생성하기

다음 예제에서는 사용자 프롬프트를 OpenAI의 GPT-4o mini 모델로 전송합니다. 모델의 응답은 이후 Weave의 OpenAI moderation API에 전달되어, LLM의 응답에 유해하거나 독성이 있는 콘텐츠가 포함되어 있는지 평가됩니다. 모델의 응답은 guardrail 함수(generate_safe_response())로 전달되며, 여기서 OpenAIModerationScorer를 사용해 LLM의 원래 응답을 검사합니다. 그런 다음 함수 로직은 OpenAI의 평가 결과 응답에서 passed 필드의 불리언 값을 확인하고, 이 값을 기준으로 애플리케이션의 응답 방식을 결정합니다.
import weave
import openai
from weave.scorers import OpenAIModerationScorer
import asyncio

# Weave 초기화
weave.init("your-team-name/your-project-name")

# OpenAI 클라이언트 초기화
client = openai.OpenAI()  # OPENAI_API_KEY 환경 변수 사용

# 모더레이션 스코어러 초기화
moderation_scorer = OpenAIModerationScorer()

# OpenAI에 프롬프트 전송
@weave.op
def generate_response(prompt: str) -> str:
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "You are a helpful assistant."},
            {"role": "user", "content": prompt}
        ],
        max_tokens=200
    )
    return response.choices[0].message.content

# 가드레일 함수로 응답의 유해성 검사
async def generate_safe_response(prompt: str) -> str:
    """콘텐츠 모더레이션 가드레일을 적용하여 응답을 생성합니다."""
    # 결과와 Call 객체를 모두 가져옴
    result, call = generate_response.call(prompt)
    
    # 사용자에게 반환하기 전에 모더레이션 스코어러 적용
    score = await call.apply_scorer(moderation_scorer)
    print("This is the score object:", score)
    
    # 콘텐츠 플래그 여부 확인
    if not score.result.get("passed", True): 
        categories = score.result.get("categories", {})
        flagged_categories = list(categories.keys()) if categories else []
        print(f"Content blocked. Flagged categories: {flagged_categories}")
        return "I'm sorry, I can't provide that response due to content policy restrictions."
    
    return result

# 예제 실행
if __name__ == "__main__":
    
    prompts = [
        "What's the capital of France?",
        "Tell me a funny fact about dogs.",
    ]
    
    for prompt in prompts:
        print(f"\nPrompt: {prompt}")
        response = asyncio.run(generate_safe_response(prompt))
        print(f"Response: {response}")
LLM-as-a-judge scorer를 사용할 때 채점 프롬프트에서 op에서 정의한 변수를 참조할 수 있습니다. 예를 들어 “{ground_truth}를 기반으로 {output}가 정확한지 평가하세요.”와 같이 사용할 수 있습니다. 자세한 내용은 프롬프트 변수를 참고하세요.

예시: 커스텀 스코어러를 사용하여 가드레일 생성하기

다음 예제에서는 LLM 응답에서 이메일 주소, 전화번호, 사회보장번호와 같은 개인 식별 정보(PII)를 감지하는 커스텀 가드레일을 생성합니다. 이를 통해 생성된 콘텐츠에 민감한 정보가 노출되는 것을 방지할 수 있습니다. 함수 generate_safe_response는 커스텀 PIIDetectionScorer를 적용합니다.
import weave
import openai
import re
import asyncio
from weave import Scorer

weave.init("your-team-name/your-project-name")

client = openai.OpenAI()

class PIIDetectionScorer(Scorer):
    """LLM 출력에서 데이터 유출을 방지하기 위해 PII를 감지합니다."""
    
    @weave.op
    def score(self, output: str) -> dict:
        """
        출력에서 일반적인 PII 패턴을 확인합니다.
        
        Returns:
            dict: 'passed' (bool) 및 'detected_types' (list) 포함
        """
        detected_types = []
        
        # 이메일 패턴
        if re.search(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', output):
            detected_types.append("email")
        
        # 전화번호 패턴 (미국 형식)
        if re.search(r'\b\d{3}[-.]?\d{3}[-.]?\d{4}\b', output):
            detected_types.append("phone")
        
        # SSN 패턴
        if re.search(r'\b\d{3}-\d{2}-\d{4}\b', output):
            detected_types.append("ssn")
        
        return {
            "passed": len(detected_types) == 0,
            "detected_types": detected_types
        }

# 최적의 성능을 위해 함수 외부에서 scorer 초기화
pii_scorer = PIIDetectionScorer()

@weave.op
def generate_response(prompt: str) -> str:
    """LLM을 사용하여 응답을 생성합니다."""
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": "You are a helpful assistant."},
            {"role": "user", "content": prompt}
        ],
        max_tokens=200
    )
    return response.choices[0].message.content

async def generate_safe_response(prompt: str) -> str:
    """PII 감지 가드레일을 적용하여 응답을 생성합니다."""
    result, call = generate_response.call(prompt)
    
    # PII 감지 scorer 적용
    score = await call.apply_scorer(pii_scorer)
    
    # PII가 감지된 경우 응답 차단
    if not score.result.get("passed", True):
        detected_types = score.result.get("detected_types", [])
        return f"I cannot provide a response that may contain sensitive information (detected: {', '.join(detected_types)})."
    
    return result

# 사용 예시
if __name__ == "__main__":
    prompts = [
        "What's the weather like today?",
        "Can you help me contact someone at john.doe@example.com?",
        "Tell me about machine learning.",
    ]
    
    for prompt in prompts:
        print(f"\nPrompt: {prompt}")
        response = asyncio.run(generate_safe_response(prompt))
        print(f"Response: {response}")

Weave를 AWS Bedrock Guardrails와 통합하기

BedrockGuardrailScorer는 구성된 정책을 기반으로 콘텐츠를 감지하고 필터링하기 위해 AWS Bedrock Guardrails를 사용합니다. Bedrock Guardrails 통합을 구성하기 전에 다음이 필요합니다: 직접 Bedrock 클라이언트를 생성할 필요는 없습니다. Weave가 대신 생성합니다. 리전을 지정하려면 스코어러의 bedrock_runtime_kwargs 파라미터에 리전 값을 전달하십시오. AWS Bedrock에서 guardrail을 생성하는 예제는 Bedrock guardrails notebook을 참고하십시오. 다음 예제는 사용자에게 결과를 반환하기 전에 텍스트 생성 결과를 AWS Bedrock Guardrails 정책에 대해 검사합니다:
import weave
from weave.scorers.bedrock_guardrails import BedrockGuardrailScorer

weave.init("your-team-name/your-project-name")

guardrail_scorer = BedrockGuardrailScorer(
    guardrail_id="your-guardrail-id",
    guardrail_version="DRAFT",
    source="INPUT",
    bedrock_runtime_kwargs={"region_name": "us-east-1"}
)

@weave.op
def generate_text(prompt: str) -> str:
    # 텍스트 생성 로직을 여기에 작성하세요
    return "Generated text..."

async def generate_safe_text(prompt: str) -> str:
    result, call = generate_text.call(prompt)

    score = await call.apply_scorer(guardrail_scorer)

    if not score.result.passed:
        if score.result.metadata.get("modified_output"):
            return score.result.metadata["modified_output"]
        return "콘텐츠 정책 제한으로 인해 해당 콘텐츠를 생성할 수 없습니다."

    return result