RAG · 검색증강생성수정 2026-08-07

토큰과 컨텍스트 윈도우 — RAG 비용은 어디서 나오고 무엇을 넣을 것인가

RAG 비용의 실체인 토큰 구조와 컨텍스트 윈도우 예산을 정리하고, 적게 넣어야 한다면 무엇을 넣을지 고르는 MMR 알고리즘까지 이어서 다룬다.

RAG에서 비용이 새는 지점은 대개 둘이다. 대화 히스토리를 자르지 않고 전부 재전송하는 것, 그리고 top-k를 습관적으로 크게 잡는 것. 둘 다 "일단 많이 넣으면 안전하다"는 직관에서 나오는데, 실제로는 비용만 늘고 답변 품질은 오히려 떨어진다.

이 글은 그 직관이 왜 틀렸는지를 토큰 단위에서 설명하고, 적게 넣어야 한다면 무엇을 넣을 것인가라는 다음 질문까지 이어서 답한다. 토큰과 컨텍스트 윈도우의 구조, 한국어가 비싼 구조적 이유, 컨텍스트를 공유 예산으로 보는 관점, 그리고 중복 문서를 걷어내는 MMR 알고리즘을 다룬다.

용어 정리

용어원어
토큰TokenLLM이 텍스트를 처리하는 최소 단위. 과금 단위이자 한계 단위
토큰화Tokenization텍스트를 토큰으로 쪼개는 과정. 토크나이저에 따라 토큰 수가 2배 이상 차이 난다
BPEByte Pair Encoding자주 등장하는 문자 쌍을 반복 병합해 서브워드 사전을 만드는 알고리즘. 현대 LLM 토크나이저의 표준
서브워드Subword단어보다 작은 단위. unhappinessun + happiness
컨텍스트 윈도우Context Window모델이 한 번에 처리할 수 있는 최대 입력+출력 토큰 수
max_tokens모델이 답변으로 생성할 수 있는 최대 출력 토큰 수
입력 토큰Input / Prompt Token모델에 밀어넣는 토큰. RAG는 여기가 폭증하는 구조
출력 토큰Output / Completion Token모델이 생성한 토큰. 단가가 입력의 3배
MMRMax Marginal Relevance관련성과 다양성을 동시에 고려해 결과를 고르는 알고리즘
λ (lambda_mult)Lambda MultiplierMMR에서 관련성 대 다양성의 균형 계수 (0~1)
fetch_kMMR이 후보로 먼저 끌어올 문서 수

네 개 축이 서로를 물고 있다

RAG 운영의 핵심 개념은 독립된 주제가 아니라 하나의 순환이다.

도식을 탭하면 확대해서 볼 수 있습니다
던지는 질문다음 축으로 넘기는 것
비용·한계문서를 몇 개나 넣을 수 있고, 넣으면 얼마인가"적게 넣어야 한다"는 압력
검색 품질적게 넣을 거라면 어떤 문서를 넣어야 하나중복 제거로 확보한 토큰 여유
로컬 LLM 운영토큰당 과금 자체를 없앨 수는 없나고정비 전환 · 데이터 반출 통제
성능·관측무엇이 느리고 무엇이 비싼지 어떻게 아나측정값 → 다시 비용 최적화

이 글은 앞의 두 축을 다룬다. 나머지 두 축은 로컬 LLM 운영비동기와 트레이싱에서 이어진다.

토큰 — 과금 단위이자 한계 단위

토큰은 LLM이 텍스트를 이해·처리하기 위해 분할한 최소 단위이고, 나누는 과정을 토큰화라고 한다. 방식은 셋으로 나뉜다.

방식설명예시토큰 수특징
문자 기반문자 단위로 분할"Hello"["H","e","l","l","o"]많음사전 불필요, 시퀀스가 길어져 비효율
단어 기반단어 단위로 분할"Hello, world!"["Hello",",","world","!"]적음미등록 단어(OOV) 처리 불가, 사전 폭발
서브워드 기반자주 쓰이는 서브워드 기준 분할"unhappiness"["un","happiness"]중간현대 LLM의 표준. OOV 없음 + 시퀀스 짧음

서브워드 방식의 대표 알고리즘이 BPE다. 자주 등장하는 문자 쌍을 반복적으로 병합해 서브워드 사전을 구성한다. "Machine learning"["Ma","chine","learn","ing"]으로 쪼개지는 식이다.

토큰이 중요한 이유는 둘이다. 하나는 문맥 이해 — 토큰화 결과에 따라 모델이 의미를 파악하는 정확도가 달라진다. 다른 하나는 더 직접적이다. 토큰 사용량이 곧 비용이다.

한국어는 왜 더 비싼가

