RAG์ LLM 2026๋ ํ: ๋ฐ์ดํฐ ์ฌ์ด์ธ์ค ๋ฉด์ ์ ์ํ ๊ฒ์ ์ฆ๊ฐ ์์ฑ ์๋ฒฝ ๊ฐ์ด๋
2026๋ ๋ฐ์ดํฐ ์ฌ์ด์ธ์ค ๋ฉด์ ์ ์ํ RAG ๊ฐ์ด๋์ ๋๋ค. ๊ฒ์ ์ฆ๊ฐ ์์ฑ ํ์ดํ๋ผ์ธ, ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค, ์ฒญํน, ์๋ฒ ๋ฉ, ์์ด์ ํฑ RAG, Graph RAG๋ฅผ ํฌ๊ด์ ์ผ๋ก ๋ค๋ฃน๋๋ค.

๊ฒ์ ์ฆ๊ฐ ์์ฑ(RAG: Retrieval-Augmented Generation)์ LLM์ ์ถ๋ ฅ์ ์ฌ์ค์ ๊ธฐ๋ฐํ ์ต์ ๋ฐ์ดํฐ๋ก ๋ท๋ฐ์นจํ๋ ํ์ค ์ํคํ ์ฒ๋ก ์๋ฆฌ ์ก์์ต๋๋ค. 2026๋ ๋ฐ์ดํฐ ์ฌ์ด์ธ์ค ๋ฐ AI ์์ง๋์ด๋ง ๋ฉด์ ์์๋ RAG ๊ด๋ จ ์ง๋ฌธ์ด ๊ธฐ์กด ML(๋จธ์ ๋ฌ๋) ์ฃผ์ ์ ํจ๊ป ์ถ์ ๋๊ณ ์์ผ๋ฉฐ, ์์คํ ์ค๊ณ ์ญ๋๊ณผ ์ค์ ๊ตฌํ ๋ฅ๋ ฅ์ด ๋์์ ํ๊ฐ๋ฉ๋๋ค.
๊ฒ์ ์ฆ๊ฐ ์์ฑ(RAG)์ ๊ฒ์ ์์คํ (์ง์ ๋ฒ ์ด์ค์ ๋ํ ๋ฒกํฐ ๊ฒ์)๊ณผ LLM ์์ฑ๊ธฐ๋ฅผ ๊ฒฐํฉํ์ฌ, ๋ชจ๋ธ์ด ํ์ต ๋ฐ์ดํฐ์ ๊ธฐ์ต์ ์์กดํ์ง ์๊ณ ์ค์ ๋ฌธ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ต๋ณ์ ์์ฑํ๋ ์ํคํ ์ฒ์ ๋๋ค.
RAG ํ์ดํ๋ผ์ธ์ ์๋ํฌ์๋ ๋์ ์๋ฆฌ
RAG ์์คํ ์ ๋ ๊ฐ์ง ๋จ๊ณ๋ก ๋์ํฉ๋๋ค. ์ง์ ๋ฒ ์ด์ค๋ฅผ ๊ตฌ์ถํ๋ ์คํ๋ผ์ธ ์ธ์ ์ค์ฒ ๋จ๊ณ์, ๊ด๋ จ ์ปจํ ์คํธ๋ฅผ ๊ฒ์ํ์ฌ ๋ต๋ณ์ ์์ฑํ๋ ์จ๋ผ์ธ ์ฟผ๋ฆฌ ๋จ๊ณ์ ๋๋ค.
์ธ์ ์ค์ฒ ๊ณผ์ ์์๋ ์๋ณธ ๋ฌธ์๊ฐ ํด๋ฆฌ๋, ์ฒญํน, ์๋ฒ ๋ฉ ์ฒ๋ฆฌ๋ฅผ ๊ฑฐ์ณ ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋ฉ๋๋ค. ์ถ๋ก ์์๋ ์ฌ์ฉ์์ ์ฟผ๋ฆฌ๊ฐ ๋์ผํ ์๋ฒ ๋ฉ ๊ฒฝ๋ก๋ฅผ ๋ฐ๋ฅด๋ฉฐ, ์ต๊ทผ์ ์ด์ ๊ฒ์์ ํตํด ๊ฐ์ฅ ๊ด๋ จ์ฑ์ด ๋์ ์ฒญํฌ๊ฐ ๊ฒ์๋ฉ๋๋ค. ์ด๋ฌํ ์ฒญํฌ๊ฐ LLM ํ๋กฌํํธ์ ์ผ๋ถ๊ฐ ๋์ด, ์์ฑ๋๋ ๋ต๋ณ์ด ์์ค ์๋ฃ์ ๊ทผ๊ฑฐํ๊ฒ ๋ฉ๋๋ค.
# rag_pipeline.py
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
# Offline: ingest documents into the vector store
def build_index(documents: list[str]) -> Chroma:
splitter = RecursiveCharacterTextSplitter(
chunk_size=512, # tokens per chunk
chunk_overlap=64, # overlap preserves context at boundaries
separators=["\n\n", "\n", ". ", " "]
)
chunks = splitter.create_documents(documents)
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
return Chroma.from_documents(chunks, embeddings)
# Online: retrieve + generate
def query(vectorstore: Chroma, question: str) -> str:
retriever = vectorstore.as_retriever(
search_type="mmr", # Maximal Marginal Relevance for diversity
search_kwargs={"k": 5, "fetch_k": 20}
)
prompt = ChatPromptTemplate.from_template(
"Answer based on this context only:\n{context}\n\nQuestion: {question}"
)
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| ChatOpenAI(model="gpt-4o", temperature=0)
)
return chain.invoke(question).content์ด ํ์ดํ๋ผ์ธ์ RAG์ ํต์ฌ ๋ฃจํ(์ฒญํน, ์๋ฒ ๋ฉ, ์ ์ฅ, ๊ฒ์, ์์ฑ)๋ฅผ ๋ค๋ฃจ๊ณ ์์ต๋๋ค. search_type="mmr" ํ๋ผ๋ฏธํฐ๋ ๊ฒ์๋ ์ฒญํฌ๊ฐ ๊ด๋ จ์ฑ๊ณผ ๋ค์์ฑ์ ๋์์ ๊ฐ์ถ๋๋ก ๋ณด์ฅํ์ฌ, ์ปจํ
์คํธ ์๋์ฐ ๋ด์ ์ค๋ณต์ ์ค์
๋๋ค.
๊ฒ์ ํ์ง์ ์ข์ฐํ๋ ์ฒญํน ์ ๋ต
์ฒญํน์ ๋ค๋ฅธ ์ด๋ค ์ปดํฌ๋ํธ๋ณด๋ค ๊ฒ์ ํ์ง์ ํฐ ์ํฅ์ ๋ฏธ์นฉ๋๋ค. ๋ถ์ ์ ํ ์ฒญํน์ ์ปจํ ์คํธ๊ฐ ๋ถ์กฑํ ๋จํธ์ด๋ ๋ฌด๊ดํ ์ ๋ณด๋ก ์ ํธ๊ฐ ํฌ์๋ ๋จํธ์ ๊ฒ์ ๊ฒฐ๊ณผ๋ก ๋ฐํํ๋ ์์ธ์ด ๋ฉ๋๋ค.
2026๋ ํ๋ก๋์ ์์คํ ์์๋ ์ธ ๊ฐ์ง ์ฒญํน ์ ๊ทผ ๋ฐฉ์์ด ์ฃผ๋ฅ๋ฅผ ์ด๋ฃจ๊ณ ์์ต๋๋ค.
๊ณ ์ ํฌ๊ธฐ ์ฒญํน์ ์ค์ ๋ ํ ํฐ ์(๋ณดํต 256~512 ํ ํฐ)๋ก ํ ์คํธ๋ฅผ ๋ถํ ํ๊ณ ์ค๋ฒ๋ฉ์ ๋ก๋๋ค. ๊ตฌํ์ด ๊ฐ๋จํ์ง๋ง ๋ฌธ์ฅ์ด๋ ์์ด๋์ด ์ค๊ฐ์์ ๋ถํ ๋๋ ๋จ์ ์ด ์์ต๋๋ค.
์๋งจํฑ ์ฒญํน์ ์ฐ์๋ ๋ฌธ์ฅ ๊ฐ์ ์๋ฒ ๋ฉ ์ ์ฌ๋๋ฅผ ์ธก์ ํ์ฌ ์ฃผ์ ์ ๊ฒฝ๊ณ๋ฅผ ๊ฐ์งํฉ๋๋ค. ์ ์ฌ๋๊ฐ ์๊ณ๊ฐ ์๋๋ก ๋จ์ด์ง๋ฉด ์๋ก์ด ์ฒญํฌ๊ฐ ์์๋ฉ๋๋ค. ๊ฐ ์ฒญํฌ๋ ํ ์คํธ์ ์์ ๋จํธ์ด ์๋ ์ผ๊ด๋ ์์ด๋์ด๋ฅผ ๋ด๊ฒ ๋ฉ๋๋ค.
๋ ์ดํธ ์ฒญํน์ ๋จผ์ ํธ๋์คํฌ๋จธ ๋ชจ๋ธ์ ๋ฌธ์ ์ ์ฒด์ ์ ์ฉํ์ฌ ์ปจํ ์คํธ๊ฐ ํฌํจ๋ ํ ํฐ ์๋ฒ ๋ฉ์ ์์ฑํ ํ, ์ฒญํฌ๋ก ๋ถํ ํฉ๋๋ค. ์ด๋ฅผ ํตํด ๊ธฐ์กด ์ฒญํน์ด ํ๊ดดํ๋ ์ฅ๊ฑฐ๋ฆฌ ์์กด ๊ด๊ณ๋ฅผ ๋ณด์กดํ ์ ์์ต๋๋ค.
# semantic_chunking.py
import numpy as np
from sentence_transformers import SentenceTransformer
def semantic_chunk(text: str, threshold: float = 0.3) -> list[str]:
"""Split text where semantic similarity drops below threshold."""
model = SentenceTransformer("all-MiniLM-L6-v2")
sentences = text.split(". ")
embeddings = model.encode(sentences)
chunks, current_chunk = [], [sentences[0]]
for i in range(1, len(sentences)):
# Cosine similarity between consecutive sentences
sim = np.dot(embeddings[i-1], embeddings[i]) / (
np.linalg.norm(embeddings[i-1]) * np.linalg.norm(embeddings[i])
)
if sim < threshold: # topic shift detected
chunks.append(". ".join(current_chunk))
current_chunk = [sentences[i]]
else:
current_chunk.append(sentences[i])
chunks.append(". ".join(current_chunk)) # final chunk
return chunks๋ฉด์ ์์์ ํต์ฌ ํฌ์ธํธ๋ ์ฒญํฌ ํฌ๊ธฐ๊ฐ ์ ๋ฐ๋์ ์ฌํ์จ ๊ฐ์ ํธ๋ ์ด๋์คํ๋ผ๋ ์ ์ ๋๋ค. ์์ ์ฒญํฌ(100 ํ ํฐ)๋ ๊ฒ์ ์ ๋ฐ๋๋ฅผ ํฅ์์ํค์ง๋ง ์ปจํ ์คํธ๊ฐ ๋จํธํ๋ฉ๋๋ค. ํฐ ์ฒญํฌ(1000 ํ ํฐ)๋ ์ปจํ ์คํธ๋ฅผ ๋ณด์กดํ์ง๋ง ์๋ฒ ๋ฉ์ ํน์ด์ฑ์ด ํฌ์๋ฉ๋๋ค. ๋๋ถ๋ถ์ ํ๋ก๋์ ์์คํ ์์๋ 10~20%์ ์ค๋ฒ๋ฉ์ ๋ 256~512 ํ ํฐ์ผ๋ก ์ค์ ํฉ๋๋ค.
ํ๋ก๋์ ํ๊ฒฝ์ ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์๋ฒ ๋ฉ ๋ชจ๋ธ
๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ์๋ฒ ๋ฉ์ ์ ์ฅํ๊ณ ๊ณ ์ ๊ทผ์ฌ ์ต๊ทผ์ ์ด์(ANN) ๊ฒ์์ ์ง์ํฉ๋๋ค. ์๋ฒ ๋ฉ ๋ชจ๋ธ๊ณผ ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ ํ ์กฐํฉ์ ์ ํํ๋ ๊ฒ์ด ๊ฒ์ ๋ ์ดํด์์ ์ ํ๋์ ์ง์ ์ ์ธ ์ํฅ์ ๋ฏธ์นฉ๋๋ค.
2026๋
์ ์๋ฒ ๋ฉ ๋ชจ๋ธ์ ๋ช ๊ฐ์ง ๊ณ ์ฑ๋ฅ ์ต์
์ผ๋ก ์๋ ด๋์์ต๋๋ค. OpenAI์ text-embedding-3-large(3072์ฐจ์)์ BAAI์ bge-m3, Cohere์ embed-v4 ๊ฐ์ ์คํ์์ค ๋์์ด ๊ฐ๋ ฅํ ๋ค๊ตญ์ด ๊ฒ์ ์ฑ๋ฅ์ ์ ๊ณตํ๊ณ ์์ต๋๋ค. MTEB ๋ฆฌ๋๋ณด๋๋ ์๋ฒ ๋ฉ ํ์ง ๋น๊ต๋ฅผ ์ํ ํ์ค ๋ฒค์น๋งํฌ๋ก ๊ณ์ ํ์ฉ๋๊ณ ์์ต๋๋ค.
Pinecone, Weaviate, Milvus, Qdrant, pgvector ๋ฑ์ ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ๊ฐ๊ฐ ๋ค๋ฅธ ํธ๋ ์ด๋์คํ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
| ๋ฐ์ดํฐ๋ฒ ์ด์ค | ์ธ๋ฑ์ฑ | ๋งค๋์ง๋ | ๊ฐ์ | |----------|----------|---------|----------| | Pinecone | ๋ ์ ๋ฐฉ์ | ์ง์ | ๊ฐํธํจ, ์๋ฒ๋ฆฌ์ค ์ค์ผ์ผ๋ง | | Weaviate | HNSW | ์ง์/์ ํ | ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์(๋ฒกํฐ + BM25) | | Milvus | IVF, HNSW | ์ง์/์ ํ | ์์ญ์ต ๊ท๋ชจ ๋ฐ์ดํฐ์ | | Qdrant | HNSW | ์ง์/์ ํ | ํํฐ๋ง + ํ์ด๋ก๋ ์ ์ฅ | | pgvector | IVF, HNSW | ์ ํ | PostgreSQL ํตํฉ |
๋ฉด์ ์์ ์ค์ํ ๊ฒ์ HNSW(Hierarchical Navigable Small World) ์๊ณ ๋ฆฌ์ฆ์ ๋ํ ์ดํด์ ๋๋ค. HNSW๋ ๋ค์ธต ๊ทธ๋ํ๋ฅผ ๊ตฌ์ถํ์ฌ ๊ฐ ๋ ธ๋๊ฐ ์ต๊ทผ์ ์ด์์ ์ฐ๊ฒฐ๋๋ฉฐ, ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ฆ๊ฐ๋ฅผ ๋๊ฐ๋ก O(log n) ๊ฒ์์ ๊ตฌํํฉ๋๋ค.
Data Science & ML ๋ฉด์ ์ค๋น๊ฐ ๋์ จ๋์?
์ธํฐ๋ํฐ๋ธ ์๋ฎฌ๋ ์ดํฐ, flashcards, ๊ธฐ์ ํ ์คํธ๋ก ์ฐ์ตํ์ธ์.
ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์: ๋ฐ์ง ๋ฒกํฐ์ ํฌ์ ๋ฒกํฐ์ ๊ฒฐํฉ
์์ ๋ฒกํฐ ๊ฒ์์ ์ ํํ ํค์๋ ๋งค์นญ์ด๋ ํฌ๊ท ์ฉ์ด ๊ฒ์์ ์คํจํฉ๋๋ค. ๋ฐ๋ฉด ์์ ๋ ์์ปฌ ๊ฒ์(BM25)์ ์๋งจํฑ ์ ์ฌ์ฑ์ ๋์นฉ๋๋ค. ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์์ ์ด ๋์ ๊ฒฐํฉํ๋ ์ ๊ทผ ๋ฐฉ์์ด๋ฉฐ, 2026๋ ํ๋ก๋์ RAG ์์คํ ์์๋ ๊ธฐ๋ณธ ์ค์ ์ด ๋์์ต๋๋ค.
ํ์ค ํจํด์์๋ Reciprocal Rank Fusion(RRF)์ ์ฌ์ฉํ์ฌ ๋ ๋ฆฌํธ๋ฆฌ๋ฒ์ ๋ญํน ๊ฒฐ๊ณผ๋ฅผ ํตํฉํฉ๋๋ค.
# hybrid_retrieval.py
from rank_bm25 import BM25Okapi
import numpy as np
def reciprocal_rank_fusion(
dense_results: list[str],
sparse_results: list[str],
k: int = 60
) -> list[str]:
"""Merge dense (vector) and sparse (BM25) results using RRF."""
scores: dict[str, float] = {}
for rank, doc_id in enumerate(dense_results):
scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank + 1)
for rank, doc_id in enumerate(sparse_results):
scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank + 1)
# Sort by combined RRF score, highest first
return sorted(scores.keys(), key=lambda d: scores[d], reverse=True)ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์์ '์ดํ ๋ถ์ผ์น' ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์๊ฐ '๊ตฌ๋ ์ทจ์'์ ๋ํด ์ง๋ฌธํ๊ณ ์๋๋ฐ, ๊ด๋ จ ๋ฌธ์์์๋ '๊ณ์ ํด์ง ์ ์ฑ '์ด๋ผ๋ ํํ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์ ๋๋ค. BM25๊ฐ ์ ํํ ์ฉ์ด ์ผ์น๋ฅผ ํฌ์ฐฉํ๋ ๋ฐ๋ฉด, ๋ฒกํฐ ๊ฒ์์ ์๋งจํฑ ๊ด๋ จ์ฑ์ ํ์ ํฉ๋๋ค.
๋ฆฌ๋ญํน: 2๋จ๊ณ ํํฐ
๊ฒ์์ ํ๋ณด๋ฅผ ๋ฐํํ๊ณ , ๋ฆฌ๋ญํน์ ๊ทธ๊ฒ๋ค์ ์ค์ ๊ด๋ จ์ฑ์ ๋ฐ๋ผ ์ ๋ ฌํฉ๋๋ค. Cohere Rerank๋ bge-reranker-v2.5-gemma2-lightweight ๊ฐ์ ํฌ๋ก์ค ์ธ์ฝ๋ ๋ฆฌ๋ญ์ปค๋ ๊ฐ ์ฟผ๋ฆฌ-๋ฌธ์ ์์ ๋์์ ์ค์ฝ์ด๋งํ์ฌ, ๋ฐ์ด ์ธ์ฝ๋ ์ ์ฌ๋๋ณด๋ค ํจ์ฌ ์ ํํ ๊ด๋ จ์ฑ ์ ์๋ฅผ ์์ฑํฉ๋๋ค.
2๋จ๊ณ ๊ฒ์ ํ์ดํ๋ผ์ธ -- ๋์ 1๋จ๊ณ ๋ฆฌ์ฝ(๋ฒกํฐ + BM25๋ก ์์ 50~100๊ฐ ํ๋ณด), ์ด์ด์ ์ ๋ฐ ๋ฆฌ๋ญํน(ํ๋กฌํํธ์ฉ ์์ 5~10๊ฐ) -- ์ ํ๋ก๋์ ํ๊ฒฝ์ ํ์ค์ ๋๋ค. 1๋จ๊ณ์์ ๊ณ ์ ANN ๊ฒ์์ ์ฌ์ฉํ๊ณ , ๋น์ฉ์ด ๋์ ํฌ๋ก์ค ์ธ์ฝ๋๋ ์์์ ํ๋ณด ์ธํธ๋ง ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ ๋ ์ดํด์๋ฅผ ๊ด๋ฆฌ ๊ฐ๋ฅํ ์์ค์ผ๋ก ์ ์งํ ์ ์์ต๋๋ค.
ํฌ๋ก์ค ์ธ์ฝ๋๊ฐ ๋ฐ์ด ์ธ์ฝ๋๋ณด๋ค ์ ํํ ์ด์ ๋ ์ฟผ๋ฆฌ์ ๋ฌธ์๋ฅผ ํธ๋์คํฌ๋จธ์ ๋ชจ๋ ๋ ์ด์ด์์ ๋์์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ฐ์ด ์ธ์ฝ๋๋ ๊ฐ๊ฐ์ ๋ ๋ฆฝ์ ์ผ๋ก ์๋ฒ ๋ฉํ๋ฏ๋ก ์ธ๋ฐํ ์ํธ์์ฉ ์ ํธ๊ฐ ์์ค๋ฉ๋๋ค. ํธ๋ ์ด๋์คํ๋ ์๋์ ๋๋ค. ํฌ๋ก์ค ์ธ์ฝ๋๋ ์ฌ์ ์ธ๋ฑ์ฑ์ด ๋ถ๊ฐ๋ฅํฉ๋๋ค.
์์ด์ ํฑ RAG: ๋จ๋ฐ์ฑ ๊ฒ์์ ๋์ด์
๋์ด๋ธ RAG๋ ํ ๋ฒ ๊ฒ์ํ๊ณ ์์ฑํ๋ ๊ฒ์ด ์ ๋ถ์ ๋๋ค. ์์ด์ ํฑ RAG๋ LLM์ ์ธ์ ๊ฒ์ํ ์ง, ๋ฌด์์ ๊ฒ์ํ ์ง, ๊ฒ์๋ ์ปจํ ์คํธ๊ฐ ์ถฉ๋ถํ์ง๋ฅผ ํ๋จํ๋ ์ถ๋ก ์์ด์ ํธ๋ก ์ทจ๊ธํฉ๋๋ค.
2026๋ ์๋ ๋ค๋จ๊ณ ์ถ๋ก ์ด ํ์ํ ๋ณต์กํ ์ฟผ๋ฆฌ์ ๋ํด ์์ด์ ํฑ RAG๊ฐ ์ง๋ฐฐ์ ์ธ ํจํด์ด ๋์์ต๋๋ค. ์์ด์ ํธ๋ ๋ค์๊ณผ ๊ฐ์ ์์ ์ ์ํํ ์ ์์ต๋๋ค.
- ์๊ธฐ ํ๊ฐ: ๊ฒ์๋ ๋ฌธ์๊ฐ ์ง๋ฌธ์ ๋ต๋ณํ๊ณ ์๋์ง ํ๊ฐ
- ์ฌ์ฟผ๋ฆฌ: ์ด๊ธฐ ๊ฒฐ๊ณผ๊ฐ ๋ถ์ถฉ๋ถํ ๊ฒฝ์ฐ ๊ฒ์ ์ฟผ๋ฆฌ๋ฅผ ์ฌ๊ตฌ์ฑ
- ๋ผ์ฐํ : ๋ค์ํ ์ง์ ์์ค(๋ฒกํฐ DB, SQL ๋ฐ์ดํฐ๋ฒ ์ด์ค, API) ์ค์์ ์ ํ
- ๊ฒ์ฆ: ์ฌ๋ฌ ๊ฒ์ ํจ์์ง ๊ฐ์ ์ฌ์ค ๊ด๊ณ๋ฅผ ๊ต์ฐจ ํ์ธ
# agentic_rag.py
from langgraph.graph import StateGraph, END
from typing import TypedDict
class RAGState(TypedDict):
question: str
documents: list[str]
generation: str
retries: int
def retrieve(state: RAGState) -> RAGState:
"""Retrieve documents from vector store."""
docs = vectorstore.similarity_search(state["question"], k=5)
return {"documents": [d.page_content for d in docs]}
def grade_documents(state: RAGState) -> str:
"""Decide if documents are relevant enough to answer."""
prompt = f"Are these documents relevant to: {state['question']}?\n"
prompt += "\n".join(state["documents"])
relevance = llm.invoke(prompt) # returns 'relevant' or 'not_relevant'
return "generate" if "relevant" in relevance.content else "rewrite"
def rewrite_query(state: RAGState) -> RAGState:
"""Reformulate the query for better retrieval."""
new_query = llm.invoke(
f"Rewrite this query for better search results: {state['question']}"
)
return {"question": new_query.content, "retries": state["retries"] + 1}
# Build the agent graph
workflow = StateGraph(RAGState)
workflow.add_node("retrieve", retrieve)
workflow.add_node("grade", grade_documents) # conditional routing
workflow.add_node("rewrite", rewrite_query)
workflow.add_node("generate", generate_answer)
workflow.set_entry_point("retrieve")
workflow.add_edge("retrieve", "grade")
workflow.add_conditional_edges("grade", grade_documents,
{"generate": "generate", "rewrite": "rewrite"})
workflow.add_edge("rewrite", "retrieve") # retry loop
workflow.add_edge("generate", END)์ด ํจํด -- ๊ฒ์, ํ๊ฐ, ํ์ ์ ์ฟผ๋ฆฌ ์ฌ์์ฑ ํ ์ฌ์๋ -- ์ Corrective RAG(CRAG)๋ก ์๋ ค์ ธ ์์ต๋๋ค. LangGraph ํ๋ ์์ํฌ๋ ์ํฌํ๋ก๋ฅผ ์กฐ๊ฑด ๋ถ๊ธฐ๊ฐ ์๋ ์ ํฅ ์ํ ๊ทธ๋ํ๋ก ๋ชจ๋ธ๋งํ์ฌ, ๊ฒ์ฆ ๋จ๊ณ, ํด๋จผ์ธ๋๋ฃจํ ์ฒดํฌํฌ์ธํธ, ๋ฉํฐ์์ค ๋ผ์ฐํ ์ ์ถ๊ฐ๋ฅผ ์ฉ์ดํ๊ฒ ํฉ๋๋ค.
Graph RAG: ๊ตฌ์กฐํ๋ ์ง์ ๊ฒ์
Graph RAG๋ ๋ฌธ์์์ ์ํฐํฐ์ ๊ด๊ณ๋ฅผ ์ถ์ถํ์ฌ ์ง์ ๊ทธ๋ํ๋ฅผ ๊ตฌ์ถํ๊ณ , ๊ทธ๋ํ์ ๋ฒกํฐ ์คํ ์ด ์์ชฝ์ ์ฟผ๋ฆฌ๋ฅผ ์คํํฉ๋๋ค. ์ด ์ํคํ ์ฒ๋ ๋น์ ํ ํ ์คํธ ์ ์ฌ์ฑ์ด ์๋ ๋ช ์์ ์ธ ์ํฐํฐ ๊ฐ ๊ด๊ณ์ ๋ต๋ณ์ ๊ทผ๊ฑฐํจ์ผ๋ก์จ, ์ฌ์ค ๊ด๋ จ ์ฟผ๋ฆฌ์์์ ํ ๋ฃจ์๋ค์ด์ ์ ์ค์ ๋๋ค.
์ธ์ ์ค์ฒ ํ์ดํ๋ผ์ธ์ ๊ฐ ๋ฌธ์ ์ฒญํฌ์์ ํธ๋ฆฌํ(์ฃผ์ด, ์ ์ด, ๋ชฉ์ ์ด)์ ์ถ์ถํฉ๋๋ค. ์ฟผ๋ฆฌ ์์๋ ์ง๋ฌธ ๋ด์ ๊ด๋ จ ์ํฐํฐ๋ฅผ ์๋ณํ๊ณ , ์ง์ ๊ทธ๋ํ๋ฅผ ํ์ํ์ฌ ์ฐ๊ฒฐ๋ ์ฌ์ค์ ๊ฒ์ํ ํ, ๊ทธ๋ํ ๊ฒ์์ผ๋ก ์ป์ ์ปจํ ์คํธ์ ๋ฒกํฐ ๊ฒ์์ผ๋ก ์ป์ ํจ์์ง๋ฅผ ๊ฒฐํฉํฉ๋๋ค.
Graph RAG๋ '๋ฌธ์ X์์ ์ธ๊ธ๋ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๋ ํ๋ก์ ํธ๋ฅผ ์ด๋๋ ํ์ ์ด๋์ธ๊ฐ?'์ ๊ฐ์ ๋ฉํฐํ ์ถ๋ก ์ฟผ๋ฆฌ์ ํ์ํฉ๋๋ค. ์ด๋ ์ฌ๋ฌ ๋ฌธ์์ ๊ฑธ์น ์ฌ์ค์ ์ฐ๊ฒฐํด์ผ ํ๋ ์ฟผ๋ฆฌ๋ก, ๋จ์ผ ์ฒญํฌ์ ์์ ํ ๋ต๋ณ์ด ํฌํจ๋์ด ์์ง ์๊ธฐ ๋๋ฌธ์ ์์ ๋ฒกํฐ ๊ฒ์์ผ๋ก๋ ๋์ํ๊ธฐ ์ด๋ ต์ต๋๋ค.
Graph RAG๋ ์ฌ์ค ์ ํ๋๋ฅผ ํฌ๊ฒ ํฅ์์ํค์ง๋ง(์ํฐํฐ๊ฐ ๋ง์ ์ฟผ๋ฆฌ์์ ํ ๋ฃจ์๋ค์ด์ ์ ์ต๋ 40% ๊ฐ์), ์ฑ์ํ ์ํฐํฐ ์ถ์ถ ํ์ดํ๋ผ์ธ์ ํ์๋ก ํฉ๋๋ค. ๋ ธ์ด์ฆ๊ฐ ๋ง์ ์ถ์ถ์ ๋ ธ์ด์ฆ๊ฐ ๋ง์ ๊ทธ๋ํ๋ฅผ ์์ฑํ์ฌ, ๋์ด๋ธ RAG๋ณด๋ค ๊ฒฐ๊ณผ๊ฐ ์ ํ๋ ์ ์์ต๋๋ค.
RAG ์์คํ ํ๊ฐ: ์ค์ํ ์งํ
RAG ํ๊ฐ๋ ๊ฒ์ ์งํ์ ์์ฑ ์งํ๋ก ๋๋ฉ๋๋ค. ์ฅ์ ์ง๋จ์ ์ํด์๋ ๋ ๊ฐ์ง๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ์ธก์ ํด์ผ ํฉ๋๋ค.
๊ฒ์ ์งํ:
- Recall@k: ๊ด๋ จ ๋ฌธ์๊ฐ ์์ k๊ฐ ๊ฒฐ๊ณผ์ ํฌํจ๋์๋๊ฐ?
- MRR(Mean Reciprocal Rank): ์ฒซ ๋ฒ์งธ ๊ด๋ จ ๊ฒฐ๊ณผ์ ์์๋ ์ผ๋ง๋ ๋์๊ฐ?
- NDCG: ๋ญํน์ด ์ด์์ ์ธ ๊ด๋ จ์ฑ ์์์ ์ผ์นํ๋๊ฐ?
์์ฑ ์งํ:
- ์ถฉ์ค๋(Faithfulness): ๋ต๋ณ์ด ๊ฒ์๋ ์ปจํ ์คํธ์ ์ ๋ณด๋ง ์ฌ์ฉํ๊ณ ์๋๊ฐ? (ํ ๋ฃจ์๋ค์ด์ ์ธก์ )
- ๋ต๋ณ ๊ด๋ จ์ฑ(Answer relevance): ๋ต๋ณ์ด ์๋ ์ง๋ฌธ์ ๋์ํ๊ณ ์๋๊ฐ?
- ์ปจํ ์คํธ ์ ๋ฐ๋(Context precision): ๊ฒ์๋ ์ฒญํฌ๊ฐ ์ค์ ๋ก ๋ต๋ณ์ ํ์ฉ๋์๋๊ฐ?
Ragas์ DeepEval ๊ฐ์ ํ๋ ์์ํฌ๋ LLM-as-judge ํจํด์ ์ฌ์ฉํ์ฌ ์ด๋ฌํ ํ๊ฐ๋ฅผ ์๋ํํฉ๋๋ค. ๋ฐ์ดํฐ ์ฌ์ด์ธ์ค ๋ฉด์ ๋น์ถ ์ง๋ฌธ์์๋ RAG ํ๊ฐ ์ค๊ณ๊ฐ ์ ์ ๋ ๋ง์ด ํฌํจ๋๊ณ ์์ผ๋ฉฐ, RAG ์์คํ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง๋ฅผ ์ด๋ป๊ฒ ์ธก์ ํ๋์ง์ ๋ํ ์ค๋ช ์ด ์๊ตฌ๋ฉ๋๋ค.
ํ๋ก๋์ ํ๊ฒฝ์ ์ฅ์ ๋ชจ๋์ ๋๋ฒ๊น
RAG ์์คํ ์ ์์ธก ๊ฐ๋ฅํ ํจํด์ผ๋ก ์ฅ์ ๋ฅผ ์ผ์ผํต๋๋ค. ์ด๋ฌํ ํจํด์ ์๋ ๊ฒ์ ๋ฉด์ ๊ณผ ์ค์ ๋ฐฐํฌ ๋ชจ๋์ ํ์์ ์ ๋๋ค.
์ปจํ ์คํธ ์๋์ฐ ์ค์ผ์ ๊ฒ์๋ ์ฒญํฌ๊ฐ ๋๋ฌด ๋ง์ ๊ด๋ จ ์ ํธ๊ฐ ํฌ์๋ ๋ ๋ฐ์ํฉ๋๋ค. LLM์ด 10๊ฐ์ ์ฒญํฌ๋ฅผ ๋ฐ์ง๋ง ์ ์ฉํ ์ ๋ณด๋ฅผ ํฌํจํ ๊ฒ์ 2๊ฐ๋ฟ์ธ ์ํฉ์ ๋๋ค. ํด๊ฒฐ์ฑ : ๋ฆฌ๋ญ์ปค๋ฅผ ์ฌ์ฉํ์ฌ ํํฐ๋งํ๊ณ ๋ฆฌํธ๋ฆฌ๋ฒ์ top-k๋ฅผ ์ค์ ๋๋ค.
์ฒญํน ์ํฐํฉํธ๋ ๊ณ ์ ํฌ๊ธฐ ๋ถํ ์ด ๋ฌธ์ฅ, ํ ์ด๋ธ, ์ฝ๋ ๋ธ๋ก์ ์ค๊ฐ์์ ์๋ผ๋ผ ๋ ๋ฐ์ํฉ๋๋ค. ๊ฒ์๋ ์ฒญํฌ๋ ๊ตฌ๋ฌธ์ ์ผ๋ก ๋ถ์์ ํ๊ณ ์๋งจํฑ์ ์ผ๋ก ๋ฌด์ฉํฉ๋๋ค. ์๋งจํฑ ์ฒญํน ๋๋ ๋ฌธ์ ๊ตฌ์กฐ๋ฅผ ๊ณ ๋ คํ ๋ถํ (ํค๋, ๋จ๋ฝ, ์ฝ๋ ํ์ค ์กด์ค)๋ก ํด๊ฒฐํ ์ ์์ต๋๋ค.
์๋ฒ ๋ฉ ๋๋ฆฌํํธ๋ ์๋ฒ ๋ฉ ๋ชจ๋ธ์ด ์ ๋ฐ์ดํธ๋์์์๋ ๋ฒกํฐ ์คํ ์ด์ ์ด์ ๋ชจ๋ธ์ ์๋ฒ ๋ฉ์ด ๊ทธ๋๋ก ์ ์ฅ๋์ด ์์ ๋ ๋ฐ์ํฉ๋๋ค. ์ ๋ชจ๋ธ๋ก ์ธ์ฝ๋ฉ๋ ์ฟผ๋ฆฌ๊ฐ ์ด์ ๋ชจ๋ธ๋ก ๊ตฌ์ถ๋ ๋ฒกํฐ ๊ณต๊ฐ์ ๊ฒ์ํ๊ฒ ๋์ด ๊ฒ์ ํ์ง์ด ์ ํ๋ฉ๋๋ค. ํด๊ฒฐ์ฑ : ๋ชจ๋ธ ๋ณ๊ฒฝ ํ ์ ์ฒด ์ฝํผ์ค๋ฅผ ์ฌ์๋ฒ ๋ฉํฉ๋๋ค.
๋ ธํํ๋ ์ธ๋ฑ์ค๋ ์ธ์ ์ค์ฒ ํ์ดํ๋ผ์ธ์ด ๋ฌธ์ ์ ๋ฐ์ดํธ์ ๋ค์ฒ์ ธ ์ค๋๋ ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ ๊ฒฝ์ฐ์ ๋๋ค. ๋จธ์ ๋ฌ๋ ์์คํ ์์๋ ์ด๋ฅผ ํ์ต-์๋น ์คํ์ ๋น์ ํ ์ ์์ต๋๋ค. ๊ฒ์ ์์คํ ์ด ํ๋ก๋์ ํ๊ฒฝ์ ์กด์ฌํ๋ ๋ฐ์ดํฐ ๋ถํฌ์ ๋ค๋ฅธ ๊ฒ์ ์ฐธ์กฐํ๊ฒ ๋๋ ๊ฒ์ ๋๋ค.
์ฐ์ต์ ์์ํ์ธ์!
๋ฉด์ ์๋ฎฌ๋ ์ดํฐ์ ๊ธฐ์ ํ ์คํธ๋ก ์ง์์ ํ ์คํธํ์ธ์.
๊ฒฐ๋ก
- RAG๋ ๊ฒ์(์ง์ ๋ฒ ์ด์ค์ ๋ํ ๋ฒกํฐ ๊ฒ์)๊ณผ LLM ์์ฑ์ ๊ฒฐํฉํ์ฌ, ๋ชจ๋ธ ์ฌํ์ต ์์ด ์ฌ์ค์ ๊ธฐ๋ฐํ ๋ต๋ณ์ ์์ฑํฉ๋๋ค
- ์ฒญํน ์ ๋ต์ด ๊ฒ์ ํ์ง์ ๊ฐ์ฅ ํฐ ์ํฅ์ ๋ฏธ์นฉ๋๋ค. ์๋งจํฑ ์ฒญํน๊ณผ ๋ ์ดํธ ์ฒญํน์ ๋๋ถ๋ถ์ ์ฌ์ฉ ์ฌ๋ก์์ ๊ณ ์ ํฌ๊ธฐ ๋ถํ ์ ๋ฅ๊ฐํฉ๋๋ค
- ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์(๋ฐ์ง ๋ฒกํฐ + ํฌ์ BM25)๊ณผ Reciprocal Rank Fusion์ ํ๋ก๋์ ์ ๊ธฐ๋ณธ ์ค์ ์ด๋ฉฐ, ์์ ๋ฒกํฐ ๊ฒ์์ผ๋ก๋ ํด๊ฒฐํ ์ ์๋ ์ดํ ๋ถ์ผ์น ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค
- ํฌ๋ก์ค ์ธ์ฝ๋ ๋ฆฌ๋ญ์ปค๋ ๊ด๋ฒ์ํ ๊ฒ์ ํ ์ ๋ฐ๋ ๊ณ์ธต์ ์ถ๊ฐํ๋ฉฐ, ์์์ ํ๋ณด ์ธํธ๋ง ์ฒ๋ฆฌํ์ฌ ๋ ์ดํด์๋ฅผ ํ์ฉ ๋ฒ์ ๋ด๋ก ์ ์งํฉ๋๋ค
- ์์ด์ ํฑ RAG(๊ฒ์, ํ๊ฐ, ์ฌ์์ฑ, ์ฌ์๋)์ Graph RAG(์ํฐํฐ-๊ด๊ณ ์ถ์ถ)๋ 2026๋ ์ ๋ ๊ฐ์ง ์ฃผ์ ์ํคํ ์ฒ ๋ฐ์ ์ด๋ฉฐ, ๋์ด๋ธ RAG๊ฐ ์คํจํ๋ ๋ณต์กํ ๋ฉํฐํ ์ฟผ๋ฆฌ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค
- ํ๊ฐ๋ ๊ฒ์ ์งํ(Recall@k, MRR)์ ์์ฑ ์งํ(์ถฉ์ค๋, ๋ต๋ณ ๊ด๋ จ์ฑ)๋ฅผ ๋ถ๋ฆฌํ์ฌ, ํ์ดํ๋ผ์ธ์์ ์ฅ์ ๊ฐ ๋ฐ์ํ๋ ์์น๋ฅผ ์ง๋จํด์ผ ํฉ๋๋ค
- ๊ฐ์ฅ ํํ ํ๋ก๋์ ์ฅ์ -- ์ปจํ ์คํธ ์ค์ผ, ์ฒญํน ์ํฐํฉํธ, ์๋ฒ ๋ฉ ๋๋ฆฌํํธ, ๋ ธํํ๋ ์ธ๋ฑ์ค -- ๋ ์๋ณ๋๋ฉด ๋ชจ๋ ๊ฐ๋จํ ์์ ํ ์ ์์ต๋๋ค
์ฐ์ต์ ์์ํ์ธ์!
๋ฉด์ ์๋ฎฌ๋ ์ดํฐ์ ๊ธฐ์ ํ ์คํธ๋ก ์ง์์ ํ ์คํธํ์ธ์.
ํ๊ทธ
๊ณต์
๊ด๋ จ ๊ธฐ์ฌ

