일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
- Oracle 사용자명
- 무료 오라클 데이터베이스
- 서평단
- ora-01722
- Oracle 사용자명 입력
- ORA-00922
- Oracle 윈도우 설치
- Oracle 18c HR
- ORA-12899
- 윈도우 Oracle
- 오라클 캐릭터셋 확인
- 오라클 캐릭터셋 변경
- Oracle 18c 설치
- Oracle 18c HR schema
- 비전공자를 위한 데이터베이스 입문
- oracle 18c
- Oracle Express Edition
- oracle
- Oracle 테이블 띄어쓰기
- Oracle 테이블 대소문자
- Oracle 초기 사용자
- Orace 18c
- 무료 오라클 설치
- 오라클 캐릭터셋 조회
- Today
- Total
The Nirsa Way
[Spring AI] #1. LLM 호출 실습 시작 – 셋팅 및 전체 구조 먼저 실행해보기 본문
[Spring AI] #1. LLM 호출 실습 시작 – 셋팅 및 전체 구조 먼저 실행해보기
KoreaNirsa 2025. 6. 24. 20:21※ 인프런 강의 Spring AI 실전 가이드: RAG 챗봇 만들기를 실습하는 내용입니다.
※ 해당 강의 코드를 코틀린 → 자바로 언어를 바꿔 진행하기 때문에 일부 코드 및 구현부가 다를 수 있습니다.
※ 실습이지만 코드를 직접 까보는 내용을 기록하는 포스팅이므로 강의 내용과 상이할 수 있습니다.
[Spring AI] #1. LLM 호출 실습 시작 – 구조 먼저 실행해보기
[Spring AI] #2. AiConfig 분석 – OpenAI API 연결 설정 방법
[Spring AI] #3-1. ChatService 분석 – 메시지 생성과 모델 호출 흐름
[Spring AI] #3-2. ChatService 분석 – buildRequestPrompt()로 요청 준비하기
[Spring AI] #3-3. ChatService 분석 – internalCall()로 요청과 응답 재구성 흐름 파악하기
[Spring AI] #4. ChatController 분석 – 요청 처리와 응답 흐름 정리
Spring AI란?
Spring 개발자들을 위한 LLM 통합 도구로써 OpenAI, Anthropic, Google AI 등 다양한 AI 모델을 Spring 스타일로 쉽게 연동하고 활용할 수 있도록 지원하는 Spring 공식 프레임워크 입니다. 아래의 4가지 컴포넌트를 중심으로 구현할 수 있습니다.
- PromptTemplate
☞ 프롬프트를 템플릿으로 관리 가능 - ChatClient / EmbeddingClient 인터페이스
☞ LLM 서비스 호출을 추상화하여 관리
☞ ex. ChatClient : OpenAI와의 채팅, EmbeddingClient : 임베디 생성 등 - Service Provider 구현체
☞ 내부적으로 Open AI 등의 클라이언트를 구현하여 제공 - Spring Configuration 기반 설정
☞ application.yml에서 API Key, Model, Endpoint 설정 가능
그 외에 MCP, Function Calling 등 다양한 기능을 지원해줍니다. 직접 구현하지 않아도 프레임워크에 구현되어있는 기능을 기반으로 틀을 잡고 시작하기에 훨씬 빠르고 안정적으로 접근할 수 있는 방법을 제공합니다.
LLM(Large Language Model) 이란?
방대한 양의 텍스트 데이터를 학습하여 사람이 쓰는 자연어를 이해하고 생성이 가능한 AI 모델입니다. 이러한 특성으로 인해 다양한 질문과 프롬프트에 대해 응답을 생성할 수 있습니다. 대표적인 LLM 모델로는 GPT, Claude, Gemini 등이 있으며 번역, 요약, 코드 생성, 질의응답 등 다양한 언어 기반 작업에 폭넓게 활용되고 있습니다.
이러한 배경을 바탕으로 이번 포스팅에서는 Spring AI를 사용하여 LLM 활용하기, 즉 LLM 모델과 상호작용하여 질의를 하고 원하는 응답을 받아오는 구현 예제를 다룹니다.
위에서 언급했듯이 해당 포스팅은 인프런 강의 Spring AI 실전 가이드: RAG 챗봇 만들기 를 참고하여 실습중이며 해당 강의에서 사용되는 코틀린 대신 자바로 구현한 코드입니다. 무료 강의이기 때문에 관심이 있으신 분들은 해당 강의를 보시는것도 좋을 것 같습니다.
OpenAI Key 발급받기
https://platform.openai.com/api-keys 으로 이동하여 OpenAI Key를 발급 받습니다. (2025년 6월 21일 기준으로 $18 크레딧이 제공됩니다) 발급받은 API Key는 따로 저장하여 관리해주세요.
현재재 날짜 기준으로 크레딧을 지급해주지 않기 때문에 저는 그냥 학습비용이라 생각하고 5달러를 결제하여 사용했습니다. https://platform.openai.com/settings/organization/billing/overview 에서 카드 등록하여 진행하였습니다.
추후 코드에서 구현할 때 mini 모델로 사용하실 경우 무료로 가능하기에 굳이 크레딧을 충전할 필요는 없을 것 같습니다. (2025년 6월 24일 기준)
build.gradle / application.properties / 패키지 구조
프로젝트는 스프링 부트로 생성하시면 되고 사용할 build.gradle은 아래와 같습니다. 스웨거를 통해 LLM을 호출하여 진행합니다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.ai:spring-ai-openai:1.0.0-M6'
implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter:1.0.0-M6'
implementation 'org.projectlombok:lombok:1.18.38'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
application.properties에 위에서 발급 받았던 API Key를 넣어주세요.
spring.ai.openai.api-key=API키
저의 경우 패키지 구조는 아래와 같이 진행합니다. 크게 config, controller, dto, service 4개의 패키지로 진행합니다.
kr.co.ai.config.AiConfig
package co.kr.ai.config;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AiConfig {
@Value("${spring.ai.openai.api-key}")
private String apiKey;
@Bean
public OpenAiApi openAiApi() {
return OpenAiApi.builder()
.apiKey(apiKey)
.build();
}
}
kr.co.ai.config.ApiConfig
package co.kr.ai.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
@Configuration
class OpenApiConfig {
@Bean
public OpenAPI springOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("Spring AI Tutorial API")
.version("1.0")
.description("Spring AI를 활용한 챗봇 API"));
}
}
kr.co.ai.controller.ChatController
package co.kr.ai.controller;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import co.kr.ai.dto.ChatRequest;
import co.kr.ai.dto.Response;
import co.kr.ai.service.ChatService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping("/api/v1/chat")
@RequiredArgsConstructor
@Tag(name = "Chat API", description = "OpenAI API를 통한 채팅 기능")
public class ChatController {
private final ChatService chatService;
private static final Logger logger = LoggerFactory.getLogger(ChatController.class);
@Operation(
summary = "LLM 채팅 메시지 전송",
description = "사용자의 메시지를 받아 OpenAI API를 통해 응답을 생성합니다.",
responses = {
@ApiResponse(
responseCode = "200",
description = "LLM 응답 성공",
content = @Content(schema = @Schema(implementation = ApiResponse.class))
),
@ApiResponse(responseCode = "400", description = "잘못된 요청"),
@ApiResponse(responseCode = "500", description = "서버 오류")
}
)
@PostMapping("/query")
public ResponseEntity<Response<Map<String, Object>>> sendMessage(
@Parameter(description = "채팅 요청 객체", required = true)
@RequestBody ChatRequest request) {
logger.info("Chat API 요청 받음: model={}", request.getModel());
if (request.getQuery() == null || request.getQuery().isBlank()) {
logger.warn("빈 질의가 요청됨");
return ResponseEntity.badRequest().body(
new Response<>(false, null, "질의가 비어있습니다.")
);
}
try {
String systemMessage = "You are a helpful AI assistant.";
var response = chatService.openAiChat(
request.getQuery(),
systemMessage,
request.getModel()
);
logger.debug("LLM 응답 생성: {}", response);
if (response != null) {
return ResponseEntity.ok(
new Response<>(true, Map.of("answer", response.getResult().getOutput().getText()), null)
);
} else {
logger.error("LLM 응답 생성 실패");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(
new Response<>(false, null, "LLM 응답 생성 중 오류 발생")
);
}
} catch (Exception e) {
logger.error("Chat API 처리 중 오류 발생", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(
new Response<>(false, null, e.getMessage() != null ? e.getMessage() : "알 수 없는 오류 발생")
);
}
}
}
kr.co.ai.service.ChatService
package co.kr.ai.service;
import java.util.Arrays;
import java.util.List;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
@RequiredArgsConstructor
public class ChatService {
private final OpenAiApi openAiApi;
/**
* OpenAI 챗 API를 이용하여 응답을 생성합니다.
*
* @param userInput 사용자 입력 메시지
* @param systemMessage 시스템 프롬프트
* @param model 사용할 LLM 모델명
* @return ChatResponse 객체 (실패 시 null)
*/
public ChatResponse openAiChat(String userInput, String systemMessage, String model) {
log.debug("OpenAI 챗 호출 시작 - 모델: {}", model);
try {
// 메시지 구성
List<Message> messages = Arrays.asList(
new SystemMessage(systemMessage),
new UserMessage(userInput)
);
// 챗 옵션 구성
OpenAiChatOptions chatOptions = OpenAiChatOptions.builder()
.model(model)
.temperature(0.7d)
.build();
// 프롬프트 생성
Prompt prompt = new Prompt(messages, chatOptions);
// 챗 모델 생성 및 호출
OpenAiChatModel chatModel = OpenAiChatModel.builder()
.openAiApi(openAiApi)
.build();
return chatModel.call(prompt);
} catch (Exception e) {
log.error("OpenAI 챗 호출 중 오류 발생: {}", e.getMessage(), e);
return null;
}
}
}
kr.co.ai.dto.ChatResponse
package co.kr.ai.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@Schema(description = "채팅 요청 데이터 모델")
public class ChatRequest {
@Schema(description = "사용자 질문", example = "안녕하세요")
private String query;
@Schema(description = "사용할 LLM 모델", example = "gpt-3.5-turbo", defaultValue = "gpt-3.5-turbo")
private String model = "gpt-3.5-turbo";
}
kr.co.ai.dto.Response
package co.kr.ai.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@AllArgsConstructor
@Schema(description = "API 응답 포맷")
public class Response<T> {
@Schema(description = "요청 처리 성공 여부")
private boolean success;
@Schema(description = "성공 응답 데이터")
private T data;
@Schema(description = "실패 오류 메시지")
private String error;
}
LLM 호출해보기
서버를 실행하신 후 스웨거 페이지로 이동하여 LLM을 호출 해보시면 됩니다. 저의 경우 기본 포트 8080을 사용중이기에 http://localhost:8080/swagger-ui/index.html 를 입력하면 아래와 같이 스웨거 문서를 확인하실 수 있습니다.
POST를 펼친 후 Try it out을 눌러 요청을 준비합니다.
query는 질문이라고 생각하시면 되며, 모델은 gpt 등 ai 모델이라고 보시면 됩니다. 크레딧 없이 무료로 사용하시는 분들은 mini 모델(gpt-4o-mini 등)을 작성하시면 됩니다. 저는 "현재 시간 가장 핫한 언어를 추천해줘" 라고 질문하였으며 gpt-3.5-turbo 모델을 사용하였습니다.
아래와 같이 응답까지 확인을 할 수 있습니다.
'Development > Spring AI' 카테고리의 다른 글
[Spring AI] #4. ChatController 분석 – 요청 처리와 응답 흐름 정리 (1) | 2025.07.06 |
---|---|
[Spring AI] #3-3. ChatService 분석 – internalCall()로 요청과 응답 재구성 흐름 파악하기 (2) | 2025.07.01 |
[Spring AI] #3-2. ChatService 분석 – buildRequestPrompt()로 요청 준비하기 (0) | 2025.06.29 |
[Spring AI] #3-1. ChatService 분석 – 메시지 생성과 모델 호출 흐름 (0) | 2025.06.29 |
[Spring AI] #2. AiConfig 분석 – OpenAI API 연결 설정 (2) | 2025.06.24 |