RAG 자료창고 설계 – AI주지스님 자료창고

어떤 방법으로 불교 관련 자료들을 창고에 쌓아가야 AI 주지스님이 더 적은 자원으로 더 빠른 시간에 더 깊은 답변을 할 수 있을까.
이걸 정하기 위해 필요한 개념들을 먼저 정리해 보자.

RAG는 어떤 조각들로 이뤄져 있나

RAG(Retrieval-Augmented Generation, 검색 증강 생성)는 AI가 답변을 만들기 전에 외부문서나 데이터베이스에서 필요한 정보를 먼저 찾고, 그 내용을 바탕으로 정확한 답을 말하게 해주는 기술이다.

RAG와 관련된 개념과 기능들을 레벨에 따라 정리해 보면 다음과 같다.

프레임워크 (L1) 파이프라인 (L2) 핵심 기능 (L3) 정의 및 주요 역할 관련 기술/스택
RAG(Retrieval-Augmented Generation) 인덱싱 파이프라인
(Indexing Pipeline)
=

“자료창고 구축
(청킹→임베딩→벡터DB저장)”
문서 청킹
(Document Chunking)
방대한 문서를 LLM이 소화하기 좋은 적절한 크기의 텍스트 조각으로 분할하는 기능 LangChain Chunkers, Recursive Character
의미 기반 검색
(Semantic Search)
단순 키워드 매칭을 넘어, 문맥과 의도를 파악하여 유사한 의미의 정보를 찾아내는 기능 Vector DB, Embedding Model
생성 파이프라인
(Generation Pipeline)
컨텍스트 증강
(Context Augmentation)
검색된 관련 문서 조각들을 프롬프트에 자연스럽게 삽입하여 LLM에 전달하는 기능 Prompt Engineering
답변 생성 및 검증
(Generation & Guardrails)
주입된 컨텍스트를 바탕으로 할루시네이션(거짓말) 없이 정확한 답변을 도출하는 기능 LLM, Guardrails

자료창고 구축에 필요한 “청킹, 임베딩, 벡터DB”는 “인덱싱 파이프라인” 혹은 “자료창고 구축” 단계에서 다음과 같이 서로 다른 역할을 한다.

의미기반 분할 (청킹) → 텍스트를 의미 단위로 자름
↓
임베딩 → 그 단위를 숫자 벡터로 변환
↓
벡터DB → 그 벡터를 저장해서 검색 가능하게 함

임베딩은 인덱싱 파이프라인에서 청킹과 벡터DB를 이어주는 핵심 기술이다.

지금 구축하려는 불교 자료창고 작업은 위의 표에서 “인덱싱 파이프라인” 단계에 해당하고,
“생성(Generation)”, 즉 실제 챗봇 또는 에이전트가 이 자료를 바탕으로 답하는 부분은 그 다음 단계이다.

실전 — 자료창고를 채우는 방식

데이터 구조 (7개 필드)

json
{
“id”: “heart_sutra_003”,
“source”: “반야심경”,
“text”: “색불이공 공불이색 색즉시공 공즉시색”,
“translation”: “색이 공과 다르지 않고 공이 색과 다르지 않으니, 색이 곧 공이요 공이 곧 색이니라”,
“note”: “이 구절, 예전에 회계 하면서 ‘숫자 뒤의 실체가 뭔가’ 계속 의심했던 거랑 닮았다는 생각이 들었다. 숫자(색)도 결국 약속된 표현일 뿐(공)…”,
“tags”: [“색”, “공”],
“domain”: [“불교”]
}

필드 역할 원칙
id 출처 추적용 고유번호 나중에 “이 답변 어디서 왔나” 역추적할 때 씀
source 원 출처 경전명, 책 제목, “AI주지스님용 대본” 등
text 원문 인용구 또는 원문 그대로
translation 표준/공식 번역 이미 존재하는 해석만. 없으면 null
note 개인적인 해석·감상 항상 이 필드로만. translation과 절대 역할 안 섞임
tags 검색 품질 검증용 개념어 라벨 필수는 아니지만 있으면 유용
domain 자료가 속한 학문 영역 배열. 불교/정신분석/실존철학 등, 융합 자료는 여러 개 조합

핵심 원칙 1 — translation과 note는 출처가 경전이든 일반 책이든 상관없이 역할이 고정된다.

  • 경전처럼 표준 번역이 있는 자료 → translation에 그 표준 번역
  • 학자·스님이 쓴 일반 서적처럼 표준 번역 개념이 없는 자료 → translation은 비우고 note에 감상
  • 경전인데 개인적 감상까지 있는 경우 → translation(표준 번역) + note(개인 감상) 둘 다 채움

