본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 23. 23:37

모든 AI 데모를 프로덕션으로 가져가기에 아직은 시기상조일지도 모릅니다

요약

AI 데모와 실제 프로덕션 환경 사이의 간극을 경고하며, 단순한 API 호환성만으로는 복잡한 프로덕션 요구사항을 충족할 수 없음을 설명합니다. 도구 호출, 구조화된 출력, 캐싱 등 세부적인 기술적 차이가 시스템의 안정성을 결정한다고 강조합니다.

핵심 포인트

  • 단순한 API 호환성(OpenAI compatible)은 얕은 수준의 호환성에 불과함
  • 프로덕션에서는 도구 호출, 구조화된 출력, 스트리밍 등 세부 구현의 차이가 중요함
  • 데모는 해피 패스 위주지만, 프로덕션은 동시성, 비용, 컴플라이언스 등 복잡한 변수가 존재함
  • 단순한 폴백(fallback) 전략은 모델 간 동작 차이로 인해 프로덕션에서 실패할 수 있음

AI 엔지니어링 분야에서 무해하고 실용적이며 성숙하게 들리는 문장이 하나 있습니다. 바로 “그냥 폴백 제공자(fallback provider)를 추가하세요”라는 말입니다.

깔끔하고, 우아하며, 멋진 말입니다. 보통 프로덕션 환경이 이를 건드리기 시작할 때까지 살아남는 종류의 문장이죠. 왜냐하면 데모에서 폴백(fallback)은 '제공자 A가 실패하면, 제공자 B를 호출한다'는 것을 의미하기 때문입니다. 하지만 프로덕션에서 폴백은 매우 다른 의미를 갖습니다.

제공자 B가 프롬프트(prompt)를 동일한 방식으로 해석할까요? 도구 스키마(tool schema)를 동일한 방식으로 직렬화(serialize)할까요? 캐시 지침(cache directives)을 동일한 방식으로 준수할까요? 토큰(tokens)을 동일한 방식으로 스트리밍(stream)할까요? 오류를 동일한 방식으로 노출할까요? 토큰을 동일한 방식으로 계산할까요? 타임아웃(timeouts)을 동일한 방식으로 준수할까요? 그리고 당신의 시스템이 실제로 이해할 수 있는 방식으로 실패할까요?

대부분의 경우, 대답은 '아니오'입니다.

그리고 바로 이 지점에서 현재의 AI 산업은 자신들이 가장 좋아하는 마술을 계속 부리고 있습니다. 매우 불안정한 무언가를 가져와서 익숙한 API 형태로 감싸고, 반짝이는 호환성 라벨을 붙여주면, 갑자기 모두가 마치 표준(standard)이 있는 것처럼 행동합니다. 우리에게는 표준이 없습니다. 우리에겐 코스튬(costume)이 있을 뿐입니다!

유명한 많은 “OpenAI 호환(OpenAI compatible)” API들은 거짓말을 하고 있으며, 알려진 이름 뒤에 표준의 부재를 숨기고 있습니다. 실제로 그것들은 가장 얕은 경로에서만 호환될 뿐입니다. 기본적인 채팅 요청을 보내고 텍스트를 돌려받을 수는 있습니다. 환상적이죠. 데모는 작동합니다. 슬라이드는 멋져 보입니다. 아키텍처 다이어그램의 박스 수도 줄어듭니다. 하지만 “안녕 모델아, 이 단락을 요약해줘”를 넘어서는 순간, 모든 것들이 균열되기 시작합니다.

도구 호출(Tool calling). 구조화된 출력(Structured output). JSON 강제(JSON enforcement). 프롬프트 캐싱(Prompt caching). 스트리밍(Streaming). 재시도 동작(Retry behavior). 사용량 계정(Usage accounting). 모델 별칭(Model aliases). 안전 오버레이(Safety overlays). 지역 라우팅(Regional routing). 타임아웃 의미론(Timeout semantics). 오류 객체(Error objects). 응답 엔벨로프(Response envelopes). 컨텍스트 처리(Context handling). 제공자별 파라미터(Provider-specific parameters). 이 모든 지루한 부분들 말입니다. 다시 말해, 당신의 AI 시스템이 프로덕션에서 살아남을지를 결정하는 모든 부분들입니다.

우리가 알다시피, 데모가 작동하는 이유는 데모가 시스템이 아니기 때문입니다

