토큰 단위 텍스트 분할
토큰 단위 텍스트 분할 (TokenTextSplitter)
언어 모델에는 토큰 제한이 있어요. 텍스트를 청크로 나눌 때 이 제한을 넘지 않도록, 청크 안의 토큰 수를 세는 게 좋은 습관이에요. 토크나이저는 종류가 많은데, 실제 언어 모델이 쓰는 것과 같은 토크나이저로 토큰을 세어야 정확해요. 이 페이지에서는 tiktoken, spaCy, SentenceTransformers, NLTK, KoNLPy, Hugging Face 토크나이저를 활용해 토큰 기준으로 분할하는 방법을 함께 살펴볼게요.
출처: 공식문서
tiktoken
tiktoken은
OpenAI가 만든 빠른BPE토크나이저예요.
원본 텍스트를 청크로 쪼갠 뒤 tiktoken으로 토큰 수를 합치려면 분할기의 .from_tiktoken_encoder() 메서드를 쓰면 돼요. OpenAI 모델에서는 이 방식이 더 정확할 거예요.
- 텍스트를 어떻게 나누나: 전달한 문자 기준.
- 청크 크기를 어떻게 재나:
tiktoken토크나이저 기준.
CharacterTextSplitter, RecursiveCharacterTextSplitter, TokenTextSplitter를 tiktoken과 함께 바로 사용할 수 있어요.
pip install --upgrade --quiet langchain-text-splitters tiktoken
from langchain_text_splitters import CharacterTextSplitter
# This is a long document we can split up.
with open("state_of_the_union.txt") as f:
state_of_the_union = f.read()
CharacterTextSplitter로 나누고 나서 tiktoken으로 청크를 합치려면 .from_tiktoken_encoder()를 사용해요. 이 메서드로 만든 분할 결과는 tiktoken 토크나이저가 재는 청크 크기보다 클 수 있다는 점을 주의해야 해요.
.from_tiktoken_encoder() 메서드는 인자로 encoding_name(예: cl100k_base)이나 model_name(예: gpt-4)을 받아요. chunk_size, chunk_overlap, separators 같은 나머지 인자는 CharacterTextSplitter를 만드는 데 그대로 사용돼요.
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
encoding_name="cl100k_base", chunk_size=100, chunk_overlap=0
)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and the Cabinet. Justices of the Supreme Court. My fellow Americans.
Last year COVID-19 kept us apart. This year we are finally together again.
Tonight, we meet as Democrats Republicans and Independents. But most importantly as Americans.
With a duty to one another to the American people to the Constitution.
청크 크기에 하드 제약을 걸고 싶다면 RecursiveCharacterTextSplitter.from_tiktoken_encoder를 쓰면 돼요. 이 경우 어느 분할이든 크기가 더 크면 재귀적으로 다시 나뉘어요.
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
model_name="gpt-4",
chunk_size=100,
chunk_overlap=0,
)
tiktoken과 직접 동작하며 모든 분할이 청크 크기보다 작음을 보장하는 TokenTextSplitter도 쓸 수 있어요.
from langchain_text_splitters import TokenTextSplitter
text_splitter = TokenTextSplitter(chunk_size=10, chunk_overlap=0)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
Madam Speaker, Madam Vice President, our
중국어·일본어처럼 한 글자가 두 개 이상의 토큰으로 인코딩되는 언어가 있어요. TokenTextSplitter를 직접 쓰면 한 문자의 토큰이 두 청크로 나뉘어 잘못된 유니코드 문자가 생길 수 있죠. 이런 경우엔 RecursiveCharacterTextSplitter.from_tiktoken_encoder나 CharacterTextSplitter.from_tiktoken_encoder를 써서 청크에 온전한 유니코드 문자열이 들어가도록 해야 해요.
js-tiktoken
js-tiktoken은
OpenAI가 만든BPE토크나이저의 JavaScript 버전이에요.
npm install @langchain/textsplitters
pnpm install @langchain/textsplitters
yarn add @langchain/textsplitters
bun add @langchain/textsplitters
import { TokenTextSplitter } from "@langchain/textsplitters";
import { readFileSync } from "fs";
// Example: read a long document
const stateOfTheUnion = readFileSync("state_of_the_union.txt", "utf8");
TokenTextSplitter로 나누고 tiktoken으로 합치려면 초기화할 때 encodingName(예: cl100k_base)을 전달해요. 이 메서드로 만든 분할 결과는 tiktoken 토크나이저가 재는 청크 크기보다 클 수 있다는 점을 주의해야 해요.
import { TokenTextSplitter } from "@langchain/textsplitters";
// Example: use cl100k_base encoding
const splitter = new TokenTextSplitter({ encodingName: "cl100k_base", chunkSize: 10, chunkOverlap: 0 });
const texts = splitter.splitText(stateOfTheUnion);
console.log(texts[0]);
Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and the Cabinet. Justices of the Supreme Court. My fellow Americans.
Last year COVID-19 kept us apart. This year we are finally together again.
Tonight, we meet as Democrats Republicans and Independents. But most importantly as Americans.
With a duty to one another to the American people to the Constitution.
spaCy
spaCy는 Python과 Cython으로 작성된 고급 자연어 처리를 위한 오픈소스 라이브러리예요.
LangChain은 spaCy 토크나이저 기반 분할기를 구현해요.
- 텍스트를 어떻게 나누나:
spaCy토크나이저 기준. - 청크 크기를 어떻게 재나: 문자 수 기준.
pip install --upgrade --quiet spacy
# This is a long document we can split up.
with open("state_of_the_union.txt") as f:
state_of_the_union = f.read()
from langchain_text_splitters import SpacyTextSplitter
text_splitter = SpacyTextSplitter(chunk_size=1000)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
Madam Speaker, Madam Vice President, our First Lady and Second Gentleman.
Members of Congress and the Cabinet.
Justices of the Supreme Court.
My fellow Americans.
Last year COVID-19 kept us apart.
This year we are finally together again.
Tonight, we meet as Democrats Republicans and Independents.
But most importantly as Americans.
With a duty to one another to the American people to the Constitution.
And with an unwavering resolve that freedom will always triumph over tyranny.
Six days ago, Russia’s Vladimir Putin sought to shake the foundations of the free world thinking he could make it bend to his menacing ways.
But he badly miscalculated.
He thought he could roll into Ukraine and the world would roll over.
Instead he met a wall of strength he never imagined.
He met the Ukrainian people.
From President Zelenskyy to every Ukrainian, their fearlessness, their courage, their determination, inspires the world.
SentenceTransformers
SentenceTransformersTokenTextSplitter는 sentence-transformer 모델용으로 특화된 분할기예요. 기본 동작은 사용하려는 sentence-transformer 모델의 토큰 윈도우에 맞는 청크로 텍스트를 나누는 거예요. 선택적으로 지정할 수 있는 값은 다음과 같아요.
chunk_overlap: 토큰 단위 중첩 개수.
from langchain_text_splitters import SentenceTransformersTokenTextSplitter
splitter = SentenceTransformersTokenTextSplitter(chunk_overlap=0)
text = "Lorem "
count_start_and_stop_tokens = 2
text_token_count = splitter.count_tokens(text=text) - count_start_and_stop_tokens
print(text_token_count)
2
token_multiplier = splitter.maximum_tokens_per_chunk // text_token_count + 1
# `text_to_split` does not fit in a single chunk
text_to_split = text * token_multiplier
print(f"tokens in text to split: {splitter.count_tokens(text=text_to_split)}")
tokens in text to split: 514
text_chunks = splitter.split_text(text=text_to_split)
print(text_chunks[1])
lorem
NLTK
자연어 처리 툴킷(The Natural Language Toolkit), 흔히 NLTK는 Python으로 작성된 영어용 기호·통계 자연어 처리(NLP) 라이브러리 묶음이에요.
단순히 "\n\n"으로만 나누는 대신, NLTK의 토크나이저를 활용해 문장 단위로 나눌 수 있어요.
- 텍스트를 어떻게 나누나:
NLTK토크나이저 기준. - 청크 크기를 어떻게 재나: 문자 수 기준.
# pip install nltk
# This is a long document we can split up.
with open("state_of_the_union.txt") as f:
state_of_the_union = f.read()
from langchain_text_splitters import NLTKTextSplitter
text_splitter = NLTKTextSplitter(chunk_size=1000)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
Madam Speaker, Madam Vice President, our First Lady and Second Gentleman.
Members of Congress and the Cabinet.
Justices of the Supreme Court.
My fellow Americans.
Last year COVID-19 kept us apart.
This year we are finally together again.
Tonight, we meet as Democrats Republicans and Independents.
But most importantly as Americans.
With a duty to one another to the American people to the Constitution.
And with an unwavering resolve that freedom will always triumph over tyranny.
Six days ago, Russia’s Vladimir Putin sought to shake the foundations of the free world thinking he could make it bend to his menacing ways.
But he badly miscalculated.
He thought he could roll into Ukraine and the world would roll over.
Instead he met a wall of strength he never imagined.
He met the Ukrainian people.
From President Zelenskyy to every Ukrainian, their fearlessness, their courage, their determination, inspires the world.
Groups of citizens blocking tanks with their bodies.
KoNLPy
KoNLPy는 한국어 자연어 처리(NLP)를 위한 Python 패키지예요.
토큰 분할은 텍스트를 더 작고 다루기 쉬운 '토큰' 단위로 나누는 것인데, 이 토큰은 흔히 단어·구·기호 같은 의미 요소예요. 영어 같은 언어에서는 공백과 구두점으로 단어를 나누는 게 일반적이죠. 그런데 영어용으로 만들어진 토크나이저는 한국어처럼 구조가 다른 언어의 의미 구조를 이해하지 못해서, 한국어 처리에는 그대로 쓰기 어려워요.
KoNLPy의 kkma 분석기로 한국어 토큰 분할하기
KoNLPY는 형태소 분석기인 Kkma(Korean Knowledge Morpheme Analyzer)를 포함해요. Kkma는 한국어 텍스트를 상세하게 형태소 분석해요. 문장을 단어로, 단어를 각각의 형태소로 쪼갠 뒤 각 토큰의 품사를 식별하죠. 또 텍스트 블록을 개별 문장으로 분절해서 긴 텍스트를 처리할 때 특히 유용해요.
사용 시 고려사항
Kkma는 분석이 상세하기로 유명하지만, 그 정밀함이 처리 속도에 영향을 줄 수 있어요. 따라서 빠른 텍스트 처리를 우선하는 경우보다, 분석의 깊이가 더 중요한 애플리케이션에 적합해요.
# pip install konlpy
# This is a long Korean document that we want to split up into its component sentences.
with open("./your_korean_doc.txt") as f:
korean_document = f.read()
from langchain_text_splitters import KonlpyTextSplitter
text_splitter = KonlpyTextSplitter()
texts = text_splitter.split_text(korean_document)
# The sentences are split with "\n\n" characters.
print(texts[0])
춘향전 옛날에 남원에 이 도령이라는 벼슬아치 아들이 있었다.
그의 외모는 빛나는 달처럼 잘생겼고, 그의 학식과 기예는 남보다 뛰어났다.
한편, 이 마을에는 춘향이라는 절세 가인이 살고 있었다.
춘 향의 아름다움은 꽃과 같아 마을 사람들 로부터 많은 사랑을 받았다.
어느 봄날, 도령은 친구들과 놀러 나갔다가 춘 향을 만 나 첫 눈에 반하고 말았다.
두 사람은 서로 사랑하게 되었고, 이내 비밀스러운 사랑의 맹세를 나누었다.
하지만 좋은 날들은 오래가지 않았다.
도령의 아버지가 다른 곳으로 전근을 가게 되어 도령도 떠나 야만 했다.
이별의 아픔 속에서도, 두 사람은 재회를 기약하며 서로를 믿고 기다리기로 했다.
그러나 새로 부임한 관아의 사또가 춘 향의 아름다움에 욕심을 내 어 그녀에게 강요를 시작했다.
춘 향 은 도령에 대한 자신의 사랑을 지키기 위해, 사또의 요구를 단호히 거절했다.
이에 분노한 사또는 춘 향을 감옥에 가두고 혹독한 형벌을 내렸다.
이야기는 이 도령이 고위 관직에 오른 후, 춘 향을 구해 내는 것으로 끝난다.
두 사람은 오랜 시련 끝에 다시 만나게 되고, 그들의 사랑은 온 세상에 전해 지며 후세에까지 이어진다.
- 춘향전 (The Tale of Chunhyang)
Hugging Face 토크나이저
Hugging Face에는 토크나이저가 많아요. 여기서는 GPT2TokenizerFast로 텍스트 길이를 토큰 단위로 셀게요.
- 텍스트를 어떻게 나누나: 전달한 문자 기준.
- 청크 크기를 어떻게 재나:
Hugging Face토크나이저가 계산한 토큰 수 기준.
from transformers import GPT2TokenizerFast
tokenizer = GPT2TokenizerFast.from_pretrained("gpt2")
# This is a long document we can split up.
with open("state_of_the_union.txt") as f:
state_of_the_union = f.read()
from langchain_text_splitters import CharacterTextSplitter
text_splitter = CharacterTextSplitter.from_huggingface_tokenizer(
tokenizer, chunk_size=100, chunk_overlap=0
)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and the Cabinet. Justices of the Supreme Court. My fellow Americans.
Last year COVID-19 kept us apart. This year we are finally together again.
Tonight, we meet as Democrats Republicans and Independents. But most importantly as Americans.
With a duty to one another to the American people to the Constitution.
더 알아보기 (Learn more)
- Text splitters 개요 — 분할기의 종류와 선택 기준
- 재귀 문자 텍스트 분할 — 일반 텍스트 권장 분할기
- 문자 단위 텍스트 분할 — 가장 단순한 분할 방식
- 코드 텍스트 분할 — 프로그래밍 언어별 분할