채팅봇 데모가 작동한다고 해서 10,000명의 사용자에게 배포할 준비가 되었다는 의미는 아닙니다.
LLM 주변에 어떤 요소들이 갖춰져야 하는지에 대한 아키텍트의 설명: 실제 고객에게 AI 어시스턴트를 출시하기 전에
IMAGE: 01-hero-iceberg.png
LLM 호출은 보이는 부분입니다. 당신이 출시 주간을 생존할지 여부를 결정하는 거의 모든 것이 그 아래에 있습니다.
다음 상황을 상상해 보세요. 한 이커머스 회사(BlipKart라고 부르겠습니다)의 엔지니어가 챗봇을 만들었습니다. 이 챗봇은 질문에 답하고, 제품 정보를 찾아주고, 심지어 고객이 주문하는 과정을 안내할 수도 있습니다. 데모는 순조롭게 진행됩니다. CEO는 감명받고 단 한 가지를 요청합니다. 월요일까지 10,000명의 사용자에게 배포해 달라고요.
이는 익숙한 순간이지만 함정을 숨기고 있습니다. 데모는 친절한 사람이 친절한 질문을 했을 때 모델이 좋은 답변을 생성할 수 있음을 증명합니다. 하지만 프로덕션은 다른 질문을 던집니다: 시스템이 수천 명의 낯선 사용자가 동시에 사용할 때, 그들 중 일부가 시스템을 망가뜨리려고 시도하고, 당신의 모델 제공업체가 컨디션을 좋지 않을 때에도 안전하고 정확하며 합리적인 답변을 계속 생성할 수 있는가?
LLM API를 호출하는 것은 쉬운 부분입니다. 그 주변에 신뢰할 수 있는 제품을 운영하는 것이 진짜 일입니다. 결제, 카드 및 뱅킹 플랫폼 설계 경험이 15년 동안 쌓인 저는 — 여기서 '데모에서 작동했다'는 적절한 승인 사유가 된 적은 단 한 번도 없었습니다 — AI 시스템에도 거의 하나하나 동일하게 적용되는 원칙들을 발견했습니다. 제가 BlipKart를 데모에서 프로덕션으로 가져가는 방법은 다음과 같습니다.
1. 측정 가능한 요구사항부터 시작하세요
단 하나의 박스를 그리기 전에, 팀들이 끊임없이 혼동하는 두 가지 대화를 분리해야 합니다.
**고수준 설계(High-level design)**는 지도가 됩니다: 어떤 주요 구성 요소가 존재하며 어떻게 통신하는지입니다. BlipKart의 경우 이는 API 게이트웨이, 의도 라우터(intent router), 캐시, 검색 증강 생성(Retrieval-Augmented Generation, RAG) 파이프라인, 모델 게이트웨이 및 커머스 API입니다.
**저수준 설계(Low-level design)는 각 상자 내부를 의미합니다: 벡터 스토어 복제본 및 리전, 청크 크기, 스키마, 프롬프트 템플릿, 그리고 이를 구현하는 클래스들입니다. 이 두 가지 레벨을 하나의 검토에서 혼합하여 논의하면, 아무도 인증 계층(authentication layer)이 없다는 사실을 알아차리지 못한 채 팀원들이 청크 크기에 대해 한 시간 동안 토론하는 상황이 발생합니다.
그러면 요구사항을 두 개의 목록으로 작성하세요.
기능적(Functional) — 봇이 무엇을 해야 하는가: 자주 묻는 질문(FAQs)에 답변하기, 주문 추적하기, 환불 처리하기, 특정 대화를 인간에게 인계하기.
비기능적(Non-functional) — 얼마나 잘 수행해야 하는가, 이해관계자들이 숫자로 서명하는 부분:
- P95 지연 시간(latency) 3초 미만
- 월별 지출액 ₹3 lakh 이내
- 개인 식별 정보(PII) 유출 0건
- 가용성 99.9%
이러한 숫자들이 문서화되지 않으면, 나중에 발생하는 모든 트레이드오프는 목표 대비 확인 작업이 아니라 의견에 대한 논쟁거리가 됩니다.
용량 계산을 수행하고 — 평균값만 믿지 마세요
10,000명 사용자 × 일일 5개 메시지 = 50,000개 메시지. 이를 86,400초에 균등하게 분산하면, 초당 약 0.58 요청입니다. 사소해 들립니다. 하지만 오해의 소지가 있습니다.
03-capacity-average-vs-peak.png
같은 50,000개 메시지라도 부하가 매우 다를 수 있습니다. 온화한 저녁 피크 시간대조차도 일일 평균보다 두 배 이상 높을 수 있으며 — 세일 캠페인이나 푸시 알림은 훨씬 더 심각할 수 있습니다.
트래픽 클러스터: 점심시간, 저녁 시간, 프로모션 푸시가 도착한 순간. 여기에 재시도(retries), 다중 턴 대화(multi-turn conversations), 그리고 각각 여러 모델 호출로 분산되는 도구 호출(tool calls)을 추가하세요. 하루 기준이 아닌 **피크 분(peak minute)**에 맞춰 용량을 계획하고, 메시지를 **월별 토큰 수(tokens per month)**로 변환하여 출시 전에 제공업체와 속도 제한 및 예약된 용량에 대해 논의할 수 있도록 하세요. 그렇지 않으면 사고가 발생한 후에야 이야기하게 됩니다.
2. 경계에서 고객을 보호하기
02-reference-architecture.png
시스템의 참조 구조입니다. 신뢰 경계(trust boundary) 내부에서는 단일 토큰이 생성되기 전에 모든 것이 실행됩니다.
계정 조치 전 인증 수행 (Authenticate before any account action)
"제 마지막 주문을 환불해 주세요"라는 문구는 시스템이 누구의 마지막 주문인지 알지 못하면 아무 의미가 없습니다. 신원(Identity)은 Keycloak과 같은 ID 공급자(identity provider)를 사용하여 적절한 표준—OIDC, OAuth 기반 로그인, SSO—으로 확립되어야 합니다.
제가 가장 강조하고 싶은 점 중 하나는 다음과 같습니다: 권한 부여(authorisation)는 프롬프트가 아닌 도구에 존재해야 합니다. 주문 조회 도구는 모델이 텍스트로 전달하는 내용이 아니라 검증된 토큰에서 고객 ID를 파생시켜야 합니다. 만약 모델이 "고객 9902의 주문 4471"을 요청하도록 유도될 수 있다고 해도, 이를 막아야 하는 것은 모델의 예의가 아니라 API 자체가 거부하는 것이어야 합니다.
게이트웨이를 통한 오용 방지 (Let the gateway absorb abuse)
API 게이트웨이는 트래픽이 애플리케이션이나 LLM에 도달하기 전에 사용자별 요청 제한 및 일일 또는 월간 토큰 예산을 적용하기에 적절한 장소입니다. 이를 웹 애플리케이션 방화벽(web application firewall) 및 로드 밸런싱과 결합하십시오. Cloudflare, NGINX, Kong, Apigee 또는 사용 중인 클라우드 제공업체의 네이티브 게이트웨이가 모두 이 기능을 수행할 수 있습니다. 제한 사항을 조정하여 서비스를 제공하는 측과 귀하의 청구서를 보호하면서도, 다섯 가지 후속 질문을 하는 실제 고객에게 불이익을 주지 않도록 하십시오.
입력과 출력을 모두 확인하기 (Check what goes in — and what comes out)
프롬프트 인젝션(Prompt injection)은 이론적인 문제가 아닙니다. 한 자동차 딜러십의 챗봇이 사용자가 모든 것에 동의하도록 지시하자, 약 $70,000 상당의 차량을 $1에 판매하는 데 동의하는 것처럼 보이는 사례가 광범위하게 보고되었습니다. 이러한 사례들의 법적 결과와 관계없이, 설계 교훈은 명확합니다: 챗봇이 절대 약속할 수 없는 것이 무엇인지 사전에 정의해야 합니다.
- **입력 가드레일(Input guardrails)**은 금지되거나 조작적인 요청을 차단합니다.
- **출력 가드레일(Output guardrails)**은 응답이 고객에게 도달하기 전에 봇이 권한을 갖지 않은 개인 식별 정보(PII), 가격 또는 약속을 포착합니다.
금지된 응답 목록은 법무 및 규정 준수팀(Legal and compliance)에서 소유해야 합니다. 엔지니어링팀(Engineering)이 이를 강제 집행할 책임이 있습니다.
3. 모든 요청을 올바른 곳으로 라우팅하기
모든 메시지가 대규모 언어 모델(LLM)의 도움을 받을 필요는 없습니다. 인사말, 주문 상태 문의, 환불 요청 및 정책 질문은 네 가지 다른 워크로드입니다.
**의도 라우터(intent router)**가 설계의 중앙에 위치하여 경로를 선택합니다:
- 인사 및 감사 → 고정된 응답
- 주문 상태, 가격, 환불 → 커머스 API 및 도구(tools)
- 정책 및 사용 방법 질문 → RAG
- 모호한 판매 또는 지원 질문 → 분류기(classifier)를 거친 후 LLM
정책 PDF와 문제 해결 가이드는 청크(chunk)로 분할되어 임베딩되고 벡터 스토어(vector store)—Qdrant, Chroma, Pinecone, pgvector 등—에 인덱싱됩니다. 실패 모드는 첫날의 검색 품질 문제가 아니라, 반품 정책이 변경되었는데 봇이 여전히 이전 정보를 인용하는 '90일째의 오래됨(staleness)' 문제입니다.
콘텐츠 소스에 변경 데이터 캡처(change data capture) 기능을 연결하세요. 문서가 변경되면 영향을 받은 청크만 재인덱싱하고, 그 기반으로 구축된 캐시 항목은 제거해야 합니다. 매일 밤 '모든 것을 재인덱싱'하는 작업도 없고, 일주일 동안 오래된 답변이 남아있지도 않아야 합니다.
인간에게 인계할 시점을 파악하기
청구 금액에 대해 이의를 제기하거나 멤버십 취소를 앞둔 고객은 생성된 단락이 아니라 판단력과 공감이 필요합니다. AI가 절대 혼자 처리해서는 안 되는 의도(intent)가 무엇인지 사전에 결정해야 합니다. 그리고 봇이 상업적 가치를 지닌 무언가—유지 할인, 선의 크레딧 등—를 제공하도록 허용한다면, 언제, 얼마나 많이, 얼마나 자주 제공할지에 대한 명시적인 규칙을 작성하세요.
4. 품질 저하 없이 비용 통제하기
최소한으로 충분한 지능(Minimum sufficient intelligence)
04-minimum-sufficient-intelligence.png
필요한 만큼만 올라가세요. 계단 하나를 오를 때마다 비용이 더 들고 예측 가능성이 떨어집니다.
제가 벽에 붙일 원칙은 이것입니다: 품질 기준을 충족하는 가장 덜 복잡한 메커니즘을 사용하세요.
모델 라우팅(Model routing)은 각 요청을 해당 요청에 가장 적합한 모델로 보냅니다. 선택 기준이 브랜드나 매개변수 개수가 되어서는 안 됩니다. 실제 BlipKart 대화에서 평가 세트(evaluation set)를 구축하고, 정확도(accuracy), 지연 시간(latency), 비용(cost), 정책 준수 여부(policy compliance)에 따라 후보 모델들을 점수화해야 합니다. 프롬프트나 모델 버전을 변경할 때마다 이 과정을 재실행하세요.
예상치 못한 지출이 되기 전에 비용을 가시화하기
만약 월별 청구서가 조용히 30만 루피(₹3 lakh)에서 60만 루피(₹6 lakh)로 상승한다면, 인보이스를 받는 날이 아니라 8일째에 그 사실을 알아야 합니다. 사용자 또는 계정별 토큰 예산(token budgets)을 설정하고, 모델 및 의도(intent)별 지출을 추적하며, 임계값에 접근할 때 알림을 받으세요. 어떤 의도가 실제로 비싼 모델 사용을 정당화하는지 주기적으로 검토해야 합니다.
5. 급증과 장애에 대비하여 구축하기
06-resilience-gateway-queue.png
큐(Queues)는 급증을 흡수하고; 모델 게이트웨이(model gateway)는 테스트된 폴백(fallback) 기능을 통해 제공업체의 장애를 숨깁니다.
제공업체와 자신 사이에 모델 게이트웨이를 두세요
AI/모델 게이트웨이는 제공업체의 키를 애플리케이션 코드에서 분리하고, 속도 제한(rate limits)과 토큰 예산을 중앙 집중화하며, 기본 제공업체가 오류를 반환하거나 요청을 제한할 때 두 번째 제공업체로 장애 조치(fail over)할 수 있게 해줍니다. LiteLLM과 Vercel AI Gateway가 그 예시입니다.