OpenAI Moderation

OpenAI Moderation

Spring AI는 텍스트에서 잠재적으로 유해하거나 민감한 콘텐츠를 감지할 수 있는 OpenAI의 Moderation 모델을 지원해요. 이 글에서는 의존성 추가, 자동 설정, 프로퍼티 그리고 런타임 옵션까지 차근차근 살펴볼게요.

출처: 문서

본문

Moderation

소개 (Introduction)

Spring AI는 텍스트에서 잠재적으로 유해하거나 민감한 콘텐츠를 감지할 수 있게 해 주는 OpenAI의 Moderation 모델을 지원해요. OpenAI의 moderation 모델에 대한 자세한 내용은 이 가이드를 참고해 주세요.

참고: 버전 2.0.0-M5부터 Spring AI는 모든 OpenAI 모델에 공식 openai-java SDK를 내부적으로 사용해요. 전환은 매끄럽게 이루어질 것이며, 기존 OpenAI API 프로퍼티와 빌더 사용자에게는 호환성을 깨는 변경이 없어요. 문제를 발견하면 Spring AI GitHub Issues에 알려 주세요.

사전 준비 (Prerequisites)

  1. OpenAI 계정을 만들고 API 키를 받으세요. OpenAI signup page에서 가입하고, API Keys page에서 API 키를 생성할 수 있어요.
  2. 프로젝트의 빌드 파일에 spring-ai-openai 의존성을 추가하세요. 자세한 내용은 Dependency Management 섹션을 참고해 주세요.

자동 설정 (Auto-configuration)

참고: Spring AI auto-configuration과 starter 모듈의 아티팩트 이름에 큰 변화가 있었어요. 자세한 내용은 upgrade notes를 참고해 주세요.

Spring AI는 OpenAI Moderation 모델에 대한 Spring Boot 자동 설정을 제공해요. 활성화하려면 프로젝트의 Maven pom.xml 파일에 다음 의존성을 추가하세요:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>

또는 Gradle build.gradle 빌드 파일에 추가할 수도 있어요:

dependencies {
    implementation 'org.springframework.ai:spring-ai-starter-model-openai'
}

참고: 빌드 파일에 Spring AI BOM을 추가하려면 Dependency Management 섹션을 참고해 주세요.

Moderation 프로퍼티 (Moderation Properties)

연결 프로퍼티 (Connection Properties)

프리픽스 spring.ai.openai는 OpenAI에 연결할 수 있게 해 주는 프로퍼티 프리픽스로 사용돼요.

Property Description Default
spring.ai.openai.base-url 연결할 URL api.openai.com
spring.ai.openai.api-key API 키 -
spring.ai.openai.organization-id 선택적으로 API 요청에 사용할 organization을 지정할 수 있어요. -
spring.ai.openai.project-id 선택적으로 API 요청에 사용할 project를 지정할 수 있어요. -
spring.ai.openai.timeout OpenAI 클라이언트의 요청 타임아웃. 60 sec.
spring.ai.openai.max-retries OpenAI 클라이언트의 최대 재시도 횟수. 3
spring.ai.openai.proxy OpenAI 클라이언트의 프록시 설정. -
spring.ai.openai.custom-headers OpenAI 클라이언트 요청에 추가할 커스텀 HTTP 헤더. empty
spring.ai.openai.connection-pool-metrics-enabled 내부 OkHttp 클라이언트의 연결 풀 메트릭스를 활성화할지 여부. false

참고: 여러 organization에 속한 사용자(또는 레거시 사용자 API 키로 프로젝트에 접근하는 사용자)는 선택적으로 API 요청에 사용할 organization과 project를 지정할 수 있어요. 이 API 요청에서의 사용량은 지정된 organization과 project의 사용량으로 집계돼요.

구성 프로퍼티 (Configuration Properties)

