고급 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 변형은 이러한 진화의 로드맵을 제공합니다.

유용한 링크

외부 참조

구독하기

시스템, 인프라, AI 엔지니어링에 관한 새 글을 받아보세요.