LLM & Generative AI/RAG in Practice

[LangChain RAG 구축 시리즈 Ep.13] 🧪 Stuff / MapReduce / Refine 전략 비교

ygtoken 2025. 4. 5. 20:22
728x90

이 글에서는 RAG 시스템에서 여러 개의 문서가 검색되었을 때,
GPT가 어떤 방식으로 응답을 생성할지를 결정하는
문서 조합 전략(Combining Strategy) 3가지 — Stuff, MapReduce, Refine 를 비교해봅니다.


🔍 문서 조합 전략이란?

검색된 여러 문서를 LLM에게 어떻게 전달할 것인지를 결정하는 전략입니다.

전략 방식
stuff 모든 문서를 한 번에 LLM에 전달
map_reduce 각 문서별로 응답 후, 전체 응답을 정리
refine 첫 문서로 응답한 뒤, 나머지 문서로 점진적 개선

🧠 각 전략의 특징

전략 장점 단점
Stuff 빠름, 간단 문서가 많으면 context overflow
MapReduce 안정적 처리 시간 오래 걸림
Refine 정교함 ↑ 불필요하게 verbose 해질 수 있음

📦 실습 전 준비: 공통 구성

from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
# ✅ 모델 및 벡터 저장소 구성
embedding = OpenAIEmbeddings()
vectordb = Chroma(
    persist_directory="./chroma_db",
    embedding_function=embedding,
    collection_name="iceberg_tables"
)
retriever = vectordb.as_retriever(search_kwargs={"k": 3})
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)

⚙️ 1. Stuff 전략: 문서를 전부 한 번에 전달

qa_stuff = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",                # 모든 문서를 연결해서 LLM에게 한 번에 전달
    retriever=retriever,
    return_source_documents=True
)

result = qa_stuff("테이블의 파티션 기준은 뭐야?")
print("📄 Stuff 응답:\n", result['result'])

✅ 빠르지만, 문서가 많으면 Token 초과로 에러 발생 가능


⚙️ 2. MapReduce 전략: 문서별 응답 → 요약 정리

qa_mapreduce = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="map_reduce",           # 각 문서마다 응답을 만든 뒤, 요약
    retriever=retriever,
    return_source_documents=True
)

result = qa_mapreduce("테이블의 파티션 기준은 뭐야?")
print("📄 MapReduce 응답:\n", result['result'])

✅ 각 문서의 정보를 분리해서 보고 요약하므로 LLM token overflow 위험 ↓
❗그러나 상대적으로 느릴 수 있음


⚙️ 3. Refine 전략: 응답을 점점 개선하며 완성

qa_refine = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="refine",               # 첫 문서로 응답 → 나머지 문서로 수정 보완
    retriever=retriever,
    return_source_documents=True
)

result = qa_refine("테이블의 파티션 기준은 뭐야?")
print("📄 Refine 응답:\n", result['result'])

✅ 초기 응답에 정보를 점점 덧붙여서 정확도 향상 가능
❗하지만 중복 표현이 많아지고 시간이 더 걸릴 수 있음


🔬 출력 비교 예시

💬 질문: "상품 테이블의 파티션 컬럼이 뭐야?"

  • Stuff: "category 컬럼으로 파티셔닝 되어 있습니다."
  • MapReduce: "products 테이블은 category 기준으로 파티션되며, 다른 테이블은 region을 기준으로 나뉩니다."
  • Refine: "초기에는 category가 파티션 기준입니다. 이후 다른 테이블은 region 등을 사용합니다."

✅ 언제 어떤 전략을 선택할까?

상황  추천 전략
문서 수가 적고 빠른 응답 필요 stuff
안정적 검색 + 문서 많음 map_reduce
신중하고 정교한 응답 필요 refine

📎 요약 및 핵심 정리

  • LangChain은 stuff, map_reduce, refine 전략을 통해 문서 응답 방식을 선택할 수 있습니다.
  • 각 전략은 처리 방식, 속도, 정확도, token 사용량 등에서 차이를 보입니다.
  • 실제 사용 시 목적과 상황에 따라 전략을 선택하는 것이 중요합니다.
728x90