이렇게 정리하면, 책이냐 경전이냐에 따라 translation의 성격이 달라지지 않고,
나중에 “개인 감상만 따로 모아 검색”하려는 경우엔 note가 채워진 것만 필터링하면 되므로,
각 필드의 역할이 분명해진다.

핵심 원칙 2 — tags와 domain은 층위가 다르다.

tags는 “오온”, “공” 같은 개념어, domain은 그 자료가 어느 학문 영역(불교/정신분석/실존철학)에 속하는지를 가리키는 상위 분류다.

domain은 불교와 정신분석을 함께 다루는 책처럼 두 영역에 걸친 자료가 실제로 꽤 있어서, [“불교”, “정신분석”]처럼 여러 값을 담을 수 있도록 배열로 설계했다.

청크 크기 — 길이는 무관, 의미 완결성이 기준

임베딩은 한 덩어리의 텍스트 전체 의미를 하나의 벡터로 뭉뚱그리기 때문에, 청크가 길고 여러 주제가 섞일수록 검색 정확도가 흐려진다.

따라서 청크 크기에 대한 판단 기준은 다음과 같다.

“이 덩어리가 하나의 완결된 의미를 담고 있는가?”

  • 반야심경처럼 원문도 짧고 번역도 짧은 경우 → 그대로 구절 단위
  • 붓다 심리학처럼 원문 문단이 긴 경우 → 문단 안에 여러 생각이 섞여 있으면 그 경계에서 쪼갬
  • note(개인 감상)도 마찬가지 — 감상 안에 여러 갈래 생각이 섞이면 검색이 흐려질 수 있음

규모별 접근

불교공부는 매일 1개씩의 자료를 정리하고 창고에 쌓을 계획이나, 이후 다른 분야의 대량 자료를 한꺼번에 창고에 쌓아야 할 일이 생길 수도 있다.

따라서 규모에 따라 어떻게 청킹하고 임베딩, 태깅을 붙일지 등을 정리하면 다음과 같다.

소량 대량
청킹 사람이 직접 읽고 판단 코드로 1차 기계적 분절 → 사람이 표본만 훑으며 조정
저장 형식 JSON / JSONL 동일 (규모 커지면 벡터DB로 이전)
태깅 사람 또는 LLM이 직접 임베딩+클러스터링으로 그룹화 → 대표만 사람/LLM이 이름 붙임 → 나머지 자동 상속
검증 전수 확인 가능 표본 검토 + 검색 결과 사후 모니터링

자료가 적을 땐 모두 사람 또는 LLM이 직접 처리하고, 자료가 많아지면 대표적인 것만 직접 처리하고 나머지는 미리 정한 규칙에 따라 처리한다.

원리는 규모와 무관하게 같다. 단지 “사람이 직접 개입하는 지점”이 매 청크 확인에서 ‘규칙 설계 → 표본 검증 → 사후 모니터링’으로 옮겨갈 뿐이다.

저장 형식 — JSON, 언제까지 쓸 수 있나

JSON 파일 방식의 한계는 검색할 때마다 저장된 모든 항목과 일일이 비교해야 한다는 점(선형 탐색)이다. 규모가 커질수록 이 비교 시간이 점점 늘어난다.

규모 적정 도구
수십~수백 개 JSON 파일로 충분 (체감 속도 차이 없음)
수천 개 JSON도 가능하지만 점점 느려짐
수만 개 이상 ChromaDB 같은 벡터DB 필요 (색인 기반 고속 검색)

※ JSON : 데이터를 표현하는 표기법/규칙(format). 하나의 자료를 “이름표: 값”의 짝으로 정리해서 사람도 읽고 컴퓨터도 정확히 구분해서 읽을 수 있는 텍스트 형식(위의 ‘2-1. 데이터 구조’ 제목 바로 아래의 반야심경 예시)
JSONL : JSON 형식에서 하나의 청크에 대한 정보들(“이름표: 값”들의 묶음)을 줄바꿈 없이 한 줄에 다 쓰고, 다음 청크의 정보는 그다음 줄에 쓰는 형식. 청크 하나가 아직 안 끝났는데 중간에 줄을 바꾸면, 컴퓨터가 그 지점에서 청크가 끝난 걸로 착각해 오류가 남.

기준은 “회사 규모”가 아니라 “쌓인 청크 개수”다.
1인 쇼핑몰이라도 자료가 많으면 JSON으로는 충분하지 않고, 중견기업이라도 챗봇용 자료가 적으면 JSON으로 충분하다.

