27장. 연구실에서 세상으로
이 장의 질문: 노트북에서 돌아가는 모델과 수만 명이 쓰는 서비스 사이에는 무엇이 있는가? 서빙, 비용과 지연, 모니터링, 그리고 모델이 늙는 문제 — 만든 것을 세상에 내보내고 살아 있게 유지하는 기술을 배운다.
전제: 8장(평가와 기록), 18장(생성의 직렬성), 23장(RAG). 이 장은 원리 개관이며, 세부는 코드랩 20에서 손으로 익힌다.
모델은 제품의 일부일 뿐이다
실제 AI 시스템에서 모델 코드가 차지하는 비중은 놀랄 만큼 작다. 나머지는 데이터를 모으고 검증하는 파이프라인, 특징을 계산하는 코드, 서빙 인프라, 모니터링, 실험 관리다. 첫 모델을 만드는 데 2주가 걸렸다면, 그것을 안정적으로 운영하는 데는 몇 달이 걸린다. 이 장은 그 몇 달의 지도다.
서빙: 모델을 API로
배포의 첫걸음은 모델을 요청을 받아 예측을 돌려주는 서비스로 감싸는 것이다. 원칙 몇 가지가 사고를 막는다.
- 모델은 시작 시 한 번만 로드한다. 요청마다 로드하는 것은 최악의 안티패턴이다.
- 전처리는 학습 때와 완전히 동일해야 한다. 학습 시 정규화 상수와 서빙 시 상수가 다르면 성능이 소리 없이 깎인다 — 학습-서빙 왜곡이라는 이름이 붙은, 가장 흔하고 가장 발견하기 어려운 버그다. 처방은 전처리 코드를 학습·서빙이 같은 함수로 공유하는 것.
- 입력을 검증하고 실패를 정의하라. 모델은 어떤 입력에도 무언가를 출력한다 — 잘못된 형식, 비어 있는 이미지, 범위 밖의 값에 대해 "어떻게 실패할지"를 코드로 정해야 한다.
- 헬스 체크 엔드포인트. 로드밸런서와 오케스트레이터가 "살아 있는가"를 물을 곳.
성능의 핵심 기법은 배칭이다. GPU는 요청 하나를 처리하는 데 최적화된 기계가 아니다 — 수천 개를 동시에 처리할 때 효율이 나온다(3장의 행렬 곱). 그래서 짧은 시간(수 밀리초) 동안 도착한 요청을 모아 한 배치로 추론하는 동적 배칭이 처리량을 몇 배로 끌어올린다. 대가는 그 몇 밀리초의 대기 — 지연과 처리량의 트레이드오프 다이얼이다.
LLM 서빙은 별도의 세계다. 18장에서 본 대로 생성은 토큰 하나씩 직렬이고, 매 토큰마다 지금까지의 모든 토큰에 대한 어텐션이 필요하다. 이전 토큰들의 키·밸류를 다시 계산하지 않고 저장해 두는 KV 캐시가 필수이며, 이 캐시가 메모리를 지배한다. 요청마다 생성 길이가 달라 배치 관리가 까다로운데, 끝난 요청의 자리를 즉시 새 요청으로 채우는 연속 배칭과 캐시 메모리를 페이지 단위로 관리하는 기법이 표준이 되었다. 여기에 가중치의 정밀도를 낮춰 메모리와 속도를 버는 양자화(16비트 → 4비트, 정확도 손실 최소화 기법과 함께), 작은 모델이 초안을 뽑고 큰 모델이 검증하는 추측 디코딩 등이 얹힌다. 직접 구현할 일은 드물다 — 전용 서빙 엔진이 이것들을 내장한다 — 하지만 왜 그런 기법이 필요한지를 알아야 병목을 진단할 수 있다.
비용과 지연: 숫자로 결정하기
배포 결정은 세 숫자로 내린다 — 처리량(초당 요청), 지연(요청당 시간 — 평균이 아니라 p95/p99: 가장 느린 5%, 1%의 경험), 비용(요청당 원). 세 숫자는 서로 당긴다. 배칭은 처리량을 올리고 지연을 조금 높인다. 양자화는 비용을 내리고 정확도를 조금 깎는다. 작은 모델은 셋 다 좋아지고 품질이 떨어진다.
정답은 없고 요구사항이 있을 뿐이다. 실시간 대화는 첫 토큰까지의 지연이 생명이고, 야간 배치 분석은 처리량과 비용만 본다. 그러니 먼저 요구사항을 숫자로 적고, 그 다음 기법을 고른다. 그리고 어떤 기법이든 부하 테스트로 실제 숫자를 재기 전에는 믿지 않는다 — 8장의 "측정 없는 성적은 소문"이 운영에서는 "부하 테스트 없는 성능은 소문"이 된다.
늙는 모델: 모니터링과 드리프트
가장 중요한 절이다. 배포 첫날의 모델이 최고 성능이고, 그 뒤로는 늙는다. 세상이 변하기 때문이다. 유행어가 바뀌고, 신제품이 나오고, 사용자층이 바뀌고, 경제 상황이 변한다. 훈련 데이터의 분포와 실제 입력의 분포가 멀어지는 것을 드리프트라 하며, 두 종류를 구분한다.
- 데이터 드리프트 — 입력 분포
의 변화. 신규 사용자층 유입으로 연령 분포가 바뀌는 것. 입력 통계를 지켜보면 정답 없이도 감지된다. - 컨셉 드리프트 — 입력과 정답의 관계
의 변화. 팬데믹으로 같은 소비 패턴의 의미가 달라지는 것. 정답이 나중에 도착해야(지연 레이블) 성능 하락으로 감지된다.
그래서 모니터링은 두 층이다. 첫째, 입력과 출력의 통계 — 특징 분포, 예측 클래스 비율, 확신도 분포를 시간별로 추적해 훈련 시점과 비교한다. 둘째, 실제 성능 — 정답이 도착하는 대로(구매 여부, 클릭, 사람 검수) 지표를 갱신한다. 그리고 로그 — 요청 ID, 입력, 예측, 지연을 구조화해 남기는 것 — 는 이 모두의 원재료이자, 다음 재학습 데이터의 원천이다.
드리프트를 감지하면 재학습한다. 그리고 재학습이 주기적으로 일어난다면, 그 과정은 자동화된 파이프라인이어야 한다 — 데이터 수집·검증 → 학습 → 평가 게이트(기존 모델보다 나은가? 회귀 테스트를 통과하는가?) → 등록 → 배포. 사람이 노트북에서 손으로 돌리는 재학습은 두 번째부터 재현되지 않는다.
안전한 배포: 한 번에 다 바꾸지 않기
새 모델은 검증 세트에서 좋았어도 실제 트래픽에서 무너질 수 있다(4장 이후 계속 보아 온 분포 차이). 그래서 배포는 단계적이다.
- 섀도 배포 — 새 모델에 실제 트래픽을 복제해 보내되 응답은 쓰지 않는다. 위험 없이 실제 분포에서의 동작을 관찰한다.
- 카나리 배포 — 트래픽의 작은 비율(1~5%)만 새 모델로 보내며 지표를 감시하고, 이상이 없으면 점진 확대한다.
- A/B 테스트 — 사용자를 무작위로 나눠 비즈니스 지표(전환율 등)를 통계적으로 비교한다. "모델 지표가 좋다"와 "사업에 좋다"는 다르다.
- 롤백 준비 — 이전 모델로 즉시 되돌릴 수 있어야 한다. 모델 버전·설정·데이터 버전을 함께 기록하는 레지스트리(8장 기록 규율의 운영판)가 이를 가능하게 한다.
재현성이라는 기반
이 모든 것의 바닥에 8장의 규율이 있다. 코드 버전, 데이터 버전(스냅샷 또는 해시), 환경(의존성, 컨테이너 이미지), 설정과 시드, 학습된 아티팩트, 평가 결과 — 이 여섯을 묶어 두지 않으면 "지난달 그 모델을 다시 만들어 달라"는 요청에 답할 수 없고, 사고가 났을 때 무엇이 바뀌었는지 추적할 수 없다. 도구(실험 추적기, 데이터 버전 관리, 모델 레지스트리)는 이 규율을 편하게 해 줄 뿐, 규율을 대신하지는 않는다.
핵심 요약
- 모델은 시스템의 작은 부분이다. 서빙의 원칙: 한 번 로드, 학습-서빙 전처리 동일(왜곡 방지), 입력 검증과 실패 정의, 헬스 체크. GPU 효율은 동적 배칭에서 나온다.
- LLM 서빙은 직렬 생성과 KV 캐시 메모리가 지배한다 — 연속 배칭, 양자화, 추측 디코딩이 표준이며, 왜 필요한지 알아야 병목을 진단한다.
- 처리량·지연(p95/p99)·비용은 서로 당긴다. 요구사항을 숫자로 먼저 적고, 부하 테스트로 재기 전엔 믿지 않는다.
- 모델은 늙는다. 데이터 드리프트(입력 통계로 감지)와 컨셉 드리프트(지연 레이블로 감지)를 모니터링하고, 재학습은 평가 게이트를 가진 자동 파이프라인으로. 배포는 섀도→카나리→A/B, 언제나 롤백 가능하게.
- 재현성(코드·데이터·환경·설정·아티팩트·결과)은 운영의 바닥이다.
스스로 점검
- 학습-서빙 왜곡이 "소리 없이" 성능을 깎는 이유와, 그것을 구조적으로 막는 방법을 설명해 보라.
- 평균 지연 50ms인 서비스의 p99가 2초라면 사용자는 무엇을 경험하는가? 왜 평균만 보면 안 되는가?
- 정답이 3개월 뒤에 도착하는 대출 상환 예측 모델에서, 배포 후 첫 3개월 동안 무엇으로 이상을 감지할 수 있는가?
- 섀도 배포와 카나리 배포의 차이를 "위험"과 "정보"의 관점에서 비교해 보라.
다음 장에서
마지막 장이다. 이 책은 여기서 끝나지만 이 분야는 매달 바뀐다. 무엇이 변하고 무엇이 변하지 않는지, 논문을 어떻게 읽고, 어디서 계속 배우며, 어떤 순서로 실력을 쌓아 갈지 — 책을 덮은 뒤에도 성장하는 법을 적고 마친다.