문서 읽는 데 59분 · day23

Day 23. LLM Ops & 마무리 — 운영 생태계 · 2.0 전환 · 전체 회고

전체 26강 중 25강 · 스프링 AI
난이도 · 심화선수지식자바 기초스프링 부트

ℹ️스프링 부트로 만든 ai-friends 프로젝트 위에 얹어 진행해요. 자바·스프링이 처음이라면 먼저 “서버 만들기” 트랙부터 권해요.

안녕하세요, 여러분의 AI 튜터 홍순구입니다.

지난 시간에 Prometheus + Grafana 대시보드를 완성했어요. UsageTrackingMeterAdvisor로 토큰 메트릭을 기록하고, AuditLoggingAdvisor로 감사 로그를 저장하고, PiiMaskingAdvisor로 개인정보를 걸러냈죠.

Grafana에 8개 패널이 올라간 순간, 드디어 ai-friends에 운영의 눈이 달렸어요.

그런데 한 가지 빈 칸이 남아 있어요.

Prometheus + Grafana는 인프라 메트릭에 강해요. CPU, 메모리, 요청 지연, 에러율... 전통적인 웹 앱 관측의 핵심이죠.

그런데 LLM 앱은 전통적인 앱에 없는 관측 축이 있어요. "이 프롬프트가 저 버전보다 환각률이 낮은가?", "모델 A와 B 중 비용 대비 품질은?" — Grafana만으로는 답하기 어려워요.

오늘은 이 빈 칸을 채우는 LLM Ops 생태계를 조감하고, Day 1부터 Day 23까지 쌓아온 모든 축을 한눈에 회고합니다. 그리고 곧 출시되는 Spring AI 2.0으로 어떻게 전환할지 방향도 잡아요.

🎯 오늘의 한 줄. Prometheus가 (인프라 건강)을 본다면, LLM Ops 플랫폼은 나무(개별 LLM 호출 품질)를 본다 — 프로덕션에서는 둘 다 필요하다.

🎯 학습 목표

  • LLM Ops가 전통 APM과 어떻게 다른지 이해한다
  • Langfuse(오픈소스)와 LangSmith(상용)의 핵심 차이를 파악한다
  • Day 22 관측 인프라가 LLM Ops 플랫폼과 어떻게 연결되는지 그림을 그린다
  • Spring AI Agent Utils와 A2A 프로토콜의 현재 생태계를 파악한다
  • LLM 앱 프로덕션 배포 시 필수 체크리스트를 정리한다
  • Spring AI 2.0의 주요 변경점을 파악하고 마이그레이션 방향을 세운다
  • Day 1~23 전체 과정에서 ai-friends가 어떻게 진화했는지 회고한다

Step 1. LLM Ops 생태계 조감 — Langfuse vs LangSmith

전통 APM vs LLM Ops

Day 22에서 Micrometer + Prometheus + Grafana를 연결했어요. 전통적인 APM(Application Performance Monitoring)의 정석이죠. 이 조합으로 볼 수 있는 건 이런 것들이에요.

전통 APM 관측 축 예시
응답 지연 p50 = 200ms, p99 = 1.2s
에러율 5xx 비율 0.3%
처리량 초당 120 요청
리소스 사용 CPU 40%, 메모리 2.1GB
토큰 사용량 일 120K 입력 + 45K 출력

Day 22의 UsageTrackingMeterAdvisor가 마지막 줄까지 커버해줬어요. 그런데 LLM 앱은 여기서 끝이 아니에요.

LLM Ops가 추가로 보는 축:

LLM Ops 관측 축 전통 APM에 없는 이유
프롬프트 버전 관리 전통 앱에는 "프롬프트"가 없다
모델 A/B 평가 전통 앱은 로직이 결정적이다
환각률 추적 LLM 고유 현상
사용자 피드백 점수 출력 품질의 주관적 평가
비용 모델별 분석 토큰 단위 과금 구조
데이터셋 관리 평가 기준 데이터 버전 관리

Langfuse — 오픈소스 LLM Ops

Langfuse는 오픈소스 LLM Ops 플랫폼이에요. 셀프 호스팅(Docker)도 가능하고, 클라우드 서비스도 있어요.

핵심 개념 3가지:

  1. Trace — 사용자 요청 한 건의 전체 흐름. 우리 ai-friends에서 "채팅 메시지 1건 보내기"가 Trace 하나예요.
  2. Generation — Trace 안에서 실제 LLM 호출 1건. ChatClient가 ChatModel.call()을 부르는 순간이 Generation이에요. 모델명, 토큰 수, 지연시간, 비용이 자동으로 기록돼요.
  3. Score — Generation이나 Trace에 붙이는 품질 점수. 사용자 👍/👎 피드백, 또는 Day 21의 AgentBench 같은 자동 평가 결과를 Score로 기록해요.

Langfuse가 해결하는 문제들:

  • 프롬프트 버전 관리: Day 3에서 만든 SoulmateSystemPrompt.st 를 버전 v1, v2, v3으로 관리. 어느 버전이 더 나은 응답을 만드는지 A/B 비교.
  • 비용 대시보드: 모델별, 기능별, 사용자별 비용 분석. "이미지 생성이 전체 비용의 70%를 쓴다"를 숫자로 확인.
  • 평가 파이프라인: 자동 평가(환각률, 관련성, 독성) + 사람 평가(라벨링) 결합.

현재 서버 v3.175.0, Python/JS SDK는 v4로 전면 리라이트되었어요.

LangSmith — LangChain 진영의 관리형 서비스

LangSmith는 LangChain 팀이 만든 상용 LLM Ops 플랫폼이에요. LangChain에 최적화되어 있지만, REST API로 어떤 프레임워크에서든 사용할 수 있어요.

요금 구조 (2026년 5월 기준):

플랜 가격 Trace 한도 주요 기능
Developer 무료 5,000/월 기본 트레이싱 + 평가
Plus $39/seat/월 무제한 팀 협업 + 고급 분석
Enterprise 별도 문의 무제한 SSO + SLA + 전용 인프라