참고: embedding 자동 설정의 활성화·비활성화는 이제 프리픽스 spring.ai.model.moderation이 붙은 최상위 프로퍼티로 구성해요. 활성화하려면 spring.ai.model.moderation=openai (기본적으로 활성화돼 있음). 비활성화하려면 spring.ai.model.moderation=none (또는 openai와 일치하지 않는 어떤 값). 이 변경은 여러 모델의 구성을 허용하기 위한 것이에요.

프리픽스 spring.ai.openai.moderation은 OpenAI moderation 모델을 구성하는 프로퍼티 프리픽스로 사용돼요.

Property Description Default
spring.ai.model.moderation Moderation 모델 활성화 openai
spring.ai.openai.moderation.base-url 연결할 URL api.openai.com
spring.ai.openai.moderation.api-key API 키 -
spring.ai.openai.moderation.organization-id 선택적으로 API 요청에 사용할 organization을 지정할 수 있어요. -
spring.ai.openai.moderation.project-id 선택적으로 API 요청에 사용할 project를 지정할 수 있어요. -
spring.ai.openai.moderation.model moderation에 사용할 모델의 ID. omni-moderation-latest

참고: 공통 spring.ai.openai.base-url, spring.ai.openai.api-key, spring.ai.openai.organization-id, spring.ai.openai.project-id 프로퍼티를 재정의할 수 있어요. spring.ai.openai.moderation.base-url, spring.ai.openai.moderation.api-key, spring.ai.openai.moderation.organization-id, spring.ai.openai.moderation.project-id 프로퍼티가 설정되어 있으면 공통 프로퍼티보다 우선해요. 이는 서로 다른 모델과 모델 엔드포인트에 서로 다른 OpenAI 계정을 사용하려 할 때 유용해요.

참고: spring.ai.openai.moderation 프리픽스가 붙은 모든 프로퍼티는 런타임에 재정의할 수 있어요.

런타임 옵션 (Runtime Options)

OpenAiModerationOptions 클래스는 moderation 요청 시 사용할 옵션을 제공해요. 시작 시 spring.ai.openai.moderation으로 지정한 옵션이 사용되지만 런타임에 이를 재정의할 수 있어요.

예를 들어:

OpenAiModerationOptions moderationOptions = OpenAiModerationOptions.builder()
    .model("omni-moderation-latest")
    .build();

ModerationPrompt moderationPrompt = new ModerationPrompt("Text to be moderated", this.moderationOptions);
ModerationResponse response = openAiModerationModel.call(this.moderationPrompt);

// Access the moderation results
Moderation moderation = moderationResponse.getResult().getOutput();

// Print general information
System.out.println("Moderation ID: " + moderation.getId());
System.out.println("Model used: " + moderation.getModel());

// Access the moderation results (there's usually only one, but it's a list)
for (ModerationResult result : moderation.getResults()) {
    System.out.println("\nModeration Result:");
    System.out.println("Flagged: " + result.isFlagged());

    // Access categories
    Categories categories = this.result.getCategories();
    System.out.println("\nCategories:");
    System.out.println("Sexual: " + categories.isSexual());
    System.out.println("Hate: " + categories.isHate());
    System.out.println("Harassment: " + categories.isHarassment());
    System.out.println("Self-Harm: " + categories.isSelfHarm());
    System.out.println("Sexual/Minors: " + categories.isSexualMinors());
    System.out.println("Hate/Threatening: " + categories.isHateThreatening());
    System.out.println("Violence/Graphic: " + categories.isViolenceGraphic());
    System.out.println("Self-Harm/Intent: " + categories.isSelfHarmIntent());
    System.out.println("Self-Harm/Instructions: " + categories.isSelfHarmInstructions());
    System.out.println("Harassment/Threatening: " + categories.isHarassmentThreatening());
    System.out.println("Violence: " + categories.isViolence());

    // Access category scores
    CategoryScores scores = this.result.getCategoryScores();
    System.out.println("\nCategory Scores:");
    System.out.println("Sexual: " + scores.getSexual());
    System.out.println("Hate: " + scores.getHate());
    System.out.println("Harassment: " + scores.getHarassment());
    System.out.println("Self-Harm: " + scores.getSelfHarm());
    System.out.println("Sexual/Minors: " + scores.getSexualMinors());
    System.out.println("Hate/Threatening: " + scores.getHateThreatening());
    System.out.println("Violence/Graphic: " + scores.getViolenceGraphic());
    System.out.println("Self-Harm/Intent: " + scores.getSelfHarmIntent());
    System.out.println("Self-Harm/Instructions: " + scores.getSelfHarmInstructions());
    System.out.println("Harassment/Threatening: " + scores.getHarassmentThreatening());
    System.out.println("Violence: " + scores.getViolence());
}

