AI/Spring AI 3

팀 프로젝트(Zelo) - LLM 구조화 출력: 엄격 모드 도입 배경

Zelo(제로클릭 커머스)는 채팅 한 줄로 장보기를 끝내는 서비스다. 사용자의 말을 LLM이 정해진 칸의 객체로 정리하고, 서버가 그 값으로 상품을 고르고 금액을 계산한다. 이 글은 LLM의 답을 어떤 방식으로 객체로 받을지 고른 과정과 근거를 기록한 것이다. 1. 무엇을 받아야 했나사용자가 이렇게 말한다.토요일에 초등학생 둘이랑 넷이 먹을 건데, 김치볶음밥 재료 3만 원 안에서 준비해 줘서버가 필요한 건 문장이 아니라 칸이 정해진 값이다. 이 값을 MenuPlan이라는 record로 정의했다.public record MenuPlan( MenuPlanIntent intent, // SHOPPING_REQUEST / GENERAL_QUESTION ..

AI/Spring AI 2026.10.24

[Troubleshooting] Spring AI 2.0에서 OpenAI 타임아웃이 적용되지 않았던 이유

application.yaml에 OpenAI 타임아웃을 5초로 적어 두었는데, 실제 요청은 60초까지 기다리고 있었다. Spring AI 2.0.1이 요청을 보낼 때마다 타임아웃을 기본값 60초로 다시 덮어쓰기 때문이었고, 요청 옵션에 타임아웃을 직접 넣어 해결했다. 고친 뒤에는 1초로 설정하면 정확히 1.01초에 요청이 끊긴다.배경: 타임아웃이 왜 필요한가식당에서 주문하면서 "15분 안에 안 나오면 취소할게요"라고 정해 두는 것과 같다. 우리 서버가 OpenAI에 질문을 보내면 답이 올 때까지 기다리는데, OpenAI가 느리거나 장애가 나면 무한정 기다릴 수는 없다.사용자는 채팅창에서 계속 빈 화면을 본다.기다리는 동안 서버의 일꾼(요청 스레드)이 하나씩 묶인다. 이런 요청이 쌓이면 주문·결제 같은 다..

AI/Spring AI 2026.10.22

서킷 브레이커 이해하기: 외부 LLM API의 장애가 우리 서비스로 번지지 않도록

Zelo의 장보기 도우미 채팅은 사용자의 메시지를 받아 OpenAI(gpt-5-mini)를 호출하고, 그 결과를 AI 메시지로 저장해 응답한다. 그런데 OpenAI에 장애가 발생하면 어떻게 될까?사용자는 답변을 기다리고, 서버는 응답이 오지 않는 요청을 계속 처리해야 한다. 여기에 재시도까지 더해지면 장애가 발생한 외부 서비스에 요청이 반복해서 전달된다.이때 필요한 것이 서킷 브레이커(Circuit Breaker)이다.이 글에서는 서킷 브레이커가 언제 호출을 차단하고 어떻게 다시 허용하는지 개념을 먼저 정리하고, 각 개념이 우리 프로젝트 코드에서 어떻게 구현되었는지, 왜 그렇게 했는지를 함께 살펴본다.사용 기술: Spring Boot, Spring AI 2.0.1(OpenAI), Resilience4j ..

AI/Spring AI 2026.10.21