동일한 4턴 대화를 모델별·언어별로 측정한 결과다. 측정 대상은 시스템 프롬프트 1개와 인사말 수준의 사용자·어시스턴트 발화 각 1개다.

모델토크나이저한국어 토큰영어 토큰한/영 배율
gpt-3.5-turbocl100k_base73491.49배
gpt-4-1106-previewcl100k_base1321081.22배
gpt-4oo200k_base53451.18배

행 간 비교는 하지 말 것. gpt-3.5-turbo 73 → gpt-4-1106-preview 132로 뛴 것은 후자가 한국어를 더 비싸게 처리해서가 아니다. 토큰 ID 열을 보면 후자는 <|im_start|>27, 91, 318, 5011, 91, 29처럼 문자 단위로 쪼개져 있다. 측정 도구가 해당 템플릿의 특수토큰을 단일 토큰으로 인식하지 못한 결과다. 의미 있는 비교는 같은 행 안의 한/영 배율과 동일 토크나이저 계열 간 비교뿐이다.

여기서 나오는 결론은 둘이다.

결론근거실무 함의
한국어는 영어보다 토큰을 더 먹는다모든 행에서 한국어 > 영어 (1.18~1.49배)같은 내용이면 한국어 프롬프트가 더 비싸다. 시스템 프롬프트를 영어로 쓰는 관행의 근거
토크나이저 세대 교체가 한국어 비용을 크게 줄였다o200k_base 53 vs cl100k_base 73한국어 서비스는 모델 교체만으로 토큰 수가 줄어든다. 단가 비교 시 토큰 수 변화까지 함께 봐야 한다

원인은 언어의 난이도가 아니라 토크나이저다. BPE 사전이 영어 코퍼스 중심으로 학습됐기 때문에 한국어가 더 잘게 쪼개진다.

컨텍스트 윈도우와 max_tokens는 다르다

항목Context Windowmax_tokens
정의한 번에 처리 가능한 최대 입출력 토큰 수답변으로 생성 가능한 최대 출력 토큰 수
성격모델의 하드 스펙. 바꿀 수 없음호출 시 지정하는 파라미터
포함 범위입력 + 출력 전체출력만
위반 시요청 자체가 에러답변이 중간에 잘림
제약 관계컨텍스트 윈도우를 초과할 수 없음
모델Context Length
GPT-3.5약 16K 토큰
GPT-4 (기본)8,192 토큰
GPT-4 (확장)최대 32,768 토큰
GPT-4 Turbo 계열128,000 토큰

비대칭에 주의한다. 컨텍스트가 128,000 토큰이어도 출력은 최대 4,096 토큰인 모델이 있다. "128K 모델"이라고 해서 128K짜리 답변이 나오지 않는다. 입력은 128K까지 받되 답변은 4K가 상한이다. 긴 문서 요약·번역을 설계할 때 이 비대칭을 모르면 "왜 답변이 자꾸 잘리는가"에 답할 수 없다.

컨텍스트 윈도우는 공유 예산이다

도식을 탭하면 확대해서 볼 수 있습니다
구성요소성격비용 통제 레버
내부 고정 프롬프트 토큰프레임워크가 자동으로 붙임. 눈에 안 보임프레임워크의 기본 프롬프트를 확인·축약
System Prompt매 호출마다 반복 전송짧게. 영어로. 프롬프트 캐싱 활용
User Prompt사용자 입력통제 불가
참고 문서 내용RAG에서 가장 크게 부푸는 영역top-k 축소 · 청크 크기 조정 · MMR로 중복 제거
대화내용 히스토리턴이 쌓일수록 선형 증가윈도우 버퍼 / 요약 메모리로 절단
max_tokens답변 몫으로 예약필요한 만큼만. 과하게 잡으면 입력 여유가 줄어듦

실무에서 비용이 새는 지점이 대개 두 곳이라는 것이 이 표에서 드러난다. 대화 히스토리를 자르지 않고 전부 재전송하면 10턴째에는 1턴 대비 입력 토큰이 몇 배가 되어 있다. 그리고 RAG top-k를 습관적으로 크게 잡으면 k=10과 k=3의 차이가 그대로 매 호출 비용 차이가 된다.

단가에서 읽어야 할 것은 숫자가 아니라 패턴

모델컨텍스트입력 $/1M출력 $/1M출력/입력 배율
GPT-4o128k$5$153배
GPT-4 Turbo128k$10$303배
GPT-3.5 Turbo16k$0.50$1.503배
패턴내용설계 함의
출력이 입력의 3배세 모델 모두 예외 없이 3배답변 길이 제어가 프롬프트 축약보다 비용 효율이 높은 경우가 많다
세대 교체가 반값GPT-4 Turbo $10/$30 → GPT-4o $5/$15성능 동급이면 최신 모델이 싸다. 모델 고정은 비용 부채
티어 간 10~20배GPT-3.5 $0.50 vs GPT-4o $5작업별 모델 라우팅의 근거. 분류·추출은 저가 모델로 충분
컨텍스트와 단가는 별개GPT-3.5는 16k, 나머지는 128k긴 문서 처리는 저가 모델로 내려갈 수 없는 경우가 있다