JSON을 지금 직접 손으로 익히는 이유는 이것이 “작을 때만 쓰는 임시방편”이 아니기 때문이다.
벡터DB도 내부적으로는 거의 같은 구조로 데이터를 저장한다 — 자료 하나마다 고유 id를 붙이고, 그 밑에 원문(text)과 나머지 부가정보(metadata)를 함께 저장한다.
즉 지금 만드는 필드 구조는 나중에 도구가 ChromaDB로 바뀌어도 거의 그대로 이전되고, 바뀌는 건 저장/검색 인프라 뿐이지 원리는 동일하다.

※ 벡터DB에서 말하는 ‘metadata’는 원래의 뜻(자료의 저장 위치와 같은 ‘data에 대한 data’)가 아니라, ‘임베딩(벡터)으로 변환되지 않은 나머지 필드들’을 통틀어 부르는 용어이다. 위의 구조에서는 source, translation, note, tags, domain이 해당.

실제 입력 — 왜 자료를 직접 타이핑하려고 하는가?

기술적으로는 여러 경로가 가능하다(Claude가 대신 작성/엑셀로 표를 만들어 변환/텍스트 편집기에 직접 입력 등).

이번에는 그중 “직접 타이핑 + 검증 도구로 확인” 방법으로 입력하려는데,
이는 내가 지금 하고 있는 AI 주지스님 구축 프로젝트의 목적이 “학습”이란 걸 염두에 두고 한 선택이다.
남이 대신 JSON을 만들어주면 편하긴 하겠지만,
“이 형식이 왜 이렇게 생겼는지” 그 감각은 나에게 쌓이지 않을 거다. 난 노가다의 힘을 믿는다.

  • ‘.JSONL'(JSON Lines) 형식으로 자료를 쌓아갈 계획이다.
    하나의 청크 당 한 줄, 배열 기호([ ]) 없이 파일 맨 아래에 계속 추가하면 된다.
    여러 항목을 배열([ ])로 묶어 한 파일에 담는 JSON 형식과 달리, 마지막 항목 뒤에 콤마를 빠뜨리거나 잘못 추가하는 실수에서 자유롭다.
  • 저장 전 검증: 아래 코드를 ‘check.py’ 같은 이름의 파일로 저장해두고 실행해서, 에러가 나면 그 메시지를 직접 읽고 스스로 고치는 연습을 한다.
import json
with open('파일명.jsonl') as f:
    for line in f:
        json.loads(line)

엑셀은 “다른 이름으로 저장 → .json”이 불가능하다.
엑셀에는 JSON 저장 기능이 없고, 여러 경로를 거쳐 JSON파일로 저장이 가능하긴 하지만
매일 1건씩 자료를 추가해 가는 지금의 상황에선 비효율적이고 학습목적에도 맞지 않는다.
엑셀은 나중에 자료가 수백~수천 개로 늘어나 “전체를 한눈에 훑어보거나 태그별 개수를 세고 싶다” 등의
검토·분석 단계에서 유용하게 될 도구이다.

왜 구조는 고정된 것이 아닌가

위에서 소개한 domain 필드는 사실 처음부터 만들려던 게 아니었다.
워크스루에서 사용한 반야심경 자료는, 순수하게 불교 경전인 까닭에 id, source, text, translation, note, tags 6개 필드로 아무 문제가 없었다.
이 구조를 짤 당시엔 “이 자료창고에 담길 자료는 전부 불교 관련일 것”이라고 생각했었다.

그런데 최근 공부의 방향을 다시 정비하다 보니,
앞으로 오래 공부해보고 싶은 분야가 AI 공부와 함께 불교·정신분석·실존철학이었다.
불교를 파다 보니 정신분석과 맞닿는 지점이 자꾸 나왔고,
오랫동안 관심은 있었으나 제대로 접할 기회가 없었던 정신분석과 실존주의 철학에 대해서도 마음이 가면서,
이 세 분야가 따로가 아니라 서로 계속 얽히며 갈 것 같다는 생각이 들었다.
자료창고에 불교 경전만 쌓는 게 아니라면, 이 세 분야를 구분해 줄 별도의 필드가 필요하지 않을까?
그래서 추가한 필드가 ‘domain’이다.

“오온이 뭔가요?” 같은 순수 교리 질문엔 ‘domain: 불교’로 좁혀서 검색하고,
“요즘 마음이 자꾸 불안해요” 같은 질문엔 경전뿐 아니라 정신분석·실존철학 자료도 함께 검색해서,
주지스님이 경전 인용과 다른 관점의 통찰을 엮어 답할 수 있는 재료가 된다.
주지스님이 항상 경전 구절로만 답해야 한다는 법은 없으니까.

