Spring AI와 MCP를 사용해 AI 의사 앱을 재구축하고 프롬프트 과부하 문제를 해결한 방법
요약
Java와 Spring Boot 기반으로 AI 건강 비서 앱을 재구축하고, 기존의 프롬프트 연결 방식 대신 Model Context Protocol (MCP)을 활용한 에이전트 도구 호출(tool calling) 방식으로 전환했습니다. 이를 통해 모델이 필요할 때만 외부 데이터를 가져오고 구조화된 행동을 수행하여 '프롬프트 과부하' 문제를 해결했습니다.
핵심 포인트
- Spring AI와 MCP를 사용하여 LLM 오케스트레이션을 구현함.
- 도구 호출(Tool Calling)은 텍스트 파싱보다 정확하고 구조적임.
- 환자 프로필 및 응급 상황 플래그 등 외부 데이터 접근을 도구로 분리하여 관리함.
- ChatMemory를 활용해 다중 턴 대화의 컨텍스트를 유지하며, MySQL에 저장됨.
안녕하세요, 저는 인도 Bhopal 출신의 백엔드 개발자 Swayam Verma이며 Java와 Spring Boot로 작업합니다. 이 글은 제가 만든 AI 건강 비서인 Virtual AI Doctor에 관한 내용과, 여기에 적용한 가장 큰 변화점: 프롬프트 연결(prompt concatenation) 방식에서 Model Context Protocol (MCP)을 사용한 에이전트 도구 호출(agentic tool calling) 방식으로 전환한 것에 대한 이야기입니다.
Virtual AI Doctor는 학습 및 포트폴리오 프로젝트이며, 실제 의사를 대체할 수 없습니다.
앱의 기능
사용자는 Hindi 또는 English로 자신의 증상을 설명하고, 동일한 언어로 의료 지침을 받습니다. 사용된 기술 스택은 다음과 같습니다:
- Java 17, Spring Boot 3.5, JWT를 사용한 Spring Security
- LLM 오케스트레이션을 위한 Spring AI (
ChatClient,ChatMemory, 도구 호출) - Spring AI의 OpenAI 호환 클라이언트를 통해 접근하는 Groq (LLaMA 3.1)
- Spring Data JPA 및 Hibernate를 사용한 MySQL
- Render(백엔드), Railway(데이터베이스), 그리고 Vercel(프론트엔드)에 배포
Spring AI는 공식 MCP Java SDK를 기반으로 구축된 MCP 서버/클라이언트 아키텍처를 지원합니다. 저는 앱의 두 부분을 모델이 필요하다고 판단할 때 호출할 수 있는 도구(tool)로 만들었습니다:
getPatientProfile: 요청마다 환자의 건강 프로필을 주입하는 대신, 필요할 때 환자 프로필을 가져옵니다.flagHighSeverity: 상담이 응급 상황이라고 모델 스스로 판단했을 때 호출됩니다.
이제 모델은 언제 프로필이 필요한지, 그리고 무엇이 플래그를 지정할 만큼 심각한지를 결정합니다. 백엔드는 더 이상 텍스트에서 심각도를 스크랩하지 않습니다. 도구 호출(tool call)은 문자열에 대한 추측이 아니라 구조화된 행동입니다.
심각도 플래그가 들어오면, 백엔드는 Brevo API를 통해 이메일 알림을 보내고 사용자는 상담의 PDF 보고서를 다운로드할 수 있습니다.
사용자별 도구 작동 방식 구현하기
도구 호출은 해당 세션이 누구에게 속하는지 알아야 합니다. 저는 요청 범위 컨텍스트(ConsultationContext)를 사용하여, 도구가 모델에게 노출하지 않으면서 현재 세션을 볼 수 있도록 했습니다. 이것을 올바르게 하는 것이 중요합니다. 왜냐하면 잘못된 환자의 프로필을 반환하는 도구는 심각한 버그가 될 것이기 때문입니다.
턴 간 메모리 유지하기
다중 턴(Multi-turn) 대화에는 Spring AI의 **ChatMemory**를 사용하며, 이는 MySQL의 Spring AI JDBC 채팅 메모리 저장소에 의해 백업됩니다. 어시스턴트는 대화의 컨텍스트를 유지하고, 과거 세션은 진단 및 심각도와 함께 상담 기록에 저장됩니다.
기타 기능들
-
가입 및 로그인을 위한 JWT 인증, 보안 API 포함
-
OpenStreetMap과 Overpass API를 사용한 근처 약국 찾기 (API 키 불필요)
-
나이, 혈액형, 알레르기와 병력 정보가 포함된 건강 프로필
-
다크 모드 및 라이트 모드
-
Tool calling이 프롬프트 과부하(prompt stuffing)보다 우수합니다. 모델은 필요한 경우에만 컨텍스트를 요청하기 때문에, 프롬프트를 더 작게 유지하고 데이터 접근을 명시적으로 할 수 있습니다.
-
구조화된 액션(Structured actions)이 텍스트 파싱(text parsing)보다 우수합니다. '답변에서 심각도 태그 찾기'를
flagHighSeverity도구로 대체함으로써 응급 처리가 더 깔끔해졌습니다. -
보안은 설계의 일부입니다. 건강 앱에서는 기능 구현 이전에 인증 및 세션별 컨텍스트가 우선되어야 합니다.
다음 계획 (What's next)
- 기존 HIGH 심각도 플래그와 함께 사용할 MEDIUM 심각도 도구
- React 프론트엔드
- WebSocket 기반 실시간 채팅
- 증상에 대한 음성 입력 기능
직접 사용해보고 코드 확인하기 (Try it and see the code)
- 라이브 데모: https://virtual-ai-doctor-frontend.vercel.app
- 소스 코드: https://github.com/Swayamverma8/Virtual-Ai-Doctor
- 제 포트폴리오: https://swayam-portfolio-eta.vercel.app
저는 TIT Bhopal의 최종 학년 CSE 학생이며, Google Student Ambassador (Gemini AI)입니다. 백엔드 및 AI 중심 역할에 관심이 있습니다. LinkedIn 또는 GitHub에서 저와 연결해 주세요.
만약 Spring AI나 MCP를 사용해서 비슷한 것을 구축하셨다면, 어떤 어려움이 있었는지 듣고 싶습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기