지난 글에서 컨텍스트를 항목별 예산으로 나눠 봤다. 그러면 자연스럽게 드는 생각이 있다 — 창이 100만 토큰이면 이 배분 고민을 안 해도 되는 것 아닌가. 문서를 통째로 넣고 검색 파이프라인을 걷어내면 시스템이 훨씬 단순해진다. 실제로 이 방향으로 갔다가 되돌아온 팀이 많다. 창에 들어가는 것과 그 안의 정보가 제대로 쓰이는 것이 같은 말이 아니기 때문이다.
위치에 따라 다르게 읽힌다
정답이 담긴 한 조각을 긴 컨텍스트의 여러 위치에 옮겨 넣으면서 정확도를 재면 일관된 모양이 나온다. 앞과 뒤는 잘 보고 가운데가 약하다.
이 모양이 실무에 주는 함의는 둘이다.
첫째, 긴 컨텍스트의 성능은 평균으로 말할 수 없다. "이 모델은 20만 토큰에서 정확도 90%"라는 숫자는 정답이 어디 있었는지에 따라 크게 달라진다. 자기 데이터로 잴 때도 정답 위치를 앞·중간·뒤로 흩어 놓고 각각 재야 의미가 있다.
둘째, 순서가 통제 가능한 변수라면 반드시 통제해야 한다. 검색 결과 열 개를 컨텍스트에 넣을 때 관련도 순으로 그냥 나열하면 상위 문서 몇 개가 가운데에 놓인다. 가장 관련 높은 것을 맨 앞과 맨 뒤에 배치하고 낮은 것을 가운데로 미는 배치가 더 안전하다.
찾기는 되는데 엮기가 안 된다
긴 컨텍스트 평가에서 자주 인용되는 것이 "바늘 찾기" 류의 시험이다. 긴 글 어딘가에 특이한 문장 하나를 심어 놓고 찾아내게 하는 것인데, 요즘 모델들은 여기서 아주 잘한다. 그래서 이 점수만 보면 긴 컨텍스트가 완전히 해결된 것처럼 보인다.
문제는 실제 작업이 대개 바늘 하나 찾기가 아니라는 것이다. 계약서 세 곳에 흩어진 조항을 모아 모순을 찾는다든지, 회의록 스무 건에서 한 결정이 어떻게 바뀌어 왔는지 추적한다든지 하는 일은 여러 조각을 동시에 붙들고 관계를 따져야 한다. 이 종류의 작업에서는 컨텍스트가 길어질수록 성능이 훨씬 빨리 떨어진다.
| 작업 유형 | 긴 컨텍스트 적합도 | 이유 |
|---|---|---|
| 특정 사실 하나 찾기 | 높다 | 한 지점만 보면 된다 |
| 전체 요약 | 높다 | 세부 누락이 치명적이지 않다 |
| 흩어진 근거 3개 이상 종합 | 낮다 | 동시에 붙들어야 할 것이 많다 |
| 전체를 훑는 집계·카운트 | 낮다 | 하나만 놓쳐도 답이 틀린다 |
| 미묘한 모순·누락 찾기 | 낮다 | 없는 것을 찾는 일이라 더 어렵다 |
아래 세 줄에 해당하는 작업이라면 컨텍스트를 키우는 대신 작업을 쪼개는 쪽이 낫다. 문서를 구간별로 처리해 중간 결과를 만들고, 그 중간 결과들만 모아 마지막 판단을 하는 식이다. 이러면 각 호출의 컨텍스트가 짧아져 정확도가 올라가고, 구간별 처리는 병렬로 돌릴 수 있어 지연도 줄어든다.
비용과 지연은 길이에 그냥 비례하지 않는다
토큰당 단가만 보면 입력이 열 배면 비용도 열 배다. 여기까지는 예상대로다. 문제는 지연이다.
어텐션 계산량은 시퀀스 길이의 제곱에 비례한다.
실제 서빙에서는 여러 최적화가 들어가 체감 곡선이 이보다 완만하지만, 첫 토큰이 나오기까지의 시간(프리필 구간)은 입력 길이에 확실히 민감하다. 20만 토큰을 넣으면 첫 글자가 나오기까지 수 초가 걸리는 일이 드물지 않다. 사용자가 화면을 보고 기다리는 제품이라면 이 하나만으로 설계가 갈린다.
여기에 더해 KV 캐시가 GPU 메모리를 길이에 비례해 먹는다. 자체 서빙을 한다면 긴 컨텍스트 요청 하나가 동시에 처리 가능한 요청 수를 크게 깎는다. 즉 긴 컨텍스트의 진짜 비용은 그 요청의 청구서가 아니라 시스템 전체의 처리량 감소로 나타난다.
그러면 검색은 필요 없는가
정리하면 이렇게 갈린다.
긴 컨텍스트가 나은 경우 — 대상 문서가 애초에 몇 개로 정해져 있고(계약서 한 건, 코드베이스 한 모듈), 전체 맥락이 답에 영향을 주며, 매번 다른 부분이 필요해 미리 나눠 두기 어려운 작업. 이런 데서는 검색 파이프라인을 유지하는 비용이 이득보다 크다.
검색이 나은 경우 — 후보 문서가 수천 건 이상이거나, 자주 갱신되거나, 사용자마다 접근 권한이 다르거나, 응답 속도가 중요한 경우. 특히 권한이 걸리면 선택의 여지가 없다. 전부 넣을 수가 없으니 고르는 단계가 반드시 있어야 한다.
둘을 섞는 경우가 실은 가장 흔하다. 검색으로 후보를 문서 단위까지 좁힌 다음, 그 문서는 잘게 자르지 않고 통째로 넣는다. 예전에는 청크를 잘게 쪼개 조각만 넣어야 했지만, 창이 커진 덕분에 "관련 문서 세 건 전문"이 들어간다. 조각으로 자를 때 생기던 맥락 손실이 사라지면서 검색의 선별 능력은 그대로 쓴다.
def build_evidence(query, k_docs=3):
hits = search(query, top_k=20) # 조각 단위로 넓게 찾고
doc_ids = dedup([h.doc_id for h in hits])[:k_docs] # 문서 단위로 좁힌 뒤
docs = [load_full_document(d) for d in doc_ids]
# 가장 관련 높은 문서를 앞뒤로, 낮은 것을 가운데로
return reorder_edges(docs)
def reorder_edges(docs):
ordered = []
for i, doc in enumerate(docs):
ordered.insert(len(ordered) // 2 if i % 2 else 0, doc)
return ordered
자기 데이터로 재는 법
벤더가 발표하는 긴 컨텍스트 점수는 참고 이상이 되기 어렵다. 문서의 성격과 질문의 종류가 다르면 곡선이 달라진다. 최소한의 자체 측정은 이렇게 짠다.
- 실제 문서로 컨텍스트 길이를 4단계(예: 8K·32K·128K·전체)로 만든다.
- 각 길이에서 정답 위치를 앞·중간·뒤 세 곳으로 흩어 각각 잰다.
- 질문은 두 종류를 섞는다 — 사실 하나 찾기, 근거 셋 이상 종합.
- 정확도와 함께 첫 토큰까지의 시간을 같이 기록한다.
이 표가 나오면 "우리 시스템에서 컨텍스트를 어디까지 늘려도 되는가"에 숫자로 답할 수 있다. 대부분의 경우 그 값은 모델이 광고하는 창 크기보다 한참 작고, 그 사실을 알고 설계하는 것과 모르고 설계하는 것의 차이가 크다.
읽어주셔서 감사합니다. 😊

