AI는 긴 문서의 중간을 놓칠까 — 4만8천자 문서로 488회 다시 재봤습니다
질문은 짧았습니다.
3층 소회의실 예약은 누가 관리하나요? 이름만 답하세요.
문서에 심은 정답은 김하늘이었습니다. 모델이 내놓은 답은 달랐습니다.
이유진
이유진은 문서 밖에서 지어낸 이름이 아니었습니다. 같은 문서 안에 방해 조항으로 넣어 둔 세 이름 가운데 하나였습니다. 모델은 사실 한 줄을 완전히 잊은 대신, 형식이 비슷한 옆 조항의 값을 가져왔습니다.
긴 문서를 로컬 AI에 넣으려는 분이라면 두 실패를 따로 봐야 합니다. 컨텍스트 크기를 지정하지 않아 입력이 잘리는 문제와, 문서가 들어갔는데도 닮은 조항을 정답으로 고르는 문제입니다.
이번 488회에서는 둘이 서로 다른 모양으로 나타났습니다.
방해 조항이 없으면 160번 모두 찾았습니다
2026년 9월 21일, 자체 작성한 한국어 사내 규정을 2천자, 8천자, 2만4천자, 4만8천자로 만들었습니다. 문서마다 이름, 금액, 일정, 문서 코드 가운데 사실 하나를 심었습니다.
사실의 위치는 문서 맨 앞부터 25%, 50%, 75%, 맨 끝까지 다섯 단계로 옮겼습니다. 각 조합은 두 번씩 실행했습니다.
비교 조건은 세 갈래였습니다.
num_ctx=32768을 명시하고 방해 조항을 넣지 않은 조건- 같은 컨텍스트 설정에서 동일한 형식과 다른 값을 가진 방해 조항 세 개를 넣은 조건
num_ctx옵션을 보내지 않은 기본값 조건
사실 한 줄만 보여 주는 대조군도 따로 돌렸습니다. 전체 기록은 488회입니다. 이 가운데 명시 컨텍스트의 긴 문서 조건이 320회, 옵션 미지정 조건이 160회, 대조군이 8회였습니다.
저는 먼저 방해 조항이 없는 조건을 기준선으로 놓고 결과를 확인했습니다.
방해 조항이 없는 문서는 160회 모두 정답이었습니다. 4만8천자 문서에 사실을 심어도, 위치가 앞·중간·끝 어디든 이번 조건에서는 놓치지 않았습니다.
대조군도 8/8이었습니다. 질문 자체를 이해하지 못했거나 정답 표현이 채점기에 걸리지 않은 문제는 확인되지 않았습니다.
따라서 이번 결과만 놓고 보면 “문서가 길어지면 중간 내용을 반드시 잊는다”라고 말하기 어렵습니다. 길이만 늘린 조건에서는 실패가 없었습니다.
닮은 조항 세 개가 들어오자 실패 모양이 바뀌었습니다
방해 조항에는 정답과 같은 종류의 다른 값을 넣었습니다. 예약 담당자 김하늘을 묻는 문서에는 최민호·이유진·박서준이 다른 조항의 담당자로 등장하는 식입니다. 금액과 일정, 문서 코드도 같은 방식으로 만들었습니다.
방해 조항이 들어간 160회에서는 정답이 122회로 줄었습니다. 오답 38건 가운데 35건은 문서 안의 방해값을 가져온 경우였습니다.
즉, 실패의 대부분은 아무 답이나 만든 장면이 아니었습니다. 정답 조항과 닮은 다른 조항을 찾아 답한 장면이었습니다.
길이별로 보면 차이가 더 분명합니다.
- 2천자에서는 40/40으로 실패가 없었습니다.
- 8천자에서는 34/40이 정답이었습니다.
- 2만4천자에서는 22/40으로 내려갔습니다.
- 4만8천자에서는 26/40이 정답이었습니다.
가장 긴 문서가 가장 낮지는 않았습니다. 이번 실행에서 최저점은 2만4천자의 55%였습니다.
이 숫자는 “2만4천자가 위험 한계”라는 뜻이 아닙니다. 문서 길이와 방해 조항 배치, 네 가지 질문이 결합된 이번 테스트에서 그렇게 나왔다는 뜻입니다. 길이만 보고 안전선을 정하기보다 정답과 비슷한 형태의 조항이 얼마나 섞여 있는지를 함께 확인해야 합니다.
가장 약한 위치도 문서 한가운데가 아니었습니다
방해 조항이 있는 조건만 위치별로 다시 나눴습니다.
사실을 맨 앞에 심었을 때는 32/32가 정답이었습니다. 25% 지점에서는 16/32로 떨어졌고, 그중 14회는 방해값을 답했습니다. 이후에는 50% 지점 24/32, 75% 지점 21/32, 맨 끝 29/32였습니다.
이번 실행에서 가장 약한 곳은 문서 한가운데나 맨 끝이 아니라 앞에서 4분의 1 지점이었습니다.
처음 보여 준 “이유진” 응답은 8천자 문서의 75% 지점에서 나왔습니다. 한 장면의 위치와 전체에서 가장 낮은 위치는 다릅니다. 개별 실패 한 건만 보고 취약 구간을 정하면 이 차이를 놓치게 됩니다.
25% 최저점은 방해 조항을 12%, 42%, 88%에 고정하고 정답 조항만 옮긴 이번 배치에서 나온 결과입니다. 따라서 이 수치는 모든 긴 문서의 공통 위험 구간이 아니라 이번 실험 조건의 위치별 결과로 읽어야 합니다.
여기서 남는 판단은 더 좁습니다.
긴 문서 회상은 끝부분만 확인해서는 안 됩니다. 같은 형식의 조항이 여러 개라면 문서 전체의 후보값을 함께 대조해야 합니다.
num_ctx를 빼자 다른 종류의 실패가 생겼습니다
파일럿에서 먼저 잡힌 실패는 방해값 흡입이 아니었습니다.
4만8천자 문서의 첫 조항에 김하늘을 심고 num_ctx를 지정하지 않았습니다. 모델의 응답은 다음과 같았습니다.
정보에는 3층 소회의실 예약에 대한 언급이 없습니다.
정답은 문서 맨 앞에 있었지만, 모델은 없다고 답했습니다.
이 화면은 14회 파일럿에서 찍힌 배관 점검 장면입니다. 해당 실행 키는 이후 최종 488회 기록에도 포함됐습니다. 별도의 추가 표본으로 더하지 않았습니다.
옵션 미지정 팔 전체에서는 72/160만 정답이었습니다. 모델이 문서에 없다고 답한 기권이 56건, 방해값 흡입이 아닌 다른 오답이 32건이었습니다.
길이가 늘면서 변화가 급했습니다. 2천자는 40/40이었지만 8천자는 16/40, 2만4천자와 4만8천자는 각각 8/40이었습니다.
위치별 결과는 잘린 방향을 더 선명하게 보여 줍니다. 문서 맨 앞의 사실은 8/32만 살아남았고, 맨 끝의 사실은 32/32가 정답이었습니다.
저는 정답률만 보지 않고 API가 기록한 입력 토큰 수도 함께 대조했습니다. 옵션 미지정 팔의 prompt_eval_count는 1342, 1349, 1351, 2051 네 값뿐이었습니다. 문서가 8천자에서 4만8천자로 커져도 기록된 입력은 최대 2051토큰에서 멈췄습니다.
반면 num_ctx=32768을 명시한 팔의 최대 입력은 29231토큰이었습니다. 채점 결과의 prompt_fits_context도 참이었습니다. 이 조건에서는 방해 조항이 없는 4만8천자 문서까지 모두 정답이었습니다.
두 실패를 같은 “긴 문서 기억력”으로 묶으면 대응도 흐려집니다.
- 옵션 미지정 조건에서는 입력 앞부분이 모델에 전달되지 않은 패턴이 나타났습니다.
- 명시 컨텍스트 조건에서는 문서가 범위 안에 들어왔지만, 같은 형식의 방해값을 정답으로 가져왔습니다.
앞의 문제는 입력 설정과 토큰 기록을 확인해야 합니다. 뒤의 문제는 원문에서 후보 조항을 대조해야 잡힙니다.
로컬 Ollama에서는 세 군데를 먼저 확인합니다
이번 결과를 실제 문서 작업에 적용하면 다음 순서가 남습니다.
1. num_ctx를 요청에 명시하고 실제 입력 토큰을 기록합니다
모델 설명에 적힌 최대 컨텍스트만 보고 끝내지 않습니다. 요청에 보낸 num_ctx와 응답 메타데이터의 prompt_eval_count를 함께 남깁니다.
문서가 커졌는데 입력 토큰 수가 일정 값에서 멈추면 답변 품질을 평가하기 전에 잘림부터 의심할 수 있습니다. 이번 실행에서는 이 확인만으로 옵션 미지정 팔과 명시 팔을 분리할 수 있었습니다.
로컬 모델과 클라우드 모델을 어떤 작업에 배치할지 고민한다면 로컬 gemma3와 Gemini 같은 날 실측도 함께 볼 수 있습니다. 그 측정에서도 모델 이름 하나보다 과업별 검사 가능 여부가 선택을 갈랐습니다.
2. 정답과 같은 형식의 값부터 모읍니다
담당자를 묻는다면 문서 안의 사람 이름을, 비용을 묻는다면 비슷한 금액을 먼저 모읍니다. 답 하나를 받은 뒤 “문서에 있었는가”만 확인하면 이유진 같은 방해값도 통과할 수 있습니다.
이번에는 채점기가 정답 별칭과 방해값을 따로 비교했습니다. 그 결과 오답 38건 가운데 35건이 방해값 흡입이라는 사실을 분리할 수 있었습니다.
실무에서는 답변에 근거 조항 번호와 해당 문장을 함께 요구하고, 모델이 고른 값이 원문의 어느 조항에서 나왔는지 대조하겠습니다. 이번 측정은 이 검수 절차의 효과가 아니라, 방해값 흡입이 실제로 일어나는지를 확인한 실험입니다.
3. 출력 형식 검사와 내용 회상 검사를 나눕니다
“이름만 답하세요”라는 출력 지시는 답을 짧게 만들었지만, 그 이름이 맞는지는 보장하지 않았습니다. 형식이 맞는 것과 사실을 찾은 것은 별개의 판정입니다.
역할·맥락·작업·출력형식을 어떻게 나눌지는 AI 프롬프트 4칸 공식 실측에서 확인할 수 있습니다. 그 글의 형식 검사 뒤에, 이번 글의 원문 대조 단계를 붙이는 방식이 맞습니다.
이번 488회가 말하지 않는 것
측정 대상은 gemma3:4b의 Q4_K_M 한 모델입니다. 한국어 사내 규정 형태로 만든 문서와 네 종류의 사실만 사용했습니다.
모델의 기본 생성 설정을 사용했고 각 조합은 두 번씩 실행했습니다. 위치별 순위는 이 반복 수와 고정된 문항·방해 조항 배치 안에서 해석해야 합니다.
속도는 488회 기록을 합쳐 2463.270초, 회당 평균 5.048초였습니다. keep_alive=0이라 각 요청 뒤 모델을 메모리에 남기지 않은 조건입니다. 이는 동시 처리량이나 상시 로드 서버의 응답 속도가 아닙니다.
이번 테스트가 구분한 것은 컨텍스트 미지정 때 나타난 잘림 패턴과, 컨텍스트 안에 문서가 들어온 뒤 발생한 방해값 흡입입니다.
컨텍스트를 명시하고 방해 조항을 빼면 160회 모두 사실을 찾았습니다. 같은 형식의 다른 값 세 개가 들어오자 160회 중 정답은 122회로 줄었고, 오답 38건 가운데 35건은 방해값을 가져온 경우였습니다. 옵션을 지정하지 않은 팔에서는 입력 토큰이 최대 2051에 머물며 앞부분이 크게 무너졌습니다.
그래서 로컬 AI에 긴 문서를 넣을 때는 길이 하나만 보지 않겠습니다. 먼저 실제 입력 토큰을 확인하고, 답과 같은 형식의 후보 조항을 모아 원문과 대조하겠습니다.
재현: cinevyze-bench의 run_needle_bench.py와 needle_bench_cases.json (문항 파일 포함). 본문의 원자료 경로(test_runs/…)는 비공개 작업 폴더라 외부에서 열 수 없습니다.
긴 문서 회상 조건은 로컬 gemma3:4b로 순서대로 실행했습니다. 측정 코드와 본문 작성에 AI 도구를 활용했고, 조건 승인과 발행 전 검수는 제가 합니다.
cinevyze 운영자 — RTX 4070 Ti SUPER 한 장과 로컬 Ollama의 gemma3:4b로 긴 문서 회상 조건을 순차 실행했습니다. 측정 시점은 2026년 9월 21일입니다. 운영자 소개
댓글
댓글 쓰기