본문 바로가기

서비스 제작

[MDQA]1.2 텍스트 데이터를 chunk로 자르기(chunker 모듈)

MDQA를 위해 “유저가 입력한 웹 페이지 또는 파일을 데이터 베이스에 저장”하는 과정에 대해 다루고 있다. [MDQA]1. 웹 페이지 또는 파일을 데이터 베이스에 저장하기 에서 설명한 것처럼 그 전체 과정은 아래와 같다.

  1. 유저가 웹 페이지의 URL을 입력 또는 PDF 파일을 업로드
  2. 웹 페이지는 크롤링, PDF는 파일을 읽어서 텍스트 데이터를 가져옴(Loader 모듈)
  3. 텍스트 데이터를 chunk로 자른다.(chunker 모듈)
  4. 자른 텍스트를 특정 크기의 벡터로 임베딩한다. (embedder 모듈)
  5. chunk를 중요한 순서대로 정렬한 데이터도 저장한다. (Text ranker 모듈, 이 부분은 필수적이지 않다.)
  6. 이렇게 처리한 데이터들을 데이터베이스에 저장한다.

이번 포스팅에서는 3번 과정인 “텍스트 데이터를 chunk로 자른다.(chunker 모듈)”를 설명해본다.

Chunker 모듈

Chunking이 필요한 이유

문서의 텍스트를 자르는 Chunking이 왜 필요할까? MDQA task(유저가 질문을 하고, 그에 대한 답변을 여러 문서에서 찾아 제공하는 task)에서 그 이유는 아래와 같다.


  1. LLM이 수용할 수 있는 Context Size가 제한되어있어 모든 문서 텍스트를 LLM에 넣을 수 없다.
  2. LLM에 들어갈 때 모든 문서를 다 넣을 경우 질문과 연관된 부분을 찾지 못할 확률이 올라가서 답변의 품질이 떨어진다.

위와 같은 이유로 문서를 chunk라는 텍스트 단위로 자른다. 이렇게 자른 chunk는 이후 유저 질문에 답변을 제공하기 위한 단서(chunk)를 검색하는 과정에 사용된다. 그리고 이렇게 찾은 단서(chunk)는 LLM에 질문과 함께 입력되어 답변을 생성한다. 위와 같은 검색 과정은 retrieval, 답변 생성의 과정은 generation이라고 부른다.

Chunking 방식

Chunking 방식 중 고려할 수 있는 것은 아래와 같다.

  • 토큰수 기반으로 자르기: 특정 길이의 토큰을 기준으로 자름
  • 특수 기호 + 토큰수 기반으로 자르기(예시. 온점 또는 줄바꿈으로 분리하고, 이후 토큰 수로 자르기)
  • 시각적으로 자르기
  • WEB의 경우 HTML 구조를 이용해서 자르기
  • semantic chunking: 연속된 비슷한 내용끼리 embedding similarity를 기준으로 묶는 방법이다.

빠른 개발을 위해서 시각적으로 자르는 방식(AI 모듈을 개발해야해서 시간이 오래 걸림)과 HTML 구조를 이용해서 자르는 방식(알고리즘 기반의 방식이기 때문에 복잡하고, 모든 HTML에 대해서 잘 적용되지 않음)은 고려하지 않았다. 추후 포스팅으로 남기도록 하겠다. 이 방식들도 잘 사용하면 최고의 chunking 방식이라고 생각한다.

또한 “특수 기호 + 토큰수 기반”으로 자르는 방식은 고려하지 않았다. 이 방식이 토큰수를 기반해서 자르는 방식과 성능적으로 큰 차이가 없을 것으로 생각했기 때문이다.

토큰수 기반과 semantic chunking방식을 아래 표에서 장단점을 비교해보자.

토큰수 기반 semantic chunking
chunk들의 토큰수 토큰수가 동일 토큰수가 다름
광고 필터링 광고와 contents가 섞임 광고와 contents가 분리됨
문맥 클러스터링 문맥과 상관없이 내용이 묶임 문맥이 유사한 글들만 묶임
비용(돈 & 시간) 저렴 비쌈

Retrieval 성능 측면에서 chunking 방식 비교

