본문 바로가기
  • think normal
새로워지기/마흔의 생활코딩

LLM | Five Levels of Chunking( 스압 주의!)

by 청춘만화 2024. 5. 1.
Agentic 컨셉 시리즈
  👉  Agentic Chunking LangChain RAG
  - AI 소프트웨어 엔지니어 DEVIKA
  - AI 에이전트를 오케스트레이션 프레임워크 CrewAI

 

 

먼저..

RAG에 대한 기본적인 내용은 이전에 포스팅을 참고하면 좋을 것 같다. 

 

LLM | Langchain - 02 유형/단계별 RAG 실습

실습 링크는 코랩 입니다.   기본 대화 준비, API KEY 발급가입, 키발급실습, GPT와 대화하기OpenAI - DocumentsLangchain - Langchain(LLM)_실습GPT 3, 3.5 비교매개변수 조절temperature : 0일관적 답변, 2매번 다른

normalstory.tistory.com

 

 

 

 

 

1. 개요

 

Chunking 

Chunking은 고품질의 응답에 많은 영향을 미치는 중요한 과정으로써 텍스트를 관리를 쉽고, 명확하게 중요한 부분으로 나누는 과정으로 맥락의 효율적인 처리와 검색을 위해 사용된다. 

 

Chunking 전략의 변천사

처음?에는 더 작은 단위로 나누기 위해 고민을 했다. 더 작은 단위로 텍스트를 나눌 수록 검색 정확도가 향상 하기 때문이다. 하지만 너무 작기만 한 경우 ‘문장에 대한 맥락을 충분히 전달하지 못할 수 있다’라는 매우 치명적인 한계가 발행했다.

그래서 찾게 된 첫 개선 방안은 자른 부분 앞뒤로 조금 더 여유를 줘서 중복되는 부분을 만드는 방법이었다. 중복이라는 이슈가 있지만 이전보다 균형감 있게 의미를 이해할 수 있게 되었다.

그리고 추가로 찾게 된 개선 방안이 Small-to-Big 방식이다. Small-to-big 검색은 검색 과정 중 더 작은 텍스트 조각을 사용하고, 그 다음에 검색된 텍스트가 속해 있는 더 큰 텍스트 단위를 제공하는 것을 포함한다. 이 방식은 충분한 맥락을 유지하면서 보다 집중적인 검색을 가능하게 한다. 하지만 이 방식도 결국 쿼리 시간이 더 걸리고 데이터를 다시 임베드 하는데 드는 비용이 더 들 수 있다는 단점이 발생한다.

이렇게 그동안?은 얼마나 더 적당히 분할하느냐?가 주요 관점이었다면 최근 트랜드는 에이전트를 통해 상황에 따라 적절히 분할하는 방향으로 다양한 시도가 이뤄지고 있다. 바로 레벨 5 단계인 Agentic Chunking(에이전트 기반 분할)이다.

*참고로 몇일? 전에 Agentic과 관련해서 작성했던 포스트 링크를 걸어둔다. 

 

Agentic | MOE(mixture of exports)

이전에 사요나라, 프롬프트 엔지니어링에 대해 작성한 적이 있다. LLM을 위한 프롬프트는 LLM이 가장 잘 알고, 각각의 LLM은 저마다의 최적의 하이퍼파라미터를 갖고 있기 때문에 인간이 매번 모든

normalstory.tistory.com

 

 

Chunking 전략의 다섯 단계

1. 문자 분할
2. 재귀문자 분할
3. 문서/단락기반 분할
4. 의미/의미론적 분할
5. 에이전트 기반 분할

 

Chunking 전략과 관련된 핵심 키워드

Chunks , CharacterTextSplitter , SenctenceSplitter , RecursiveCharacterTextSplitter , MarkdownTextSplitter , PythonCodeTextSplitter , SemanticSplitterNodeParse , Buffer size , Breakpoint percentile threshold , Embed mode , Propositional-retrieval template

 

 

 

2. 실습 준비

1. 작업 폴더를 만들고 그 안에 '.env 파일'(과 github에 올리는 경우, 본인에게 맞는 .gitignore)을 작성한다.

2. 필요한 경우 가상 환경을 구축한다. 
      맥의 경우, python -m venv langChunking
                      source langChunking/bin/activate
     *참고로 'langChunking'는 본인이 정하고 싶은 이름으로 작성하면 된다

3. 의존성 패키지를 설치한다 
      pip install -U chromadb langchain llama-index langchain_experimental langchain_openai
      pip install langchainhub rich
      pip install python-dotenv

4. ollama를 설치하고 필요한 모델을 pull 받는다
      개인적으로  text embedding용으로는   ollama pull nomic-embed-text  를 받았고 
      local llm으로는 'ollama pull mistral:v0.2'   를 받았다.

5. 이번 예시에서 테스트를 위한 파일을 간단하게 .txt로 작성해서 진행하기로 한다

# 동화 작가 # 

## 안데르센 ## 
한스 크리스티안 안데르센(덴마크어: Hans Christian Andersen 한스 크리스티안 아네르센, 1805년 4월 2일 ~ 1875년 8월 4일)은 덴마크의 동화작가이자 소설가다. 
그는 사는 동안에 여러 나라 어린이들을 기쁘게 하는 데 성공했다. 그의 시와 이야기는 150개가 넘는 언어로 번역되었다. 
그가 쓴 작품은 여러 영화, 연극, 발레, 애니메이션이 탄생하는 데 필요한 영감을 불러 일으켰다.

## 생애 ## 
안데르센은 덴마크의 오덴세에서 구두 수선공의 아들로 태어났다. 
한스 크리스티안 안데르센이라는 이름은 안데르센이 루터교에서 세례를 받았을 때 대부모(代父母)가 붙여준 이름이다. 
안데르센의 집안은 할머니가 병원에서 청소 노동자로 일할 정도로 가난하여, 안데르센의 성장 과정에 큰 영향을 끼쳤다. 
독실한 루터교 신자인 어머니는 안데르센에게 예수를 공경하는 순수한 개신교 신앙을 심어주었고, 아버지는 인형극과 독서를 통해 어린 그에게 옛날 이야기와 <아라비안 나이트>를 자주 들려 주며 상상력과 교양을 심어주었다. 
어린시절 아버지의 갑작스러운 별세로, 가장의 자리가 비게 되자 안데르센은 어린나이에 공장에서 일하고, 어머니는 빨래를 대신해주는 일을 했다. 
1819년에는 연극 배우의 꿈을 품고 코펜하겐으로 갔으나, 변성기 이후 목소리가 탁해지면서 꿈을 접어야 했다. 
더구나 가난 때문에 정규 교육을 받지 못해서 문법과 맞춤법이 엉망인 그의 연극대본은 극단주에 의해 반송되었기에 자살을 생각할 정도로 극심한 마음의 고통에 시달렸다. 
다행히 그의 작가로서의 재능을 알아본 덴마크 의회 의원인 요나스 콜린의 후원으로 라틴어 학교에 입학했으나, 안데르센이 시를 쓰는 것을 싫어하는 교장과의 갈등 때문에, 5년 만에 학교를 그만두고 1828년 코펜하겐 대학교에 입학하였다. 
몇 편의 희곡, 소설을 쓰면서 작가로서의 재능을 드러낸 안데르센은 《즉흥시인》(1834년작)으로 문학계의 호평을 받았다. 
1835년부터 본격적인 동화 저작에 들어갔는데, 어른들도 읽을 정도로 독자들의 반응이 좋았다. 
하지만, 일부 문학비평가들은 '《즉흥시인》을 쓸 정도로 뛰어난 작가가 어린이를 속이는 이야기나 쓴다.'는 가혹한 비판을 하기도 했다. 
1872년까지 발표한 총 160여편의 동화 작품은 모두 유명해져서 연금 수령, 안데르센의 그림이 들어간 우표 발행이라는 영광을 누렸다. 
62세 때 그는 고향 오덴세의 명예 시민으로 받들어졌으며 1875년 수도인 코펜하겐에서 병으로 세상을 떠났다. 그의 장례식에는 덴마크 국왕과 왕비가 참석하였다. 
2005년 4월 2일에 안데르센 탄생 200주년을 맞아, 200주년 기념 웹사이트가 개설되기도 했다.

## 주요 작품 ## 
즉흥시인, 빨간 구두, 눈의 여왕, 인어공주, 성냥팔이 소녀, 벌거숭이 임금님, 미운 오리 새끼, 엄지 공주, 꿋꿋한 주석 병정, 야생의 백조

## 안데르센 문학의 특징 ## 
안데르센 문학은 안데르센이 가난한 구두 수선공의 아들이라는 것에 영향을 많이 받았다. 《성냥팔이 소녀》는 가난하게 자라서 구걸까지 해야 했던 안데르센의 어머니를 소재로 한 작품이다. 
또한 《눈의 여왕》은 어렸을 때 나폴레옹 전쟁에 참전했다가 돌아온 아버지가, 서리가 내리던 밤에 신경쇠약으로 죽자, 고아가 되었고 이를 '눈의 여왕'이 데려가는 것으로 생각한 어린시절의 기억이 소재가 되었으며, 《미운 오리 새끼》는 안데르센이 작가로 데뷔한 후에도, 그의 출신 때문에 홀대를 받은 상처가 문학으로 표현된 작품이다.

## 출처 ## 
위키피디아

 

 

 

 

3. 실습

레벨 1: Fixed Size Chunking(문자 분할)

- 정의: 내용이나 구조에 관계없이 지정된 문자 수만큼의 단위로 텍스트를 나누는 가장 간단한 방법
- 사용 가능한 클래스: Langchain과 Llamaindex 프레임워크에서 제공하는 CharacterTextSplitter와 SenctenceSplitter
- 분할 Chunk 단위크기 측정: 각 분할 기준이 되는 문자 수
- 분할 Chunk 영역의 중복: 연속된 분할 과정에서 중복되는 데이터 양을 피하기 위한 문자 수
- 분리 기준: 기본 분리 기준은 빈 문자열("")

- Code : content.txt 청킹 예 

from rich import print
from langchain.docstore.document import Document
from langchain_community.chat_models import ChatOllama
from langchain_community.vectorstores import Chroma
from langchain_community import embeddings
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate

local_llm = ChatOllama(model="mistral:v0.2")

# RAG
def rag(chunks, collection_name):
    vectorstore = Chroma.from_documents(
        documents=documents,
        collection_name=collection_name,
        embedding=embeddings.ollama.OllamaEmbeddings(model='nomic-embed-text'),
    )
    retriever = vectorstore.as_retriever()

    prompt_template = """
    다음 문맥에 근거해서만 질문에 답하세요 : 
    {context}
    질문 : {question}
    """
    prompt = ChatPromptTemplate.from_template(prompt_template)

    chain = (
        {"context": retriever, "question": RunnablePassthrough()}
        | prompt
        | local_llm
        | StrOutputParser()
    )
    result = chain.invoke("안데르센은 언제부터 동화를 썼나요?")
    print(result)

