[LangChain] ๐ Ensemble Retriever๋ก RAG ๊ฒ์ ์ ํ๋ ๋์ด๊ธฐ: BM25 + Vector ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์
LangChain Ensemble Retriever๋ก BM25 ํค์๋ ๊ฒ์๊ณผ Vector ์๋ฏธ ๊ฒ์์ ๊ฒฐํฉํ๋ ํ์ด๋ธ๋ฆฌ๋ RAG ๊ตฌ์ถ ๋ฐฉ๋ฒ์ ์ ๋ฆฌํ์ต๋๋ค. RRF ์๊ณ ๋ฆฌ์ฆ, weights ์ค์ , ์ค๋ฌด ์ฝ๋ ์์๊น์ง ๋ค๋ฃน๋๋ค.
LangChain Ensemble Retriever๋ BM25 ํค์๋ ๊ฒ์๊ณผ Vector ์๋ฏธ ๊ฒ์์ ๊ฒฐํฉํ์ฌ ๋จ์ผ ๊ฒ์๊ธฐ๋ณด๋ค ๋์ ์ ํ๋๋ฅผ ์ ๊ณตํ๋ ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์ ๋ฐฉ์์ ๋๋ค. ๋ ๊ฒ์๊ธฐ์ ๊ฒฐ๊ณผ๋ฅผ RRF(Reciprocal Rank Fusion) ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ์ฌ์์ํํ์ฌ ์ต์ ์ ๋ฌธ์๋ฅผ ๋ฐํํฉ๋๋ค. ์ด ๊ธ์์๋ Ensemble Retriever์ ๋์ ์๋ฆฌ๋ถํฐ BM25 + FAISS ์กฐํฉ ์ฝ๋, weights ํ๋, ์ค๋ฌด ์ ์ฉ ํ๊น์ง ์ ๋ฆฌํฉ๋๋ค.
๐ค ์ ๋จ์ผ ๊ฒ์๊ธฐ๋ก๋ ๋ถ์กฑํ๊ฐ?
RAG(Retrieval-Augmented Generation) ์์คํ ์์ ๊ฒ์ ํ์ง์ LLM ๋ต๋ณ์ ํ์ง์ ์ง์ ๊ฒฐ์ ํฉ๋๋ค. ๊ทธ๋ฐ๋ฐ ํ์ฌ ๊ฐ์ฅ ๋ง์ด ์ฐ์ด๋ ๋ ๊ฐ์ง ๊ฒ์ ๋ฐฉ์์ ๊ฐ๊ฐ ๋๋ ทํ ํ๊ณ๊ฐ ์์ต๋๋ค.
Dense Retrieval (์๋ฏธ ๊ธฐ๋ฐ โ Vector Search)
์๋ฒ ๋ฉ ๋ฒกํฐ์ ์ฝ์ฌ์ธ ์ ์ฌ๋๋ก ์๋ฏธ์ ์ผ๋ก ์ ์ฌํ ๋ฌธ์๋ฅผ ์ฐพ์ต๋๋ค. ๋จ์ด๊ฐ ๋ฌ๋ผ๋ ์๋ฏธ๊ฐ ๊ฐ์ผ๋ฉด ๊ฒ์๋๋ ๊ฒ์ด ๊ฐ์ ์ด์ง๋ง, ์ ํํ ์ฉ์ดยท๊ณ ์ ๋ช ์ฌยท์ฝ๋ ์๋ณ์ ๊ฒ์์๋ ์ทจ์ฝํฉ๋๋ค.
Sparse Retrieval (ํค์๋ ๊ธฐ๋ฐ โ BM25)
๋จ์ด ๋น๋(TF-IDF ๊ธฐ๋ฐ BM25)๋ก ๋ฌธ์๋ฅผ ๊ฒ์ํฉ๋๋ค. โ์ฟ ๋ฒ๋คํฐ์คโ, โCVE-2024-1234โ ๊ฐ์ ์ ํํ ํค์๋ ์ผ์น์ ๊ฐํ์ง๋ง, ๋์์ดยท๋ฌธ๋งฅ ๊ธฐ๋ฐ ์ง๋ฌธ์๋ ์ฝํฉ๋๋ค.
| ๋ฐฉ์ | ๊ฐ์ | ์ฝ์ |
|---|---|---|
| Vector (Dense) | ์๋ฏธ ์ ์ฌ์ฑ, ๋์์ด, ๋งฅ๋ฝ ์ดํด | ์ ํํ ์ฉ์ดยท๊ณ ์ ๋ช ์ฌยท์ฝ๋ ๊ฒ์ |
| BM25 (Sparse) | ํค์๋ ์ ํ ์ผ์น, ๋๋ฉ์ธ ์ ๋ฌธ์ฉ์ด | ์คํ, ๋์์ด, ๋ฌธ๋งฅ ํ์ |
| Hybrid (Ensemble) | ๋ ๋ฐฉ์์ ์ฅ์ ๊ฒฐํฉ | ์ค์ ๋ณต์ก๋ ์ฆ๊ฐ |
Tip: ์ค๋ฌด์์๋ ๋ ๋ฐฉ์์ ๊ฒฐํฉํ ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์์ด ๋จ์ผ ๋ฐฉ์๋ณด๋ค ์ผ๊ด๋๊ฒ ๋ ๋์ ์ฑ๋ฅ์ ๋ณด์ ๋๋ค.
๐ Ensemble Retriever๋?
Ensemble Retriever๋ ์ฌ๋ฌ ๊ฒ์๊ธฐ์ ๊ฒฐ๊ณผ๋ฅผ RRF(Reciprocal Rank Fusion) ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๋ณํฉํ๋ LangChain ์ปดํฌ๋ํธ์ ๋๋ค.
1
2
3
4
5
6
7
์ฟผ๋ฆฌ
โโ BM25Retriever โ [๋ฌธ์A(1์), ๋ฌธ์C(2์), ๋ฌธ์E(3์), ...]
โโ FAISSRetriever โ [๋ฌธ์B(1์), ๋ฌธ์A(2์), ๋ฌธ์D(3์), ...]
โ
RRF ์ฌ์์ํ (weights ์ ์ฉ)
โ
์ต์ข
๊ฒฐ๊ณผ: [๋ฌธ์A, ๋ฌธ์B, ๋ฌธ์C, ...]
RRF ์๊ณ ๋ฆฌ์ฆ
RRF(Reciprocal Rank Fusion)๋ ๊ฐ ๊ฒ์๊ธฐ์์ ๋ฐํ๋ ๋ฌธ์์ ์์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ต์ข ์ ์๋ฅผ ๊ณ์ฐํฉ๋๋ค.
1
RRF ์ ์ = ฮฃ (weight_i / (rank_i + c))
rank_iโ ๊ฐ ๊ฒ์๊ธฐ์์์ ์์ (1๋ถํฐ ์์)weight_iโ ํด๋น ๊ฒ์๊ธฐ์ ๊ฐ์ค์นcโ ์์ (๊ธฐ๋ณธ๊ฐ 60, ๋์์๋ก ์์ ์ฐจ์ด ์ํ)
์์๋ง ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ์๋ก ๋ค๋ฅธ ์ ์ ์ค์ผ์ผ์ ๊ฐ์ง ๊ฒ์๊ธฐ๋ฅผ ์ง์ ๊ฒฐํฉํ ์ ์๋ค๋ ๊ฒ์ด ํต์ฌ ์ฅ์ ์ ๋๋ค.
๐ ์ค์น
1
pip install langchain langchain-community langchain-openai faiss-cpu rank_bm25
| ํจํค์ง | ์ฉ๋ |
|---|---|
langchain | ์ฝ์ด ํ๋ ์์ํฌ |
langchain-community | BM25Retriever, FAISS ๋ฑ ์ปค๋ฎค๋ํฐ ์ปดํฌ๋ํธ |
langchain-openai | OpenAI ์๋ฒ ๋ฉ |
faiss-cpu | Facebook AI ์ ์ฌ๋ ๊ฒ์ (GPU ๋ฒ์ : faiss-gpu) |
rank_bm25 | BM25 ์๊ณ ๋ฆฌ์ฆ ๊ตฌํ์ฒด |
1๏ธโฃ ๊ธฐ๋ณธ ์์ : BM25 + FAISS ๊ฒฐํฉ
๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์กฐํฉ์ธ BM25์ FAISS๋ฅผ ์ฌ์ฉํ Ensemble Retriever ๊ตฌ์ฑ์ ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
# ์ํ ๋ฌธ์
docs = [
Document(page_content="์ฟ ๋ฒ๋คํฐ์ค(Kubernetes)๋ ์ปจํ
์ด๋ ์ค์ผ์คํธ๋ ์ด์
ํ๋ซํผ์
๋๋ค."),
Document(page_content="Docker๋ ์ปจํ
์ด๋ ๊ธฐ๋ฐ ๊ฐ์ํ ๊ธฐ์ ๋ก ์ ํ๋ฆฌ์ผ์ด์
์ ํจํค์งํฉ๋๋ค."),
Document(page_content="Helm์ ์ฟ ๋ฒ๋คํฐ์ค ํจํค์ง ๋งค๋์ ๋ก ์ฐจํธ๋ฅผ ํตํด ๋ฐฐํฌ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค."),
Document(page_content="Prometheus๋ ์๊ณ์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ธฐ๋ฐ์ ๋ชจ๋ํฐ๋ง ์๋ฃจ์
์
๋๋ค."),
Document(page_content="Istio๋ ์๋น์ค ๋ฉ์๋ก ๋ง์ดํฌ๋ก์๋น์ค ๊ฐ ํต์ ์ ๊ด๋ฆฌํฉ๋๋ค."),
]
# BM25 ๋ฆฌํธ๋ฆฌ๋ฒ (ํค์๋ ๊ธฐ๋ฐ)
bm25_retriever = BM25Retriever.from_documents(docs)
bm25_retriever.k = 3 # ๋ฐํํ ๋ฌธ์ ์
# FAISS ๋ฆฌํธ๋ฆฌ๋ฒ (์๋ฏธ ๊ธฐ๋ฐ)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = FAISS.from_documents(docs, embeddings)
faiss_retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
# Ensemble Retriever ๊ตฌ์ฑ
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, faiss_retriever],
weights=[0.4, 0.6], # BM25 40%, FAISS 60%
)
# ๊ฒ์ ์คํ
results = ensemble_retriever.invoke("์ฟ ๋ฒ๋คํฐ์ค ํจํค์ง ๊ด๋ฆฌ ๋๊ตฌ๋?")
for doc in results:
print(doc.page_content)
2๏ธโฃ ์ค์ ์์ : RAG ํ์ดํ๋ผ์ธ์ ํตํฉ
๋ฌธ์ ๋ก๋ฉ๋ถํฐ LLM ๋ต๋ณ ์์ฑ๊น์ง ์ ์ฒด RAG ํ์ดํ๋ผ์ธ์ Ensemble Retriever๋ฅผ ํตํฉํฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import TextLoader
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
# 1. ๋ฌธ์ ๋ก๋ฉ ๋ฐ ๋ถํ
loader = TextLoader("knowledge_base.txt", encoding="utf-8")
raw_docs = loader.load()
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
)
docs = splitter.split_documents(raw_docs)
# 2. BM25 ๋ฆฌํธ๋ฆฌ๋ฒ
bm25_retriever = BM25Retriever.from_documents(docs)
bm25_retriever.k = 5
# 3. FAISS ๋ฒกํฐ์คํ ์ด
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = FAISS.from_documents(docs, embeddings)
faiss_retriever = vectorstore.as_retriever(
search_type="mmr", # ๋ค์์ฑ ํ๋ณด (Maximum Marginal Relevance)
search_kwargs={"k": 5, "fetch_k": 20, "lambda_mult": 0.7}
)
# 4. Ensemble Retriever
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, faiss_retriever],
weights=[0.3, 0.7],
)
# 5. RAG ์ฒด์ธ ๊ตฌ์ฑ
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=ensemble_retriever,
return_source_documents=True,
)
# 6. ์ง์
response = qa_chain.invoke({"query": "์๋น์ค ๋ฉ์์ ์ญํ ์ ๋ฌด์์ธ๊ฐ์?"})
print(response["result"])
print("\n--- ์ฐธ์กฐ ๋ฌธ์ ---")
for doc in response["source_documents"]:
print(f"- {doc.page_content[:100]}...")
3๏ธโฃ ChromaDB + BM25 ์กฐํฉ
FAISS ๋์ ChromaDB๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์ ๋๋ค. ์๊ตฌ ์ ์ฅ์ด ํ์ํ ํ๋ก๋์ ํ๊ฒฝ์ ์ ํฉํฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
# ChromaDB ๋ฒกํฐ์คํ ์ด ์์ฑ
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(
docs,
embeddings,
collection_name="my_collection",
persist_directory="./chroma_db", # ๋์คํฌ ์ ์ฅ
)
chroma_retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
# Ensemble ๊ตฌ์ฑ
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, chroma_retriever],
weights=[0.5, 0.5],
)
โ๏ธ weights ์ค์ ๊ฐ์ด๋
weights๋ ๊ฐ ๊ฒ์๊ธฐ๊ฐ ์ต์ข
์์์ ๋ฏธ์น๋ ์ํฅ๋ ฅ์ ์กฐ์ ํฉ๋๋ค. ํฉ๊ณ๊ฐ ๋ฐ๋์ 1.0์ผ ํ์๋ ์์ง๋ง, ์๋์ ๋น์จ๋ก ์ดํดํ๋ฉด ๋ฉ๋๋ค.
| ์ํฉ | ๊ถ์ฅ weights (BM25 : Vector) |
|---|---|
| ์ผ๋ฐ QA (๊ท ํ) | [0.5, 0.5] |
| ๊ธฐ์ ๋ฌธ์, ์ฝ๋, ์ ๋ฌธ์ฉ์ด | [0.6, 0.4] โ BM25 ๊ฐํ |
| ๊ณ ๊ฐ ์๋ด, ์์ฐ์ด ์ง๋ฌธ | [0.3, 0.7] โ Vector ๊ฐํ |
| ๋ด์คยท๋ธ๋ก๊ทธ ๋ฑ ์ผ๋ฐ ๋ฌธ์ | [0.4, 0.6] โ Vector ์ฝ๊ฐ ์ฐ์ธ |
| ๋ฒ๋ฅ ยท์๋ฃ ์ ๋ฌธ ๋๋ฉ์ธ | [0.7, 0.3] โ ์ ํํ ์ฉ์ด ์ฐ์ |
1
2
3
4
5
# ์ธ ๊ฐ์ ๊ฒ์๊ธฐ๋ฅผ ๊ฒฐํฉํ ์๋ ์์ต๋๋ค
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, faiss_retriever, chroma_retriever],
weights=[0.3, 0.4, 0.3],
)
Tip: weights๋ ๋๋ฉ์ธ๊ณผ ์ง์ ํจํด์ ๋ฐ๋ผ ๋ค๋ฅด๋ฏ๋ก, ํ๊ฐ ๋ฐ์ดํฐ์ ์ผ๋ก ์คํํ์ฌ ์ต์ ๊ฐ์ ์ฐพ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๐ ๋ค๋ฅธ ๋ค์ค ๊ฒ์๊ธฐ ์ ๋ต๊ณผ ๋น๊ต
Ensemble Retriever ์ธ์๋ LangChain์ด ์ ๊ณตํ๋ ๋ค์ค ๊ฒ์๊ธฐ ์ ๋ต๋ค์ด ์์ต๋๋ค.
| ์ ๋ต | ์ค๋ช | ์ ํฉํ ๊ฒฝ์ฐ |
|---|---|---|
| EnsembleRetriever | ์ฌ๋ฌ ๊ฒ์๊ธฐ ๊ฒฐ๊ณผ๋ฅผ RRF๋ก ๋ณํฉ | ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์์ ๊ธฐ๋ณธ |
| MultiQueryRetriever | ์ง๋ฌธ์ ์ฌ๋ฌ ๋ณํ์ผ๋ก ์ฌ์์ฑ ํ ๊ฒ์ | ๋ชจํธํ ์ง๋ฌธ, ๋ค๊ฐ๋ ๊ฒ์ |
| ContextualCompression | ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ LLM์ผ๋ก ์์ถยทํํฐ๋ง | ๋ถํ์ํ ์ ๋ณด ์ ๊ฑฐ |
| ParentDocumentRetriever | ์์ ์ฒญํฌ๋ก ๊ฒ์ ํ ์๋ณธ ์์ ๋ฌธ์ ๋ฐํ | ๋ฌธ๋งฅ ์์ค ๋ฐฉ์ง |
| SelfQueryRetriever | LLM์ด ๋ฉํ๋ฐ์ดํฐ ํํฐ๋ฅผ ์๋ ์์ฑ | ๊ตฌ์กฐํ๋ ํํฐ ์กฐ๊ฑด ์ฒ๋ฆฌ |
MultiQueryRetriever์ Ensemble ์กฐํฉ
1
2
3
4
5
6
7
8
9
10
11
12
13
from langchain.retrievers.multi_query import MultiQueryRetriever
# MultiQuery๋ก ์ง๋ฌธ์ ๋ค๊ฐ๋๋ก ํ์ฅ
multi_query_retriever = MultiQueryRetriever.from_llm(
retriever=faiss_retriever,
llm=ChatOpenAI(temperature=0),
)
# MultiQuery + BM25๋ฅผ Ensemble๋ก ๊ฒฐํฉ
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, multi_query_retriever],
weights=[0.4, 0.6],
)
๐๏ธ ํ๋ก๋์ ๊ณ ๋ ค์ฌํญ
์ฑ๋ฅ ์ต์ ํ
1
2
3
4
5
6
7
8
9
10
11
# FAISS ๊ฒ์ ํ์
๋ณ ํน์ฑ
faiss_retriever = vectorstore.as_retriever(
search_type="mmr", # ๋ค์์ฑ + ๊ด๋ จ์ฑ ๊ท ํ
# search_type="similarity", # ์์ ์ ์ฌ๋ (๊ธฐ๋ณธ๊ฐ)
# search_type="similarity_score_threshold", # ์ต์ ์ ์ ํํฐ
search_kwargs={
"k": 5,
"fetch_k": 20, # mmr์์ ํ๋ณด ํ ํฌ๊ธฐ
"lambda_mult": 0.5, # 0=๋ค์์ฑ ์ต๋, 1=์ ์ฌ๋ ์ต๋
}
)
๋์ฉ๋ ๋ฌธ์ ์ฒ๋ฆฌ
1
2
3
4
5
6
7
8
9
# BM25 ๋ฆฌํธ๋ฆฌ๋ฒ๋ฅผ ํ์ผ์์ ์ง์ ๋ก๋ฉ (๋ฉ๋ชจ๋ฆฌ ํจ์จ)
from langchain_community.retrievers import BM25Retriever
# ์ฒญํฌ ํฌ๊ธฐ๋ฅผ ๊ณ ๋ คํ k ์ค์
bm25_retriever = BM25Retriever.from_documents(
docs,
bm25_params={"k1": 1.5, "b": 0.75} # BM25 ํ์ดํผํ๋ผ๋ฏธํฐ ์กฐ์
)
bm25_retriever.k = 10
๊ฒ์ ๊ฒฐ๊ณผ ํ๊ฐ
1
2
3
4
5
6
7
8
9
10
11
12
# ๊ฒ์ ๊ฒฐ๊ณผ ํ์ง ๊ฐ๋จ ํ์ธ
def evaluate_retrieval(retriever, test_queries):
for query, expected_keyword in test_queries:
results = retriever.invoke(query)
hit = any(expected_keyword in doc.page_content for doc in results)
print(f"{'โ
' if hit else 'โ'} [{query}] โ {len(results)}๊ฐ ๋ฐํ")
test_cases = [
("์ฟ ๋ฒ๋คํฐ์ค ์ค์น ๋ฐฉ๋ฒ", "Kubernetes"),
("์ปจํ
์ด๋ ํจํค์ง", "Docker"),
]
evaluate_retrieval(ensemble_retriever, test_cases)
๐ก ์ค๋ฌด ์ ์ฉ ํ
BM25 ํ ํฌ๋์ด์ ์ปค์คํฐ๋ง์ด์ง โ ํ๊ตญ์ด ๋ฌธ์๋ ๊ธฐ๋ณธ ํ ํฌ๋์ด์ ๊ฐ ํํ์๋ฅผ ๊ณ ๋ คํ์ง ์์ ์ฑ๋ฅ์ด ๋จ์ด์ง ์ ์์ต๋๋ค. konlpy ๋ฑ์ ํ๊ตญ์ด ํํ์ ๋ถ์๊ธฐ๋ฅผ ์ ์ฒ๋ฆฌ ๋จ๊ณ์ ์ถ๊ฐํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
์ฒญํฌ ํฌ๊ธฐ์ k์ ๊ท ํ โ ์ฒญํฌ๊ฐ ์์์๋ก ๋ ๋ง์ k๊ฐ ํ์ํฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก 500~1000์ ์ฒญํฌ์ k=4~8์ด ์ ์ ํฉ๋๋ค.
์ค๋ณต ๋ฌธ์ ์ฒ๋ฆฌ โ ๋ ๊ฒ์๊ธฐ๊ฐ ๊ฐ์ ๋ฌธ์๋ฅผ ๋ฐํํ๋ฉด EnsembleRetriever๊ฐ ์๋์ผ๋ก ์ค๋ณต์ ์ ๊ฑฐํ๊ณ ์ ์๋ฅผ ํฉ์ฐํฉ๋๋ค.
์ ์ง์ ๋์
โ ๊ธฐ์กด Vector ๊ฒ์๋ง ์ฌ์ฉํ๋ ์์คํ
์ด๋ผ๋ฉด, weights=[0.2, 0.8]์ฒ๋ผ BM25 ๋น์ค์ ๋ฎ๊ฒ ์์ํ์ฌ ์ ์ง์ ์ผ๋ก ์กฐ์ ํ์ธ์.
โ ์์ฃผ ๋ฌป๋ ์ง๋ฌธ
Q. BM25Retriever์ EnsembleRetriever ์ค ๋ฌด์์ด ๋ ๋์๊ฐ์?
๋จ๋ ์ผ๋ก๋ ์ฐ์ด์ ๊ฐ๋ฆด ์ ์์ต๋๋ค. BM25๋ ํค์๋ ์ผ์น์ ๊ฐํ๊ณ , Vector๋ ์๋ฏธ ์ดํด์ ๊ฐํฉ๋๋ค. ๋๋ถ๋ถ์ ์ค๋ฌด RAG์์๋ ๋ ๋ฐฉ์์ ๊ฒฐํฉํ Ensemble์ด ๋จ์ผ ๋ฐฉ์๋ณด๋ค ์ผ๊ด๋๊ฒ ์ข์ ์ฑ๋ฅ์ ๋ณด์ ๋๋ค.
Q. weights ํฉ์ด ๋ฐ๋์ 1.0์ด์ด์ผ ํ๋์?
์๋๋๋ค. [0.4, 0.6]์ด๋ [2, 3]์ด๋ ์๋์ ๋น์จ๋ง ์ค์ํฉ๋๋ค. ๋ด๋ถ์ ์ผ๋ก ์ ๊ทํ๋ฉ๋๋ค.
Q. rank_bm25 ํจํค์ง ์์ด BM25Retriever๋ฅผ ์ธ ์ ์๋์?
์์ต๋๋ค. BM25Retriever๋ ๋ด๋ถ์ ์ผ๋ก rank_bm25๋ฅผ ์์กดํฉ๋๋ค. pip install rank_bm25๊ฐ ํ์์
๋๋ค.
Q. RRF์ c ํ๋ผ๋ฏธํฐ๋ ์ด๋ป๊ฒ ์กฐ์ ํ๋์?
ํ์ฌ LangChain์ EnsembleRetriever๋ c ํ๋ผ๋ฏธํฐ๋ฅผ ์ง์ ๋
ธ์ถํ์ง ์์ต๋๋ค. ๊ธฐ๋ณธ๊ฐ 60์ด ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์ ํฉํ๋ฉฐ, ์ปค์คํฐ๋ง์ด์ง์ด ํ์ํ๋ค๋ฉด ์์ค๋ฅผ ์์ํ์ฌ ์ค๋ฒ๋ผ์ด๋ํ ์ ์์ต๋๋ค.
Q. ํ๊ตญ์ด ๋ฌธ์์์ BM25 ์ฑ๋ฅ์ด ๋ฎ์ต๋๋ค.
ํ๊ตญ์ด๋ ํํ์ ๋ถ์ ์์ด ์ด์ ๋จ์๋ก ๋ถ๋ฆฌ๋๋ฉด ๊ฒ์ ์ ํ๋๊ฐ ๋ฎ์ต๋๋ค. konlpy์ Okt๋ Mecab์ผ๋ก ํํ์ ๋ถ์ ํ ํ ํฐ์ ์ง์ BM25์ ์ ๋ฌํ๋ฉด ์ฑ๋ฅ์ด ํฅ์๋ฉ๋๋ค.