chunking방식을 비교하기에 앞서 어떻게 해야 Retrieval의 성능이 올라가는지 알아보자. chunk 토큰수의 측면에서 Retrieval의 성능을 간단하게 비교해보자면 아래와 같다.(당연히 토큰수나 얼마나 토큰수가 다른지 정도에 따라 부등호는 바뀔 수 있다. 아래 비교는 chunk의 길이가 짧을 때는 128토큰, 길 때는 1024토큰, 토큰수가 다른 정도는 10토큰에서 1000토큰까지 다양하게 분포되어 있을 때라고 생각하면 된다.)

모든 chunk의 토큰수가 동일하고 짧다 > 모든 chunk의 토큰수가 동일하고 길다 > 모든 chunk의 토큰수가 다르다.


위와 같은 Retrieval 성능 측면에서 토큰수 기반으로 자르는 방식은 모든 chunk의 토큰수가 동일하므로 Retrieval 성능에서 장점이 있다. 반대로 semantic chunking의 chunk마다 토큰수가 다른점은 단점이다. 이런 부분을 보강하기 위해 parent-child chunking방식을 추가로 사용했다.


parent-child chunking방식은 아래 그림과 같다. parent-child chunking 방식은 document를 parent chunk와 child chunk의 두 단계의 chunk로 자른다. Retrieval에서는 child chunk를 이용해서 검색하지만 LLM에 들어갈 때는 parent chunk가 들어간다. 이 방식을 사용하면 retrieval 단계에서는 child chunk의 적은 토큰수를 따르기 때문에 retrieval 성능이 올라간다. 또한 generation단계에서는 parent chunk의 전체 문맥을 포함한 내용이 LLM에 들어가기 때문에 generation 성능이 올라간다. Parent-child Chunking 방식은 추후 포스팅에서 다시 설명하겠다.



Semantic chunking은 광고 필터링과 문맥 클러스터링 측면에서 중요한 장점을 가지고 있다. 광고 필터링은 웹 페이지에 있는 컨텐츠 내용과 광고와 같은 컨텐츠와 다른 부분을 거르는 것이고, 문맥 클러스터링은 컨텐츠를 비슷한 내용끼리 묶는 것이다. 토큰수 기반 접근법이 광고든 다른 내용이든 구분 없이 모든 내용을 하나의 청크로 묶는 반면, semantic chunking은 관련성에 기반하여 내용을 효과적으로 분리하거나 그룹화한다. 이는 Generation 과정에서 LLM에 context로 넣을 때 관련된 내용이 함께 처리되어 문맥 파악이 가능하고, 답변의 일관성을 향상시킬 수 있다. 광고를 분리하고 비슷한 문맥을 클러스터링함으로써, semantic chunking은 이론적으로 Retrieval 성능과 LLM의 결과물 품질을 향상시킬 가능성이 있다.(실제 실험값으로 알아보지는 못했다.)

비용 측면에서 chunking 방식 비교

비용의 관점에서 토큰수 기반 방식은 단순히 특정 토큰수를 기준으로 자르고, 1회만 embedding하면 되기 때문에 저렴하다. 하지만 semantic chunking에서는 자르기 위한 추가적인 embedding과 similarity 계산이 필요하다. 따라서 토큰수 기반 방식에 비해서 많은 비용과 시간이 필요하다. 자세한 semantic chunking 방식은 추후 포스팅에서 기술한다.

결론적으로 선택한 Chunking 방식

  • Web: Semantic chunking을 사용
  • PDF: 토큰수 기준으로 자름

위와 같은 내용을 종합했을 때 WEB의 경우에는 Semantic chunking을 적용했고, PDF에서는 토큰수기반 chunking을 적용했다. WEB은 글의 앞 뒤, 중간에 광고가 있는 경우가 많고, 비교적 글의 길이가 짧다. WEB에서는 광고를 잘 거르는 것이 중요하다. 글의 길이도 짧기 때문에 Semantic chunking을 적용해도 비용과 처리에 걸리는 시간이 작다. PDF는 광고가 없고, 글에서 컨텐츠의 밀도가 높은 경우가 많다. 글들의 문맥이 전체에 걸쳐서 어느정도 유사한 경우가 많기 때문에 Semantic chunking을 적용하면 잘 분리되지 않아 제대로된 성능이 나오지 않는 경우가 많다. 글의 길이도 긴 경우가 많아서 비용과 처리에 걸리는 시간이 길다.