LangSmith의 강점:

  • Hub: 프롬프트를 팀 단위로 공유하는 저장소. "이 프롬프트 잘 됐으니까 팀에 공유"가 클릭 한 번.
  • Datasets: 평가용 입력/기대 출력 데이터셋을 버전 관리. CI/CD에 평가 자동 실행.
  • Annotation Queue: 사람이 라벨링할 응답을 큐로 관리.

Langfuse vs LangSmith — 어떤 걸 선택할까

Langfuse LangSmith
호스팅 셀프 호스팅 가능 (Docker) 클라우드 전용
가격 셀프 호스팅이면 무료 Developer 무료 5K/월
프롬프트 관리 버전 관리 + A/B Hub + 팀 공유
Spring AI 연동 OpenTelemetry 기반 REST API 직접 호출
데이터 주권 자체 인프라에 보관 LangChain 클라우드
생태계 프레임워크 독립 LangChain 최적화
🙋 학생 질문 — "Prometheus+Grafana 있으면 LLM Ops 플랫폼이 꼭 필요한가요?"

프로토타입 단계에서는 Prometheus만으로 충분해요. 하지만 프로덕션에서 프롬프트 품질을 관리하기 시작하면 LLM Ops 플랫폼이 필요해져요.

"프롬프트 v3이 v2보다 환각률이 20% 낮다"를 Grafana만으로 보기는 어려워요.

Prometheus는 숫자(메트릭)를 잘 보고, LLM Ops는 텍스트(프롬프트/응답)를 잘 봐요.

💡 결론: 사내 인프라에 데이터를 보관해야 하는 조직이라면 Langfuse 셀프 호스팅이 적합해요. 빠른 시작과 관리형 서비스를 선호한다면 LangSmith Developer(무료)부터 시작하세요.

어느 쪽이든 Day 22에서 만든 Prometheus 메트릭 인프라와 병행해서 쓰는 거예요.


Step 2. Day 22 관측 인프라 → LLM Ops 플랫폼 연결 그림

Day 22에서 만든 것 복습

Day 22에서 3종의 Advisor를 만들었어요.

Advisor 역할 데이터 흐름
UsageTrackingMeterAdvisor 토큰 사용량 메트릭 → Micrometer → Prometheus → Grafana
AuditLoggingAdvisor 프롬프트/응답 전문 저장 → AuditLog DB 테이블
PiiMaskingAdvisor 개인정보 마스킹 → 감사 로그 저장 전 필터링

Prometheus + Grafana에서 8개 패널 대시보드까지 만들었어요. 인프라 메트릭 관점은 완성된 상태예요.

LLM Ops 플랫폼이 추가하는 계층

여기에 Langfuse 같은 LLM Ops 플랫폼을 연결하면 두 번째 관측 경로가 생겨요.

사용자 요청
  → ChatClient
    → Advisor Chain
      ├── PiiMaskingAdvisor
      ├── AuditLoggingAdvisor ──→ AuditLog DB
      └── UsageTrackingMeterAdvisor ──→ Micrometer
    → ChatModel.call()
      → LLM Provider (Gemini / Ollama)

관측 경로 1 (인프라): Micrometer → Prometheus → Grafana
관측 경로 2 (LLM 특화): OpenTelemetry → Langfuse

연결 포인트 — Spring AI Observation

Spring AI는 내부적으로 Micrometer Observation API를 사용해요. Day 22에서 spring-boot-starter-actuator를 추가했을 때 자동으로 활성화된 것이죠.

이 Observation 데이터를 OpenTelemetry 프로토콜(OTLP)로 내보내면, Langfuse가 받을 수 있어요.

연결에 필요한 설정은 이런 형태예요.

# application.yml — Langfuse 연결 (개념 예시)
spring:
  ai:
    chat:
      observations:
        include-input: true
        include-output: true

management:
  otlp:
    tracing:
      endpoint: http://localhost:3000/api/public/otel/v1/traces
    metrics:
      export:
        otlp:
          enabled: true
# .env
LANGFUSE_PUBLIC_KEY=pk-...
LANGFUSE_SECRET_KEY=sk-...

⚠️ 이 설정은 개념 안내예요. 오늘은 단방향 강의라 직접 연결하지 않아요. 핵심은 "Day 22 인프라 위에 OTLP exporter 하나 추가하면 LLM Ops 관측이 열린다"는 그림이에요.

Langfuse에서 보이는 것들

연결이 되면 Langfuse 대시보드에서 이런 정보를 볼 수 있어요.

Trace 워터폴: 사용자가 채팅 메시지를 보내면, Advisor chain의 각 단계가 타임라인으로 펼쳐져요. ChatMemory 조회에 12ms, LLM 호출에 850ms, PII 마스킹에 3ms — 병목이 어디인지 한눈에 보여요.

Generation 상세: LLM 호출 하나하나의 모델명, 토큰 수, 비용, 지연시간이 기록돼요. "이번 주 Gemini Flash 비용이 $12.30인데, 이미지 분석이 $8.70"처럼 기능별 비용을 바로 확인할 수 있어요.

프롬프트 버전 비교: SoulmateSystemPrompt.st v1과 v2를 같은 입력으로 돌려서, 어느 쪽 응답이 더 좋은지 Score로 비교해요.

🙋 학생 질문 — "감사 로그를 이미 DB에 저장하는데, Langfuse에도 보내면 중복 아닌가요?"

역할이 달라요. AuditLoggingAdvisor의 DB 저장은 규정 준수(법적 기록)가 목적이에요.

Langfuse는 품질 개선(어떤 프롬프트가 더 나은 응답을 만드는지 분석)이 목적이에요.

프로덕션에서는 둘 다 필요한 경우가 많아요. 감사 로그는 보존 기간이 법에 의해 정해지고, Langfuse 트레이스는 분석 목적에 따라 유연하게 정할 수 있어요.

💡 결론: Grafana는 (전체 시스템 건강)을 보고, Langfuse는 나무(개별 LLM 호출 품질)를 봐요. Day 22의 인프라 위에 OTLP 한 줄 추가하면 LLM 특화 관측이 열려요.


Step 3. Spring AI Agent Utils + A2A 프로토콜 심화

Spring AI Agent Utils

