JSCODE Logo
JSCODE 박재성JSCODE 제이온JSCODE 시니
온라인 강의프로그래밍 과외책/전자책무료 강의
유튜브블로그
후기
완강 후기 이벤트블로그 리뷰 이벤트AWS SAA 합격 후기 이벤트
회사명 : JSCODE대표 : 박재성사업자 등록번호 : 244-22-01557통신판매업 : 제 2023-인천미추홀-0381 호

서울특별시 구로구 경인로 20가길 11(오류동, 아델리아)

Copyright ⓒ 2026 JSCODE - 최상위 현업 개발자들의 프로그래밍 교육 All rights reserved.

이용약관개인정보처리방침

실무에 바로 적용하는 Spring AI: Spring 서비스에 챗봇·RAG·MCP 도입하기

백엔드 개발자를 위한 LLM 기초

Prompt란 무엇일까?
Tokens란 무엇일까? /
Embeddings란 무엇일까? / Semantic Space
Fine Tuning이란 무엇일까?
RAG란 무엇일까?
AI Models란 무엇일까?
AI Model Providers란 무엇일까?

Spring AI 기본기

Spring AI란 무엇일까? / 백엔드 개발자가 왜 Spring AI를 배워야할까?
Spring AI 1.0 GA의 탄생
Spring AI와 LangChain - 어떤 도구를 선택해야 할까?
Spring AI와 LangChain - Chat Model 쉽게 이해하기
Spring AI와 LangChain - VectorStore 인터페이스

Spring AI 핵심 구성요소

핵심 컴포넌트 - ChatClient, Advisors, Prompts, Models, Structured Output
Spring AI ChatClient란 무엇일까?
Spring AI Advisor란 무엇일까?
Spring AI Prompts란 무엇일까?
Spring AI Models이란 무엇일까?
Spring AI Structured Output이란 무엇일까?

