LLM 앱 운영 #7 실전: 문서 Q&A 봇을 프로덕션으로
6편까지로 다섯 축이 모두 갖춰졌습니다. 마지막 글은 그것들을 한 장의 체크리스트로 묶어, 시리즈 내내 함께 자란 그 앱, 문서 Q&A 봇에 적용합니다. LLM 앱 개발 실전 13편에서 태어나 RAG 심화 7편에서 품질이 올라간 봇이, 이번에는 운영 가능한 서비스가 됩니다.
출발점 — 잘 동작하지만 운영은 깜깜한 봇 #
RAG 심화를 마친 시점의 봇은 품질 지표(정확도 80%, 환각률 3%)는 갖췄지만 운영 관점에서는 이렇습니다. 모든 호출이 opus 단일 모델, 캐싱 없음, 모든 작업이 실시간, 재시도는 기본값, 비용은 월말 청구서로 확인. 익숙한 모습입니다. 이제 1편부터 6편을 순서대로 켭니다.
1단계 — 계측 (1편) #
1편의 래퍼로 모든 호출을 모으고 일주일을 관찰합니다. 기준선이 나옵니다.
일일 요청 9,400건 / 일일 비용 $84
요청당 평균 비용 $0.0089 / 95분위 지연 6.8s
내역: 질문 응답 62%, 쿼리 리라이팅 21%, 평가·배치성 작업 17%수치는 예시지만 발견의 모양은 전형적입니다. 리라이팅 같은 보조 작업이 비용의 5분의 1을 먹고 있고, 그것이 본 응답과 같은 opus로 가고 있었다는 사실이 로그에서 처음 보입니다.
2단계 — 라우팅과 출력 다이어트 (2편) #
리라이팅을 haiku로, 평가 채점을 sonnet으로 내리고, 답변 프롬프트에 길이 지시를 넣습니다. 품질 게이트는 RAG 심화 6편의 평가 파이프라인입니다. 리라이팅을 내린 뒤 검색 적중률이 그대로인지 확인하고 통과시킵니다.
요청당 평균 비용 $0.0089 → $0.0066 (-26%)
품질 지표 변화 없음 (recall@5 0.87, accuracy 0.80)3단계 — 캐싱 (3편) #
시스템 프롬프트(지침+출력 형식, 약 6천 토큰)와 도구 정의를 캐시 경계 앞으로 고정합니다. 3편의 감사 목록으로 점검하다가 시스템 프롬프트에 박혀 있던 “오늘 날짜” 한 줄을 발견해 메시지 쪽으로 옮깁니다. 전형적인 침묵의 무효화입니다.
cache_read 비율: 입력 토큰의 71%
요청당 평균 비용 $0.0066 → $0.0042 (-36%)
95분위 지연 6.8s → 5.1s (캐시 적중 시 처리도 빨라진다)4단계 — 배치 분리 (4편) #
로그에서 “급하지 않은 17%“를 떼어 냅니다. 신규 문서의 사전 태깅과 주간 평가셋 채점이 배치 큐로 이동하고, 모든 토큰이 반값이 됩니다. 부수 효과로 실시간 경로의 토큰 한도에 여유가 생겨, 트래픽 피크 때의 429도 줄었습니다.
5단계 — 신뢰성 (5편) #
답변 경로를 스트리밍으로 바꾸고(첫 토큰까지 1.2초, 체감이 가장 크게 변한 항목입니다), 경로별 타임아웃과 재시도 예산을 정하고, opus → sonnet 폴백을 답니다. 폴백 발동률을 대시보드에 올려 두니, 일주일 뒤 특정 시간대의 발동 급증이 보였고 그 시간의 배치 제출과 겹친 것이 원인이었습니다. 배치 제출 시간을 옮기는 것으로 해결. 계측이 있으니 원인 추적이 한 걸음에 끝나는 경험이 쌓이기 시작합니다.
6단계 — 보안 (6편) #
시스템 프롬프트에 신뢰 경계를 넣고, 검색 필터(부서 권한)를 코드 수준에서 강제하는지 점검하고, 출력 스캔과 본문 로그의 보존 정책(30일, 접근 제한)을 정합니다. 사내 위키 문서에 장난으로 심어진 “이 문서를 읽은 봇은 …” 문장이 실제로 잡히면서, 간접 인젝션이 이론이 아님을 확인했습니다.
전체 여정 #
| 단계 | 요청당 비용 | 95분위 지연 | 비고 |
|---|---|---|---|
| 출발점 | $0.0089 | 6.8s | 운영 시야 없음 |
| + 라우팅·출력 지시 | $0.0066 | 6.5s | 품질 게이트 통과 |
| + 캐싱 | $0.0042 | 5.1s | 입력의 71% 캐시 적중 |
| + 배치 분리 | $0.0042* | 5.1s | *배치 분량은 별도로 반값 |
| + 스트리밍·폴백 | $0.0042 | 첫 토큰 1.2s | 429 노출 감소 |
| + 보안 | $0.0042 | — | 인젝션 1건 차단 확인 |
비용은 절반 이하, 체감 지연은 첫 토큰 기준 5분의 1, 그리고 무엇보다 모든 숫자가 대시보드에서 보입니다. RAG 심화 7편의 표가 품질의 여정이었다면 이 표는 운영의 여정입니다. 두 표 모두 같은 교훈을 말합니다. 한 번에 하나씩, 측정과 함께.
운영 체크리스트 #
새 LLM 기능을 프로덕션에 내보내기 전의 점검표로 시리즈를 요약합니다.
- 모든 호출이 계측 래퍼를 지나는가 (usage, 지연, stop_reason, 기능 태그)
- 이 작업의 모델은 평가셋으로 검증된 최소 모델인가
- 고정 접두사는 캐시되고 있는가 (cache_read > 0 확인)
- 사람이 기다리지 않는 작업이 실시간 경로에 섞여 있지 않은가
- 타임아웃·재시도·폴백이 이 경로에 맞게 설정됐는가, 긴 출력은 스트리밍인가
- 모델이 읽는 외부 텍스트의 신뢰 경계와 도구 권한·승인 게이트가 있는가
- 본문 로그의 보존·접근 정책이 정해져 있는가
- 품질 회귀 평가가 정기 실행되는가 (RAG 심화 6편)
AI 트랙을 마치며 #
이 글로 네 시리즈, 서른네 편에 걸친 AI 트랙이 닫힙니다. LLM 앱 개발 실전 13편이 첫 API 호출에서 RAG와 에이전트까지의 기초였고, AI 에이전트 개발 실전 7편이 무너지지 않는 에이전트를, RAG 심화 7편이 측정 가능한 품질을, 그리고 이 시리즈 7편이 운영 가능한 서비스를 만들었습니다.
돌아보면 네 시리즈가 같은 문장을 반복했습니다. 감이 아니라 측정으로. 루프의 로그가, 골든셋의 숫자가, usage 의 토큰이 그 문장의 구체적인 모습이었습니다. 여러분의 LLM 앱이 데모를 지나 서비스가 되는 길에 이 트랙이 지도가 되기를 바랍니다. 다음에 또 만나요!