Spring AI + OpenAI Embeddings + PGVector 기반 RAG 시스템을 구축할 때 가장 중요한 요소가 토큰(token)과 청크(chunk)이다.
문서를 통째로 임베딩하면 비효율적이고 검색 정확도가 떨어지기 때문에, 문서를 먼저 토큰 단위로 쪼개고, 이 토큰들을 일정 단위(청크)로 묶어 처리하는 방식이 필요하다.
이 과정에서 가장 핵심적인 구성 요소가 Token과 Chunk이며, Spring AI의 TokenTextSplitter가 이를 담당한다.
전체 텍스트 파일이나 PDF는 LLM이 한 번에 다루기에는 크고 구조가 복잡하다.
따라서 효과적인 검색을 위해 여러 의미 단위로 분할해야 한다.
텍스트를 LLM이 계산하기 좋은 최소 단위로 나눈 조각이다.
한국어의 경우 단어가 아니라 음절·부분 단위로 나뉘기 때문에 토큰 개수가 더 많아질 수 있다.
예시
“홍길동은 의적이다.” → “홍”, “길”, “동”, “은”, “의”, “적”, “이다”, “.”
모델별 토크나이저 차이 때문에 같은 문장을 입력해도 토큰 수는 달라진다.
따라서 동일 설정에서도 결과가 달라질 수 있다.
| 모델 | 토크나이저 | 특징 |
|---|---|---|
| GPT-4, GPT-4o | tiktoken | 영어 중심, 한국어는 더 잘게 분리 |
| Claude 3.5 | SentencePiece 변형 | 한국어를 비교적 큰 단위로 묶음 |
| Gemini | SentencePiece | 다국어 처리에 안정적 |
| Llama 3 | BPE 기반 SentencePiece | 오픈소스 기반 |
여러 토큰을 묶어 만든 의미 단위이다.
RAG 시스템의 실제 임베딩과 검색은 청크 단위로 이루어진다.
청크 하나 = 보통 800~1000 토큰 정도
(한국어 기준 약 500~800 단어, A4 1~2페이지 분량)
Spring AI의 TokenTextSplitter는
문서를 토큰 기준으로 자연스럽게 나누는 기능을 담당한다.
new TokenTextSplitter(
int chunkSize,
int chunkOverlap,
int minChunkSize,
int maxChunkSize,
boolean keepSeparators
)
Spring AI 공식 기본값은 아래와 같다.
| 옵션 | 기본값 | 설명 |
|---|---|---|
| chunkSize | 500 | 청크 하나의 최대 크기(토큰 단위) |
| chunkOverlap | 50 | 청크 간 겹치는 토큰 수 |
| minChunkSize | 100 | 이보다 작은 청크는 버린다 |
| maxChunkSize | Integer.MAX_VALUE | 최대 청크 크기 제한 |
| keepSeparators | false | 구분자(개행·마침표 등)를 청크에 포함하지 않음 |
즉, 기본 설정만 적용해도 문서를 일정한 의미 단위로 잘라주는 동작을 수행할 수 있다.
청크가 너무 작으면 의미가 분산되고, 너무 크면 검색이 정확하지 않다.
청크 하나를 만들 때 포함할 최대 토큰 수.
예: chunkSize=1000 → 청크 하나는 최대 1000 tokens.
Overlap은 문맥 끊김을 방지하기 위해 (문맥 보존을 위해)
앞 청크의 일부를 다음 청크에 포함하는 필수적인 값으로 보통 200~400 정도가 안정적이다.
예
Chunk1: A B C D E F G
Chunk2: E F G H I J K
구분자(개행·마침표 등)를 포함할지 여부.
기본값은 false이지만, 보통 문맥 보존을 위해 true로 두는 경우가 많다.
1) 웹사이트 크롤링
URL을 입력해 HTML을 텍스트로 변환한다.
이 단계에서는 robots.txt, 서비스 약관, 저작권 제한 등을 반드시 고려해야 한다.
2) TokenTextSplitter로 청크 분리
크롤링한 텍스트를 의미 단위로 나눈다.
이 과정을 통해 긴 문서를 효율적으로 처리할 수 있다.
3) 청크별 임베딩 생성
각 청크는 OpenAI Embeddings 모델을 통해 1536차원 벡터로 변환된다.
4) PGVector DB에 저장
각 벡터는 Postgres + pgvector 확장 기능으로 저장된다.
5) 사용자의 질문도 임베딩
질문을 벡터로 변환한다.
6) similaritySearch로 연관 청크 조회
DB에서 질문 벡터와 가장 유사한 청크를 topK만큼 검색한다.
7) 검색된 청크를 Prompt에 포함
LLM은 전체 문서가 아니라 관련 조각만 참고한다.
8) 최종 답변 생성
문서의 특정 부분을 중심으로 정확한 답변을 생성할 수 있다.