with open('content.txt', 'r', encoding='utf-8') as file:
    text = file.read()

# 1. Character Text Splitting
print("#### Character Text Splitting ####")
    
# Manual Splitting
chunks = []
chunk_size = 35 # Characters
for i in range(0, len(text), chunk_size):
    chunk = text[i:i + chunk_size]
    chunks.append(chunk)
documents = [Document(page_content=chunk, metadata={"source": "local"}) for chunk in chunks]
print("-- Manual --")
print(documents)

# Automatic Text Splitting
from langchain.text_splitter import CharacterTextSplitter
text_splitter = CharacterTextSplitter(chunk_size = 35, chunk_overlap=0, separator='', strip_whitespace=False)
documents = text_splitter.create_documents([text])
print("-- Automatic --")
print(documents)

# Result 
print("-- RAG : Automatic Result --")
rag(documents, "Character-Text")

 

- Result 

#### Character Text Splitting ####
-- Manual --
[
    Document(
        page_content='# 동화 작가 \\n\\n## 안데르센\\n한스 크리스티안 안데르센(덴마크',
        metadata={'source': 'local'}
    ),
    Document(page_content='어: Hans Christian Andersen 한스 크리스티안', metadata={'source': 'local'}),
    Document(page_content=' 아네르센[*], 1805년 4월 2일 ~ 1875년 8월 4일', metadata={'source': 'local'}),
    Document(
        page_content=')은 덴마크의 동화작가이자 소설가다. 그는 사는 동안에 여러 나',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='라 어린이들을 기쁘게 하는 데 성공했다. 그의 시와 이야기는 1',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='50개가 넘는 언어로 번역되었다. 그가 쓴 작품은 여러 영화, ',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='연극, 발레, 애니메이션이 탄생하는 데 필요한 영감을 불러 일으',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='켰다.[1]\\n\\n## 생애\\n안데르센은 덴마크의 오덴세에서 구두 수',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='선공의 아들로 태어났다. 한스 크리스티안 안데르센이라는 이름은 ',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='안데르센이 루터교에서 세례를 받았을 때 대부모(代父母)[2]가 ',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='붙여준 이름이다. 안데르센의 집안은 할머니가 병원에서 청소 노동',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='자로 일할 정도로 가난하여, 안데르센의 성장 과정에 큰 영향을 ',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='끼쳤다. 독실한 루터교 신자인 어머니는 안데르센에게 예수를 공경',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='하는 순수한 개신교 신앙을 심어주었고, 아버지는 인형극과 독서를',
        metadata={'source': 'local'}
    ),
    Document(
        page_content=' 통해 어린 그에게 옛날 이야기와 <아라비안 나이트>를 자주 들',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='려 주며 상상력과 교양을 심어주었다. 어린시절 아버지의 갑작스러',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='운 별세로, 가장의 자리가 비게 되자 안데르센은 어린나이에 공장',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='에서 일하고, 어머니는 빨래를 대신해주는 일을 했다. 1819년',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='에는 연극 배우의 꿈을 품고 코펜하겐으로 갔으나, 변성기 이후 ',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='목소리가 탁해지면서 꿈을 접어야 했다. 더구나 가난 때문에 정규',
        metadata={'source': 'local'}
    ),
    Document(
        page_content=' 교육을 받지 못해서 문법과 맞춤법이 엉망인 그의 연극대본은 극',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='단주에 의해 반송되었기에 자살을 생각할 정도로 극심한 마음의 고',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='통에 시달렸다. 다행히 그의 작가로서의 재능을 알아본 덴마크 의',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='회 의원인 요나스 콜린의 후원으로 라틴어 학교에 입학했으나, 안',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='데르센이 시를 쓰는 것을 싫어하는 교장과의 갈등 때문에, 5년 ',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='만에 학교를 그만두고 1828년 코펜하겐 대학교에 입학하였다. ',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='몇 편의 희곡, 소설을 쓰면서 작가로서의 재능을 드러낸 안데르센',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='은 《즉흥시인》(1834년작)으로 문학계의 호평을 받았다. 18',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='35년부터 본격적인 동화 저작에 들어갔는데, 어른들도 읽을 정도',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='로 독자들의 반응이 좋았다. 하지만, 일부 문학비평가들은 "《즉',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='흥시인》을 쓸 정도로 뛰어난 작가가 어린이를 속이는 이야기나 쓴',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='다."는 가혹한 비판을 하기도 했다. 1872년까지 발표한 총 ',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='160여편의 동화 작품은 모두 유명해져서 연금 수령, 안데르센의',
        metadata={'source': 'local'}
    ),
    Document(
        page_content=' 그림이 들어간 우표 발행이라는 영광을 누렸다. 62세 때 그는',
        metadata={'source': 'local'}
    ),
    Document(
        page_content=' 고향 오덴세의 명예 시민으로 받들어졌으며 1875년 수도인 코',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='펜하겐에서 병으로 세상을 떠났다. 그의 장례식에는 덴마크 국왕과',
        metadata={'source': 'local'}
    ),
    Document(
        page_content=' 왕비가 참석하였다. 2005년 4월 2일에 안데르센 탄생 20',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='0주년을 맞아, 200주년 기념 웹사이트가 개설되기도 했다.[3',
        metadata={'source': 'local'}
    ),
    Document(
        page_content=']\\n\\n## 주요 작품\\n즉흥시인, 빨간 구두, 눈의 여왕, 인어공',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='주, 성냥팔이 소녀, 벌거숭이 임금님, 미운 오리 새끼, 엄지 ',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='공주, 꿋꿋한 주석 병정, 야생의 백조\\n\\n## 안데르센 문학의 ',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='특징\\n안데르센 문학은 안데르센이 가난한 구두 수선공의 아들이라는',
        metadata={'source': 'local'}
    ),
    Document(
        page_content=' 것에 영향을 많이 받았다. 《성냥팔이 소녀》는 가난하게 자라서',
        metadata={'source': 'local'}
    ),
    Document(
        page_content=' 구걸까지 해야 했던 안데르센의 어머니를 소재로 한 작품이다. ',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='또한 《눈의 여왕》은 어렸을 때 나폴레옹 전쟁에 참전했다가 돌아',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='온 아버지가, 서리가 내리던 밤에 신경쇠약으로 죽자, 고아가 되',
        metadata={'source': 'local'}
    ),
    Document(
        page_content="었고 이를 '눈의 여왕'이 데려가는 것으로 생각한 어린시절의 기",
        metadata={'source': 'local'}
    ),
    Document(
        page_content='억이 소재가 되었으며, 《미운 오리 새끼》는 안데르센이 작가로 ',
        metadata={'source': 'local'}
    ),
    Document(
        page_content='데뷔한 후에도, 그의 출신 때문에 홀대를 받은 상처가 문학으로 ',
        metadata={'source': 'local'}
    ),
    Document(page_content='표현된 작품이다.\\n\\n## 출처\\n위키피디아 ', metadata={'source': 'local'})
]

-- Automatic --
[
    Document(page_content='# 동화 작가 \\n\\n## 안데르센\\n한스 크리스티안 안데르센(덴마크'),
    Document(page_content='어: Hans Christian Andersen 한스 크리스티안'),
    Document(page_content=' 아네르센[*], 1805년 4월 2일 ~ 1875년 8월 4일'),
    Document(page_content=')은 덴마크의 동화작가이자 소설가다. 그는 사는 동안에 여러 나'),
    Document(page_content='라 어린이들을 기쁘게 하는 데 성공했다. 그의 시와 이야기는 1'),
    Document(page_content='50개가 넘는 언어로 번역되었다. 그가 쓴 작품은 여러 영화, '),
    Document(page_content='연극, 발레, 애니메이션이 탄생하는 데 필요한 영감을 불러 일으'),
    Document(page_content='켰다.[1]\\n\\n## 생애\\n안데르센은 덴마크의 오덴세에서 구두 수'),
    Document(page_content='선공의 아들로 태어났다. 한스 크리스티안 안데르센이라는 이름은 '),
    Document(page_content='안데르센이 루터교에서 세례를 받았을 때 대부모(代父母)[2]가 '),
    Document(page_content='붙여준 이름이다. 안데르센의 집안은 할머니가 병원에서 청소 노동'),
    Document(page_content='자로 일할 정도로 가난하여, 안데르센의 성장 과정에 큰 영향을 '),
    Document(page_content='끼쳤다. 독실한 루터교 신자인 어머니는 안데르센에게 예수를 공경'),
    Document(page_content='하는 순수한 개신교 신앙을 심어주었고, 아버지는 인형극과 독서를'),
    Document(page_content=' 통해 어린 그에게 옛날 이야기와 <아라비안 나이트>를 자주 들'),
    Document(page_content='려 주며 상상력과 교양을 심어주었다. 어린시절 아버지의 갑작스러'),
    Document(page_content='운 별세로, 가장의 자리가 비게 되자 안데르센은 어린나이에 공장'),
    Document(page_content='에서 일하고, 어머니는 빨래를 대신해주는 일을 했다. 1819년'),
    Document(page_content='에는 연극 배우의 꿈을 품고 코펜하겐으로 갔으나, 변성기 이후 '),
    Document(page_content='목소리가 탁해지면서 꿈을 접어야 했다. 더구나 가난 때문에 정규'),
    Document(page_content=' 교육을 받지 못해서 문법과 맞춤법이 엉망인 그의 연극대본은 극'),
    Document(page_content='단주에 의해 반송되었기에 자살을 생각할 정도로 극심한 마음의 고'),
    Document(page_content='통에 시달렸다. 다행히 그의 작가로서의 재능을 알아본 덴마크 의'),
    Document(page_content='회 의원인 요나스 콜린의 후원으로 라틴어 학교에 입학했으나, 안'),
    Document(page_content='데르센이 시를 쓰는 것을 싫어하는 교장과의 갈등 때문에, 5년 '),
    Document(page_content='만에 학교를 그만두고 1828년 코펜하겐 대학교에 입학하였다. '),
    Document(page_content='몇 편의 희곡, 소설을 쓰면서 작가로서의 재능을 드러낸 안데르센'),
    Document(page_content='은 《즉흥시인》(1834년작)으로 문학계의 호평을 받았다. 18'),
    Document(page_content='35년부터 본격적인 동화 저작에 들어갔는데, 어른들도 읽을 정도'),
    Document(page_content='로 독자들의 반응이 좋았다. 하지만, 일부 문학비평가들은 "《즉'),
    Document(page_content='흥시인》을 쓸 정도로 뛰어난 작가가 어린이를 속이는 이야기나 쓴'),
    Document(page_content='다."는 가혹한 비판을 하기도 했다. 1872년까지 발표한 총 '),
    Document(page_content='160여편의 동화 작품은 모두 유명해져서 연금 수령, 안데르센의'),
    Document(page_content=' 그림이 들어간 우표 발행이라는 영광을 누렸다. 62세 때 그는'),
    Document(page_content=' 고향 오덴세의 명예 시민으로 받들어졌으며 1875년 수도인 코'),
    Document(page_content='펜하겐에서 병으로 세상을 떠났다. 그의 장례식에는 덴마크 국왕과'),
    Document(page_content=' 왕비가 참석하였다. 2005년 4월 2일에 안데르센 탄생 20'),
    Document(page_content='0주년을 맞아, 200주년 기념 웹사이트가 개설되기도 했다.[3'),
    Document(page_content=']\\n\\n## 주요 작품\\n즉흥시인, 빨간 구두, 눈의 여왕, 인어공'),
    Document(page_content='주, 성냥팔이 소녀, 벌거숭이 임금님, 미운 오리 새끼, 엄지 '),
    Document(page_content='공주, 꿋꿋한 주석 병정, 야생의 백조\\n\\n## 안데르센 문학의 '),
    Document(page_content='특징\\n안데르센 문학은 안데르센이 가난한 구두 수선공의 아들이라는'),
    Document(page_content=' 것에 영향을 많이 받았다. 《성냥팔이 소녀》는 가난하게 자라서'),
    Document(page_content=' 구걸까지 해야 했던 안데르센의 어머니를 소재로 한 작품이다. '),
    Document(page_content='또한 《눈의 여왕》은 어렸을 때 나폴레옹 전쟁에 참전했다가 돌아'),
    Document(page_content='온 아버지가, 서리가 내리던 밤에 신경쇠약으로 죽자, 고아가 되'),
    Document(page_content="었고 이를 '눈의 여왕'이 데려가는 것으로 생각한 어린시절의 기"),
    Document(page_content='억이 소재가 되었으며, 《미운 오리 새끼》는 안데르센이 작가로 '),
    Document(page_content='데뷔한 후에도, 그의 출신 때문에 홀대를 받은 상처가 문학으로 '),
    Document(page_content='표현된 작품이다.\\n\\n## 출처\\n위키피디아 ')
]
-- RAG : Automatic Result --
 Based on the given documents, there is no clear answer to when Hans Christian Andersen started writing fairy tales. The documents 
