RAG 자료창고 짓기 전 알아야 할 것들

📚 이 글은 마인크래프트 AI 주지스님 워크스루 4편입니다.

① 서피스프로8에서 SLM 가볍게 테스트 – Ollama로 1.5B~3B 모델 로컬 실행해보기
② SLM에게 참고자료를 줬더니, 3B와 8B가 다르다 – Llama 3B vs. 8B RAG 테스트 비교
③ RAG는 결국 ‘프롬프트를 잘 만들어 주는 도구’네
④ RAG 자료창고 짓기 전 알아야 할 것들
⑤ 임베딩을 오해하며 이해하기
⑥ 질문에서 답까지 – RAG 파이프라인, 로컬에서 완성
⑦ 같은 질문, 다른 크기 — 1B/3B/8B가 반야심경에 답하다

RAG는 ①코드가 자동으로 자료창고에서 게임참가자의 질문과 관련된 구절을 찾아오고(검색), ②그 구절과 게임참가자의 질문을 합쳐서 만든 프롬프트를(조립), ③인공지능 모델에게 보내서 받은 답을 주지스님의 대사로 화면에 출력(생성)해 주는 순서로 구현된다.

지난 글에서는, 답변을 위한 참고자료를 질문과 함께 프롬프트로 주면 SLM 중 8B는 참고자료을 활용해서 적절한 답변을 한다는 걸 테스트로 확인했다는 내용을 정리했는데, 참고자료를 질문과 함께 프롬프트로 만들어서 SLM에 입력하는 과정을 “손으로” 직접 했었다.

이제는 코드가 자동으로 자료창고에서 질문과 관련된 자료를 찾아서 프롬프트를 조립하고, 그 프롬프트를 인공지능에게 보내서 받은 답을 화면에 보여주도록 만들어 볼 차례다.

그런데 창고가 없다.

질문에 답을 하기 위해 자료를 찾아오려면 먼저 “자료창고”가 있어야겠지?
어어.. 근데 그 자료창고는 이제 내가 만들어야 한다.
마인크래프트에 사찰을 짓고 주지스님을 AI로 만들어 보자고 했으니 불교 자료를 쌓아야 하는데, 이게 어디 하루 이틀에 뚝딱 될 일인가.

그리고 좋은 답변을 얻기 위한 참고자료들을 쌓는 거라면, 코드가 작동하는 방식에 따라서 효과적이고 효율적으로 자료들을 쌓아야 할 텐데..
그럼 코드가 질문에 답하기 위한 자료를 검색해서 찾아오는 로직을 알아야 자료창고를 잘 지을 수 있을 거 같다.
코드가 검색할 수 있는 자료의 형태는 뭔지, 그 중 질문에 어떤 자료가 가장 적절한 건지 판단하는 방법은 뭔지..

뭐부터 해야 하는 거지?

그리고 또 한가지 걱정되는 건..
SLM은 자체 지식이 얕아서 부실한 창고에서 검색해 온 자료로는 엉뚱한 답변을 그럴 듯하게 할 가능성이 많은데, 이 불교자료창고를 어느 정도로 가득 채워야 SLM이 신뢰성 있는 답변을 할 수 있는 건지 가늠이 되지 않았다.

문제를 정리해 보면, 두 가지다.
“검색 메커니즘” 자체에 대한 이해와 “자료창고의 범위와 품질” 문제에 대한 고민.
일단 검색 메커니즘에 대한 이해를 제대로 해야,
자료창고를 만들고 품질 좋은 자료로 채울 수 있을 것 같다.

그래서 우선은 반야심경 텍스트만으로 작은 창고를 만들고,
검색 코드를 만들어서 질문과 관련된 구절을 제대로 찾아오는지 확인해보는 간단한 실습을 하면서 검색 메커니즘을 이해해 보려고 한다.
이후에 창고를 넓혀가면서 검색 품질이 어떻게 달라지는지,
또 창고가 부실할 때 SLM이 어떻게 그럴듯한 답변을 만들어 내는지 관찰해 봐야지.

더 나아가
같은 창고를 이용해서 더 좋은 답변을 만들어 낼 수 있는 방법들엔 어떤 것이 있는지,
비슷한 규모의 창고를 좀더 알찬 자료로 채울 수 있는 또 다른 방법들은 없는지,
같은 참고자료를 가지고 SLM이 더 나은 답을 할 수 있게 튜닝할 수 있는 방법은 어떤 게 있는지..
시간을 두고 찾아보고 확인해 봐야지.

오늘은 일단 미니 창고를 지으려고 한다.

반야심경 텍스트로 미니 창고 짓기

반야심경 창고에 들어갈 내용은 반야심경 원문 260자와 해설본인데, 창고가 작으니 JSON 파일로 만들기로 했다.
규모가 커지면 ChromaDB 같은 벡터 데이터베이스가 필요해질 수도 있겠지만, 지금은 JSON이나 CSV 파일로 충분하단다.

