보고서의 표가 10쪽에서 11쪽으로 이어질 때, 두 페이지를 따로 파싱하면 제목과 단위가 다음 페이지의 숫자에서 떨어질 수 있습니다. OCR 결과가 RAG의 근거가 되면 이 작은 단절이 잘못된 답변과 출처로 이어집니다. Unlimited-OCR 2를 검토할 이유는 긴 문서를 받는다는 사실보다 그 경계를 어떻게 보존하는가에 있습니다.

Baidu의 모델 카드는 10월 27일 버전 2 출시를 기록합니다. 6월의 기존 Unlimited-OCR 발표와 구별해야 합니다. 이 글은 10월 29일 문서·소스를 확인한 분석이며 실제 OCR·GPU 추론은 수행하지 않았습니다.

고정된 참조 집합이 전체 작업을 고정 비용으로 만들지는 않는다

모델 카드의 SR-SWA 설명은 긴 텍스트·시각 attention을 제한된 작업 참조 집합으로 줄이는 방식입니다. 예시 크기는 512토큰입니다. 여기서 제한하는 참조량과 입력 PDF의 총량은 다른 개념입니다. SR-SWA 설명

참조가 제한돼도 100페이지를 이미지로 변환하고 인코딩하고 출력하는 일은 남습니다. 디코딩 한 단계의 attention 비용이 안정적이라는 주장으로 문서 전체 처리 시간, 모든 임시 메모리, 동시 요청의 비용까지 일정하다고 결론 낼 수 없습니다. 또한 유한한 참조를 유지하는 것이 과거 페이지의 모든 세부사항을 손실 없이 보관한다는 뜻도 아닙니다.

이 구분은 설정에서 드러납니다. 공식 README의 SGLang 메모리 안내는 페이지 윈도를 줄이면 peak memory를 낮출 수 있지만 윈도 경계의 이어지는 블록은 문맥을 잃어 병합 품질이 떨어질 수 있다고 설명합니다. 윈도 크기는 정확도와 함께 평가할 변수입니다.

같은 문서를 나눠 읽을 때도 입력 조건을 맞춰야 한다

모델 카드의 Transformers 예제는 순서대로 정렬한 페이지를 infer_multi에 넘깁니다. A800 80GB는 공개된 테스트 환경이며 최소 VRAM 요구량으로 제시된 값은 아닙니다. 아래는 모델·토크나이저를 이미 로드했고 이미지 파일이 존재한다는 전제의 미실행 예시입니다. 추론 안내

pages = [f"document/page_{i:03d}.jpg" for i in range(1, 11)]
text, output_tokens = model.infer_multi(
    tokenizer, image_files=pages,
    output_path="output/document", save_results=True,
)

예상 반환값은 파싱 텍스트와 출력 토큰 수입니다. 설치·모델 다운로드·로딩은 이 글에서 실행하지 않았습니다. 공식 로딩 경로는 custom code를 사용하므로 재현할 때는 모델 revision과 코드를 먼저 검토하고 고정해야 합니다. 고객 문서 대신 공개·합성 문서부터 사용하세요.

또 하나의 비교 함정이 있습니다. 카드에서 단일 페이지의 기본 경로는 동적 타일링, 여러 페이지 경로는 global view를 사용한다고 설명합니다. 기본 옵션으로 각각 실행한 결과가 다르면 그것이 문맥 유지 때문인지 이미지 표현 때문인지 분리하기 어렵습니다. 렌더링 해상도와 인코딩 조건을 기록하고, 비교 가능한 설정을 먼저 확인해야 합니다.

검토한 모델 소스에서 infer_multi는 텍스트와 토큰 수를 반환하는 래퍼입니다. 내부 _uocr_generate에는 길이 제한과 종료 사유가 있습니다. 함수 호출이 돌아왔다는 사실만으로 모든 페이지가 끝까지 생성됐다고 승인하지 마세요. 이 코드 관찰을 SGLang의 전체 메모리 동작을 측정한 결과로 확대할 수도 없습니다.

