LLM ๊ธฐ๋ฐ์ RAG(Retrieval-Augmented Generation) ์์คํ ์ ๊ตฌ์ถํ ๋, ๋ํ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ์ ์ฅํ๊ณ ๊ฒ์ํ๊ธฐ ์ํด ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค(Vector DB)๋ฅผ ์ฌ์ฉํ๋ค. ์ด๋ฒ ๊ธ์์๋ ChromaDB๋ฅผ ํ์ฉํ์ฌ ๋ฒกํฐ DB์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ๋ฐฉ๋ฒ์ ์ ๋ฆฌํ๋ค. ๐ญ๐ฉโ๐ป
RAG(Retrieval-Augmented Generation) ์์คํ ์ ๊ตฌ์ถํ๋ ค๋ฉด, ๊ฒ์ ์๋๋ฅผ ๋์ด๊ณ ํจ์จ์ ์ธ ๋ฌธ์ ๊ฒ์์ ์ํด ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค(Vector DB)๊ฐ ํ์๋ค.
โ ๋ฐ์ดํฐ ๊ท๋ชจ โ ๋๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋์ง
โ ๊ฒ์ ์ฑ๋ฅ โ ๋น ๋ฅธ ์ ์ฌ๋ ๊ฒ์์ด ๊ฐ๋ฅํ์ง
โ ํ์ฅ์ฑ โ ํด๋ผ์ฐ๋ ๋ฐฐํฌ์ ํ์ฅ์ด ๊ฐ๋ฅํ์ง
โ ํธํ์ฑ โ LangChain๊ณผ ๊ฐ์ ํ๋ ์์ํฌ์ ์ ํตํฉ๋๋์ง
๋ฐ์ดํฐ๋ฒ ์ด์ค | ํน์ง | ์ฅ์ | ๋จ์ |
---|---|---|---|
FAISS | Facebook AI ๊ฐ๋ฐ, ๋น ๋ฅธ ๊ทผ์ฌ ์ต๊ทผ์ ์ด์ ๊ฒ์ | ์คํ์์ค, ๋น ๋ฅธ ๊ฒ์ ์๋ | ํด๋ฌ์คํฐ๋ง ๊ธฐ๋ฅ ๋ถ์กฑ |
ChromaDB | LangChain๊ณผ ํธํ๋๋ ๋ฒกํฐDB | ๊ฐํธํ ์ฌ์ฉ, ์คํ์์ค | ๋๊ท๋ชจ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ํ๊ณ |
Pinecone | ํด๋ผ์ฐ๋ ๊ธฐ๋ฐ, AI ๊ฒ์ ์ต์ ํ | ํ์ฅ์ฑ ๋ฐ์ด๋จ | ์ ๋ฃ ๋ชจ๋ธ |
Elasticsearch | ํค์๋ + ๋ฒกํฐ ๊ฒ์ ์ง์ | ๋ณตํฉ ๊ฒ์ ๊ฐ๋ฅ | ์ค์ ์ด ๋ณต์ก |
๐ ๋ด๊ฐ ์ ํํ ๋ฐ์ดํฐ๋ฒ ์ด์ค: ChromaDB
โ ํ์ง๋ง ์ดํ ํ๋ก์ ํธ ํ์ฅ ์ ๋ค๋ฅธ DB๋ก ๊ต์ฒดํ ์๋ ์์
์ฐ์ ChromaDB๋ฅผ ์ฌ์ฉํ ์ค๋น๋ฅผ ํด์ผ ํ๋ค. ๋ฒกํฐํ๋ฅผ ์ํํ๊ธฐ ์ํด Ollama ์๋ฒ ๋ฉ ๋ชจ๋ธ์ ํ์ฉํ๋ฉฐ, ๋ฐ์ดํฐ ์ ์ฅ์ ์ํ ๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑํ๋ค.
# Chroma ๋ฒกํฐ DB ์ค์
CHROMA_DB_DIR = "vectorstore"
embeddings = OllamaEmbeddings(model="llama3.1-instruct-8b:latest")
os.makedirs(CHROMA_DB_DIR, exist_ok=True)
โ ์ค์ ์ด์
CHROMA_DB_DIR
: ๋ฒกํฐ DB ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋๋ ํ ๋ฆฌ ์์ฑOllamaEmbeddings
: ๋ฒกํฐํ๋ฅผ ์ํ ์๋ฒ ๋ฉ ๋ชจ๋ธ ์ง์ os.makedirs()
: ํด๋๊ฐ ์์ผ๋ฉด ์๋ ์์ฑ๋ฉ์์ง ๋ฐ์ดํฐ๋ฅผ ๋ฒกํฐํํ์ฌ ChromaDB์ ์ ์ฅํ๋ ํจ์๋ฅผ ๋ง๋ค์ด ๋ณด์.
# ๋ฒกํฐ DB ์ ์ฅ ํจ์
def save_to_vector_db(messages):
try:
# ChromaDB ์ธ์คํด์ค ์์ฑ
vector_db = Chroma(embedding_function=embeddings, persist_directory=CHROMA_DB_DIR)
# ๋ฉ์์ง๋ฅผ ํ๋์ ํ
์คํธ๋ก ๊ฒฐํฉํ์ฌ ๋ฒกํฐํ
combined_text = " ".join(messages)
vectors = embeddings.embed_documents([combined_text])
# ๊ณ ์ ID ์์ฑ (๋ฌธ์ ๋ด์ฉ์ ํด์๊ฐ ์ฌ์ฉ)
doc_id = str(hash(combined_text))
# Document ๊ฐ์ฒด ์์ฑ
document = Document(page_content=combined_text, metadata={"id": doc_id})
# ChromaDB์ ์ ์ฅ
vector_db.add_documents(
documents=[document],
embeddings=vectors,
ids=[doc_id]
)
logger.info("๋ฒกํฐ DB์ ๋ฉ์์ง ์ ์ฅ ์ฑ๊ณต")
except Exception as e:
logger.error(f"๋ฒกํฐ DB ์ ์ฅ ์ค ์ค๋ฅ ๋ฐ์: {e}")
โ ํต์ฌ ๊ฐ๋
๋ฐ์ดํฐ๊ฐ ์ ์์ ์ผ๋ก ์ ์ฅ๋์๋์ง ํ์ธํ๋ ๋ฐฉ๋ฒ์ด๋ค.
save_to_vector_db(input_data.messages) # ๋ฉ์์ง ์ ์ฅ ์คํ
๐ ์ ์ฅ๋ ๋ฐ์ดํฐ ํ์ธ ๋ฐฉ๋ฒ
logger.info(f"Document saved: {doc_id}, Message: {message}")
documents = vector_db.get()
logger.info(f"์ ์ฒด ์กฐํ: {documents}")
โ ๋ฒกํฐ DB ์กฐํ ๋ฐฉ๋ฒ
์ถํ ๊ฒ์๊ณผ ๊ด๋ฆฌ๋ฅผ ์ฉ์ดํ๊ฒ ํ๊ธฐ ์ํด, ๋ฌธ์ ํ์ (ํ ์คํธ, PDF, ์น ๋ฐ์ดํฐ ๋ฑ)์ ์ถ๊ฐํ์ฌ ์ ์ฅํ๋ ๊ฒ์ด ์ข๋ค.
# ๋ฉํ๋ฐ์ดํฐ ์ถ๊ฐ (๋ฌธ์ ํ์
๋ฐ ์ถ์ฒ)
metadata = {
"id": doc_id,
"type": document_type, # 'message', 'pdf', 'web'
"source": "user_input"
}
โ ๋ฉํ๋ฐ์ดํฐ ์ถ๊ฐ ์ด์
OCR๋ก ๋ณํ๋ ์ด๋ฏธ์ง ๋ฐ์ดํฐ๋ฅผ ๋ฒกํฐ DB์ ์ ์ฅํ ๊ฒฝ์ฐ, ์๋์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌ๋๋ค.
โ OCR ๋ฐ์ดํฐ ๊ด๋ฆฌ ๋ฐฉ์
FastAPI๋ฅผ ์ฌ์ฉํ์ฌ, ๋ฒกํฐ DB๋ฅผ ๋ํํ API์ ํตํฉํ ์ ์๋ค.
# ๋ฒกํฐ DB๋ฅผ FastAPI ์๋ํฌ์ธํธ์ ์ถ๊ฐ
async def chat(input: str = Form(...), file: Optional[UploadFile] = File(None), document_type: str = "message", vector_db: Chroma = Depends(get_vector_db)):
๐ FastAPI ์์กด์ฑ ์ฃผ์ (Dependency Injection)
# ๋ฒกํฐ DB ์ด๊ธฐํ ํจ์
def get_vector_db():
global vector_db
if vector_db is None:
vector_db = Chroma(embedding_function=embeddings, persist_directory=CHROMA_DB_DIR)
logger.info("๋ฒกํฐ DB ์ฐ๊ฒฐ ์๋ฃ")
return vector_db
โ ์ด์
โ ํ์ฌ๊น์ง ๊ตฌํ๋ ๊ธฐ๋ฅ
โ ๋ค์ ๋ชฉํ
โก ๋ค์ ๋จ๊ณ๋ก ๋์ด๊ฐ๋ฉด์ ์ต์ ํ ๋ฐ ๊ฒ์ ๊ธฐ๋ฅ์ ๊ฐํํด๋ณด์....!!