---
title: 콘텐츠 모더레이션
url: https://platform.claude.com/docs/ko/about-claude/use-case-guides/content-moderation
description: 콘텐츠 모더레이션은 디지털 애플리케이션에서 안전하고 존중하며 생산적인 환경을 유지하는 데 있어 핵심적인 요소입니다. 이 가이드에서는 Claude를 사용하여 디지털 애플리케이션 내의 콘텐츠를 모더레이션하는 방법을 설명합니다.
---

> Claude를 사용한 콘텐츠 모더레이션 구현 예시를 보려면 [콘텐츠 모더레이션 cookbook](https://platform.claude.com/cookbook/misc-building-moderation-filter)을 방문하세요.

<Tip>
  이 가이드는 애플리케이션 내의 사용자 생성 콘텐츠를 모더레이션하는 데 중점을 둡니다. Claude와의 상호작용을 모더레이션하는 방법에 대한 안내를 찾고 있다면 

  [탈옥 및 프롬프트 인젝션 완화](https://platform.claude.com/docs/ko/test-and-evaluate/strengthen-guardrails/mitigate-jailbreaks)

  를 참조하세요.
</Tip>

## Claude로 구축하기 전에

### 콘텐츠 모더레이션에 Claude를 사용할지 결정하기

다음은 "content moderation"(콘텐츠 모더레이션)에 기존 ML 또는 규칙 기반 접근 방식 대신 Claude와 같은 "large language model"(대규모 언어 모델), 즉 LLM을 사용해야 하는 몇 가지 주요 지표입니다:

<AccordionGroup>
  <Accordion title="비용 효율적이고 신속한 구현을 원하는 경우">
    기존 ML 방법은 상당한 엔지니어링 리소스, ML 전문 지식 및 인프라 비용을 필요로 합니다. 인간 모더레이션 시스템은 훨씬 더 높은 비용이 발생합니다. Claude를 사용하면 훨씬 짧은 시간과 훨씬 낮은 비용으로 정교한 모더레이션 시스템을 운영할 수 있습니다.
  </Accordion>

  <Accordion title="의미론적 이해와 빠른 결정을 모두 원하는 경우">
    bag-of-words 모델이나 단순 패턴 매칭과 같은 기존 ML 접근 방식은 콘텐츠의 어조, 의도 및 맥락을 이해하는 데 어려움을 겪는 경우가 많습니다. 인간 모더레이션 시스템은 의미론적 의미를 이해하는 데 뛰어나지만, 콘텐츠를 검토하는 데 시간이 필요합니다. Claude는 의미론적 이해와 모더레이션 결정을 신속하게 내릴 수 있는 능력을 결합하여 두 가지 요구를 모두 충족합니다.
  </Accordion>

  <Accordion title="일관된 정책 결정이 필요한 경우">
    Claude는 고급 추론 능력을 활용하여 복잡한 모더레이션 가이드라인을 일관되게 해석하고 적용할 수 있습니다. 이러한 일관성은 모든 콘텐츠에 대한 공정한 처리를 보장하는 데 도움이 되며, 사용자 신뢰를 훼손할 수 있는 일관성 없거나 편향된 모더레이션 결정의 위험을 줄여줍니다.
  </Accordion>

  <Accordion title="모더레이션 정책이 시간이 지남에 따라 변경되거나 발전할 가능성이 있는 경우">
    기존 ML 접근 방식이 일단 확립되면, 이를 변경하는 것은 힘들고 데이터 집약적인 작업입니다. 반면, 제품이나 고객의 요구가 발전함에 따라 Claude는 학습 데이터를 광범위하게 다시 레이블링할 필요 없이 모더레이션 정책의 변경이나 추가에 쉽게 적응할 수 있습니다.
  </Accordion>

  <Accordion title="모더레이션 결정에 대해 해석 가능한 추론이 필요한 경우">
    사용자나 규제 기관에 모더레이션 결정의 배경에 대한 명확한 설명을 제공하고자 한다면, Claude는 상세하고 일관성 있는 근거를 생성할 수 있습니다. 이러한 투명성은 콘텐츠 모더레이션 관행에서 신뢰를 구축하고 책임성을 보장하는 데 중요합니다.
  </Accordion>

  <Accordion title="별도의 모델을 유지하지 않고 다국어 지원이 필요한 경우">
    기존 ML 접근 방식은 일반적으로 지원되는 각 언어에 대해 별도의 모델이나 광범위한 번역 프로세스를 필요로 합니다. 인간 모더레이션은 지원되는 각 언어에 능통한 인력을 고용해야 합니다. Claude의 다국어 기능을 사용하면 별도의 모델이나 광범위한 번역 프로세스 없이 다양한 언어의 티켓을 분류할 수 있어, 글로벌 고객 기반을 위한 모더레이션을 간소화할 수 있습니다.
  </Accordion>

  <Accordion title="멀티모달 지원이 필요한 경우">
    Claude의 멀티모달 기능을 사용하면 텍스트와 이미지 모두에 걸쳐 콘텐츠를 분석하고 해석할 수 있습니다. 이는 서로 다른 미디어 유형을 함께 평가해야 하는 환경에서 포괄적인 콘텐츠 모더레이션을 위한 다재다능한 도구가 됩니다.
  </Accordion>
</AccordionGroup>

<Note>
  모든 Claude 모델은 내장된 안전 동작을 갖추도록 학습되었습니다. 이로 인해 사용된 프롬프트와 관계없이 Claude가 특히 위험하다고 간주되는 콘텐츠(

  [이용 정책](https://www.anthropic.com/legal/aup)

  에 따라)를 모더레이션할 수 있습니다. 예를 들어, 사용자가 노골적인 성적 콘텐츠를 게시하도록 허용하려는 성인 웹사이트의 경우, 프롬프트에서 노골적인 성적 콘텐츠를 모더레이션하지 않도록 지정하더라도 Claude가 여전히 노골적인 콘텐츠를 모더레이션이 필요한 것으로 표시할 수 있습니다. 모더레이션 솔루션을 구축하기 전에 AUP를 검토하는 것을 고려하세요.
</Note>

### 모더레이션할 콘텐츠 예시 생성하기

콘텐츠 모더레이션 솔루션을 개발하기 전에, 먼저 표시되어야 하는 콘텐츠와 표시되지 않아야 하는 콘텐츠의 예시를 만드세요. 콘텐츠 모더레이션 시스템이 효과적으로 처리하기 어려울 수 있는 엣지 케이스와 까다로운 시나리오를 반드시 포함하세요. 그런 다음, 예시를 검토하여 잘 정의된 모더레이션 카테고리 목록을 만드세요. 예를 들어, 소셜 미디어 플랫폼에서 생성한 예시에는 다음이 포함될 수 있습니다:

<CodeGroup exclude="shell">
  ```python Python
  client = anthropic.Anthropic()

  allowed_user_comments = [
      "This movie was great, I really enjoyed it. The main actor really killed it!",
      "I hate Mondays.",
      "It is a great time to invest in gold!",
  ]

  disallowed_user_comments = [
      "Delete this post now or you better hide. I am coming after you and your family.",
      "Stay away from the 5G cellphones!! They are using 5G to control you.",
      "Congratulations! You have won a $1,000 gift card. Click here to claim your prize!",
  ]

  # 콘텐츠 조정을 테스트하기 위한 샘플 사용자 댓글
  user_comments = allowed_user_comments + disallowed_user_comments

  # 콘텐츠 조정에서 안전하지 않은 것으로 간주되는 카테고리
  unsafe_categories = [
      "Child Exploitation",
      "Conspiracy Theories",
      "Hate",
      "Indiscriminate Weapons",
      "Intellectual Property",
      "Non-Violent Crimes",
      "Privacy",
      "Self-Harm",
      "Sex Crimes",
      "Sexual Content",
      "Specialized Advice",
      "Violent Crimes",
  ]
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const allowedUserComments = [
    "This movie was great, I really enjoyed it. The main actor really killed it!",
    "I hate Mondays.",
    "It is a great time to invest in gold!"
  ];

  const disallowedUserComments = [
    "Delete this post now or you better hide. I am coming after you and your family.",
    "Stay away from the 5G cellphones!! They are using 5G to control you.",
    "Congratulations! You have won a $1,000 gift card. Click here to claim your prize!"
  ];

  // 콘텐츠 조정을 테스트하기 위한 샘플 사용자 댓글
  const userComments = [...allowedUserComments, ...disallowedUserComments];

  // 콘텐츠 조정에서 안전하지 않은 것으로 간주되는 카테고리
  const unsafeCategories = [
    "Child Exploitation",
    "Conspiracy Theories",
    "Hate",
    "Indiscriminate Weapons",
    "Intellectual Property",
    "Non-Violent Crimes",
    "Privacy",
    "Self-Harm",
    "Sex Crimes",
    "Sexual Content",
    "Specialized Advice",
    "Violent Crimes"
  ];
  ```

  ```csharp C#
  var client = new AnthropicClient();

  string[] allowedUserComments =
  [
      "This movie was great, I really enjoyed it. The main actor really killed it!",
      "I hate Mondays.",
      "It is a great time to invest in gold!",
  ];

  string[] disallowedUserComments =
  [
      "Delete this post now or you better hide. I am coming after you and your family.",
      "Stay away from the 5G cellphones!! They are using 5G to control you.",
      "Congratulations! You have won a $1,000 gift card. Click here to claim your prize!",
  ];

  // 콘텐츠 조정을 테스트하기 위한 샘플 사용자 댓글
  string[] userComments = [.. allowedUserComments, .. disallowedUserComments];

  // 콘텐츠 조정에서 안전하지 않은 것으로 간주되는 카테고리
  string[] unsafeCategories =
  [
      "Child Exploitation",
      "Conspiracy Theories",
      "Hate",
      "Indiscriminate Weapons",
      "Intellectual Property",
      "Non-Violent Crimes",
      "Privacy",
      "Self-Harm",
      "Sex Crimes",
      "Sexual Content",
      "Specialized Advice",
      "Violent Crimes",
  ];
  ```

  ```go Go
  var client = anthropic.NewClient()

  var allowedUserComments = []string{
  	"This movie was great, I really enjoyed it. The main actor really killed it!",
  	"I hate Mondays.",
  	"It is a great time to invest in gold!",
  }

  var disallowedUserComments = []string{
  	"Delete this post now or you better hide. I am coming after you and your family.",
  	"Stay away from the 5G cellphones!! They are using 5G to control you.",
  	"Congratulations! You have won a $1,000 gift card. Click here to claim your prize!",
  }

  // 콘텐츠 조정을 테스트하기 위한 샘플 사용자 댓글
  var userComments = slices.Concat(allowedUserComments, disallowedUserComments)

  // 콘텐츠 조정에서 안전하지 않은 것으로 간주되는 카테고리
  var unsafeCategories = []string{
  	"Child Exploitation",
  	"Conspiracy Theories",
  	"Hate",
  	"Indiscriminate Weapons",
  	"Intellectual Property",
  	"Non-Violent Crimes",
  	"Privacy",
  	"Self-Harm",
  	"Sex Crimes",
  	"Sexual Content",
  	"Specialized Advice",
  	"Violent Crimes",
  }
  ```

  ```java Java
  final AnthropicClient client = AnthropicOkHttpClient.fromEnv();

  final List<String> allowedUserComments = List.of(
          "This movie was great, I really enjoyed it. The main actor really killed it!",
          "I hate Mondays.",
          "It is a great time to invest in gold!");

  final List<String> disallowedUserComments = List.of(
          "Delete this post now or you better hide. I am coming after you and your family.",
          "Stay away from the 5G cellphones!! They are using 5G to control you.",
          "Congratulations! You have won a $1,000 gift card. Click here to claim your prize!");

  // 콘텐츠 조정을 테스트하기 위한 샘플 사용자 댓글
  final List<String> userComments =
          Stream.concat(allowedUserComments.stream(), disallowedUserComments.stream()).toList();

  // 콘텐츠 조정에서 안전하지 않은 것으로 간주되는 카테고리
  final List<String> unsafeCategories = List.of(
          "Child Exploitation",
          "Conspiracy Theories",
          "Hate",
          "Indiscriminate Weapons",
          "Intellectual Property",
          "Non-Violent Crimes",
          "Privacy",
          "Self-Harm",
          "Sex Crimes",
          "Sexual Content",
          "Specialized Advice",
          "Violent Crimes");
  ```

  ```php PHP
  $client = new Client();

  $allowedUserComments = [
      'This movie was great, I really enjoyed it. The main actor really killed it!',
      'I hate Mondays.',
      'It is a great time to invest in gold!',
  ];

  $disallowedUserComments = [
      'Delete this post now or you better hide. I am coming after you and your family.',
      'Stay away from the 5G cellphones!! They are using 5G to control you.',
      'Congratulations! You have won a $1,000 gift card. Click here to claim your prize!',
  ];

  // 콘텐츠 조정을 테스트하기 위한 샘플 사용자 댓글
  $userComments = [...$allowedUserComments, ...$disallowedUserComments];

  // 콘텐츠 조정에서 안전하지 않은 것으로 간주되는 카테고리
  $unsafeCategories = [
      'Child Exploitation',
      'Conspiracy Theories',
      'Hate',
      'Indiscriminate Weapons',
      'Intellectual Property',
      'Non-Violent Crimes',
      'Privacy',
      'Self-Harm',
      'Sex Crimes',
      'Sexual Content',
      'Specialized Advice',
      'Violent Crimes',
  ];
  ```

  ```ruby Ruby
  CLIENT = Anthropic::Client.new

  ALLOWED_USER_COMMENTS = [
    "This movie was great, I really enjoyed it. The main actor really killed it!",
    "I hate Mondays.",
    "It is a great time to invest in gold!"
  ]

  DISALLOWED_USER_COMMENTS = [
    "Delete this post now or you better hide. I am coming after you and your family.",
    "Stay away from the 5G cellphones!! They are using 5G to control you.",
    "Congratulations! You have won a $1,000 gift card. Click here to claim your prize!"
  ]

  # 콘텐츠 조정을 테스트하기 위한 샘플 사용자 댓글
  USER_COMMENTS = ALLOWED_USER_COMMENTS + DISALLOWED_USER_COMMENTS

  # 콘텐츠 조정에서 안전하지 않은 것으로 간주되는 카테고리
  UNSAFE_CATEGORIES = [
    "Child Exploitation",
    "Conspiracy Theories",
    "Hate",
    "Indiscriminate Weapons",
    "Intellectual Property",
    "Non-Violent Crimes",
    "Privacy",
    "Self-Harm",
    "Sex Crimes",
    "Sexual Content",
    "Specialized Advice",
    "Violent Crimes"
  ]
  ```
</CodeGroup>

이러한 예시를 효과적으로 모더레이션하려면 언어에 대한 미묘한 이해가 필요합니다. `This movie was great, I really enjoyed it. The main actor really killed it!`이라는 댓글에서 콘텐츠 모더레이션 시스템은 "killed it"이 실제 폭력을 나타내는 것이 아니라 비유적 표현임을 인식해야 합니다. 반대로, 폭력에 대한 명시적인 언급이 없음에도 불구하고 `Delete this post now or you better hide. I am coming after you and your family.`라는 댓글은 콘텐츠 모더레이션 시스템에 의해 표시되어야 합니다.

안전하지 않은 카테고리는 특정 요구에 맞게 사용자 정의할 수 있습니다. 예를 들어, 미성년자가 웹사이트에서 콘텐츠를 생성하는 것을 방지하려면 카테고리에 "Underage Posting"을 추가할 수 있습니다.

***

## Claude를 사용하여 콘텐츠를 모더레이션하는 방법

### 적합한 Claude 모델 선택하기

모델을 선택할 때는 데이터의 크기를 고려하는 것이 중요합니다. 비용이 우려된다면 Claude Haiku 5.5와 같은 소형 모델이 비용 효율성 측면에서 탁월한 선택입니다. 다음은 매월 10억 개의 게시물을 받는 소셜 미디어 플랫폼의 텍스트를 모더레이션하는 데 드는 비용의 추정치입니다:

* **콘텐츠 규모**

  * 월별 게시물 수: 10억
  * 게시물당 문자 수: 100
  * 총 문자 수: 1,000억

* **추정 토큰**

  * 입력 토큰: 286억 (3.5자당 1토큰으로 가정)
  * 표시된 메시지 비율: 3%
  * 표시된 메시지당 출력 토큰: 50
  * 총 출력 토큰: 15억

* **Claude Haiku 5.5 추정 비용**

  * 입력 토큰 비용: 28,600 MTok \* $0.10/MTok = $2,860 USD
  * 출력 토큰 비용: 1,500 MTok \* $0.50/MTok = $750 USD
  * 월별 비용: $2,860 + $750 = $3,610 USD

* **Claude Opus 5 추정 비용**

  * 입력 토큰 비용: 28,600 MTok \* $5.00/MTok = $143,000 USD
  * 출력 토큰 비용: 1,500 MTok \* $25.00/MTok = $37,500 USD
  * 월별 비용: $143,000 + $37,500 = $180,500 USD

* **Claude Opus 4.8 추정 비용**

  * 입력 토큰 비용: 28,600 MTok \* $5.00/MTok = $143,000 USD
  * 출력 토큰 비용: 1,500 MTok \* $25.00/MTok = $37,500 USD
  * 월별 비용: $143,000 + $37,500 = $180,500 USD

<Tip>
  실제 비용은 이 추정치와 다를 수 있습니다. 이 추정치는 

  [배치 처리](https://platform.claude.com/docs/ko/about-claude/use-case-guides/content-moderation#consider-batch-processing)

   섹션에서 강조된 프롬프트를 기반으로 합니다. 응답에서 

  `explanation`

   필드를 제거하면 출력 토큰을 더욱 줄일 수 있습니다.
</Tip>

### 강력한 프롬프트 구축하기

콘텐츠 모더레이션에 Claude를 사용하려면 Claude가 애플리케이션의 모더레이션 요구 사항을 이해해야 합니다. 먼저 모더레이션 요구 사항을 정의할 수 있는 프롬프트를 작성하세요:

<CodeGroup exclude="shell">
  ```python Python
  def moderate_message(message, unsafe_categories):
      # 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
      unsafe_category_str = "\n".join(unsafe_categories)

      # 메시지와 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
      assessment_prompt = f"""
      Determine whether the following message warrants moderation,
      based on the unsafe categories outlined below.

      Message:
      <message>{message}</message>

      Unsafe Categories:
      <categories>
      {unsafe_category_str}
      </categories>

      Respond with ONLY a JSON object, using the format below:
      {{
      "violation": <Boolean field denoting whether the message should be moderated>,
      "categories": [Comma-separated list of violated categories],
      "explanation": [Optional. Only include if there is a violation.]
      }}
  Do not include markdown formatting or code fences in your response."""

      # 콘텐츠 조정을 위해 Claude에 요청 전송
      response = client.messages.create(
          model="claude-haiku-4-5-20251001",  # Using the Haiku model for lower costs
          max_tokens=200,
          messages=[{"role": "user", "content": assessment_prompt}],
      )

      # Claude의 JSON 응답 파싱
      text_block = next(block for block in response.content if block.type == "text")
      assessment = json.loads(text_block.text)

      # 평가 결과에서 위반 상태 추출
      contains_violation = assessment["violation"]

      # 위반이 있으면 카테고리와 설명을 가져오고, 그렇지 않으면 빈 기본값 사용
      violated_categories = assessment.get("categories", []) if contains_violation else []
      explanation = assessment.get("explanation") if contains_violation else None

      return contains_violation, violated_categories, explanation


  # 각 댓글을 처리하고 결과 출력
  for comment in user_comments:
      print(f"\nComment: {comment}")
      violation, violated_categories, explanation = moderate_message(
          comment, unsafe_categories
      )

      if violation:
          print(f"Violated Categories: {', '.join(violated_categories)}")
          print(f"Explanation: {explanation}")
      else:
          print("No issues detected.")
  ```

  ```typescript TypeScript
  // Claude가 반환하는 JSON 평가의 형태
  interface ModerationAssessment {
    violation: boolean;
    categories?: string[];
    explanation?: string;
  }

  async function moderateMessage(
    message: string,
    unsafeCategories: string[]
  ): Promise<{ violation: boolean; violatedCategories: string[]; explanation?: string }> {
    // 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
    const unsafeCategoryStr = unsafeCategories.join("\n");

    // 메시지와 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
    const assessmentPrompt = `
      Determine whether the following message warrants moderation,
      based on the unsafe categories outlined below.

      Message:
      <message>${message}</message>

      Unsafe Categories:
      <categories>
      ${unsafeCategoryStr}
      </categories>

      Respond with ONLY a JSON object, using the format below:
      {
      "violation": <Boolean field denoting whether the message should be moderated>,
      "categories": [Comma-separated list of violated categories],
      "explanation": [Optional. Only include if there is a violation.]
      }
  Do not include markdown formatting or code fences in your response.`;

    // 콘텐츠 조정을 위해 Claude에 요청 전송
    const response = await client.messages.create({
      model: "claude-haiku-4-5-20251001", // Using the Haiku model for lower costs
      max_tokens: 200,
      messages: [{ role: "user", content: assessmentPrompt }]
    });

    // Claude의 JSON 응답 파싱
    const textBlock = response.content.find((block) => block.type === "text");
    if (!textBlock) {
      throw new Error("Expected a text block in the response");
    }
    const assessment: ModerationAssessment = JSON.parse(textBlock.text);

    // 평가에서 위반 상태 추출
    const containsViolation = assessment.violation;

    // 위반이 있으면 카테고리와 설명을 가져오고, 그렇지 않으면 빈 기본값 사용
    const violatedCategories = containsViolation ? (assessment.categories ?? []) : [];
    const explanation = containsViolation ? assessment.explanation : undefined;

    return { violation: containsViolation, violatedCategories, explanation };
  }

  // 각 댓글을 처리하고 결과 출력
  for (const comment of userComments) {
    console.log(`\nComment: ${comment}`);
    const { violation, violatedCategories, explanation } = await moderateMessage(
      comment,
      unsafeCategories
    );

    if (violation) {
      console.log(`Violated Categories: ${violatedCategories.join(", ")}`);
      console.log(`Explanation: ${explanation}`);
    } else {
      console.log("No issues detected.");
    }
  }
  ```

  ```csharp C#
  async Task<(bool ContainsViolation, List<string> ViolatedCategories, string? Explanation)> ModerateMessage(
      string message,
      IReadOnlyList<string> categories
  )
  {
      // 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
      var unsafeCategoryText = string.Join("\n", categories);

      // 메시지와 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
      var assessmentPrompt = $$"""

      Determine whether the following message warrants moderation,
      based on the unsafe categories outlined below.

      Message:
      <message>{{message}}</message>

      Unsafe Categories:
      <categories>
      {{unsafeCategoryText}}
      </categories>

      Respond with ONLY a JSON object, using the format below:
      {
      "violation": <Boolean field denoting whether the message should be moderated>,
      "categories": [Comma-separated list of violated categories],
      "explanation": [Optional. Only include if there is a violation.]
      }
  Do not include markdown formatting or code fences in your response.
  """;

      // 콘텐츠 조정을 위해 Claude에 요청 전송
      var response = await client.Messages.Create(
          new()
          {
              Model = Model.ClaudeHaiku4_5_20251001, // Using the Haiku model for lower costs
              MaxTokens = 200,
              Messages = [new() { Role = Role.User, Content = assessmentPrompt }],
          }
      );

      // 첫 번째 콘텐츠 블록을 텍스트 블록으로 좁힌 다음 Claude의 JSON 응답을 파싱
      if (!response.Content[0].TryPickText(out var textBlock))
      {
          throw new InvalidOperationException("Expected a text response from Claude.");
      }
      var assessment = JsonNode.Parse(textBlock.Text)!;

      // 평가 결과에서 위반 상태 추출
      var containsViolation = assessment["violation"]!.GetValue<bool>();

      // 위반이 있으면 카테고리와 설명을 가져오고, 그렇지 않으면 빈 기본값 사용
      List<string> violatedCategories = containsViolation
          ? assessment["categories"]?.AsArray().Select(category => category!.GetValue<string>()).ToList() ?? []
          : [];
      var explanation = containsViolation ? assessment["explanation"]?.GetValue<string>() : null;

      return (containsViolation, violatedCategories, explanation);
  }

  // 각 댓글을 처리하고 결과 출력
  foreach (var comment in userComments)
  {
      Console.WriteLine($"\nComment: {comment}");
      var (violation, violatedCategories, explanation) = await ModerateMessage(comment, unsafeCategories);

      if (violation)
      {
          Console.WriteLine($"Violated Categories: {string.Join(", ", violatedCategories)}");
          Console.WriteLine($"Explanation: {explanation}");
      }
      else
      {
          Console.WriteLine("No issues detected.");
      }
  }
  ```

  ```go Go
  func moderateMessage(message string, unsafeCategories []string) (bool, []string, string) {
  	// 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
  	unsafeCategoryStr := strings.Join(unsafeCategories, "\n")

  	// 메시지와 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
  	assessmentPrompt := fmt.Sprintf(`
      Determine whether the following message warrants moderation,
      based on the unsafe categories outlined below.

      Message:
      <message>%s</message>

      Unsafe Categories:
      <categories>
      %s
      </categories>

      Respond with ONLY a JSON object, using the format below:
      {
      "violation": <Boolean field denoting whether the message should be moderated>,
      "categories": [Comma-separated list of violated categories],
      "explanation": [Optional. Only include if there is a violation.]
      }
  Do not include markdown formatting or code fences in your response.`, message, unsafeCategoryStr)

  	// 콘텐츠 조정을 위해 Claude에 요청 전송
  	response, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
  		Model:     anthropic.ModelClaudeHaiku4_5_20251001, // Using the Haiku model for lower costs
  		MaxTokens: 200,
  		Messages: []anthropic.MessageParam{
  			anthropic.NewUserMessage(anthropic.NewTextBlock(assessmentPrompt)),
  		},
  	})
  	if err != nil {
  		log.Fatal(err)
  	}

  	// 텍스트를 읽기 전에 첫 번째 콘텐츠 블록을 텍스트 블록으로 좁히기
  	textBlock, ok := response.Content[0].AsAny().(anthropic.TextBlock)
  	if !ok {
  		log.Fatalf("expected a text block, got %q", response.Content[0].Type)
  	}

  	// Claude의 JSON 응답 파싱
  	var assessment struct {
  		Violation   bool     `json:"violation"`
  		Categories  []string `json:"categories"`
  		Explanation string   `json:"explanation"`
  	}
  	if err := json.Unmarshal([]byte(textBlock.Text), &assessment); err != nil {
  		log.Fatal(err)
  	}

  	// 위반이 있으면 카테고리와 설명을 반환하고, 그렇지 않으면 빈 기본값 사용
  	if !assessment.Violation {
  		return false, nil, ""
  	}
  	return true, assessment.Categories, assessment.Explanation
  }

  // moderateAllComments는 각 댓글을 처리하고 결과를 출력합니다.
  func moderateAllComments() {
  	for _, comment := range userComments {
  		fmt.Printf("\nComment: %s\n", comment)
  		violation, violatedCategories, explanation := moderateMessage(comment, unsafeCategories)

  		if violation {
  			fmt.Printf("Violated Categories: %s\n", strings.Join(violatedCategories, ", "))
  			fmt.Printf("Explanation: %s\n", explanation)
  		} else {
  			fmt.Println("No issues detected.")
  		}
  	}
  }
  ```

  ```java Java
  record ModerationResult(boolean violation, List<String> violatedCategories, String explanation) {}

  ModerationResult moderateMessage(String message, List<String> unsafeCategories)
          throws JsonProcessingException {
      // 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
      String unsafeCategoryStr = String.join("\n", unsafeCategories);

      // 메시지와 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
      String assessmentPrompt = """

              Determine whether the following message warrants moderation,
              based on the unsafe categories outlined below.

              Message:
              <message>%s</message>

              Unsafe Categories:
              <categories>
              %s
              </categories>

              Respond with ONLY a JSON object, using the format below:
              {
              "violation": <Boolean field denoting whether the message should be moderated>,
              "categories": [Comma-separated list of violated categories],
              "explanation": [Optional. Only include if there is a violation.]
              }
          Do not include markdown formatting or code fences in your response."""
              .formatted(message, unsafeCategoryStr);

      // 콘텐츠 조정을 위해 Claude에 요청 전송
      Message response = client.messages().create(MessageCreateParams.builder()
              .model(Model.CLAUDE_HAIKU_4_5_20251001) // Using the Haiku model for lower costs
              .maxTokens(200)
              .addUserMessage(assessmentPrompt)
              .build());

      // Claude의 JSON 응답 파싱
      String assessmentJson = response.content().stream()
              .flatMap(contentBlock -> contentBlock.text().stream())
              .findFirst()
              .orElseThrow()
              .text();
      ObjectMapper mapper = new ObjectMapper();
      JsonNode assessment = mapper.readTree(assessmentJson);

      // 평가 결과에서 위반 상태 추출
      boolean containsViolation = assessment.required("violation").asBoolean();

      // 위반이 있으면 카테고리와 설명을 가져오고, 그렇지 않으면 빈 기본값 사용
      List<String> violatedCategories = containsViolation && assessment.has("categories")
              ? mapper.convertValue(assessment.get("categories"), new TypeReference<List<String>>() {})
              : List.of();
      String explanation = containsViolation && assessment.hasNonNull("explanation")
              ? assessment.get("explanation").asText()
              : null;

      return new ModerationResult(containsViolation, violatedCategories, explanation);
  }

  // 각 댓글을 처리하고 결과 출력
  void printModerationResults() throws JsonProcessingException {
      for (String comment : userComments) {
          IO.println("\nComment: " + comment);
          ModerationResult result = moderateMessage(comment, unsafeCategories);

          if (result.violation()) {
              IO.println("Violated Categories: " + String.join(", ", result.violatedCategories()));
              IO.println("Explanation: " + result.explanation());
          } else {
              IO.println("No issues detected.");
          }
      }
  }
  ```

  ```php PHP
  $moderateMessage = function (string $message, array $unsafeCategories) use ($client): array {
      // 안전하지 않은 카테고리를 각 카테고리가 한 줄씩 차지하는 문자열로 변환
      $unsafeCategoryStr = implode("\n", $unsafeCategories);

      // 메시지와 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
      $assessmentPrompt = <<<PROMPT

          Determine whether the following message warrants moderation,
          based on the unsafe categories outlined below.

          Message:
          <message>{$message}</message>

          Unsafe Categories:
          <categories>
          {$unsafeCategoryStr}
          </categories>

          Respond with ONLY a JSON object, using the format below:
          {
          "violation": <Boolean field denoting whether the message should be moderated>,
          "categories": [Comma-separated list of violated categories],
          "explanation": [Optional. Only include if there is a violation.]
          }
      Do not include markdown formatting or code fences in your response.
      PROMPT;

      // 콘텐츠 조정을 위해 Claude에 요청 전송
      $response = $client->messages->create(
          model: 'claude-haiku-4-5-20251001', // Using the Haiku model for lower costs
          maxTokens: 200,
          messages: [['role' => 'user', 'content' => $assessmentPrompt]],
      );

      // Claude의 JSON 응답을 파싱합니다. SDK는 각 콘텐츠 블록을
      // 구체적인 클래스로 디코딩하므로, 텍스트를 읽기 전에 TextBlock을 찾습니다.
      $textBlock = array_find($response->content, fn ($block) => $block instanceof \Anthropic\Messages\TextBlock)
          ?? throw new \RuntimeException('Expected a text block in the response.');
      $assessment = json_decode($textBlock->text, associative: true, flags: JSON_THROW_ON_ERROR);

      // 평가 결과에서 위반 여부 추출
      $containsViolation = $assessment['violation'];

      // 위반이 있으면 카테고리와 설명을 가져오고, 그렇지 않으면 빈 기본값 사용
      $violatedCategories = $containsViolation ? ($assessment['categories'] ?? []) : [];
      $explanation = $containsViolation ? ($assessment['explanation'] ?? null) : null;

      return [$containsViolation, $violatedCategories, $explanation];
  };

  // 각 댓글을 처리하고 결과 출력
  foreach ($userComments as $comment) {
      echo "\nComment: {$comment}\n";
      [$violation, $violatedCategories, $explanation] = $moderateMessage($comment, $unsafeCategories);

      if ($violation) {
          echo 'Violated Categories: ' . implode(', ', $violatedCategories) . "\n";
          echo "Explanation: {$explanation}\n";
      } else {
          echo "No issues detected.\n";
      }
  }
  ```

  ```ruby Ruby
  def moderate_message(message, unsafe_categories)
    # 안전하지 않은 카테고리를 각 카테고리가 한 줄씩 차지하는 문자열로 변환
    unsafe_category_str = unsafe_categories.join("\n")

    # 메시지와 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
    assessment_prompt = <<~PROMPT.chomp

          Determine whether the following message warrants moderation,
          based on the unsafe categories outlined below.

          Message:
          <message>#{message}</message>

          Unsafe Categories:
          <categories>
          #{unsafe_category_str}
          </categories>

          Respond with ONLY a JSON object, using the format below:
          {
          "violation": <Boolean field denoting whether the message should be moderated>,
          "categories": [Comma-separated list of violated categories],
          "explanation": [Optional. Only include if there is a violation.]
          }
      Do not include markdown formatting or code fences in your response.
    PROMPT

    # 콘텐츠 조정을 위해 Claude에 요청 전송
    response = CLIENT.messages.create(
      model: "claude-haiku-4-5-20251001", # Using the Haiku model for lower costs
      max_tokens: 200,
      messages: [{role: :user, content: assessment_prompt}]
    )

    # Claude의 JSON 응답 파싱
    text_block = response.content.find { it.type == :text }
    assessment = JSON.parse(text_block.text)

    # 평가 결과에서 위반 상태 추출
    contains_violation = assessment["violation"]

    # 위반이 있으면 카테고리와 설명을 가져오고, 그렇지 않으면 빈 기본값 사용
    violated_categories = contains_violation ? assessment.fetch("categories", []) : []
    explanation = contains_violation ? assessment["explanation"] : nil

    [contains_violation, violated_categories, explanation]
  end


  # 각 댓글을 처리하고 결과 출력
  USER_COMMENTS.each do |comment|
    puts "\nComment: #{comment}"
    violation, violated_categories, explanation = moderate_message(comment, UNSAFE_CATEGORIES)

    if violation
      puts "Violated Categories: #{violated_categories.join(", ")}"
      puts "Explanation: #{explanation}"
    else
      puts "No issues detected."
    end
  end
  ```
</CodeGroup>

이 예시에서 `moderate_message` 함수에는 안전하지 않은 콘텐츠 카테고리와 평가할 메시지를 포함하는 평가 프롬프트가 들어 있습니다. 이 프롬프트는 앞서 정의한 안전하지 않은 카테고리를 기반으로 메시지를 모더레이션해야 하는지 여부를 Claude에게 평가하도록 요청합니다.

그런 다음 모델의 평가를 파싱하여 위반 사항이 있는지 판단합니다. 위반 사항이 있는 경우, Claude는 위반된 카테고리 목록과 메시지가 안전하지 않은 이유에 대한 설명도 함께 반환합니다.

### 프롬프트 평가하기

콘텐츠 모더레이션은 분류 문제입니다. 따라서 [분류 cookbook](https://platform.claude.com/cookbook/capabilities-classification-guide)에 설명된 것과 동일한 기법을 사용하여 콘텐츠 모더레이션 시스템의 정확도를 판단할 수 있습니다.

한 가지 추가로 고려할 점은 콘텐츠 모더레이션을 이진 분류 문제로 취급하는 대신, 다양한 위험 수준을 나타내는 여러 카테고리를 만들 수 있다는 것입니다. 여러 위험 수준을 만들면 모더레이션의 강도를 조정할 수 있습니다. 예를 들어, 고위험으로 간주되는 사용자 쿼리는 자동으로 차단하고, 중간 위험 쿼리가 많은 사용자는 인간 검토 대상으로 표시할 수 있습니다.

<CodeGroup exclude="shell">
  ```python Python
  def assess_risk_level(message, unsafe_categories):
      # 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
      unsafe_category_str = "\n".join(unsafe_categories)

      # 메시지, 안전하지 않은 카테고리, 위험 수준 정의를 포함하여 Claude용 프롬프트 구성
      assessment_prompt = f"""
      Assess the risk level of the following message,
      based on the unsafe categories listed below.

  Message:
  <message>{message}</message>

  Unsafe Categories:
  <categories>
  {unsafe_category_str}
  </categories>

  Assign a risk level based on your confidence that the user's message should be moderated
  based on the defined unsafe categories:

  0 - No risk
  1 - Low risk
  2 - Medium risk
  3 - High risk

  Respond with ONLY a JSON object, using the format below:
  {{
    "risk_level": <Numerical field denoting the risk level>,
    "categories": [Comma-separated list of violated categories],
    "explanation": <Optional. Only include if risk level is greater than 0>
  }}
  Do not include markdown formatting or code fences in your response."""

      # 위험 평가를 위해 Claude에 요청 전송
      response = client.messages.create(
          model="claude-haiku-4-5-20251001",  # Using the Haiku model for lower costs
          max_tokens=200,
          messages=[{"role": "user", "content": assessment_prompt}],
      )

      # Claude의 JSON 응답 파싱
      text_block = next(block for block in response.content if block.type == "text")
      assessment = json.loads(text_block.text)

      # 평가 결과에서 위험 수준, 위반된 카테고리, 설명 추출
      risk_level = assessment["risk_level"]
      violated_categories = assessment["categories"]
      explanation = assessment.get("explanation")

      return risk_level, violated_categories, explanation


  # 각 댓글을 처리하고 결과 출력
  for comment in user_comments:
      print(f"\nComment: {comment}")
      risk_level, violated_categories, explanation = assess_risk_level(
          comment, unsafe_categories
      )

      print(f"Risk Level: {risk_level}")
      if violated_categories:
          print(f"Violated Categories: {', '.join(violated_categories)}")
      if explanation:
          print(f"Explanation: {explanation}")
  ```

  ```typescript TypeScript
  // Claude가 반환하는 JSON 위험 평가의 형태
  interface RiskAssessment {
    risk_level: number;
    categories: string[];
    explanation?: string;
  }

  async function assessRiskLevel(
    message: string,
    unsafeCategories: string[]
  ): Promise<{ riskLevel: number; violatedCategories: string[]; explanation?: string }> {
    // 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
    const unsafeCategoryStr = unsafeCategories.join("\n");

    // 메시지, 안전하지 않은 카테고리, 위험 수준 정의를 포함하여 Claude용 프롬프트 구성
    const assessmentPrompt = `
      Assess the risk level of the following message,
      based on the unsafe categories listed below.

  Message:
  <message>${message}</message>

  Unsafe Categories:
  <categories>
  ${unsafeCategoryStr}
  </categories>

  Assign a risk level based on your confidence that the user's message should be moderated
  based on the defined unsafe categories:

  0 - No risk
  1 - Low risk
  2 - Medium risk
  3 - High risk

  Respond with ONLY a JSON object, using the format below:
  {
    "risk_level": <Numerical field denoting the risk level>,
    "categories": [Comma-separated list of violated categories],
    "explanation": <Optional. Only include if risk level is greater than 0>
  }
  Do not include markdown formatting or code fences in your response.`;

    // 위험 평가를 위해 Claude에 요청 전송
    const response = await client.messages.create({
      model: "claude-haiku-4-5-20251001", // Using the Haiku model for lower costs
      max_tokens: 200,
      messages: [{ role: "user", content: assessmentPrompt }]
    });

    // Claude의 JSON 응답 파싱
    const textBlock = response.content.find((block) => block.type === "text");
    if (!textBlock) {
      throw new Error("Expected a text block in the response");
    }
    const assessment: RiskAssessment = JSON.parse(textBlock.text);

    // 평가에서 위험 수준, 위반된 카테고리, 설명 추출
    const { risk_level: riskLevel, categories: violatedCategories, explanation } = assessment;

    return { riskLevel, violatedCategories, explanation };
  }

  // 각 댓글을 처리하고 결과 출력
  for (const comment of userComments) {
    console.log(`\nComment: ${comment}`);
    const { riskLevel, violatedCategories, explanation } = await assessRiskLevel(
      comment,
      unsafeCategories
    );

    console.log(`Risk Level: ${riskLevel}`);
    if (violatedCategories.length > 0) {
      console.log(`Violated Categories: ${violatedCategories.join(", ")}`);
    }
    if (explanation) {
      console.log(`Explanation: ${explanation}`);
    }
  }
  ```

  ```csharp C#
  async Task<(int RiskLevel, List<string> ViolatedCategories, string? Explanation)> AssessRiskLevel(
      string message,
      IReadOnlyList<string> categories
  )
  {
      // 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
      var unsafeCategoryText = string.Join("\n", categories);

      // 메시지, 안전하지 않은 카테고리, 위험 수준 정의를 포함하여 Claude용 프롬프트 구성
      var assessmentPrompt = $$"""

      Assess the risk level of the following message,
      based on the unsafe categories listed below.

  Message:
  <message>{{message}}</message>

  Unsafe Categories:
  <categories>
  {{unsafeCategoryText}}
  </categories>

  Assign a risk level based on your confidence that the user's message should be moderated
  based on the defined unsafe categories:

  0 - No risk
  1 - Low risk
  2 - Medium risk
  3 - High risk

  Respond with ONLY a JSON object, using the format below:
  {
    "risk_level": <Numerical field denoting the risk level>,
    "categories": [Comma-separated list of violated categories],
    "explanation": <Optional. Only include if risk level is greater than 0>
  }
  Do not include markdown formatting or code fences in your response.
  """;

      // 위험 평가를 위해 Claude에 요청 전송
      var response = await client.Messages.Create(
          new()
          {
              Model = Model.ClaudeHaiku4_5_20251001, // Using the Haiku model for lower costs
              MaxTokens = 200,
              Messages = [new() { Role = Role.User, Content = assessmentPrompt }],
          }
      );

      // 첫 번째 콘텐츠 블록을 텍스트 블록으로 좁힌 다음 Claude의 JSON 응답을 파싱
      if (!response.Content[0].TryPickText(out var textBlock))
      {
          throw new InvalidOperationException("Expected a text response from Claude.");
      }
      var assessment = JsonNode.Parse(textBlock.Text)!;

      // 평가 결과에서 위험 수준, 위반된 카테고리, 설명 추출
      var riskLevel = assessment["risk_level"]!.GetValue<int>();
      var violatedCategories = assessment["categories"]!
          .AsArray()
          .Select(category => category!.GetValue<string>())
          .ToList();
      var explanation = assessment["explanation"]?.GetValue<string>();

      return (riskLevel, violatedCategories, explanation);
  }

  // 각 댓글을 처리하고 결과 출력
  foreach (var comment in userComments)
  {
      Console.WriteLine($"\nComment: {comment}");
      var (riskLevel, violatedCategories, explanation) = await AssessRiskLevel(comment, unsafeCategories);

      Console.WriteLine($"Risk Level: {riskLevel}");
      if (violatedCategories.Count > 0)
      {
          Console.WriteLine($"Violated Categories: {string.Join(", ", violatedCategories)}");
      }
      if (!string.IsNullOrEmpty(explanation))
      {
          Console.WriteLine($"Explanation: {explanation}");
      }
  }
  ```

  ```go Go
  func assessRiskLevel(message string, unsafeCategories []string) (int, []string, string) {
  	// 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
  	unsafeCategoryStr := strings.Join(unsafeCategories, "\n")

  	// 메시지, 안전하지 않은 카테고리, 위험 수준 정의를 포함하여 Claude용 프롬프트 구성
  	assessmentPrompt := fmt.Sprintf(`
      Assess the risk level of the following message,
      based on the unsafe categories listed below.

  Message:
  <message>%s</message>

  Unsafe Categories:
  <categories>
  %s
  </categories>

  Assign a risk level based on your confidence that the user's message should be moderated
  based on the defined unsafe categories:

  0 - No risk
  1 - Low risk
  2 - Medium risk
  3 - High risk

  Respond with ONLY a JSON object, using the format below:
  {
    "risk_level": <Numerical field denoting the risk level>,
    "categories": [Comma-separated list of violated categories],
    "explanation": <Optional. Only include if risk level is greater than 0>
  }
  Do not include markdown formatting or code fences in your response.`, message, unsafeCategoryStr)

  	// 위험 평가를 위해 Claude에 요청 전송
  	response, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
  		Model:     anthropic.ModelClaudeHaiku4_5_20251001, // Using the Haiku model for lower costs
  		MaxTokens: 200,
  		Messages: []anthropic.MessageParam{
  			anthropic.NewUserMessage(anthropic.NewTextBlock(assessmentPrompt)),
  		},
  	})
  	if err != nil {
  		log.Fatal(err)
  	}

  	// 텍스트를 읽기 전에 첫 번째 콘텐츠 블록을 텍스트 블록으로 좁히기
  	textBlock, ok := response.Content[0].AsAny().(anthropic.TextBlock)
  	if !ok {
  		log.Fatalf("expected a text block, got %q", response.Content[0].Type)
  	}

  	// Claude의 JSON 응답 파싱
  	var assessment struct {
  		RiskLevel   int      `json:"risk_level"`
  		Categories  []string `json:"categories"`
  		Explanation string   `json:"explanation"`
  	}
  	if err := json.Unmarshal([]byte(textBlock.Text), &assessment); err != nil {
  		log.Fatal(err)
  	}

  	// 평가에서 위험 수준, 위반된 카테고리, 설명 반환
  	return assessment.RiskLevel, assessment.Categories, assessment.Explanation
  }

  // assessAllRiskLevels는 각 댓글을 처리하고 결과를 출력합니다.
  func assessAllRiskLevels() {
  	for _, comment := range userComments {
  		fmt.Printf("\nComment: %s\n", comment)
  		riskLevel, violatedCategories, explanation := assessRiskLevel(comment, unsafeCategories)

  		fmt.Printf("Risk Level: %d\n", riskLevel)
  		if len(violatedCategories) > 0 {
  			fmt.Printf("Violated Categories: %s\n", strings.Join(violatedCategories, ", "))
  		}
  		if explanation != "" {
  			fmt.Printf("Explanation: %s\n", explanation)
  		}
  	}
  }
  ```

  ```java Java
  record RiskAssessment(int riskLevel, List<String> violatedCategories, String explanation) {}

  RiskAssessment assessRiskLevel(String message, List<String> unsafeCategories)
          throws JsonProcessingException {
      // 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
      String unsafeCategoryStr = String.join("\n", unsafeCategories);

      // 메시지, 안전하지 않은 카테고리, 위험 수준 정의를 포함하여 Claude용 프롬프트 구성
      String assessmentPrompt = """

              Assess the risk level of the following message,
              based on the unsafe categories listed below.

          Message:
          <message>%s</message>

          Unsafe Categories:
          <categories>
          %s
          </categories>

          Assign a risk level based on your confidence that the user's message should be moderated
          based on the defined unsafe categories:

          0 - No risk
          1 - Low risk
          2 - Medium risk
          3 - High risk

          Respond with ONLY a JSON object, using the format below:
          {
            "risk_level": <Numerical field denoting the risk level>,
            "categories": [Comma-separated list of violated categories],
            "explanation": <Optional. Only include if risk level is greater than 0>
          }
          Do not include markdown formatting or code fences in your response."""
              .formatted(message, unsafeCategoryStr);

      // 위험 평가를 위해 Claude에 요청 전송
      Message response = client.messages().create(MessageCreateParams.builder()
              .model(Model.CLAUDE_HAIKU_4_5_20251001) // Using the Haiku model for lower costs
              .maxTokens(200)
              .addUserMessage(assessmentPrompt)
              .build());

      // Claude의 JSON 응답 파싱
      String assessmentJson = response.content().stream()
              .flatMap(contentBlock -> contentBlock.text().stream())
              .findFirst()
              .orElseThrow()
              .text();
      ObjectMapper mapper = new ObjectMapper();
      JsonNode assessment = mapper.readTree(assessmentJson);

      // 평가 결과에서 위험 수준, 위반된 카테고리, 설명 추출
      int riskLevel = assessment.required("risk_level").asInt();
      JsonNode categoriesNode = assessment.required("categories");
      List<String> violatedCategories = categoriesNode.isNull()
              ? List.of()
              : mapper.convertValue(categoriesNode, new TypeReference<List<String>>() {});
      String explanation = assessment.hasNonNull("explanation")
              ? assessment.get("explanation").asText()
              : null;

      return new RiskAssessment(riskLevel, violatedCategories, explanation);
  }

  // 각 댓글을 처리하고 결과 출력
  void printRiskLevels() throws JsonProcessingException {
      for (String comment : userComments) {
          IO.println("\nComment: " + comment);
          RiskAssessment assessment = assessRiskLevel(comment, unsafeCategories);

          IO.println("Risk Level: " + assessment.riskLevel());
          if (!assessment.violatedCategories().isEmpty()) {
              IO.println("Violated Categories: " + String.join(", ", assessment.violatedCategories()));
          }
          if (assessment.explanation() != null && !assessment.explanation().isEmpty()) {
              IO.println("Explanation: " + assessment.explanation());
          }
      }
  }
  ```

  ```php PHP
  $assessRiskLevel = function (string $message, array $unsafeCategories) use ($client): array {
      // 안전하지 않은 카테고리를 각 카테고리가 한 줄씩 차지하는 문자열로 변환
      $unsafeCategoryStr = implode("\n", $unsafeCategories);

      // 메시지, 안전하지 않은 카테고리, 위험 수준 정의를 포함하여 Claude용 프롬프트 구성
      $assessmentPrompt = <<<PROMPT

          Assess the risk level of the following message,
          based on the unsafe categories listed below.

      Message:
      <message>{$message}</message>

      Unsafe Categories:
      <categories>
      {$unsafeCategoryStr}
      </categories>

      Assign a risk level based on your confidence that the user's message should be moderated
      based on the defined unsafe categories:

      0 - No risk
      1 - Low risk
      2 - Medium risk
      3 - High risk

      Respond with ONLY a JSON object, using the format below:
      {
        "risk_level": <Numerical field denoting the risk level>,
        "categories": [Comma-separated list of violated categories],
        "explanation": <Optional. Only include if risk level is greater than 0>
      }
      Do not include markdown formatting or code fences in your response.
      PROMPT;

      // 위험 평가를 위해 Claude에 요청 전송
      $response = $client->messages->create(
          model: 'claude-haiku-4-5-20251001', // Using the Haiku model for lower costs
          maxTokens: 200,
          messages: [['role' => 'user', 'content' => $assessmentPrompt]],
      );

      // Claude의 JSON 응답을 파싱합니다. SDK는 각 콘텐츠 블록을
      // 구체적인 클래스로 디코딩하므로, 텍스트를 읽기 전에 TextBlock을 찾습니다.
      $textBlock = array_find($response->content, fn ($block) => $block instanceof \Anthropic\Messages\TextBlock)
          ?? throw new \RuntimeException('Expected a text block in the response.');
      $assessment = json_decode($textBlock->text, associative: true, flags: JSON_THROW_ON_ERROR);

      // 평가 결과에서 위험 수준, 위반된 카테고리, 설명 추출
      $riskLevel = $assessment['risk_level'];
      $violatedCategories = $assessment['categories'];
      $explanation = $assessment['explanation'] ?? null;

      return [$riskLevel, $violatedCategories, $explanation];
  };

  // 각 댓글을 처리하고 결과 출력
  foreach ($userComments as $comment) {
      echo "\nComment: {$comment}\n";
      [$riskLevel, $violatedCategories, $explanation] = $assessRiskLevel($comment, $unsafeCategories);

      echo "Risk Level: {$riskLevel}\n";
      if ($violatedCategories) {
          echo 'Violated Categories: ' . implode(', ', $violatedCategories) . "\n";
      }
      if ($explanation) {
          echo "Explanation: {$explanation}\n";
      }
  }
  ```

  ```ruby Ruby
  def assess_risk_level(message, unsafe_categories)
    # 안전하지 않은 카테고리를 각 카테고리가 한 줄씩 차지하는 문자열로 변환
    unsafe_category_str = unsafe_categories.join("\n")

    # 메시지, 안전하지 않은 카테고리, 위험 수준 정의를 포함하여 Claude용 프롬프트 구성
    assessment_prompt = <<~PROMPT.chomp

          Assess the risk level of the following message,
          based on the unsafe categories listed below.

      Message:
      <message>#{message}</message>

      Unsafe Categories:
      <categories>
      #{unsafe_category_str}
      </categories>

      Assign a risk level based on your confidence that the user's message should be moderated
      based on the defined unsafe categories:

      0 - No risk
      1 - Low risk
      2 - Medium risk
      3 - High risk

      Respond with ONLY a JSON object, using the format below:
      {
        "risk_level": <Numerical field denoting the risk level>,
        "categories": [Comma-separated list of violated categories],
        "explanation": <Optional. Only include if risk level is greater than 0>
      }
      Do not include markdown formatting or code fences in your response.
    PROMPT

    # 위험 평가를 위해 Claude에 요청 전송
    response = CLIENT.messages.create(
      model: "claude-haiku-4-5-20251001", # Using the Haiku model for lower costs
      max_tokens: 200,
      messages: [{role: :user, content: assessment_prompt}]
    )

    # Claude의 JSON 응답 파싱
    text_block = response.content.find { it.type == :text }
    assessment = JSON.parse(text_block.text)

    # 평가 결과에서 위험 수준, 위반된 카테고리, 설명 추출
    risk_level = assessment["risk_level"]
    violated_categories = assessment["categories"]
    explanation = assessment["explanation"]

    [risk_level, violated_categories, explanation]
  end


  # 각 댓글을 처리하고 결과 출력
  USER_COMMENTS.each do |comment|
    puts "\nComment: #{comment}"
    risk_level, violated_categories, explanation = assess_risk_level(comment, UNSAFE_CATEGORIES)

    puts "Risk Level: #{risk_level}"
    puts "Violated Categories: #{violated_categories.join(", ")}" if violated_categories&.any?
    puts "Explanation: #{explanation}" if explanation
  end
  ```
</CodeGroup>

이 코드는 Claude를 사용하여 메시지의 위험 수준을 평가하는 `assess_risk_level` 함수를 구현합니다. 이 함수는 메시지와 안전하지 않은 카테고리를 입력으로 받습니다.

함수 내에서는 평가할 메시지, 안전하지 않은 카테고리, 위험 수준 평가를 위한 구체적인 지침을 포함하는 프롬프트가 Claude를 위해 생성됩니다. 이 프롬프트는 Claude에게 위험 수준, 위반된 카테고리, 선택적 설명을 포함하는 JSON 객체로 응답하도록 지시합니다.

이 접근 방식은 위험 수준을 할당함으로써 유연한 콘텐츠 모더레이션을 가능하게 합니다. 이는 더 큰 시스템에 원활하게 통합되어 평가된 위험 수준에 따라 콘텐츠 필터링을 자동화하거나 댓글을 인간 검토 대상으로 표시할 수 있습니다. 예를 들어, 이 코드를 실행하면 `Delete this post now or you better hide. I am coming after you and your family.`라는 댓글은 위험한 위협 때문에 고위험으로 식별됩니다. 반대로, `Stay away from the 5G cellphones!! They are using 5G to control you.`라는 댓글은 중간 위험으로 분류됩니다.

### 프롬프트 배포하기

솔루션의 품질에 확신이 생기면 프로덕션에 배포할 차례입니다. 다음은 프로덕션에서 콘텐츠 모더레이션을 사용할 때 따라야 할 몇 가지 모범 사례입니다:

1. **사용자에게 명확한 피드백 제공:** 콘텐츠 모더레이션으로 인해 사용자 입력이 차단되거나 응답이 표시된 경우, 사용자가 자신의 메시지가 표시된 이유와 적절하게 다시 표현하는 방법을 이해할 수 있도록 유익하고 건설적인 피드백을 제공하세요. 앞선 코딩 예시에서는 Claude 응답의 `explanation` 필드를 통해 이를 수행합니다.

2. **모더레이션된 콘텐츠 분석:** 모더레이션 시스템에 의해 표시되는 콘텐츠 유형을 추적하여 추세와 잠재적인 개선 영역을 파악하세요.

3. **지속적인 평가 및 개선:** 정밀도 및 재현율 추적과 같은 지표를 사용하여 콘텐츠 모더레이션 시스템의 성능을 정기적으로 평가하세요. 이 데이터를 사용하여 모더레이션 프롬프트, 키워드 및 평가 기준을 반복적으로 개선하세요.

***

## 성능 향상

복잡한 시나리오에서는 표준 [프롬프트 엔지니어링 기법](https://platform.claude.com/docs/ko/build-with-claude/prompt-engineering/overview) 외에 성능을 향상시키기 위한 추가 전략을 고려하는 것이 도움이 될 수 있습니다. 다음은 몇 가지 고급 전략입니다:

### 주제 정의 및 예시 제공

프롬프트에 안전하지 않은 카테고리를 나열하는 것 외에도, 각 카테고리와 관련된 정의와 문구를 제공하여 추가적인 개선을 이룰 수 있습니다.

<CodeGroup exclude="shell">
  ```python Python
  # 콘텐츠 조정에서 안전하지 않은 것으로 간주되는 카테고리와 그 정의
  unsafe_category_definitions = {
      "Child Exploitation": "Content that depicts child nudity or that enables, encourages, excuses, or depicts the sexual abuse of children.",
      "Conspiracy Theories": """Content that promotes or endorses unfounded, false, or misleading theories about events, situations, or individuals,
          which can incite harm or undermine public trust in institutions or facts.""",
      "Hate": """Content that is hateful toward people on the basis of their protected characteristics
          (race, color, ethnicity, national origin, disability, religious affiliation, caste, sexual orientation, sex, gender identity and serious disease),
          or content that perpetuates negative stereotypes.""",
      "Indiscriminate Weapons": "Content that enables the creation of weapons of mass destruction.",
      "Intellectual Property": "Content that violates the intellectual property rights of third parties.",
      "Non-Violent Crimes": "Content that enables, encourages, or excuses the commission of non-violent crimes.",
      "Privacy": "Content that contains sensitive, personal information about private individuals.",
      "Self-Harm": "Content that enables, encourages, or excuses acts of intentional self-harm.",
      "Sex Crimes": "Content that enables, encourages, or excuses the commission of sex crimes.",
      "Sexual Content": "Content that contains erotic descriptions or explicit depictions of sex acts.",
      "Specialized Advice": """Content that contains financial, medical, or legal advice.
          Financial advice includes guidance on investments, stocks, bonds, or any financial planning.""",
      "Violent Crimes": "Content that enables, encourages, or excuses the commission of violent crimes.",
  }


  def moderate_message_with_definitions(message, unsafe_category_definitions):
      # 각 카테고리와 정의가 새 줄에 오도록 안전하지 않은 카테고리 문자열 포맷
      unsafe_category_str = "\n".join(
          f"{category}: {definition}"
          for category, definition in unsafe_category_definitions.items()
      )

      # 메시지와 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
      assessment_prompt = f"""Determine whether the following message warrants moderation, based on the unsafe categories outlined below.

  Message:
  <message>{message}</message>

  Unsafe Categories and Their Definitions:
  <categories>
  {unsafe_category_str}
  </categories>

  It's important that you remember all unsafe categories and their definitions.

  Respond with ONLY a JSON object, using the format below:
  {{
    "violation": <Boolean field denoting whether the message should be moderated>,
    "categories": [Comma-separated list of violated categories],
    "explanation": [Optional. Only include if there is a violation.]
  }}
  Do not include markdown formatting or code fences in your response."""

      # 콘텐츠 조정을 위해 Claude에 요청 전송
      response = client.messages.create(
          model="claude-haiku-4-5-20251001",  # Using the Haiku model for lower costs
          max_tokens=200,
          messages=[{"role": "user", "content": assessment_prompt}],
      )

      # Claude의 JSON 응답 파싱
      text_block = next(block for block in response.content if block.type == "text")
      assessment = json.loads(text_block.text)

      # 평가 결과에서 위반 상태 추출
      contains_violation = assessment["violation"]

      # 위반이 있으면 카테고리와 설명을 가져오고, 그렇지 않으면 빈 기본값 사용
      violated_categories = assessment.get("categories", []) if contains_violation else []
      explanation = assessment.get("explanation") if contains_violation else None

      return contains_violation, violated_categories, explanation


  # 각 댓글을 처리하고 결과 출력
  for comment in user_comments:
      print(f"\nComment: {comment}")
      violation, violated_categories, explanation = moderate_message_with_definitions(
          comment, unsafe_category_definitions
      )

      if violation:
          print(f"Violated Categories: {', '.join(violated_categories)}")
          print(f"Explanation: {explanation}")
      else:
          print("No issues detected.")
  ```

  ```typescript TypeScript
  // Claude가 반환하는 JSON 평가의 형태
  interface DefinitionBasedAssessment {
    violation: boolean;
    categories?: string[];
    explanation?: string;
  }

  // 콘텐츠 조정에서 안전하지 않은 것으로 간주되는 카테고리와 그 정의
  // (객체 키는 삽입 순서를 유지하므로 카테고리가 이 순서로 표시됨)
  const unsafeCategoryDefinitions: Record<string, string> = {
    "Child Exploitation":
      "Content that depicts child nudity or that enables, encourages, excuses, or depicts the sexual abuse of children.",
    "Conspiracy Theories": `Content that promotes or endorses unfounded, false, or misleading theories about events, situations, or individuals,
          which can incite harm or undermine public trust in institutions or facts.`,
    Hate: `Content that is hateful toward people on the basis of their protected characteristics
          (race, color, ethnicity, national origin, disability, religious affiliation, caste, sexual orientation, sex, gender identity and serious disease),
          or content that perpetuates negative stereotypes.`,
    "Indiscriminate Weapons":
      "Content that enables the creation of weapons of mass destruction.",
    "Intellectual Property":
      "Content that violates the intellectual property rights of third parties.",
    "Non-Violent Crimes":
      "Content that enables, encourages, or excuses the commission of non-violent crimes.",
    Privacy: "Content that contains sensitive, personal information about private individuals.",
    "Self-Harm": "Content that enables, encourages, or excuses acts of intentional self-harm.",
    "Sex Crimes": "Content that enables, encourages, or excuses the commission of sex crimes.",
    "Sexual Content":
      "Content that contains erotic descriptions or explicit depictions of sex acts.",
    "Specialized Advice": `Content that contains financial, medical, or legal advice.
          Financial advice includes guidance on investments, stocks, bonds, or any financial planning.`,
    "Violent Crimes":
      "Content that enables, encourages, or excuses the commission of violent crimes."
  };

  async function moderateMessageWithDefinitions(
    message: string,
    unsafeCategoryDefinitions: Record<string, string>
  ): Promise<{ violation: boolean; violatedCategories: string[]; explanation?: string }> {
    // 각 카테고리와 그 정의가 새 줄에 오도록 안전하지 않은 카테고리 문자열 포맷
    const unsafeCategoryStr = Object.entries(unsafeCategoryDefinitions)
      .map(([category, definition]) => `${category}: ${definition}`)
      .join("\n");

    // 메시지와 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
    const assessmentPrompt = `Determine whether the following message warrants moderation, based on the unsafe categories outlined below.

  Message:
  <message>${message}</message>

  Unsafe Categories and Their Definitions:
  <categories>
  ${unsafeCategoryStr}
  </categories>

  It's important that you remember all unsafe categories and their definitions.

  Respond with ONLY a JSON object, using the format below:
  {
    "violation": <Boolean field denoting whether the message should be moderated>,
    "categories": [Comma-separated list of violated categories],
    "explanation": [Optional. Only include if there is a violation.]
  }
  Do not include markdown formatting or code fences in your response.`;

    // 콘텐츠 조정을 위해 Claude에 요청 전송
    const response = await client.messages.create({
      model: "claude-haiku-4-5-20251001", // Using the Haiku model for lower costs
      max_tokens: 200,
      messages: [{ role: "user", content: assessmentPrompt }]
    });

    // Claude의 JSON 응답 파싱
    const textBlock = response.content.find((block) => block.type === "text");
    if (!textBlock) {
      throw new Error("Expected a text block in the response");
    }
    const assessment: DefinitionBasedAssessment = JSON.parse(textBlock.text);

    // 평가에서 위반 상태 추출
    const containsViolation = assessment.violation;

    // 위반이 있으면 카테고리와 설명을 가져오고, 그렇지 않으면 빈 기본값 사용
    const violatedCategories = containsViolation ? (assessment.categories ?? []) : [];
    const explanation = containsViolation ? assessment.explanation : undefined;

    return { violation: containsViolation, violatedCategories, explanation };
  }

  // 각 댓글을 처리하고 결과 출력
  for (const comment of userComments) {
    console.log(`\nComment: ${comment}`);
    const { violation, violatedCategories, explanation } = await moderateMessageWithDefinitions(
      comment,
      unsafeCategoryDefinitions
    );

    if (violation) {
      console.log(`Violated Categories: ${violatedCategories.join(", ")}`);
      console.log(`Explanation: ${explanation}`);
    } else {
      console.log("No issues detected.");
    }
  }
  ```

  ```csharp C#
  // 콘텐츠 조정에서 안전하지 않은 것으로 간주되는 카테고리와 그 정의입니다.
  // 항목은 삽입 순서를 유지하므로 렌더링된 프롬프트는 카테고리를
  // 정확히 이 순서대로 나열합니다.
  (string Category, string Definition)[] unsafeCategoryDefinitions =
  [
      (
          "Child Exploitation",
          "Content that depicts child nudity or that enables, encourages, excuses, or depicts the sexual abuse of children."
      ),
      (
          "Conspiracy Theories",
          """
          Content that promotes or endorses unfounded, false, or misleading theories about events, situations, or individuals,
                  which can incite harm or undermine public trust in institutions or facts.
          """
      ),
      (
          "Hate",
          """
          Content that is hateful toward people on the basis of their protected characteristics
                  (race, color, ethnicity, national origin, disability, religious affiliation, caste, sexual orientation, sex, gender identity and serious disease),
                  or content that perpetuates negative stereotypes.
          """
      ),
      ("Indiscriminate Weapons", "Content that enables the creation of weapons of mass destruction."),
      ("Intellectual Property", "Content that violates the intellectual property rights of third parties."),
      ("Non-Violent Crimes", "Content that enables, encourages, or excuses the commission of non-violent crimes."),
      ("Privacy", "Content that contains sensitive, personal information about private individuals."),
      ("Self-Harm", "Content that enables, encourages, or excuses acts of intentional self-harm."),
      ("Sex Crimes", "Content that enables, encourages, or excuses the commission of sex crimes."),
      ("Sexual Content", "Content that contains erotic descriptions or explicit depictions of sex acts."),
      (
          "Specialized Advice",
          """
          Content that contains financial, medical, or legal advice.
                  Financial advice includes guidance on investments, stocks, bonds, or any financial planning.
          """
      ),
      ("Violent Crimes", "Content that enables, encourages, or excuses the commission of violent crimes."),
  ];


  async Task<(bool ContainsViolation, List<string> ViolatedCategories, string? Explanation)> ModerateMessageWithDefinitions(
      string message,
      IReadOnlyList<(string Category, string Definition)> categoryDefinitions
  )
  {
      // 각 카테고리와 그 정의가 새 줄에 오도록 안전하지 않은 카테고리 문자열 포맷
      var unsafeCategoryText = string.Join(
          "\n",
          categoryDefinitions.Select(entry => $"{entry.Category}: {entry.Definition}")
      );

      // 메시지와 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
      var assessmentPrompt = $$"""
  Determine whether the following message warrants moderation, based on the unsafe categories outlined below.

  Message:
  <message>{{message}}</message>

  Unsafe Categories and Their Definitions:
  <categories>
  {{unsafeCategoryText}}
  </categories>

  It's important that you remember all unsafe categories and their definitions.

  Respond with ONLY a JSON object, using the format below:
  {
    "violation": <Boolean field denoting whether the message should be moderated>,
    "categories": [Comma-separated list of violated categories],
    "explanation": [Optional. Only include if there is a violation.]
  }
  Do not include markdown formatting or code fences in your response.
  """;

      // 콘텐츠 조정을 위해 Claude에 요청 전송
      var response = await client.Messages.Create(
          new()
          {
              Model = Model.ClaudeHaiku4_5_20251001, // Using the Haiku model for lower costs
              MaxTokens = 200,
              Messages = [new() { Role = Role.User, Content = assessmentPrompt }],
          }
      );

      // 첫 번째 콘텐츠 블록을 텍스트 블록으로 좁힌 다음 Claude의 JSON 응답을 파싱
      if (!response.Content[0].TryPickText(out var textBlock))
      {
          throw new InvalidOperationException("Expected a text response from Claude.");
      }
      var assessment = JsonNode.Parse(textBlock.Text)!;

      // 평가 결과에서 위반 상태 추출
      var containsViolation = assessment["violation"]!.GetValue<bool>();

      // 위반이 있으면 카테고리와 설명을 가져오고, 그렇지 않으면 빈 기본값 사용
      List<string> violatedCategories = containsViolation
          ? assessment["categories"]?.AsArray().Select(category => category!.GetValue<string>()).ToList() ?? []
          : [];
      var explanation = containsViolation ? assessment["explanation"]?.GetValue<string>() : null;

      return (containsViolation, violatedCategories, explanation);
  }

  // 각 댓글을 처리하고 결과 출력
  foreach (var comment in userComments)
  {
      Console.WriteLine($"\nComment: {comment}");
      var (violation, violatedCategories, explanation) = await ModerateMessageWithDefinitions(
          comment,
          unsafeCategoryDefinitions
      );

      if (violation)
      {
          Console.WriteLine($"Violated Categories: {string.Join(", ", violatedCategories)}");
          Console.WriteLine($"Explanation: {explanation}");
      }
      else
      {
          Console.WriteLine("No issues detected.");
      }
  }
  ```

  ```go Go
  // 콘텐츠 조정에서 안전하지 않은 것으로 간주되는 카테고리와 그 정의입니다.
  // 맵 대신 카테고리/정의 쌍의 슬라이스를 사용하면 렌더링 순서가
  // 안정적으로 유지됩니다. Go 맵은 무작위 순서로 반복됩니다.
  type categoryDefinition struct {
  	category   string
  	definition string
  }

  var unsafeCategoryDefinitions = []categoryDefinition{
  	{"Child Exploitation", "Content that depicts child nudity or that enables, encourages, excuses, or depicts the sexual abuse of children."},
  	{"Conspiracy Theories", `Content that promotes or endorses unfounded, false, or misleading theories about events, situations, or individuals,
          which can incite harm or undermine public trust in institutions or facts.`},
  	{"Hate", `Content that is hateful toward people on the basis of their protected characteristics
          (race, color, ethnicity, national origin, disability, religious affiliation, caste, sexual orientation, sex, gender identity and serious disease),
          or content that perpetuates negative stereotypes.`},
  	{"Indiscriminate Weapons", "Content that enables the creation of weapons of mass destruction."},
  	{"Intellectual Property", "Content that violates the intellectual property rights of third parties."},
  	{"Non-Violent Crimes", "Content that enables, encourages, or excuses the commission of non-violent crimes."},
  	{"Privacy", "Content that contains sensitive, personal information about private individuals."},
  	{"Self-Harm", "Content that enables, encourages, or excuses acts of intentional self-harm."},
  	{"Sex Crimes", "Content that enables, encourages, or excuses the commission of sex crimes."},
  	{"Sexual Content", "Content that contains erotic descriptions or explicit depictions of sex acts."},
  	{"Specialized Advice", `Content that contains financial, medical, or legal advice.
          Financial advice includes guidance on investments, stocks, bonds, or any financial planning.`},
  	{"Violent Crimes", "Content that enables, encourages, or excuses the commission of violent crimes."},
  }

  func moderateMessageWithDefinitions(message string, unsafeCategoryDefinitions []categoryDefinition) (bool, []string, string) {
  	// 각 카테고리와 그 정의가 새 줄에 오도록 안전하지 않은 카테고리 문자열 포맷
  	categoryLines := make([]string, len(unsafeCategoryDefinitions))
  	for i, entry := range unsafeCategoryDefinitions {
  		categoryLines[i] = fmt.Sprintf("%s: %s", entry.category, entry.definition)
  	}
  	unsafeCategoryStr := strings.Join(categoryLines, "\n")

  	// 메시지와 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
  	assessmentPrompt := fmt.Sprintf(`Determine whether the following message warrants moderation, based on the unsafe categories outlined below.

  Message:
  <message>%s</message>

  Unsafe Categories and Their Definitions:
  <categories>
  %s
  </categories>

  It's important that you remember all unsafe categories and their definitions.

  Respond with ONLY a JSON object, using the format below:
  {
    "violation": <Boolean field denoting whether the message should be moderated>,
    "categories": [Comma-separated list of violated categories],
    "explanation": [Optional. Only include if there is a violation.]
  }
  Do not include markdown formatting or code fences in your response.`, message, unsafeCategoryStr)

  	// 콘텐츠 조정을 위해 Claude에 요청 전송
  	response, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
  		Model:     anthropic.ModelClaudeHaiku4_5_20251001, // Using the Haiku model for lower costs
  		MaxTokens: 200,
  		Messages: []anthropic.MessageParam{
  			anthropic.NewUserMessage(anthropic.NewTextBlock(assessmentPrompt)),
  		},
  	})
  	if err != nil {
  		log.Fatal(err)
  	}

  	// 텍스트를 읽기 전에 첫 번째 콘텐츠 블록을 텍스트 블록으로 좁히기
  	textBlock, ok := response.Content[0].AsAny().(anthropic.TextBlock)
  	if !ok {
  		log.Fatalf("expected a text block, got %q", response.Content[0].Type)
  	}

  	// Claude의 JSON 응답 파싱
  	var assessment struct {
  		Violation   bool     `json:"violation"`
  		Categories  []string `json:"categories"`
  		Explanation string   `json:"explanation"`
  	}
  	if err := json.Unmarshal([]byte(textBlock.Text), &assessment); err != nil {
  		log.Fatal(err)
  	}

  	// 위반이 있으면 카테고리와 설명을 반환하고, 그렇지 않으면 빈 기본값 사용
  	if !assessment.Violation {
  		return false, nil, ""
  	}
  	return true, assessment.Categories, assessment.Explanation
  }

  // moderateAllCommentsWithDefinitions는 각 댓글을 처리하고 결과를 출력합니다.
  func moderateAllCommentsWithDefinitions() {
  	for _, comment := range userComments {
  		fmt.Printf("\nComment: %s\n", comment)
  		violation, violatedCategories, explanation := moderateMessageWithDefinitions(comment, unsafeCategoryDefinitions)

  		if violation {
  			fmt.Printf("Violated Categories: %s\n", strings.Join(violatedCategories, ", "))
  			fmt.Printf("Explanation: %s\n", explanation)
  		} else {
  			fmt.Println("No issues detected.")
  		}
  	}
  }
  ```

  ```java Java
  // 콘텐츠 조정에서 안전하지 않은 것으로 간주되는 카테고리와 그 정의
  record CategoryDefinition(String category, String definition) {}

  final List<CategoryDefinition> unsafeCategoryDefinitions = List.of(
          new CategoryDefinition(
                  "Child Exploitation",
                  "Content that depicts child nudity or that enables, encourages, excuses, or depicts the sexual abuse of children."),
          new CategoryDefinition(
                  "Conspiracy Theories",
                  """
                  Content that promotes or endorses unfounded, false, or misleading theories about events, situations, or individuals,
                          which can incite harm or undermine public trust in institutions or facts."""),
          new CategoryDefinition(
                  "Hate",
                  """
                  Content that is hateful toward people on the basis of their protected characteristics
                          (race, color, ethnicity, national origin, disability, religious affiliation, caste, sexual orientation, sex, gender identity and serious disease),
                          or content that perpetuates negative stereotypes."""),
          new CategoryDefinition(
                  "Indiscriminate Weapons",
                  "Content that enables the creation of weapons of mass destruction."),
          new CategoryDefinition(
                  "Intellectual Property",
                  "Content that violates the intellectual property rights of third parties."),
          new CategoryDefinition(
                  "Non-Violent Crimes",
                  "Content that enables, encourages, or excuses the commission of non-violent crimes."),
          new CategoryDefinition(
                  "Privacy",
                  "Content that contains sensitive, personal information about private individuals."),
          new CategoryDefinition(
                  "Self-Harm",
                  "Content that enables, encourages, or excuses acts of intentional self-harm."),
          new CategoryDefinition(
                  "Sex Crimes",
                  "Content that enables, encourages, or excuses the commission of sex crimes."),
          new CategoryDefinition(
                  "Sexual Content",
                  "Content that contains erotic descriptions or explicit depictions of sex acts."),
          new CategoryDefinition(
                  "Specialized Advice",
                  """
                  Content that contains financial, medical, or legal advice.
                          Financial advice includes guidance on investments, stocks, bonds, or any financial planning."""),
          new CategoryDefinition(
                  "Violent Crimes",
                  "Content that enables, encourages, or excuses the commission of violent crimes."));

  record ModerationDecision(boolean violation, List<String> violatedCategories, String explanation) {}

  ModerationDecision moderateMessageWithDefinitions(
          String message, List<CategoryDefinition> unsafeCategoryDefinitions)
          throws JsonProcessingException {
      // 각 카테고리와 정의가 새 줄에 오도록 안전하지 않은 카테고리 문자열 포맷
      String unsafeCategoryStr = unsafeCategoryDefinitions.stream()
              .map(categoryDefinition ->
                      categoryDefinition.category() + ": " + categoryDefinition.definition())
              .collect(Collectors.joining("\n"));

      // 메시지와 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
      String assessmentPrompt = """
          Determine whether the following message warrants moderation, based on the unsafe categories outlined below.

          Message:
          <message>%s</message>

          Unsafe Categories and Their Definitions:
          <categories>
          %s
          </categories>

          It's important that you remember all unsafe categories and their definitions.

          Respond with ONLY a JSON object, using the format below:
          {
            "violation": <Boolean field denoting whether the message should be moderated>,
            "categories": [Comma-separated list of violated categories],
            "explanation": [Optional. Only include if there is a violation.]
          }
          Do not include markdown formatting or code fences in your response."""
              .formatted(message, unsafeCategoryStr);

      // 콘텐츠 조정을 위해 Claude에 요청 전송
      Message response = client.messages().create(MessageCreateParams.builder()
              .model(Model.CLAUDE_HAIKU_4_5_20251001) // Using the Haiku model for lower costs
              .maxTokens(200)
              .addUserMessage(assessmentPrompt)
              .build());

      // Claude의 JSON 응답 파싱
      String assessmentJson = response.content().stream()
              .flatMap(contentBlock -> contentBlock.text().stream())
              .findFirst()
              .orElseThrow()
              .text();
      ObjectMapper mapper = new ObjectMapper();
      JsonNode assessment = mapper.readTree(assessmentJson);

      // 평가 결과에서 위반 상태 추출
      boolean containsViolation = assessment.required("violation").asBoolean();

      // 위반이 있으면 카테고리와 설명을 가져오고, 그렇지 않으면 빈 기본값 사용
      List<String> violatedCategories = containsViolation && assessment.has("categories")
              ? mapper.convertValue(assessment.get("categories"), new TypeReference<List<String>>() {})
              : List.of();
      String explanation = containsViolation && assessment.hasNonNull("explanation")
              ? assessment.get("explanation").asText()
              : null;

      return new ModerationDecision(containsViolation, violatedCategories, explanation);
  }

  // 각 댓글을 처리하고 결과 출력
  void printModerationResultsWithDefinitions() throws JsonProcessingException {
      for (String comment : userComments) {
          IO.println("\nComment: " + comment);
          ModerationDecision result = moderateMessageWithDefinitions(comment, unsafeCategoryDefinitions);

          if (result.violation()) {
              IO.println("Violated Categories: " + String.join(", ", result.violatedCategories()));
              IO.println("Explanation: " + result.explanation());
          } else {
              IO.println("No issues detected.");
          }
      }
  }
  ```

  ```php PHP
  // 콘텐츠 조정에서 안전하지 않은 것으로 간주되는 카테고리와 그 정의
  $unsafeCategoryDefinitions = [
      'Child Exploitation' => 'Content that depicts child nudity or that enables, encourages, excuses, or depicts the sexual abuse of children.',
      'Conspiracy Theories' => 'Content that promotes or endorses unfounded, false, or misleading theories about events, situations, or individuals,
          which can incite harm or undermine public trust in institutions or facts.',
      'Hate' => 'Content that is hateful toward people on the basis of their protected characteristics
          (race, color, ethnicity, national origin, disability, religious affiliation, caste, sexual orientation, sex, gender identity and serious disease),
          or content that perpetuates negative stereotypes.',
      'Indiscriminate Weapons' => 'Content that enables the creation of weapons of mass destruction.',
      'Intellectual Property' => 'Content that violates the intellectual property rights of third parties.',
      'Non-Violent Crimes' => 'Content that enables, encourages, or excuses the commission of non-violent crimes.',
      'Privacy' => 'Content that contains sensitive, personal information about private individuals.',
      'Self-Harm' => 'Content that enables, encourages, or excuses acts of intentional self-harm.',
      'Sex Crimes' => 'Content that enables, encourages, or excuses the commission of sex crimes.',
      'Sexual Content' => 'Content that contains erotic descriptions or explicit depictions of sex acts.',
      'Specialized Advice' => 'Content that contains financial, medical, or legal advice.
          Financial advice includes guidance on investments, stocks, bonds, or any financial planning.',
      'Violent Crimes' => 'Content that enables, encourages, or excuses the commission of violent crimes.',
  ];

  $moderateMessageWithDefinitions = function (string $message, array $unsafeCategoryDefinitions) use ($client): array {
      // 각 카테고리와 정의가 한 줄씩 차지하도록 안전하지 않은 카테고리 문자열 포맷
      $categoryLines = [];
      foreach ($unsafeCategoryDefinitions as $category => $definition) {
          $categoryLines[] = "{$category}: {$definition}";
      }
      $unsafeCategoryStr = implode("\n", $categoryLines);

      // 메시지와 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
      $assessmentPrompt = <<<PROMPT
      Determine whether the following message warrants moderation, based on the unsafe categories outlined below.

      Message:
      <message>{$message}</message>

      Unsafe Categories and Their Definitions:
      <categories>
      {$unsafeCategoryStr}
      </categories>

      It's important that you remember all unsafe categories and their definitions.

      Respond with ONLY a JSON object, using the format below:
      {
        "violation": <Boolean field denoting whether the message should be moderated>,
        "categories": [Comma-separated list of violated categories],
        "explanation": [Optional. Only include if there is a violation.]
      }
      Do not include markdown formatting or code fences in your response.
      PROMPT;

      // 콘텐츠 조정을 위해 Claude에 요청 전송
      $response = $client->messages->create(
          model: 'claude-haiku-4-5-20251001', // Using the Haiku model for lower costs
          maxTokens: 200,
          messages: [['role' => 'user', 'content' => $assessmentPrompt]],
      );

      // Claude의 JSON 응답을 파싱합니다. SDK는 각 콘텐츠 블록을
      // 구체적인 클래스로 디코딩하므로, 텍스트를 읽기 전에 TextBlock을 찾습니다.
      $textBlock = array_find($response->content, fn ($block) => $block instanceof \Anthropic\Messages\TextBlock)
          ?? throw new \RuntimeException('Expected a text block in the response.');
      $assessment = json_decode($textBlock->text, associative: true, flags: JSON_THROW_ON_ERROR);

      // 평가 결과에서 위반 여부 추출
      $containsViolation = $assessment['violation'];

      // 위반이 있으면 카테고리와 설명을 가져오고, 그렇지 않으면 빈 기본값 사용
      $violatedCategories = $containsViolation ? ($assessment['categories'] ?? []) : [];
      $explanation = $containsViolation ? ($assessment['explanation'] ?? null) : null;

      return [$containsViolation, $violatedCategories, $explanation];
  };

  // 각 댓글을 처리하고 결과 출력
  foreach ($userComments as $comment) {
      echo "\nComment: {$comment}\n";
      [$violation, $violatedCategories, $explanation] = $moderateMessageWithDefinitions($comment, $unsafeCategoryDefinitions);

      if ($violation) {
          echo 'Violated Categories: ' . implode(', ', $violatedCategories) . "\n";
          echo "Explanation: {$explanation}\n";
      } else {
          echo "No issues detected.\n";
      }
  }
  ```

  ```ruby Ruby
  # 콘텐츠 조정에서 안전하지 않은 것으로 간주되는 카테고리와 그 정의
  UNSAFE_CATEGORY_DEFINITIONS = {
    "Child Exploitation" => "Content that depicts child nudity or that enables, encourages, excuses, or depicts the sexual abuse of children.",
    "Conspiracy Theories" => "Content that promotes or endorses unfounded, false, or misleading theories about events, situations, or individuals,
          which can incite harm or undermine public trust in institutions or facts.",
    "Hate" => "Content that is hateful toward people on the basis of their protected characteristics
          (race, color, ethnicity, national origin, disability, religious affiliation, caste, sexual orientation, sex, gender identity and serious disease),
          or content that perpetuates negative stereotypes.",
    "Indiscriminate Weapons" => "Content that enables the creation of weapons of mass destruction.",
    "Intellectual Property" => "Content that violates the intellectual property rights of third parties.",
    "Non-Violent Crimes" => "Content that enables, encourages, or excuses the commission of non-violent crimes.",
    "Privacy" => "Content that contains sensitive, personal information about private individuals.",
    "Self-Harm" => "Content that enables, encourages, or excuses acts of intentional self-harm.",
    "Sex Crimes" => "Content that enables, encourages, or excuses the commission of sex crimes.",
    "Sexual Content" => "Content that contains erotic descriptions or explicit depictions of sex acts.",
    "Specialized Advice" => "Content that contains financial, medical, or legal advice.
          Financial advice includes guidance on investments, stocks, bonds, or any financial planning.",
    "Violent Crimes" => "Content that enables, encourages, or excuses the commission of violent crimes."
  }


  def moderate_message_with_definitions(message, unsafe_category_definitions)
    # 각 카테고리와 정의가 한 줄씩 차지하도록 안전하지 않은 카테고리 문자열 포맷
    unsafe_category_str = unsafe_category_definitions
      .map { |category, definition| "#{category}: #{definition}" }
      .join("\n")

    # 메시지와 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
    assessment_prompt = <<~PROMPT.chomp
      Determine whether the following message warrants moderation, based on the unsafe categories outlined below.

      Message:
      <message>#{message}</message>

      Unsafe Categories and Their Definitions:
      <categories>
      #{unsafe_category_str}
      </categories>

      It's important that you remember all unsafe categories and their definitions.

      Respond with ONLY a JSON object, using the format below:
      {
        "violation": <Boolean field denoting whether the message should be moderated>,
        "categories": [Comma-separated list of violated categories],
        "explanation": [Optional. Only include if there is a violation.]
      }
      Do not include markdown formatting or code fences in your response.
    PROMPT

    # 콘텐츠 조정을 위해 Claude에 요청 전송
    response = CLIENT.messages.create(
      model: "claude-haiku-4-5-20251001", # Using the Haiku model for lower costs
      max_tokens: 200,
      messages: [{role: :user, content: assessment_prompt}]
    )

    # Claude의 JSON 응답 파싱
    text_block = response.content.find { it.type == :text }
    assessment = JSON.parse(text_block.text)

    # 평가 결과에서 위반 상태 추출
    contains_violation = assessment["violation"]

    # 위반이 있으면 카테고리와 설명을 가져오고, 그렇지 않으면 빈 기본값 사용
    violated_categories = contains_violation ? assessment.fetch("categories", []) : []
    explanation = contains_violation ? assessment["explanation"] : nil

    [contains_violation, violated_categories, explanation]
  end


  # 각 댓글을 처리하고 결과 출력
  USER_COMMENTS.each do |comment|
    puts "\nComment: #{comment}"
    violation, violated_categories, explanation = moderate_message_with_definitions(comment, UNSAFE_CATEGORY_DEFINITIONS)

    if violation
      puts "Violated Categories: #{violated_categories.join(", ")}"
      puts "Explanation: #{explanation}"
    else
      puts "No issues detected."
    end
  end
  ```
</CodeGroup>

`moderate_message_with_definitions` 함수는 각 안전하지 않은 카테고리를 상세한 정의와 짝지을 수 있도록 하여 앞선 `moderate_message` 함수를 확장합니다. 이는 코드에서 원래 함수의 `unsafe_categories` 컬렉션을 `unsafe_category_definitions` 매핑으로 대체함으로써 이루어집니다. 이 매핑은 각 안전하지 않은 카테고리를 해당 정의와 짝짓습니다. 카테고리 이름과 그 정의가 모두 프롬프트에 포함됩니다.

특히, `Specialized Advice` 카테고리의 정의는 이제 금지되어야 하는 금융 조언의 유형을 명시합니다. 그 결과, 이전에는 `moderate_message` 평가를 통과했던 `It is a great time to invest in gold!`라는 댓글이 이제 위반을 유발합니다.

### 배치 처리 고려하기

실시간 모더레이션이 필요하지 않은 상황에서 비용을 줄이려면 메시지를 배치로 모더레이션하는 것을 고려하세요. 프롬프트의 컨텍스트 내에 여러 메시지를 포함하고, Claude에게 어떤 메시지를 모더레이션해야 하는지 평가하도록 요청하세요.

<CodeGroup exclude="shell">
  ```python Python
  def batch_moderate_messages(messages, unsafe_categories):
      # 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
      unsafe_category_str = "\n".join(unsafe_categories)

      # 각 메시지를 XML 형식 태그로 감싸고 ID를 부여하여 메시지 문자열 포맷
      messages_str = "\n".join(
          [f"<message id={idx}>{msg}</message>" for idx, msg in enumerate(messages)]
      )

      # 메시지들과 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
      assessment_prompt = f"""Determine the messages to moderate, based on the unsafe categories outlined below.

  Messages:
  <messages>
  {messages_str}
  </messages>

  Unsafe Categories:
  <categories>
  {unsafe_category_str}
  </categories>

  Respond with ONLY a JSON object, using the format below:
  {{
    "violations": [
      {{
        "id": <message id>,
        "categories": [list of violated categories],
        "explanation": <Explanation of why there's a violation>
      }}
    ]
  }}

  Important Notes:
  - Remember to analyze every message for a violation.
  - Select any number of violations that reasonably apply.
  - Do not include markdown formatting or code fences in your response."""

      # 콘텐츠 조정을 위해 Claude에 요청 전송
      response = client.messages.create(
          model="claude-haiku-4-5-20251001",  # Using the Haiku model for lower costs
          max_tokens=2048,  # Increased max token count to handle batches
          messages=[{"role": "user", "content": assessment_prompt}],
      )

      # Claude의 JSON 응답 파싱
      text_block = next(block for block in response.content if block.type == "text")
      assessment = json.loads(text_block.text)
      return assessment


  # 댓글 배치를 처리하고 응답 가져오기
  response_obj = batch_moderate_messages(user_comments, unsafe_categories)

  # 감지된 각 위반에 대한 결과 출력
  for violation in response_obj["violations"]:
      print(f"""Comment: {user_comments[violation["id"]]}
  Violated Categories: {", ".join(violation["categories"])}
  Explanation: {violation["explanation"]}
  """)
  ```

  ```typescript TypeScript
  // Claude가 반환하는 JSON 배치 평가의 형태
  interface BatchAssessment {
    violations: {
      id: number;
      categories: string[];
      explanation: string;
    }[];
  }

  async function batchModerateMessages(
    messages: string[],
    unsafeCategories: string[]
  ): Promise<BatchAssessment> {
    // 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
    const unsafeCategoryStr = unsafeCategories.join("\n");

    // 각 메시지를 XML 형태의 태그로 감싸고 ID를 부여하여 메시지 문자열 포맷
    const messagesStr = messages
      .map((msg, idx) => `<message id=${idx}>${msg}</message>`)
      .join("\n");

    // 메시지들과 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
    const assessmentPrompt = `Determine the messages to moderate, based on the unsafe categories outlined below.

  Messages:
  <messages>
  ${messagesStr}
  </messages>

  Unsafe Categories:
  <categories>
  ${unsafeCategoryStr}
  </categories>

  Respond with ONLY a JSON object, using the format below:
  {
    "violations": [
      {
        "id": <message id>,
        "categories": [list of violated categories],
        "explanation": <Explanation of why there's a violation>
      }
    ]
  }

  Important Notes:
  - Remember to analyze every message for a violation.
  - Select any number of violations that reasonably apply.
  - Do not include markdown formatting or code fences in your response.`;

    // 콘텐츠 조정을 위해 Claude에 요청 전송
    const response = await client.messages.create({
      model: "claude-haiku-4-5-20251001", // Using the Haiku model for lower costs
      max_tokens: 2048, // Increased max token count to handle batches
      messages: [{ role: "user", content: assessmentPrompt }]
    });

    // Claude의 JSON 응답 파싱
    const textBlock = response.content.find((block) => block.type === "text");
    if (!textBlock) {
      throw new Error("Expected a text block in the response");
    }
    const assessment: BatchAssessment = JSON.parse(textBlock.text);
    return assessment;
  }

  // 댓글 배치를 처리하고 응답 가져오기
  const batchAssessment = await batchModerateMessages(userComments, unsafeCategories);

  // 감지된 각 위반에 대한 결과 출력
  for (const violation of batchAssessment.violations) {
    console.log(`Comment: ${userComments[violation.id]}
  Violated Categories: ${violation.categories.join(", ")}
  Explanation: ${violation.explanation}
  `);
  }
  ```

  ```csharp C#
  async Task<JsonNode> BatchModerateMessages(IReadOnlyList<string> messages, IReadOnlyList<string> categories)
  {
      // 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
      var unsafeCategoryText = string.Join("\n", categories);

      // 각 메시지를 XML 형식 태그로 감싸고 ID를 부여하여 메시지 문자열 포맷
      var messagesText = string.Join(
          "\n",
          messages.Select((message, index) => $"<message id={index}>{message}</message>")
      );

      // 메시지들과 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
      var assessmentPrompt = $$"""
  Determine the messages to moderate, based on the unsafe categories outlined below.

  Messages:
  <messages>
  {{messagesText}}
  </messages>

  Unsafe Categories:
  <categories>
  {{unsafeCategoryText}}
  </categories>

  Respond with ONLY a JSON object, using the format below:
  {
    "violations": [
      {
        "id": <message id>,
        "categories": [list of violated categories],
        "explanation": <Explanation of why there's a violation>
      }
    ]
  }

  Important Notes:
  - Remember to analyze every message for a violation.
  - Select any number of violations that reasonably apply.
  - Do not include markdown formatting or code fences in your response.
  """;

      // 콘텐츠 조정을 위해 Claude에 요청 전송
      var response = await client.Messages.Create(
          new()
          {
              Model = Model.ClaudeHaiku4_5_20251001, // Using the Haiku model for lower costs
              MaxTokens = 2048, // Increased max token count to handle batches
              Messages = [new() { Role = Role.User, Content = assessmentPrompt }],
          }
      );

      // 첫 번째 콘텐츠 블록을 텍스트 블록으로 좁힌 다음 Claude의 JSON 응답을 파싱
      if (!response.Content[0].TryPickText(out var textBlock))
      {
          throw new InvalidOperationException("Expected a text response from Claude.");
      }
      return JsonNode.Parse(textBlock.Text)!;
  }

  // 댓글 배치를 처리하고 응답 가져오기
  var moderationResults = await BatchModerateMessages(userComments, unsafeCategories);

  // 감지된 각 위반에 대한 결과 출력
  foreach (var violation in moderationResults["violations"]!.AsArray())
  {
      var flaggedComment = userComments[violation!["id"]!.GetValue<int>()];
      var violatedCategories = string.Join(
          ", ",
          violation["categories"]!.AsArray().Select(category => category!.GetValue<string>())
      );
      var explanation = violation["explanation"]!.GetValue<string>();

      Console.WriteLine($"""
          Comment: {flaggedComment}
          Violated Categories: {violatedCategories}
          Explanation: {explanation}

          """);
  }
  ```

  ```go Go
  // batchViolation은 Claude의 "violations" 배열의 한 항목으로, 위반한
  // 메시지의 인덱스와 위반한 카테고리 및 그 이유를 담습니다.
  type batchViolation struct {
  	ID          int      `json:"id"`
  	Categories  []string `json:"categories"`
  	Explanation string   `json:"explanation"`
  }

  func batchModerateMessages(messages []string, unsafeCategories []string) []batchViolation {
  	// 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
  	unsafeCategoryStr := strings.Join(unsafeCategories, "\n")

  	// 각 메시지를 XML 유사 태그로 감싸고 ID를 부여하여 메시지 문자열 포맷
  	messageLines := make([]string, len(messages))
  	for i, message := range messages {
  		messageLines[i] = fmt.Sprintf("<message id=%d>%s</message>", i, message)
  	}
  	messagesStr := strings.Join(messageLines, "\n")

  	// 메시지들과 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
  	assessmentPrompt := fmt.Sprintf(`Determine the messages to moderate, based on the unsafe categories outlined below.

  Messages:
  <messages>
  %s
  </messages>

  Unsafe Categories:
  <categories>
  %s
  </categories>

  Respond with ONLY a JSON object, using the format below:
  {
    "violations": [
      {
        "id": <message id>,
        "categories": [list of violated categories],
        "explanation": <Explanation of why there's a violation>
      }
    ]
  }

  Important Notes:
  - Remember to analyze every message for a violation.
  - Select any number of violations that reasonably apply.
  - Do not include markdown formatting or code fences in your response.`, messagesStr, unsafeCategoryStr)

  	// 콘텐츠 조정을 위해 Claude에 요청 전송
  	response, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
  		Model:     anthropic.ModelClaudeHaiku4_5_20251001, // Using the Haiku model for lower costs
  		MaxTokens: 2048,                                   // Increased max token count to handle batches
  		Messages: []anthropic.MessageParam{
  			anthropic.NewUserMessage(anthropic.NewTextBlock(assessmentPrompt)),
  		},
  	})
  	if err != nil {
  		log.Fatal(err)
  	}

  	// 텍스트를 읽기 전에 첫 번째 콘텐츠 블록을 텍스트 블록으로 좁히기
  	textBlock, ok := response.Content[0].AsAny().(anthropic.TextBlock)
  	if !ok {
  		log.Fatalf("expected a text block, got %q", response.Content[0].Type)
  	}

  	// Claude의 JSON 응답 파싱
  	var assessment struct {
  		Violations []batchViolation `json:"violations"`
  	}
  	if err := json.Unmarshal([]byte(textBlock.Text), &assessment); err != nil {
  		log.Fatal(err)
  	}
  	return assessment.Violations
  }

  // moderateAllCommentsAsBatch는 전체 댓글 배치를 단일 요청으로 조정하고
  // 감지된 각 위반에 대한 결과를 출력합니다.
  func moderateAllCommentsAsBatch() {
  	// 댓글 배치를 처리하고 응답 받기
  	violations := batchModerateMessages(userComments, unsafeCategories)

  	// 감지된 각 위반에 대한 결과 출력
  	for _, violation := range violations {
  		fmt.Printf(`Comment: %s
  Violated Categories: %s
  Explanation: %s

  `, userComments[violation.ID], strings.Join(violation.Categories, ", "), violation.Explanation)
  	}
  }
  ```

  ```java Java
  JsonNode batchModerateMessages(List<String> messages, List<String> unsafeCategories)
          throws JsonProcessingException {
      // 안전하지 않은 카테고리를 각 카테고리가 새 줄에 오도록 문자열로 변환
      String unsafeCategoryStr = String.join("\n", unsafeCategories);

      // 각 메시지를 XML 형식 태그로 감싸고 ID를 부여하여 메시지 문자열 포맷
      String messagesStr = IntStream.range(0, messages.size())
              .mapToObj(idx -> "<message id=%d>%s</message>".formatted(idx, messages.get(idx)))
              .collect(Collectors.joining("\n"));

      // 메시지들과 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
      String assessmentPrompt = """
          Determine the messages to moderate, based on the unsafe categories outlined below.

          Messages:
          <messages>
          %s
          </messages>

          Unsafe Categories:
          <categories>
          %s
          </categories>

          Respond with ONLY a JSON object, using the format below:
          {
            "violations": [
              {
                "id": <message id>,
                "categories": [list of violated categories],
                "explanation": <Explanation of why there's a violation>
              }
            ]
          }

          Important Notes:
          - Remember to analyze every message for a violation.
          - Select any number of violations that reasonably apply.
          - Do not include markdown formatting or code fences in your response."""
              .formatted(messagesStr, unsafeCategoryStr);

      // 콘텐츠 조정을 위해 Claude에 요청 전송
      Message response = client.messages().create(MessageCreateParams.builder()
              .model(Model.CLAUDE_HAIKU_4_5_20251001) // Using the Haiku model for lower costs
              .maxTokens(2048) // Increased max token count to handle batches
              .addUserMessage(assessmentPrompt)
              .build());

      // Claude의 JSON 응답 파싱
      String assessmentJson = response.content().stream()
              .flatMap(contentBlock -> contentBlock.text().stream())
              .findFirst()
              .orElseThrow()
              .text();
      return new ObjectMapper().readTree(assessmentJson);
  }

  // 댓글 배치를 처리하고 감지된 각 위반에 대한 결과 출력
  void printBatchViolations() throws JsonProcessingException {
      JsonNode response = batchModerateMessages(userComments, unsafeCategories);

      ObjectMapper mapper = new ObjectMapper();
      for (JsonNode violation : response.required("violations")) {
          List<String> violatedCategories =
                  mapper.convertValue(violation.required("categories"), new TypeReference<List<String>>() {});
          IO.println("""
                  Comment: %s
                  Violated Categories: %s
                  Explanation: %s
                  """.formatted(
                          userComments.get(violation.required("id").asInt()),
                          String.join(", ", violatedCategories),
                          violation.required("explanation").asText()));
      }
  }
  ```

  ```php PHP
  $batchModerateMessages = function (array $messages, array $unsafeCategories) use ($client): array {
      // 안전하지 않은 카테고리를 각 카테고리가 한 줄씩 차지하는 문자열로 변환
      $unsafeCategoryStr = implode("\n", $unsafeCategories);

      // 각 메시지를 XML 형태의 태그로 감싸고 ID를 부여하여 메시지 문자열 포맷
      $messageLines = [];
      foreach ($messages as $idx => $msg) {
          $messageLines[] = "<message id={$idx}>{$msg}</message>";
      }
      $messagesStr = implode("\n", $messageLines);

      // 메시지들과 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
      $assessmentPrompt = <<<PROMPT
      Determine the messages to moderate, based on the unsafe categories outlined below.

      Messages:
      <messages>
      {$messagesStr}
      </messages>

      Unsafe Categories:
      <categories>
      {$unsafeCategoryStr}
      </categories>

      Respond with ONLY a JSON object, using the format below:
      {
        "violations": [
          {
            "id": <message id>,
            "categories": [list of violated categories],
            "explanation": <Explanation of why there's a violation>
          }
        ]
      }

      Important Notes:
      - Remember to analyze every message for a violation.
      - Select any number of violations that reasonably apply.
      - Do not include markdown formatting or code fences in your response.
      PROMPT;

      // 콘텐츠 조정을 위해 Claude에 요청 전송
      $response = $client->messages->create(
          model: 'claude-haiku-4-5-20251001', // Using the Haiku model for lower costs
          maxTokens: 2048, // Increased max token count to handle batches
          messages: [['role' => 'user', 'content' => $assessmentPrompt]],
      );

      // Claude의 JSON 응답을 파싱합니다. SDK는 각 콘텐츠 블록을
      // 구체적인 클래스로 디코딩하므로, 텍스트를 읽기 전에 TextBlock을 찾습니다.
      $textBlock = array_find($response->content, fn ($block) => $block instanceof \Anthropic\Messages\TextBlock)
          ?? throw new \RuntimeException('Expected a text block in the response.');

      return json_decode($textBlock->text, associative: true, flags: JSON_THROW_ON_ERROR);
  };

  // 댓글 배치를 처리하고 응답 가져오기
  $responseObj = $batchModerateMessages($userComments, $unsafeCategories);

  // 감지된 각 위반에 대한 결과 출력
  foreach ($responseObj['violations'] as $violation) {
      echo "Comment: {$userComments[$violation['id']]}\n";
      echo 'Violated Categories: ' . implode(', ', $violation['categories']) . "\n";
      echo "Explanation: {$violation['explanation']}\n\n";
  }
  ```

  ```ruby Ruby
  def batch_moderate_messages(messages, unsafe_categories)
    # 안전하지 않은 카테고리를 각 카테고리가 한 줄씩 차지하는 문자열로 변환
    unsafe_category_str = unsafe_categories.join("\n")

    # 각 메시지를 XML 형태의 태그로 감싸고 ID를 부여하여 메시지 문자열 포맷
    messages_str = messages
      .map.with_index { |message, index| "<message id=#{index}>#{message}</message>" }
      .join("\n")

    # 메시지들과 안전하지 않은 카테고리를 포함하여 Claude용 프롬프트 구성
    assessment_prompt = <<~PROMPT.chomp
      Determine the messages to moderate, based on the unsafe categories outlined below.

      Messages:
      <messages>
      #{messages_str}
      </messages>

      Unsafe Categories:
      <categories>
      #{unsafe_category_str}
      </categories>

      Respond with ONLY a JSON object, using the format below:
      {
        "violations": [
          {
            "id": <message id>,
            "categories": [list of violated categories],
            "explanation": <Explanation of why there's a violation>
          }
        ]
      }

      Important Notes:
      - Remember to analyze every message for a violation.
      - Select any number of violations that reasonably apply.
      - Do not include markdown formatting or code fences in your response.
    PROMPT

    # 콘텐츠 조정을 위해 Claude에 요청 전송
    response = CLIENT.messages.create(
      model: "claude-haiku-4-5-20251001", # Using the Haiku model for lower costs
      max_tokens: 2048, # Increased max token count to handle batches
      messages: [{role: :user, content: assessment_prompt}]
    )

    # Claude의 JSON 응답 파싱
    text_block = response.content.find { it.type == :text }
    JSON.parse(text_block.text)
  end


  # 댓글 배치를 처리하고 응답 가져오기
  response_obj = batch_moderate_messages(USER_COMMENTS, UNSAFE_CATEGORIES)

  # 감지된 각 위반에 대한 결과 출력
  response_obj["violations"].each do |violation|
    puts <<~RESULT
      Comment: #{USER_COMMENTS[violation["id"]]}
      Violated Categories: #{violation["categories"].join(", ")}
      Explanation: #{violation["explanation"]}

    RESULT
  end
  ```
</CodeGroup>

이 예시에서 `batch_moderate_messages` 함수는 단일 Claude API 호출로 전체 메시지 배치의 모더레이션을 처리합니다. 함수 내부에서는 평가할 메시지 목록과 안전하지 않은 콘텐츠 카테고리를 포함하는 프롬프트가 생성됩니다. 이 프롬프트는 Claude에게 위반 사항이 포함된 모든 메시지를 나열하는 JSON 객체를 반환하도록 지시합니다. 응답의 각 메시지는 배치 내 메시지의 위치에 해당하는 `id`로 식별됩니다. 특정 요구에 맞는 최적의 배치 크기를 찾으려면 약간의 실험이 필요할 수 있다는 점을 염두에 두세요. 배치 크기가 클수록 비용을 낮출 수 있지만, 품질이 약간 저하될 수도 있습니다. 또한, 더 긴 응답을 수용하기 위해 Claude API 호출에서 `max_tokens` 매개변수를 늘려야 할 수도 있습니다. 선택한 모델이 출력할 수 있는 최대 토큰 수에 대한 자세한 내용은 [모델 비교 표](https://platform.claude.com/docs/ko/models/overview#latest-models-comparison)를 참조하세요.

<CardGroup cols={2}>
  <Card title="콘텐츠 모더레이션 cookbook" icon="link" href="https://platform.claude.com/cookbook/misc-building-moderation-filter">
    콘텐츠 모더레이션에 Claude를 사용하는 방법에 대한 완전히 구현된 코드 기반 예시를 확인하세요.
  </Card>

  <Card title="탈옥 완화" icon="link" href="https://platform.claude.com/docs/ko/test-and-evaluate/strengthen-guardrails/mitigate-jailbreaks">
    Claude와의 상호작용을 모더레이션하기 위한 가드레일 기법을 살펴보세요.
  </Card>
</CardGroup>
