1. RAG(Retrieval Augmented Generation)
: LLM์ด ์ธ๋ถ ๋ฌธ์๋ฅผ ๊ฒ์ํด ์ฐธ๊ณ ํ ๋ค ๋ต๋ณ ์์ฑํ๋ ๊ธฐ๋ฒ
- LLM์ด ํ์ตํ์ง ์์ ์ต์ ์ ๋ณด ๋ค๋ฃจ๊ธฐ or ํ ๋ฃจ์๋ค์ด์ ์ค์ด๊ธฐ์ ํจ๊ณผ์
• ํ์ธํ๋ vs RAG ๋น๊ต
| ํญ๋ชฉ | ํ์ธํ๋ | RAG |
| ๋๋ฉ์ธ ์ต์ ํ | ๊ฐ๋ฅ | ์ ํ์ |
| ์ต์ ์ ๋ณด ๋ฐ์ | ๋ถ๊ฐ๋ฅ | ๊ฐ๋ฅ |
| ๊ตฌํ ๋์ด๋ | ๋์ | ๋ณดํต |
| ์ ์ฐ์ฑ | ๋ฎ์ | ๋์ |
1-1. RAG ์๋ ๋จ๊ณ
โ ์ ๋ณด ์ ์ฅ(์ธ๋ฑ์ฑ)

