Split View: GraphRAG 완전 가이드: 지식 그래프가 RAG의 한계를 어떻게 넘는가
GraphRAG 완전 가이드: 지식 그래프가 RAG의 한계를 어떻게 넘는가
- 기존 RAG의 한계: 어떤 질문에서 실패하는가
- GraphRAG란? (Microsoft Research, 2024)
- 핵심 구조 이해하기
- 코드로 보는 GraphRAG
- Local Search vs Global Search: 언제 무엇을 쓸까
- 지식 그래프 직접 살펴보기
- GraphRAG vs 일반 RAG: 성능 비교
- 비용 현실: 솔직한 계산
- GraphRAG가 적합한 경우 vs 일반 RAG로 충분한 경우
- LightRAG: GraphRAG의 더 실용적인 대안
- 결론: GraphRAG는 도구이지 모든 것의 답이 아니다
기존 RAG의 한계: 어떤 질문에서 실패하는가
Vector DB 기반 RAG를 운영하다 보면 특정 유형의 질문에서 일관되게 실패하는 패턴을 발견합니다.
실패하는 질문들:
- "이 분기 보고서들에서 전반적인 리스크 요인을 요약해줘"
- "우리 제품 리뷰에서 반복적으로 등장하는 불만 패턴은?"
- "CEO가 바뀐 이후 회사 전략의 변화를 설명해줘"
- "A 제품과 B 제품의 공통된 결함 특성은?"
왜 실패할까요? 이 질문들의 공통점은 단일 청크로는 답할 수 없고, 전체 지식베이스를 횡단하는 이해가 필요하다는 것입니다.
일반 RAG의 작동 방식을 생각해보면:
- 질문을 임베딩
- 유사도로 가장 관련성 높은 청크 3-5개 검색
- 그 청크들로 답변 생성
"이 분기 보고서들의 전반적인 리스크 요인"을 물으면 RAG는 특정 보고서의 한 섹션을 가져올 뿐, 전체를 가로지르는 패턴을 볼 수 없습니다. 이게 근본적인 한계입니다.
GraphRAG란? (Microsoft Research, 2024)
Microsoft Research에서 2024년 발표한 논문 "From Local to Global: A GraphRAG Approach to Query-Focused Summarization" (Edge et al., 2024)에서 소개된 방법론입니다.
핵심 아이디어는 간단합니다: 단순히 텍스트를 청크로 나누는 대신, 문서에서 엔티티와 관계를 추출해 지식 그래프를 만들고, 그 위에서 검색한다.
일반 RAG:
문서들 → 청크 분할 → 임베딩 → 벡터 DB → 유사도 검색 → 관련 청크
GraphRAG:
문서들 → 엔티티 추출 → 지식 그래프 구성 → 커뮤니티 탐지 →
→ 계층적 요약 생성 → 다단계 검색 (Local + Global)
핵심 구조 이해하기
1. 엔티티와 관계 추출
GraphRAG는 LLM을 사용해 문서에서 엔티티(사람, 조직, 장소, 개념)와 그 관계를 추출합니다.
입력 텍스트:
"삼성전자는 2024년 갤럭시 S25를 출시하여 애플 아이폰 16과 직접 경쟁합니다.
갤럭시 S25는 퀄컴 스냅드래곤 8 Elite 칩을 탑재했습니다."
추출되는 엔티티:
- 삼성전자 (조직)
- 갤럭시 S25 (제품)
- 애플 (조직)
- 아이폰 16 (제품)
- 퀄컴 (조직)
- 스냅드래곤 8 Elite (제품/기술)
추출되는 관계:
- 삼성전자 --[출시]--> 갤럭시 S25
- 갤럭시 S25 --[경쟁]--> 아이폰 16
- 갤럭시 S25 --[탑재]--> 스냅드래곤 8 Elite
- 퀄컴 --[제조]--> 스냅드래곤 8 Elite
2. 커뮤니티 탐지 (Community Detection)
엔티티 그래프에서 Leiden 알고리즘 등을 사용해 서로 밀접하게 연결된 엔티티 그룹(커뮤니티)을 찾습니다.
예: 스마트폰 시장 커뮤니티, 반도체 커뮤니티, 소프트웨어 생태계 커뮤니티
3. 계층적 요약
각 커뮤니티에 대해 여러 수준의 요약을 생성합니다:
Level 0 (최세밀): 개별 엔티티/관계 요약
Level 1: 소규모 커뮤니티 요약
Level 2: 중규모 커뮤니티 요약 (일반적으로 이걸 많이 사용)
Level 3 (최포괄): 전체 주제 요약
코드로 보는 GraphRAG
Microsoft의 공식 graphrag 라이브러리를 사용합니다.
# 설치
pip install graphrag
# 프로젝트 초기화
mkdir my-graphrag-project
graphrag init --root ./my-graphrag-project
초기화하면 settings.yaml이 생성됩니다. 핵심 설정:
# settings.yaml 주요 설정
llm:
api_key: ${GRAPHRAG_API_KEY}
type: openai_chat
model: gpt-4o-mini # 인덱싱용 (비용 절감 위해 mini 사용)
model_supports_json: true
embeddings:
llm:
model: text-embedding-3-small # 임베딩용
input:
type: file
file_type: text
base_dir: "input" # 문서를 여기에 넣기
chunks:
size: 1200
overlap: 100
# 인덱싱 (지식 그래프 구축)
# graphrag index --root ./my-graphrag-project
# 이 명령이 내부적으로 하는 일:
# 1. 문서 청킹
# 2. 엔티티 및 관계 추출 (LLM 호출)
# 3. 그래프 구성
# 4. 커뮤니티 탐지
# 5. 각 커뮤니티에 대한 요약 생성 (LLM 호출)
# Python API로 쿼리
import asyncio
from graphrag.query.api import local_search, global_search
# Local Search: 특정 엔티티/관계 중심 질문
async def search_local(query: str):
result = await local_search(
config_dir="./my-graphrag-project",
data_dir="./my-graphrag-project/output",
root_dir="./my-graphrag-project",
community_level=2,
response_type="multiple paragraphs",
query=query,
)
return result.response
# Global Search: 전체 지식베이스 합성이 필요한 질문
async def search_global(query: str):
result = await global_search(
config_dir="./my-graphrag-project",
data_dir="./my-graphrag-project/output",
root_dir="./my-graphrag-project",
community_level=2,
response_type="multiple paragraphs",
query=query,
)
return result.response
# 사용 예시
local_result = asyncio.run(search_local(
"삼성전자와 TSMC의 관계는 어떻게 되나요?"
))
global_result = asyncio.run(search_global(
"이 문서들에서 반도체 산업의 주요 트렌드는 무엇인가요?"
))
Local Search vs Global Search: 언제 무엇을 쓸까
GraphRAG의 두 검색 모드를 이해하는 게 핵심입니다.
| 쿼리 유형 | 최적 모드 | 예시 |
|---|---|---|
| 특정 엔티티에 대한 질문 | Local Search | "김철수의 역할은?" |
| 두 엔티티의 관계 | Local Search | "삼성과 TSMC의 관계는?" |
| 전체 트렌드 파악 | Global Search | "이 문서들의 주요 주제는?" |
| 전반적인 패턴 분석 | Global Search | "업계 전체의 리스크 요인은?" |
| 시간에 따른 변화 | Local/Global 모두 활용 | "지난 5년간 전략 변화는?" |
Local Search 작동 방식:
- 질문에서 관련 엔티티 찾기
- 해당 엔티티와 연결된 텍스트 청크, 관계, 커뮤니티 요약 수집
- LLM으로 최종 답변 생성
Global Search 작동 방식:
- 모든 커뮤니티 요약을 여러 "청크"로 나눔
- 각 청크에 대해 부분 답변 생성 (Map phase)
- 부분 답변들을 합쳐 최종 답변 생성 (Reduce phase)
지식 그래프 직접 살펴보기
GraphRAG가 생성한 그래프를 시각화하면 통찰을 얻을 수 있습니다.
import pandas as pd
import networkx as nx
# GraphRAG 출력 파일에서 엔티티와 관계 로드
entities_df = pd.read_parquet("./output/entities.parquet")
relationships_df = pd.read_parquet("./output/relationships.parquet")
print(f"총 엔티티 수: {len(entities_df)}")
print(f"총 관계 수: {len(relationships_df)}")
# NetworkX 그래프 구성
G = nx.DiGraph()
for _, entity in entities_df.iterrows():
G.add_node(entity["title"], type=entity["type"])
for _, rel in relationships_df.iterrows():
G.add_edge(
rel["source"],
rel["target"],
weight=rel["weight"],
description=rel["description"]
)
# 가장 연결이 많은 엔티티 (허브 찾기)
top_hubs = sorted(G.degree(), key=lambda x: x[1], reverse=True)[:10]
print("가장 중요한 엔티티 Top 10:")
for entity, degree in top_hubs:
print(f" {entity}: {degree}개 연결")
GraphRAG vs 일반 RAG: 성능 비교
Microsoft의 원논문 결과 (HotPotQA, MuSiQue 데이터셋):
글로벌 질문 (전체 요약 필요):
- 일반 RAG: 포괄성 40%, 다양성 57%
- GraphRAG: 포괄성 72%, 다양성 62%
→ 포괄성 80% 향상!
로컬 질문 (특정 사실):
- 일반 RAG: 정확도 ~65%
- GraphRAG: 정확도 ~70%
→ 약간 개선
속도:
- 일반 RAG: 0.5-2초
- GraphRAG: 3-10초 (커뮤니티 요약 합산 때문)
결론: 전역 질문에서는 GraphRAG가 압도적으로 좋지만, 특정 사실 검색에서는 일반 RAG와 비슷하거나 느립니다.
비용 현실: 솔직한 계산
GraphRAG의 가장 큰 단점은 인덱싱 비용입니다.
# GraphRAG 인덱싱 비용 추정
# 가정: 1,000개 문서, 각 1,000 토큰
num_documents = 1000
tokens_per_doc = 1000
total_tokens = num_documents * tokens_per_doc # 1M 토큰
# 인덱싱 단계별 LLM 호출 횟수 추정
entity_extraction_calls = total_tokens / 1200 # 청크당 1번
# 각 추출 호출: ~800 토큰 입력 + ~400 토큰 출력
community_summary_calls = 200 # 커뮤니티 수 × 레벨
# 각 요약 호출: ~2000 토큰 입력 + ~500 토큰 출력
# GPT-4o-mini 기준 비용 ($0.15 / 1M input, $0.60 / 1M output)
entity_input_cost = (entity_extraction_calls * 800 / 1_000_000) * 0.15
entity_output_cost = (entity_extraction_calls * 400 / 1_000_000) * 0.60
community_cost = (community_summary_calls * 2500 / 1_000_000) * 0.40
total_indexing_cost = entity_input_cost + entity_output_cost + community_cost
print(f"추정 인덱싱 비용: ${total_indexing_cost:.2f}")
# 1,000개 문서: 약 $1-5 (GPT-4o-mini 사용 시)
# 10,000개 문서: 약 $10-50
# 100,000개 문서: 약 $100-500
# 쿼리 비용 (Global Search)
# Global search는 커뮤니티 요약 전체를 LLM에 보내므로 쿼리당 비용이 높음
# 커뮤니티가 200개, 각 요약 500토큰이면 쿼리당 ~100K 토큰 처리
global_query_cost = (100_000 / 1_000_000) * 2.50 # GPT-4o 기준
print(f"Global search 쿼리당 비용: ${global_query_cost:.3f}") # $0.25/쿼리
이 비용이 받아들일 만한지 판단하려면:
- 초기 인덱싱: 문서가 자주 변경되지 않는다면 일회성 비용
- 쿼리 비용: Global search는 RAG보다 10-100배 비쌀 수 있음
GraphRAG가 적합한 경우 vs 일반 RAG로 충분한 경우
GraphRAG가 가치 있는 경우:
- 수백~수천 개 문서에 걸친 패턴/트렌드 분석
- 재무 보고서, 특허, 법률 문서 분석
- 지식베이스가 거의 변경되지 않는 경우 (인덱싱 비용 일회성)
- "이 회사에 대해 뭘 알고 있어?"처럼 광범위한 질문이 많은 경우
일반 RAG가 충분한 경우:
- 특정 사실 검색 ("이 계약서의 만료일은?")
- 빠른 응답이 필요한 실시간 서비스
- 문서가 자주 업데이트되는 경우 (재인덱싱 비용)
- 소규모 지식베이스 (< 100개 문서)
- 비용 예산이 타이트한 경우
LightRAG: GraphRAG의 더 실용적인 대안
Microsoft의 GraphRAG가 너무 복잡하거나 비싸다면 LightRAG를 고려해보세요.
# pip install lightrag-hku
from lightrag import LightRAG, QueryParam
from lightrag.llm import gpt_4o_mini_complete
rag = LightRAG(
working_dir="./lightrag-storage",
llm_model_func=gpt_4o_mini_complete,
)
# 문서 추가
with open("document.txt", "r") as f:
rag.insert(f.read())
# 쿼리 (naive, local, global, hybrid 4가지 모드)
result = rag.query(
"주요 트렌드는 무엇인가요?",
param=QueryParam(mode="global") # hybrid 모드도 효과적
)
LightRAG는 구현이 더 간단하고 비용도 저렴하며, 소규모-중간 규모 지식베이스에서 충분한 성능을 냅니다.
결론: GraphRAG는 도구이지 모든 것의 답이 아니다
GraphRAG는 강력하지만 모든 상황에 적합하지는 않습니다.
핵심 정리:
- 전역 질문(global queries)에서 일반 RAG를 크게 능가
- 인덱싱 비용이 높으므로 지식베이스가 안정적일 때 적합
- 쿼리 비용도 일반 RAG보다 높음
- 간단히 시작하려면 Microsoft의
graphrag또는LightRAG라이브러리 활용
투자 대비 효과를 생각하세요. "문서에서 전체적인 패턴을 이해해야 한다"는 명확한 요구사항이 있을 때 GraphRAG를 도입하고, 특정 사실 검색이 주 용도라면 잘 튜닝된 일반 RAG가 더 경제적입니다.
GraphRAG Complete Guide: How Knowledge Graphs Overcome RAG Limitations
- Where Standard RAG Fails
- What Is GraphRAG? (Microsoft Research, 2024)
- Understanding the Core Structure
- GraphRAG in Code
- Local vs Global Search: When to Use Which
- Exploring the Knowledge Graph Directly
- GraphRAG vs Standard RAG: Performance Comparison
- Cost Reality: Honest Numbers
- GraphRAG vs Standard RAG: When to Use Which
- LightRAG: A More Practical Alternative
- Conclusion: GraphRAG Is a Tool, Not a Silver Bullet
Where Standard RAG Fails
After running vector-search RAG in production, you'll notice it fails consistently on certain question types.
Questions that break standard RAG:
- "Summarize the overall risk factors across this quarter's reports"
- "What complaint patterns appear repeatedly in our product reviews?"
- "How has the company's strategy changed since the CEO transition?"
- "What are the common failure characteristics between Product A and Product B?"
Why does it fail? These questions share a common property: no single chunk can answer them — you need a cross-document understanding of the entire knowledge base.
Standard RAG's mechanics:
- Embed the question
- Find the 3-5 most similar chunks by cosine similarity
- Generate an answer from those chunks
When you ask "what are the overall risk factors across these reports?" RAG retrieves a section from one report — it can't see patterns that span all the documents. That's the fundamental limitation.
What Is GraphRAG? (Microsoft Research, 2024)
Microsoft Research published "From Local to Global: A GraphRAG Approach to Query-Focused Summarization" (Edge et al., 2024) introducing this methodology.
The core idea is straightforward: instead of just splitting documents into chunks, extract entities and relationships to build a knowledge graph, then retrieve from that graph.
Standard RAG:
Documents -> Chunk -> Embed -> Vector DB -> Similarity Search -> Relevant Chunks
GraphRAG:
Documents -> Entity Extraction -> Knowledge Graph -> Community Detection ->
-> Hierarchical Summaries -> Multi-level Retrieval (Local + Global)
Understanding the Core Structure
1. Entity and Relationship Extraction
GraphRAG uses an LLM to extract entities (people, organizations, places, concepts) and their relationships from documents.
Input text:
"Samsung launched the Galaxy S25 in 2024, competing directly with Apple's
iPhone 16. The Galaxy S25 is powered by the Qualcomm Snapdragon 8 Elite chip."
Extracted entities:
- Samsung (organization)
- Galaxy S25 (product)
- Apple (organization)
- iPhone 16 (product)
- Qualcomm (organization)
- Snapdragon 8 Elite (product/technology)
Extracted relationships:
- Samsung --[launched]--> Galaxy S25
- Galaxy S25 --[competes with]--> iPhone 16
- Galaxy S25 --[powered by]--> Snapdragon 8 Elite
- Qualcomm --[manufactures]--> Snapdragon 8 Elite
2. Community Detection
Using algorithms like Leiden on the entity graph, GraphRAG finds clusters of closely connected entities (communities).
Examples: smartphone market community, semiconductor community, software ecosystem community.
3. Hierarchical Summaries
Summaries are generated for each community at multiple granularity levels:
Level 0 (most detailed): individual entity/relationship summaries
Level 1: small community summaries
Level 2: mid-scale community summaries (most commonly used)
Level 3 (most comprehensive): global topic summaries
GraphRAG in Code
Using Microsoft's official graphrag library:
# Install
pip install graphrag
# Initialize project
mkdir my-graphrag-project
graphrag init --root ./my-graphrag-project
The generated settings.yaml key configuration:
# Key settings in settings.yaml
llm:
api_key: ${GRAPHRAG_API_KEY}
type: openai_chat
model: gpt-4o-mini # for indexing (mini to reduce cost)
model_supports_json: true
embeddings:
llm:
model: text-embedding-3-small
input:
type: file
file_type: text
base_dir: "input" # put your documents here
chunks:
size: 1200
overlap: 100
# Indexing (building the knowledge graph)
# graphrag index --root ./my-graphrag-project
# What this does internally:
# 1. Chunk documents
# 2. Extract entities and relationships (LLM calls)
# 3. Build the graph
# 4. Run community detection
# 5. Generate summaries for each community (LLM calls)
# Querying via Python API
import asyncio
from graphrag.query.api import local_search, global_search
# Local Search: entity/relationship-focused questions
async def search_local(query: str):
result = await local_search(
config_dir="./my-graphrag-project",
data_dir="./my-graphrag-project/output",
root_dir="./my-graphrag-project",
community_level=2,
response_type="multiple paragraphs",
query=query,
)
return result.response
# Global Search: questions requiring synthesis across the full knowledge base
async def search_global(query: str):
result = await global_search(
config_dir="./my-graphrag-project",
data_dir="./my-graphrag-project/output",
root_dir="./my-graphrag-project",
community_level=2,
response_type="multiple paragraphs",
query=query,
)
return result.response
# Usage
local_result = asyncio.run(search_local(
"What is the relationship between Samsung and TSMC?"
))
global_result = asyncio.run(search_global(
"What are the main trends in the semiconductor industry across these documents?"
))
Local vs Global Search: When to Use Which
Understanding the two query modes is the key to using GraphRAG effectively.
| Query Type | Best Mode | Example |
|---|---|---|
| Question about a specific entity | Local Search | "What is John Kim's role?" |
| Relationship between two entities | Local Search | "What's the Samsung-TSMC relationship?" |
| Overall trend identification | Global Search | "What are the main themes in these docs?" |
| Cross-document pattern analysis | Global Search | "What are the industry-wide risk factors?" |
| Changes over time | Both | "How did strategy evolve over 5 years?" |
Local Search internally:
- Find relevant entities from the query
- Collect text chunks, relationships, and community summaries connected to those entities
- Generate final answer with LLM
Global Search internally:
- Split all community summaries into "batches"
- Generate partial answers for each batch (Map phase)
- Merge partial answers into final answer (Reduce phase)
Exploring the Knowledge Graph Directly
Visualizing GraphRAG's generated graph reveals insights about your data.
import pandas as pd
import networkx as nx
# Load entities and relationships from GraphRAG output
entities_df = pd.read_parquet("./output/entities.parquet")
relationships_df = pd.read_parquet("./output/relationships.parquet")
print(f"Total entities: {len(entities_df)}")
print(f"Total relationships: {len(relationships_df)}")
# Build NetworkX graph
G = nx.DiGraph()
for _, entity in entities_df.iterrows():
G.add_node(entity["title"], type=entity["type"])
for _, rel in relationships_df.iterrows():
G.add_edge(
rel["source"],
rel["target"],
weight=rel["weight"],
description=rel["description"]
)
# Find hub entities (most connected)
top_hubs = sorted(G.degree(), key=lambda x: x[1], reverse=True)[:10]
print("Top 10 most connected entities:")
for entity, degree in top_hubs:
print(f" {entity}: {degree} connections")
GraphRAG vs Standard RAG: Performance Comparison
From Microsoft's original paper (HotPotQA, MuSiQue datasets):
Global queries (requiring whole-document synthesis):
- Standard RAG: comprehensiveness 40%, diversity 57%
- GraphRAG: comprehensiveness 72%, diversity 62%
-> 80% improvement in comprehensiveness!
Local queries (specific fact retrieval):
- Standard RAG: accuracy ~65%
- GraphRAG: accuracy ~70%
-> Modest improvement
Latency:
- Standard RAG: 0.5-2 seconds
- GraphRAG: 3-10 seconds (due to community summary aggregation)
Conclusion: GraphRAG dominates on global queries, but is comparable to or slower than standard RAG for specific fact retrieval.
Cost Reality: Honest Numbers
GraphRAG's biggest drawback is indexing cost.
# GraphRAG indexing cost estimate
# Assumptions: 1,000 documents, 1,000 tokens each
num_documents = 1000
tokens_per_doc = 1000
total_tokens = num_documents * tokens_per_doc # 1M tokens
# Estimated LLM calls during indexing
entity_extraction_calls = total_tokens / 1200 # 1 call per chunk
# Each call: ~800 input tokens + ~400 output tokens
community_summary_calls = 200 # number of communities x levels
# Each call: ~2000 input tokens + ~500 output tokens
# Cost using GPT-4o-mini ($0.15/1M input, $0.60/1M output)
entity_input_cost = (entity_extraction_calls * 800 / 1_000_000) * 0.15
entity_output_cost = (entity_extraction_calls * 400 / 1_000_000) * 0.60
community_cost = (community_summary_calls * 2500 / 1_000_000) * 0.40
total_indexing_cost = entity_input_cost + entity_output_cost + community_cost
print(f"Estimated indexing cost: ${total_indexing_cost:.2f}")
# 1,000 documents: approx $1-5 (using GPT-4o-mini)
# 10,000 documents: approx $10-50
# 100,000 documents: approx $100-500
# Query cost (Global Search)
# Global search processes all community summaries for each query
# 200 communities x 500 tokens each = ~100K tokens processed per query
global_query_cost = (100_000 / 1_000_000) * 2.50 # GPT-4o pricing
print(f"Global search cost per query: ${global_query_cost:.3f}") # $0.25/query
Is this acceptable? Depends on your situation:
- Initial indexing: one-time cost if your documents don't change often
- Query cost: Global search can be 10-100x more expensive per query than standard RAG
GraphRAG vs Standard RAG: When to Use Which
GraphRAG is worth it when:
- Analyzing patterns/trends across hundreds to thousands of documents
- Financial reports, patents, legal document analysis
- Knowledge base is relatively static (indexing cost amortizes)
- Broad exploratory questions are common ("what do we know about this company?")
Standard RAG is sufficient when:
- Specific fact retrieval ("what's the expiration date on this contract?")
- Real-time services requiring fast response
- Frequently updated documents (re-indexing cost)
- Small knowledge base (under ~100 documents)
- Tight cost budget
LightRAG: A More Practical Alternative
If Microsoft's GraphRAG feels too complex or expensive, consider LightRAG.
# pip install lightrag-hku
from lightrag import LightRAG, QueryParam
from lightrag.llm import gpt_4o_mini_complete
rag = LightRAG(
working_dir="./lightrag-storage",
llm_model_func=gpt_4o_mini_complete,
)
# Insert documents
with open("document.txt", "r") as f:
rag.insert(f.read())
# Query (4 modes: naive, local, global, hybrid)
result = rag.query(
"What are the main trends?",
param=QueryParam(mode="global") # hybrid mode is also effective
)
LightRAG is simpler to implement, cheaper to run, and delivers sufficient performance for small to medium knowledge bases.
Conclusion: GraphRAG Is a Tool, Not a Silver Bullet
GraphRAG is powerful, but it's not the right choice for every situation.
Summary:
- Significantly outperforms standard RAG on global queries
- High indexing cost means it's best when the knowledge base is stable
- Query cost is also higher than standard RAG
- To get started quickly: use Microsoft's
graphraglibrary orLightRAG
Think about ROI. Adopt GraphRAG when you have a clear requirement like "we need to understand patterns across this corpus." For specific fact retrieval, a well-tuned standard RAG pipeline is more cost-effective.