Intlayer의 향후 출시 예정에 대한 알림을 받으세요
    생성:2025-09-10마지막 업데이트:2025-09-10

    RAG 기반 문서 지원 도우미 구축하기 (청킹, 임베딩, 검색)

    제공 내용

    저는 RAG 기반 문서 지원 도우미를 구축하고, 즉시 사용할 수 있는 보일러플레이트로 패키징했습니다.

    • 즉시 사용 가능한 애플리케이션 포함 (Next.js + OpenAI API)
    • 작동하는 RAG 파이프라인 포함 (청킹, 임베딩, 코사인 유사도)
    • React로 구축된 완전한 챗봇 UI 제공
    • 모든 UI 컴포넌트는 Tailwind CSS로 완전히 편집 가능합니다.
    • 모든 사용자 쿼리를 기록하여 누락된 문서, 사용자 불편 사항 및 제품 기회를 식별하는 데 도움을 줍니다.

    👉 라이브 데모 👉 코드 보일러플레이트

    소개

    문서에서 답을 찾으려고 끝없이 스크롤하다가 길을 잃은 적이 있다면, 그 고통이 얼마나 큰지 아실 겁니다. 문서는 유용하지만 정적이고, 검색하는 것이 종종 불편하게 느껴집니다.

    바로 이때 RAG (검색 증강 생성, Retrieval-Augmented Generation) 이 등장합니다. 사용자가 텍스트를 뒤지도록 강요하는 대신, 검색 (문서의 적절한 부분 찾기)과 생성 (LLM이 자연스럽게 설명하기)을 결합할 수 있습니다.

    이 글에서는 제가 어떻게 RAG 기반 문서 챗봇을 만들었는지, 그리고 그것이 단순히 사용자가 더 빠르게 답을 찾도록 돕는 것뿐만 아니라 제품 팀이 사용자 고충을 이해하는 새로운 방법을 제공하는지 설명하겠습니다.

    왜 문서에 RAG를 사용할까?

    RAG가 인기 있는 접근법이 된 데는 이유가 있습니다. 대형 언어 모델을 실제로 유용하게 만드는 가장 실용적인 방법 중 하나이기 때문입니다.

    문서에 있어서 그 이점은 명확합니다:

    • 즉각적인 답변: 사용자가 자연어로 질문하면 관련된 답변을 받습니다.
    • 더 나은 맥락: 모델은 가장 관련성 높은 문서 부분만 보기 때문에 환각 현상이 줄어듭니다.
    • 인간적인 검색 경험: Algolia + FAQ + 챗봇이 하나로 합쳐진 느낌입니다.
    • 피드백 루프: 쿼리를 저장함으로써 사용자가 실제로 어려워하는 점을 파악할 수 있습니다.

    그 마지막 점이 매우 중요합니다. RAG 시스템은 단순히 질문에 답하는 것뿐만 아니라 사람들이 무엇을 묻고 있는지 알려줍니다. 이는 다음을 의미합니다:

    • 문서에서 누락된 정보를 발견할 수 있습니다.
    • 기능 요청이 나타나는 것을 볼 수 있습니다.
    • 제품 전략을 안내할 수 있는 패턴을 발견할 수 있습니다.

    따라서 RAG는 단순한 지원 도구가 아닙니다. 그것은 또한 제품 발견 엔진입니다.

    RAG 파이프라인 작동 방식

    RAG Pipeline

    전체적인 개요는 다음과 같습니다:

    1. 문서 청킹(Chunking) 큰 마크다운 파일을 여러 청크로 분할합니다. 청킹은 문서의 관련된 부분만 컨텍스트로 제공할 수 있게 합니다.
    2. 임베딩 생성(Generating embeddings) 각 청크는 OpenAI의 임베딩 API(text-embedding-3-large) 또는 벡터 데이터베이스(Chroma, Qdrant, Pinecone)를 사용해 벡터로 변환됩니다.
    3. 인덱싱 및 저장 임베딩은 간단한 JSON 파일에 저장됩니다(데모용). 하지만 실제 운영 환경에서는 벡터 DB를 사용할 가능성이 높습니다.
    4. 검색 (RAG의 R) 사용자 쿼리를 임베딩하고, 코사인 유사도를 계산하여 가장 일치하는 청크들을 검색합니다.
    5. 증강 및 생성 (RAG의 AG) 해당 청크들을 ChatGPT 프롬프트에 주입하여, 모델이 실제 문서 컨텍스트를 기반으로 답변하도록 합니다.
    6. 피드백을 위한 쿼리 기록 모든 사용자 쿼리를 저장합니다. 이는 문제점 파악, 누락된 문서, 새로운 기회를 이해하는 데 매우 중요합니다.

    1단계: 문서 읽기

    첫 번째 단계는 간단했습니다: docs/ 폴더 내 모든 .md 파일을 스캔할 방법이 필요했습니다. Node.js와 glob을 사용하여 각 마크다운 파일의 내용을 메모리로 가져왔습니다.

    이것은 파이프라인을 유연하게 유지합니다: Markdown 대신 데이터베이스, CMS, 또는 API에서 문서를 가져올 수도 있습니다.

    2단계: 문서 청킹(Chunking)

    왜 청킹을 할까요? 언어 모델에는 컨텍스트 제한이 있기 때문입니다. 전체 문서 책을 한 번에 입력하는 것은 불가능합니다.

    그래서 텍스트를 관리 가능한 청크(예: 각 500 토큰)로 나누고, 겹치는 부분(예: 100 토큰)을 둡니다. 겹치는 부분은 청크 경계에서 의미가 끊기지 않도록 연속성을 보장합니다.

    예시:

    • 청크 1 → “…많은 이들이 잊어버린 오래된 도서관. 그 높이 솟은 선반들은 책들로 가득 차 있었다…”
    • 청크 2 → “…선반들은 상상할 수 있는 모든 장르의 책들로 가득 차 있었고, 각각이 이야기를 속삭이고 있었다…”

    이 겹침은 두 청크가 공유된 컨텍스트를 포함하도록 하여, 검색 시 일관성을 유지하게 합니다.

    이 절충안(청크 크기 대 중첩)은 RAG 효율성에 매우 중요합니다:

    • 너무 작으면 → 노이즈가 발생합니다.
    • 너무 크면 → 컨텍스트 크기가 너무 커집니다.

    3단계: 임베딩 생성

    문서가 청크로 나뉘면, 각 청크를 나타내는 고차원 벡터인 임베딩을 생성합니다.

    저는 OpenAI의 text-embedding-3-large 모델을 사용했지만, 최신 임베딩 모델이라면 어떤 것이든 사용할 수 있습니다.

    임베딩 예시:

    js
    [  -0.0002630692, -0.029749284, 0.010225477, -0.009224428, -0.0065269712,  -0.002665544, 0.003214777, 0.04235309, -0.033162255, -0.00080789323,  //...+1533 elements];

    각 벡터는 텍스트의 수학적 지문으로, 유사도 검색을 가능하게 합니다.

    4단계: 임베딩 인덱싱 및 저장

    임베딩을 여러 번 다시 생성하지 않도록, 저는 이를 embeddings.json에 저장했습니다.

    프로덕션 환경에서는 다음과 같은 벡터 데이터베이스를 사용하는 것이 좋습니다:

    • Chroma
    • Qdrant
    • Pinecone
    • FAISS, Weaviate, Milvus 등

    벡터 DB는 인덱싱, 확장성, 빠른 검색을 처리합니다. 하지만 제 프로토타입에서는 로컬 JSON으로도 충분했습니다.

    5단계: 코사인 유사도를 이용한 검색

    사용자가 질문을 하면:

    1. 쿼리에 대한 임베딩을 생성합니다.
    2. 모든 문서 임베딩과 코사인 유사도를 사용해 비교합니다.
    3. 가장 유사한 상위 N개의 청크만 유지합니다.

    코사인 유사도는 두 벡터 사이의 각도를 측정합니다. 완벽한 일치는 1.0 점수를 받습니다.

    이렇게 시스템은 쿼리와 가장 가까운 문서 구간을 찾습니다.

    6단계: 증강 + 생성

    이제 마법이 시작됩니다. 상위 청크들을 가져와 ChatGPT의 시스템 프롬프트에 주입합니다.

    그것은 모델이 마치 해당 청크들이 대화의 일부인 것처럼 답변한다는 의미입니다.

    결과: 정확하고, 문서 기반의 응답.

    7단계: 사용자 쿼리 기록

    이것이 숨겨진 슈퍼파워입니다.

    모든 질문이 저장됩니다. 시간이 지나면서 다음과 같은 데이터셋을 구축할 수 있습니다:

    • 가장 빈번한 질문들 (FAQ에 매우 유용)
    • 답변되지 않은 질문들 (문서가 없거나 불명확한 경우)
    • 질문으로 위장된 기능 요청 (“X와 통합되나요?”)
    • 예상치 못한 새로운 사용 사례

    이로써 당신의 RAG 어시스턴트는 지속적인 사용자 조사 도구가 됩니다.

    비용은 얼마나 들까?

    RAG에 대한 흔한 반대 의견 중 하나는 비용입니다. 실제로는 놀라울 정도로 저렴합니다:

    • 약 200개의 문서에 대한 임베딩 생성은 약 5분이 걸리며 비용은 1~2 유로입니다.
    • 문서 검색 기능은 100% 무료입니다.
    • 쿼리의 경우, “thinking” 모드 없이 gpt-4o-latest를 사용합니다. Intlayer에서는 한 달에 약 300건의 채팅 쿼리가 발생하며, OpenAI API 요금은 거의 $10를 넘지 않습니다.

    여기에 호스팅 비용을 포함할 수 있습니다.

    구현 세부사항

    스택:

    • 모노레포: pnpm 워크스페이스
    • 문서 패키지: Node.js / TypeScript / OpenAI API
    • 프론트엔드: Next.js / React / Tailwind CSS
    • 백엔드: Node.js API 라우트 / OpenAI API

    @smart-doc/docs 패키지는 문서 처리를 담당하는 TypeScript 패키지입니다. 마크다운 파일이 추가되거나 수정되면, 이 패키지는 각 언어별 문서 목록을 재구성하고 임베딩을 생성하여 embeddings.json 파일에 저장하는 build 스크립트를 포함합니다.

    프론트엔드에는 다음 기능을 제공하는 Next.js 애플리케이션을 사용합니다:

    • 마크다운을 HTML로 렌더링
    • 관련 문서를 찾기 위한 검색 바
    • 문서에 대한 질문을 할 수 있는 챗봇 인터페이스

    문서 검색을 수행하기 위해, Next.js 애플리케이션은 쿼리에 맞는 문서 청크를 검색하는 @smart-doc/docs 패키지의 함수를 호출하는 API 라우트를 포함합니다. 이 청크들을 사용하여 사용자의 검색과 관련된 문서 페이지 목록을 반환할 수 있습니다.

    챗봇 기능의 경우, 동일한 검색 과정을 따르지만 추가로 검색된 문서 청크를 ChatGPT에 보내는 프롬프트에 주입합니다.

    다음은 ChatGPT에 보내는 프롬프트 예시입니다:

    시스템 프롬프트:

    txt
    당신은 Intlayer 문서에 관한 질문에 답변할 수 있는 유용한 도우미입니다.관련 청크:-----docName: "getting-started"docChunk: "1/3"docUrl: "https://example.com/docs/ko/getting-started"---# 시작하는 방법...-----docName: "another-doc"docChunk: "1/5"docUrl: "https://example.com/docs/ko/another-doc"---# 다른 문서...

    사용자 질의 :

    txt
    시작하는 방법은?

    우리는 API 경로에서 응답을 스트리밍하기 위해 SSE를 사용합니다.

    앞서 언급했듯이, 우리는 "생각하는" 모드 없이 gpt-4-turbo를 사용합니다. 응답은 관련성이 높고 지연 시간이 낮습니다. gpt-5도 실험해 보았지만, 지연 시간이 너무 길었고(때로는 응답에 최대 15초까지 걸림) 앞으로 다시 검토할 예정입니다.

    👉 여기에서 데모를 시도해 보세요 👉 GitHub에서 코드 템플릿 확인하기

    더 나아가기

    이 프로젝트는 최소한의 구현입니다. 하지만 여러 가지 방법으로 확장할 수 있습니다:

    • MCP 서버 → 문서 검색 기능을 MCP 서버로 확장하여 문서를 모든 AI 어시스턴트에 연결
    • 벡터 DB → 수백만 개의 문서 청크로 확장
    • LangChain / LlamaIndex → RAG 파이프라인을 위한 기성 프레임워크
    • 분석 대시보드 → 사용자 쿼리와 문제점을 시각화
    • 다중 소스 검색 → 문서뿐만 아니라 데이터베이스 항목, 블로그 게시물, 티켓 등도 검색
    • 향상된 프롬프트 → 재순위화, 필터링, 하이브리드 검색(키워드 + 의미 기반)

    우리가 직면한 한계

    • 청크 분할과 중첩은 경험적입니다. 적절한 균형(청크 크기, 중첩 비율, 검색된 청크 수)은 반복과 테스트가 필요합니다.
    • 문서가 변경될 때 임베딩이 자동으로 재생성되지 않습니다. 우리 시스템은 저장된 청크 수와 다를 때만 파일의 임베딩을 재설정합니다.
    • 이 프로토타입에서는 임베딩이 JSON에 저장됩니다. 이는 데모에는 적합하지만 Git을 오염시킵니다. 실제 운영 환경에서는 데이터베이스나 전용 벡터 스토어가 더 적합합니다.

    문서를 넘어 중요한 이유

    흥미로운 부분은 단순한 챗봇이 아닙니다. 바로 피드백 루프입니다.

    RAG를 사용하면 단순히 답변하는 것에 그치지 않습니다:

    • 사용자가 무엇에 혼란스러워하는지 알게 됩니다.
    • 사용자가 기대하는 기능을 발견합니다.
    • 실제 쿼리를 기반으로 제품 전략을 조정합니다.

    예시:

    새로운 기능을 출시하고 즉시 다음과 같은 상황을 상상해 보세요:

    • 질문의 50%가 동일한 불명확한 설정 단계에 관한 것
    • 사용자가 아직 지원하지 않는 통합 기능을 반복적으로 요청
    • 사람들이 새로운 사용 사례를 드러내는 용어를 검색

    이것이 바로 사용자로부터 직접 얻는 제품 인텔리전스입니다.

    결론

    RAG는 LLM을 실용적으로 만드는 가장 간단하면서도 강력한 방법 중 하나입니다. 검색(retrieval) + 생성(generation)을 결합함으로써 정적인 문서를 스마트 어시스턴트로 전환할 수 있으며, 동시에 지속적인 제품 인사이트 흐름을 얻을 수 있습니다.

    저에게 이 프로젝트는 RAG가 단순한 기술적 트릭이 아님을 보여주었습니다. RAG는 문서를 다음과 같이 변환하는 방법입니다:

    • 상호작용하는 지원 시스템
    • 피드백 채널
    • 제품 전략 도구

    👉 여기서 데모를 시도해보세요 👉 GitHub에서 코드 템플릿을 확인하세요

    그리고 만약 여러분도 RAG를 실험하고 있다면, 어떻게 사용하고 있는지 듣고 싶습니다.