only mention that Andersen came from a common background and lost his father at a young age, and that he received education and 
imagination from his mother. There's no information about him starting to write fairy tales in these documents.

 

 

레벨 2: Recursive Chunking(재귀문자 분할)

- 정의: 구분자를 사용하여 계층적이고 반복적인 방식으로 텍스트를 더 작은 단위로 나누는 방법
- 사용 가능한 클래스: Langchain 프레임워크에서 제공하는 RecursiveCharacterTextSplitter
- 분리 기준: 기본 분리 기준은 "\n\n",  "\n",   " ",     ","
- 한계 : 특정 기호( , ; .)로 자르는 경우, 완결된 문장으로 만들기 어렵다

- code : content.txt 청킹 예 

from rich import print
from langchain.docstore.document import Document
from langchain_community.chat_models import ChatOllama
from langchain_community.vectorstores import Chroma
from langchain_community import embeddings
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate

local_llm = ChatOllama(model="mistral:v0.2")

# RAG
def rag(chunks, collection_name):
    vectorstore = Chroma.from_documents(
        documents=documents,
        collection_name=collection_name,
        embedding=embeddings.ollama.OllamaEmbeddings(model='nomic-embed-text'),
    )
    retriever = vectorstore.as_retriever()

    prompt_template = """
    다음 문맥에 근거해서만 질문에 답하세요 : 
    {context}
    질문 : {question}
    """
    prompt = ChatPromptTemplate.from_template(prompt_template)

    chain = (
        {"context": retriever, "question": RunnablePassthrough()}
        | prompt
        | local_llm
        | StrOutputParser()
    )
    result = chain.invoke("안데르센은 언제부터 동화를 썼나요?")
    print(result)

with open('content.txt', 'r', encoding='utf-8') as file:
    text = file.read()
    

# 2. Recursive Character Text Splitting
print("#### Recursive Character Text Splitting ####")

from langchain.text_splitter import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(chunk_size = 65, chunk_overlap=0) # ["\\n\\n", "\\n", " ", ""] 65,450
documents = text_splitter.create_documents([text])
print(documents) 

# Result 
print("-- Recursive Result --")
rag(documents, "Recursive-Text")

- Result 

#### Recursive Character Text Splitting ####
[
    Document(page_content='# 동화 작가'),
    Document(page_content='## 안데르센'),
    Document(page_content='한스 크리스티안 안데르센(덴마크어: Hans Christian Andersen 한스 크리스티안 아네르센[*],'),
    Document(page_content='1805년 4월 2일 ~ 1875년 8월 4일)은 덴마크의 동화작가이자 소설가다. 그는 사는 동안에 여러 나라'),
    Document(page_content='어린이들을 기쁘게 하는 데 성공했다. 그의 시와 이야기는 150개가 넘는 언어로 번역되었다. 그가 쓴 작품은 여러'),
    Document(page_content='영화, 연극, 발레, 애니메이션이 탄생하는 데 필요한 영감을 불러 일으켰다.[1]'),
    Document(page_content='## 생애'),
    Document(page_content='안데르센은 덴마크의 오덴세에서 구두 수선공의 아들로 태어났다. 한스 크리스티안 안데르센이라는 이름은 안데르센이'),
    Document(page_content='루터교에서 세례를 받았을 때 대부모(代父母)[2]가 붙여준 이름이다. 안데르센의 집안은 할머니가 병원에서 청소'),
    Document(page_content='노동자로 일할 정도로 가난하여, 안데르센의 성장 과정에 큰 영향을 끼쳤다. 독실한 루터교 신자인 어머니는'),
    Document(page_content='안데르센에게 예수를 공경하는 순수한 개신교 신앙을 심어주었고, 아버지는 인형극과 독서를 통해 어린 그에게 옛날'),
    Document(page_content='이야기와 <아라비안 나이트>를 자주 들려 주며 상상력과 교양을 심어주었다. 어린시절 아버지의 갑작스러운 별세로,'),
    Document(page_content='가장의 자리가 비게 되자 안데르센은 어린나이에 공장에서 일하고, 어머니는 빨래를 대신해주는 일을 했다.'),
    Document(page_content='1819년에는 연극 배우의 꿈을 품고 코펜하겐으로 갔으나, 변성기 이후 목소리가 탁해지면서 꿈을 접어야 했다.'),
    Document(page_content='더구나 가난 때문에 정규 교육을 받지 못해서 문법과 맞춤법이 엉망인 그의 연극대본은 극단주에 의해 반송되었기에'),
    Document(page_content='자살을 생각할 정도로 극심한 마음의 고통에 시달렸다. 다행히 그의 작가로서의 재능을 알아본 덴마크 의회 의원인'),
    Document(page_content='요나스 콜린의 후원으로 라틴어 학교에 입학했으나, 안데르센이 시를 쓰는 것을 싫어하는 교장과의 갈등 때문에, 5년'),
    Document(page_content='만에 학교를 그만두고 1828년 코펜하겐 대학교에 입학하였다. 몇 편의 희곡, 소설을 쓰면서 작가로서의 재능을'),
    Document(page_content='드러낸 안데르센은 《즉흥시인》(1834년작)으로 문학계의 호평을 받았다. 1835년부터 본격적인 동화 저작에'),
    Document(page_content='들어갔는데, 어른들도 읽을 정도로 독자들의 반응이 좋았다. 하지만, 일부 문학비평가들은 "《즉흥시인》을 쓸 정도로'),
    Document(page_content='뛰어난 작가가 어린이를 속이는 이야기나 쓴다."는 가혹한 비판을 하기도 했다. 1872년까지 발표한 총 160여편의'),
    Document(page_content='동화 작품은 모두 유명해져서 연금 수령, 안데르센의 그림이 들어간 우표 발행이라는 영광을 누렸다. 62세 때 그는'),
    Document(page_content='고향 오덴세의 명예 시민으로 받들어졌으며 1875년 수도인 코펜하겐에서 병으로 세상을 떠났다. 그의 장례식에는'),
    Document(page_content='덴마크 국왕과 왕비가 참석하였다. 2005년 4월 2일에 안데르센 탄생 200주년을 맞아, 200주년 기념'),
    Document(page_content='웹사이트가 개설되기도 했다.[3]'),
    Document(page_content='## 주요 작품'),
    Document(page_content='즉흥시인, 빨간 구두, 눈의 여왕, 인어공주, 성냥팔이 소녀, 벌거숭이 임금님, 미운 오리 새끼, 엄지 공주,'),
    Document(page_content='꿋꿋한 주석 병정, 야생의 백조'),
    Document(page_content='## 안데르센 문학의 특징'),
    Document(page_content='안데르센 문학은 안데르센이 가난한 구두 수선공의 아들이라는 것에 영향을 많이 받았다. 《성냥팔이 소녀》는 가난하게'),
    Document(page_content='자라서 구걸까지 해야 했던 안데르센의 어머니를 소재로 한 작품이다. 또한 《눈의 여왕》은 어렸을 때 나폴레옹 전쟁에'),
    Document(page_content="참전했다가 돌아온 아버지가, 서리가 내리던 밤에 신경쇠약으로 죽자, 고아가 되었고 이를 '눈의 여왕'이 데려가는"),
    Document(page_content='것으로 생각한 어린시절의 기억이 소재가 되었으며, 《미운 오리 새끼》는 안데르센이 작가로 데뷔한 후에도, 그의 출신'),
    Document(page_content='때문에 홀대를 받은 상처가 문학으로 표현된 작품이다.'),
    Document(page_content='## 출처\\n위키피디아')
]
-- RAG : Recursive Result --
 The context provided does not mention or imply anything about text splitting. Therefore, an answer based on this context would not be able to address the 
question regarding the use of text splitting.

 

 

레벨 3: Document-Based Chunking(문서/단락기반 분할)

- 정의: 문서의 내재 구조를 고려하여 흐름과 내용을 기반으로 문서를 나누는 방법입니다. 구조가 명확한 문서에 효과적
- 사용 가능한 클래스: Langchain에서 제공하는 MarkdownTextSplitter는 마크다운 구분자를 바탕으로 문서를 나눈다
                                 PythonCodeTextSplitter는 클래스, 함수 등을 기준으로 파이썬 또는 자바스크립트 코드를 나눈다
- 한계 : 특정 단락으로 자르는 경우, 전후 단락의 문맥을 놓칠 수 있다

- code : MarkDown, Python, JavaScript 타입 문서에 대한 청킹 예

from rich import print
from langchain.docstore.document import Document
from langchain_community.chat_models import ChatOllama
from langchain_community.vectorstores import Chroma
from langchain_community import embeddings
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate

local_llm = ChatOllama(model="mistral:v0.2")

# RAG
def rag(chunks, collection_name):
    vectorstore = Chroma.from_documents(
        documents=documents,
        collection_name=collection_name,
        embedding=embeddings.ollama.OllamaEmbeddings(model='nomic-embed-text'),
    )
    retriever = vectorstore.as_retriever()

    prompt_template = """
    다음 문맥에 근거해서만 질문에 답하세요 : 
    {context}
    질문 : {question}
    """
    prompt = ChatPromptTemplate.from_template(prompt_template)

    chain = (
        {"context": retriever, "question": RunnablePassthrough()}
        | prompt
        | local_llm
        | StrOutputParser()
    )
    result = chain.invoke("안데르센은 언제부터 동화를 썼나요?")
    print(result)

