---
createdAt: 2025-09-10
updatedAt: 2025-09-10
title: RAG 기반 문서 지원 도우미 구축하기 (청킹, 임베딩, 검색)
description: RAG 기반 문서 지원 도우미 구축하기 (청킹, 임베딩, 검색)
keywords:
  - RAG
  - 문서
  - 도우미
  - 청킹
  - 임베딩
  - 검색
slugs:
  - blog
  - rag-powered-documentation-assistant
---

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

## 제공 내용

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

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

👉 [라이브 데모](https://intlayer.org/doc/why) 👉 [코드 보일러플레이트](https://github.com/aymericzip/smart_doc_RAG)

## 소개

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

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

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

## 왜 문서에 RAG를 사용할까?

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

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

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

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

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

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

## RAG 파이프라인 작동 방식

![RAG Pipeline](https://github.com/aymericzip/intlayer/blob/main/docs/assets/rag_flow.svg)

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

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초까지 걸림) 앞으로 다시 검토할 예정입니다.

👉 [여기에서 데모를 시도해 보세요](https://intlayer.org/doc/why) 👉 [GitHub에서 코드 템플릿 확인하기](https://github.com/aymericzip/smart_doc_RAG)

## 더 나아가기

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

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

## 우리가 직면한 한계

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

## 문서를 넘어 중요한 이유

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

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

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

**예시:**

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

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

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

## 결론

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

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

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

👉 [여기서 데모를 시도해보세요](https://intlayer.org/doc/why) 👉 [GitHub에서 코드 템플릿을 확인하세요](https://github.com/aymericzip/smart_doc_RAG)

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