๋จธ์ ๋ฌ๋ ์๊ณ ๋ฆฌ์ฆ ์๋ฒฝ ํด์ค: ๊ธฐ์ ๋ฉด์ ์ ์ํ ์ข ํฉ ๊ฐ์ด๋
๋จธ์ ๋ฌ๋ ์๊ณ ๋ฆฌ์ฆ ๊ธฐ์ ๋ฉด์ ๊ฐ์ด๋. ์ ํ ๋ชจ๋ธ, ์์ฌ๊ฒฐ์ ํธ๋ฆฌ, ์์๋ธ, ํด๋ฌ์คํฐ๋ง, ํ๊ฐ ์งํ, ์ ๊ทํ๋ฅผ scikit-learn ์ฝ๋์ ํจ๊ป ์ฒด๊ณ์ ์ผ๋ก ํด์คํฉ๋๋ค.

2026๋ ๋ฐ์ดํฐ ์ฌ์ด์ธ์ค ๋ฉด์ ์ง๋ฌธ 25์
ํต๊ณ, ๋จธ์ ๋ฌ๋, ํผ์ฒ ์์ง๋์ด๋ง, ๋ฅ๋ฌ๋, SQL, ์์คํ ์ค๊ณ๋ฅผ ๋ง๋ผํ๋ ๋ฐ์ดํฐ ์ฌ์ด์ธ์ค ๋ฉด์ ์ง๋ฌธ 25์ โ Python ์ฝ๋ ์์ ์ ์ฌ์ธต ํด์ค ํฌํจ.

PyTorch vs TensorFlow 2026๋ ๋น๊ต: ์ด๋ค ๋ฅ๋ฌ๋ ํ๋ ์์ํฌ๋ฅผ ์ ํํด์ผ ํ ๊น
2026๋ PyTorch vs TensorFlow์ ์ฑ๋ฅ ๋ฒค์น๋งํฌ, ๋ฐฐํฌ, ์์ฝ์์คํ , ๊ฐ๋ฐ์ ๊ฒฝํ ์ธก๋ฉด์์ ๋น๊ตํ์ฌ ํ๋ก์ ํธ์ ์ ํฉํ ๋ฅ๋ฌ๋ ํ๋ ์์ํฌ ์ ํ์ ๋๋ ๊ฐ์ด๋์ ๋๋ค.