Day 14에서 @Tool로 날씨 검색, 캘린더 조회 같은 도구를 직접 만들었어요. 하나씩 구현하는 건 학습에 좋지만, 프로덕션 에이전트에 범용 도구를 매번 새로 짤 수는 없어요.

Spring AI Agent Utilsspring-ai-community 프로젝트에서 개발 중인 재사용 가능한 도구 라이브러리예요. Claude Code의 도구 시스템에서 영감을 받았어요.

제공 도구 카테고리:

카테고리 도구 예시 Day 14 비교
File Operations 파일 읽기/쓰기/검색 @Tool로 직접 구현했던 것
Shell Execution 명령어 실행 + 결과 반환 가드레일이 기본 내장
Web Access URL 가져오기 + 검색 외부 API 호출 래핑
Task Management 작업 생성/추적/완료 에이전트 간 작업 분배

현재 0.7.0-SNAPSHOT 단계예요. 정식 릴리즈가 되면 build.gradle에 의존성 한 줄 추가로 에이전트에 범용 도구를 장착할 수 있어요.

// 정식 릴리즈 후 예상 형태
implementation 'org.springframework.ai:spring-ai-agent-utils:1.0.0'

Day 19 Harness 6구성요소를 떠올려보세요. 그 중 Tool Belt(에이전트가 사용하는 도구 집합)를 표준화한 것이 Agent Utils예요.

A2A 프로토콜 심화 — 에이전트가 팀으로 일하는 시대

Day 18에서 A2A(Agent-to-Agent) 프로토콜을 처음 만났어요. MCP가 도구 연결(Tool → AI)이라면, A2A는 에이전트 간 통신(AI ↔ AI)이라고 했죠.

팀 차원에서 A2A를 도입할 때 알아야 할 설계 포인트 3가지를 짚어볼게요.

1. Agent Card — 에이전트의 이력서

에이전트가 자신의 역량을 JSON으로 선언하는 것이 Agent Card예요.

{
  "name": "ai-friends-chat-agent",
  "description": "미연시 게임 캐릭터 대화 에이전트",
  "capabilities": [
    "text-chat",
    "image-analysis",
    "voice-synthesis"
  ],
  "endpoint": "https://ai-friends.example.com/a2a",
  "authentication": "oauth2"
}

다른 에이전트가 "이미지 분석을 해줄 수 있어?"라고 물으면, Agent Card의 capabilities를 보고 판단해요. 사람이 팀원의 역할을 파악하는 것과 같아요.

2. Secure Message Envelope — 에이전트 간 통신 보안

에이전트끼리 메시지를 주고받을 때, 세 가지 보안 계층이 필요해요.

계층 목적 기술
인증 "이 메시지가 정말 저 에이전트에서 온 건가?" OAuth2 / mTLS
권한 "이 에이전트가 이 기능을 요청할 자격이 있는가?" RBAC / Capability check
암호화 "전송 중에 내용이 노출되지 않는가?" TLS 1.3

3. 생태계 현황 (2026년 5월)

A2A는 빠르게 성장하고 있어요.

  • 150+ 조직이 참여 (Google, Microsoft, Anthropic, Salesforce 등)
  • Linux Foundation 산하 프로젝트로 거버넌스 확립
  • Azure, AWS Bedrock에서 프로덕션 사례 공개
  • MCP와 A2A는 경쟁이 아니라 상호보완: MCP는 도구 수준, A2A는 에이전트 수준
🙋 학생 질문 — "MCP와 A2A를 둘 다 써야 하는 건가요?"

규모에 따라 달라요. 단일 에이전트 앱(ai-friends처럼)은 MCP만으로 충분해요. 에이전트가 외부 도구를 연결하는 것만 필요하니까요.

멀티 에이전트 시스템(고객 상담 + 주문 처리 + 재고 확인 에이전트)에서는 A2A가 필요해요. 에이전트끼리 "이 고객 주문 확인해줘"라고 업무를 위임해야 하니까요.

💡 결론: MCP가 개인 도구함이라면, A2A는 팀원 간 업무 위임 프로토콜이에요. 에이전트가 혼자 일하는 시대에서 팀으로 일하는 시대로 넘어가고 있어요.


Step 4. 배포 체크리스트 — Day 1~22 부품의 프로덕션 점검

ai-friends를 프로덕션에 배포한다고 가정해볼게요. Day 1부터 22까지 만든 부품들을 실제 서비스에 올릴 때 어떤 점을 챙겨야 하는지 정리해요.

프로바이더 폴백 전략

Day 2에서 application.yml 프로파일 한 줄로 프로바이더를 전환하는 법을 배웠어요. 프로덕션에서는 자동 폴백이 필요해요.

Primary: Gemini Flash (무료 티어)
  ↓ 장애 발생 (5xx / 타임아웃)
Fallback: Ollama 로컬 (또는 다른 프로바이더)

Day 20에서 만든 Resilience4j @CircuitBreaker가 이 역할을 해요. Primary 프로바이더가 3번 연속 실패하면 Circuit이 열리고, 자동으로 Fallback 프로바이더로 전환돼요.

⚠️ "프로바이더 하나에만 의존하면 장애 = 서비스 전체 다운이에요. 반드시 폴백을 준비하세요."

비용 관리

Day 참조 부품 프로덕션 적용
Day 20 UsageBudgetAdvisor 사용자별/기능별 토큰 예산 설정
Day 20 Bucket4j + Redis API Gateway 수준 Rate Limiting으로 격상
Day 20 Resilience4j Circuit Breaker + Retry + Bulkhead 조합
Day 22 CostAlertHealthIndicator 임계값 초과 시 Slack/PagerDuty 알림 연동

프로덕션에서는 일 예산월 ceiling을 따로 설정해요. 일 예산 초과는 경고, 월 ceiling 초과는 자동 throttling(응답 속도 제한)으로 비용 폭주를 방지해요.

API 키 관리

환경 방법
로컬 개발 .env 파일 + spring.config.import
스테이징 Kubernetes Secrets
프로덕션 AWS Secrets Manager / HashiCorp Vault

⚠️ .env 파일은 절대 git에 커밋하면 안 돼요. Day 1부터 .gitignore에 포함해둔 이유예요.