‘translation’와 ‘note’를 나눌 때도, 지금 ‘domain’을 추가할 때도 패턴이 비슷했던 것 같다.
실제로 필요해질 때, 구조를 그 필요에 맞춰 넓힌다.
처음부터 모든 경우의 수를 예상해서 완벽한 스키마를 설계하려 했다면 오히려 과했을 것이다.
반야심경만 다룰 때는 ‘note’와 ‘domain’ 없이도 충분했고, 공부 범위가 넓어지고 나서야 이 필드의 필요가 눈에 보였다.
자료창고의 구조는 한 번 정하면 끝나는 설계도가 아니라, 공부가 진행되는 방향을 따라 같이 넓어지는 것이다.

정리

‘청킹 → 임베딩 → 벡터DB’는 RAG의 “자료창고 구축(인덱싱)” 단계를 이루는 세 조각이고, JSON/JSONL로 손수 채워갈 경전·책·대본 등의 데이터가 바로 이 파이프라인의 출발점이다.
규모가 커지면 도구(벡터DB)와 개입 방식(표본 검토)이 바뀌겠지만, 데이터 구조와 원리는 지금 손으로 익힌 것이 그대로 적용된다.
그리고 창고 구조 자체도 처음부터 고정된 게 아니라, 공부의 방향이 명확해질 때마다 넓어질 수 있다.

Q1. RAG에서 청킹, 임베딩, 벡터DB는 각각 어떤 역할을 하나요?

청킹은 텍스트를 의미 단위로 자르는 작업, 임베딩은 그 조각을 숫자 벡터로 변환하는 기술, 벡터DB는 그 벡터를 저장해서 검색 가능하게 만드는 저장소예요. 셋을 합쳐 “인덱싱 파이프라인” 또는 “자료창고 구축” 단계라고 부르고, 임베딩이 청킹과 벡터DB를 이어주는 다리 역할을 해요.

Q2. RAG용 자료창고를 JSON으로 만들 때, 청크는 어느 정도 크기로 잘라야 하나요?

글자 수보다 “이 덩어리가 하나의 완결된 의미를 담고 있는가”가 우선 기준이 될 수 있어요. 짧은 경전 구절은 그대로, 긴 문단은 여러 생각이 섞이는 지점에서 나누는 식이에요. 청크가 길고 주제가 섞일수록 임베딩 검색 정확도가 흐려지기 쉽다는 게 이 기준의 배경이에요.

Q3. RAG 자료창고, JSON 파일로는 언제까지 쓸 수 있나요?

자료 수십~수백 개 정도는 JSON 파일로 충분하고, 수천 개부터는 점점 느려지며, 수만 개 이상이면 ChromaDB 같은 벡터DB가 필요해질 수 있어요. 기준은 회사나 서비스 규모가 아니라 실제로 쌓인 청크 개수예요.

Q4. JSON과 JSONL은 어떻게 다른가요?

JSON은 자료 하나를 “이름표: 값”의 짝으로 정리하는 표기법이고, JSONL(JSON Lines)은 그 JSON 자료 여러 개를 배열로 묶지 않고 한 줄에 하나씩 나열하는 형식이에요. 자료가 늘어날 때마다 파일 맨 아래에 한 줄만 추가하면 되는 게 특징이에요.

Q5. 벡터DB에서 말하는 metadata는 원래 뜻(파일 저장 위치 같은 부가정보)과 같은 건가요?

아니요, 조금 달라요. 벡터DB 맥락에서 metadata는 “임베딩(벡터)으로 변환되지 않은 나머지 필드들”을 통틀어 부르는 용어예요. 보통 원문(text)이 임베딩 대상이 되는 경우가 많지만, 이것도 설계에 따라 원문과 다른 필드를 함께 묶어 임베딩할 수도 있어요. 어느 쪽이든 임베딩되지 않고 그대로 저장되는 필드들이 metadata이고, 이 정보들이 원문보다 덜 중요하다는 뜻은 아니에요.

Q6. 자료창고의 필드 구조는 한 번 정하면 계속 유지해야 하나요?

꼭 그렇지는 않아요. 처음엔 필요 없어 보였던 필드도, 다루는 자료 범위가 넓어지면서 뒤늦게 필요해질 수 있어요. 구조를 처음부터 완벽하게 설계하려 하기보다, 실제로 필요가 생겼을 때 그에 맞춰 넓혀가는 방식도 가능해요.

관련 글 보기