with open('content.txt', 'r', encoding='utf-8') as file:
    text = file.read()

# 1. Character Text Splitting
print("#### Character Text Splitting ####")
    
# Manual Splitting
chunks = []
chunk_size = 35 # Characters
for i in range(0, len(text), chunk_size):
    chunk = text[i:i + chunk_size]
    chunks.append(chunk)
documents = [Document(page_content=chunk, metadata={"source": "local"}) for chunk in chunks]
print("-- Manual --")
print(documents)

# Automatic Text Splitting
from langchain.text_splitter import CharacterTextSplitter
text_splitter = CharacterTextSplitter(chunk_size = 35, chunk_overlap=0, separator='', strip_whitespace=False)
documents = text_splitter.create_documents([text])
print("-- Automatic --")
print(documents)

# Result 
print("-- RAG : Automatic Result --")
rag(documents, "Character-Text")

 

- Result :

#### Document Specific Splitting ####
[
    Document(page_content='# 동화 작가 \\n## 안데르센'),
    Document(page_content='한스 크리스티안 안데르센(1805년 4월 2일 ~ 1875년 8월'),
    Document(page_content='4일)은 덴마크의 동화작가이자 소설가다.'),
    Document(page_content='## 생애'),
    Document(page_content='안데르센은 덴마크의 오덴세에서 구두 수선공의 아들로 태어났다.'),
    Document(page_content='## 주요 작품'),
    Document(page_content='즉흥시인, 빨간 구두, 눈의 여왕, 인어공주, 성냥팔이 소녀, 벌거숭이'),
    Document(page_content='임금님, 미운 오리 새끼, 엄지 공주, 꿋꿋한 주석 병정, 야생의 백조'),
    Document(page_content='## 안데르센 문학의 특징'),
    Document(page_content='안데르센 문학은 안데르센이 가난한 구두 수선공의 아들이라는 것에 영향을'),
    Document(page_content='많이 받았다. 《성냥팔이 소녀》는 가난하게 자라서 구걸까지 해야 했던'),
    Document(page_content='안데르센의 어머니를 소재로 한 작품이다.'),
    Document(page_content='## 출처\\n위키피디아')
]
[
    Document(page_content='class Person:\\n  def __init__(self, name, age):\\n    self.name = name\\n    self.age = age'),
    Document(page_content='p1 = Person("Andersen", 70)\\n\\nfor i in range(10):\\n    print (i)')
]
[
    Document(page_content='// Function is called, the return value will end up in age'),
    Document(page_content='let age = myFunction(1805, 1875);'),
    Document(page_content='function myFunction(a, b) {'),
    Document(page_content='// Function returns the age of born and died\\n  return b - a;\\n}')
]

 

 

 

레벨 4: Semantic Chunking(의미/의미론적 분할)

- 정의: 임베딩을 사용하여 의미를 추출하고 이 부분들 사이의 의미 관계를 평가하는 방법
- 사용 가능한 클래스: Llamaindex에서 제공하는 SemanticSplitterNodeParse는 임베딩 유사성을 바탕으로
                                 문장 사이에 적응적으로 분할 지점을 결정
- 조정 가능한 매개변수:
     — 버퍼 크기: 분할 영역에 대한 크기 
     — 분할 백분위 기준선: 분할 기준을 결정할 임계값
     — 임베드 모드: 사용된 임베딩 모델

- Code : content.txt 청킹 예 

from rich import print
from langchain.docstore.document import Document
from langchain_community.chat_models import ChatOllama
from langchain_community.vectorstores import Chroma
from langchain_community import embeddings
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate

local_llm = ChatOllama(model="mistral:v0.2")

# RAG
def rag(chunks, collection_name):
    vectorstore = Chroma.from_documents(
        documents=documents,
        collection_name=collection_name,
        embedding=embeddings.ollama.OllamaEmbeddings(model='nomic-embed-text'),
    )
    retriever = vectorstore.as_retriever()

    prompt_template = """
    다음 문맥에 근거해서만 질문에 답하세요 : 
    {context}
    질문 : {question}
    """
    prompt = ChatPromptTemplate.from_template(prompt_template)

    chain = (
        {"context": retriever, "question": RunnablePassthrough()}
        | prompt
        | local_llm
        | StrOutputParser()
    )
    result = chain.invoke("안데르센은 언제부터 동화를 썼나요?")
    print(result)
    
with open('content.txt', 'r', encoding='utf-8') as file:
    text = file.read()

# 4. Semantic Chunking
print("#### Semantic Chunking ####")
    
from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai.embeddings import OpenAIEmbeddings

# Percentile - 백분위수, 문장 간의 모든 차이를 계산한 다음 X 백분위수보다 큰 차이는 분할됩니다.
text_splitter = SemanticChunker(OpenAIEmbeddings())
text_splitter = SemanticChunker(
    OpenAIEmbeddings(), breakpoint_threshold_type="percentile" #standard_deviation(표준_편차),interquartile(사분위수)
)
documents = text_splitter.create_documents([text])
print(documents)

# Result 
print("-- Automatic Result --")
rag(documents, "Character-Text")

 

- Result :

#### Semantic Chunking ####
[
    Document(
        page_content='# 동화 작가 \\n\\n## 안데르센\\n한스 크리스티안 안데르센(덴마크어: Hans Christian Andersen 한스 크리스티안 
아네르센[*], 1805년 4월 2일 ~ 1875년 8월 4일)은 덴마크의 동화작가이자 소설가다. 그는 사는 동안에 여러 나라 어린이들을 기쁘게 하는 데 
성공했다.'
    ),
    Document(
        page_content='그의 시와 이야기는 150개가 넘는 언어로 번역되었다. 그가 쓴 작품은 여러 영화, 연극, 발레, 애니메이션이 탄생하는 
데 필요한 영감을 불러 일으켰다.[1]\\n\\n## 생애\\n안데르센은 덴마크의 오덴세에서 구두 수선공의 아들로 태어났다. 한스 크리스티안 
안데르센이라는 이름은 안데르센이 루터교에서 세례를 받았을 때 대부모(代父母)[2]가 붙여준 이름이다. 안데르센의 집안은 할머니가 병원에서 
청소 노동자로 일할 정도로 가난하여, 안데르센의 성장 과정에 큰 영향을 끼쳤다. 독실한 루터교 신자인 어머니는 안데르센에게 예수를 
공경하는 순수한 개신교 신앙을 심어주었고, 아버지는 인형극과 독서를 통해 어린 그에게 옛날 이야기와 <아라비안 나이트>를 자주 들려 주며 
상상력과 교양을 심어주었다. 어린시절 아버지의 갑작스러운 별세로, 가장의 자리가 비게 되자 안데르센은 어린나이에 공장에서 일하고, 
어머니는 빨래를 대신해주는 일을 했다. 1819년에는 연극 배우의 꿈을 품고 코펜하겐으로 갔으나, 변성기 이후 목소리가 탁해지면서 꿈을 
접어야 했다. 더구나 가난 때문에 정규 교육을 받지 못해서 문법과 맞춤법이 엉망인 그의 연극대본은 극단주에 의해 반송되었기에 자살을 
생각할 정도로 극심한 마음의 고통에 시달렸다. 다행히 그의 작가로서의 재능을 알아본 덴마크 의회 의원인 요나스 콜린의 후원으로 라틴어 
학교에 입학했으나, 안데르센이 시를 쓰는 것을 싫어하는 교장과의 갈등 때문에, 5년 만에 학교를 그만두고 1828년 코펜하겐 대학교에 
입학하였다. 몇 편의 희곡, 소설을 쓰면서 작가로서의 재능을 드러낸 안데르센은 《즉흥시인》(1834년작)으로 문학계의 호평을 받았다. 
1835년부터 본격적인 동화 저작에 들어갔는데, 어른들도 읽을 정도로 독자들의 반응이 좋았다. 하지만, 일부 문학비평가들은 "《즉흥시인》을 
쓸 정도로 뛰어난 작가가 어린이를 속이는 이야기나 쓴다."는 가혹한 비판을 하기도 했다. 1872년까지 발표한 총 160여편의 동화 작품은 모두 
유명해져서 연금 수령, 안데르센의 그림이 들어간 우표 발행이라는 영광을 누렸다. 62세 때 그는 고향 오덴세의 명예 시민으로 받들어졌으며 
1875년 수도인 코펜하겐에서 병으로 세상을 떠났다. 그의 장례식에는 덴마크 국왕과 왕비가 참석하였다. 2005년 4월 2일에 안데르센 탄생 
200주년을 맞아, 200주년 기념 웹사이트가 개설되기도 했다.[3]\\n\\n## 주요 작품\\n즉흥시인, 빨간 구두, 눈의 여왕, 인어공주, 성냥팔이 소녀, 
벌거숭이 임금님, 미운 오리 새끼, 엄지 공주, 꿋꿋한 주석 병정, 야생의 백조\\n\\n## 안데르센 문학의 특징\\n안데르센 문학은 안데르센이 
가난한 구두 수선공의 아들이라는 것에 영향을 많이 받았다. 《성냥팔이 소녀》는 가난하게 자라서 구걸까지 해야 했던 안데르센의 어머니를 
소재로 한 작품이다. 또한 《눈의 여왕》은 어렸을 때 나폴레옹 전쟁에 참전했다가 돌아온 아버지가, 서리가 내리던 밤에 신경쇠약으로 죽자, 
고아가 되었고 이를 \\'눈의 여왕\\'이 데려가는 것으로 생각한 어린시절의 기억이 소재가 되었으며, 《미운 오리 새끼》는 안데르센이 작가로 
데뷔한 후에도, 그의 출신 때문에 홀대를 받은 상처가 문학으로 표현된 작품이다. ## 출처\\n위키피디아 '
    )
]
# Case-Kr: .. .invoke("안데르센은 언제부터 동화를 썼나요?")

-- Automatic Result --
Number of requested results 4 is greater than number of elements in index 2, updating n_results = 2
 Answer: Hans Christian Andersen began writing fairy tales from the time he debuted as a writer. However, some of his most famous 
works such as "The Ugly Duckling," "The Little Mermaid," and "Thumbelina" were published starting in the 1830s and 1840s.
# Case-En: .. .invoke("When did Andersen start writing fairy tales?")

-- Automatic Result --
Number of requested results 4 is greater than number of elements in index 2, updating n_results = 2
 Andersen started writing fairy tales in the late 1830s.

 

 

레벨 5: Agentic Chunking(에이전트 기반 분할)

- 정의: 맥락에 따라 얼마나 많은 텍스트를 어떤 부분으로 포함시킬지 ‘LLM을 사용하여’ 결정하는 방법
- 사용 가능한 클래스: ’Proposiitional-retrieval template’은 Langchain에서 제공하는 에이전트 기반 청킹을 위한 템플릿이다

 

