우와한 개발자

[Spring AI] Spring AI로 OpenAI API 연동하기 — ChatClient

by 우와한개발자

 

1. Spring AI 란?

  • Spring 생태계에서 AI 기능을 쉽게 사용할 수 있도록 만든 프레임워크
  • OpenAI, Anthropic, Google 등 다양한 AI 모델을 동일한 코드 구조로 사용할 수 있도록 추상화해준다.
  • Spring Boot의 자동 설정을 지원하기 때문에 복잡한 설정 없이 바로 사용 가능하다.

 

1) 주요기능

기능 설명
Chat OpenAI, Claude 등 LLM 모델과 대화 기능을 제공한다.
멀티턴 대화 (ChatMemory) 대화 히스토리를 관리하여 이전 대화를 기억한다.
프롬프트 관리 시스템 프롬프트(AI 역할 정의)와 사용자 프롬프트를 구조적으로 관리할 수 있다.
Model Abstraction 특정 AI 모델에 종속되지 않고 동일한 코드로 여러 모델을 교체해서 사용할 수 있다.
RAG 외부 문서를 검색하여 AI 응답에 활용한다.
Embedding 텍스트를 벡터로 변환하여 유사도 검색에 활용한다.
Image Generation DALL-E 등 이미지 생성 모델을 지원한다.
Function Calling AI가 외부 함수를 호출하여 실시간 데이터를 활용한다.
Vector Store 벡터 데이터베이스와 연동하여 문서 검색을 지원한다.

 

2) 프롬프트(Prompt)

  • AI에게 보내는 입력 텍스트 전체

(1) System Prompt

  • AI의 역할, 성격, 행동 방식을 정의한다.
  • 대화 시작 전에 AI에게 "너는 어떤 존재야" 라고 설정하는 것이다.
  • 사용자에게는 보이지 않는다.
"너는 친절한 한국어 고객 상담사야. 
 항상 존댓말을 사용하고 모르는 내용은 모른다고 답해."

(2) User Prompt

  • 사용자가 실제로 입력하는 질문이나 요청dlek
"환불 규정이 어떻게 되나요?"

(3) OpenAI API 요청 구조

{
  "messages": [
    {"role": "system",    "content": "너는 친절한 한국어 고객 상담사야."},
    {"role": "user",      "content": "환불 규정이 어떻게 되나요?"},
    {"role": "assistant", "content": "환불은 7일 이내 가능합니다."},
    {"role": "user",      "content": "7일 이후에는 어떻게 되나요?"}
  ]
}
role 설명
system 시스템 프롬프트. AI 역할 정의
user 사용자 프롬프트. 사용자 입력
assistant AI 응답. 멀티턴에서 이전 답변 기록

 

2. 지원 AI 모델

제공사 모델
OpenAI GPT-4o, GPT-4o-mini, DALL-E
Anthropic Claude 3.5
Google Gemini
Meta Llama
Mistral Mistral
Ollama 로컬 모델 실행

 

3. WebClient vs Spring AI

구분 WebClient Spring AI
설정 WebClient 빈 직접 설정 필요 Spring Boot 자동 설정
코드량 요청/응답 직접 구성 → 많음 추상화로 간결함
응답 형태 JSON 문자열 그대로 파싱 필요 텍스트 바로 추출 가능
모델 교체 코드 수정 필요 설정 파일만 변경
멀티턴 히스토리 직접 관리 ChatMemory 로 간단히 구현
RAG 직접 구현 기본 제공
유연성 높음 (세밀한 제어 가능) 낮음 (추상화로 제한)
레퍼런스 많음 적음 (아직 milestone 버전)
안정성 높음 낮음 (정식 릴리즈 전)

 

4. Spring AI로 OpenAI API 연동하기

1) 사전 준비

변수명 : OPENAI_API_KEY
값     : sk-xxxxxxxxxxxxxxxxxxxxxxxx

 

2) 프로젝트 설정 (build.gradle)

repositories {
    mavenCentral()
    maven { url '<https://repo.spring.io/milestone>' }  // Spring AI 밀리스톤 저장소
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter:1.0.0-M6'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'io.projectreactor:reactor-test'
    testCompileOnly 'org.projectlombok:lombok'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    testAnnotationProcessor 'org.projectlombok:lombok'
}

 

3) application.properties

  • 시스템 환경변수에 등록한 API 키를 application.properties 에서 읽는다.
spring.ai.openai.api-key=${OPENAI_API_KEY}
spring.ai.openai.chat.options.model=gpt-4o-mini

 

4) Service 구현

  • Spring AI는 ChatClient 를 자동으로 빈으로 등록해주기 때문에 별도 WebClient 설정이 필요 없다.
@Service
@RequiredArgsConstructor
public class SpringAiService {

    private final ChatClient chatClient;

    public Mono<String> getChatCompletion(String userMessage) {
        return Mono.fromCallable(() ->
                chatClient.prompt()
                        .user(userMessage)          // 사용자 메시지 설정
                        .call()
                        .content()                  // 응답 텍스트 추출
        );
    }
}

 

5) Controller 구현

@RestController
@RequiredArgsConstructor
public class SpringAiController {

    private final SpringAiService springAiService;

    @GetMapping("/chat/springai")
    public Mono<String> chat(@RequestParam("q") String q) {
        return springAiService.getChatCompletion(q);  // 서비스로 위임
    }
}

 

6) 실행 및 테스트

GET <http://localhost:8080/chat/springai?q=안녕하세요>
안녕하세요! 무엇을 도와드릴까요?

 

블로그의 정보

우와한개발자 님의 블로그

우와한개발자

활동하기