고급 RAG: LongRAG, Self-RAG 및 GraphRAG 해설

LongRAG, Self-RAG, GraphRAG - 차세대 기법

Page content

검색 증강 생성 (RAG) 은 단순한 벡터 유사성 검색을 넘어 크게 진화했습니다. LongRAG, Self-RAG, GraphRAG 는 이러한 기능의 최전선을 대표합니다.

현대적인 RAG 시스템 은 방대한 문서를 처리하고 복잡한 엔티티 관계를 이해하는 등 훨씬 더 많은 것을 처리해야 합니다.

a-pirate-captain 이 아름다운 이미지는 AI 모델 Flux 1 dev 로 생성되었습니다.

기본 RAG 를 넘어선 진화

전통적인 RAG 시스템은 단순한 패턴을 따릅니다: 문서를 청크 (chunk) 로 나누고, 벡터로 임베딩한 후 코사인 유사도를 통해 유사한 청크를 검색하여 LLM 에 전달합니다. 이 방식은 많은 사용 사례에서 효과적이지만, 세 가지 중요한 시나리오에서 어려움을 겪습니다:

검색 (Search), 심층 검색 (Deepsearch), 심층 연구 (Deep Research) 간의 차이를 이해하는 것이 복잡한 정보 검색 작업에 고급 RAG 변형이 필요한 이유를 명확히 하는 데 도움이 됩니다. 이 개념에 대한 더 깊은 이해를 원하시면 검색 vs 심층검색 vs 심층연구 를 참조하세요.

  1. 장거리 의존성 (Long-range dependencies): 중요한 맥락이 여러 청크에 걸쳐 수천 개의 토큰에 걸쳐 분산될 수 있습니다
  2. 검색 신뢰도 (Retrieval confidence): 시스템은 검색된 콘텐츠가 실제로 관련성이 있는지 평가할 방법이 없습니다
  3. 관계의 복잡성 (Relationship complexity): 벡터 유사성만으로는 엔티티 간의 복잡한 연결을 포착할 수 없습니다

고급 RAG 변형은 이러한 한계를 해결하기 위해 특정 도전에 맞춘 전용 아키텍처를 제공합니다.

LongRAG: 확장된 컨텍스트 정복

아키텍처 개요

LongRAG 는 32K, 100K, 심지어 1M 토큰의 확장된 컨텍스트 윈도우를 가진 LLM 을 활용하여 청킹 전략을 근본적으로 재고합니다. 문서를 작은 512 토큰 청크로 나누는 대신, LongRAG 는 계층적 접근 방식을 사용합니다:

문서 수준 임베딩 (Document-Level Embedding): 전체 문서 (또는 매우 큰 섹션) 가 단일 단위로 처리됩니다. 문서 수준 임베딩은 전체 의미를 포착하는 동시에 하류 처리를 위해 전체 텍스트를 유지합니다.

최소한의 단편화 (Minimal Fragmentation): 청킹이 필요한 경우 LongRAG 는 훨씬 더 큰 청크 (4K-8K 토큰) 와 상당한 중복 (20-30%) 을 사용합니다. 이는 서사적 흐름을 보존하고 컨텍스트 단편화를 줄입니다.

컨텍스트 조립 (Context Assembly): 검색 시 LongRAG 는 산재된 단편이 아닌 완전한 문서나 큰 일관된 섹션을 반환합니다. LLM 은 구조적 및 의미론적 관계를 보존하는 연속된 컨텍스트를 받습니다.

구현 전략

다음은 Python 과 현대적인 임베딩 모델을 사용한 개념적 구현 예시입니다:

from typing import List, Dict
import numpy as np

