좋은 아침입니다.
Similarity Search를 사용하면 사용자의 질문과 의미적으로 가까운 문서를 검색할 수 있습니다.
하지만 긴 문서를 하나의 Embedding Vector로 변환하면 여러 주제와 정보가 하나의 Vector에 함께 포함될 수 있습니다.
이 경우 질문과 관련된 특정 내용을 정확하게 검색하기 어려워집니다.
이번 글에서는 긴 문서를 검색하기 좋은 작은 단위로 나누는 Chunking에 대해 알아보겠습니다.
하나의 문서에는 여러 주제가 함께 포함될 수 있습니다.
예를 들어 회사 규정 문서에 다음과 같은 내용이 있다고 가정하겠습니다.
회사 규정 문서
- 연차 신청 방법
- 급여 지급일
- 출장비 처리 방법
- 회의실 사용 규정
이 문서 전체를 하나의 Embedding Vector로 변환하면 여러 내용이 하나의 Vector에 함께 표현됩니다.
사용자가 연차 신청 방법을 질문하더라도 다른 내용의 영향을 받아 관련 문서를 정확하게 찾기 어려울 수 있습니다.
또한 긴 문서 전체가 검색되면 LLM에 필요하지 않은 정보까지 함께 전달됩니다.
사용자 질문 : "연차는 어떻게 신청하나요?"
LLM에 전달되는 문서
- 연차 신청 방법
- 급여 지급일
- 출장비 처리 방법
- 회의실 사용 규정
불필요한 정보가 많아지면 Context가 길어지고, 답변 생성에 필요한 비용과 시간도 증가할 수 있습니다.
이러한 문제를 줄이기 위해 긴 문서를 여러 개의 작은 조각으로 나눕니다.
Chunking은 긴 문서를 검색하기 좋은 작은 단위로 나누는 과정입니다.
이렇게 나누어진 각각의 문서 조각을 Chunk라고 합니다.
긴 문서
↓
Chunking
↓
Chunk 1
Chunk 2
Chunk 3
예를 들어 회사 규정 문서를 주제별로 나누면 다음과 같습니다.
Chunk 1 (연차 신청 방법)
Chunk 2 (급여 지급일)
Chunk 3 (출장비 처리 방법)
Chunk 4 (회의실 사용 규정)
각 Chunk는 별도의 Embedding Vector로 변환되어 저장됩니다.
사용자의 질문이 들어오면 전체 문서가 아니라 질문과 관련된 Chunk를 검색할 수 있습니다.
사용자 질문 "연차는 어떻게 신청하나요?"
↓
검색 결과 : Chunk 1 (연차 신청 방법)
이를 통해 검색의 정확도를 높이고 LLM에 필요한 정보만 전달할 수 있습니다.
Chunk Size는 하나의 Chunk에 포함되는 텍스트의 크기를 의미합니다.
Chunk Size는 문자 수나 Token 수를 기준으로 설정할 수 있습니다.
Chunk Size = 200 Token
→ 하나의 Chunk에 최대 200개의 Token 포함
Chunk Size가 너무 크거나 너무 작으면 검색 품질에 영향을 줄 수 있습니다.
하나의 Chunk에 더 많은 문맥을 포함할 수 있습니다.
질문에 대한 정보가 여러 문장에 걸쳐 있을 때 전체 내용을 함께 검색할 수 있습니다.
하지만 하나의 Chunk에 여러 주제가 포함될 가능성이 커집니다.
또한 검색된 Chunk가 길어지면서 LLM에 전달되는 Context와 처리 비용도 증가할 수 있습니다.
하나의 Chunk가 특정 내용에 집중하기 때문에 세부적인 정보를 검색하기 쉽습니다.
검색된 문서의 불필요한 내용도 줄일 수 있습니다.
하지만 하나의 의미가 여러 Chunk로 나뉘면 필요한 문맥이 사라질 수 있습니다.
원래 문장 :
"연차는 사내 시스템에서 신청한 뒤
팀장의 승인을 받아야 합니다."
너무 작게 나눈 경우
Chunk 1: 연차는 사내 시스템에서 신청한 뒤
Chunk 2: 팀장의 승인을 받아야 합니다.
질문에 답하기 위해 필요한 정보가 여러 Chunk에 분리되면 검색된 하나의 Chunk만으로는 내용을 이해하기 어려울 수 있습니다.
따라서 문서의 구조와 질문의 특성을 고려하여 적절한 Chunk Size를 설정해야 합니다.
Chunk Overlap은 서로 인접한 Chunk가 일부 내용을 겹쳐서 가지도록 만드는 방법입니다.
Chunk 1
[ A B C D ]
Chunk 2
[ C D E F ]
위 예시에서는 C D가 두 Chunk에 모두 포함됩니다.
Chunk Overlap을 사용하면 Chunk의 경계에서 문장이 잘리더라도 앞뒤 문맥을 어느 정도 유지할 수 있습니다.
Chunk 1 :
연차는 사내 시스템에서 신청한 뒤
팀장의 승인을 받아야 합니다.
Chunk 2 :
팀장의 승인을 받아야 합니다.
승인이 완료되면 연차를 사용할 수 있습니다.
하지만 Overlap이 너무 크면 같은 내용이 여러 Chunk에 반복해서 저장됩니다.
이는 저장 공간을 증가시키고 비슷한 Chunk가 검색 결과에 중복으로 나타나는 원인이 될 수 있습니다.
Chunk 사이의 문맥을 더 많이 유지할 수 있습니다.
중요한 문장이 Chunk의 경계에서 잘리는 문제를 줄일 수 있습니다.
하지만 중복되는 텍스트가 많아져 저장해야 하는 Embedding Vector의 수도 증가합니다.
검색 결과에 비슷한 내용의 Chunk가 반복해서 포함될 수도 있습니다.
중복되는 텍스트와 저장 공간을 줄일 수 있습니다.
하지만 Chunk의 경계에서 문장이 잘리면 앞뒤 문맥이 분리될 수 있습니다.
Overlap을 전혀 사용하지 않으면 필요한 정보가 두 Chunk에 나뉘는 문제가 더 자주 발생할 수 있습니다.
Fixed-Size Chunking은 일정한 문자 수나 Token 수를 기준으로 문서를 나누는 방법입니다.
Chunk Size = 100 Token
Chunk 1: 1~100 Token
Chunk 2: 101~200 Token
Chunk 3: 201~300 Token
구현이 단순하고 빠르지만 문장이나 문단 중간에서 내용이 잘릴 수 있습니다.
Recursive Chunking은 문단, 줄바꿈, 문장과 같은 구분자를 순서대로 사용하여 문서를 나누는 방법입니다.
1. 문단을 기준으로 분리
2. Chunk가 너무 크면 문장으로 분리
3. 그래도 크면 단어 단위로 분리
Fixed-Size Chunking보다 문서의 구조를 유지하기 쉽습니다.
Semantic Chunking은 텍스트의 의미 변화를 기준으로 Chunk를 나누는 방법입니다.
주제가 비슷한 문장은 하나의 Chunk로 묶고, 주제가 달라지는 지점에서 새로운 Chunk를 생성합니다.
연차 신청과 관련된 문장
→ 하나의 Chunk
급여 지급과 관련된 문장
→ 새로운 Chunk
문맥을 유지하는 데 도움이 되지만, 문장의 의미를 비교하는 추가 연산이 필요하므로 구조가 복잡해질 수 있습니다.
RAG에서는 원본 문서를 Chunk로 나눈 뒤 각 Chunk를 Embedding Vector로 변환합니다.
1. 원본 문서 불러오기
2. 문서를 여러 Chunk로 분리
3. 각 Chunk를 Embedding Vector로 변환
4. 원본 Chunk와 Vector 저장
5. 사용자 질문 입력
6. 질문과 유사한 Chunk 검색
7. 검색된 Chunk를 LLM에 전달
각 Chunk에는 원본 문서의 이름, 페이지와 제목 같은 Metadata를 함께 저장할 수 있습니다.
Chunk 내용 : "연차는 사내 시스템에서 신청해야 합니다."
Metadata
문서명: 사내 규정
페이지: 12
제목: 연차 신청
Metadata를 함께 저장하면 검색된 내용이 어떤 문서에서 가져온 것인지 확인하거나 답변에 출처를 표시할 수 있습니다.
이번 글에서는 Chunking에 대해 알아보았습니다.
핵심 내용을 정리하면 다음과 같습니다.
Chunking은 긴 문서를 검색하기 좋은 작은 단위로 나누는 과정입니다.
Chunking으로 나누어진 각각의 문서 조각을 Chunk라고 합니다.
Fixed-Size Chunking은 일정한 문자 수나 Token 수를 기준으로 문서를 나눕니다.
Recursive Chunking은 문단과 문장 같은 문서 구조를 기준으로 나눕니다.
Semantic Chunking은 텍스트의 의미가 변하는 지점을 기준으로 나눕니다.
RAG의 검색 품질은 Chunk Size, Chunk Overlap과 Chunking 방법에 영향을 받습니다.
다음 글에서는 Chunk와 Embedding Vector를 저장하고 검색하는 Vector Database에 대해 알아보겠습니다.
Vector Database는 많은 Embedding Vector를 저장하고, 사용자의 질문과 가까운 Vector를 빠르게 검색하기 위한 데이터베이스입니다.
부족한 글 읽어주셔서 감사합니다.
틀린 내용이나 피드백은 댓글로 남겨주시면 감사하겠습니다.
감사합니다.