키 로테이션도 중요해요. 한 키를 영원히 쓰면 유출 시 피해가 커져요. 주기적으로 새 키를 발급하고, 이전 키를 폐기하는 zero-downtime 로테이션을 설정하세요.

프로덕션 배포 체크리스트

# 항목 Day 참조 설명
1 프로바이더 폴백 Day 2, 20 Primary + Fallback 설정
2 토큰 예산 + 비용 알람 Day 20, 22 일/월 예산 + 알림 연동
3 API 키 환경변수 분리 Day 1 .env → Secrets Manager
4 PII 마스킹 Day 22 감사 로그 저장 전 필수
5 Rate Limiting Day 20 사용자별/IP별 차등 제한
6 감사 로그 보존 정책 Day 22 업종별 규정 준수
7 메트릭 대시보드 Day 22 Prometheus + Grafana
8 ChatMemory 영속화 Day 5 InMemory 금지, JDBC 필수
9 에이전트 가드레일 Day 14, 21 maxIterations + 토큰 예산 + 타임아웃
10 컨테이너 기반 배포 Day 15 docker-compose → K8s
🙋 학생 질문 — "이 체크리스트를 CI/CD에 자동화할 수 있나요?"

네, 대부분 자동화할 수 있어요. API 키 하드코딩은 git-secrets pre-commit hook으로 잡고, Rate Limiting 설정 누락은 통합 테스트에서 검증하고, 메트릭 엔드포인트는 배포 후 health check로 확인해요.

Day 21의 AgentBench 평가를 CI에 넣으면 "에이전트 품질이 떨어졌는지"도 자동 감지할 수 있어요.

💡 결론: 이 체크리스트의 10개 항목은 Day 1부터 22까지 하나씩 쌓아온 부품이에요. 새로 만들 게 없어요 — 이미 가지고 있는 것을 프로덕션 수준으로 조이기만 하면 돼요.


Step 5. Spring AI 2.0 마이그레이션 노트 — Day 24 예고

릴리즈 일정

우리 강의는 Spring AI 1.1.x(Spring Boot 3.x 호환)로 진행했어요. Spring AI 2.0은 Spring Boot 4.0 기반의 메이저 업그레이드예요.

마일스톤 날짜 상태
2.0.0-M1 2025-12 릴리즈 완료
2.0.0-M8 2026-05-27 릴리즈 완료 (현재 최신)
2.0.0-RC1 2026-06-01 예정 API freeze + 버그 수정만
2.0.0 GA 2026-06-04 예정 정식 릴리즈

원래 5월 28일 GA로 예고되었지만, RC를 거쳐 6월 4일로 조정됐어요. RC1 이후로는 API가 동결되니까, RC1 기준으로 마이그레이션을 시작해도 안전해요.

기반 전환 — Big Picture

1.1.x (현재) 2.0
Spring Boot 3.x 4.0 (Spring Framework 7)
Jackson 2.x (com.fasterxml.jackson) 3.x (tools.jackson)
Java 17+ 17+ (21 권장)
Null Safety 선택적 기본 적용

Jackson 3 패키지 변경이 가장 큰 영향이에요. com.fasterxml.jacksontools.jackson으로 패키지가 바뀌었어요. 직접 Jackson 클래스를 import한 코드가 있다면 전부 수정해야 해요.

주요 변경 카테고리

1. ChatClient API 변경 (M7)

Tool calling이 자동 등록돼요. 이전에는 ToolCallAdvisor를 수동으로 추가했는데, 2.0에서는 tools를 설정하면 자동으로 등록돼요.

// 1.1.x — 수동 등록
chatClient.prompt("날씨 알려줘")
    .tools(weatherTool)
    .advisors(ToolCallAdvisor.builder().build())
    .call().content();

// 2.0 — 자동 등록
chatClient.prompt("날씨 알려줘")
    .tools(weatherTool)
    .call().content();

개별 tool 메서드도 통합됐어요.

// 1.1.x
chatClient.prompt()
    .toolCallbacks(myCallback)
    .toolContext(Map.of("tenantId", "acme"))
    .call().content();

// 2.0
chatClient.prompt()
    .tools(t -> t.callbacks(myCallback)
                  .context("tenantId", "acme"))
    .call().content();

2. ChatMemory 변경 (M6)

Conversation ID가 필수가 됐어요. DEFAULT_CONVERSATION_ID 상수가 삭제되었고, 매 호출마다 명시적으로 전달해야 해요.

// 1.1.x — 기본값 사용 가능
MessageChatMemoryAdvisor.builder(chatMemory)
    .conversationId("my-session")  // 선택적
    .build();

// 2.0 — 필수 전달
chatClient.prompt()
    .user("안녕!")
    .advisors(a -> a.param(
        ChatMemory.CONVERSATION_ID, "my-session"))
    .call().content();

PromptChatMemoryAdvisor도 삭제돼요. MessageChatMemoryAdvisor로 통합됐어요.

3. MCP 마이그레이션 (M3)

MCP 어노테이션이 Spring AI 본체로 흡수됐어요.

// 1.1.x (외부 라이브러리)
import org.springaicommunity.mcp.annotation.McpTool;

// 2.0 (Spring AI 내장)
import org.springframework.ai.mcp.annotation.McpTool;

MCP transport 모듈도 Spring AI로 이동했어요.

<!-- 1.1.x -->
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-spring-webflux</artifactId>

<!-- 2.0 -->
<groupId>org.springframework.ai</groupId>
<artifactId>mcp-spring-webflux</artifactId>

4. 설정 프로퍼티 변경 (M6)

.options. 세그먼트가 제거됐어요.

# 1.1.x
spring.ai.openai.chat.options.model: gpt-4
spring.ai.openai.chat.options.temperature: 0.7

# 2.0
spring.ai.openai.chat.model: gpt-4
spring.ai.openai.chat.temperature: 0.7

하위 호환을 위해 .options. 프로퍼티도 당분간 동작하지만, deprecated 경고가 뜰 거예요.

5. 모델 모듈 정리 (M3, M5)

  • spring-ai-azure-openai 삭제 → spring-ai-openai로 통합 (Azure 배포 지원 내장)
  • Anthropic: 자체 API 클래스 삭제 → 공식 Java SDK 사용
  • OpenAI: 공식 openai-java SDK 전환