데모는 보통 해피 패스 (happy path)입니다. 단 한 명의 사용자, 하나의 모델, 하나의 제공자 (provider), 하나의 프롬프트 (prompt), 하나의 작업 (task). 캐시 (cache)도 없을 수 있고, 동시성 (concurrency)도 없을 수 있습니다. 구조화된 출력 (structured output)도 없을 수 있고, 감사 추적 (audit trail)도 없을 수 있습니다. 폴백 (fallback)도 없을 수 있고, 고객별 버전 고정 (version pinning)도 없을 수 있습니다. 컴플라이언스 (compliance) 요구사항도 없을 수 있고, 비용 압박도 없을 수 있습니다. 여러 개의 병렬 스트림이 연결되었다가 2분 동안 아무것도 생성하지 못하는 사고 (incident)도 없을 수 있습니다.

그런 세상에서 AI는 마법처럼 느껴집니다. 하지만 프로덕션 (production) 환경에서 AI는 마치 분산 시스템 (distributed systems)이 법적 모호성 및 확률적 동작 (probabilistic behavior)과 사이에서 아이를 낳기로 결정한 것처럼 느껴집니다.

당신은 단순히 모델을 통합하는 것이 아닙니다. 당신은 런타임 (runtime)을 통합하는 것입니다. 그리고 그 런타임은 대개 충분히 명확하게 명시되지 않습니다. 이것이 사람들이 계속해서 놓치고 있는 부분입니다.

모델이 전체 제품은 아닙니다. 제공자의 서빙 스택 (serving stack)이 제품의 일부입니다. SDK가 제품의 일부입니다. 직렬화 계층 (serialization layer)이 제품의 일부입니다. 캐시 구현 (cache implementation)이 제품의 일부입니다. 안전 래퍼 (safety wrapper)가 제품의 일부입니다. 지역 라우팅 전략 (regional routing strategy)이 제품의 일부입니다.

그래서 누군가 "같은 모델입니다"라고 말할 때, 저는 점점 더 다음과 같이 듣게 됩니다: "우리는 모델 주변의 구성 요소들을 측정하지 않았습니다."

동일한 가중치 (weights)가 동일한 동작을 의미하지는 않습니다. 동일한 모델 제품군 (model family)이 동일한 프로덕션 계약 (production contract)을 의미하지도 않습니다. 동일한 엔드포인트 형태 (endpoint shape)가 동일한 시스템을 의미하지도 않습니다.

같은 모델, 다른 현실

제가 본 가장 강력한 사례 중 하나는 실제 프로덕션과 유사한 워크플로우 (workflows)에서 동일한 모델 제품군을 사용하여 제공자 A와 제공자 B를 직접 비교한 것이었습니다. 헤드라인은 단순해 보였습니다: 동일한 모델 제품군, 다른 제공자 경로. 하지만 결과는 단순하지 않았습니다.

워크플로우 1 (Workflow 1)에서 품질 저하 (quality regression)는 통계적으로 유의미했습니다. 제공자 A의 평균 점수는 0.716이었습니다. 제공자 B의 평균 점수는 0.497이었습니다. p-값 (p-value)은 0.0001 미만이었으며, 중간 정도의 효과 크기 (effect size)를 보였습니다. 이것은 "약간의 노이즈"가 아닙니다. 이것은 마이그레이션 (migration)을 중단시켜야 할 정도의 차이입니다.

흥미로운 점은 모든 워크플로 (workflow)가 퇴보한 것은 아니라는 사실입니다. 워크플로 2와 워크플로 3에서는 결과가 기본적으로 괜찮았습니다.

좋습니다. 이는 결과의 신뢰성을 떨어뜨리는 것이 아니라 오히려 높여줍니다. 실제 제공업체 (provider) 마이그레이션은 모든 곳에서 실패하지 않기 때문입니다. 특정 워크플로, 특정 프롬프트 (prompt), 특정 스키마 경로 (schema path), 특정 흐름 (flow), 특정 에지 케이스 (edge case)에서 실패합니다. 하나의 핵심적인 워크플로가 조용히 악화되는 동안 평균값은 수용 가능한 수준으로 보일 수 있습니다.

이것이 바로 “몇 개의 프롬프트를 수동으로 테스트해 봤는데 괜찮아 보였다”라는 말이 엔지니어링이 아닌 이유입니다. 그것은 curl 명령어를 사용하는 연극에 불과합니다.

제공업체를 교체하고 싶다면, 재현 트레이스 (replay traces)가 필요합니다. 평가 (evals)가 필요합니다. 워크플로별 점수가 필요합니다. 통계적 비교가 필요합니다. 모델이 여전히 유창한 기업용 영어를 구사하는지 여부뿐만 아니라, 동작이 어디에서 변했는지를 알아야 합니다.

비용은 단순히 표시 가격만이 아닙니다