• Load : ์ธ๋ถ ๋ฐ์ดํฐ(ํ์ผ, DB, ์น ๋ฑ)๋ฅผ ๋ถ๋ฌ์ด
• Split(Chunking) : ๊ธด ํ ์คํธ๋ฅผ ์ผ์ ํฌ๊ธฐ์ chunk๋ก ๋ถํ
• Embedding : ๊ฐ chunk๋ฅผ ๋ฒกํฐ๋ก ๋ณํ
• Store(Vector DB) : ๋ฒกํฐ DB์ ์ ์ฅํด ์ ์ฌ ๊ฒ์์ด ๊ฐ๋ฅํ๋๋ก ์ค๋น
๊ด๊ณํ DB : ์ปฌ๋ผ ๋ด์ฉ ์ผ์นํ๋ ๊ฒ, ๋ฒกํฐ DB : ์๋ฏธ์ ์ผ๋ก ์ ์ฌํ ๊ฒ ์ฐพ์
โก ๊ฒ์&์์ฑ(Runtime)
- ์ฌ์ฉ์ ์ง๋ฌธ → Retrieve(์ ์ฌ chunk ๊ฒ์) → ํ๋กฌํํธ ๊ตฌ์ฑ → LLM ๋ต๋ณ ์์ฑ
• Retrieve : ์ง๋ฌธ ์๋ฒ ๋ฉ ํ ๋ฒกํฐ DB์์ ์ ์ฌ chunk ๊ฒ์
• Query : ๊ฒ์๋ chunk์ ์ฌ์ฉ์ ์ง๋ฌธ์ ํ๋กฌํํธ๋ก ๊ตฌ์ฑํด LLM์ ์ ๋ฌ
• Generation : ๋ฐ์ ํ๋กฌํํธ์ ๋ํ LLM ์๋ต ์์ฑ
2. Document Loader
: LLM์ ์ ๋ฌํ ์ฐธ์กฐ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๋ ๋๊ตฌ
- LangChain : ๋์ผํ ์ธํฐํ์ด์ค๋ก ๋ค์ํ ๋ฆฌ์์ค์์ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํ๋๋ก ์ง์
- ๋ฐํ ํ์ : list[Document]
| Document ์์ฑ | ์ค๋ช |
| page_content | ๋ฌธ์ ๋ด์ฉ(str) |
| metadata | ๋ฌธ์์ ๋ํ ๋ถ๊ฐ ์ ๋ณด(dict) |
| id | ๋ฌธ์ ์๋ณ์(optional) |
โ๏ธ LangChaind์ DocumentLoader๊ฐ ์๋ ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ฝ์ด๋ ๋ฌด๋ฐฉ!
2-1. TextLoader
: ํ ์คํธ ํ์ผ(.txt) ์ฝ์
from langchain_community.document_loaders import TextLoader
loader = TextLoader("data/olympic.txt", encoding="utf-8")
docs = loader.load() # ์ฆ์ ์ฝ๊ธฐ -> list[Document]
# docs = loader.lazy_load() # ์ง์ฐ ์ฝ๊ธฐ -> generator[Document]
2-2. PDF Loader
• PyPDFLoader(๊ธฐ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ : PyPDF2) : ๋น ๋ฅธ ํ ์คํธ ์ถ์ถ, ๊ฒฝ๋
• PyMuPDFLoader(๊ธฐ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ : PyMuPDF) : ์ด๋ฏธ์ง/์ฃผ์ ์ถ์ถ ์ฑ๋ฅ ์ฐ์
• PDFPlumberLoader(๊ธฐ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ : PDFPlumber) : ํ ๋ฑ ๋ณต์กํ ๊ตฌ์กฐ ์ฒ๋ฆฌ์ ๊ฐ์
from langchain_community.document_loaders import PyMuPDFLoader
loader = PyMuPDFLoader("data/novel/๊ธ_๋ฐ๋_์ฝฉ๋ฐญ_๊น์ ์ .pdf")
docs = loader.load() # ํ์ด์ง ๋จ์๋ก ๋ถ๋ฆฌ๋ list[Document]
2-3. WebBaseLoader
: requests + BeautifulSoup์ผ๋ก ์น ํ์ด์ง ํฌ๋กค๋งํด ๋ก๋
- RAG ํ์ง ํฅ์ ์ํด separator="\n", strip=True ์ค์ ๊ถ์ฅ
- SoupStrainer๋ก ํ์ํ ํ๊ทธ/์์ญ ์ ํ์ ํ์ฑ ๊ฐ๋ฅ
from langchain_community.document_loaders import WebBaseLoader
from bs4 import SoupStrainer
loader = WebBaseLoader(
web_path=["https://...url1", "https://...url2"],
bs_kwargs={
"parse_only":SoupStrainer(name"div", attrs={"class":"_article_content})
},
bs_get_text_kwargs={"strip":True, "seperator":"\n\n"}
)
docs = loader.load()
2-4. RecursiveUrlLoader
: ์์ URL์์ ๋ด๋ถ ๋งํฌ๋ฅผ ์ฌ๊ท์ ์ผ๋ก ๋ฐ๋ผ๊ฐ๋ฉฐ ์ฌ๋ฌ ํ์ด์ง๋ฅผ ์๋ ์์ง
from langchain_community.document_loaders import RecursiveUrlLoader
loader = RecursiveUrlLoader(
url="https://docs.python.org/3",
max_depth=2, # 0: ์์ ํ์ด์ง๋ง, 1: 1์ฐจ ๋งํฌ๊น์ง, 2: 2์ฐจ ๋งํฌ๊น์ง
prevent_outside=True, # ๋๋ฉ์ธ ์ธ๋ถ๋ก ๋๊ฐ์ง ์์
extractor=custom_extractor # ์ฌ์ฉ์ ์ ์ ํ
์คํธ ์ถ์ถ ํจ์
)
โ๏ธ WebBaseLoaer : ๋จ์ผ URL ๋จ์, RecursiveUrlLoader : ์ฌ์ดํธ ์ ์ฒด ํฌ๋กค๋ง
2-5. ArxivLoader
: ArxivLoader ์์ฒด๋ API ์ ๋ฐ์ดํธ๋ก ์๋ํ์ง ์์, arxiv ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ง์ ๊ฒ์ ํ PDF ๋ค์ด๋ก๋ ํด PyPDFLoader๋ก ๋ก๋
import arxiv
search = arxiv.Search(query="Advanced RAG", max_result=10, sort_by=arxiv.SortCriterion.Relevance)
client = arxiv.Client()
result = client.results(search)
- ๊ฒ์ ๊ฒฐ๊ณผ(arxiv.Result)์์ ์ ๋ชฉ, ์ ์, ์นดํ ๊ณ ๋ฆฌ, ์์ฝ, PDF URL ๋ฑ ์ถ์ถํด Document.metadata์ ๋ด์ ์ปค์คํ ํจ์ lode_arxiv_docs() ์ง์ ๊ตฌํ
2-6. DoclingLoader
: PDF, DOCX, PPTX, XLSX, HTML, ์ด๋ฏธ์ง ๋ฑ ๋ค์ํ ํ์์ ๊ตฌ์กฐํ๋ ๋ฐ์ดํฐ๋ก ๋ณํ
- ํ์ด์ง ๋ ์ด์์, ์ฝ๊ธฐ ์์, ํ ๊ตฌ์กฐ, ์์ ๋ฑ ์ ํํ ์ธ์
- OCR ์ง์(ํ์ฌ RapidOCR ํธํ์ฑ ๋ฌธ์ ๋ก ๋นํ์ฑํ ๊ถ์ฅ)
- Markdown, HTML, JSON ํ์ ์ถ๋ ฅ ์ง์
from langchain_docling import DoclingLoader
from langchain_docling.loader import ExportType
loader = DoclingLoader(
file_path=["paper1.pdf", "paper2.pdf"],
export_type=ExportType.MARKDOWN,
converter=converter # OCR ์ค์ ๋ฑ ํฌํจ
)
3. Chunking(๋ฌธ์ ๋ถํ )
: ๋ก๋ํ ๋ฌธ์๋ฅผ ์ผ์ ํ ๊ธฐ์ค์ ๋ฉ์ด๋ฆฌ(chunk)๋ก ๋๋๋ ์์
• ๋๋๋ ์ด์
โ ์๋ฒ ๋ฉ ๋ชจ๋ธ์ ์ปจํ ์คํธ ๊ธธ์ด ์ ํ ๊ทน๋ณต
โก ๊ฒ์ ์ ํ๋ ํฅ์ - ์์ chunk๊ฐ ์ง๋ฌธ์ ๋ ์ ํํ ๋งค์นญ
โข ๊ณ์ฐ ํจ์จ์ฑ - ๋ฒกํฐ ์ฐ์ฐ, ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ ๊ฐ
Splitter ๋ชฉํ : ์๋ฏธ ์๋ ๋ฉ์ด๋ฆฌ๋ฅผ ์ ์งํ๋ฉด์, ์ต๋ ๊ธธ์ด(chunk_size)๋ฅผ ๋์ง ์๋๋ก ๋๋
3-1. CharacterTextSplitter
: ๋จ์ผ ๊ตฌ๋ถ์(default: "\n\n") ๊ธฐ์ค ๋ถ๋ฆฌ
- ๋๋ ์กฐ๊ฐ์ด chunk_size๋ณด๋ค ์์ผ๋ฉด ๋ค์ ์กฐ๊ฐ๊ณผ ํฉ์นจ
- chunk_size๋ณด๋ค ํฐ ์กฐ๊ฐ์ด ์๊ฒจ๋ ๊ตฌ๋ถ์ ์ฐ์ ์ ์ฉ
- separator=""์ผ ๋๋ง chunk_overlap ์ ์ฉ
from langchain_text_splitters import CharacterTextSplitter
splitter = CharacterTextSplitter(
chunk_size=60,
chunk_overlap=10,
separator="" # ๊ธ์ ์ ๊ธฐ์ค์ผ๋ก ์๋ฆ
)
chunk_overlap : ์ฒญํฌ ๊ฒฝ๊ณ์์ ์ ์ฒญํฌ ๋๋ถ๋ถ์ ๋ค์ ์ฒญํฌ ์์ ๋ถ์ฌ ๋ฌธ๋งฅ ์ฐ์์ฑ ์ ์ง
- ๋น ๋ฌธ์์ด("")๋ก ์๋ฆฐ ๊ฒฝ์ฐ๋ง ์ ์ฉ(๊ตฌ๋ถ์๋ก ์ ์ ๋ถ๋ฆฌ๋ ๊ฒฝ์ฐ์๋ ๋ฏธ์ ์ฉ)
3-2. RecursiveCharacterTextSplitter
: ์ฌ๋ฌ ๊ตฌ๋ถ์๋ฅผ ์ฐ์ ์์๋๋ก ์ ์ฉํด ์์ฐ์ค๋ฌ์ด ๋จ์๋ก ๋ถํ
- ๊ธฐ๋ณธ ๊ตฌ๋ถ์ ์ฐ์ ์์ : "\n\n" → "\n" → " " → ""
- ์์ ๊ตฌ๋ถ์๋ก ๋๋ ์กฐ๊ฐ์ด chunk_size ์ด๊ณผ ์ ํ์ ๊ตฌ๋ถ์๋ก ์ฌ๊ท์ ์ฌ๋ถํ
from langchain_text_splitters import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separators=["\n\n", "\n", r"[\.?!,~]", " ", ""],
is_separator_regex=True # ๊ตฌ๋ถ์์ ์ ๊ท์ ์ฌ์ฉ ๊ฐ๋ฅ
)
# '๋ฌธ์ ๋ก๋ + ๋ถํ ' ํ ๋ฒ์
docs = loader.load_and_split(splitter)
3-3. ํ ํฐ ์ ๊ธฐ์ค ๋ถํ
: LLM์ ํ ํฐ ์ ํ์ด ์์ผ๋ฏ๋ก ๊ธ์ ์๋ณด๋ค ํ ํฐ ์ ๊ธฐ์ค์ด ๋ ์ ํ
# tiktoken(OpenAI GPT ๊ณ์ด ๊ถ์ฅ)
splitter = CharacterTextSplitter.from_tiktoken_encoder(
encoding_name="o200k_base", # GPT-4 ์ดํ ๋ชจ๋ธ
chunk_size=500,
chunk_overlap=50
)
# HuggingFace Tokenizer
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("google/gemma-3-4b-it")
splitter_hf = RecursiveCharacterTextSplitter.from_huggingface_tokenizer(
tokenizer=tokenizer,
chunk_size=500,
chunk_overlap=50
)
3-4. MarkdownHeaderTextSplitter
: Markdown ๋ฌธ์์์ ํค๋(#, ##, ###) ๊ธฐ์ค์ผ๋ก ๋ถํ . ํค๋ ์ ๋ณด๊ฐ metadata์ ์๋ ์ ์ฅ
from langchain_text_splitters import MarkdownHeaderTextSplitter
header_to_split = [
("#", "header1"),
("##", "header2"),
("###", "header3")
]
splitter = MarkdownHeaderTextSplitter(
headers_to_split_on=header_to_split,
strip_headers=True # ํค๋ ํ
์คํธ๋ฅผ ๋ด์ฉ์ ํฌํจํ ์ง ์ฌ๋ถ
)
# split_text(str)๋ง ์ง์(split_documents ์์)
docs = splitter.split_text(doc_txt)
- ๋ถํ ๋ ๊ฐ Document์ metadata์ {"header1": "...", "header2":"..."} ํํ๋ก ๊ณ์ธต ์ ๋ณด ์๋ ํฌํจ
'STUDY > LLM' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [LLM] Qdrant (1) | 2026.07.02 |
|---|---|
| [LLM] RAG - Embedding VectorDB (0) | 2026.07.01 |
| [LLM] Chain - LCEL (0) | 2026.06.27 |
| [LLM] Output Parser (0) | 2026.06.26 |
| [LLM] Prompt (0) | 2026.06.25 |