6. Observation 변경 (M6)

스팬 이름이 바뀌었어요.

1.1.x: tool_call <tool-name>
2.0:   execute_tool <tool-name>

Day 22에서 Grafana 대시보드를 만들었다면, 쿼리의 메트릭 이름을 업데이트해야 해요.

ai-friends 코드베이스 영향 분석 (요약)

코드베이스 365개 파일을 전수 분석한 결과예요.

등급 건수 대표 변경
HIGH 12건 build.gradle 버전 3건 + ChatMemory 상수 + 불변 옵션 + MCP 패키지 등
MEDIUM 11건 BaseAdvisor 인터페이스(14 구현체) + 캐시 단락 + MCP 설정 블록 등

이 중 일부는 RC1/GA에서 확정될 예정이에요. 다음 시간(Day 24)에서 이 변경점들을 직접 코드로 옮겨봐요.

OpenRewrite 자동 변환

Spring AI 팀이 OpenRewrite 레시피를 제공해요. MCP 패키지 이동 같은 반복적인 변환을 자동화할 수 있어요.

mvn org.openrewrite.maven:rewrite-maven-plugin:6.32.0:run \
  -Drewrite.activeRecipes=\
    org.springframework.ai.migration.MigrateToSpringAI200M3

자동 변환으로 커버되는 것(패키지 이동, import 정리)과 수동 보정이 필요한 것(ChatMemory ID 필수화, Tool API 통합)이 있어요. Day 24에서 둘 다 경험해봐요.

🙋 학생 질문 — "1.1.x에서 배운 건 2.0에서 못 쓰는 건가요?"

아니에요. 원리는 그대로예요. ChatClient + Advisor 패턴, ChatMemory, RAG, Tool Calling, MCP — 구조가 바뀐 게 아니라 API 이름이 바뀌고 패키지가 이동한 거예요.

"운전면허를 따고 차를 바꾼 것"과 같아요. 운전하는 법은 그대로인데, 기어 위치가 살짝 달라진 정도예요.

💡 결론: 1.1.x로 배운 원리는 2.0에서도 그대로 살아 있어요. API 이름이 바뀌고 패키지가 이동했을 뿐, ChatClient + Advisor + ChatMemory + RAG 구조는 동일해요.

다음 시간에 직접 코드를 옮기면서 확인해봐요.


Step 6. Day 1 → Day 23 전체 과정 회고 — ai-friends 변천사

23일 동안 ai-friends가 어떻게 변했는지, 큰 그림으로 돌아봐요.

Phase별 축 정리

Phase Day 핵심 축 ai-friends에 추가된 것
1. 기초 1~2 ChatModel + 프로바이더 추상화 RestClient 직접 호출 → ChatClient 한 줄
2. 대화 3~6 Prompt + 출력 + Memory + Stream 수동 파싱 → 구조화 출력 + 영속 메모리 + SSE
3. 멀티모달 7~10 Image + Voice + Video 텍스트 전용 → 이미지/음성/비디오 AI 게임
4. 에이전트 11~14 Tool + 패턴 + 가드레일 수동 함수 → 자율 에이전트 + 안전 장치
5. RAG 15~16 Embedding + VectorStore 단순 대화 → 검색 증강 응답
6. 연결 17~18 MCP + A2A 고립된 앱 → 외부 도구/에이전트 연결
7. 운영 19~23 Harness + Cost + Obs + Ops 코드 → 프로덕션 운영 가능

Before / After — Day 0 vs Day 23

Day 0: 기존 ai-friends (RestClient 기반)

사용자 → AiChatController
           → GeminiService
             └── RestClient로 Gemini API 직접 호출
             └── String.formatted()로 프롬프트 조립
             └── 수동 JSON 파싱
           → ChatLog 엔티티
             └── 수동 DB 조회로 대화 기록

기능: 텍스트 대화만. Gemini에 묶여 있고, 대화 기록은 수동 관리.

Day 23: 완성된 ai-friends (Spring AI 기반)

사용자 → ChatClient
           → Advisor Chain
             ├── MessageChatMemoryAdvisor
             │     └── JdbcChatMemoryRepository
             ├── RetrievalAugmentationAdvisor
             │     └── PgVectorStore
             ├── ToolCallAdvisor
             │     └── @Tool 함수들
             ├── UsageTrackingMeterAdvisor
             │     └── Micrometer → Prometheus
             ├── AuditLoggingAdvisor
             │     └── AuditLog DB
             └── PiiMaskingAdvisor
           → ChatModel (프로바이더 독립)
             → Gemini / Ollama / OpenAI...
           → Cost Guardrail
             └── Bucket4j + Redis + Resilience4j
           → Observability
             └── Prometheus + Grafana

기능: 텍스트 + 이미지 + 음성 + 비디오. 프로바이더 독립. 영속 메모리. RAG 검색. 도구 사용. 에이전트 패턴. 비용 관리. 관측 인프라.

축별 Before / After 비교

Day 0 (Before) Day 23 (After)
LLM 호출 RestClient 직접 HTTP ChatClient 추상화
프로바이더 Gemini 하드코딩 ChatModel 인터페이스 (프로파일 전환)
프롬프트 String.formatted() 순서 기반 PromptTemplate 이름 기반 슬롯
응답 파싱 수동 JSON 파싱 BeanOutputConverter 자동 매핑
대화 기록 ChatLog 수동 DB 조회 JdbcChatMemoryRepository 자동 관리
스트리밍 없음 SSE ChatClient.stream()
이미지 없음 ImageModel 생성 + 분석
음성 없음 STT + TTS
도구 사용 없음 @Tool + ToolCallAdvisor
RAG 없음 pgvector + RetrievalAugmentationAdvisor
외부 연결 없음 MCP Client/Server + A2A
비용 관리 없음 Bucket4j + Redis + Resilience4j
관측 없음 Micrometer + Prometheus + Grafana
보안 API 키 하드코딩 위험 .env + PII 마스킹 + 감사 로그

학습 곡선에서 인상 깊었을 순간들

돌이켜보면, 몇 가지 순간이 기억에 남을 거예요.