동일한 비교를 통해 대량 워크플로에서 약 2배의 비용 프리미엄이 발생함을 확인했습니다. 얼핏 보면 제공업체의 가격 책정 (pricing)을 탓할 수도 있습니다. 하지만 역산 결과, 더 지루하면서도 더 위험한 원인이 지목되었습니다. 바로 프롬프트 캐싱 (prompt caching)입니다.

제공업체 A (Provider A)의 경우, 암시된 토큰 볼륨이 보고된 토큰보다 60~67% 낮았습니다. 이것이 캐시 시그니처 (cache signature)입니다. 구조는 여전히 전송하고 있지만, 제공업체가 캐싱된 프롬프트 블록을 재사용하기 때문에 매번 전체 입력 비용을 지불하지 않는 것입니다.

제공업체 B (Provider B)의 경우, 하나의 대량 워크플로 경로에서 차이가 정확히 0%로 나타났습니다. 캐시가 꺼져 있거나 항상 누락된 상태였습니다. 다른 경로들은 부분적인 캐시 동작을 보였는데, 한 사례에서는 약 14~21%, 다른 사례에서는 약 33%였습니다.

동일한 모델 제품군 (model family)임에도 불구하고, 캐시의 현실은 다릅니다. 청구서도 다릅니다. 바로 이 지점에서

캐싱은 단순한 장식이 아니기 때문입니다. 대규모 AI 시스템에서 캐싱은 경제적 아키텍처 (economic architecture)의 일부입니다. 캐시 시맨틱 (cache semantics)이 변하면 단위 경제성 (unit economics)이 변합니다. 지역적 라우팅 (regional routing)이 캐시 미스 (cache miss)를 유발하면 비용 모델이 변합니다. 만약 한 제공업체가 다른 제공업체와 다르게 캐시 지시어 (cache directives)를 준수한다면, 개별 요청은 여전히 "작동"하고 있음에도 불구하고 프로덕션 청구서가 달라집니다.

이것은 최악의 종류의 실패입니다. 성공적인 실패 말입니다. 예외도 없고, 스택 트레이스 (stack trace)도 없으며, 비명을 지르는 서비스도 없습니다. 그저 추상화가 가짜였다고 말해주는 조용한 인보이스 (invoice)가 있을 뿐입니다.

교차 지역 캐시 (Cross-region cache)는 아름답고 작은 함정입니다

교차 지역 추론 (Cross-region inference)은 견고하게 들립니다. 더 많은 지역, 더 높은 가용성, 더 높은 회복 탄력성(resilience). 하지만 캐시 동작을 살펴보면 이야기가 달라집니다.

Region A에서 처리된 요청은 Region A에 캐시를 씁니다. 다음 요청은 Region B로 라우팅될 수 있습니다. Region B에는 해당 캐시가 없습니다. 따라서 미스가 발생하고 다시 캐시를 씁니다. 그 후 용량과 라우팅에 따라 또 다른 호출이 다시 Region A로 가거나 다른 곳으로 라우팅될 수 있습니다.

이것은 깔끔한 "이중 지불" 상황이 아닙니다. 개념적으로 더 나쁩니다. 저렴한 캐시 읽기 (cache reads)를 통해 비용을 안정적으로 분할 상환(amortizing)하지 못한 채, 캐시 쓰기 프리미엄을 계속 지불하게 됩니다. 이것이 바로 캐싱을 올바르게 설정했다고 생각하면서도 측정된 히트율 (hit rate)이 0%로 끝나는 방식입니다.

다시 말하지만, 외부에서 보기에는 모든 것이 호환되는 것처럼 보입니다. API는 요청을 수락합니다. 모델은 응답합니다. 통합은 작동합니다. 서빙 레이어 (serving layer)가 변했기 때문에 경제성이 달라졌다는 점만 제외하고 말입니다.

이것이 바로 AI 프로덕션 작업이 프롬프트 (prompts)에 관한 것이 아니라 계약 (contracts)에 관한 것이 되어가는 이유입니다. 정확히 무엇이 보장됩니까? 무엇이 고정(pinned)되어 있습니까? 무엇이 지역적(regional)입니까? 무엇이 캐시됩니까? 무엇이 카운트됩니까? 무엇이 재현(replayable) 가능합니까? 무엇이 안정적입니까?

만약 답변이 "저희를 믿으세요, 호환됩니다"라면, 저의 엔지니어링적 해석은 간단합니다: 계약을 찾을 수 없음(no contract found).

신뢰성 (Reliability) 또한 이식 가능하지 않습니다

