Ver3.0 ๐ RAG ๊ตฌ์กฐ์ Pinecone ๋ฒกํฐDB ์ฐ๋ํ๊ธฐ: ์ค์ ๊ฐ์ด๋์ ์๋ฒฝ ๊ตฌํ๋ฒ

๐ RAG ๊ตฌ์กฐ์ Pinecone ๋ฒกํฐDB ์ฐ๋ํ๊ธฐ: ์ค์ ๊ฐ์ด๋์ ์๋ฒฝ ๊ตฌํ๋ฒ
AI ์๋์ ํ์ ๊ธฐ์ , ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ฒ์ ์ฆ๊ฐ ์์ฑ์ ๋ง์คํฐํ์!
์๋
! ๐ ์ค๋์ ์์ฆ AI ๊ฐ๋ฐ์๋ค ์ฌ์ด์์ ์ ๋ง ํซํ ์ฃผ์ ์ธ RAG(Retrieval-Augmented Generation)์ Pinecone ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๋์ ๋ํด ์ด์ผ๊ธฐํด๋ณผ๊ฒ.
์์งํ ๋งํ๋ฉด, ChatGPT ๊ฐ์ ๋ํ ์ธ์ด ๋ชจ๋ธ(LLM)์ด ์๋ฌด๋ฆฌ ๋๋ํด๋ ์ต์ ์ ๋ณด๋ ํน์ ๋๋ฉ์ธ ์ง์์๋ ํ๊ณ๊ฐ ์์์? ๐ค ๋ฐ๋ก ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๊ฒ RAG ๊ตฌ์กฐ์ผ. ๊ทธ๋ฆฌ๊ณ ์ด RAG๋ฅผ ์ ๋๋ก ๊ตฌํํ๋ ค๋ฉด ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ํ์์ธ๋ฐ, ๊ทธ ์ค์์๋ Pinecone์ด ์ ๋ง ๊ฐ๋ ฅํ ์ ํ์ง์ง!
๐ฏ RAG๊ฐ ๋ญ๊ธธ๋ ์ด๋ ๊ฒ ๋๋ฆฌ์ผ?
๋จผ์ RAG๊ฐ ์ ํํ ๋ญ์ง๋ถํฐ ์์๋ณด์. RAG(Retrieval-Augmented Generation)๋ ๋ง ๊ทธ๋๋ก "๊ฒ์์ผ๋ก ์ฆ๊ฐ๋ ์์ฑ" ๊ธฐ์ ์ด์ผ. ์ฝ๊ฒ ๋งํ๋ฉด, AI๊ฐ ๋ต๋ณ์ ์์ฑํ๊ธฐ ์ ์ ๊ด๋ จ ์ ๋ณด๋ฅผ ๋จผ์ ์ฐพ์๋ณด๊ณ , ๊ทธ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ๋ ์ ํํ ๋ต๋ณ์ ๋ง๋๋ ๊ฑฐ์ง. ๐
์๊ฐํด๋ด. ์ํ ๋ณผ ๋ ๊ต๊ณผ์ ๋ณด๋ฉด์ ๋ต ์ฐ๋ ๊ฒ๊ณผ ์๋ฌด๊ฒ๋ ์ ๋ณด๊ณ ๊ธฐ์ต๋ง์ผ๋ก ์ฐ๋ ๊ฒ ์ค ์ด๋ ๊ฒ ๋ ์ ํํ ๊น? ๋น์ฐํ ์ ์์ง! RAG๋ ๋๊ฐ์ ์๋ฆฌ์ผ.
์ ํต์ ์ธ LLM์ ๋ฌธ์ ์ ์ ์ด๋:
โ ํ์ต ๋ฐ์ดํฐ ์์ ์ ํ๊ณ
GPT-4๊ฐ ์๋ฌด๋ฆฌ ๋๋ํด๋ 2023๋
์ดํ ์ ๋ณด๋ ๋ชจ๋ฅด์์? ์ต์ ๋ด์ค๋ ์ค์๊ฐ ๋ฐ์ดํฐ๋ ๋ต๋ณ ๋ชป ํด.
โ ํ๊ฐ(Hallucination) ๋ฌธ์
๋ชจ๋ฅด๋ ๊ฑธ ๋ฌผ์ด๋ณด๋ฉด ๊ทธ๋ด๋ฏํ๊ฒ ๊ฑฐ์ง๋ง์ ์ง์ด๋ด๋ ๊ฒฝ์ฐ๊ฐ ์์ด. ์ด๊ฒ ์ง์ง ํฐ ๋ฌธ์ ์ผ. ๐
โ ๋๋ฉ์ธ ํนํ ์ง์ ๋ถ์กฑ
ํ์ฌ ๋ด๋ถ ๋ฌธ์, ์ ๋ฌธ ์๋ฃ ์ง์, ๋ฒ๋ฅ ์ ๋ณด ๊ฐ์ ํน์ํ ์์ญ์ ์ผ๋ฐ ๋ชจ๋ธ๋ก๋ ํ๊ณ๊ฐ ์์ง.
โ ์ถ์ฒ ์ถ์ ๋ถ๊ฐ
์ด๋์ ์ด ์ ๋ณด๋ฅผ ๊ฐ์ ธ์๋์ง ์ ์ ์์ด์ ์ ๋ขฐ์ฑ ๊ฒ์ฆ์ด ์ด๋ ค์.
RAG๋ ์ด ๋ชจ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด์ค! ๐ ์ธ๋ถ ์ง์ ๋ฒ ์ด์ค์์ ์ค์๊ฐ์ผ๋ก ์ ๋ณด๋ฅผ ๊ฐ์ ธ์์ ๋ต๋ณํ๋๊น ์ต์ ์ ๋ณด๋ OK, ์ถ์ฒ๋ ๋ช ํํ๊ณ , ํ๊ฐ ํ์๋ ๋ํญ ์ค์ด๋ค์ง.
๐ ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค, ์ ํ์ํ ๊ฑฐ์ผ?
์, ๊ทธ๋ผ ์ฌ๊ธฐ์ ์๋ฌธ์ด ์๊ธธ ๊ฑฐ์ผ. "๊ทธ๋ฅ ์ผ๋ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํ
์คํธ ์ ์ฅํ๊ณ ํค์๋ ๊ฒ์ํ๋ฉด ์ ๋ผ?" ๐ค
์ข์ ์ง๋ฌธ์ด์ผ! ํ์ง๋ง ์ ํต์ ์ธ ํค์๋ ๊ฒ์์ ํ๊ณ๊ฐ ๋ช
ํํด:
๐ค ์ ํต์ ํค์๋ ๊ฒ์
"๊ฐ์์ง ์ฌ๋ฃ ์ถ์ฒ" ๊ฒ์ ์
โ ์ ํํ "๊ฐ์์ง", "์ฌ๋ฃ", "์ถ์ฒ" ๋จ์ด๊ฐ ์๋ ๋ฌธ์๋ง ์ฐพ์
โ "๋ฐ๋ ค๊ฒฌ ๋จน์ด ์ ์"์ ๋ชป ์ฐพ์
โ ์๋ฏธ๋ ๊ฐ์๋ฐ ๋จ์ด๊ฐ ๋ค๋ฅด๋ฉด ๋์นจ ๐ข
๐ฏ ๋ฒกํฐ ์๋ฏธ ๊ฒ์
"๊ฐ์์ง ์ฌ๋ฃ ์ถ์ฒ" ๊ฒ์ ์
โ ์๋ฏธ์ ์ผ๋ก ์ ์ฌํ ๋ชจ๋ ๋ฌธ์ ์ฐพ์
โ "๋ฐ๋ ค๊ฒฌ ๋จน์ด ์ ์", "์ ๊ฒฌ ์๋จ ๊ฐ์ด๋" ๋ชจ๋ ์ฐพ์
โ ๋ฌธ๋งฅ๊ณผ ์๋ฏธ๋ฅผ ์ดํดํด์ ๊ฒ์ ๐
๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ํ
์คํธ๋ฅผ ๊ณ ์ฐจ์ ๋ฒกํฐ(์ซ์ ๋ฐฐ์ด)๋ก ๋ณํํด์ ์ ์ฅํด. ์๋ฅผ ๋ค์ด, "๊ฐ์์ง"๋ผ๋ ๋จ์ด๊ฐ [0.23, -0.45, 0.78, ...] ์ด๋ฐ ์์ผ๋ก ์๋ฐฑ~์์ฒ ๊ฐ์ ์ซ์๋ก ํํ๋๋ ๊ฑฐ์ง.
์ด๋ ๊ฒ ํ๋ฉด ๋ญ๊ฐ ์ข๋๊ณ ? ๋ฒกํฐ ๊ณต๊ฐ์์ ์ฝ์ฌ์ธ ์ ์ฌ๋(Cosine Similarity)๋ ์ ํด๋ฆฌ๋ ๊ฑฐ๋ฆฌ(Euclidean Distance) ๊ฐ์ ์ํ์ ๋ฐฉ๋ฒ์ผ๋ก "์๋ฏธ์ ์ ์ฌ์ฑ"์ ๊ณ์ฐํ ์ ์์ด! ๐งฎ
๐ก ์ค์ ํ
๋ฒกํฐ ์๋ฒ ๋ฉ์ OpenAI์ text-embedding-ada-002, Cohere์ embed ๋ชจ๋ธ, ๋๋ ์คํ์์ค์ธ sentence-transformers ๊ฐ์ ๊ฑธ ์ฌ์ฉํด. ๊ฐ๊ฐ ์ฅ๋จ์ ์ด ์์ผ๋ ํ๋ก์ ํธ ์๊ตฌ์ฌํญ์ ๋ง์ถฐ ์ ํํ๋ฉด ๋ผ!
๐ฒ Pinecone, ์ ์ ํํด์ผ ํ ๊น?
๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ฅ์๋ ์ฌ๋ฌ ์ ํ์ง๊ฐ ์์ด. Weaviate, Milvus, Qdrant, Chroma ๋ฑ๋ฑ... ๊ทธ๋ฐ๋ฐ ์ Pinecone์ผ๊น? ๐คทโโ๏ธ
์์งํ ๋งํ๋ฉด, Pinecone์ ์์ ๊ด๋ฆฌํ(Fully Managed) ์๋น์ค๋ผ๋ ๊ฒ ๊ฐ์ฅ ํฐ ์ฅ์ ์ด์ผ. ์ธํ๋ผ ๊ด๋ฆฌ, ์ค์ผ์ผ๋ง, ๋ฐฑ์
, ๋ชจ๋ํฐ๋ง ๊ฐ์ ๊ท์ฐฎ์ ๊ฒ๋ค์ Pinecone์ด ๋ค ์์์ ํด์ค. ๊ฐ๋ฐ์๋ ๊ทธ๋ฅ API ํธ์ถ๋ง ํ๋ฉด ๋! ๐
๐ Pinecone์ ํต์ฌ ์ฅ์
1๏ธโฃ ์ด๊ณ ์ ๊ฒ์ ์ฑ๋ฅ
์๋ฐฑ๋ง~์์ต ๊ฐ์ ๋ฒกํฐ์์ ๋ฐ๋ฆฌ์ด ๋จ์๋ก ๊ฒ์. HNSW(Hierarchical Navigable Small World) ์๊ณ ๋ฆฌ์ฆ ๊ธฐ๋ฐ์ผ๋ก ์ต์ ํ๋์ด ์์ด.
2๏ธโฃ ์๋ ์ค์ผ์ผ๋ง
ํธ๋ํฝ์ด ๊ฐ์๊ธฐ ํญ์ฆํด๋ ์๋์ผ๋ก ํ์ฅ. ๋ธ๋ํ๋ผ์ด๋ฐ์ด ๊ฐ์ ์ด๋ฒคํธ ๋๋ ๊ฑฑ์ ์์ง!
3๏ธโฃ ๋ฉํ๋ฐ์ดํฐ ํํฐ๋ง
๋ฒกํฐ ๊ฒ์๊ณผ ๋์์ ๋ฉํ๋ฐ์ดํฐ ์กฐ๊ฑด ํํฐ๋ง ๊ฐ๋ฅ. ์: "2023๋
์ดํ ์์ฑ๋ ๋ฌธ์ ์ค์์ ์ ์ฌํ ๊ฒ๋ง ์ฐพ๊ธฐ"
4๏ธโฃ ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์
๋ฒกํฐ ๊ฒ์๊ณผ ํค์๋ ๊ฒ์์ ๋์์ ์ํํ๋ ํ์ด๋ธ๋ฆฌ๋ ๋ชจ๋ ์ง์.
5๏ธโฃ ๊ฐํธํ ํตํฉ
LangChain, LlamaIndex ๊ฐ์ ์ฃผ์ RAG ํ๋ ์์ํฌ์ ๋ค์ดํฐ๋ธ ํตํฉ. Python, JavaScript, Go ๋ฑ ๋ค์ํ ์ธ์ด SDK ์ ๊ณต.
6๏ธโฃ ์ํฐํ๋ผ์ด์ฆ๊ธ ๋ณด์
SOC 2 Type II ์ธ์ฆ, ๋ฐ์ดํฐ ์ํธํ, VPC ํผ์ด๋ง, SSO ๋ฑ ๊ธฐ์
์ฉ ๋ณด์ ๊ธฐ๋ฅ ์๋น.
๋ฌผ๋ก ๋จ์ ๋ ์์ด. ๊ฐ๊ฒฉ์ด ์ข ๋น์ผ ํธ์ด๊ณ , ์์ ํ ์คํ์์ค๊ฐ ์๋๋ผ์ ๋ฒค๋ ์ข ์์ฑ์ด ์๊ธธ ์ ์์ง. ํ์ง๋ง ํ๋ก๋์ ํ๊ฒฝ์์ ์์ ์ฑ๊ณผ ์ฑ๋ฅ์ด ์ค์ํ๋ค๋ฉด Pinecone์ ์ ๋ง ํ๋ฅญํ ์ ํ์ด์ผ! ๐ช
๐ ๏ธ Pinecone ์์ํ๊ธฐ: ๊ณ์ ์ค์ ๋ถํฐ
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก ์ค์ ์ผ๋ก ๋ค์ด๊ฐ๋ณด์! ๋จผ์ Pinecone ๊ณ์ ์ ๋ง๋ค์ด์ผ ํด.
Step 1: ํ์๊ฐ์
pinecone.io์ ์ ์ํด์ "Start Free" ๋ฒํผ ํด๋ฆญ. ์ด๋ฉ์ผ๋ก ๊ฐ์
ํ๊ฑฐ๋ Google/GitHub ๊ณ์ ์ผ๋ก ๊ฐํธ ๊ฐ์
๊ฐ๋ฅํด. ๋ฌด๋ฃ ํ๋์ผ๋ก ์์ํ ์ ์์ผ๋ ๋ถ๋ด ์์ด ์์ํด๋ด! ๐
Step 2: API ํค ๋ฐ๊ธ
๋์๋ณด๋์ ๋ก๊ทธ์ธํ๋ฉด API Keys ๋ฉ๋ด๊ฐ ๋ณด์ผ ๊ฑฐ์ผ. ์ฌ๊ธฐ์ ์ API ํค๋ฅผ ์์ฑํ๋ฉด ๋ผ. ์ด ํค๋ ์ ๋ ๊ณต๊ฐํ๋ฉด ์ ๋ผ! ํ๊ฒฝ๋ณ์๋ ์ํฌ๋ฆฟ ๋งค๋์ ์ ์์ ํ๊ฒ ๋ณด๊ดํ์. ๐
โ ๏ธ ๋ณด์ ์ฃผ์์ฌํญ
API ํค๋ฅผ GitHub ๊ฐ์ ๊ณต๊ฐ ์ ์ฅ์์ ์ปค๋ฐํ์ง ๋ง! .env ํ์ผ์ ์ฌ์ฉํ๊ณ .gitignore์ ์ถ๊ฐํ๋ ๊ฑธ ์์ง ๋ง์. ์ค์๋ก ๋
ธ์ถ๋๋ฉด ์ฆ์ ํค๋ฅผ ์ฌ๋ฐ๊ธ๋ฐ์์ผ ํด.
Step 3: ์ธ๋ฑ์ค ์์ฑ
Pinecone์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ๋จ์๋ฅผ "์ธ๋ฑ์ค(Index)"๋ผ๊ณ ํด. ์ธ๋ฑ์ค๋ฅผ ๋ง๋ค ๋ ๋ช ๊ฐ์ง ์ค์ํ ์ค์ ์ด ์์ด:
๐ ์ธ๋ฑ์ค ์ค์ ํ๋ผ๋ฏธํฐ
โข dimension (์ฐจ์)
๋ฒกํฐ์ ์ฐจ์ ์. OpenAI ada-002๋ 1536์ฐจ์, Cohere embed-english-v3.0์ 1024์ฐจ์์ด์ผ. ์ฌ์ฉํ๋ ์๋ฒ ๋ฉ ๋ชจ๋ธ์ ๋ง์ถฐ ์ค์ ํด์ผ ํด!
โข metric (๊ฑฐ๋ฆฌ ์ธก์ ๋ฐฉ์)
- cosine: ์ฝ์ฌ์ธ ์ ์ฌ๋ (๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ, ์ถ์ฒ! โญ)
- euclidean: ์ ํด๋ฆฌ๋ ๊ฑฐ๋ฆฌ
- dotproduct: ๋ด์
โข pod_type (ํ ํ์
)
- s1: ์คํ ๋ค๋ (๋ฒ์ฉ, ๊ฐ์ฑ๋น ์ข์)
- p1: ํผํฌ๋จผ์ค (๊ณ ์ฑ๋ฅ, ๋์ฉ๋)
- p2: ํ๋ฆฌ๋ฏธ์ (์ต๊ณ ์ฑ๋ฅ)
โข replicas (๋ณต์ ๋ณธ ์)
๊ณ ๊ฐ์ฉ์ฑ์ ์ํ ๋ณต์ ๋ณธ ๊ฐ์. ํ๋ก๋์
์์๋ ์ต์ 2๊ฐ ์ด์ ๊ถ์ฅ.
๐ป Python์ผ๋ก Pinecone ์ฐ๋ํ๊ธฐ
์ด์ ์ฝ๋๋ก ๋ค์ด๊ฐ๋ณด์! Python์ด ๊ฐ์ฅ ๋ง์ด ์ฐ์ด๋๊น Python ์์ ๋ก ์ค๋ช ํ ๊ฒ. ๋จผ์ ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํ์:
pip install pinecone-client openai langchain tiktoken
๊ธฐ๋ณธ์ ์ธ Pinecone ์ฐ๊ฒฐ ์ฝ๋๋ ์ด๋ ๊ฒ ์๊ฒผ์ด:
import pinecone
import os
from openai import OpenAI
# ํ๊ฒฝ๋ณ์์์ API ํค ๋ก๋
PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")
PINECONE_ENV = os.getenv("PINECONE_ENVIRONMENT") # ์: "us-west1-gcp"
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
# Pinecone ์ด๊ธฐํ
pinecone.init(
api_key=PINECONE_API_KEY,
environment=PINECONE_ENV
)
# OpenAI ํด๋ผ์ด์ธํธ ์ด๊ธฐํ
openai_client = OpenAI(api_key=OPENAI_API_KEY)
# ์ธ๋ฑ์ค ์ด๋ฆ ์ค์
index_name = "my-rag-index"
# ์ธ๋ฑ์ค๊ฐ ์์ผ๋ฉด ์์ฑ
if index_name not in pinecone.list_indexes():
pinecone.create_index(
name=index_name,
dimension=1536, # OpenAI ada-002 ์๋ฒ ๋ฉ ์ฐจ์
metric="cosine",
pod_type="s1"
)
# ์ธ๋ฑ์ค ์ฐ๊ฒฐ
index = pinecone.Index(index_name)
์ฌ๊ธฐ๊น์ง ํ๋ฉด ๊ธฐ๋ณธ ์ค์ ์ ๋! ์ด์ ์ค์ ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ฃ๊ณ ๊ฒ์ํด๋ณด์. ๐ฏ
๐ RAG ํ์ดํ๋ผ์ธ ๊ตฌํ ๋จ๊ณ
1๋จ๊ณ: ํ
์คํธ๋ฅผ ๋ฒกํฐ๋ก ๋ณํ (์๋ฒ ๋ฉ)
OpenAI API๋ฅผ ์ฌ์ฉํด์ ํ
์คํธ๋ฅผ 1536์ฐจ์ ๋ฒกํฐ๋ก ๋ณํ
2๋จ๊ณ: Pinecone์ ๋ฒกํฐ ์ ์ฅ (์
์ํธ)
๋ณํ๋ ๋ฒกํฐ๋ฅผ ๋ฉํ๋ฐ์ดํฐ์ ํจ๊ป ์ธ๋ฑ์ค์ ์ ์ฅ
3๋จ๊ณ: ์ฟผ๋ฆฌ ๋ฒกํฐ ์์ฑ
์ฌ์ฉ์ ์ง๋ฌธ์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋ฒกํฐ๋ก ๋ณํ
4๋จ๊ณ: ์ ์ฌ ๋ฒกํฐ ๊ฒ์
Pinecone์์ ๊ฐ์ฅ ์ ์ฌํ ๋ฒกํฐ๋ค์ ์ฐพ์์ด
5๋จ๊ณ: ์ปจํ
์คํธ ๊ตฌ์ฑ ๋ฐ LLM ํธ์ถ
๊ฒ์๋ ๋ฌธ์๋ค์ ์ปจํ
์คํธ๋ก ์ฌ์ฉํด ์ต์ข
๋ต๋ณ ์์ฑ
์ค์ ๊ตฌํ ์ฝ๋๋ฅผ ๋ณด์:
def get_embedding(text, model="text-embedding-ada-002"):
"""ํ
์คํธ๋ฅผ ๋ฒกํฐ๋ก ๋ณํ"""
response = openai_client.embeddings.create(
input=text,
model=model
)
return response.data[0].embedding
def upsert_documents(documents):
"""๋ฌธ์๋ค์ Pinecone์ ์ ์ฅ"""
vectors = []
for i, doc in enumerate(documents):
# ์๋ฒ ๋ฉ ์์ฑ
embedding = get_embedding(doc['text'])
# ๋ฒกํฐ ๋ฐ์ดํฐ ๊ตฌ์ฑ
vector_data = {
'id': f"doc_{i}",
'values': embedding,
'metadata': {
'text': doc['text'],
'source': doc.get('source', 'unknown'),
'timestamp': doc.get('timestamp', '')
}
}
vectors.append(vector_data)
# Pinecone์ ๋ฐฐ์น ์
์ํธ (ํ ๋ฒ์ ์ต๋ 100๊ฐ)
batch_size = 100
for i in range(0, len(vectors), batch_size):
batch = vectors[i:i+batch_size]
index.upsert(vectors=batch)
print(f"โ
{len(documents)}๊ฐ ๋ฌธ์ ์ ์ฅ ์๋ฃ!")
# ์์ ๋ฌธ์๋ค
sample_docs = [
{
'text': 'Pinecone์ ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ๊ณ ์ ์ ์ฌ๋ ๊ฒ์์ ์ ๊ณตํฉ๋๋ค.',
'source': 'docs',
'timestamp': '2024-01-15'
},
{
'text': 'RAG๋ ๊ฒ์ ์ฆ๊ฐ ์์ฑ ๊ธฐ์ ๋ก LLM์ ํ๊ณ๋ฅผ ๊ทน๋ณตํฉ๋๋ค.',
'source': 'blog',
'timestamp': '2024-01-20'
},
{
'text': '์ฌ๋ฅ๋ท์ ๋ค์ํ AI ๊ฐ๋ฐ ์ฌ๋ฅ์ ๊ฑฐ๋ํ ์ ์๋ ํ๋ซํผ์
๋๋ค.',
'source': 'platform',
'timestamp': '2024-02-01'
}
]
# ๋ฌธ์ ์ ์ฅ
upsert_documents(sample_docs)
์ด์ ๊ฒ์ ๊ธฐ๋ฅ์ ๊ตฌํํด๋ณด์:
def search_similar_docs(query, top_k=3):
"""์ฟผ๋ฆฌ์ ์ ์ฌํ ๋ฌธ์ ๊ฒ์"""
# ์ฟผ๋ฆฌ๋ฅผ ๋ฒกํฐ๋ก ๋ณํ
query_embedding = get_embedding(query)
# Pinecone์์ ๊ฒ์
results = index.query(
vector=query_embedding,
top_k=top_k,
include_metadata=True
)
# ๊ฒฐ๊ณผ ํ์ฑ
similar_docs = []
for match in results['matches']:
similar_docs.append({
'text': match['metadata']['text'],
'score': match['score'],
'source': match['metadata']['source']
})
return similar_docs
# ๊ฒ์ ํ
์คํธ
query = "๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํด ์๋ ค์ค"
results = search_similar_docs(query)
print(f"๐ ๊ฒ์ ์ฟผ๋ฆฌ: {query}\n")
for i, doc in enumerate(results, 1):
print(f"{i}. [์ ์ฌ๋: {doc['score']:.4f}]")
print(f" {doc['text']}")
print(f" ์ถ์ฒ: {doc['source']}\n")
๋ง์ง๋ง์ผ๋ก ์ ์ฒด RAG ํ์ดํ๋ผ์ธ์ ์์ฑํด๋ณด์:
def rag_query(user_question, top_k=3):
"""RAG ๊ธฐ๋ฐ ์ง์์๋ต"""
# 1. ๊ด๋ จ ๋ฌธ์ ๊ฒ์
similar_docs = search_similar_docs(user_question, top_k)
# 2. ์ปจํ
์คํธ ๊ตฌ์ฑ
context = "\n\n".join([doc['text'] for doc in similar_docs])
# 3. ํ๋กฌํํธ ์์ฑ
prompt = f"""๋ค์ ์ปจํ
์คํธ๋ฅผ ์ฐธ๊ณ ํ์ฌ ์ง๋ฌธ์ ๋ต๋ณํด์ฃผ์ธ์.
์ปจํ
์คํธ:
{context}
์ง๋ฌธ: {user_question}
๋ต๋ณ:"""
# 4. LLM ํธ์ถ
response = openai_client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "๋น์ ์ ์น์ ํ AI ์ด์์คํดํธ์
๋๋ค. ์ฃผ์ด์ง ์ปจํ
์คํธ๋ฅผ ๋ฐํ์ผ๋ก ์ ํํ๊ฒ ๋ต๋ณํ์ธ์."},
{"role": "user", "content": prompt}
],
temperature=0.7,
max_tokens=500
)
answer = response.choices[0].message.content
# 5. ๊ฒฐ๊ณผ ๋ฐํ
return {
'answer': answer,
'sources': similar_docs
}
# RAG ์์คํ
ํ
์คํธ
question = "Pinecone์ ์ฅ์ ์ ๋ญ์ผ?"
result = rag_query(question)
print(f"โ ์ง๋ฌธ: {question}\n")
print(f"๐ก ๋ต๋ณ: {result['answer']}\n")
print("๐ ์ฐธ๊ณ ๋ฌธ์:")
for i, source in enumerate(result['sources'], 1):
print(f" {i}. {source['text'][:50]}... (์ ์ฌ๋: {source['score']:.4f})")
๐จ LangChain๊ณผ ํตํฉํ๊ธฐ
์์งํ ์์์ ๋ณธ ๊ฒ์ฒ๋ผ ์ง์ ๊ตฌํํ๋ ๊ฒ๋ ์ข์ง๋ง, LangChain์ ์ฌ์ฉํ๋ฉด ํจ์ฌ ๊ฐ๋จํด์ ธ! LangChain์ LLM ์ ํ๋ฆฌ์ผ์ด์
๊ฐ๋ฐ์ ์ํ ํ๋ ์์ํฌ์ธ๋ฐ, Pinecone๊ณผ์ ํตํฉ์ด ์ ๋ง ์ ๋์ด ์์ด. ๐
LangChain์ ์ฌ์ฉํ ๊ตฌํ์ ๋ณด์:
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Pinecone as LangchainPinecone
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.text_splitter import RecursiveCharacterTextSplitter
import pinecone
# Pinecone ์ด๊ธฐํ (์ด์ ๊ณผ ๋์ผ)
pinecone.init(
api_key=PINECONE_API_KEY,
environment=PINECONE_ENV
)
# ์๋ฒ ๋ฉ ๋ชจ๋ธ ์ค์
embeddings = OpenAIEmbeddings(
model="text-embedding-ada-002",
openai_api_key=OPENAI_API_KEY
)
# ํ
์คํธ ๋ถํ ๊ธฐ (๊ธด ๋ฌธ์๋ฅผ ์ฒญํฌ๋ก ๋๋๊ธฐ)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
length_function=len
)
# ์์ : ๊ธด ๋ฌธ์ ์ฒ๋ฆฌ
long_document = """
Pinecone์ 2019๋
์ ์ค๋ฆฝ๋ ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ์ฌ์
๋๋ค.
๋จธ์ ๋ฌ๋๊ณผ AI ์ ํ๋ฆฌ์ผ์ด์
์ ์ํ ๊ณ ์ฑ๋ฅ ๋ฒกํฐ ๊ฒ์ ์์ง์ ์ ๊ณตํฉ๋๋ค.
์ฃผ์ ํน์ง์ผ๋ก๋ ์ค์๊ฐ ์
๋ฐ์ดํธ, ์๋ ์ค์ผ์ผ๋ง, ๋ฉํ๋ฐ์ดํฐ ํํฐ๋ง ๋ฑ์ด ์์ต๋๋ค.
RAG ์์คํ
์์ Pinecone์ ์ฌ์ฉํ๋ฉด ์๋ฐฑ๋ง ๊ฐ์ ๋ฌธ์์์
๋ฐ๋ฆฌ์ด ๋จ์๋ก ๊ด๋ จ ์ ๋ณด๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
์ด๋ ChatGPT ๊ฐ์ LLM์ ํ๊ณ๋ฅผ ๊ทน๋ณตํ๋ ํต์ฌ ๊ธฐ์ ์
๋๋ค.
์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์๋ AI ๊ธฐ์ ๊ด๋ จ ์ฌ๋ฅ์ ๊ฑฐ๋ํ ์ ์์ด,
๊ฐ๋ฐ์๋ค์ด ์๋ก์ ์ ๋ฌธ์ฑ์ ๊ณต์ ํ๊ณ ๋ฐฐ์ธ ์ ์์ต๋๋ค.
"""
# ๋ฌธ์๋ฅผ ์ฒญํฌ๋ก ๋ถํ
chunks = text_splitter.split_text(long_document)
# LangChain Pinecone ๋ฒกํฐ์คํ ์ด ์์ฑ
vectorstore = LangchainPinecone.from_texts(
texts=chunks,
embedding=embeddings,
index_name=index_name
)
# LLM ์ค์
llm = ChatOpenAI(
model_name="gpt-4",
temperature=0.7,
openai_api_key=OPENAI_API_KEY
)
# RetrievalQA ์ฒด์ธ ์์ฑ
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff", # ๋ชจ๋ ๋ฌธ์๋ฅผ ํ ๋ฒ์ ์ ๋ฌ
retriever=vectorstore.as_retriever(
search_kwargs={"k": 3} # ์์ 3๊ฐ ๋ฌธ์ ๊ฒ์
),
return_source_documents=True
)
# ์ง์์๋ต ์คํ
query = "Pinecone์ ์ฃผ์ ํน์ง์ ๋ญ์ผ?"
result = qa_chain({"query": query})
print(f"โ ์ง๋ฌธ: {query}\n")
print(f"๐ก ๋ต๋ณ: {result['result']}\n")
print("๐ ์ฐธ๊ณ ๋ฌธ์:")
for i, doc in enumerate(result['source_documents'], 1):
print(f" {i}. {doc.page_content[:100]}...")
์์ฐ! ์ฝ๋๊ฐ ํจ์ฌ ๊ฐ๊ฒฐํด์ก์ง? ๐ LangChain์ด ๋ณต์กํ ๋ถ๋ถ๋ค์ ๋ค ์ถ์ํํด์ค์ ์ฐ๋ฆฌ๋ ๋น์ฆ๋์ค ๋ก์ง์๋ง ์ง์คํ ์ ์์ด.
LangChain์ ์ฅ์ ์ ์ ๋ฆฌํ๋ฉด:
โจ LangChain ์ฌ์ฉ์ ์ด์
โข ์ฒด์ธ ๊ตฌ์ฑ: ์ฌ๋ฌ ๋จ๊ณ๋ฅผ ์ฒด์ธ์ผ๋ก ์ฐ๊ฒฐํด์ ๋ณต์กํ ์ํฌํ๋ก์ฐ ๊ตฌํ
โข ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ: ๋ํ ํ์คํ ๋ฆฌ๋ฅผ ์๋์ผ๋ก ๊ด๋ฆฌ
โข ๋ค์ํ ํตํฉ: ์์ญ ๊ฐ์ LLM, ๋ฒกํฐDB, ๋๊ตฌ๋ค๊ณผ ์ฆ์ ์ฐ๋
โข ํ๋กฌํํธ ํ
ํ๋ฆฟ: ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ํ๋กฌํํธ ๊ด๋ฆฌ
โข ์์ด์ ํธ: ์์จ์ ์ผ๋ก ๋๊ตฌ๋ฅผ ์ ํํ๊ณ ์คํํ๋ AI ์์ด์ ํธ ๊ตฌ์ถ
โก ์ฑ๋ฅ ์ต์ ํ ํ
ํ๋ก๋์ ํ๊ฒฝ์์ RAG ์์คํ ์ ์ด์ํ๋ค ๋ณด๋ฉด ์ฑ๋ฅ์ด ์ ๋ง ์ค์ํด์ ธ. ๋ช ๊ฐ์ง ์ค์ ์ต์ ํ ํ์ ๊ณต์ ํ ๊ฒ! ๐
1๏ธโฃ ๋ฐฐ์น ์ฒ๋ฆฌ ํ์ฉ
ํ ๋ฒ์ ํ๋์ฉ ์๋ฒ ๋ฉํ์ง ๋ง๊ณ ๋ฐฐ์น๋ก ์ฒ๋ฆฌํ๋ฉด ์๋๊ฐ 10๋ฐฐ ์ด์ ๋นจ๋ผ์ ธ:
def batch_embed(texts, batch_size=100):
"""๋ฐฐ์น ๋จ์๋ก ์๋ฒ ๋ฉ ์์ฑ"""
all_embeddings = []
for i in range(0, len(texts), batch_size):
batch = texts[i:i+batch_size]
response = openai_client.embeddings.create(
input=batch,
model="text-embedding-ada-002"
)
embeddings = [item.embedding for item in response.data]
all_embeddings.extend(embeddings)
return all_embeddings
2๏ธโฃ ์บ์ฑ ์ ๋ต
์์ฃผ ๊ฒ์๋๋ ์ฟผ๋ฆฌ๋ ์บ์ฑํด์ Pinecone ํธ์ถ์ ์ค์ด์:
import redis
import json
import hashlib
redis_client = redis.Redis(host='localhost', port=6379, db=0)
def cached_search(query, top_k=3, ttl=3600):
"""์บ์๋ฅผ ํ์ฉํ ๊ฒ์"""
# ์ฟผ๋ฆฌ ํด์ ์์ฑ
cache_key = f"search:{hashlib.md5(query.encode()).hexdigest()}"
# ์บ์ ํ์ธ
cached = redis_client.get(cache_key)
if cached:
print("๐ฏ ์บ์ ํํธ!")
return json.loads(cached)
# ์บ์ ๋ฏธ์ค - ์ค์ ๊ฒ์
results = search_similar_docs(query, top_k)
# ์บ์ ์ ์ฅ
redis_client.setex(
cache_key,
ttl,
json.dumps(results)
)
return results
3๏ธโฃ ๋ฉํ๋ฐ์ดํฐ ํํฐ๋ง์ผ๋ก ๊ฒ์ ๋ฒ์ ์ถ์
์ ์ฒด ์ธ๋ฑ์ค๋ฅผ ๊ฒ์ํ์ง ๋ง๊ณ ๋ฉํ๋ฐ์ดํฐ๋ก ๋จผ์ ํํฐ๋ง:
def filtered_search(query, filters, top_k=3):
"""๋ฉํ๋ฐ์ดํฐ ํํฐ๋ง์ ํ์ฉํ ๊ฒ์"""
query_embedding = get_embedding(query)
results = index.query(
vector=query_embedding,
top_k=top_k,
include_metadata=True,
filter={
"source": {"$eq": filters.get("source")},
"timestamp": {"$gte": filters.get("start_date")}
}
)
return results
# ์ฌ์ฉ ์
results = filtered_search(
query="AI ๊ฐ๋ฐ ํ",
filters={
"source": "blog",
"start_date": "2024-01-01"
}
)
4๏ธโฃ ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์ (๋ฒกํฐ + ํค์๋)
Pinecone์ sparse-dense ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์์ ํ์ฉํ๋ฉด ์ ํ๋๊ฐ ์ฌ๋ผ๊ฐ:
from pinecone_text.sparse import BM25Encoder
# BM25 ์ธ์ฝ๋ ์ด๊ธฐํ (ํค์๋ ๊ฒ์์ฉ)
bm25 = BM25Encoder()
bm25.fit(corpus) # ๋ฌธ์ ์ฝํผ์ค๋ก ํ์ต
def hybrid_search(query, top_k=3, alpha=0.5):
"""๋ฒกํฐ + ํค์๋ ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์"""
# Dense ๋ฒกํฐ (์๋ฏธ ๊ฒ์)
dense_vec = get_embedding(query)
# Sparse ๋ฒกํฐ (ํค์๋ ๊ฒ์)
sparse_vec = bm25.encode_queries(query)
# ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์
results = index.query(
vector=dense_vec,
sparse_vector=sparse_vec,
top_k=top_k,
include_metadata=True
)
return results
๐ก ํ๋ก ํ
alpha ๊ฐ์ผ๋ก ๋ฒกํฐ ๊ฒ์๊ณผ ํค์๋ ๊ฒ์์ ๊ฐ์ค์น๋ฅผ ์กฐ์ ํ ์ ์์ด. 0.5๋ 50:50 ๋น์จ์ด๊ณ , 0.7์ด๋ฉด ๋ฒกํฐ ๊ฒ์์ ๋ ๊ฐ์ค์น๋ฅผ ๋๋ ๊ฑฐ์ผ. ๋๋ฉ์ธ์ ๋ฐ๋ผ ์ต์ ๊ฐ์ด ๋ค๋ฅด๋๊น ์คํํด๋ณด์!
5๏ธโฃ ์ฒญํฌ ํฌ๊ธฐ ์ต์ ํ
๋ฌธ์๋ฅผ ๋๋ฌด ์๊ฒ ๋๋๋ฉด ์ปจํ
์คํธ๊ฐ ๋ถ์กฑํ๊ณ , ๋๋ฌด ํฌ๊ฒ ๋๋๋ฉด ๊ด๋ จ ์๋ ์ ๋ณด๊ฐ ์์ฌ. ์ต์ ํฌ๊ธฐ๋ฅผ ์ฐพ์์ผ ํด:
๐ ์ฒญํฌ ํฌ๊ธฐ ๊ฐ์ด๋๋ผ์ธ
โข ์งง์ FAQ/Q&A: 200-400 ํ ํฐ
โข ์ผ๋ฐ ๋ฌธ์/๋ธ๋ก๊ทธ: 500-1000 ํ ํฐ
โข ๊ธฐ์ ๋ฌธ์/๋
ผ๋ฌธ: 1000-1500 ํ ํฐ
โข ์ฝ๋ ๋ฌธ์: ํจ์/ํด๋์ค ๋จ์๋ก ๋ถํ
์ค๋ฒ๋ฉ(overlap)์ ์ฒญํฌ ํฌ๊ธฐ์ 10-20% ์ ๋๊ฐ ์ ๋นํด. ๋ฌธ๋งฅ์ด ๋๊ธฐ๋ ๊ฑธ ๋ฐฉ์งํ ์ ์๊ฑฐ๋ !
๐ ํธ๋ฌ๋ธ์ํ : ์์ฃผ ๋ง๋๋ ๋ฌธ์ ๋ค
์ค์ ์์ ์์ฃผ ๊ฒช๋ ๋ฌธ์ ๋ค๊ณผ ํด๊ฒฐ๋ฒ์ ์ ๋ฆฌํด๋ดค์ด. ๋๋ ์ด๊ฑฐ ๋๋ฌธ์ ๋จธ๋ฆฌ ์์ฒญ ์ธ๋งธ๊ฑฐ๋ ... ๐
โ ๋ฌธ์ 1: "Dimension mismatch" ์๋ฌ
์ฆ์: ๋ฒกํฐ๋ฅผ ์
์ํธํ ๋ ์ฐจ์์ด ๋ง์ง ์๋๋ค๋ ์๋ฌ
์์ธ: ์ธ๋ฑ์ค ์์ฑ ์ ์ค์ ํ dimension๊ณผ ์ค์ ์๋ฒ ๋ฉ ์ฐจ์์ด ๋ค๋ฆ
ํด๊ฒฐ:
โข OpenAI ada-002: 1536์ฐจ์
โข OpenAI ada-001: 1024์ฐจ์
โข Cohere embed-english-v3.0: 1024์ฐจ์
โข sentence-transformers/all-MiniLM-L6-v2: 384์ฐจ์
์ธ๋ฑ์ค ์์ฑ ์ ์ ์ฌ์ฉํ ๋ชจ๋ธ์ ์ฐจ์์ ์ ํํ ํ์ธํ์!
โ ๋ฌธ์ 2: ๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์๋ฑํด์
์ฆ์: ์ฟผ๋ฆฌ์ ์ ํ ๊ด๋ จ ์๋ ๋ฌธ์๊ฐ ๊ฒ์๋จ
์์ธ:
1. ์๋ฒ ๋ฉ ๋ชจ๋ธ์ด ๋๋ฉ์ธ์ ๋ง์ง ์์
2. ๋ฉํ๋ฐ์ดํฐ๊ฐ ์ ๋๋ก ์ ์ฅ๋์ง ์์
3. ์ฟผ๋ฆฌ์ ๋ฌธ์์ ์๋ฒ ๋ฉ ๋ชจ๋ธ์ด ๋ค๋ฆ
ํด๊ฒฐ:
โข ์ฟผ๋ฆฌ์ ๋ฌธ์์ ๋์ผํ ์๋ฒ ๋ฉ ๋ชจ๋ธ ์ฌ์ฉ
โข ๋๋ฉ์ธ ํนํ ํ์ธํ๋ ๊ณ ๋ ค
โข ๊ฒ์ ๊ฒฐ๊ณผ์ score ๊ฐ ํ์ธ (0.7 ์ดํ๋ฉด ๊ด๋ จ์ฑ ๋ฎ์)
โ ๋ฌธ์ 3: ์๋๊ฐ ๋๋ฌด ๋๋ ค์
์ฆ์: ๊ฒ์์ ์ ์ด ์ด์ ๊ฑธ๋ฆผ
์์ธ:
1. ์ธ๋ฑ์ค๊ฐ ๋๋ฌด ํผ (์์ฒ๋ง ๊ฐ ์ด์)
2. ๋ฉํ๋ฐ์ดํฐ ํํฐ๋ง ์์ด ์ ์ฒด ๊ฒ์
3. Pod ํ์
์ด ๋ถ์ ์
ํด๊ฒฐ:
โข ๋ค์์คํ์ด์ค๋ก ์ธ๋ฑ์ค ๋ถํ
โข ๋ฉํ๋ฐ์ดํฐ ํํฐ๋ง ์ ๊ทน ํ์ฉ
โข p1/p2 pod๋ก ์
๊ทธ๋ ์ด๋
โข ์บ์ฑ ์ ๋ต ๋์
โ ๋ฌธ์ 4: ๋น์ฉ์ด ๋๋ฌด ๋ง์ด ๋์์
์ฆ์: ์ ์ฒญ๊ตฌ ๊ธ์ก์ด ์์๋ณด๋ค ๋์
์์ธ:
1. ๋ถํ์ํ ๋ณต์ ๋ณธ(replicas) ์ค์
2. ๊ณผ๋ํ pod ํ์
์ฌ์ฉ
3. ์๋ฒ ๋ฉ API ํธ์ถ ๊ณผ๋ค
ํด๊ฒฐ:
โข ๊ฐ๋ฐ ํ๊ฒฝ์ s1 pod, ๋ณต์ ๋ณธ 1๊ฐ๋ก ์ถฉ๋ถ
โข ์๋ฒ ๋ฉ ์บ์ฑ์ผ๋ก API ํธ์ถ ์ค์ด๊ธฐ
โข ๋ฐฐ์น ์ฒ๋ฆฌ๋ก ํจ์จ์ฑ ๋์ด๊ธฐ
โข ์ฌ์ฉํ์ง ์๋ ์ธ๋ฑ์ค๋ ์ญ์
๐ ์ค์ ํ๋ก์ ํธ ์์ด๋์ด
์ด๋ก ์ ์ถฉ๋ถํ ๋ฐฐ์ ์ผ๋ ์ด์ ์ค์ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์ด๋ณด์! ์ฌ๊ธฐ ๋ช ๊ฐ์ง ์ฌ๋ฏธ์๋ ์์ด๋์ด๋ฅผ ์๊ฐํ ๊ฒ. ๐ก
1๏ธโฃ ๊ฐ์ธ ์ง์ ๋ฒ ์ด์ค ์ฑ๋ด
๋
ธ์
, ๊ตฌ๊ธ ๋
์ค, PDF ํ์ผ ๋ฑ ๊ฐ์ธ ๋ฌธ์๋ค์ ๋ชจ๋ Pinecone์ ์ ์ฅํ๊ณ , ์์ ๋ง์ AI ์ด์์คํดํธ๋ฅผ ๋ง๋ค์ด๋ด. "์ง๋๋ฌ ํ์๋ก์์ ์์ฐ ๊ด๋ จ ๋ด์ฉ ์ฐพ์์ค" ๊ฐ์ ์ง๋ฌธ์ ์ฆ์ ๋ต๋ณ!
๊ธฐ์ ์คํ:
โข ๋ฌธ์ ํ์ฑ: PyPDF2, python-docx, notion-client
โข ์๋ฒ ๋ฉ: OpenAI ada-002
โข ๋ฒกํฐDB: Pinecone
โข ํ๋ก ํธ์๋: Streamlit ๋๋ Gradio
โข LLM: GPT-4 ๋๋ Claude
2๏ธโฃ ๊ธฐ์ ๋ธ๋ก๊ทธ ๊ฒ์ ์์ง
Medium, Dev.to, ๊ฐ์ธ ๋ธ๋ก๊ทธ ๋ฑ์์ ๊ธฐ์ ๊ธ๋ค์ ํฌ๋กค๋งํด์ ์๋ฏธ ๊ธฐ๋ฐ ๊ฒ์ ์์ง์ ๋ง๋ค์ด๋ด. "React ์ฑ๋ฅ ์ต์ ํ ๋ฐฉ๋ฒ"์ ๊ฒ์ํ๋ฉด ๊ด๋ จ๋ ๋ชจ๋ ๊ธ์ ์ฐพ์์ฃผ๋ ๊ฑฐ์ง!
์ถ๊ฐ ๊ธฐ๋ฅ:
โข ํ๊ทธ ๊ธฐ๋ฐ ํํฐ๋ง
โข ์์ฑ์ผ ๊ธฐ์ค ์ ๋ ฌ
โข ์ ์ฌ ๊ธ ์ถ์ฒ
โข ๋ถ๋งํฌ ๊ธฐ๋ฅ
3๏ธโฃ ๊ณ ๊ฐ ์ง์ ์๋ํ ์์คํ
ํ์ฌ์ FAQ, ์ ํ ๋งค๋ด์ผ, ์ด์ ๊ณ ๊ฐ ๋ฌธ์ ๋ด์ญ์ ํ์ต์์ผ์ ์๋ ์๋ต ์์คํ
์ ๊ตฌ์ถํด๋ด. ๊ณ ๊ฐ ๋ง์กฑ๋๋ ์ฌ๋ผ๊ฐ๊ณ ์๋ด์ ์
๋ฌด๋ ์ค์ด๋ค์ง!
ํต์ฌ ๊ธฐ๋ฅ:
โข ๋ค๊ตญ์ด ์ง์ (multilingual embedding)
โข ์ ๋ขฐ๋ ์ ์ ํ์
โข ์ฌ๋ ์๋ด์ ์์ค์ปฌ๋ ์ด์
โข ๋ํ ํ์คํ ๋ฆฌ ๊ด๋ฆฌ
4๏ธโฃ ์ฝ๋ ๊ฒ์ ๋์ฐ๋ฏธ
GitHub ๋ ํฌ์งํ ๋ฆฌ๋ ํ์ฌ ์ฝ๋๋ฒ ์ด์ค๋ฅผ ์ธ๋ฑ์ฑํด์ ์์ฐ์ด๋ก ์ฝ๋๋ฅผ ๊ฒ์ํ ์ ์๊ฒ ๋ง๋ค์ด๋ด. "JWT ํ ํฐ ๊ฒ์ฆํ๋ ํจ์ ์ด๋ ์์ง?"๋ผ๊ณ ๋ฌผ์ด๋ณด๋ฉด ๋ฐ๋ก ์ฐพ์์ฃผ๋ ๊ฑฐ์ผ!
ํน๋ณ ๊ณ ๋ ค์ฌํญ:
โข ์ฝ๋ ์ ์ฉ ์๋ฒ ๋ฉ ๋ชจ๋ธ ์ฌ์ฉ (์: CodeBERT)
โข ํจ์/ํด๋์ค ๋จ์๋ก ์ฒญํฌ ๋ถํ
โข ์ฃผ์๊ณผ docstring ํ์ฉ
โข ์ฝ๋ ์คํ ์์ ํฌํจ
์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ์ด๋ฐ ํ๋ก์ ํธ ๊ฒฝํ์ ๊ณต์ ํ๊ฑฐ๋, ๊ด๋ จ ๊ฐ๋ฐ ์ฌ๋ฅ์ ๊ฑฐ๋ํ ์๋ ์์ด. AI ๊ฐ๋ฐ์๋ค๋ผ๋ฆฌ ์๋ก ๋ฐฐ์ฐ๊ณ ์ฑ์ฅํ๋ ๊ฑฐ์ง! ๐ฑ
๐ ๋ณด์๊ณผ ํ๋ผ์ด๋ฒ์ ๊ณ ๋ ค์ฌํญ
RAG ์์คํ ์ ์ด์ํ ๋ ๋ณด์์ ์ ๋ง ์ค์ํด. ํนํ ๋ฏผ๊ฐํ ๊ธฐ์ ๋ฐ์ดํฐ๋ ๊ฐ์ธ์ ๋ณด๋ฅผ ๋ค๋ฃฌ๋ค๋ฉด ๋๋์ฑ! ๐
๐ก๏ธ ํ์ ๋ณด์ ์ฒดํฌ๋ฆฌ์คํธ
1. API ํค ๊ด๋ฆฌ
โข ํ๊ฒฝ๋ณ์ ์ฌ์ฉ (.env ํ์ผ)
โข AWS Secrets Manager, HashiCorp Vault ๊ฐ์ ์ํฌ๋ฆฟ ๊ด๋ฆฌ ๋๊ตฌ ํ์ฉ
โข ํค ๋กํ
์ด์
์ ์ฑ
์๋ฆฝ
โข ์ ๋ ์ฝ๋์ ํ๋์ฝ๋ฉ ๊ธ์ง!
2. ๋ฐ์ดํฐ ์ํธํ
โข ์ ์ก ์ค ์ํธํ (TLS/SSL)
โข ์ ์ฅ ์ ์ํธํ (Pinecone์ ๊ธฐ๋ณธ ์ ๊ณต)
โข ๋ฏผ๊ฐ ์ ๋ณด๋ ๋ง์คํน ์ฒ๋ฆฌ
3. ์ ๊ทผ ์ ์ด
โข ๋ค์์คํ์ด์ค๋ก ๋ฐ์ดํฐ ๊ฒฉ๋ฆฌ
โข ์ฌ์ฉ์๋ณ ๊ถํ ๊ด๋ฆฌ
โข IP ํ์ดํธ๋ฆฌ์คํธ ์ค์
โข VPC ํผ์ด๋ง (์ํฐํ๋ผ์ด์ฆ ํ๋)
4. ๊ฐ์ฌ ๋ก๊น
โข ๋ชจ๋ ์ฟผ๋ฆฌ ๋ก๊ทธ ๊ธฐ๋ก
โข ์ด์ ํจํด ๋ชจ๋ํฐ๋ง
โข ์ ๊ธฐ์ ์ธ ๋ณด์ ๊ฐ์ฌ
5. ๋ฐ์ดํฐ ์ต์ํ
โข ํ์ํ ์ ๋ณด๋ง ์ ์ฅ
โข ๊ฐ์ธ์๋ณ์ ๋ณด(PII) ์ ๊ฑฐ
โข ๋ฐ์ดํฐ ๋ณด๊ด ๊ธฐ๊ฐ ์ค์
โข ์ ๊ธฐ์ ์ธ ๋ฐ์ดํฐ ์ ๋ฆฌ
import os
from cryptography.fernet import Fernet
# ์ํธํ ํค ์์ฑ (ํ ๋ฒ๋ง ์คํ, ์์ ํ๊ฒ ๋ณด๊ด)
encryption_key = Fernet.generate_key()
cipher = Fernet(encryption_key)
def secure_upsert(documents, namespace="default"):
"""๋ฏผ๊ฐ ์ ๋ณด๋ฅผ ์ํธํํด์ ์ ์ฅ"""
vectors = []
for i, doc in enumerate(documents):
# ๋ฏผ๊ฐ ์ ๋ณด ๋ง์คํน
text = doc['text']
if 'email' in doc:
text = text.replace(doc['email'], '[EMAIL_MASKED]')
if 'phone' in doc:
text = text.replace(doc['phone'], '[PHONE_MASKED]')
# ์๋ฒ ๋ฉ ์์ฑ
embedding = get_embedding(text)
# ๋ฉํ๋ฐ์ดํฐ ์ํธํ (์ ํ์ )
encrypted_metadata = {
'text': cipher.encrypt(text.encode()).decode(),
'source': doc.get('source', 'unknown')
}
vectors.append({
'id': f"doc_{i}",
'values': embedding,
'metadata': encrypted_metadata
})
# ๋ค์์คํ์ด์ค๋ณ๋ก ๊ฒฉ๋ฆฌํด์ ์ ์ฅ
index.upsert(vectors=vectors, namespace=namespace)
def secure_search(query, namespace="default", user_role="user"):
"""๊ถํ ๊ธฐ๋ฐ ๊ฒ์"""
# ์ฌ์ฉ์ ๊ถํ ํ์ธ
if user_role not in ["admin", "user"]:
raise PermissionError("์ ๊ทผ ๊ถํ์ด ์์ต๋๋ค")
# ๊ฒ์ ์ํ
query_embedding = get_embedding(query)
results = index.query(
vector=query_embedding,
top_k=3,
namespace=namespace,
include_metadata=True
)
# ๊ฒฐ๊ณผ ๋ณตํธํ
decrypted_results = []
for match in results['matches']:
decrypted_text = cipher.decrypt(
match['metadata']['text'].encode()
).decode()
decrypted_results.append({
'text': decrypted_text,
'score': match['score']
})
# ๊ฐ์ฌ ๋ก๊ทธ ๊ธฐ๋ก
log_search_audit(query, user_role, namespace)
return decrypted_results
๐ ๋ชจ๋ํฐ๋ง๊ณผ ์ฑ๋ฅ ์ธก์
์์คํ ์ ๋ฐฐํฌํ ํ์๋ ์ง์์ ์ธ ๋ชจ๋ํฐ๋ง์ด ํ์์ผ. ๋ญ ์ธก์ ํด์ผ ํ ๊น? ๐
๐ ํต์ฌ ๋ฉํธ๋ฆญ
1. ๊ฒ์ ํ์ง ๋ฉํธ๋ฆญ
โข Precision@K: ์์ K๊ฐ ๊ฒฐ๊ณผ ์ค ๊ด๋ จ ๋ฌธ์ ๋น์จ
โข Recall@K: ์ ์ฒด ๊ด๋ จ ๋ฌธ์ ์ค ๊ฒ์๋ ๋น์จ
โข MRR (Mean Reciprocal Rank): ์ฒซ ๋ฒ์งธ ๊ด๋ จ ๊ฒฐ๊ณผ์ ์์
โข NDCG (Normalized Discounted Cumulative Gain): ์์ ํ์ง
2. ์ฑ๋ฅ ๋ฉํธ๋ฆญ
โข ํ๊ท ์๋ต ์๊ฐ
โข P95, P99 ๋ ์ดํด์
โข ์ฒ๋ฆฌ๋ (QPS - Queries Per Second)
โข ์๋ฒ ๋ฉ ์์ฑ ์๊ฐ
3. ๋น์ฆ๋์ค ๋ฉํธ๋ฆญ
โข ์ฌ์ฉ์ ๋ง์กฑ๋
โข ํด๋ฆญ๋ฅ (CTR)
โข ์ธ์
๋น ์ฟผ๋ฆฌ ์
โข ์ฌ๊ฒ์ ๋น์จ
4. ์์คํ
๋ฉํธ๋ฆญ
โข ์ธ๋ฑ์ค ํฌ๊ธฐ
โข ๋ฒกํฐ ๊ฐ์
โข API ํธ์ถ ํ์
โข ์๋ฌ์จ
import time
from datetime import datetime
import logging
# ๋ก๊น
์ค์
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('rag_system.log'),
logging.StreamHandler()
]
)
class RAGMonitor:
def __init__(self):
self.query_times = []
self.search_scores = []
self.error_count = 0
def log_query(self, query, results, elapsed_time):
"""์ฟผ๋ฆฌ ๋ก๊ทธ ๊ธฐ๋ก"""
logging.info(f"Query: {query}")
logging.info(f"Response time: {elapsed_time:.3f}s")
logging.info(f"Results count: {len(results)}")
self.query_times.append(elapsed_time)
if results:
avg_score = sum(r['score'] for r in results) / len(results)
self.search_scores.append(avg_score)
logging.info(f"Average relevance score: {avg_score:.4f}")
def log_error(self, error_type, error_msg):
"""์๋ฌ ๋ก๊ทธ"""
self.error_count += 1
logging.error(f"Error type: {error_type}")
logging.error(f"Error message: {error_msg}")
def get_stats(self):
"""ํต๊ณ ์กฐํ"""
if not self.query_times:
return "No data yet"
return {
'total_queries': len(self.query_times),
'avg_response_time': sum(self.query_times) / len(self.query_times),
'p95_response_time': sorted(self.query_times)[int(len(self.query_times) * 0.95)],
'avg_relevance_score': sum(self.search_scores) / len(self.search_scores) if self.search_scores else 0,
'error_count': self.error_count,
'error_rate': self.error_count / len(self.query_times) if self.query_times else 0
}
# ๋ชจ๋ํฐ ์ธ์คํด์ค ์์ฑ
monitor = RAGMonitor()
def monitored_rag_query(query):
"""๋ชจ๋ํฐ๋ง์ด ํฌํจ๋ RAG ์ฟผ๋ฆฌ"""
start_time = time.time()
try:
# RAG ๊ฒ์ ์ํ
results = rag_query(query)
# ์ฑ๋ฅ ์ธก์
elapsed_time = time.time() - start_time
# ๋ก๊ทธ ๊ธฐ๋ก
monitor.log_query(query, results['sources'], elapsed_time)
return results
except Exception as e:
monitor.log_error(type(e).__name__, str(e))
raise
# ์ฃผ๊ธฐ์ ์ผ๋ก ํต๊ณ ์ถ๋ ฅ
import schedule
def print_stats():
stats = monitor.get_stats()
print("\n๐ ์์คํ
ํต๊ณ:")
for key, value in stats.items():
print(f" {key}: {value}")
schedule.every(1).hours.do(print_stats)
๐ ํ๋ก๋์ ๋ฐฐํฌ ๊ฐ์ด๋
๊ฐ๋ฐ ํ๊ฒฝ์์ ์ ๋์๊ฐ๋ค๊ณ ๋์ด ์๋์ผ. ํ๋ก๋์ ๋ฐฐํฌ๋ ๋ ๋ค๋ฅธ ์ธ๊ณ์ง! ๐
๋ฐฐํฌ ์ ์ฒดํฌ๋ฆฌ์คํธ
โ
์ธํ๋ผ ์ค๋น
โข Pinecone ํ๋ก๋์
ํ๋ ๊ตฌ๋
โข ์ถฉ๋ถํ pod ์ฉ๋ ํ๋ณด
โข ๋ณต์ ๋ณธ(replicas) ์ต์ 2๊ฐ ์ด์
โข ๋ฐฑ์
์ ๋ต ์๋ฆฝ
โ
์ฝ๋ ์ต์ ํ
โข ๋ฐฐ์น ์ฒ๋ฆฌ ๊ตฌํ
โข ์บ์ฑ ๋ ์ด์ด ์ถ๊ฐ
โข ์๋ฌ ํธ๋ค๋ง ๊ฐํ
โข ํ์์์ ์ค์
โ
๋ชจ๋ํฐ๋ง ์ค์
โข ๋ก๊น
์์คํ
๊ตฌ์ถ
โข ์๋ฆผ ์ค์ (Slack, PagerDuty ๋ฑ)
โข ๋์๋ณด๋ ๊ตฌ์ฑ (Grafana, Datadog ๋ฑ)
โ
๋ณด์ ๊ฐํ
โข API ํค ์ํฌ๋ฆฟ ๊ด๋ฆฌ
โข HTTPS ์ ์ฉ
โข Rate limiting ์ค์
โข ์
๋ ฅ ๊ฒ์ฆ ๋ฐ ์๋ํ์ด์ง
โ
ํ
์คํธ
โข ๋จ์ ํ
์คํธ
โข ํตํฉ ํ
์คํธ
โข ๋ถํ ํ
์คํธ
โข ์ฅ์ ์๋๋ฆฌ์ค ํ
์คํธ
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
# ์์กด์ฑ ์ค์น
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# ์ ํ๋ฆฌ์ผ์ด์
์ฝ๋ ๋ณต์ฌ
COPY . .
# ํ๊ฒฝ๋ณ์ ์ค์
ENV PYTHONUNBUFFERED=1
# ํฌ์ค์ฒดํฌ
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD python -c "import requests; requests.get('http://localhost:8000/health')"
# ์คํ
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: rag-service
spec:
replicas: 3
selector:
matchLabels:
app: rag-service
template:
metadata:
labels:
app: rag-service
spec:
containers:
- name: rag-service
image: your-registry/rag-service:latest
ports:
- containerPort: 8000
env:
- name: PINECONE_API_KEY
valueFrom:
secretKeyRef:
name: pinecone-secret
key: api-key
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: openai-secret
key: api-key
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
๐ฐ ๋น์ฉ ์ต์ ํ ์ ๋ต
RAG ์์คํ ์ ์ด์ํ๋ค ๋ณด๋ฉด ๋น์ฉ์ด ๋ง๋ง์น ์์. ํนํ ์๋ฒ ๋ฉ API ํธ์ถ๊ณผ Pinecone ์ฌ์ฉ๋ฃ๊ฐ ์ฃผ์ ๋น์ฉ์ด์ง. ํ๋ช ํ๊ฒ ์ ์ฝํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์! ๐ธ
๐ก ๋น์ฉ ์ ๊ฐ ํ
1. ์๋ฒ ๋ฉ ๋น์ฉ ์ค์ด๊ธฐ
โข ์บ์ฑ: ๋์ผํ ํ
์คํธ๋ ์ฌ์ฌ์ฉ
โข ๋ฐฐ์น ์ฒ๋ฆฌ: ํ ๋ฒ์ ์ฌ๋ฌ ๊ฐ ์ฒ๋ฆฌ
โข ์คํ์์ค ๋ชจ๋ธ ๊ณ ๋ ค: sentence-transformers๋ ๋ฌด๋ฃ!
โข ์ฒญํฌ ํฌ๊ธฐ ์ต์ ํ: ๋ถํ์ํ๊ฒ ์๊ฒ ๋๋์ง ๋ง๊ธฐ
2. Pinecone ๋น์ฉ ์ค์ด๊ธฐ
โข ๊ฐ๋ฐ/์คํ
์ด์ง์ s1 pod ์ฌ์ฉ
โข ๋ค์์คํ์ด์ค๋ก ์ธ๋ฑ์ค ๊ณต์
โข ์ฌ์ฉํ์ง ์๋ ์ธ๋ฑ์ค ์ญ์
โข ๋ฉํ๋ฐ์ดํฐ ํฌ๊ธฐ ์ต์ํ
3. LLM ๋น์ฉ ์ค์ด๊ธฐ
โข ์ปจํ
์คํธ ๊ธธ์ด ์ต์ ํ
โข ์บ์ฑ์ผ๋ก ์ค๋ณต ํธ์ถ ๋ฐฉ์ง
โข ์ ๋ ดํ ๋ชจ๋ธ ํ์ฉ (GPT-3.5 vs GPT-4)
โข ์คํธ๋ฆฌ๋ฐ์ผ๋ก ์ฌ์ฉ์ ๊ฒฝํ ๊ฐ์
์์ ๋น์ฉ (์ ๊ธฐ์ค)
โข Pinecone s1 pod (1๊ฐ): $70
โข OpenAI ada-002 (100๋ง ํ ํฐ): $0.10
โข GPT-4 (100๋ง ํ ํฐ): $30
โข ์ด ์์: $100-200 (์๊ท๋ชจ ์๋น์ค ๊ธฐ์ค)
๐ก ํ๋ก ํ: ํ์ด๋ธ๋ฆฌ๋ ์ ๋ต
์์ฃผ ๋ฌป๋ ์ง๋ฌธ(FAQ)์ ๋ฏธ๋ฆฌ ๋ต๋ณ์ ์บ์ฑํด๋๊ณ , ์๋ก์ด ์ง๋ฌธ๋ง RAG๋ก ์ฒ๋ฆฌํ๋ฉด ๋น์ฉ์ 50% ์ด์ ์ค์ผ ์ ์์ด!
๐ฎ ๋ฏธ๋ ์ ๋ง๊ณผ ๋ฐ์ ๋ฐฉํฅ
RAG ๊ธฐ์ ์ ์ง๊ธ๋ ๋น ๋ฅด๊ฒ ๋ฐ์ ํ๊ณ ์์ด. ์์ผ๋ก ์ด๋ค ๋ณํ๊ฐ ์ฌ๊น? ๐
๐ ์ฃผ๋ชฉํ ํธ๋ ๋
1. ๋ฉํฐ๋ชจ๋ฌ RAG
ํ
์คํธ๋ฟ๋ง ์๋๋ผ ์ด๋ฏธ์ง, ์ค๋์ค, ๋น๋์ค๊น์ง ํตํฉ ๊ฒ์. CLIP, ImageBind ๊ฐ์ ๋ชจ๋ธ์ด ์ด๋ฏธ ๋์์ด!
2. ๊ทธ๋ํ RAG
์ง์ ๊ทธ๋ํ์ ๋ฒกํฐ ๊ฒ์์ ๊ฒฐํฉํด์ ๋ ์ ๊ตํ ์ถ๋ก ๊ฐ๋ฅ. Microsoft์ GraphRAG๊ฐ ๋ํ์ ์ด์ผ.
3. ์์ด์ ํธ ๊ธฐ๋ฐ RAG
AI ์์ด์ ํธ๊ฐ ์์จ์ ์ผ๋ก ์ฌ๋ฌ ์์ค๋ฅผ ๊ฒ์ํ๊ณ ์ข
ํฉ. LangChain Agents, AutoGPT ๊ฐ์ ํ๋ ์์ํฌ๊ฐ ๋ฐ์ ์ค.
4. ์ค์๊ฐ RAG
์คํธ๋ฆฌ๋ฐ ๋ฐ์ดํฐ๋ฅผ ์ค์๊ฐ์ผ๋ก ์ธ๋ฑ์ฑํ๊ณ ๊ฒ์. ๋ด์ค, ์์
๋ฏธ๋์ด ๊ฐ์ ์ค์๊ฐ ์ ๋ณด ํ์ฉ.
5. ํ๋ผ์ด๋ฒ์ ๋ณด์กด RAG
์ฐํฉ ํ์ต(Federated Learning), ๋ํ ์ํธํ(Homomorphic Encryption)๋ก ๋ฐ์ดํฐ ํ๋ผ์ด๋ฒ์ ๋ณด์ฅ.
6. ๊ฒฝ๋ํ ๋ฐ ์ฃ์ง ๋ฐฐํฌ
๋ชจ๋ฐ์ผ, IoT ๊ธฐ๊ธฐ์์๋ RAG ์คํ ๊ฐ๋ฅํ๋๋ก ๋ชจ๋ธ ๊ฒฝ๋ํ. Quantization, Distillation ๊ธฐ์ ํ์ฉ.
ํนํ ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์๋ ์ด๋ฐ ์ต์ ๊ธฐ์ ์ ํ์ฉํ ํ๋ก์ ํธ๋ค์ด ๋ง์ด ๊ฑฐ๋๋ ๊ฑฐ์ผ. AI ๊ฐ๋ฐ์๋ก์ ๊ณ์ ํ์ตํ๊ณ ์คํํ๋ ๊ฒ ์ค์ํด! ๐
๐ ํ์ต ๋ฆฌ์์ค ์ถ์ฒ
๋ ๊น์ด ๊ณต๋ถํ๊ณ ์ถ๋ค๋ฉด ์ด๋ฐ ์๋ฃ๋ค์ ์ถ์ฒํด:
๐ ๊ณต์ ๋ฌธ์
โข Pinecone Docs: docs.pinecone.io
โข LangChain Docs: python.langchain.com
โข OpenAI Cookbook: cookbook.openai.com
๐ฅ ์จ๋ผ์ธ ๊ฐ์
โข DeepLearning.AI - LangChain for LLM Application Development
โข Coursera - Natural Language Processing Specialization
โข YouTube - Pinecone ๊ณต์ ์ฑ๋
๐ ๋
ผ๋ฌธ
โข "Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks" (Facebook AI, 2020)
โข "Dense Passage Retrieval for Open-Domain Question Answering" (Facebook AI, 2020)
โข "REALM: Retrieval-Augmented Language Model Pre-Training" (Google, 2020)
๐ป GitHub ๋ ํฌ
โข langchain-ai/langchain
โข pinecone-io/examples
โข openai/openai-cookbook
๐ฅ ์ปค๋ฎค๋ํฐ
โข LangChain Discord
โข Pinecone Community Forum
โข Reddit r/MachineLearning
โข ์ฌ๋ฅ๋ท AI/๋จธ์ ๋ฌ๋ ์นดํ
๊ณ ๋ฆฌ
๐ฏ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
์, ์ฌ๊ธฐ๊น์ง ์ ๋ง ๊ธด ์ฌ์ ์ด์์ด! ๐ RAG ๊ตฌ์กฐ์ Pinecone ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๋์ ๋ํด ์ฒ์๋ถํฐ ๋๊น์ง ์ดํด๋ดค์ง.
ํต์ฌ์ ๋ค์ ์ ๋ฆฌํ๋ฉด:
๐ ํต์ฌ ์์ฝ
1๏ธโฃ RAG๋ LLM์ ํ๊ณ๋ฅผ ๊ทน๋ณตํ๋ ํต์ฌ ๊ธฐ์
์ต์ ์ ๋ณด, ๋๋ฉ์ธ ์ง์, ์ถ์ฒ ์ถ์ ์ด ๊ฐ๋ฅํด์ ธ
2๏ธโฃ Pinecone์ ํ๋ก๋์
๊ธ ๋ฒกํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค
์์ ๊ด๋ฆฌํ, ๊ณ ์ฑ๋ฅ, ์ฌ์ด ํตํฉ์ด ์ฅ์
3๏ธโฃ ๊ตฌํ์ 5๋จ๊ณ
๋ฐ์ดํฐ ์์ง โ ์ ์ฒ๋ฆฌ โ ์๋ฒ ๋ฉ โ Pinecone ์ ์ฅ โ RAG ์ฟผ๋ฆฌ
4๏ธโฃ LangChain์ผ๋ก ๋ ์ฝ๊ฒ
ํ๋ ์์ํฌ๋ฅผ ํ์ฉํ๋ฉด ๊ฐ๋ฐ ์๊ฐ ๋ํญ ๋จ์ถ
5๏ธโฃ ์ฑ๋ฅ, ๋ณด์, ๋น์ฉ ์ต์ ํ๊ฐ ์ค์
๋ฐฐ์น ์ฒ๋ฆฌ, ์บ์ฑ, ๋ชจ๋ํฐ๋ง์ ํ์
6๏ธโฃ ๊ณ์ ๋ฐ์ ํ๋ ๋ถ์ผ
๋ฉํฐ๋ชจ๋ฌ, ๊ทธ๋ํ, ์์ด์ ํธ ๊ธฐ๋ฐ RAG๊ฐ ๋ฏธ๋
์ด์ ๋น์ ๋ RAG ์์คํ
์ ๊ตฌ์ถํ ์ค๋น๊ฐ ๋์ด! ์ฒ์์ ์์ ํ๋ก์ ํธ๋ก ์์ํด์ ์ ์ ํ์ฅํด๋๊ฐ๋ฉด ๋ผ. ์คํจ๋ฅผ ๋๋ ค์ํ์ง ๋ง๊ณ ๊ณ์ ์คํํ๊ณ ๋ฐฐ์ฐ์. ๐ช
์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ๋ค๋ฅธ ๊ฐ๋ฐ์๋ค๊ณผ ๊ฒฝํ์ ๊ณต์ ํ๊ณ , ์๋ก ๋ฐฐ์ฐ๋ฉด์ ์ฑ์ฅํ๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ. AI ๊ฐ๋ฐ์ ํผ์ ํ๋ ๊ฒ ์๋๋ผ ์ปค๋ฎค๋ํฐ์ ํจ๊ป ํ๋ ๊ฑฐ๋๊น! ๐
๊ถ๊ธํ ์ ์ด ์๊ฑฐ๋ ๋งํ๋ ๋ถ๋ถ์ด ์์ผ๋ฉด ์ธ์ ๋ ์ปค๋ฎค๋ํฐ์ ๋ฌผ์ด๋ด. ์ฐ๋ฆฌ ๋ชจ๋ ์ฒ์์ ์ด๋ณด์๊ณ , ์๋ก ๋์ฐ๋ฉด์ ์ฑ์ฅํ๊ฑฐ๋ . ํ์ดํ
! ๐โจ
๐ ์ด ๊ธ์ด ๋์์ด ๋์๋ค๋ฉด ์ฌ๋ฅ๋ท์์ ๋ ๋ง์ AI ์ง์์ ํํํด๋ณด์ธ์!
ํจ๊ป ๋ฐฐ์ฐ๊ณ ์ฑ์ฅํ๋ ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ๊ฐ ๊ธฐ๋ค๋ฆฌ๊ณ ์์ด์ ๐ฑ
๊ด๋ จ ํค์๋
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.

๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.