Day 2application.yml 프로파일 한 줄 바꿔서 Gemini → Ollama로 프로바이더를 전환했을 때. "코드 한 줄 안 고치고 모델이 바뀐다"는 인터페이스 추상화의 위력을 체감한 순간이에요.

Day 5 — ChatMemory를 도입하고, 이전 대화가 자연스럽게 이어지는 걸 확인했을 때. "AI가 나를 기억한다"는 사용자 경험의 전환점이에요.

Day 11@Tool 하나 등록했더니 AI가 날씨를 검색하는 걸 봤을 때. "AI가 외부 세계와 상호작용한다"는 에이전트의 시작점이에요.

Day 14 — 가드레일 없는 에이전트가 폭주하는 걸 시연했을 때. "자율성에는 반드시 안전 장치가 필요하다"는 교훈이에요.

Day 15 — 첫 RAG에서 "AI가 내 문서를 읽고 답변한다"를 확인했을 때. 일반 대화를 넘어 도메인 특화 AI로 가는 첫걸음이에요.

Day 22 — Grafana 대시보드에 실시간 메트릭이 올라가는 걸 봤을 때. "코드를 짜는 것"에서 "운영하는 것"으로 시야가 넓어진 순간이에요.

🙋 학생 질문 — "이 구조를 실무 프로젝트에 그대로 가져가도 되나요?"

패턴은 그대로 가져가되, 규모에 맞게 조정하세요. ai-friends는 학습용 모놀리스예요. 실무에서는 Advisor 수, 프로바이더 수, RAG 인덱스 규모가 다를 수 있어요.

하지만 ChatClient + Advisor chain + ChatMemory + RAG 기본 구조는 프로덕션에서도 동일해요. Day 19 Harness 6구성요소의 프레임으로 실무 프로젝트를 설계하면 돼요.

💡 결론: 23일 동안 ai-friends는 "RestClient + 수동 파싱 덩어리"에서 "ChatClient + Advisors + ChatMemory + RAG + Tools + Harness + Observability의 레이어드 구조"로 진화했어요.

여러분이 만든 거예요.


Step 7. 다음 학습 방향 — 여기서 어디로 갈 것인가

Day 24 예고

다음 시간에 ai-friends를 Spring AI 2.0으로 실제 마이그레이션해요.

  • build.gradle 버전 올리기 (Spring Boot 4.0 + Spring AI 2.0)
  • OpenRewrite 자동 변환 실행
  • 수동 보정 (ChatMemory ID 필수화, Tool API 통합 등)
  • ./gradlew test 전체 Green 달성

Step 5에서 정리한 마이그레이션 포인트를 직접 코드로 옮기는 시간이에요. RC1(6/1) 또는 GA(6/4)가 나온 시점에 진행하면 가장 정확해요.

이 강의 이후 학습 방향

Spring AI의 기본기는 충분히 쌓았어요. 여기서 더 나아가고 싶다면 이런 방향이 있어요.

1. Spring AI 공식 리소스

2. 커뮤니티 참여

  • spring-ai-community — Agent Utils, MCP Annotations 등 커뮤니티 프로젝트
  • GitHub Discussions — 질문과 아이디어 공유
  • Spring One / AI Conference — 연간 컨퍼런스

3. 심화 학습

  • Agentic Patterns 심화 — Alibaba Graph (LangGraph의 Java 구현) 참고
  • LLM Ops 전문 과정 — Langfuse / LangSmith 깊이 있는 활용
  • MLOps + LLMOps 통합 — 모델 파인튜닝 + 서빙 + 모니터링 파이프라인

4. AI 엔지니어 커리어

2026년 현재, "AI 엔지니어"라는 역할이 빠르게 자리잡고 있어요. 기존 백엔드 개발자와 다른 점은 이런 것들이에요.

역할 핵심 역량
백엔드 개발자 API 설계, DB 모델링, 트랜잭션 관리
AI 엔지니어 + 프롬프트 설계, 에이전트 아키텍처, 평가 시스템, LLM Ops

여러분은 이미 Spring Boot 백엔드 위에 Spring AI를 올려 에이전트를 만들고, Harness로 감싸고, Observability를 구축하는 경험을 했어요. 이 경험이 AI 엔지니어의 출발점이에요.

마지막으로

Day 1에서 RestClient로 Gemini를 호출하고 "Hello, AI"를 받아본 그 순간부터 여기까지 왔어요. 23일 동안 쌓은 건 코드만이 아니에요. LLM 앱을 설계하고, 구현하고, 운영하는 감각이에요.

Spring AI의 원리를 이해하고 있으니, 프레임워크가 바뀌어도 적응할 수 있어요. 2.0이 나와도, 새로운 프레임워크가 나와도 밑바닥의 ChatModel + Memory + Tools + RAG + Harness 구조는 동일해요.

다음 시간에 2.0 마이그레이션을 함께 해봐요. 마지막까지 함께해 주셔서 고마워요.


마무리

오늘 Day 23에서 다룬 내용을 정리할게요.

Step 한 줄 요약
1 LLM Ops 생태계 조감 — Langfuse(오픈소스) vs LangSmith(상용) 비교
2 Day 22 관측 인프라 → Langfuse 연결 그림 (OTLP 한 줄 추가)
3 Agent Utils(범용 도구 라이브러리) + A2A(에이전트 간 통신) 심화
4 배포 체크리스트 10항목 — Day 1~22 부품의 프로덕션 점검
5 Spring AI 2.0 마이그레이션 노트 — GA 6/4, 주요 변경 6카테고리
6 Day 1 → Day 23 ai-friends 변천사 — 7개 Phase 회고
7 다음 학습 방향 — 커리어 + 커뮤니티 + 심화 학습

Day 24로 이어지는 다리

오늘 Step 5에서 정리한 마이그레이션 포인트를 다음 시간에 직접 코드로 옮겨요. build.gradle 버전 올리기부터 OpenRewrite 자동 변환, 수동 보정, 전체 테스트 Green까지 함께 합니다.


생각해볼 주제
1. LLM Ops 플랫폼을 언제 도입해야 하는가?