또 다른 프로덕션 스타일의 장애 사례: 동시성 (concurrency) 상황에서 여러 개의 병렬 스트림 (parallel streams)이 연결된 후, 약 2분 동안 아무것도 생성하지 않았습니다. 토큰도 없었고, 유용한 에러도 없었습니다. 그저 기다리기만 했습니다.

가장 가능성 있는 해석은 용량 (capacity) 문제나 스로틀링 큐잉 (throttle queueing)이었습니다. 제공업체 (provider)가 깔끔한 스로틀링 (throttling) 응답을 반환하는 대신 요청을 붙잡고 있었을 수 있습니다. 엔드포인트 (endpoint)에 따라, 어떤 경로는 진행 중인 작업 (in-flight work)을 큐에 쌓는 반면, 다른 경로는 명확한 속도 제한 (rate-limit) 에러를 던질 수도 있습니다.

이러한 차이는 매우 중요합니다. 명확한 속도 제한 (rate-limit) 에러는 보기 흉하지만 유용합니다. 그 에러에 대응할 수 있기 때문입니다. 백오프 (backoff)를 적용하여 재시도할 수 있고, 폴백 (fallback)을 트리거할 수 있으며, 시스템을 보호할 수 있습니다. 하지만 연결된 스트림이 2분 동안 아무것도 생성하지 않는 것은 차원이 다른 실패입니다. 시스템이 기다릴 수 있을 만큼 살아있으면서도, 동시에 무용지물일 만큼 죽어있는 상태인 것입니다.

네트워크 계층 (network layer)이 연관되었을 것이라는 경쟁 가설도 있었습니다. 게이트웨이 (gateway) 동작, 프라이빗 엔드포인트 (private endpoints), 로드 밸런서 (load balancers), 유휴 타임아웃 (idle timeouts), 스트리밍 연결 끊김 (streaming connection drops), 또는 용량 (capacity) 에러 등이 모두 겹치는 증상을 만들어낼 수 있습니다.

따라서 올바른 대응은 "제공업체가 형편없다"가 아니었습니다. 올바른 대응은 다음과 같았습니다: 시스템이 멈춰 있는 시간 동안 런타임 메트릭 (runtime metrics)을 조사하십시오. 스로틀링 카운터 (throttle counters)를 확인하십시오. 서버 에러 카운터 (server error counters)를 확인하십시오. 네트워크 타임아웃 (network timeouts)을 확인하십시오. 연결 수명 (connection lifetime)을 확인하십시오. 요청이 모델 런타임 (model runtime)에 도달하기는 했는지 확인하십시오.

이것이 실제 프로덕션 AI의 모습입니다. 프롬프트 마법 (prompt magic)이 아닙니다. 데모 영상도 아닙니다. "보세요, 저는 20분 만에 에이전트 (agent)를 만들었습니다"와 같은 것도 아닙니다. 0개의 토큰이 생성되며 2분간 멈추는 현상이 모델 용량 (model capacity), 런타임 큐잉 (runtime queueing), 네트워크 인프라 (network infrastructure), 스트리밍 시맨틱스 (streaming semantics), 재시도 정책 (retry policy), 또는 여러분 자신의 동시성 설계 (concurrency design) 때문인지 디버깅하는 과정, 그것이 실제 모습입니다.

매우 화려하군요. 누군가 출시 영상에 이 내용을 꼭 넣어야겠습니다.

구조화된 출력 (Structured output)은 표준 출력 (standard output)이 아닙니다

다음으로는 SDK 직렬화 (serialization) 문제가 있습니다. 동일한 모델, 동일한 애플리케이션 수준의 입력임에도 불구하고 토큰 수가 다릅니다.

한 비교 사례에 따르면, 제공업체 B (Provider B)는 약 10,473개의 입력 토큰을 사용한 반면, 제공업체 A (Provider A)는 약 10,019개를 사용했습니다. 이는 454토큰의 차이로, 대략 4.5퍼센트에 달합니다.

그 실마리는 구조화된 출력 (structured output)에 있었습니다. 한 제공업체 경로에서는 프롬프트에 도구 스키마 (tool schema)를 주입함으로써 구조화된 출력을 구현했습니다. 다른 경로에서는 다르게 처리되었습니다. 애플리케이션 레벨에서 페이로드 (payload)를 바이트 단위로 동일하게 만들었음에도 불구하고, 남은 구조적 차이는 제공업체별 캐시 지시문 직렬화 (cache directive serialization)에서 발생했습니다.

이는 왜 API 호환성만으로는 충분하지 않은지를 보여주는 완벽한 사례입니다. 당신의 프롬프트는 동일할지 모릅니다. 하지만 제공업체의 프롬프트는 그렇지 않습니다.