class LongRAGRetriever:
    def __init__(self, model, chunk_size=8000, overlap=1600):
        self.model = model
        self.chunk_size = chunk_size
        self.overlap = overlap
        self.doc_embeddings = []
        self.documents = []
    
    def create_long_chunks(self, text: str) -> List[str]:
        """중복되는 큰 청크 생성"""
        chunks = []
        start = 0
        while start < len(text):
            end = start + self.chunk_size
            chunk = text[start:end]
            chunks.append(chunk)
            start += (self.chunk_size - self.overlap)
        return chunks
    
    def index_document(self, doc: str, metadata: Dict):
        """계층적 임베딩을 사용한 문서 색인화"""
        # 전체 문서 임베딩
        doc_embedding = self.model.embed(doc)
        
        # 중복을 가진 큰 청크 생성
        chunks = self.create_long_chunks(doc)
        chunk_embeddings = [self.model.embed(c) for c in chunks]
        
        self.doc_embeddings.append({
            'doc_id': len(self.documents),
            'doc_embedding': doc_embedding,
            'chunk_embeddings': chunk_embeddings,
            'chunks': chunks,
            'full_text': doc,
            'metadata': metadata
        })
        self.documents.append(doc)
    
    def retrieve(self, query: str, top_k: int = 3) -> List[Dict]:
        """관련 장문 콘텐츠 검색"""
        query_embedding = self.model.embed(query)
        
        # 먼저 문서 수준에서 점수 계산
        doc_scores = [
            np.dot(query_embedding, doc['doc_embedding'])
            for doc in self.doc_embeddings
        ]
        
        # 상위 문서 가져오기
        top_doc_indices = np.argsort(doc_scores)[-top_k:][::-1]
        
        results = []
        for idx in top_doc_indices:
            doc_data = self.doc_embeddings[idx]
            
            # 각 문서에서 가장 좋은 청크 찾기
            chunk_scores = [
                np.dot(query_embedding, emb)
                for emb in doc_data['chunk_embeddings']
            ]
            best_chunk_idx = np.argmax(chunk_scores)
            
            # 가장 좋은 청크 주변의 확장된 컨텍스트 반환
            context_chunks = self._get_extended_context(
                doc_data['chunks'], 
                best_chunk_idx
            )
            
            results.append({
                'text': ''.join(context_chunks),
                'score': doc_scores[idx],
                'metadata': doc_data['metadata']
            })
        
        return results
    
    def _get_extended_context(self, chunks: List[str], 
                             center_idx: int) -> List[str]:
        """관련 청크 주변의 확장된 컨텍스트 가져오기"""
        start = max(0, center_idx - 1)
        end = min(len(chunks), center_idx + 2)
        return chunks[start:end]

사용 사례 및 성능

LongRAG 는 컨텍스트가 중요한 시나리오에서 탁월합니다:

  • 법적 문서 분석: 계약서와 법적 요약서에는 수십 페이지에 걸친 의존성이 자주 존재합니다
  • 학술 논문 검색: 방법론을 이해하려면 고립된 단락이 아닌 일관된 섹션이 필요합니다
  • 코드 저장소: 함수와 클래스는 모듈 컨텍스트 내에서 이해되어야 합니다

성능 특성:

  • 지연 시간 (Latency): 큰 청크 처리로 인해 더 높음 (표준 RAG 보다 2-5 배 느림)
  • 정확도: 장문 QA 벤치마크에서 15-25% 향상
  • 메모리: 컨텍스트 윈도우를 위해 3-4 배 더 많은 메모리 필요

Self-RAG: 반사적 검색

핵심 원칙

Self-RAG 는 RAG 시스템에 메타인지 (metacognitive) 레이어를 도입합니다. 맹목적으로 검색하고 생성하는 대신, 시스템은 특수한 반사 토큰을 통해 자신의 프로세스에 능동적으로 반성합니다:

검색 토큰 (Retrieve Token): 주어진 쿼리에 검색이 필요한지 결정합니다 관련성 토큰 (Relevance Token): 검색된 문서가 실제로 관련성이 있는지 평가합니다 지원 토큰 (Support Token): 생성된 답변이 검색된 콘텐츠에 의해 지지되는지 확인합니다 비평 토큰 (Critique Token): 생성된 응답의 전반적인 품질을 평가합니다

아키텍처 구성 요소

Self-RAG 아키텍처는 세 개의 교차되는 단계로 구성됩니다:

