문서를 받고, 임베딩 처리를 할 때, 어떤 사이즈로 청크를 만들어야 가장 최적화가 될까?
벡터스토어 기반 검색 시스템에서 문서 임베딩 후, 사용자가 원하는 정보를 정확히 찾지 못하는 문제가 발생했다. 이는 검색 시스템에서 문서를 분할(청크)하는 방식이 최적화되지 않았기 때문일 가능성이 크다. 문서를 청크로 나누는 과정에서 크기와 중첩(오버랩) 설정이 검색 정확도와 문맥 유지에 큰 영향을 미치기 때문이다.
청크 크기와 오버랩 설정을 다양하게 조정하여 최적의 설정을 찾고, 검색 결과의 정확도와 문맥 유지 정도를 평가.
나는 웹링크를 제공하면, 여기 웹링크에 들어가서 내용을 스크랩핑을 한 후, 임베딩 처리를 해 DB에 반영하는 흐름으로 로직을 짰다.
내가 주로 사용하는 웹링크는 회사의 뉴스룸이다.
우선 뉴스 문서의 특성을 생각해보자면,
1) 짧은 단락으로 구성되어 문맥 단위가 비교적 명확하다.
2) 초반에는 중요한 정보를 요약하며, 이후에 세부 내용을 다룬다.
3) 키워드 중심으로 정보를 전달해, 검색 쿼리에 키워드가 중요한 역할을 한다.
그럼 이제 어떤 청크 크기를 설계해야 적합할까?
1) 문맥이 비교적 독립적인 뉴스 문서이기에, 청크 크기를 작게 설정을 해야 한다.
2) 문맥 연결을 위해 청크 간 중첩을 추가해야 한다. 각 청크의 끝에서 50~100 토큰 정도를 다음 청크에 포함시켜야 한다. 이 설정을 하면 계산 정확도가 향상된다.
나는 무료로 쓸 수 있는 임베딩 모델을 사용하기 위해 이 모델을 선정하였다. 이 모델은 일반적으로 200~400 토큰 사이에서 가장 높은 성능을 발휘한다.
청크 크기를 여러개로 정하여 최적화 실험을 해보겠다.
우선 내가 사용하는 예시 웹링크를 기반으로 한 문장과 한 단락당 몇개의 토큰이 있는지 계산해보겠다.
import tiktoken
def calculate_tokens(text: str, model: str = "gpt-3.5-turbo") -> int:
# 모델에 맞는 토크나이저 로드
tokenizer = tiktoken.encoding_for_model(model)
# 텍스트를 토큰으로 변환하고 토큰의 개수를 반환
tokens = tokenizer.encode(text)
return len(tokens)
# 사용 예제
text = "문장"
token_count = calculate_tokens(text)
print(f"Number of tokens: {token_count}")
이 코드를 실행시켜 내가 사용하는 문서의 전반적인 문장의 토큰 수를 계산해보았다.
텍스트 데이터를 벡터화하고 검색 결과의 정확성을 높이기 위해 토큰(청크) 사이즈와 오버랩 크기를 최적화하는 것은 매우 중요하다. 따라서 동일한 문서를 임베딩하되, 토큰 사이즈와 오버랩 크기를 다르게 해 저장을 하고 동일한 질문을 주었다.
테스트는 동일한 질문과 데이터를 기반으로 수행되었으며, 각 설정에서 반환된 검색 결과를 분석했다.
토큰 사이즈와 오버랩 크기의 최적화는 검색 결과의 품질을 좌우하는 핵심 요소다. 이번 테스트에서는 질문 중심의 검색에 Chunk Size 300, Overlap 100이 가장 적합한 설정으로 나타났다. 이 설정은 세부 정보와 문맥의 균형을 효과적으로 유지하며, 검색 효율성을 극대화한다.
앞으로 벡터 스토어를 활용한 검색 엔진 개발 시, 데이터 특성과 질문 유형에 따라 이러한 설정을 조정해야 한다. 무지성으로 남들이 좋다는 값으로 설정하는 것이 아닌, 데이터와 질문의 성격에 맞는 최적의 설정을 찾는 것이 성공적인 검색 시스템의 핵심임을 깨닫게 되었다.