절대 단가는 시간이 지나면 바뀌지만 이 네 패턴은 유지된다. 특히 출력이 입력의 3배라는 구조는 어디를 먼저 줄일지의 순서를 정해 준다.

토큰 산정 감각

기준
4,096 토큰 ≈ 한글약 1,350자 (글자 수 기준)
4,096 토큰 ≈ 워드 문서약 3장 (1장당 500자 가정)

여기서 파생되는 환산표다.

대상대략적 토큰 수계산 근거
한글 1자약 3토큰4,096 ÷ 1,350 ≈ 3.03
한글 A4 1장(약 1,500자)약 4,500토큰1,500 × 3
영어 1단어약 1.3토큰통용 기준
128K 컨텍스트 = 한글약 42,000자 ≈ A4 28장128,000 ÷ 3

이 환산이 유용한 이유는 컨텍스트 윈도우와 max_tokens의 비대칭을 한 번에 체감시키기 때문이다. 128K 컨텍스트에는 한글 A4 28장이 들어가지만, 답변은 4K — A4 한 장이 상한이다. 넓은 입력 윈도우는 여유지 목표가 아니다.

비용 절감 레버 8가지

#레버어디에 작용효과 크기트레이드오프
1작업별 모델 라우팅단가최대 10~20배라우팅 로직 유지보수. 저가 모델 품질 검증 필요
2출력 길이 제어출력 토큰출력 단가가 3배이므로 체감 큼답변 잘림. 정보 손실
3top-k 축소 + MMR입력 토큰k=10→3이면 문서 영역 70% 감소검색 리콜 하락 위험 → MMR로 완화
4대화 히스토리 절단·요약입력 토큰장기 세션에서 가장 큼이전 맥락 상실
5프롬프트 캐싱입력 토큰고정 프롬프트가 클수록 큼프롬프트 앞부분을 안정적으로 유지해야 함
6시스템 프롬프트 영어화입력 토큰한국어 대비 15~35%가독성·유지보수성 저하
7임베딩 결과 캐싱임베딩 API 호출재색인 비용 제거캐시 무효화 정책 필요
8로컬 LLM 전환변동비 → 고정비볼륨이 클수록 유리인프라·운영 인력 비용 발생

3번이 이 글의 나머지 절반으로 이어진다. top-k를 줄이려면 남는 자리에 무엇을 넣을지 더 잘 골라야 한다.

MMR — 적게 넣는다면 무엇을 넣을 것인가

유사도 top-k만 쓰면 생기는 일

벡터 검색은 기본적으로 쿼리와의 유사도 상위 k개를 반환한다. 문제는 상위 k개가 서로 거의 같은 내용일 수 있다는 점이다.

도식을 탭하면 확대해서 볼 수 있습니다

이 경우 5개 슬롯을 썼지만 실제로 전달된 정보는 1개다. 결과는 셋이다.

결과설명
토큰 낭비같은 내용을 5번 전송하고 5번 과금
정보 손실환불 절차·예외조항·기간 문서가 밀려남
답변 품질 저하모델이 부분적 정보만 보고 답변

발상 — 관련성과 다양성을 함께 본다

레스토랑에서 메뉴를 고르는 상황에 비유하면 이해가 빠르다. 피자를 좋아하지만 피자만 다섯 개 시키고 싶지는 않다. MMR은 **취향(쿼리 관련성)**과 **이미 고른 것과의 차별성(문서 간 다양성)**을 동시에 평가한다.

평가 대상방향
관련성 (Relevance)문서 ↔ 쿼리높을수록 선택
다양성 (Diversity)문서 ↔ 이미 선택된 문서들유사할수록 감점

수식

MMR = arg max      [ λ · Sim1(Di, Q)  −  (1 − λ) · max Sim2(Di, Dj) ]
      Di ∈ R \ S                                    Dj ∈ S
기호의미
Di선택 가능한 문서 (후보)
R검색 결과 집합 (후보 풀)
S이미 선택된 문서 집합
Q사용자 쿼리
Sim1문서와 쿼리 사이의 유사성 함수
Sim2문서 유사성 함수
λ관련성과 다양성 사이의 균형 조정 파라미터

말로 풀면 이렇다. 쿼리와의 관련성 점수에서, 이미 뽑은 문서들 중 가장 비슷한 것과의 유사도를 벌점으로 뺀다. 그 값이 가장 큰 문서를 다음으로 뽑는다.