- Code 01: content.txt 청킹

from rich import print
from langchain.docstore.document import Document
from langchain_community.chat_models import ChatOllama
from langchain_community.vectorstores import Chroma
from langchain_community import embeddings
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate

local_llm = ChatOllama(model="mistral:v0.2")

# RAG
def rag(chunks, collection_name):
    vectorstore = Chroma.from_documents(
        documents=documents,
        collection_name=collection_name,
        embedding=embeddings.ollama.OllamaEmbeddings(model='nomic-embed-text'),
    )
    retriever = vectorstore.as_retriever()

    prompt_template = """
    다음 문맥에 근거해서만 질문에 답하세요 : 
    {context}
    질문 : {question}
    """
    prompt = ChatPromptTemplate.from_template(prompt_template)

    chain = (
        {"context": retriever, "question": RunnablePassthrough()}
        | prompt
        | local_llm
        | StrOutputParser()
    )
    result = chain.invoke("안데르센은 언제부터 작품 활동을 시작했나요?")
    print(result)

with open('content.txt', 'r', encoding='utf-8') as file:
    text = file.read()

# 5. Agentic Chunking
print("#### Proposition-Based Chunking ####")
# <https://arxiv.org/pdf/2312.06648.pdf>

from langchain.output_parsers.openai_tools import JsonOutputToolsParser
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableLambda
from langchain.chains import create_extraction_chain
from typing import Optional, List
from langchain.chains import create_extraction_chain_pydantic
from langchain_core.pydantic_v1 import BaseModel
from langchain import hub

obj = hub.pull("wfh/proposal-indexing")
llm = ChatOpenAI(model='gpt-3.5-turbo')
runnable = obj | llm

class Sentences(BaseModel):
    sentences: List[str]
    
    
# 추출 Extraction 
extraction_chain = create_extraction_chain_pydantic(pydantic_schema=Sentences, llm=llm)
def get_propositions(text):
    runnable_output = runnable.invoke({
    	"input": text
    }).content
    propositions = extraction_chain.invoke(runnable_output)["text"][0].sentences
    return propositions
    
paragraphs = text.split("\\n\\n")
text_propositions = []
for i, para in enumerate(paragraphs[:5]):
    propositions = get_propositions(para)
    text_propositions.extend(propositions)
    print (f"Done with {i}")

print (f"You have {len(text_propositions)} propositions")
print(text_propositions[:10])

print("#### Agentic Chunking ####")

from rag_5Chunker import AgenticChunker
ac = AgenticChunker()
ac.add_propositions(text_propositions)
print(ac.pretty_print_chunks())
chunks = ac.get_chunks(get_type='list_of_strings')
print(chunks)
documents = [Document(page_content=chunk, metadata={"source": "local"}) for chunk in chunks]
rag(documents, "agentic-chunks")

 

- Code 02: 청킹 에이전트 구성

from langchain_core.prompts import ChatPromptTemplate
import uuid
from langchain_openai import ChatOpenAI
import os
from typing import Optional
from langchain_core.pydantic_v1 import BaseModel
from langchain.chains import create_extraction_chain_pydantic
from dotenv import load_dotenv
from rich import print

load_dotenv()

class AgenticChunker:
    def __init__(self, openai_api_key=None):
        self.chunks = {}
        self.id_truncate_limit = 5

        # 새로운 정보를 얻을 때 요약 및 제목을 업데이트/수정할지 여부
        self.generate_new_metadata_ind = True
        self.print_logging = True

        if openai_api_key is None:
            openai_api_key = os.getenv("OPENAI_API_KEY")

        if openai_api_key is None:
            raise ValueError("API key is not provided and not found in environment variables")

        self.llm = ChatOpenAI(model='gpt-3.5-turbo', openai_api_key=openai_api_key, temperature=0)

    def add_propositions(self, propositions):
        for proposition in propositions:
            self.add_proposition(proposition)
    
    def add_proposition(self, proposition):
        if self.print_logging:
            print (f"\\nAdding: '{proposition}'")

        # 첫 번째 청크인 경우 새 청크를 만들고 다른 청크는 확인하지 마세요.
        if len(self.chunks) == 0:
            if self.print_logging:
                print ("No chunks, creating a new one")
            self._create_new_chunk(proposition)
            return

        chunk_id = self._find_relevant_chunk(proposition)

        # 청크가 발견되면 여기에 명제를 추가합니다.
        if chunk_id:
            if self.print_logging:
                print (f"Chunk Found ({self.chunks[chunk_id]['chunk_id']}), adding to: {self.chunks[chunk_id]['title']}")
            self.add_proposition_to_chunk(chunk_id, proposition)
            return
        else:
            if self.print_logging:
                print ("No chunks found")
            # 청크를 찾을 수 없는 경우 새 청크를 만듭니다.
            self._create_new_chunk(proposition)
        

    def add_proposition_to_chunk(self, chunk_id, proposition):
        # Add then
        self.chunks[chunk_id]['propositions'].append(proposition)

        # 그런 다음 새로운 요약을 확인하세요.
        if self.generate_new_metadata_ind:
            self.chunks[chunk_id]['summary'] = self._update_chunk_summary(self.chunks[chunk_id])
            self.chunks[chunk_id]['title'] = self._update_chunk_title(self.chunks[chunk_id])

    def _update_chunk_summary(self, chunk):
        """
        If you add a new proposition to a chunk, you may want to update the summary or else they could get stale
        """
        PROMPT = ChatPromptTemplate.from_messages(
            [
                (
                    "system",
                    """
                    You are the steward of a group of chunks which represent groups of sentences that talk about a similar topic
                    A new proposition was just added to one of your chunks, you should generate a very brief 1-sentence summary which will inform viewers what a chunk group is about.

                    A good summary will say what the chunk is about, and give any clarifying instructions on what to add to the chunk.

                    You will be given a group of propositions which are in the chunk and the chunks current summary.

                    Your summaries should anticipate generalization. If you get a proposition about apples, generalize it to food.
                    Or month, generalize it to "date and times".

                    Example:
                    Input: Proposition: Greg likes to eat pizza
                    Output: This chunk contains information about the types of food Greg likes to eat.

                    Only respond with the chunk new summary, nothing else.
                    """,
                ),
                ("user", "Chunk's propositions:\\n{proposition}\\n\\nCurrent chunk summary:\\n{current_summary}"),
            ]
        )

        runnable = PROMPT | self.llm

        new_chunk_summary = runnable.invoke({
            "proposition": "\\n".join(chunk['propositions']),
            "current_summary" : chunk['summary']
        }).content

        return new_chunk_summary
    
    def _update_chunk_title(self, chunk):
        """
        If you add a new proposition to a chunk, you may want to update the title or else it can get stale
        """
        PROMPT = ChatPromptTemplate.from_messages(
            [
                (
                    "system",
                    """
                    You are the steward of a group of chunks which represent groups of sentences that talk about a similar topic
                    A new proposition was just added to one of your chunks, you should generate a very brief updated chunk title which will inform viewers what a chunk group is about.

                    A good title will say what the chunk is about.

                    You will be given a group of propositions which are in the chunk, chunk summary and the chunk title.

                    Your title should anticipate generalization. If you get a proposition about apples, generalize it to food.
                    Or month, generalize it to "date and times".

                    Example:
                    Input: Summary: This chunk is about dates and times that the author talks about
                    Output: Date & Times

                    Only respond with the new chunk title, nothing else.
                    """,
                ),
                ("user", "Chunk's propositions:\\n{proposition}\\n\\nChunk summary:\\n{current_summary}\\n\\nCurrent chunk title:\\n{current_title}"),
            ]
        )

        runnable = PROMPT | self.llm

        updated_chunk_title = runnable.invoke({
            "proposition": "\\n".join(chunk['propositions']),
            "current_summary" : chunk['summary'],
            "current_title" : chunk['title']
        }).content

        return updated_chunk_title

    def _get_new_chunk_summary(self, proposition):
        PROMPT = ChatPromptTemplate.from_messages(
            [
                (
                    "system",
                    """
                    You are the steward of a group of chunks which represent groups of sentences that talk about a similar topic
                    You should generate a very brief 1-sentence summary which will inform viewers what a chunk group is about.

                    A good summary will say what the chunk is about, and give any clarifying instructions on what to add to the chunk.

                    You will be given a proposition which will go into a new chunk. This new chunk needs a summary.

                    Your summaries should anticipate generalization. If you get a proposition about apples, generalize it to food.
                    Or month, generalize it to "date and times".

                    Example:
                    Input: Proposition: Greg likes to eat pizza
                    Output: This chunk contains information about the types of food Greg likes to eat.

                    Only respond with the new chunk summary, nothing else.
                    """,
                ),
                ("user", "Determine the summary of the new chunk that this proposition will go into:\\n{proposition}"),
            ]
        )

        runnable = PROMPT | self.llm

        new_chunk_summary = runnable.invoke({
            "proposition": proposition
        }).content

        return new_chunk_summary
    
    def _get_new_chunk_title(self, summary):
        PROMPT = ChatPromptTemplate.from_messages(
            [
                (
                    "system",
                    """
                    You are the steward of a group of chunks which represent groups of sentences that talk about a similar topic
                    You should generate a very brief few word chunk title which will inform viewers what a chunk group is about.

                    A good chunk title is brief but encompasses what the chunk is about

                    You will be given a summary of a chunk which needs a title

                    Your titles should anticipate generalization. If you get a proposition about apples, generalize it to food.
                    Or month, generalize it to "date and times".

                    Example:
                    Input: Summary: This chunk is about dates and times that the author talks about
                    Output: Date & Times

                    Only respond with the new chunk title, nothing else.
                    """,
                ),
                ("user", "Determine the title of the chunk that this summary belongs to:\\n{summary}"),
            ]
        )

        runnable = PROMPT | self.llm

        new_chunk_title = runnable.invoke({
            "summary": summary
        }).content

        return new_chunk_title

    def _create_new_chunk(self, proposition):
        new_chunk_id = str(uuid.uuid4())[:self.id_truncate_limit] # I don't want long ids
        new_chunk_summary = self._get_new_chunk_summary(proposition)
        new_chunk_title = self._get_new_chunk_title(new_chunk_summary)

        self.chunks[new_chunk_id] = {
            'chunk_id' : new_chunk_id,
            'propositions': [proposition],
            'title' : new_chunk_title,
            'summary': new_chunk_summary,
            'chunk_index' : len(self.chunks)
        }
        if self.print_logging:
            print (f"Created new chunk ({new_chunk_id}): {new_chunk_title}")
    
    def get_chunk_outline(self):
        """
        Get a string which represents the chunks you currently have.
        This will be empty when you first start off
        """
        chunk_outline = ""

        for chunk_id, chunk in self.chunks.items():
            single_chunk_string = f"""Chunk ({chunk['chunk_id']}): {chunk['title']}\\nSummary: {chunk['summary']}\\n\\n"""
        
            chunk_outline += single_chunk_string
        
        return chunk_outline

    def _find_relevant_chunk(self, proposition):
        current_chunk_outline = self.get_chunk_outline()

        PROMPT = ChatPromptTemplate.from_messages(
            [
                (
                    "system",
                    """
                    Determine whether or not the "Proposition" should belong to any of the existing chunks.

                    A proposition should belong to a chunk of their meaning, direction, or intention are similar.
                    The goal is to group similar propositions and chunks.

                    If you think a proposition should be joined with a chunk, return the chunk id.
                    If you do not think an item should be joined with an existing chunk, just return "No chunks"

                    Example:
                    Input:
                        - Proposition: "Greg really likes hamburgers"
                        - Current Chunks:
                            - Chunk ID: 2n4l3d
                            - Chunk Name: Places in San Francisco
                            - Chunk Summary: Overview of the things to do with San Francisco Places

                            - Chunk ID: 93833k
                            - Chunk Name: Food Greg likes
                            - Chunk Summary: Lists of the food and dishes that Greg likes
                    Output: 93833k
                    """,
                ),
                ("user", "Current Chunks:\\n--Start of current chunks--\\n{current_chunk_outline}\\n--End of current chunks--"),
                ("user", "Determine if the following statement should belong to one of the chunks outlined:\\n{proposition}"),
            ]
        )

        runnable = PROMPT | self.llm

        chunk_found = runnable.invoke({
            "proposition": proposition,
            "current_chunk_outline": current_chunk_outline
        }).content

        # Pydantic data class
        class ChunkID(BaseModel):
            """Extracting the chunk id"""
            chunk_id: Optional[str]
            
        # 추출을 통해 모든 LLM 응답을 포착합니다. 이것은 임시방편입니다.
        extraction_chain = create_extraction_chain_pydantic(pydantic_schema=ChunkID, llm=self.llm)
        extraction_found = extraction_chain.invoke(chunk_found)["text"]
        if extraction_found:
            chunk_found = extraction_found[0].chunk_id

        # 청크 ID 제한이 아닌 응답을 받은 경우 불량 응답이거나 아무것도 찾지 못했을 가능성이 있습니다.
        # So return nothing
        if len(chunk_found) != self.id_truncate_limit:
            return None

        return chunk_found
    
    def get_chunks(self, get_type='dict'):
        """
        This function returns the chunks in the format specified by the 'get_type' parameter.
        If 'get_type' is 'dict', it returns the chunks as a dictionary.
        If 'get_type' is 'list_of_strings', it returns the chunks as a list of strings, where each string is a proposition in the chunk.
        """
        if get_type == 'dict':
            return self.chunks
        if get_type == 'list_of_strings':
            chunks = []
            for chunk_id, chunk in self.chunks.items():
                chunks.append(" ".join([x for x in chunk['propositions']]))
            return chunks
    
    def pretty_print_chunks(self):
        print (f"\\nYou have {len(self.chunks)} chunks\\n")
        for chunk_id, chunk in self.chunks.items():
            print(f"Chunk #{chunk['chunk_index']}")
            print(f"Chunk ID: {chunk_id}")
            print(f"Summary: {chunk['summary']}")
            print(f"Propositions:")
            for prop in chunk['propositions']:
                print(f"    -{prop}")
            print("\\n\\n")

    def pretty_print_chunk_outline(self):
        print ("Chunk Outline\\n")
        print(self.get_chunk_outline())