class SelfRAGSystem:
    def __init__(self, retriever, generator, critic):
        self.retriever = retriever
        self.generator = generator
        self.critic = critic
    
    def generate_with_reflection(self, query: str, 
                                 max_iterations: int = 3):
        """자기 반사를 통한 답변 생성"""
        
        # 단계 1: 검색 필요 여부 결정
        retrieve_decision = self.critic.should_retrieve(query)
        
        if not retrieve_decision:
            # 검색 없이 직접 생성
            return self.generator.generate(query)
        
        # 단계 2: 검색 및 관련성 평가
        retrieved_docs = self.retriever.retrieve(query)
        relevant_docs = []
        
        for doc in retrieved_docs:
            relevance_score = self.critic.assess_relevance(
                query, doc
            )
            if relevance_score > 0.7:  # 임계값
                relevant_docs.append(doc)
        
        if not relevant_docs:
            # 검색 없이 생성으로 폴백
            return self.generator.generate(query)
        
        # 단계 3: 생성 및 지원 검증
        best_answer = None
        best_score = -1
        
        for _ in range(max_iterations):
            # 후보 답변 생성
            answer = self.generator.generate(
                query, context=relevant_docs
            )
            
            # 지원 및 품질 평가
            support_score = self.critic.check_support(
                answer, relevant_docs
            )
            quality_score = self.critic.assess_quality(answer)
            
            total_score = 0.6 * support_score + 0.4 * quality_score
            
            if total_score > best_score:
                best_score = total_score
                best_answer = answer
            
            # 높은 품질 달성 시 조기 종료
            if total_score > 0.9:
                break
        
        return {
            'answer': best_answer,
            'confidence': best_score,
            'sources': relevant_docs,
            'reflections': {
                'retrieved': retrieve_decision,
                'relevance': len(relevant_docs),
                'support': support_score
            }
        }

반사 메커니즘 학습

Self-RAG 는 비평가 (critic) 구성 요소를 신뢰할 수 있는 평가를 하도록 학습시켜야 합니다. 이는 일반적으로 다음을 포함합니다:

  1. 관련성 판단이 주석 처리된 데이터셋에 대한 지도 미세 조정 (Supervised fine-tuning)
  2. 정확한 예측에 대한 보상을 통한 강화 학습 (Reinforcement learning)
  3. 지지된 주장과 지지되지 않은 주장을 구분하기 위한 대조 학습 (Contrastive learning)

반사 토큰은 다음과 같이 구현될 수 있습니다:

  • 어휘 내 특수 토큰 (예: [RETRIEVE], [RELEVANT])
  • 모델의 별도 분류기 헤드
  • 외부 비평가 모델 (앙상블 접근)

프로덕션 고려 사항

프로덕션 시스템에서 Self-RAG 를 배포할 때:

지연 시간 트레이드오프: 각 반사 단계는 20-40% 의 추론 오버헤드를 추가합니다. 철저성과 응답 시간 요구 사항 사이의 균형을 맞추세요.

신뢰도 임계값: 사용 사례에 따라 반사 임계값을 조정하세요. 법률이나 의료 애플리케이션은 일반 챗봇보다 더 높은 신뢰도가 필요합니다.

모니터링: 반사 결정을 추적하여 패턴을 식별하세요. 검색이 거의 필요하지 않다면 더 단순한 아키텍처에서 이점을 얻을 수 있습니다.

GraphRAG: 지식 그래프 향상된 검색

개념적 기초

GraphRAG 는 검색 문제를 벡터 유사성에서 그래프 순환 (traversal) 으로 변환합니다. 의미론적으로 유사한 텍스트 청크를 찾는 대신, GraphRAG 는 연결된 엔티티와 관계의 관련된 서브그래프를 식별합니다.

엔티티 추출: 고유명사, 개념 및 해당 유형 식별 관계 매핑: 엔티티 간의 관계 추출 (시간적, 인과적, 위계적) 그래프 구축: 엔티티를 노드로, 관계를 엣지로 하는 지식 그래프 구축 서브그래프 검색: 주어진 쿼리에 대해 관련된 연결된 서브그래프 찾기

그래프 구축 파이프라인

비정형 텍스트에서 지식 그래프를 구축하려면 여러 단계가 필요합니다:

class GraphRAGBuilder:
    def __init__(self, entity_extractor, relation_extractor):
        self.entity_extractor = entity_extractor
        self.relation_extractor = relation_extractor
        self.graph = NetworkGraph()
    
    def build_graph(self, documents: List[str]):
        """문서에서 지식 그래프 구축"""
        for doc in documents:
            # 엔티티 추출
            entities = self.entity_extractor.extract(doc)
            
            # 엔티티를 노드로 추가
            for entity in entities:
                self.graph.add_node(
                    entity['text'],
                    entity_type=entity['type'],
                    context=entity['surrounding_text']
                )
            
            # 관계 추출
            relations = self.relation_extractor.extract(
                doc, entities
            )
            
            # 관계를 엣지로 추가
            for rel in relations:
                self.graph.add_edge(
                    rel['source'],
                    rel['target'],
                    relation_type=rel['type'],
                    confidence=rel['score'],
                    evidence=rel['text_span']
                )
    
    def enrich_graph(self):
        """파생된 관계 및 메타데이터 추가"""
        # 노드 중요도 계산 (PageRank 등)
        self.graph.compute_centrality()
        
        # 커뮤니티/클러스터 식별
        self.graph.detect_communities()
        
        # 타임스탬프가 있는 경우 시간적 순서 추가
        self.graph.add_temporal_edges()

그래프를 활용한 쿼리 처리

GraphRAG 쿼리는 지식 그래프를 통한 다단계 추론을 포함합니다:

class GraphRAGRetriever:
    def __init__(self, graph, embedder):
        self.graph = graph
        self.embedder = embedder
    
    def retrieve_subgraph(self, query: str, 
                         max_hops: int = 2,
                         max_nodes: int = 50):
        """쿼리를 위한 관련 서브그래프 검색"""
        
        # 쿼리 내 시드 엔티티 식별
        query_entities = self.entity_extractor.extract(query)
        
        # 그래프에서 일치하는 노드 찾기
        seed_nodes = []
        for entity in query_entities:
            matches = self.graph.find_similar_nodes(
                entity['text'],
                similarity_threshold=0.85
            )
            seed_nodes.extend(matches)
        
        # 순환을 통한 서브그래프 확장
        subgraph = self.graph.create_subgraph()
        visited = set()
        
        for seed in seed_nodes:
            self._expand_from_node(
                seed, 
                subgraph, 
                visited,
                current_hop=0,
                max_hops=max_hops
            )
        
        # 관련성으로 노드 순위 매기기
        ranked_nodes = self._rank_subgraph_nodes(
            subgraph, query
        )
        
        # 컨텍스트 추출 및 포맷팅
        context = self._format_graph_context(
            ranked_nodes[:max_nodes],
            subgraph
        )
        
        return context
    
    def _expand_from_node(self, node, subgraph, visited,
                         current_hop, max_hops):
        """재귀적으로 서브그래프 확장"""
        if current_hop >= max_hops or node in visited:
            return
        
        visited.add(node)
        subgraph.add_node(node)
        
        # 이웃 노드 가져오기
        neighbors = self.graph.get_neighbors(node)
        
        for neighbor, edge_data in neighbors:
            # 서브그래프에 엣지 추가
            subgraph.add_edge(node, neighbor, edge_data)
            
            # 재귀적으로 확장
            self._expand_from_node(
                neighbor,
                subgraph,
                visited,
                current_hop + 1,
                max_hops
            )
    
    def _format_graph_context(self, nodes, subgraph):
        """서브그래프를 텍스트 컨텍스트로 변환"""
        context_parts = []
        
        for node in nodes:
            # 노드 컨텍스트 추가
            context_parts.append(f"엔티티: {node.text}")
            context_parts.append(f"유형: {node.entity_type}")
            
            # 관계 정보 추가
            edges = subgraph.get_edges(node)
            for edge in edges:
                context_parts.append(
                    f"- {edge.relation_type} -> {edge.target.text}"
                )
        
        return "\n".join(context_parts)

Microsoft 의 GraphRAG 구현

Microsoft 의 GraphRAG 는 커뮤니티 요약 (community summaries) 을 생성하는 독특한 접근 방식을 취합니다:

  1. LLM 기반 엔티티/관계 추출을 사용하여 문서에서 초기 그래프 구축
  2. Leiden 알고리즘 또는 유사한 알고리즘을 사용하여 커뮤니티 감지
  3. LLM 을 사용하여 각 커뮤니티에 대한 요약 생성
  4. 계층적 구조: 여러 수준의 커뮤니티 추상화 구축
  5. 쿼리 시간: 관련 커뮤니티 검색 및 특정 엔티티로 이동