수동 구성 (Manual Configuration)

프로젝트의 Maven pom.xml 파일에 spring-ai-openai 의존성을 추가하세요:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai</artifactId>
</dependency>

또는 Gradle build.gradle 빌드 파일에 추가할 수도 있어요:

dependencies {
    implementation 'org.springframework.ai:spring-ai-openai'
}

참고: 빌드 파일에 Spring AI BOM을 추가하려면 Dependency Management 섹션을 참고해 주세요.

다음으로 OpenAiModerationModel을 만들어볼게요:

OpenAiModerationApi openAiModerationApi = new OpenAiModerationApi(System.getenv("OPENAI_API_KEY"));

OpenAiModerationModel openAiModerationModel = new OpenAiModerationModel(this.openAiModerationApi);

OpenAiModerationOptions moderationOptions = OpenAiModerationOptions.builder()
    .model("omni-moderation-latest")
    .build();

ModerationPrompt moderationPrompt = new ModerationPrompt("Text to be moderated", this.moderationOptions);
ModerationResponse response = this.openAiModerationModel.call(this.moderationPrompt);

HTTP 클라이언트 커스터마이징 (Customizing the HTTP Client)

Spring AI는 내부적으로 공식 openai-java SDK를 사용하며, SpringAiOpenAiHttpClient.Builder가 만든 커스텀 OkHttp 클라이언트로 HTTP 전송을 구성해요. 내부 OkHttpClient가 생성되기 전에 OpenAiHttpClientBuilderCustomizer 빈을 하나 이상 노출해서 그 빌더를 가로챌 수 있어요. 각 커스터마이저는 모든 OpenAI 모델(chat, embedding, image, audio, moderation)이 사용하는 동일한 빌더를 받기 때문에 커스터마이징이 일관되게 적용돼요.

@FunctionalInterface
public interface OpenAiHttpClientBuilderCustomizer {
    void customize(SpringAiOpenAiHttpClient.Builder builder);
}

일반적인 사용 사례는 다음과 같아요:

  • OkHttp Interceptor 인스턴스 등록 (인증, 헤더 전파, 커스텀 로깅)
  • 디스패처 ExecutorService 교체 (예: 비동기 I/O를 가상 스레드로 라우팅)
  • 프록시, SSL, 호스트 이름 검증, 빌더가 노출하는 연결 풀 크기 구성

여러 커스터마이저가 있으면 @Order / Ordered 순서로, Spring AI 자체 기본값 이후에 적용돼서 사용자 코드가 우선해요.

같은 훅은 OpenAi*Model.Builder로 모델을 수동으로 연결할 때도 사용할 수 있어요:

var chatModel = OpenAiChatModel.builder()
    .options(OpenAiChatOptions.builder().model("gpt-4o").build())
    .httpClientBuilderCustomizer(myCustomizer)
    .build();

예제 코드 (Example Code)

OpenAiModerationModelIT 테스트는 라이브러리를 사용하는 몇 가지 일반적인 예제를 제공해요. 더 자세한 사용 예제는 이 테스트를 참고해 주세요.

더 알아보기 (Learn more)