본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 15. 07:03

Next.js 15에서 PDF RAG를 구축하며 마주한 5가지 장애물과 해결 방법

요약

Next.js 15 환경에서 PDF 기반 RAG 시스템을 구축하며 겪은 4가지 기술적 장애물과 해결책을 다룹니다. PDF 파서 호환성 문제, 청킹 전략, React 상태 관리, LLM 응답 제어에 대한 실무적인 경험을 공유합니다.

핵심 포인트

  • Edge/Serverless 환경을 위해 브라우저 의존성이 없는 unpdf 사용 권장
  • 검색 성능 향상을 위해 의미 단위 분할 및 오버랩(Overlap) 청킹 적용
  • 데이터가 정상임에도 UI가 갱신되지 않을 경우 React 상태 관리 확인 필요
  • 라이브러리 선택 시 Turbopack 등 빌드 도구와의 호환성 검토 필수

NochBot에서 PDF RAG를 구축하는 과정은 저를 거의 무너뜨릴 뻔했습니다.

제가 마주했던 모든 장애물과, 그것들을 정확히 어떻게 해결했는지 공유합니다.

장애물 1 — PDF 파서(Parser)의 악몽

pdf-parse로 시작했습니다. 간단하고, 대중적이며, 누구나 사용하는 라이브러리입니다.

첫 번째 에러:
ReferenceError: DOMMatrix is not defined

알고 보니 pdf-parse는 모듈 레벨에서 브라우저 API를 로드하는데, Node.js는 DOMMatrix가 무엇인지 알지 못했습니다.

pdf-parse-new로 교체했습니다.
새로운 에러:
Module not found: Can't resolve './ROOT/node_modules/pdf-parse-new/lib/pdf-child.js'

내부 경로가 깨져 있었습니다. Turbopack과 호환되지 않았습니다.

세 번째 시도 — unpdf.
Edge/Serverless 환경을 위해 특별히 제작되었습니다. 브라우저 의존성이 없으며, 함수 본문 내부에서 동적 임포트(Dynamic import)를 사용합니다.