이 접근 방식은 다음과 같은 경우에 특히 효과적입니다:

  • 탐색적 쿼리 (“이 코퍼스에서 주요 주제는 무엇인가요?”)
  • 다단계 추론 (“A 는 B 를 통해 C 와 어떻게 연결되나요?”)
  • 시간적 분석 (“이 엔티티의 관계는 어떻게 발전했나요?”)

비교 분석

각 변형 사용 시기

LongRAG 사용 시:

  • 문서가 강력한 내부 일관성을 가지고 있을 때
  • LLM 이 큰 입력 (32K+) 을 지원하는 컨텍스트 윈도우를 가지고 있을 때
  • 쿼리 답변이 장거리 의존성을 이해해야 할 때
  • 구조화된 문서 (보고서, 논문, 책) 를 다룰 때

Self-RAG 사용 시:

  • 정확성과 신뢰성이 중요한 경우
  • 설명 가능한 검색 결정이 필요한 경우
  • 관련성 없는 검색으로 인한 거짓 양성이 비용이 많이 드는 경우
  • 쿼리 복잡성이 다양하게 변할 때 (일부는 검색 필요, 일부는 불필요)

GraphRAG 사용 시:

  • 도메인이 풍부한 엔티티 관계를 가지고 있을 때
  • 쿼리가 다단계 추론을 포함할 때
  • 시간적 또는 위계적 관계가 중요한 경우
  • 엔티티 간의 연결을 이해해야 할 때

성능 지표 비교

지표 표준 RAG LongRAG Self-RAG GraphRAG
색인화 시간 1 배 0.8 배 1.1 배 3-5 배
쿼리 지연 시간 1 배 2-3 배 1.4 배 1.5-2 배
메모리 사용량 1 배 3-4 배 1.2 배 2-3 배
정확도 (QA) 기준 +15-25% +20-30% +25-40%*
설명 가능성 낮음 중간 높음 높음

*GraphRAG 개선은 도메인 의존도가 매우 높습니다

하이브리드 접근 방식

가장 강력한 프로덕션 시스템은 종종 여러 기술을 결합합니다:

LongRAG + GraphRAG: 그래프 구조를 사용하여 관련 문서 클러스터를 식별한 다음, 단편 대신 전체 문서를 검색합니다

Self-RAG + GraphRAG: 그래프 순환 결정 (어떤 경로를 따를지, 언제 확장을 멈출지) 에 반사 메커니즘을 적용합니다

3 단계 파이프라인: 초기 엔티티 기반 검색을 위해 GraphRAG 사용 → 관련성 필터링을 위해 Self-RAG 사용 → 컨텍스트 조립을 위해 LongRAG 사용

구현 고려 사항

임베딩 모델

다양한 RAG 변형은 서로 다른 임베딩 요구 사항을 가집니다:

LongRAG: 문서 수준과 청크 수준 모두에서 잘 작동하는 임베딩이 필요합니다. 긴 시퀀스에 대해 대조 학습으로 훈련된 모델을 고려하세요.

Self-RAG: 세밀한 관련성 평가를 위한 의미론적 뉘앙스를 포착하는 임베딩에서 이점을 얻습니다.

GraphRAG: 엔티티 인식 임베딩이 필요합니다. 엔티티 연결 작업에 미세 조정된 모델이 더 잘 작동합니다.

임베딩 모델의 선택은 성능에 상당한 영향을 미칩니다. 로컬 모델을 사용할 때, Ollama 와 같은 도구는 프로덕션 배포에 투입하기 전에 다양한 임베딩 모델을 실험하는 간단한 방법을 제공합니다.

재방문하는 청킹 전략

전통적인 고정 크기 청킹은 고급 RAG 에 부족합니다:

의미론적 청킹: 자연스러운 경계 (단락, 섹션, 주제 전환) 에서 끊습니다 재귀적 청킹: 부모 - 자식 관계를 가진 계층적 청크를 생성합니다 슬라이딩 윈도우: 경계에서 컨텍스트를 보존하기 위해 중복되는 청크를 사용합니다 구조 인식: 문서 구조 (마크다운 헤더, XML 태그, 코드 블록) 를 존중합니다

Python 기반 구현을 위해 LangChain 및 LlamaIndex 와 같은 라이브러리는 이러한 청킹 전략 에 대한 내장 지원을 제공합니다.

리랭킹 통합

리랭킹은 모든 RAG 변형에서 검색 품질을 극적으로 향상시킵니다. 초기 검색 후, 전문 리랭킹 모델은 쿼리 - 문서 상호작용 특징을 기반으로 결과를 재점수합니다. 이는 주의 깊게 통합될 때 지연 시간 영향이 최소화되면서 상당한 정확도 향상 (10-20%) 을 제공합니다.

프로덕션 확장

색인화 파이프라인:

  • 대규모 문서 코퍼스를 위해 분산 처리 (Ray, Dask) 사용
  • 실시간 업데이트를 위한 증분 색인화 구현
  • 최적화된 벡터 데이터베이스 (Pinecone, Weaviate, Qdrant) 에 임베딩 저장

쿼리 최적화:

  • 빈번한 쿼리 및 그 결과 캐싱
  • 쿼리 라우팅 구현 (쿼리 유형에 따라 다른 RAG 변형 사용)
  • 서브선형 확장을 위해 근사最近邻 검색 사용

모니터링:

  • 검색 관련성 점수 추적
  • Self-RAG 에서 반사 결정 모니터링
  • 그래프 순환 경로 및 깊이 측정
  • 신뢰도 점수 및 사용자 피드백 로깅

실제 적용 사례

기술 문서 검색

주요 클라우드 공급자는 문서화를 위해 GraphRAG 를 구현했습니다:

  • 엔티티: API 엔드포인트, 매개변수, 오류 코드, 서비스 이름
  • 관계: 의존성, 버전 호환성, 마이그레이션 경로
  • 결과: 지원 티켓 35% 감소, 45% 빠른 해결 시간

법률 발견 (Discovery)

법률 테크 회사는 Self-RAG 와 LongRAG 를 결합했습니다:

  • Self-RAG 가 초기에 관련성 없는 문서를 필터링합니다
  • LongRAG 가 유지된 문서에서 컨텍스트를 보존합니다
  • 변호사들이 60% 적은 거짓 양성을 검토합니다
  • 중요한 컨텍스트 보존이 71% 에서 94% 로 향상되었습니다

연구 문헌 검토

하이브리드 접근 방식을 사용하는 학술 검색 엔진:

  • GraphRAG 가 인용 네트워크 및 연구 커뮤니티를 식별합니다
  • LongRAG 가 방법론 컨텍스트를 유지하며 전체 섹션을 검색합니다
  • 관련 논문 발견율 40% 향상
  • 문헌 검토 시간이 주에서 일로 단축

고급 주제

멀티모달 RAG

이미지, 표, 코드를 처리하도록 이러한 변형을 확장합니다:

  • 시각적 그라운딩 (Visual grounding): 문서 내 텍스트 엔티티를 이미지와 연결
  • 표 이해 (Table understanding): 구조화된 데이터를 그래프 형식으로 파싱
  • 코드 분석: 코드베이스에서 의존성 그래프 구축

적응형 RAG

쿼리 특성에 따라 RAG 전략을 동적으로 선택합니다:

  • 쿼리 복잡성 분류기
  • 문서 유형 감지기
  • 전략 선택을 위한 비용 - 편익 최적화기

프라이버시 보존 RAG

프라이버시 제약 조건과 함께 이러한 변형을 구현합니다:

  • 데이터 실로 (silos) 를 통한 페더레이션 검색
  • 임베딩의 차분 프라이버시 (Differential privacy)
  • 암호화된 유사성 검색

시작하기

Python 으로 빠른 시작

이러한 기술을 구현하려는 분들을 위해, 견고한 Python 기반이 필수적입니다. 머신러닝을 위한 Python 의 풍부한 생태계는 RAG 개발에 자연스러운 선택입니다.

실험을 위한 간단한 시작점:

# 의존성 설치
# pip install sentence-transformers faiss-cpu langchain

from sentence_transformers import SentenceTransformer
import faiss
import numpy as np

# 긴 청크 실험을 위한 기본 설정
model = SentenceTransformer('all-MiniLM-L6-v2')

documents = [
    # 여기 장문 문서 입력
]

# 임베딩 생성
embeddings = model.encode(documents)

# FAISS 색인 구축
dimension = embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)
index.add(embeddings.astype('float32'))

# 쿼리
query = "질문 입력"
query_embedding = model.encode([query])
distances, indices = index.search(
    query_embedding.astype('float32'), k=3
)

프레임워크 선택

LangChain: 빠른 프로토타이핑 및 광범위한 통합에 최적 LlamaIndex: 문서 색인화 및 검색에 최적화 Haystack: 프로덕션 준비, 강력한 파이프라인 추상화 커스텀: 완전한 제어 및 최적화가 필요할 때

평가 프레임워크

프로덕션 배포 전에 엄격한 평가를 구현하세요:

검색 지표:

  • Precision@K, Recall@K, MRR (평균 역순위)
  • NDCG (정규화 할인 누적 이득)

생성 지표:

  • 텍스트 유사성을 위한 ROUGE, BLEU
  • 의미론적 유사성을 위한 BERTScore
  • 품질 평가를 위한 인간 평가

엔드투엔드 지표:

  • 작업 성공률
  • 사용자 만족도 점수
  • 지연 시간 백분위 (p50, p95, p99)

결론

RAG 시스템의 지형은 기본적인 벡터 유사성 검색을 넘어 크게 성숙되었습니다. LongRAG, Self-RAG, GraphRAG 는 각각 전통적인 접근 방식의 특정 한계를 해결합니다:

LongRAG 는 확장된 컨텍스트 윈도우를 수용하고 최소한의 청킹 을 통해 컨텍스트 단편화 문제를 해결합니다. 문서 일관성이 중요하고 큰 컨텍스트를 처리할 계산 자원이 있을 때 선택하는 것이 좋습니다.

Self-RAG 는 검색 시스템에 중요한 자기 인식 (self-awareness) 을 추가합니다. 자신의 결정에 대해 반성함으로써 거짓 양성을 줄이고 신뢰성을 향상시킵니다. 이는 정확도가 속도보다 중요한 고위험 애플리케이션에 필수적입니다.

GraphRAG 는 구조화된 지식 표현의 힘을 발휘합니다. 도메인이 엔티티 간의 복잡한 관계를 포함할 때, 그래프 기반 검색은 벡터 유사성이 완전히 놓치는 연결을 표면에 드러냅니다.

RAG 의 미래는 이러한 변형의 강점을 결합하는 하이브리드 접근 방식을 포함할 가능성이 높습니다. 프로덕션 시스템은 GraphRAG 를 사용하여 관련 엔티티 클러스터를 식별하고, Self-RAG 를 사용하여 검색을 필터링 및 검증하며, LongRAG 를 사용하여 LLM 에 대한 일관된 컨텍스트를 조립할 수 있습니다.

LLM 이 계속 발전하고 컨텍스트 윈도우가 확장됨에 따라, 우리는 더 정교한 RAG 변형을 볼 것입니다. 핵심은 특정 사용 사례 요구 사항 (문서 구조, 쿼리 패턴, 정확도 요구 사항, 계산 제약) 을 이해하고 적절한 기술 또는 그 조합을 선택하는 것입니다.

도구 생태계는 급속히 성숙하고 있으며, LangChain, LlamaIndex, Haystack 과 같은 프레임워크는 이러한 고급 패턴을 위해 점점 더 정교한 지원을 제공하고 있습니다. 강력한 로컬 LLM 런타임 및 임베딩 모델과 결합하여, 생산급 RAG 시스템을 실험하고 배포하는 것은 이제 그 어느 때보다 쉬워졌습니다.

기본부터 시작하여 성능을 엄격하게 측정하고 요구 사항에 따라 아키텍처를 발전시키세요. 여기에서 다루는 고급 RAG 변형은 이러한 진화의 로드맵을 제공합니다.

유용한 링크

외부 참조