์ต๊ทผ ๋ช๋
๊ฐ AI ๊ธฐ์ ์ ๋ฐ์ ์๋๋ ์ ๋ง ๋๋๋ค. ํนํ ๋ฐฑ์๋ ์์ญ์์ Java์ Spring Boot๋ฅผ ์ฌ์ฉํด LLM๊ธฐ๋ฐ ์๋น์ค๋ฅผ ๊ตฌ์ถํ๋ ค๋ ์๊ตฌ๊ฐ ํญ๋ฐ์ ์ผ๋ก ์ฆ๊ฐํ๊ณ ์๋ค. ์ด๋ฌํ ํ๋ฆ์ ์ค์ฌ์๋ ๋จ์ฐ Spring AI๊ฐ ์๋ค.
Spring AI ํ์์ ์์ ์ฑ๊ณผ ๊ธฐ๋ฅ์ ๋ํญ ๋์ด์ฌ๋ฆฐ Spring AI 1.1.1 ๋ฒ์ ์ ์ ์ ๋ฐํํ๋ค. ์ด๋ฒ ๋ฆด๋ฆฌ์ฆ๋ ๋จ์ํ ๋ฒ๊ทธ ์์ ์ด์์ ์๋ฏธ๋ฅผ ๊ฐ์ง๋ฉฐ, ์ค๋ฌด์์ AI ๊ธฐ๋ฅ์ ์์ ์ ์ผ๋ก ๊ตฌํํ๋ ค๋ ๊ฐ๋ฐ์๋ค์๊ฒ ๋งค์ฐ ๋ฐ๊ฐ์ด ์์์ด ๋ ๊ฒ ๊ฐ๋ค.
์ด๋ฒ ํฌ์คํ
์์๋ Spring AI 1.1.1์ ์ฃผ์ ๋ณ๊ฒฝ์ ์ ์์ธํ ์ดํด๋ณด๊ณ , ์ค์ ํ๋ก์ ํธ์์ ์ป์ ์ ์๋ ์ด์ ์ ๋ํด์ ์ ๋ฆฌํด ๋ณด๊ณ ์ ํ๋ค.
์ด๋ฒ ์ ๋ฐ์ดํธ์ ํต์ฌ์ ๋ฌด์์ธ๊ฐ?
Spring AI 1.1.1์ ๊ณต์ OpenAI Java SDK ํตํฉ ๋ฐ ๊ฐํ๋ ๊ตฌ์กฐํ ์ถ๋ ฅ(Structured Output) ์ง์์ ํตํด AI ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ์์ ์ฑ๊ณผ ์์ฐ์ฑ์ ํฌ๊ฒ ๋์ด๊ณ ์ฃผ์ ๋ฒ๊ทธ ๋ฐ ๋ณด์ ํจ์น๊ฐ ํฌํจ๋ ํต์ฌ ์์ ํ ๋ฆด๋ฆฌ์ฆ๋ค.
์ฃผ์ ๋ณ๊ฒฝ์ฌํญ
์ด๋ฒ 1.1.1 ๋ฆด๋ฆฌ์ฆ๋ 13๊ฐ์ ์๋ก์ด ๊ธฐ๋ฅ๊ณผ 16๊ฐ์ ๋ฒ๊ทธ ์์ , ๊ทธ๋ฆฌ๊ณ 2๊ฑด์ CVE ๋ณด์ ํจ์น๋ฅผ ํฌํจํ 5๊ฐ์ ์์กด์ฑ ์ ๋ฐ์ดํธ๊ฐ ์ ์ฉ๋์๋ค. ์ด์ค์์ ํนํ ๋ฐฑ์๋ ๊ฐ๋ฐ์๊ฐ ์ฃผ๋ชฉํด์ผ ํ 3๊ฐ์ง ํต์ฌ ๋ณ๊ฒฝ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
OpenAI Java SDK์์ ๊ณต์ ํตํฉ (Type-Safe API)
OpenAI๋ฅผ ์ฌ์ฉํ๋ Spring AI ๊ฐ๋ฐ์๋ค์๊ฒ ๊ฐ์ฅ ํฐ ๋ณํ์ด์ ํ์ํ ๋งํ ์์์ด๋ค.
- ๋ณ๊ฒฝ๋ด์ฉ: ๊ธฐ์กด์๋ ๋ด๋ถ์ ์ผ๋ก OpenAI API๋ฅผ ์ง์ ๋ค๋ฃจ๋ ๋ฐฉ์์ด์์ง๋ง ์ด๋ฒ ๋ฆด๋ฆฌ์ฆ๋ถํฐ ๊ณต์ OpenAI Java SDK์์ ๋ค์ดํฐ๋ธ ํตํฉ์ ์ ๊ณตํ๋ค.
- ๊ฐ๋ฐ์์ด์ : ๊ณต์ SDK๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ ํ์ ์์ ์ฑ์ด ๋ํญ ๊ฐ์ ๋์๋ค. API์๋ต๊ณผ ์์ฒญ ๊ฐ์ฒด๋ฅผ ๋ ์์ ํ๊ฒ ๋ค๋ฃฐ ์ ์์ผ๋ฉฐ ๊ณต์ SDK๊ฐ ์ ๊ณตํ๋ ๋ชจ๋ ๊ธฐ๋ฅ์ ๋น ์ง์์ด ํ์ฉํ ์ ์๊ฒ ๋์ด ๊ฐ๋ฐ ํธ์์ฑ์ด ๊ทน๋ํ๋ ์ ๋ง์ด๋ค.
ChatClient์ ๊ตฌ์กฐํ ์ถ๋ ฅ (Structured Output) ๊ธฐ๋ณธ ์ง์ ๊ฐํ
LLM์ ์ฌ์ฉํ ๋ ๊ฐ์ฅ ๊น๋ค๋ก์ด ๋ถ๋ถ ์ค ํ๋๋ ํ ์คํธ๋ก ๋ฐ์ ์๋ต์ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ์ ํํ๋ ๋ฐ์ดํฐ(ex. JSON)๋ก ์ ํํ๊ฒ ๋ณํํ๋ ๊ฒ์ด๋ค.
- ๋ณ๊ฒฝ๋ด์ฉ: ChatClient๊ฐ ๊ตฌ์กฐํ ์ถ๋ ฅ(Structured Output)์ ๋์ฑ ์์ ์ ์ผ๋ก ์ง์ํ๋๋ก ๊ฐ์ ๋์๋ค.
- ๊ฐ๋ฐ์์ด์ : AI ๋ชจ๋ธ๋ก๋ถํฐ JSON์ด๋ YAML๊ฐ์ ๊ตฌ์กฐํ๋ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ ๋ ์ค๋ฅ ์์ด ์ ๋ขฐ์ฑ ์๊ฒ ์ถ์ถํ ์ ์๋ค. ์ด๋ ํนํ ๋ณต์กํ ๋น์ฆ๋์ค ๋ก์ง์์ AI์๋ต์ DTO๋ ์ํฐํฐ๋ก ๋ณํํด์ผ ํ ๋ ๋ฐ์ํ๋ ํ์ฑ ์ค๋ฅ๋ฅผ ์ค์ฌ์ฃผ์ด ๊ฐ๋ฐ ์์์ฑ์ ํฌ๊ฒ ๋์ฌ์ค๋ค.
์๋ฅผ ๋ค์ด ๋ค์๊ณผ ๊ฐ์ด ChatClient๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณต์กํ ํ๋กฌํํธ ์์ง๋์ด๋ง ์์ด๋ Java record ํ์ ์ด๋ ํด๋์ค๋ก ๊น๋ํ๊ฒ ๋งคํ๋ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๋ค.
// 1. ์ํ๋ ์๋ต ๊ตฌ์กฐ๋ฅผ Record๋ก ์ ์
public record ActorFilms(String actor, List<String> movies) {}Java๋ค์์ ChatClient API๋ฅผ ์ฌ์ฉํ์ฌ BeanOutputConverter๋ฅผ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค.
ActorsFilms actorsFilms = ChatClient.create(chatModel).prompt()
.user(u -> u.text("Generate the filmography of 5 movies for {actor}.")
.param("actor", "Tom Hanks"))
.call()
.entity(ActorsFilms.class); //์๋ ๋งคํ ์ง์Javaํน์ ๋ก์ฐ ๋ ๋ฒจ์ ChatModel API๋ฅผ ์ง์ ์ฌ์ฉํ ์ ์๋ค.
BeanOutputConverter<ActorsFilms> beanOutputConverter =
new BeanOutputConverter<>(ActorsFilms.class);
String format = this.beanOutputConverter.getFormat();
String actor = "Tom Hanks";
String template = """
Generate the filmography of 5 movies for {actor}.
{format}
""";
Generation generation = chatModel.call(
PromptTemplate.builder().template(this.template).variables(Map.of("actor", this.actor, "format", this.format)).build().create()).getResult();
ActorsFilms actorsFilms = this.beanOutputConverter.convert(this.generation.getOutput().getText());Java์ต์ LLM ๋ชจ๋ธ ๋ฐ ์ธํ๋ผ ๊ธฐ๋ฅ ์ง์ ํ๋
Spring AI๋ ํน์ ๋ชจ๋ธ์ ์ข ์๋์ง ์๊ณ ๋ค์ํ ํด๋ผ์ฐ๋์ LLM์ ์ง์ํ๋ ๊ฒ์ ๋ชฉํ๋ก ํ๋ค. ์ด๋ฒ ์ ๋ฐ์ดํธ ์์๋ ํต์ฌ ์ ๊ณต์ ์ฒด๋ค์ ์ต์ ๊ธฐ๋ฅ์ด ๋น ๋ฅด๊ฒ ๋ฐ์๋์๋ค.
- Claude ๊ฐํ: Claude 4.5 ๋ชจ๋ธ(Opus, Haiku)์ง์์ด ์ถ๊ฐ๋์์ผ๋ฉฐ, Skills API ๋ฐ Files API ํตํฉ์ด ์ ์ฉ๋์ด ํ์ผ์ ํ์ฉํ ๊ณ ๊ธ ์ํธ์์ฉ์ด ๊ฐ๋ฅํด์ก๋ค.
- Google Gemini ๊ฐ์ : ThinkingLevel ์ค์ ์ง์์ด ์ถ๊ฐ๋์ด ์ถ๋ก ๊ณผ์ ์ ๋ํ ๋ ์ธ๋ฐํ ์ ์ด๊ฐ ๊ฐ๋ฅํด ์ก๊ณ Vertex Gemini ํตํฉ ์ ์๋ต ๋ฐ์ดํฐ์ Safety Ratings(์์ ๋ฑ๊ธ) ์ ๋ณด๊ฐ ํฌํจ๋์ด ์ด์ ์์ ์ฑ์ด ๋์์ก๋ค.
- RAG ์ธํ๋ผ ๊ฐ์ : ๋ฒกํฐ ์คํ ์ด ํ๋์ ‘ISNULL’, ‘ISNOTNULL’ ํํ์์ด ์ถ๊ฐ๋์ด RAG(๊ฒ์ ์ฆ๊ฐ ์์ฑ) ๊ตฌ์ฑ ์ ๋ฐ์ดํฐ ํํฐ๋ง์ ์ ์ฐ์ฑ์ด ํฅ์๋์๋ค.
์ด ์ ๋ฐ์ดํธ๋ฅผ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ๋ค๋ฉด?
Spring AI 1.1.1์ ๋์ ํ์ ๋ ์ค์ง์ ์ธ ์ด์ ์ ๋ฐ๋ก ๊ฐ๋ฐ ์์ฑ์ฑ๊ณผ ์์คํ ์์ ์ฑ์ ๋์ ํ๋ณด๋ผ๊ณ ํ ์ ์๋ค.
๋ฒ๊ทธ ์๋ AI ์๋ต ํ์ฑ ํ๊ฒฝ ๊ตฌ์ถ
๊ฐ์ฅ ํฐ ์ค๋ฌด์ ์ด๋์ ๊ตฌ์กฐํ ์ถ๋ ฅ์ ์ ๋ขฐ์ฑ ํฅ์์ด๋ค.
์ด์ ์๋ LLM์ด JSON์ ์๋ฒฝํ๊ฒ ์์ฑํ์ง ๋ชปํ ๊ฒฝ์ฐ, ์ด๋ฅผ ์ฒ๋ฆฌํ๋ ํ์ฒ๋ฆฌ ๋ก์ง์ด๋ ์์ธ ์ฒ๋ฆฌ ์ฝ๋๊ฐ ๋ณต์กํ๋ค. ํ์ง๋ง 1.1.1 ๋ฒ์ ์์ ๊ตฌ์กฐํ ์ถ๋ ฅ์ด ๊ฐํ๋๋ฉด์ ๊ฐ๋ฐ์๋ LLM์ ์๋ต์ ์ ๋ขฐํ๊ณ Java ๊ฐ์ฒด๋ก ๋ฐ๋ก ๋งคํํ์ฌ ๋น์ฆ๋์ค ๋ก์ง์ ์ง์คํ ์ ์๊ฒ ๋์๋ค. ์ด๋ ์ฝ๋ฉ๋ ๊ฐ์์ ํ
์คํธ ์ฉ์ด์ฑ ์ฆ๋๋ก ์ด์ด์ง ์ ์๋ค.
์ํฐํ๋ผ์ด์ฆ ํ๊ฒฝ์์์ ์์ ์ฑ ํ๋ณด
์ด๋ฒ ๋ฆด๋ฆฌ์ฆ์๋ ์ค์ํ ๋ณด์ํจ์น๊ฐ ํฌํจ๋์ด ์๋ค. ํนํ Apache Commons ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ CVE ์ทจ์ฝ์ (๋ฌดํ๋ฃจํ, ์์ํ ๋น๋ฑ)์ ๋ํ ์
๋ฐ์ดํธ๋ ์ํฐํ๋ผ์ด์ฆ ํ๊ฒฝ์์ ํ์์ ์ธ ์กฐ์น๋ผ๊ณ ํ ์ ์๋ค.
๋ํ Azure Cosmos DB Chat Memory ์๋ ๊ตฌ์ฑ ์ง์์ด ์ถ๊ฐ๋์ด ์ด๋ฏธ Azure ํ๊ฒฝ์ ์ฌ์ฉ ์ค์ธ ๊ธฐ์
์ ์ธ์
๋ฉ๋ชจ๋ฆฌ ๊ธฐ๋ฅ์ ๋ณ๋์ ์ค์ ์์ด Spring Boot Starter๋ฅผ ํตํด ์ฝ๊ฒ ํตํฉํ ์ ์๋ค. ์ด๋ ํด๋ผ์ฐ๋ ์ธํ๋ผ ํ์ฉ๋๋ฅผ ๋์ฌ์ค๋ค.
๋ฏธ๋ ์งํฅ์ ์ธ ์ํคํ ์ฒ ์ค๋น (2.0.0 ๋๋น)
Spring AIํ์ ๋ค์ ์ค์ Spring AI 2.0.0-M1 ๋ฆด๋ฆฌ์ฆ๋ฅผ ์๊ณ ํ๋ค. 1.1.1์ 1.X ๋ผ์ธ์ ์์ ํ์ ๊ธฐ๋ฅ ํ์ฅ ๋ง๋ฌด๋ฆฌ ๋จ๊ณ๋ก ๋ณผ ์ ์์ผ๋ฉฐ ์ด ๋ฒ์ ์ ์ฌ์ฉํด ์ฃผ์ ๊ธฐ๋ฅ์ ๋ฏธ๋ฆฌ ํ ์คํธํ๊ณ ์์ ํํ๋ ๊ฒ์ ๊ณง 2.0.0 ๋ฒ์ ์ผ๋ก์ ๋ง์ด๊ทธ๋ ์ด์ ์ ์ํ ํ๋ฅญํ ๋๋ค๋์ด ๋ ๊ฒ์ด๋ค.
Spring AI 1.1.1 ๋ฆด๋ฆฌ์ฆ๋ LLM์ ํ์ฉํ ์ ํ๋ฆฌ์ผ์ด์
๊ฐ๋ฐ์ด ์ ์ ์ฑ์ํด์ง๊ณ ์๋ค๋ ์ฆ๊ฑฐ๋ค. LLM ์ ๊ณต์ฌ(OpenAI, Anthropi, Google)์ ์ต์ ๊ธฐ์ ์ ๋น ๋ฅด๊ฒ ์์ฉํ๊ณ ๊ฐ๋ฐ์๊ฐ ๊ฐ์ฅ ๋ถํธํ๋ ํ์
์์ ์ฑ๊ณผ ๊ตฌ์กฐํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํํ๋ค.
AI ๊ธฐ๋ฅ์ ๋์
ํ๋ ค๋ ๋ชจ๋ Spring Boot ๊ฐ๋ฐ์ ๋ถ๋ค์ ์ด๋ฒ 1.1.1 ๋ฒ์ ์ผ๋ก ์
๋ฐ์ดํธํ์ฌ ๋์ฑ ๊ฐ๋ ฅํ๊ณ ์์ ์ ์ธ AI ๋ฐฑ์๋ ์๋น์ค๋ฅผ ๊ตฌ์ถํ๊ธฐ ๋ฐ๋๋ค.
์ฐธ๊ณ
https://spring.io/blog/2025/12/05/spring-ai-1-1-1-available-now
