メインコンテンツへスキップ
ガードレールは、LLM judges のスコアに基づいて、LLM アプリケーションの振る舞いに能動的に介入します。出力がユーザーに届く前にリアルタイムで実行され、スコアがしきい値を超えた場合は応答をブロックしたり変更したりできます。ガードレールを使用すると、有害なコンテンツをブロックしたり、応答に個人を特定できる情報 (PII) が含まれていないかをフィルターしたり、ユーザーからの不適切な入力をブロックしたりできます。 このガイドでは、Weave ガードレールの仕組みやパフォーマンスの調整方法に加え、組み込みの Scorer、カスタム Scorer、AWS Bedrock Guardrails を使用して本番環境の LLM アプリケーションを保護する例を紹介します。

Weave ガードレールの仕組み

Weave ガードレールは、インラインの Weave Scorers を使用して、ユーザーからの入力や LLM の出力を評価し、LLM の応答をリアルタイムで調整します。さまざまな目的でコンテンツを評価するために、カスタムScorerを設定することも、組み込みScorer を使用することもできます。このガイドでは、両方のタイプのScorerをガードレールとして使用する方法を説明します。 アプリケーションの制御フローを変更せずに本番トラフィックを受動的にスコアリングしたい場合は、代わりに モニター を使用してください。 モニターとは異なり、ガードレールはアプリケーションの制御フローに影響するため、コードの変更が必要です。ただし、ガードレールによるScorerの結果はすべて自動的に Weave のデータベースに保存されるため、追加の設定なしでガードレールはモニターとしても機能します。過去のScorer結果は、元の用途にかかわらず分析できます。
Weave TypeScript SDK は、ガードレールの設定に必要なツールをサポートしていません。

Weave ガードレールのパフォーマンスを最適化する

ガードレールはアプリケーションの制御フローを中断し、応答の内容を変える可能性があるため、複雑になりすぎるとパフォーマンスに影響することがあります。最高のパフォーマンスを得るには、次の推奨事項に従ってください。
  • ガードレールのロジックはシンプルかつ高速に保つ
  • よく使われる結果をキャッシュする
  • 負荷の高い外部 API call は避ける
  • 初期化コストの繰り返しを避けるため、ガードレールはメイン関数の外で初期化する
特に、次のような場合はガードレールをメイン関数の外で初期化することが重要です。
  • Scorerが ML モデルを読み込む場合
  • レイテンシが重要なローカル LLM を使用している場合
  • Scorerがネットワーク接続を維持する場合
  • トラフィックの多いアプリケーションを扱う場合

例: 組み込みの モデレーション Scorer を使用してガードレールを作成する

次の例では、ユーザーの prompt を OpenAI の GPT-4o mini モデルに送信します。次に、モデルのレスポンスを OpenAI の モデレーション Scorer API に渡して、LLM のレスポンスに有害または不適切なコンテンツが含まれているかどうかを評価します。モデルのレスポンスはガードレール関数 (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()  # Uses OPENAI_API_KEY env var

# モデレーション Scorer を初期化する
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:
    """Generate a response with content moderation guardrail."""
    # Get both the result and Call object
    result, call = generate_response.call(prompt)
    
    # ユーザーに返す前にモデレーション Scorer を適用する
    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 scorers を使用する場合、スコアリング用のプロンプトで ops の変数を参照できます。たとえば、“{output}{ground_truth} に基づいて正確かどうかを評価してください。“のように指定できます。詳細については、prompt variablesをご覧ください。

例: カスタム Scorer を使用してガードレールを作成する

以下の例では、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 パターンを確認します。
        
        戻り値:
            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 と統合する

AWS ですでにコンテンツポリシーを管理している場合は、設定されたポリシーに基づいてコンテンツを検出してフィルタリングするために AWS Bedrock Guardrails を使用する BedrockGuardrailScorer を使用して、それらを Weave に適用できます。 Bedrock Guardrails のインテグレーションを設定する前に、次のものが必要です。 Bedrock クライアントを自分で作成する必要はありません。Weave が自動的に作成します。リージョンを指定するには、Scorer の bedrock_runtime_kwargs パラメーターにリージョンの値を渡します。 AWS Bedrock でガードレールを作成する方法の例については、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 "I cannot generate that content due to content policy restrictions."

    return result