if __name__ == "__main__":
    ac = AgenticChunker()

    ## Comment and uncomment 마음껏 명제를 제안하세요
    propositions = [
        "The month is October.",
        "The year is 2023.",
        "One of the most important things that I didn't understand about the world as a child was the degree to which the returns for performance are superlinear.",
        "Teachers and coaches implicitly told us that the returns were linear.",
        "I heard a thousand times that 'You get out what you put in.' ",
        "Teachers and coaches meant well.",
        "In fame, power, military victories, knowledge, and benefit to humanity, the rich get richer."
    ]
    
    ac.add_propositions(propositions)
    ac.pretty_print_chunks()
    ac.pretty_print_chunk_outline()
    print (ac.get_chunks(get_type='list_of_strings'))

 

- Result :

#### Proposition-Based Chunking ####
Done with 0
Done with 1
Done with 2
Done with 3
Done with 4
You have 52 propositions
[
    'The person is a fairy tale writer.',
    '한스 크리스티안 안데르센은 덴마크의 동화작가이다.',
    '한스 크리스티안 안데르센은 덴마크의 소설가이다.',
    '한스 크리스티안 안데르센은 1805년 4월 2일에 태어났다.',
    '한스 크리스티안 안데르센은 1875년 8월 4일에 돌아가셨다.',
    '한스 크리스티안 안데르센은 사는 동안 여러 나라 어린이들을 기쁘게 하는 데 성공했다.',
    '한스 크리스티안 안데르센의 시와 이야기는 150개가 넘는 언어로 번역되었다.',
    '한스 크리스티안 안데르센이 쓴 작품은 여러 영화, 연극, 발레, 애니메이션의 영감을 불러 일으켰다.',
    '안데르센은 덴마크의 오덴세에서 태어났다.',
    '안데르센의 아버지는 구두 수선공이었다.'
]
#### Agentic Chunking ####

Adding: 'The person is a fairy tale writer.'
No chunks, creating a new one
Created new chunk (94a43): Occupation

Adding: '한스 크리스티안 안데르센은 덴마크의 동화작가이다.'
No chunks found
Created new chunk (de5b3): Fairy Tale Writer

Adding: '한스 크리스티안 안데르센은 덴마크의 소설가이다.'
No chunks found
Created new chunk (9bdd4): Authors

Adding: '한스 크리스티안 안데르센은 1805년 4월 2일에 태어났다.'
No chunks found
Created new chunk (c60bf): Dates & Times

Adding: '한스 크리스티안 안데르센은 1875년 8월 4일에 돌아가셨다.'
No chunks found
Created new chunk (f7a0d): Date & Time

Adding: '한스 크리스티안 안데르센은 사는 동안 여러 나라 어린이들을 기쁘게 하는 데 성공했다.'
No chunks found
Created new chunk (a35ac): Children's Literature

Adding: '한스 크리스티안 안데르센의 시와 이야기는 150개가 넘는 언어로 번역되었다.'
No chunks found
Created new chunk (909ce): Translations

Adding: '한스 크리스티안 안데르센이 쓴 작품은 여러 영화, 연극, 발레, 애니메이션의 영감을 불러 일으켰다.'
No chunks found
Created new chunk (e4125): Art Inspired by Andersen

Adding: '안데르센은 덴마크의 오덴세에서 태어났다.'
No chunks found
Created new chunk (85670): Birthplace of Andersen

Adding: '안데르센의 아버지는 구두 수선공이었다.'
No chunks found
Created new chunk (4e619): Family Background

Adding: '한스 크리스티안 안데르센은 루터교에서 세례를 받을 때 대부모가 붙여준 이름이다.'
No chunks found
Created new chunk (d491b): Personal Naming

Adding: '안데르센의 집안은 할머니가 병원에서 청소 노동자로 일하며 가난했다.'
No chunks found
Created new chunk (24052): Family & Poverty

Adding: '할머니가 청소 노동자로 일하는 정도의 가난이 안데르센의 성장 과정에 영향을 끼쳤다.'
No chunks found
Created new chunk (e0120): Family Influence

Adding: '안데르센의 어머니는 독실한 루터교 신자였다.'
No chunks found
Created new chunk (e039a): Religious Beliefs

Adding: '안데르센의 어머니는 안데르센에게 순수한 개신교 신앙을 가르쳤다.'
No chunks found
Created new chunk (bb844): Religious Upbringing

Adding: '안데르센의 아버지는 인형극과 독서를 통해 안데르센에게 상상력과 교양을 심었다.'
No chunks found
Created new chunk (d35f3): Parental Influence

Adding: '안데르센은 어릴 때 공장에서 일했다.'
No chunks found
Created new chunk (088d5): Work Experience

Adding: '안데르센은 공장에서 일하게 된 것은 아버지의 갑작스러운 별세로 자리가 비게 되었기 때문이다.'
No chunks found
Created new chunk (d0a70): Employment Reasons

Adding: '안데르센의 어머니는 빨래를 대신해주는 일을 했다.'
No chunks found
Created new chunk (6e161): Household Chores

Adding: '1819년에 안데르센은 코펜하겐으로 갔으나 목소리 변화로 연극 배우의 꿈을 접어야 했다.'
No chunks found
Created new chunk (eb91a): Life Events

Adding: '안데르센은 가난으로 정규 교육을 받지 못했다.'
No chunks found
Created new chunk (ffc30): Education & Poverty

Adding: '안데르센의 문법과 맞춤법이 엉망이었기 때문에 연극대본이 극단주에 반송되었다.'
No chunks found
Created new chunk (32fd0): Writing Errors

Adding: '안데르센은 자살을 생각할 정도로 극심한 마음의 고통을 겪었다.'
No chunks found
Created new chunk (52919): Emotional Struggles

Adding: '요나스 콜린은 덴마크 의회 의원으로서 안데르센의 작가 재능을 알아보고 후원했다.'
No chunks found
Created new chunk (e00a1): Literary Support

Adding: '안데르센은 라틴어 학교에 요나스 콜린의 후원으로 입학했다.'
No chunks found
Created new chunk (0375c): Education & Sponsorship

Adding: '안데르센은 코펜하겐 대학교에 1828년에 입학했다.'
No chunks found
Created new chunk (8da47): Education & Biography

Adding: '안데르센은 1834년에 《즉흥시인》으로 문학계의 호평을 받았다.'
No chunks found
Created new chunk (d6354): Literary Achievements

Adding: '안데르센은 1835년부터 동화 작품을 쓰기 시작했다.'
No chunks found
Created new chunk (b5e9d): Author's Beginnings

Adding: '안데르센의 동화 작품은 어른들도 읽을 정도로 반응이 좋았다.'
No chunks found
Created new chunk (63b11): Literature & Reception

Adding: '1872년까지 안데르센은 총 160여편의 동화 작품을 발표했다.'
No chunks found
Created new chunk (c2c70): Literature

Adding: '안데르센은 고향 오덴세의 명예 시민으로 받들어졌다.'
No chunks found
Created new chunk (fcc3a): Honorary Citizenship

Adding: '1875년에 안데르센은 코펜하겐에서 병으로 세상을 떠났다.'
No chunks found
Created new chunk (cdd32): Historical Events

Adding: '안데르센의 장례식에는 덴마크 국왕과 왕비가 참석했다.'
No chunks found
Created new chunk (cede1): Funeral Attendees

Adding: '2005년 4월 2일에는 안데르센 탄생 200주년을 맞아 200주년 기념 웹사이트가 개설되었다.'
No chunks found
Created new chunk (ef454): Anniversaries & Celebrations

Adding: '주요 작품: 즉흥시인'
No chunks found
Created new chunk (e1b39): Poetry & Works