프로토타입 단계에서 LLM Ops를 도입하면 오버엔지니어링이에요. 프로덕션 직후에 도입하면 "이미 문제가 터진 뒤"고요. MVP 전/후, 프로덕션 전/후 중 어느 시점이 적절한지 생각해 보세요.

규모(스타트업 5명 팀 vs 대기업 50명 팀)에 따라 어떻게 달라지는지도 함께 고민해 보세요.

2. Spring AI 2.0 마이그레이션 — Big Bang vs 점진 전환, 어느 쪽이 안전한가?

Spring Boot 3.x → 4.0 + Spring AI 1.1.x → 2.0을 한 번에 올리는 "Big Bang" 전략과, Spring Boot만 먼저 올리고 나중에 Spring AI를 올리는 "점진 전환" 전략이 있어요.

ai-friends 규모(365개 파일, 테스트 37개)에서는 어떤 전략이 적합하고, 실무의 대규모 프로젝트(수천 파일, 수백 테스트)에서는 어떻게 달라지는지 생각해 보세요.

3. "AI 엔지니어"는 기존 백엔드 개발자와 어떻게 다른가?

2026년 현재 "AI 엔지니어"라는 역할이 빠르게 정착하고 있어요. 기존 백엔드 개발자 역량(API 설계, DB 모델링, 트랜잭션 관리) 위에 어떤 역량이 추가되어야 하는지 생각해 보세요.

그리고 ML 엔지니어(모델 학습/튜닝 전문)와는 어떻게 역할이 나뉘는지도 함께 고민해 보세요.

✅ 예시 답안정답 보기

Day 23은 단방향 강의로, 과제 없이 생각해볼 주제 3개만 제공합니다.


생각해볼 주제 1. LLM Ops 플랫폼을 언제 도입해야 하는가?

[문제 상황 요약]

LLM Ops 플랫폼(Langfuse, LangSmith 등)은 프롬프트 버전 관리, 비용 분석, 평가 파이프라인을 제공해요. 그런데 "언제" 도입해야 할까요?

프로토타입 단계에서 도입하면 아직 최적화할 트래픽도 없는데 인프라만 늘어나요. 프로덕션 후에 도입하면 "왜 환각률이 올랐는지" 추적할 데이터가 없어요.

[튜터의 가이드 및 해설]

도입 시점은 "프롬프트 변경의 빈도"에 따라 결정돼요.

단계 1: 프로토타입 (도입 불필요)

사용자가 10명 이하이고, 프롬프트를 매일 직접 수정하면서 반응을 보는 단계예요. console.log나 감사 로그 DB 정도면 충분해요. Day 22의 AuditLoggingAdvisor가 이 수준이에요.

단계 2: MVP → 베타 (도입 고려)

사용자가 100명을 넘기고, 프롬프트 변경이 "실험"이 되기 시작하면 필요해져요. "v3을 배포했더니 만족도가 떨어졌다"를 수치로 확인해야 하는 순간이에요.

이 시점에 Langfuse의 Trace + Score를 연결하면, 프롬프트 변경의 영향을 정량 추적할 수 있어요.

단계 3: 프로덕션 (도입 필수)

사용자가 1,000명 이상이고, 비용이 월 $100을 넘기면 필수예요. 모델별/기능별 비용 분석, 자동 평가 파이프라인, 프롬프트 롤백이 없으면 운영이 어려워져요.

규모별 선택 가이드:

규모 추천 도구 이유
스타트업 5명 LangSmith Developer (무료) 설정 5분, 관리 부담 0
중소기업 20명 Langfuse Cloud 또는 셀프 호스팅 비용 투명성 + 데이터 주권
대기업 50명+ Langfuse 셀프 호스팅 + 사내 SSO 보안 규정 준수 + 커스터마이징

핵심 판단 기준: "프롬프트를 변경할 때 감으로 결정하고 있는가?" — 감에서 데이터로 전환해야 하는 순간이 도입 시점이에요.

🎯 면접관을 홀리는 핵심 멘트

"LLM Ops 도입 시점은 '프롬프트 변경이 실험이 되는 순간'입니다. 프로토타입에서는 로그 DB로 충분하지만, MVP 단계에서 A/B 테스트를 감으로 판단하기 시작하면 Langfuse 같은 플랫폼이 필요해요. 스타트업이라면 LangSmith 무료 플랜으로 5분 만에 시작하고, 데이터 주권이 중요한 조직이라면 Langfuse 셀프 호스팅으로 갑니다."


생각해볼 주제 2. Spring AI 2.0 마이그레이션 — Big Bang vs 점진 전환, 어느 쪽이 안전한가?

[문제 상황 요약]

Spring Boot 3.x → 4.0 + Spring AI 1.1.x → 2.0을 동시에 올리는 "Big Bang" 전략과, Spring Boot만 먼저 올린 뒤 Spring AI를 나중에 올리는 "점진 전환" 전략이 있어요.

ai-friends(365파일, 37테스트)와 실무 대규모 프로젝트(수천 파일, 수백 테스트)에서 전략이 달라질 수 있어요.

[튜터의 가이드 및 해설]

Big Bang 전략:

한 PR에서 Spring Boot 4.0 + Spring AI 2.0 + Jackson 3을 모두 올려요.

장점 단점
마이그레이션을 한 번에 끝냄 빌드가 깨지면 원인 특정이 어려움
중간 호환 코드 불필요 롤백 시 전체 되돌려야 함
테스트를 한 번만 돌림 팀 전원이 동시에 영향 받음

점진 전환 전략:

1단계: Spring Boot 3.x → 4.0 (Spring AI는 1.1.x 유지) 2단계: Jackson 2 → 3 호환 계층 확인 3단계: Spring AI 1.1.x → 2.0 (API 마이그레이션)

장점 단점
문제 원인 특정이 쉬움 중간 상태에서 호환 코드 필요
단계별 롤백 가능 전체 기간이 길어짐
팀 일부만 먼저 검증 Spring AI 2.0이 Boot 4.0 필수라 중간 단계가 좁음

ai-friends 규모에서의 추천:

ai-friends는 Big Bang이 적합해요. 이유는 세 가지예요.

  1. 파일 365개, 테스트 37개 — 전체 빌드 + 테스트가 1분 이내. 문제가 생겨도 빠르게 확인 가능.
  2. Spring AI 2.0이 Boot 4.0 필수 — Boot를 먼저 올려도 Spring AI 없이는 의미 있는 중간 상태가 없어요.
  3. OpenRewrite 자동 변환 — MCP 패키지 이동 같은 반복 작업은 자동화되니까 수동 보정 범위가 좁음.

대규모 프로젝트에서의 추천:

파일 수천 개, 테스트 수백 개 규모에서는 점진 전환이 안전해요.

  1. 빌드 시간이 10분 이상 — 한 번에 바꾸고 빌드가 깨지면 디버깅 비용이 급등.
  2. 팀이 10명 이상 — 한 PR에 모든 변경을 넣으면 코드 리뷰가 불가능해짐.
  3. 서비스 중단 리스크 — 롤백이 필요할 때 전체를 되돌리면 다른 기능 배포도 막힘.

대규모에서는 Feature Branch + Feature Flag 조합으로, Spring AI 2.0 코드를 별도 브랜치에서 개발하고 Flag로 점진 전환하는 패턴을 써요.

🎯 면접관을 홀리는 핵심 멘트

"마이그레이션 전략은 프로젝트 규모에 따라 달라집니다. 테스트 수십 개 수준의 소규모 프로젝트는 Big Bang이 효율적이에요 — 중간 호환 코드 없이 한 번에 끝내니까요. 하지만 수백 테스트 이상의 프로덕션 서비스라면 점진 전환 + Feature Flag로 단계별 롤백이 가능하게 설계합니다. Spring AI 2.0은 Boot 4.0 필수라 중간 단계가 좁지만, Jackson 3 호환을 먼저 검증하는 것만으로도 리스크를 반으로 줄일 수 있어요."


생각해볼 주제 3. "AI 엔지니어"는 기존 백엔드 개발자와 어떻게 다른가?

[문제 상황 요약]

2026년 현재 "AI 엔지니어"라는 직무가 빠르게 정착하고 있어요. 기존 백엔드 개발자와 ML 엔지니어 사이에 위치하는데, 어떤 역량이 추가되어야 하는지 생각해볼 필요가 있어요.

[튜터의 가이드 및 해설]

역할 3종 비교:

백엔드 개발자 AI 엔지니어 ML 엔지니어
핵심 업무 API 설계, DB 모델링 LLM 앱 설계 + 운영 모델 학습 + 튜닝
모델 관계 API로 호출 API로 호출 + 품질 관리 직접 학습/배포
프롬프트 거의 안 다룸 핵심 역량 학습 데이터에 포함
평가 단위/통합 테스트 + LLM 평가(환각, 관련성) 정밀도/재현율
인프라 K8s, DB, 캐시 + 벡터 DB, LLM Ops GPU 클러스터, MLflow

AI 엔지니어의 고유 역량 4가지:

1. 프롬프트 설계 (Prompt Engineering)

Day 3에서 PromptTemplate을 다뤘어요. AI 엔지니어는 프롬프트를 "코드"처럼 관리해요. 버전 관리, A/B 테스트, 롤백이 일상이에요.

백엔드 개발자는 프롬프트를 문자열로 보지만, AI 엔지니어는 설계 산출물로 봐요.

2. 에이전트 아키텍처

Day 12~14에서 배운 Workflow vs Agent 패턴 설계가 핵심이에요. "결정론적 Workflow로 충분한가, LLM 자율 결정이 필요한가?"를 판단하는 역량이에요.

백엔드 개발자는 API 라우팅을 설계하지만, AI 엔지니어는 에이전트 간 협업 구조를 설계해요.

3. 평가 시스템 (Evaluation)

Day 21 AgentBench에서 경험했어요. LLM 앱은 출력이 비결정적이라, 전통적인 단위 테스트로는 품질을 보장할 수 없어요.

AI 엔지니어는 평가 데이터셋 + 자동 평가 파이프라인을 CI/CD에 통합해요.

4. LLM Ops (오늘 배운 것)

프롬프트 버전 관리, 비용 분석, 환각률 추적, 사용자 피드백 수집을 운영 루틴으로 돌리는 역량이에요. Day 22의 Observability + 오늘의 LLM Ops가 이 영역이에요.

ML 엔지니어와의 경계:

질문 AI 엔지니어 ML 엔지니어
"모델 성능이 부족해요" 프롬프트 개선 + RAG 추가 파인튜닝 + 데이터 수집
"비용이 너무 높아요" 캐싱 + 모델 티어 분리 모델 경량화 + 양자화
"환각이 심해요" 가드레일 + 평가 강화 학습 데이터 정제

AI 엔지니어는 모델을 있는 그대로 사용하면서 앱 수준에서 최적화하고, ML 엔지니어는 모델 자체를 개선해요. 실무에서는 두 역할이 협업하는 경우가 많아요.

커리어 전환 시 가장 빠른 경로:

여러분처럼 Spring Boot 백엔드 위에 Spring AI를 올려본 경험이 있다면, AI 엔지니어로 가는 가장 빠른 경로는 이래요.

  1. 사이드 프로젝트에 RAG + Agent 패턴 적용 (Day 15~16, 12~14 복습)
  2. Langfuse로 프롬프트 A/B 테스트 경험 쌓기 (오늘 배운 것)
  3. 평가 데이터셋 만들어서 CI에 자동 평가 통합 (Day 21 확장)

🎯 면접관을 홀리는 핵심 멘트

"AI 엔지니어는 모델을 직접 학습하지 않지만, 모델을 '잘 쓰는 방법'을 설계합니다. 프롬프트를 코드처럼 버전 관리하고, 에이전트 간 협업 구조를 설계하고, 비결정적 출력에 대한 평가 파이프라인을 CI에 통합하는 게 핵심 역량이에요. 백엔드 개발자가 API를 설계하듯, AI 엔지니어는 '프롬프트 + 에이전트 아키텍처 + 평가 시스템'을 설계합니다."

더 배우려면

실무 프로젝트까지 가고 싶다면

팀스파르타 백엔드 부트캠프에서 인스타그램 클론을 풀스택으로 완성합니다.