LLM 비용 최적화는 왜 모델 선택이 아니라 서비스 티어 설계일까
이 LLM 호출은 사용자가 기다리는 작업인가, 오늘 안에 끝나면 되는 작업인가, 실패해도 재시도할 수 있는 작업인가?
LLM 비용 최적화는 왜 모델 선택이 아니라 서비스 티어 설계일까
- 카테고리: ai_dev
- 예상 읽기 시간: 10분
- 오늘의 질문: 이 LLM 호출은 사용자가 기다리는 작업인가, 오늘 안에 끝나면 되는 작업인가, 실패해도 재시도할 수 있는 작업인가?
- 핵심 출처:
- Flex processing - 게시일 미표기, 확인일 2026-07-13
- Priority processing - 게시일 미표기, 확인일 2026-07-13
- Batch API - 게시일 미표기, 확인일 2026-07-13
- Batch processing - Claude Platform Docs - 게시일 미표기, 확인일 2026-07-13
- Batch API - Gemini API - 게시일 미표기, 확인일 2026-07-13
1. 왜 지금 봐야 하나
LLM 비용을 줄인다고 하면 보통 먼저 모델을 바꾸려 한다. 큰 모델에서 작은 모델로 내리거나, temperature를 낮추거나, 출력 토큰을 줄이는 식이다. 물론 중요하다. 하지만 실제 서비스에서는 같은 모델을 쓰더라도 언제 처리해도 되는가에 따라 비용과 지연의 답이 달라진다.
최근 주요 LLM API 문서를 보면 이 방향이 뚜렷하다. OpenAI는 service_tier로 Priority와 Flex를 제공하고, 별도의 Batch API를 통해 비동기 작업을 더 낮은 비용과 24시간 처리 창으로 보낸다. Anthropic의 Message Batches API도 대량 Messages 요청을 비동기로 처리하며 비용을 50% 줄이고, 대부분의 배치가 1시간 미만에 끝나지만 24시간 만료와 결과 보관 기간 같은 운영 조건을 명시한다. Gemini Batch API도 대량 요청을 50% 표준 비용으로 비동기 처리하고, 24시간 목표 처리 시간, inline 요청과 JSONL 파일 입력, 결과 매핑, webhook 같은 운영 방식을 제공한다.
핵심은 “배치가 싸다”가 아니다. LLM 호출도 데이터베이스 쿼리나 작업 큐처럼 서비스 등급을 나눠야 한다는 점이다. 사용자가 화면에서 기다리는 추천 문구와, 밤새 돌릴 평가 데이터셋 채점과, 실패하면 나중에 다시 시도해도 되는 문서 태깅을 같은 동기 API 경로에 태우면 비용·지연·장애가 한 덩어리로 엉킨다.
오늘 글은 모델 선택보다 한 단계 위에서, LLM 작업을 Priority, Standard, Flex, Batch로 분류하는 설계 원리를 정리한다.
2. 핵심 개념
서비스 티어 설계의 기준은 모델 이름이 아니라 시간 계약이다. LLM 호출을 네 가지 질문으로 나눠보자.
첫째, 사용자가 지금 기다리는가? 사용자가 버튼을 누르고 화면에서 답을 기다린다면 tail latency가 곧 제품 품질이다. 여기서는 빠르고 일관된 지연이 중요하다. OpenAI Priority processing은 Standard보다 낮고 일관된 latency가 필요한 high-value user-facing application에 적합하다고 설명한다. 반대로 data processing, evaluations, erratic traffic에는 쓰지 말라고 한다. 즉 Priority는 “비싼 모델을 쓰는 옵션”이 아니라 “사용자 대기 시간을 줄이는 옵션”이다.
둘째, 오늘 안에 끝나면 되는가? 평가셋 채점, 로그 분류, 문서 요약, 데이터 정제처럼 사용자가 실시간으로 기다리지 않는 작업은 Batch가 어울린다. OpenAI Batch API는 비동기 요청 묶음을 50% 낮은 비용, 별도 rate limit pool, 24시간 turnaround로 처리한다고 설명한다. Anthropic과 Gemini도 batch를 대량·비긴급 작업에 맞는 경로로 설명한다. 여기서 중요한 것은 결과가 즉시 오지 않는 대신, 작업 ID, 상태 조회, 결과 파일, 실패 항목 재처리 같은 운영 절차가 필요하다는 점이다.
셋째, 늦어져도 되지만 동기 호출 모양은 유지하고 싶은가? OpenAI Flex processing은 Responses 또는 Chat Completions 요청을 더 낮은 비용으로 처리하되, 느린 응답과 occasional resource unavailability를 받아들이는 방식이다. 문서에서는 non-production, lower priority tasks, model evaluations, data enrichment, asynchronous workloads에 적합하다고 한다. Flex는 Batch처럼 파일을 올려 결과 파일을 받는 모델은 아니지만, timeout 증가, 429 Resource Unavailable 처리, exponential backoff 같은 재시도 설계가 필요하다.
넷째, 실패하거나 순서가 바뀌어도 복구할 수 있는가? Batch 문서들이 반복해서 강조하는 것이 custom_id 또는 사용자 정의 key다. OpenAI Batch 결과는 입력 순서와 출력 순서가 다를 수 있으므로 custom_id로 매핑해야 한다. Anthropic도 batch results may not match input order라고 설명하며 custom_id 사용을 요구한다. Gemini도 JSONL 요청에 사용자 정의 key를 넣고 응답에서 결과를 연결한다. 비동기 LLM 작업은 “요청을 보냈다”가 아니라 “나중에 돌아온 결과를 원래 업무 레코드와 정확히 연결한다”가 핵심이다.
3. 최신 이슈와 연결
문서들이 보여주는 최근 흐름은 LLM API가 단순한 /chat 호출에서 스케줄링 가능한 컴퓨트 자원으로 바뀌고 있다는 점이다.
OpenAI의 Priority/Flex/Batch는 같은 모델 호출도 처리 등급을 달리할 수 있음을 보여준다. Priority는 빠르고 일관된 latency를 사지만, 트래픽이 너무 급격히 늘면 일부 Priority 요청이 Standard로 downgrade될 수 있고 응답의 service_tier로 확인해야 한다. Flex는 낮은 비용을 얻지만 느린 처리와 resource unavailable 가능성을 받아들인다. Batch는 24시간 처리 창과 결과 파일 기반 운영을 받아들이는 대신 50% 비용 절감과 별도 처리 풀을 얻는다.
Anthropic Message Batches 문서도 비슷한 교훈을 준다. 각 요청은 독립적으로 처리되고, 실패한 요청 하나가 전체 batch를 망치지 않는다. 하지만 100,000개 요청 또는 256MB 제한, 24시간 만료, 29일 결과 보관, custom_id, 결과 순서 불일치, prompt caching의 best-effort hit rate 같은 조건을 개발자가 이해해야 한다. 즉 Batch는 “싸게 많이 돌리는 버튼”이 아니라 “대량 작업 처리 시스템”이다.
Gemini Batch API는 inline 요청과 파일 입력을 구분한다. 작은 작업은 inline으로, 큰 작업은 JSONL 파일로 제출한다. 결과는 job name으로 상태를 확인하고, webhook으로 완료 이벤트를 받을 수도 있다. 또 structured output, tools, context caching, embeddings batch도 지원한다. 여기서도 핵심은 비동기 작업을 제품 흐름에 어떻게 연결하느냐다.
4. 개발자 관점 해석
AI 기능을 만들 때 가장 위험한 비용 최적화는 “모든 호출을 싼 경로로 보내자”다. 그러면 사용자가 기다리는 작업까지 느려지고, 실패율이 올라가고, 재시도 폭풍이 생길 수 있다. 반대로 가장 흔한 낭비는 “모든 호출을 동기 Standard/Priority로 처리하자”다. 그러면 밤에 돌려도 되는 평가·정제·태깅 작업이 사용자 트래픽과 같은 rate limit, 같은 비용, 같은 장애 경로를 공유한다.
실무적으로는 LLM 호출을 다음처럼 나누는 편이 안전하다.
- Priority: 결제 직전 추천, 고객 상담 중 실시간 답변, 사용자가 명확히 기다리는 고가치 경로. 지연 목표와 fallback UX를 함께 설계한다.
- Standard: 일반적인 사용자 요청. 예측 가능한 비용과 지연이 필요하지만 Priority까지는 아닌 경로.
- Flex: 개발·평가·데이터 보강처럼 느려도 되고, 429 Resource Unavailable이 나와도 backoff나 Standard fallback을 걸 수 있는 경로.
- Batch: eval 채점, 대량 문서 분류, 임베딩 생성, 로그 요약처럼 작업 큐와 결과 수집이 자연스러운 경로.
여기서 설계의 중심은 “API 옵션”이 아니라 “업무 레코드”다. 예를 들어 RAG 답변 품질 eval을 10,000건 돌린다면 각 요청에 eval_case_id를 custom_id로 넣어야 한다. 결과가 순서대로 오지 않아도 원래 케이스에 붙일 수 있어야 하고, 실패한 행만 다시 제출할 수 있어야 한다. 요약 품질이 나쁘면 사람이 검토할 수 있도록 prompt version, model, service tier, input hash, output hash를 함께 남겨야 한다.
또 하나의 함정은 prompt caching과 batch를 “자동 할인”으로 보는 것이다. Anthropic 문서는 batch에서도 prompt caching discount가 stack될 수 있지만, 비동기·동시 처리 특성상 cache hit는 best-effort라고 설명한다. Gemini도 batch 요청에서 cached content를 재사용할 수 있다고 설명한다. OpenAI Flex와 Priority도 prompt caching 할인이 적용될 수 있다고 한다. 하지만 캐시는 프롬프트 prefix가 안정적일 때 의미가 있다. 매 요청마다 system prompt와 긴 컨텍스트 순서가 바뀌면 서비스 티어를 바꿔도 기대한 비용 절감이 나오지 않는다.
5. 내 프로젝트에 적용할 체크포인트
-
LLM 호출 목록을 만든다. 코드에서
responses.create,messages.create,generateContent, embeddings 호출을 찾고 기능명, 사용자 대기 여부, 평균 입력/출력 토큰, 실패 시 영향도를 적는다. -
시간 계약을 붙인다.
p95 3초 안,30초 안,1시간 안,24시간 안처럼 사람이 이해할 수 있는 목표를 적는다. “빠르면 좋다”는 계약이 아니다. -
재시도 가능성을 분류한다. 같은 요청을 다시 보내도 안전한가? write tool 호출이 섞여 있는가? 비용이 두 번 청구되어도 괜찮은가? Batch/Flex로 보낼 작업은 idempotency와 중복 결과 처리 방식을 먼저 정해야 한다.
-
결과 매핑 키를 표준화한다. Batch 작업에는
custom_id/key를 반드시 넣고, 내부 DB의job_id,record_id,prompt_version과 연결한다. 출력 순서를 믿지 않는다. -
부분 실패를 기본값으로 둔다. Batch에서는 일부 요청만 errored/expired/canceled 될 수 있다. 전체 재실행보다 실패 행 재제출이 가능한 구조가 비용과 품질 모두에 유리하다.
-
서비스 티어를 로그에 남긴다. 요청한 tier와 실제 응답의 tier가 다를 수 있다. Priority downgrade나 Flex fallback을 관측하려면 model, tier, latency, token usage, cache hit 관련 정보를 같이 남겨야 한다.
-
보관 기간과 개인정보를 확인한다. 비동기 batch는 입력과 출력이 서버 측에 일정 기간 저장된다. Anthropic은 결과가 29일 동안 제공된다고 설명하고, Gemini는 기본적으로 결과가 6주 동안 다운로드 가능하다고 설명한다. 민감 데이터가 들어가면 삭제·보관 정책을 제품 요구사항과 맞춰야 한다.
6. 오늘 10분 액션
오늘은 코드를 바꾸기보다 표 하나를 만든다.
기능명 | 사용자 대기? | 시간 계약 | 추천 경로 | 재시도 전략 | 결과 매핑 키
채팅 답변 | 예 | p95 5초 | Standard/Priority | 짧은 retry + fallback 문구 | conversation_id
야간 eval | 아니오 | 24시간 | Batch | 실패 행만 재제출 | eval_case_id
문서 태깅 | 아니오 | 1시간~24시간 | Batch 또는 Flex | backoff 후 재시도 | document_id
개발용 데이터 보강 | 아니오 | 느려도 됨 | Flex | 429면 backoff | enrichment_job_id
그리고 현재 프로젝트의 LLM 호출 5개만 이 표에 넣어본다. 만약 모든 행의 추천 경로가 Standard라면, 둘 중 하나다. 정말 사용자 대기형 기능만 있는 제품이거나, 아직 대량·비동기 작업을 같은 길로 보내고 있다는 뜻이다.
7. 더 볼 자료
- OpenAI Flex processing: 낮은 비용과 느린 처리, 429 Resource Unavailable 처리,
service_tier=flex설계를 확인한다. - OpenAI Priority processing: 사용자 대기형 경로에 Priority를 붙일 때 rate limit, downgrade, 실제
service_tier관측을 확인한다. - OpenAI Batch API: 50% 비용 절감, 24시간 completion window,
custom_id, 결과 순서 불일치, error file 흐름을 확인한다. - Anthropic Message Batches: 100,000 request 또는 256MB 제한, 24시간 만료, 29일 결과 보관, prompt caching best-effort를 확인한다.
- Gemini Batch API: inline vs JSONL 파일 입력, webhook, embeddings batch, context caching, 2GB 입력 파일 제한을 확인한다.
중복 회피 메모
로컬 content/generated와 Supabase의 최근 ai_dev 글을 확인했다. 최근 글은 prompt injection trust boundary, Programmatic Tool Calling, RAG citation grounding, agent trace, token counting, tool calling protocol, prompt caching, prefill/decode latency, KV cache quantization을 다뤘다. 이번 글은 모델 내부 최적화나 프롬프트 캐시 반복이 아니라, LLM 호출을 사용자 대기 시간과 재시도 가능성에 따라 Priority/Standard/Flex/Batch로 나누는 서비스 티어·작업 큐 설계에 집중한다.
핵심 출처
로그인하면 이 글을 북마크하고, 나만 보는 한 줄 메모를 남길 수 있어요.
댓글 0
최신순 ▾혹시 이 글을 읽는 동료 개발자가 있다면, GitHub으로 로그인하고 한 줄 흔적을 남겨줘요. (스팸 방지용 로그인이에요)