반야심경 원문과 해설본을 몇 개의 덩어리로 끊어서 자료창고에 저장하게 되는데,
사람이 여러 종류의 버전이 존재하는 해설본 중 적절하다고 판단되는 것을 선택하면,
코드로 자동화해 둔 방법에 따라 원문과 해설본을 나누고 구조화한다.
아래와 같은 식으로..

json{
“id”: “heart_sutra_001”,
“source”: “반야심경”,
“text”: “관자재보살 행심반야바라밀다시 조견오온개공 도일체고액”,
“translation”: “관자재보살이 깊은 반야바라밀다를 행할 때, 오온이 모두 공함을 비추어 보고 온갖 고통에서 건너느니라”,
“tags”: [“오온”, “공”, “관자재보살”]
}

  • id: “이 답변은 어디서 나왔는가”를 추적하기 위한 장치
  • 원문 + 번역: 한자 원문 검색이든 한글 뜻 검색이든 둘 다 대응하려고 같이 넣음
  • tags: 나중에 검색 결과가 왜 뽑혔는지 눈으로 확인할 때 쓰는 힌트
  • 청킹 단위: 반야심경은 짧아서 구절 단위(한 소절)로 나누는 게 자연스러웠음

여기서 이해가 정확히 되지 않았던 건, 덩어리를 어떻게 나누는게 적절한가였다.
RAG에서 중요한 건 “한 덩어리(chunk)가 의미적으로 완결되어 있는가”라고 한다.
뒤에 알게 됐지만,
이렇게 덩어리로 나누는 작업을 “청킹(chunking)”이라고 부르는데,
이 한 덩어리가 하나의 숫자벡터로 표시되는 임베딩의 단위이고,
이건 학습된 인공지능 모델이 그 덩어리의 ‘의미’를 읽어서 숫자로 압축해낸 결과이다.

그러니 창고 안의 그 많은 자료들 중,
질문과 가장 관련 있는 구절이 어느 것인지를 판단하는 기준이 ‘의미’를 표현하는 숫자벡터임을 고려하면,
의미를 가장 잘 표현할 수 있도록 덩어리를 나누는 것이 검색에 가장 중요한 요소인 것 같다.
너무 크면 검색이 부정확해지고, 너무 잘게 쪼개면 문맥이 끊긴다고.
이번 test에서는 위의 예처럼 한 소절이 한 뜻 덩어리가 되도록 잘라서 자료창고인 JSON 파일을 만들었다.

이 외에도 좋은 자료를 만들기 위해 반야심경의 번역본이 적절한지, tag가 적절한지를 고려해야 했지만,
이번엔 검색 메커니즘 자체를 이해하는 게 우선이라 판단해서 일단 미뤄뒀다.
해당 개념들이 실제로 검색의 품질에 어떤 영향을 미칠지는 이후 더 깊은 공부를 통해서 알아볼 생각이다.

마무리

RAG는 결국 “검색해온 자료를 근거로 답한다”는 구조인데,
자료 자체가 부정확하거나 일관성이 없으면 아무리 검색 알고리즘이 좋아도 틀린 근거를 정확하게 찾아서,
그걸 바탕으로 그럴듯하게 틀린 답을 만드는 상황이 생긴다.

“Garbage in, garbage out”
그러니 좋은 답변을 위해선 좋은 자료를 잘 구조화시켜서 쌓아야 해.

다음 글에서는 “그럼 이 벡터라는 숫자는 어떻게 만들어지는가”에 대해 정리할 예정이다.

Q. RAG에서 “청킹(chunking)”이란 무엇이고, 왜 중요한가요?

A. 청킹은 원본 자료를 검색 가능한 작은 단위(덩어리)로 나누는 작업입니다. 이렇게 나뉜 한 덩어리가 하나의 숫자벡터로 표현되는 임베딩의 단위가 되기 때문에, 덩어리가 의미적으로 완결되어 있어야 검색 결과의 정확도가 높아집니다. 청킹이 부적절하면 아무리 검색 알고리즘이 좋아도 질문과 무관한 자료가 검색되는 문제가 생깁니다.

Q. 청크(chunk) 크기는 어떻게 정하는 게 적절한가요?

A. 정답은 자료의 성격에 따라 다르지만, 일반적인 원칙은 있습니다. 덩어리가 너무 크면 여러 의미가 섞여서 검색 결과가 부정확해지고, 반대로 너무 잘게 쪼개면 문맥이 끊겨서 의미를 온전히 담지 못하게 됩니다. 그래서 한 덩어리가 하나의 뜻으로 완결되는 지점을 찾는 것이 청킹의 핵심 기준입니다.

Q. RAG 시스템에서 “Garbage in, garbage out”은 어떤 의미인가요?

A. RAG는 결국 검색해온 자료를 근거로 답을 만드는 구조이기 때문에, 원본 자료 자체가 부정확하거나 일관성이 없으면 검색 알고리즘이 아무리 정확해도 잘못된 근거를 정확하게 찾아와 그럴듯하게 틀린 답을 만들게 됩니다. 따라서 좋은 답변을 얻으려면 검색 알고리즘 못지않게 자료 자체의 품질과 구조화에 신경 써야 합니다.

관련 글 보기