핵심은 max Sim2평균이 아니라 최댓값이다. 이미 뽑은 문서 중 하나라도 매우 비슷하면 그 순간 벌점이 커진다. 평균을 쓰면 "대부분 다르지만 하나와 완전히 같은" 문서를 걸러내지 못한다.

동작 흐름

도식을 탭하면 확대해서 볼 수 있습니다

주목할 점은 탐욕적(greedy)·순차적 알고리즘이라는 것이다. 한 번에 k개를 고르는 게 아니라 하나씩 뽑으며, 뽑을 때마다 나머지 후보의 점수가 재계산된다. 그래서 순서 자체가 의미를 갖는다.

계산 예시

λ = 0.5, k = 3 조건으로 액션 영화를 고르는 상황이다.

후보Sim11회차 점수2회차 max Sim22회차 점수3회차 max Sim23회차 점수
A. 도심 총격 액션0.950.95 → 선택
B. 도심 총격 액션 (속편)0.930.930.97 (vs A)0.5×0.93 − 0.5×0.97 = −0.020.97−0.02
C. 스파이 액션0.850.850.55 (vs A)0.5×0.85 − 0.5×0.55 = 0.15
D. 고대 전쟁 액션0.800.800.40 (vs A)0.5×0.80 − 0.5×0.40 = 0.20 → 선택0.45 (vs D)0.175 → 선택
E. 액션 코미디0.780.780.50 (vs A)0.140.600.09

유사도만 썼다면 A → B → C가 되어 A와 B가 사실상 같은 영화였을 것이다. B의 2회차 점수가 음수로 떨어지는 것이 MMR의 작동 방식을 그대로 보여준다.

위 수치는 알고리즘 동작을 보이기 위해 구성한 설명용 값이다.

λ 튜닝

λ 값성격동작적합한 상황
1.0순수 관련성벌점 항이 0. 일반 유사도 검색과 동일정답이 한 문서에 확실히 있는 정밀 조회 (사번, 주문번호)
0.7~0.9관련성 우선명백한 중복만 제거RAG 기본 권장 구간. 사실 조회형 QA
0.5균형관련성과 다양성 동등 가중여러 관점을 모아야 하는 요약·비교 질의
0.2~0.4다양성 우선관련성이 다소 낮아도 다른 내용을 끌어옴브레인스토밍, 탐색적 리서치, 추천 다양화
0.0순수 다양성쿼리를 사실상 무시실무 사용 사례 거의 없음

LangChain의 lambda_mult가 이 λ에 해당하며 기본값은 0.5다.

fetch_k가 k와 같으면 MMR은 꺼진 것과 같다

MMR은 후보 풀이 넓어야 다양성을 고를 여지가 생긴다.

파라미터의미권장
k최종 반환 문서 수3~5 (컨텍스트 예산에 맞춰)
fetch_kMMR이 먼저 끌어올 후보 수k의 4~10배 (기본 20)
lambda_multλ0.5 기본 → 사실조회는 0.7~0.9
도식을 탭하면 확대해서 볼 수 있습니다

fetch_kk와 같게 두면 MMR은 사실상 무력화된다. 고를 후보가 없으니 유사도 순서를 거의 그대로 내보낸다. 반대로 fetch_k를 과도하게 키우면 문서 간 유사도 계산이 O(fetch_k × k)로 늘어 검색 지연이 증가한다.

retriever = vectorstore.as_retriever(
    search_type="mmr",
    search_kwargs={
        "k": 4,               # 최종 반환 문서 수
        "fetch_k": 20,        # MMR 후보 풀 크기
        "lambda_mult": 0.7,   # 1.0에 가까울수록 관련성 우선
    },
)

docs = retriever.invoke("환불 정책이 어떻게 되나요?")

언제 MMR을 쓰지 말아야 하나

상황이유대안
정확한 단일 사실 조회다양성이 오히려 정답을 밀어냄λ=1.0 또는 유사도 검색
인덱스에 문서가 애초에 적음후보 풀이 좁아 효과 없음유사도 검색
지연 시간이 극도로 민감문서 간 유사도 계산 오버헤드유사도 검색 + 후처리 중복 제거
이미 리랭커(Cross-Encoder)를 붙임역할이 부분적으로 겹침리랭커 이후 MMR로 중복만 제거

"MMR을 기본으로 켠다"는 선택은 그래서 틀렸다. 질의 유형별로 λ를 다르게 두는 것이 실제 설계다.

토큰당 과금 자체를 없앨 수는 없는지 — 즉 변동비를 고정비로 바꾸는 선택은 로컬 LLM 운영에서 다룬다.