토큰(Token)과 청크(Chunk)

김소희·2025년 11월 25일

Spring AI + OpenAI Embeddings + PGVector 기반 RAG 시스템을 구축할 때 가장 중요한 요소가 토큰(token)과 청크(chunk)이다.
문서를 통째로 임베딩하면 비효율적이고 검색 정확도가 떨어지기 때문에, 문서를 먼저 토큰 단위로 쪼개고, 이 토큰들을 일정 단위(청크)로 묶어 처리하는 방식이 필요하다.
이 과정에서 가장 핵심적인 구성 요소가 Token과 Chunk이며, Spring AI의 TokenTextSplitter가 이를 담당한다.


문서(Document)

전체 텍스트 파일이나 PDF는 LLM이 한 번에 다루기에는 크고 구조가 복잡하다.
따라서 효과적인 검색을 위해 여러 의미 단위로 분할해야 한다.


토큰(Token)

텍스트를 LLM이 계산하기 좋은 최소 단위로 나눈 조각이다.
한국어의 경우 단어가 아니라 음절·부분 단위로 나뉘기 때문에 토큰 개수가 더 많아질 수 있다.

예시
“홍길동은 의적이다.” → “홍”, “길”, “동”, “은”, “의”, “적”, “이다”, “.”

모델별 토크나이저 차이 때문에 같은 문장을 입력해도 토큰 수는 달라진다.
따라서 동일 설정에서도 결과가 달라질 수 있다.

모델토크나이저특징
GPT-4, GPT-4otiktoken영어 중심, 한국어는 더 잘게 분리
Claude 3.5SentencePiece 변형한국어를 비교적 큰 단위로 묶음
GeminiSentencePiece다국어 처리에 안정적
Llama 3BPE 기반 SentencePiece오픈소스 기반

청크(Chunk)

여러 토큰을 묶어 만든 의미 단위이다.
RAG 시스템의 실제 임베딩과 검색은 청크 단위로 이루어진다.

청크 하나 = 보통 800~1000 토큰 정도
(한국어 기준 약 500~800 단어, A4 1~2페이지 분량)


TokenTextSplitter가 청크를 나누는 방식

Spring AI의 TokenTextSplitter
문서를 토큰 기준으로 자연스럽게 나누는 기능을 담당한다.

TokenTextSplitter의 시그니처

new TokenTextSplitter(
    int chunkSize,
    int chunkOverlap,
    int minChunkSize,
    int maxChunkSize,
    boolean keepSeparators
)

TokenTextSplitter의 디폴트값

Spring AI 공식 기본값은 아래와 같다.

옵션기본값설명
chunkSize500청크 하나의 최대 크기(토큰 단위)
chunkOverlap50청크 간 겹치는 토큰 수
minChunkSize100이보다 작은 청크는 버린다
maxChunkSizeInteger.MAX_VALUE최대 청크 크기 제한
keepSeparatorsfalse구분자(개행·마침표 등)를 청크에 포함하지 않음

즉, 기본 설정만 적용해도 문서를 일정한 의미 단위로 잘라주는 동작을 수행할 수 있다.
청크가 너무 작으면 의미가 분산되고, 너무 크면 검색이 정확하지 않다.


TokenTextSplitter 옵션 상세 설명

chunkSize

청크 하나를 만들 때 포함할 최대 토큰 수.
예: chunkSize=1000 → 청크 하나는 최대 1000 tokens.

chunkOverlap

Overlap은 문맥 끊김을 방지하기 위해 (문맥 보존을 위해)
앞 청크의 일부를 다음 청크에 포함하는 필수적인 값으로 보통 200~400 정도가 안정적이다.

Chunk1: A B C D E F G  
Chunk2:        E F G H I J K

minChunkSize / maxChunkSize

  • 너무 작은 청크는 버리고
  • 너무 큰 청크는 강제 분할해 정제된 데이터만 임베딩한다.

keepSeparators

구분자(개행·마침표 등)를 포함할지 여부.
기본값은 false이지만, 보통 문맥 보존을 위해 true로 두는 경우가 많다.


RAG 전체 흐름 (웹사이트 크롤링 예제 기준)

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) 최종 답변 생성
문서의 특정 부분을 중심으로 정확한 답변을 생성할 수 있다.


핵심 요약

  • 토큰은 LLM이 이해하는 최소 단위
  • 청크는 토큰 여러 개를 묶은 의미 단위
  • RAG에서의 검색 및 임베딩 단위는 문서 전체가 아니라 청크
  • TokenTextSplitter는 청크 생성의 핵심
  • 디폴트값 chunkSize=500, overlap=50을 기준으로 동작
  • PGVector는 청크 임베딩을 저장·검색하는 역할
  • 청크 설계에 따라 검색 정확도와 답변 품질이 크게 달라진다
profile
백엔드 개발자의 노트

0개의 댓글