모델이 실제로 보는 대상에는 숨겨진 스캐폴딩 (scaffolding), 주입된 스키마, 번역된 파라미터, 안전 래퍼 (safety wrappers), 도구 정의, 응답 제약 조건, 또는 제공업체별 엔벨로프 (envelopes)가 포함될 수 있습니다. 그러고 나서 우리는 평가 (eval) 점수를 비교하며 동일한 것을 테스트했다고 가정합니다.

우리가 정말 그랬을까요? 그럴 수도 있고, 아닐 수도 있습니다. 그리고 만약 우리가 그 질문에 확신을 가지고 답할 수 없다면, 우리는 모델의 품질을 측정하고 있는 것이 아닙니다. 우리는 모델의 동작, SDK 번역, 제공업체 스캐폴딩, 그리고 우리 자신의 가정이 뒤섞인 것을 측정하고 있는 것입니다.

매우 과학적이고, 매우 기업적이며, 매우 "빠르게 움직이다가 실수로 서로 다른 시스템을 비교하는" 방식입니다.

폴백 (Fallback)이 장애가 될 수 있습니다

제공업체 간 폴백 (Cross-provider fallback)은 책임감 있게 들립니다. 실제로 책임감 있는 행동일 수 있습니다. 하지만 공짜는 아닙니다.

한 구체적인 사례는 제공업체 C의 프리뷰 모델과 관련이 있었습니다. 해당 모델은 간헐적인 멈춤 현상이 발생했고, 반복된 타임아웃 이후 재시도 소진 (retry-exhaustion) 오류를 생성했으며, 입력 토큰과 출력 토큰이 모두 0으로 보고되었습니다. 즉, 모델이 실제로 시작조차 되지 않은 것입니다.

재시도 예산 (retry budget)이 몇 분 동안 소진되었습니다. 그 후 실패율 가드 (failure-rate guard)가 전체 작업을 중단시켰습니다. 해결책은 폴백 모델을 추가하는 것이었습니다. 좋은 해결책입니다. 하지만 교훈은 더 큽니다.

폴백 경로에는 자체적인 엔지니어링이 필요합니다. 자체적인 타임아웃 예산이 필요합니다. 자체적인 비용 가정이 필요합니다. 자체적인 품질 기대치가 필요합니다. 그리고 존재해야 할 자체적인 이유가 필요합니다.

유용한 규칙: 기본적으로 폴백 시에는 규모를 키우십시오 (scale up). 폴백이 드물게 실행된다면, 몇 센트를 아끼는 것보다 사용 가능한 답변을 얻는 것이 더 중요합니다. 요청이 모델 제한을 초과하여 기본 모델이 실패했을 때만 규모를 줄이십시오 (scale down).

하지만 만약 당신의 폴백 (fallback)이 기본 모델과 동일하게 소진된 타임아웃 예산 (timeout budget)을 상속받는다면, 축하합니다. 당신은 폴백을 구축한 것이 아닙니다. 그저 장식용 두 번째 실패를 구축했을 뿐입니다.

폴백 (Fallback)은 백업 모델이 아닙니다. 폴백 (Fallback)은 두 번째 프로덕션 경로 (production path)입니다.

파라미터 이름조차 이식 가능하지 않습니다

작은 예시이지만 매우 시사하는 바가 큽니다. 한 모델의 "호환 가능한" API가 추론 (reasoning) 관련 파라미터 주변에서 다르게 동작했습니다. 해결 방법은 안전한 기본값 (safe default)을 강제하는 것이었습니다.

그것은 합리적입니다. 하지만 진짜 이식성 (portability) 리스크는 값 (value)뿐만이 아닙니다. 그것은 파라미터 계약 (parameter contract) 그 자체입니다.

다른 제공업체는 그것을 다른 이름으로 부를 수도 있습니다. 다른 곳은 그것을 무시할 수도 있습니다. 다른 곳은 그것을 거부할 수도 있습니다. 다른 곳은 다른 기본값을 적용할 수도 있습니다. 다른 곳은 일부 모델에서만 그것을 지원할 수도 있습니다. 다른 곳은 프리뷰 (preview) 단계에서 지원하다가 아주 적은 예고만으로 나중에 제거할 수도 있습니다.

이 지점에서 "호환 가능한 API"라는 말은 모든 자동차가 스티어링 휠 호환이 된다고 말하는 것처럼 느껴지기 시작합니다. 기술적으로는 사실입니다. 하지만 그것을 당신의 안전 근거로 사용하지는 마십시오.

프리뷰 (Preview)는 프로덕션 (production)이 아닙니다

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0