페이지 수가 맞아도 누락은 남는다

RAG에 넣기 전 최소 검사는 입력 페이지 수와 출력 경계의 대응입니다. 하지만 경계 수만 같으면 충분할까요? 아래 원본 예제의 두 번째 출력은 중간 페이지를 첫 페이지로 대체했습니다.

Node.js 18 이상에서 pages.mjs로 저장해 실행할 수 있습니다. 입력은 직접 만든 세 페이지의 문자열이며 OCR 결과·Baidu 벤치마크 데이터가 아닙니다. 설치·네트워크 호출이 없습니다.

const expected = ['A:100', 'B:200', 'C:300'];
const outputs = [
  '<PAGE>A:100<PAGE>B:200<PAGE>C:300',
  '<PAGE>A:100<PAGE>A:100<PAGE>C:300'
];
for (const text of outputs) {
  const pages = text.split('<PAGE>').slice(1).map(s => s.trim());
  console.log(JSON.stringify({
    pageCountOK: pages.length === expected.length,
    exactPages: expected.filter((ref, i) => pages[i] === ref).length,
    totalPages: expected.length
  }));
}

실행 결과:

{"pageCountOK":true,"exactPages":3,"totalPages":3}
{"pageCountOK":true,"exactPages":2,"totalPages":3}

두 경우 모두 페이지 수 검사는 통과하지만 두 번째는 내용 대응이 하나 틀립니다. 이 exact match는 합성 문자열을 위한 설명용 검사입니다. 실제 문서에는 공백·줄바꿈 정책과 사람이 확인한 기준 텍스트가 필요하고, 표 구조와 페이지 연결은 별도로 채점해야 합니다. 페이지 마커를 세는 검사는 종료·누락 의심을 찾는 출발점이지 정확도 점수가 아닙니다.

10·50·100페이지 평가에 경계 조건을 넣기

다음은 제안하는 실험 설계입니다. 실측 결과가 아닙니다. 같은 기반 문서의 10·50·100페이지 묶음을 만들고, 윈도를 바꿀 때마다 동일한 표가 경계 안과 밖에 놓이는 조건을 비교합니다. 경계 근처에만 더 어려운 표를 배치하면 윈도 영향과 문서 난도가 섞이므로 배치도 교차해야 합니다.

측정 축 기록할 내용 RAG에서 막으려는 실패
페이지 완전성 누락·중복·순서·중단 페이지 없는 근거를 정상 파싱으로 승인
경계의 표 열 제목·단위·이어지는 행 단위 없는 숫자 검색
출처 추적 문서 ID·revision·원본 페이지·텍스트 범위 답은 맞아도 잘못된 페이지 인용
자원 모델/서버 revision, 정밀도, peak GPU·host memory, 동시성 디코딩 cache만 보고 전체 비용 과소평가
시간 PDF 변환·prefill·decode·전체 시간 토큰 속도를 처리 완료 시간으로 오인

검색 청크를 만들 때는 파싱된 텍스트뿐 아니라 페이지 대응을 보존하세요. 여러 페이지의 표를 하나의 청크로 묶으면 source_pages도 여러 페이지여야 합니다. 생성 순서의 청크 번호를 원본 페이지 번호로 재사용하면 검증 가능한 인용을 만들기 어렵습니다.

작은 영수증 한 장만 처리하는 서비스라면 긴 문맥의 이점보다 설정 복잡성이 클 수 있습니다. 반대로 페이지를 넘는 표·각주가 업무의 핵심이면, 메모리가 가장 적게 드는 설정보다 그 연결이 보존되는 설정이 중요합니다. 독립 벤치마크나 한국어 정확도를 이 글에서 확인한 것으로 주장하지 않습니다.

RAG의 실패를 입력 단계부터 추적하려면 청킹·하이브리드 검색의 실패 분석도 참고할 수 있습니다.

아래 공개 유료 강의는 문서의 인덱싱·검색·RAG 평가와 연결됩니다. Unlimited-OCR 배포 전용 과정은 아니며, 마지막 링크는 홍보 링크입니다.