export async function parsePDF(buffer: Buffer) {
  const { extractText } = await import('unpdf');
  const uint8 = new Uint8Array(buffer);
...

마침내 성공했습니다. ✅

교훈: 라이브러리 선택은 실제 로직보다 더 중요합니다. 항상 Turbopack 호환성을 먼저 확인하세요.

장애물 2 — 검색(Retrieval) 성능을 저하시키는 청킹(Chunking)

첫 번째 버전은 고정된 단어 수로 청킹했습니다. 300단어. 깔끔하고 단순했습니다.

하지만 검색 성능이 최악이었습니다.

제목은 하나의 청크에 들어가고, 그 설명은 다음 청크로 넘어갔습니다. LLM(대규모 언어 모델)이 활용할 수 있는 문맥(Context)이 전혀 없었습니다.

해결책 — 오버랩(Overlap)을 포함한 문단 경계 청킹:

export function chunkText(markdown: string) {
  const blocks = markdown
    .split(/\n\n+/)
...

단어 수가 아닌 의미 단위로 분할했습니다. 25단어의 오버랩을 통해 청크 경계에서 문맥이 손실되지 않도록 보장했습니다.

검색 품질이 즉시 향상되었습니다.

교훈: 데이터를 어떻게 나누느냐는 데이터를 어떻게 저장하느냐만큼 중요합니다.

장애물 3 — 백엔드는 정상인데 UI가 빈 화면으로 나옴

벡터화(Vectorization)는 완벽하게 작동하고 있었습니다. 데이터가 Qdrant에 저장되는 것도 확인했습니다.

하지만 대시보드의 Vectorize 탭은? 완전히 빈 화면이었습니다.

백엔드 문제라고 확신하며 2시간을 허비했습니다.

원인은 업데이트되지 않는 useState였습니다.

API는 데이터를 올바르게 반환하고 있었습니다.
컴포넌트도 데이터를 받고 있었습니다.
하지만 상태 업데이트 (state update)가
리렌더링 (re-render)을 전혀 트리거하지 못했습니다.

// 잘못된 방식 — 상태를 직접 변형 (mutating state)
const data = await res.json();
vectorizeData = data; // ❌ 리렌더링 발생 안 함
...

단 한 줄의 수정. 2시간을 허비했습니다.

교훈: 백엔드는 작동하는데
UI가 작동하지 않는다면 — 상태 관리 (state management)를 가장 먼저 확인하세요.
언제나 말이죠.

장애물 4 — 단순한 질문에 과하게 생각하는 LLM

봇에게 질문했습니다:

"이 PDF는 총 몇 페이지인가요?"

돌아온 답변은:

"1단계 — PDF 컨텍스트 분석 중...
2단계 — 핵심 개념 식별 중...
3단계 — 정답 결정 중..."

단 두 단어로 끝날 답변에 300단어를 썼습니다.

두 가지 해결 방법:

해결 방법 1 — 프롬프트 수정:

단순한 사실 관계 질문에 대해서는 —
오직 1~2문장으로만 답변하도록 합니다.
추론 단계 (reasoning steps)를 절대 보여주지 마세요.
그저 최종 답변만 제공하세요.

해결 방법 2 — 온도 (Temperature):

// 수정 전
temperature: 0.6  // 사실 관계를 다루기에 너무 창의적임

...

이 두 가지 해결 방법을 함께 적용하자
과도한 생각 (overthinking) 문제가 완전히 사라졌습니다.

교훈: 만약 LLM의 출력이 좋지 않다면 —
모델의 문제가 아니라
프롬프트 (prompt)가 문제입니다.

장애물 5 — 페이지 이동 시 PDF가 사라지는 현상

사용자가 PDF 페이지를 벗어났다가
다시 돌아오면 — 업로드했던 PDF들이
시각적으로 사라져 있었습니다.

하지만 시각적으로만 그랬을 뿐입니다. 데이터는 여전히 DB에 있었습니다.

근본 원인: Next.js App Router가
페이지를 캐싱 (caching)하고 있었습니다. 컴포넌트가
다시 마운트 (remounting)되지 않았고, fetch가
다시 트리거되지 않았습니다.

해결 방법 — visibilitychange 이벤트 리스너 사용:

useEffect(() => {
  const handleVisibilityChange = () => {
    if (document.visibilityState === 'visible') {
...

탭이나 페이지가 활성화될 때마다 —
PDF 목록을 다시 가져오도록 (re-fetch) 합니다.
사용자가 어떤 방식으로 다시 돌아왔는지와 관계없이 작동합니다.

교훈: Next.js App Router의 캐싱은
당신을 방심하게 만들 것입니다.
데이터가 항상 최신 상태로 유지되어야 한다면
항상 visibilitychange 이벤트를 처리하세요.

전체 스택 (The Full Stack)

이 프로젝트를 구축하는 데 사용한 모든 기술입니다:

계층 (Layer)기술 (Technology)
프레임워크 (Framework)Next.js 15 + Turbopack
...

현재 라이브 상태

이 모든 기능은 멀티 테넌트 (Multi-tenant) AI 챗봇 SaaS인 NochBot 내부의 프로덕션 (Production) 환경에서 실행되고 있습니다.

출시된 기능:

  • PDF 업로드 + 벡터화 (Vectorization)
  • PDF별 공유 채팅 링크
  • 세션 분석 (Session analytics) — 모든 대화 확인 가능
  • 듀얼 모드 — 학습 보조 도구 + 영업 카탈로그 봇
  • 응답 중간 생성 중단
  • 무료 플랜: PDF 1개 제한

요약 (TL;DR)

  1. Next.js 15에서는 pdf-parse 대신 unpdf를 사용하세요
  2. 단어 수가 아닌 문단 경계(Paragraph boundaries)를 기준으로 청킹 (Chunking) 하세요
  3. UI가 빈 화면으로 나온다면, 먼저 useState를 확인하세요
  4. 낮은 온도 (Low temperature) + 명시적인 프롬프트 (Explicit prompts) = 과도한 추론 방지
  5. App Router 캐싱을 처리하기 위해 visibilitychange를 사용하세요

RAG를 구축하고 있다면, 이 글을 저장해 두세요.
이것들은 여러분이 반드시 마주하게 될 실제 장벽들입니다.

NochBot을 혼자 구축 중이며, 진행 과정을 모두 기록하고 있습니다.
더 많은 실전 RAG + Next.js 콘텐츠를 원하시면 팔로우해 주세요.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0