Spring AI로 만드는 채팅 API — 클라우드(OpenAI)와 로컬(Ollama

[실습] Spring AI 로컬 환경 설정 - Spring Boot 4.x, Gradle
[실습] OpenAI API Key 발급받기
[실습] OpenAI API를 활용한 채팅 API 환경 구축
[실습] Swagger UI를 활용한 테스트 - OpenAI API
[실습] Ollama 설치하기 / Hugging Face란 무엇일까? / GGUF
[실습] Ollama를 활용한 채팅 API 환경 구축
[실습] Swagger UI를 활용한 테스트 - Ollama
Spring AI 응답의 형태 - ChatClient Responses
[실습] Streaming으로 Flux 형태로 응답받기

실무에 쓰는 챗봇 만들기 - ‘대화 기억’부터 ‘CS 문의 자동 분류’까지

Spring AI Prompts - Chat Options란 무엇일까?
Spring AI Prompts - 프롬프트 엔지니어링 9가지 패턴
[실습] CLI 챗봇 개발 환경 아키텍처 미리보기
[실습] Chat Memory Advisor로 메모리 기능 추가하기
[실습] Chat Service 구현 - Advisor, CONVERSATION_ID
[실습] Spring Boot에서 CLI 기능 구현 및 테스트하기
[실습] Chat Controller 구현 - call과 stream 방식의 Chat REST API
[실습] Structured Output Converter를 통한 쇼핑몰 CS 문의 긴급도 분류하기

Vector Database와 유사도 검색 - RAG를 위한 핵심 개념

Vector Database란 무엇일까?
Vector Database Cosine Similarity란 무엇일까? / Spring AI의 Similarity Score
Spring AI Vector Store API
Metadata Filters란 무엇일까?

RAG 챗봇 만들기 - 데이터 전처리부터 ElasticSearch 연동까지

LLM 한계 극복을 위한 RAG 도입
실무에서 Spring AI를 통한 RAG 구현 방법
고품질 RAG를 위한 데이터 전처리 - Extract, Transform, Load
Spring AI RAG 기본 설계
[실습] RAG 챗봇 개발을 위한 로컬 환경 구축
[실습] RAG ETL 파이프라인 구현
[실습] RAG Advisors 구현
[실습] RAG Service 구현
[실습] RAG CLI 구현 및 실행 테스트
[실습] RAG REST API 구현
[실습] Docker 설치
[실습] ElasticSearch 기반 VectorStore로 변경하기

AI와 외부 시스템 연결하기 - Tool Calling으로 API 호출 자동화

Spring AI Tool Calling과 작동 프로세스
[실습] Tool Calling 개발 환경 구축
[실습] 지역별 날씨 조회 외부 API Tool 구현
[실습] Tool Service 구현
[실습] ToolCallingManager 설정
[실습] ToolChatConfig, ToolController 구현 - CLI, REST API
[실습] CLI 및 REST API 테스트

MCP로 완성하는 AI 연동 - Client & Server 개발과 외부 서버 활용

MCP란 무엇일까?
Tool Calling VS MCP
[실습] 아키텍처 미리보기
[실습] MCP Client 개발 환경 구축
[실습] MCP Server 개발 환경 구축
[실습] 외부 MCP Server와 연동한 실시간 날씨 조회 - MCP Client 개발
[실습] 외부 MCP Server와 연동한 실시간 날씨 조회 - MCP Server 개발
[실습] 외부 MCP Server와 연동한 실시간 날씨 조회 - MCP 연동
[실습] CLI 및 RestAPI 테스트
← 블로그 목록으로 돌아가기

[실습] Chat Controller 구현 - call과 stream 방식의 Chat REST API

JSCODE 시니
JSCODE 시니
2026. 06. 13.
author
JSCODE 시니
category
Spring AI
createdAt
Jun 13, 2026 09:52 AM
isPublic
isPublic
series
실무에 바로 적용하는 Spring AI: Spring 서비스에 챗봇·RAG·MCP 도입하기
slug
practice-chat-controller-call-vs-stream
type
post
updatedAt
notion image

✅ 1. call() 메서드 생성

ChatService.java
public @Nullable ChatResponse call(Prompt prompt, String conversationId){ return prepareRequest(prompt, conversationId) .call() .chatResponse(); }
 
 
 

✅ 2. record 생성

💁‍♀️
record는 데이터를 담고 전달하는 목적에 최적화된 최신 자바 문법입니다. 소괄호 안에 필요한 데이터(필드)를 나열해주면, 자바가 알아서 생성자와 Getter를 모두 만들어줍니다!
주로 REST API에서 프론트엔드가 서버로 보내는 데이터를 JSON 형태로 받아내기 위해 DTO를 제작할 때 사용합니다.
record 문법이 생소하신 분들은 한 번 학습하고 넘어가시길 바랍니다.
ChatController.java
public record PromptBody(@NotEmpty String conversationId, @NotEmpty String userPrompt, @Nullable String systemPrompt, DefaultChatOptions chatOptions){}
 
 
 

✅ 3. call 방식 생성

ChatController.java
@PostMapping(value = "/call", produces = MediaType.APPLICATION_JSON_VALUE) public ChatResponse call(@RequestBody @Valid PromptBody promptBody) { // 1. 메시지들을 차곡차곡 담을 빈 리스트를 생성 List<Message> messages = new ArrayList<>(); // 2. systemPrompt가 입력으로 들어왔다면 리스트에 넣자 if(promptBody.systemPrompt() != null && !promptBody.systemPrompt().isBlank()){ messages.add(new SystemMessage(promptBody.systemPrompt())); } // 3. userPrompt는 필수 값이니 무조건 리스트에 넣자 messages.add(new UserMessage(promptBody.userPrompt())); // 4. 리스트에 담긴 메시지들로 프롬프트 조립하기 Prompt.Builder promptBuilder = Prompt.builder().messages(messages); // 5. 프론트엔드에서 보낸 chatOptions가 있다면 적용하기 if(promptBody.chatOptions() != null){ promptBuilder.chatOptions(promptBody.chatOptions()); } // 완성된 프롬프트와 conversationID를 가지고 서비스 메서드 호출 return chatService.call(promptBuilder.build(), promptBody.conversationId()); }
 
 
 

✅ 4. 코드 리팩토링

ChatController.java
@PostMapping(value = "/call", produces = MediaType.APPLICATION_JSON_VALUE) public ChatResponse call(@RequestBody @Valid PromptBody promptBody) { Prompt prompt = createPrompt(promptBody); // 완성된 프롬프트와 conversationID를 가지고 서비스 메서드 호출 return chatService.call(prompt, promptBody.conversationId()); } private static Prompt createPrompt(PromptBody promptBody) { // 1. 메시지들을 차곡차곡 담을 빈 List를 생성 List<Message> messages = new ArrayList<>(); // 2. systemPrompt가 입력으로 들어왔다면 리스트에 넣자 if(promptBody.systemPrompt() != null && !promptBody.systemPrompt().isBlank()){ messages.add(new SystemMessage(promptBody.systemPrompt())); } // 3. userPrompt는 필수 값이니 무조건 리스트에 넣자 messages.add(new UserMessage(promptBody.userPrompt())); // 4. 리스트에 담긴 메시지들로 프롬프트 조립하기 Prompt.Builder promptBuilder = Prompt.builder().messages(messages); // 5. 프론트엔드에서 보낸 chatOptions가 있다면 적용하기 if(promptBody.chatOptions() != null){ promptBuilder.chatOptions(promptBody.chatOptions()); } return promptBuilder.build(); }
 
 
 

✅ 5. stream 방식 생성하기

ChatController.java
@PostMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> stream(@RequestBody @Valid PromptBody promptBody){ Prompt prompt = createPrompt(promptBody); return chatService.stream(prompt, promptBody.conversationId()); }
 
 
 

✅ 6. 로깅 설정

spring: application: name: chat # cli: true ai: #[1] openAI 설정 openai: # 환경변수 값 api-key: ${OPENAI_API_KEY} chat: # 실제 사용할 대화형 AI의 모델명 model: openai/gpt-4.1-nano # GitHub Models 서버로 요청을 보냄 base-url: https://models.github.ai/inference # 세부 API 경로 completions-path: /chat/completions #[2] Ollama 설정 ollama: init: pull-model-strategy: when_missing chat: model: hf.co/Qwen/Qwen2.5-1.5B-Instruct-GGUF logging: level: org.springframework.ai.chat.client.advisor: DEBUG
 
 
 

✅ 7. 테스트

notion image
notion image