Adding: '주요 작품: 빨간 구두'
No chunks found
Created new chunk (6f5f3): Works of Art

Adding: '주요 작품: 눈의 여왕'
No chunks found
Created new chunk (75cde): Author's Major Works

Adding: '주요 작품: 인어공주'
No chunks found
Created new chunk (2b4c6): Literary Works

Adding: '주요 작품: 성냥팔이 소녀'
No chunks found
Created new chunk (d9dc4): Literary Works

Adding: '주요 작품: 벌거숭이 임금님'
No chunks found
Created new chunk (4cc45): Korean History

Adding: '주요 작품: 미운 오리 새끼'
No chunks found
Created new chunk (a08be): Literary Works

Adding: '주요 작품: 엄지 공주'
No chunks found
Created new chunk (35e31): Fairy Tale Works

Adding: '주요 작품: 꿋꿋한 주석 병정'
No chunks found
Created new chunk (d2f62): Author's Major Works

Adding: '주요 작품: 야생의 백조'
No chunks found
Created new chunk (13bb3): Literary Works

Adding: '안데르센 문학의 특징은 안데르센이 가난한 구두 수선공의 아들이라는 것에 영향을 많이 받았다.'
No chunks found
Created new chunk (19a23): Influences on Literature

Adding: '안데르센은 가난한 구두 수선공의 아들이었다.'
No chunks found
Created new chunk (ee950): Biography

Adding: '《성냥팔이 소녀》는 안데르센의 어머니를 소재로 한 작품이다.'
No chunks found
Created new chunk (63fa3): Literary Inspirations

Adding: '안데르센의 어머니는 가난하게 자라서 구걸까지 해야 했었다.'
No chunks found
Created new chunk (36935): Family Background

Adding: '《눈의 여왕》은 어릴 때 나폴레온 전쟁에 참전한 후 돌아온 아버지가 신경쇠약으로 죽은 뒤 안데르센이 고아가 되었던 경험을 소재로
한 작품이다.'
No chunks found
Created new chunk (e8a26): Personal Experiences

Adding: '안데르센이 어린 시절에 경험한 아버지의 죽음과 고아가 된 후 '눈의 여왕'에 대한 어린시절의 기억이 작품에 반영되었다.'
No chunks found
Created new chunk (dab58): Influences on Andersen

Adding: '《미운 오리 새끼》는 안데르센이 작가로 데뷔한 후에도, 그의 출신 때문에 홀대를 받은 상처가 문학으로 표현된 작품이다.'
No chunks found
Created new chunk (1eddb): Literary Analysis

Adding: '안데르센은 작가로 데뷔한 후에도 출신 때문에 홀대를 받은 상처를 경험했다.'
No chunks found
Created new chunk (6ebc1): Challenges in Success

You have 52 chunks

Chunk #0
Chunk ID: 94a43
Summary: This chunk contains information about the occupation of the person as a fairy tale writer.
Propositions:
    -The person is a fairy tale writer.

Chunk #1
Chunk ID: de5b3
Summary: This chunk provides information about the Danish fairy tale writer Hans Christian Andersen.
Propositions:
    -한스 크리스티안 안데르센은 덴마크의 동화작가이다.

Chunk #2
Chunk ID: 9bdd4
Summary: This chunk provides information about the Danish novelist Hans Christian Andersen.
Propositions:
    -한스 크리스티안 안데르센은 덴마크의 소설가이다.

Chunk #3
Chunk ID: c60bf
Summary: This chunk provides information about the birth date of Hans Christian Andersen.
Propositions:
    -한스 크리스티안 안데르센은 1805년 4월 2일에 태어났다.

Chunk #4
Chunk ID: f7a0d
Summary: This chunk contains information about the date and time of Hans Christian Andersen's passing.
Propositions:
    -한스 크리스티안 안데르센은 1875년 8월 4일에 돌아가셨다.

Chunk #5
Chunk ID: a35ac
Summary: This chunk discusses Hans Christian Andersen's success in bringing joy to children from various countries during his 
lifetime.
Propositions:
    -한스 크리스티안 안데르센은 사는 동안 여러 나라 어린이들을 기쁘게 하는 데 성공했다.

Chunk #6
Chunk ID: 909ce
Summary: This chunk contains information about the wide range of languages in which Hans Christian Andersen's poems and stories have 
been translated.
Propositions:
    -한스 크리스티안 안데르센의 시와 이야기는 150개가 넘는 언어로 번역되었다.

Chunk #7
Chunk ID: e4125
Summary: This chunk contains information about the various forms of art inspired by the works of Hans Christian Andersen.
Propositions:
    -한스 크리스티안 안데르센이 쓴 작품은 여러 영화, 연극, 발레, 애니메이션의 영감을 불러 일으켰다.

Chunk #8
Chunk ID: 85670
Summary: This chunk provides information about the birthplace of Andersen in Odense, Denmark.
Propositions:
    -안데르센은 덴마크의 오덴세에서 태어났다.

Chunk #9
Chunk ID: 4e619
Summary: This chunk provides information about Hans Christian Andersen's father's occupation.
Propositions:
    -안데르센의 아버지는 구두 수선공이었다.

Chunk #10
Chunk ID: d491b
Summary: This chunk provides information about the name given to Hans Christian Andersen by his godparents when he was baptized in the
Lutheran church.
Propositions:
    -한스 크리스티안 안데르센은 루터교에서 세례를 받을 때 대부모가 붙여준 이름이다.

Chunk #11
Chunk ID: 24052
Summary: This chunk provides information about the grandmother working as a cleaner in a hospital and the poverty in Andersen's 
household.
Propositions:
    -안데르센의 집안은 할머니가 병원에서 청소 노동자로 일하며 가난했다.

Chunk #12
Chunk ID: e0120
Summary: This chunk discusses the impact of a grandmother working as a cleaning laborer on Andersen's growth process.
Propositions:
    -할머니가 청소 노동자로 일하는 정도의 가난이 안데르센의 성장 과정에 영향을 끼쳤다.

Chunk #13
Chunk ID: e039a
Summary: This chunk provides information about Hans Christian Andersen's mother and her strong faith in the Lutheran religion.
Propositions:
    -안데르센의 어머니는 독실한 루터교 신자였다.

Chunk #14
Chunk ID: bb844
Summary: This chunk contains information about Andersen's mother teaching him a pure Protestant faith.
Propositions:
    -안데르센의 어머니는 안데르센에게 순수한 개신교 신앙을 가르쳤다.

Chunk #15
Chunk ID: d35f3
Summary: This chunk contains information about how Andersen's father nurtured his imagination and culture through puppetry and 
reading.
Propositions:
    -안데르센의 아버지는 인형극과 독서를 통해 안데르센에게 상상력과 교양을 심었다.

Chunk #16
Chunk ID: 088d5
Summary: This chunk contains information about Andersen's work experience in a factory during his childhood.
Propositions:
    -안데르센은 어릴 때 공장에서 일했다.

Chunk #17
Chunk ID: d0a70
Summary: This chunk contains information about the reasons why Andersen started working at the factory.
Propositions:
    -안데르센은 공장에서 일하게 된 것은 아버지의 갑작스러운 별세로 자리가 비게 되었기 때문이다.

Chunk #18
Chunk ID: 6e161
Summary: This chunk contains information about the tasks Andersen's mother performed in place of doing laundry.
Propositions:
    -안데르센의 어머니는 빨래를 대신해주는 일을 했다.

Chunk #19
Chunk ID: eb91a
Summary: This chunk provides information about Andersen's visit to Copenhagen in 1819 and his decision to give up his dream of 
becoming a theater actor due to a change in his voice.
Propositions:
    -1819년에 안데르센은 코펜하겐으로 갔으나 목소리 변화로 연극 배우의 꿈을 접어야 했다.

Chunk #20
Chunk ID: ffc30
Summary: This chunk discusses Andersen's inability to receive formal education due to poverty.
Propositions:
    -안데르센은 가난으로 정규 교육을 받지 못했다.

Chunk #21
Chunk ID: 32fd0
Summary: This chunk discusses issues with Andersen's grammar and spelling leading to the rejection of a theater script.
Propositions:
    -안데르센의 문법과 맞춤법이 엉망이었기 때문에 연극대본이 극단주에 반송되었다.

Chunk #22
Chunk ID: 52919
Summary: This chunk discusses the intense emotional pain that Andersen experienced, to the point of contemplating suicide.
Propositions:
    -안데르센은 자살을 생각할 정도로 극심한 마음의 고통을 겪었다.

Chunk #23
Chunk ID: e00a1
Summary: This chunk contains information about the support provided by Jonas Kolind, a member of the Danish parliament, to the writing
talent of Andersen.
Propositions:
    -요나스 콜린은 덴마크 의회 의원으로서 안데르센의 작가 재능을 알아보고 후원했다.

Chunk #24
Chunk ID: 0375c
Summary: This chunk contains information about Andersson's admission to a Latin school with the sponsorship of Jonas Collin.
Propositions:
    -안데르센은 라틴어 학교에 요나스 콜린의 후원으로 입학했다.

Chunk #25
Chunk ID: 8da47
Summary: This chunk contains information about Hans Christian Andersen's enrollment at the University of Copenhagen in 1828.
Propositions:
    -안데르센은 코펜하겐 대학교에 1828년에 입학했다.

Chunk #26
Chunk ID: d6354
Summary: This chunk contains information about the literary success of Andersen in 1834 with his work "The Improvisatore".
Propositions:
    -안데르센은 1834년에 《즉흥시인》으로 문학계의 호평을 받았다.

Chunk #27
Chunk ID: b5e9d
Summary: This chunk provides information about when Andersen began writing fairy tales.
Propositions:
    -안데르센은 1835년부터 동화 작품을 쓰기 시작했다.

Chunk #28
Chunk ID: 63b11
Summary: This chunk discusses the positive reception of Hans Christian Andersen's fairy tales, even among adults.
Propositions:
    -안데르센의 동화 작품은 어른들도 읽을 정도로 반응이 좋았다.

Chunk #29
Chunk ID: c2c70
Summary: This chunk provides information about the number of fairy tales Hans Christian Andersen published until 1872.
Propositions:
    -1872년까지 안데르센은 총 160여편의 동화 작품을 발표했다.

Chunk #30
Chunk ID: fcc3a
Summary: This chunk contains information about the recognition of Hans Christian Andersen as an honorary citizen of his hometown 
Odense.
Propositions:
    -안데르센은 고향 오덴세의 명예 시민으로 받들어졌다.

Chunk #31
Chunk ID: cdd32
Summary: This chunk provides information about the death of Andersen in Copenhagen in 1875.
Propositions:
    -1875년에 안데르센은 코펜하겐에서 병으로 세상을 떠났다.

Chunk #32
Chunk ID: cede1
Summary: This chunk contains information about the attendees at Andersen's funeral in Denmark.
Propositions:
    -안데르센의 장례식에는 덴마크 국왕과 왕비가 참석했다.

