본문 바로가기
LLM/LLM 공부

Retrieval - Text Splitters

by 컴돌이_예준 2025. 3. 7.

Text Splitter는 토큰 제한이 있는 LLM이 여러 문장을 참고해 답변할 수 있도록 문서를 분할하는 역할

 

Text Splitter의 종류에는 2가지가 있음

대부분의 경우 RecursiveCharacter TextSplitter를 통해 분할

  • RecursiveCharacter TextSplitter
  • 줄바꿈, 마침표, 쉼표 순으로 재귀적으로 분할하므로, max_token을 지켜 분할
  • Character TextSplitter
  • 구분자 1개 기준으로 분할하므로, max_token을 지키지 못하는 경우가 발생

CharacterTextSplitter

가장 간단한 텍스트 분할기로, 특정 구분자를 기준으로 텍스트를 여러 개로 분할합니다.

# This is a long document we can split up.
with open('/content/drive/MyDrive/LLM자료/state_of_the_union.txt') as f:
    state_of_the_union = f.read()

from langchain.text_splitter import CharacterTextSplitter
text_splitter = CharacterTextSplitter(
    separator = "\\n\\n",
    chunk_size = 1000,
    chunk_overlap  = 100,
    length_function = len,
)

texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
print("-"*100)
print(texts[1])
print("-"*100)
print(texts[2])

char_list = []
for i in range(len(texts)):
    char_list.append(len(texts[i]))
print(char_list)

text_splitter.create_documents([state_of_the_union])

PDF를 가져와서 텍스트 분할로 나누기

from langchain.document_loaders import PyPDFLoader

loader = PyPDFLoader("/content/drive/MyDrive/LLM자료/[이슈리포트 2022-2호] 혁신성장 정책금융 동향.pdf")
pages = loader.load_and_split()

print(pages[1].page_content)
texts = text_splitter.split_documents(pages)
print(texts[1].page_content)

RecursiveCharacter TextSplitter

  • RecursiveCharacterTextSplit은 재귀적으로 문서를 분할합니다. 먼저, "\\n\\n"(줄바꿈)을 기준으로 문서를 분할하고 이렇게 나눈 청크가 여전히 너무 클 경우에 "\\n"(문장 단위)을 기준으로 문서를 분할합니다. 그렇게 했을 때에도 청크가 충분히 작아지지 않았다면 문장을 단어 단위로 자르게 되지만, 그렇게까지 세부적인 분할은 자주 필요하지 않습니다.
  • 이런 식의 분할 방법은 문장들의 의미를 최대한 보존하는 형태로 분할할 수 있도록 만들고, 그렇기 때문에 다수의 청크를 LLM에 활용함에 있어서 맥락이 유지되도록 하기에 용이합니다.
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
    # Set a really small chunk size, just to show.
    chunk_size = 1000,
    chunk_overlap  = 200,
    length_function = len,
)

texts = text_splitter.create_documents([state_of_the_union])
print(texts[0].page_content)
print("-"*500)
print(texts[1].page_content)

char_list = []
for i in range(len(texts)):
    char_list.append(len(texts[i].page_content))
print(char_list)
from langchain.document_loaders import PyPDFLoader
loader = PyPDFLoader("/content/drive/MyDrive/LLM자료/[이슈리포트 2022-2호] 혁신성장 정책금융 동향.pdf")
pages = loader.load_and_split()

print(pages[1].page_content)
texts = text_splitter.split_documents(pages)
len(texts)
print(texts[1].page_content)

기타 Splitter

일반적인 글로 된 문서는 모두 textsplitter로 분할할 수 있으며, 대부분의 경우가 커버됩니다. 그러나 코드, latex 등과 같이 컴퓨터 언어로 작성되는 문서의 경우 textsplitter로 처리할 수 없으며 해당 언어를 위해 특별하게 구분하는 splitter가 필요합니다.

예를 들어 Python 문서를 split하기 위해서는 def, class와 같이 하나의 단위로 묶이는 것을 기준으로 문서를 분할할 필요가 있습니다. 이러한 원리로 Latex, HTML, Code 등 다양한 문서도 분할할 수 있습니다.

from langchain.text_splitter import (
    RecursiveCharacterTextSplitter,
    Language
)

RecursiveCharacterTextSplitter.get_separators_for_language(Language.PYTHON)
PYTHON_CODE = """
def hello_world():
    print("Hello, World!")

# Call the function
hello_world()
"""
python_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.PYTHON, chunk_size=50, chunk_overlap=0
)
python_docs = python_splitter.create_documents([PYTHON_CODE])
python_docs

토큰 단위 텍스트 분할기

텍스트 분할의 목적은 LLM이 소화할 수 있을 정도의 텍스트만 호출하도록 만드는 것입니다. 따라서 LLM이 소화할 수 있는 양으로 청크를 제한하는 것은 LLM 앱을 개발할 때 필수적인 과정입니다.

LLM은 텍스트를 받아들일 때, 정해진 토큰 이상으로 소화할 수 없게 설계되어 있습니다. 따라서 글을 토큰 단위로 분할한다면 최대한 많은 글을 포함하도록 청크를 분할할 수 있습니다.

토큰이라는 것은, 텍스트와 달리 Transformer에서 처리하는 방식에 따라서 그 수가 달라질 수 있습니다. 따라서, LLM 앱을 개발하고자 한다면 앱에 얹힐 LLM의 토큰 제한을 파악하고, 해당 LLM이 사용하는 Embedder를 기반으로 토큰 수를 계산해야 합니다. 예를 들어, OpenAI의 GPT 모델은 tiktoken이라는 토크나이저를 기반으로 텍스트를 토큰화합니다. 따라서 tiktoken encoder를 기반으로 텍스트를 토큰화하고, 토큰 수를 기준으로 텍스트를 분할하는 것이 프로덕트 개발의 필수 요소라고 할 수 있습니다.

!pip install tiktoken
import tiktoken
tokenizer = tiktoken.get_encoding("cl100k_base")

def tiktoken_len(text):
    tokens = tokenizer.encode(text)
    return len(tokens)
tiktoken_len(texts[1].page_content)

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500, chunk_overlap=0, length_function = tiktoken_len
)
texts = text_splitter.split_documents(pages)

print(len(texts[1].page_content))
print(tiktoken_len(texts[1].page_content))

token_list = []
for i in range(len(texts)):
    token_list.append(tiktoken_len(texts[i].page_content))
print(token_list)

'LLM > LLM 공부' 카테고리의 다른 글

Retrieval - Vectorstores  (0) 2025.03.07
Retrieval-Text Embeddings  (0) 2025.03.07
Retrieval - Document Loaders  (0) 2025.03.07
PromptTemplate에 대해  (0) 2025.03.07
ChatGPT API 실습  (0) 2025.03.07