Chunk #33
Chunk ID: ef454
Summary: This chunk contains information about the celebration of the 200th anniversary of Andersen's birth with the launch of a 
commemorative website on April 2, 2005.
Propositions:
    -2005년 4월 2일에는 안데르센 탄생 200주년을 맞아 200주년 기념 웹사이트가 개설되었다.

Chunk #34
Chunk ID: e1b39
Summary: This chunk contains information about the major works of an improvisational poet.
Propositions:
    -주요 작품: 즉흥시인

Chunk #35
Chunk ID: 6f5f3
Summary: This chunk contains information about the major works of a specific author or artist.
Propositions:
    -주요 작품: 빨간 구두

Chunk #36
Chunk ID: 75cde
Summary: This chunk contains information about the major works of the author, including "The Snow Queen".
Propositions:
    -주요 작품: 눈의 여왕

Chunk #37
Chunk ID: 2b4c6
Summary: This chunk contains information about the major works of literature, with a focus on "The Little Mermaid".
Propositions:
    -주요 작품: 인어공주

Chunk #38
Chunk ID: d9dc4
Summary: This chunk contains information about the major works of literature, specifically focusing on the work "The Little Match 
Girl".
Propositions:
    -주요 작품: 성냥팔이 소녀

Chunk #39
Chunk ID: 4cc45
Summary: This chunk contains information about the major works of King Sejong the Great.
Propositions:
    -주요 작품: 벌거숭이 임금님

Chunk #40
Chunk ID: a08be
Summary: This chunk contains information about the major works of literature, specifically "The Ugly Duckling".
Propositions:
    -주요 작품: 미운 오리 새끼

Chunk #41
Chunk ID: 35e31
Summary: This chunk contains information about the major works of Thumbelina.
Propositions:
    -주요 작품: 엄지 공주

Chunk #42
Chunk ID: d2f62
Summary: This chunk contains information about the major works of a specific author.
Propositions:
    -주요 작품: 꿋꿋한 주석 병정

Chunk #43
Chunk ID: 13bb3
Summary: This chunk contains information about the major works of literature.
Propositions:
    -주요 작품: 야생의 백조

Chunk #44
Chunk ID: 19a23
Summary: This chunk discusses the influence of Hans Christian Andersen's background as the son of a poor shoemaker on his literature.
Propositions:
    -안데르센 문학의 특징은 안데르센이 가난한 구두 수선공의 아들이라는 것에 영향을 많이 받았다.

Chunk #45
Chunk ID: ee950
Summary: This chunk provides information about the background of Andersen, the son of a poor cobbler.
Propositions:
    -안데르센은 가난한 구두 수선공의 아들이었다.

Chunk #46
Chunk ID: 63fa3
Summary: This chunk discusses works of literature inspired by Hans Christian Andersen's mother.
Propositions:
    -《성냥팔이 소녀》는 안데르센의 어머니를 소재로 한 작품이다.

Chunk #47
Chunk ID: 36935
Summary: This chunk provides information about the difficult upbringing of Hans Christian Andersen's mother.
Propositions:
    -안데르센의 어머니는 가난하게 자라서 구걸까지 해야 했었다.

Chunk #48
Chunk ID: e8a26
Summary: This chunk contains information about the story of "The Snow Queen" by Hans Christian Andersen, which is based on his 
experience of becoming an orphan after his father returned from the Napoleonic Wars and died of mental illness.
Propositions:
    -《눈의 여왕》은 어릴 때 나폴레온 전쟁에 참전한 후 돌아온 아버지가 신경쇠약으로 죽은 뒤 안데르센이 고아가 되었던 경험을 소재로 한 
작품이다.

Chunk #49
Chunk ID: dab58
Summary: This chunk discusses how Hans Christian Andersen's childhood experiences of his father's death and becoming an orphan 
influenced his work, particularly his memories of "The Snow Queen."
Propositions:
    -안데르센이 어린 시절에 경험한 아버지의 죽음과 고아가 된 후 '눈의 여왕'에 대한 어린시절의 기억이 작품에 반영되었다.

Chunk #50
Chunk ID: 1eddb
Summary: This chunk discusses how the story "The Ugly Duckling" by Andersen reflects the author's personal experiences of being 
mistreated due to his background.
Propositions:
    -《미운 오리 새끼》는 안데르센이 작가로 데뷔한 후에도, 그의 출신 때문에 홀대를 받은 상처가 문학으로 표현된 작품이다.

Chunk #51
Chunk ID: 6ebc1
Summary: This chunk discusses the challenges Hans Christian Andersen faced due to his background even after debuting as a writer.
Propositions:
    -안데르센은 작가로 데뷔한 후에도 출신 때문에 홀대를 받은 상처를 경험했다.

None
[
    'The person is a fairy tale writer.',
    '한스 크리스티안 안데르센은 덴마크의 동화작가이다.',
    '한스 크리스티안 안데르센은 덴마크의 소설가이다.',
    '한스 크리스티안 안데르센은 1805년 4월 2일에 태어났다.',
    '한스 크리스티안 안데르센은 1875년 8월 4일에 돌아가셨다.',
    '한스 크리스티안 안데르센은 사는 동안 여러 나라 어린이들을 기쁘게 하는 데 성공했다.',
    '한스 크리스티안 안데르센의 시와 이야기는 150개가 넘는 언어로 번역되었다.',
    '한스 크리스티안 안데르센이 쓴 작품은 여러 영화, 연극, 발레, 애니메이션의 영감을 불러 일으켰다.',
    '안데르센은 덴마크의 오덴세에서 태어났다.',
    '안데르센의 아버지는 구두 수선공이었다.',
    '한스 크리스티안 안데르센은 루터교에서 세례를 받을 때 대부모가 붙여준 이름이다.',
    '안데르센의 집안은 할머니가 병원에서 청소 노동자로 일하며 가난했다.',
    '할머니가 청소 노동자로 일하는 정도의 가난이 안데르센의 성장 과정에 영향을 끼쳤다.',
    '안데르센의 어머니는 독실한 루터교 신자였다.',
    '안데르센의 어머니는 안데르센에게 순수한 개신교 신앙을 가르쳤다.',
    '안데르센의 아버지는 인형극과 독서를 통해 안데르센에게 상상력과 교양을 심었다.',
    '안데르센은 어릴 때 공장에서 일했다.',
    '안데르센은 공장에서 일하게 된 것은 아버지의 갑작스러운 별세로 자리가 비게 되었기 때문이다.',
    '안데르센의 어머니는 빨래를 대신해주는 일을 했다.',
    '1819년에 안데르센은 코펜하겐으로 갔으나 목소리 변화로 연극 배우의 꿈을 접어야 했다.',
    '안데르센은 가난으로 정규 교육을 받지 못했다.',
    '안데르센의 문법과 맞춤법이 엉망이었기 때문에 연극대본이 극단주에 반송되었다.',
    '안데르센은 자살을 생각할 정도로 극심한 마음의 고통을 겪었다.',
    '요나스 콜린은 덴마크 의회 의원으로서 안데르센의 작가 재능을 알아보고 후원했다.',
    '안데르센은 라틴어 학교에 요나스 콜린의 후원으로 입학했다.',
    '안데르센은 코펜하겐 대학교에 1828년에 입학했다.',
    '안데르센은 1834년에 《즉흥시인》으로 문학계의 호평을 받았다.',
    '안데르센은 1835년부터 동화 작품을 쓰기 시작했다.',
    '안데르센의 동화 작품은 어른들도 읽을 정도로 반응이 좋았다.',
    '1872년까지 안데르센은 총 160여편의 동화 작품을 발표했다.',
    '안데르센은 고향 오덴세의 명예 시민으로 받들어졌다.',
    '1875년에 안데르센은 코펜하겐에서 병으로 세상을 떠났다.',
    '안데르센의 장례식에는 덴마크 국왕과 왕비가 참석했다.',
    '2005년 4월 2일에는 안데르센 탄생 200주년을 맞아 200주년 기념 웹사이트가 개설되었다.',
    '주요 작품: 즉흥시인',
    '주요 작품: 빨간 구두',
    '주요 작품: 눈의 여왕',
    '주요 작품: 인어공주',
    '주요 작품: 성냥팔이 소녀',
    '주요 작품: 벌거숭이 임금님',
    '주요 작품: 미운 오리 새끼',
    '주요 작품: 엄지 공주',
    '주요 작품: 꿋꿋한 주석 병정',
    '주요 작품: 야생의 백조',
    '안데르센 문학의 특징은 안데르센이 가난한 구두 수선공의 아들이라는 것에 영향을 많이 받았다.',
    '안데르센은 가난한 구두 수선공의 아들이었다.',
    '《성냥팔이 소녀》는 안데르센의 어머니를 소재로 한 작품이다.',
    '안데르센의 어머니는 가난하게 자라서 구걸까지 해야 했었다.',
    '《눈의 여왕》은 어릴 때 나폴레온 전쟁에 참전한 후 돌아온 아버지가 신경쇠약으로 죽은 뒤 안데르센이 고아가 되었던 경험을 소재로 한 
작품이다.',
    "안데르센이 어린 시절에 경험한 아버지의 죽음과 고아가 된 후 '눈의 여왕'에 대한 어린시절의 기억이 작품에 반영되었다.",
    '《미운 오리 새끼》는 안데르센이 작가로 데뷔한 후에도, 그의 출신 때문에 홀대를 받은 상처가 문학으로 표현된 작품이다.',
    '안데르센은 작가로 데뷔한 후에도 출신 때문에 홀대를 받은 상처를 경험했다.'
]
# RAG : Agent

Based on the provided documents, there is no explicit information about when Andersen started writing fairy tales. The documents only mention that Andersen was born in Odense, Denmark, and worked in a factory as a child, and that his father was a shoemaker. There is no mention of Andersen's literary career or when it began.

 

 

 

 

*추가로 업데이트 할 부분 

코드와 결과를 모두 작성하다보니 본의아니게 스크롤 압박이 발생하고.. 작성 중에서 계속 딜레이가 생긴다.. 몇 번이나 날릴뻔 ㅜ
내용을 적절히 나누고 오히려 코드에 대한 설명을 추가하는 것이 더 좋을 것 같다는 생각이 들었다. 

1) 내용 분할, 코드 설명 추가 
2) open ai를 사용하지 않고 agentic chucking을 하는 코드를 테스트 후 추가 업데이트 예정 

 

 

 

참고 레퍼런스

https://medium.com/@anuragmishra_27746/five-levels-of-chunking-strategies-in-rag-notes-from-gregs-video-7b735895694d

 

Five Levels of Chunking Strategies in RAG| Notes from Greg’s Video

Introduction

medium.com

 

https://pub.towardsai.net/rag-in-action-beyond-basics-to-advanced-data-indexing-techniques-b7e07e3f5e43

 

RAG in Action: Beyond Basics to Advanced Data Indexing Techniques

Document Hierarchies, Knowledge Graphs, Advanced Chunking Strategies, Multi Retrieval, Hybrid Search, Reranking, Trade-offs and more

pub.towardsai.net

 

댓글