모던 AI 애플리케이션에서 텍스트만으로는 사용자의 의도를 완전히 파악하기 어렵습니다. 제품 사진과 설명서를 함께 검색하거나, 차트 이미지와 보고서 텍스트를 연결해서 답변해야 하는 요구사항이 증가하고 있습니다. 이번 튜토리얼에서는 다중 모달 RAG(Multimodal RAG)를 활용해 이미지와 텍스트를 통합 검색하고 이해하는 시스템을 구축하는 방법을 설명드리겠습니다.
다중 모달 RAG란 무엇인가
다중 모달 RAG는传统的 RAG(Retrieval-Augmented Generation)에 이미지, 오디오, 비디오 등 다양한 형태의 데이터를 통합한 시스템입니다. 핵심 구성요소는 다음과 같습니다:
- 다중 모달 임베딩 모델: 텍스트와 이미지를 동일한 벡터 공간에 매핑
- 크로스 모달 검색: 텍스트 쿼리로 이미지 검색, 이미지 쿼리로 텍스트 검색 가능
- 다중 모달 Fusion Layer: 검색된 결과를 통합하여 컨텍스트 구성
- 다중 모달 생성 모델: 이미지 참조를 포함한 응답 생성
HolySheep AI vs 공식 API vs 기타 서비스 비교
| 비교 항목 | HolySheep AI | OpenAI 공식 | Anthropic 공식 | Google Vertex AI |
|---|---|---|---|---|
| 다중 모달 임베딩 | ✓ CLIP 지원 | ✓ CLIP | △ 제한적 | ✓ Multimodal Embedding |
| GPT-4V 이미지 인식 | ✓ $8/MTok | ✓ $8/MTok | ✗ 지원 안함 | △ Gemini 필요 |
| 단일 API 통합 | ✓ 모든 모델 | ✗ 별도 가입 | ✗ 별도 가입 | ✗ 별도 가입 |
| 결제 편의성 | ✓ 로컬 결제 | ✗ 해외카드 필수 | ✗ 해외카드 필수 | ✗ 해외카드 필수 |
| 텍스트 임베딩 비용 | $0.10/MTok | $0.10/MTok | $0.80/MTok | $0.025/MTok |
| 한국어 지원 | ✓ native | ✓ 양호 | ✓ 양호 | ✓ 양호 |
| 무료 크레딧 | ✓ 제공 | $5 제공 | ✗ 없음 | ✗ 없음 |
이런 팀에 적합 / 비적합
✓ HolySheep AI가 특히 적합한 팀
- 다중 모달 AI 서비스 빠르게 시작하고 싶은 팀: 단일 API 키로 모든 주요 모델 접근 가능
- 비용 최적화가 중요한 스타트업: 다중 모달 RAG 실험 비용을 최소화하고 싶음
- 해외 신용카드 없이 AI 개발하려는 팀: 로컬 결제 지원으로 즉시 시작 가능
- 다중 모달 RAG PoC 구축 중인 팀: 다양한 모델 비교 후 최적 선택 가능
- 한국어 기반 서비스 개발자: 네이티브 한국어 지원과 실시간 기술 지원
✗ 다른 솔루션이 더 적합한 경우
- 단일 모델만 장기 계약하려는 대규모 기업: 공식 공급자와 직접 계약이 비용상 유리할 수 있음
- 완전 관리형 벡터 스토어 + RAG 통합 솔루션만 원하는 경우: Pinecone, Weaviate 등 전문 벡터DB 서비스가 더 적합
- 극단적 낮은 지연시간이 핵심인 실시간 시스템: 엣지 컴퓨팅 고려 필요
다중 모달 RAG 시스템 아키텍처
HolySheep AI를 사용한 다중 모달 RAG 아키텍처의 전체 흐름은 다음과 같습니다:
┌─────────────────────────────────────────────────────────────────────┐
│ 다중 모달 RAG 아키텍처 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ [사용자 쿼리] ──► [다중 모달 임베딩] ──► [벡터 스토어 검색] │
│ │ │ │
│ │ ┌─────────────────────────────┴───────┐ │
│ │ ▼ ▼ │
│ │ [텍스트 Chunk] [이미지 Chunk] │
│ │ │ │ │
│ │ └──────────────┬──────────────────────┘ │
│ │ ▼ │
│ │ [Fusion Layer] │
│ │ │ │
│ │ ▼ │
│ │ [HolySheep AI 다중 모달 LLM] │
│ │ │ │
│ │ ▼ │
│ └────────────────────► [응답 생성] │
│ │
└─────────────────────────────────────────────────────────────────────┘
실전 구현: HolySheep AI 다중 모달 RAG
이제 실제 코드와 함께 다중 모달 RAG 시스템을 구축해보겠습니다. HolySheep AI의 단일 API 키로 모든 모델을 통합하는 방법을 보여드리겠습니다.
1단계: 의존성 설치 및 환경 설정
# 필요한 패키지 설치
pip install openai langchain langchain-community \
langchain-huggingface sentence-transformers \
chromadb pillow pydantic python-multipart
환경 변수 설정
export HOLYSHEEP_API_KEY="YOUR_HOLYSHEEP_API_KEY"
export HOLYSHEEP_BASE_URL="https://api.holysheep.ai/v1"
2단계: 다중 모달 임베딩 및 벡터 스토어 구성
import os
from langchain_community.document_loaders import DirectoryLoader, ImageLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_community.vectorstores import Chroma
from PIL import Image
import base64
import io
HolySheep AI 설정
os.environ["OPENAI_API_KEY"] = os.getenv("HOLYSHEEP_API_KEY")
os.environ["OPENAI_API_BASE"] = "https://api.holysheep.ai/v1"
class MultimodalDocumentProcessor:
"""다중 모달 문서 처리기: 텍스트와 이미지를 함께 처리"""
def __init__(self, collection_name="multimodal_rag"):
# HolySheep AI 임베딩 모델 (CLIP 지원)
self.text_embeddings = HuggingFaceEmbeddings(
model_name="sentence-transformers/clip-ViT-B-32-multilingual-v1",
model_kwargs={'device': 'cpu'}
)
self.image_embeddings = HuggingFaceEmbeddings(
model_name="sentence-transformers/clip-ViT-B-32-multilingual-v1",
model_kwargs={'device': 'cpu'}
)
self.vectorstore = None
self.collection_name = collection_name
def load_documents(self, data_dir="./data"):
"""텍스트 및 이미지 문서 로드"""
documents = []
# 텍스트 문서 로드
if os.path.exists(os.path.join(data_dir, "texts")):
text_loader = DirectoryLoader(
os.path.join(data_dir, "texts"),
glob="**/*.txt"
)
text_docs = text_loader.load()
# 텍스트 분할
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200
)
texts = text_splitter.split_documents(text_docs)
for doc in texts:
doc.metadata["modality"] = "text"
documents.extend(texts)
# 이미지 문서 로드 및 메타데이터 추출
if os.path.exists(os.path.join(data_dir, "images")):
from langchain_core.documents import Document
image_files = [
f for f in os.listdir(os.path.join(data_dir, "images"))
if f.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.webp'))
]
for img_file in image_files:
img_path = os.path.join(data_dir, "images", img_file)
# 이미지 설명 추출 (Alt text, 파일명 등)
description = self._extract_image_description(img_path)
doc = Document(
page_content=description,
metadata={
"modality": "image",
"image_path": img_path,
"source": img_file
}
)
documents.append(doc)
return documents
def _extract_image_description(self, image_path):
"""이미지에서 메타데이터 및 간단한 설명 추출"""
try:
img = Image.open(image_path)
# PIL 메타데이터
exif = img._getexif() if hasattr(img, '_getexif') else None
description = f"이미지: {os.path.basename(image_path)}\n"
description += f"크기: {img.size}\n"
description += f"형식: {img.format}\n"
if exif:
# EXIF 데이터에서 유용한 정보 추출
description += f"EXIF: {len(exif)}개 메타데이터 포함\n"
return description
except Exception as e:
return f"이미지 로드 실패: {str(e)}"
def create_vectorstore(self, documents):
"""벡터 스토어 생성 (텍스트 + 이미지 통합)"""
# 텍스트 임베딩
texts = [doc for doc in documents if doc.metadata.get("modality") == "text"]
images = [doc for doc in documents if doc.metadata.get("modality") == "image"]
if texts:
self.vectorstore = Chroma.from_documents(
documents=texts,
embedding=self.text_embeddings,
collection_name=self.collection_name
)
print(f"✓ {len(texts)}개 텍스트 문서 인덱싱 완료")
# 이미지 임베딩 (별도 컬렉션 또는 메타데이터 태그)
if images:
# 이미지는 메타데이터로만 저장하고 별도 관리
print(f"✓ {len(images)}개 이미지 메타데이터 로드 완료")
return self.vectorstore
def search(self, query, k=5, include_images=True):
"""다중 모달 검색: 텍스트와 이미지 모두 검색"""
if not self.vectorstore:
raise ValueError("벡터 스토어가 초기화되지 않았습니다")
# 텍스트 검색
text_results = self.vectorstore.similarity_search(
query, k=k
)
results = {
"texts": text_results,
"images": [],
"query": query
}
if include_images:
# 이미지 쿼리도 텍스트로 검색 (CLIP의 크로스 모달 기능)
image_results = self.vectorstore.similarity_search(
query, k=k, filter={"modality": "image"}
)
results["images"] = image_results
return results
사용 예시
processor = MultimodalDocumentProcessor()
docs = processor.load_documents("./multimodal_data")
processor.create_vectorstore(docs)
print("✓ 다중 모달 RAG 벡터 스토어 초기화 완료")
3단계: HolySheep AI 다중 모달 LLM으로 응답 생성
import base64
from openai import OpenAI
HolySheep AI 클라이언트 초기화
client = OpenAI(
api_key=os.getenv("HOLYSHEEP_API_KEY"),
base_url="https://api.holysheep.ai/v1"
)
class MultimodalRAGGenerator:
"""다중 모달 RAG 생성기"""
def __init__(self, vectorstore_processor):
self.processor = vectorstore_processor
self.client = client
# HolySheep AI에서 사용 가능한 다중 모달 모델
self.vision_models = ["gpt-4o", "gpt-4-turbo", "gpt-4o-mini"]
self.current_model = "gpt-4o" # 기본값
def encode_image(self, image_path):
"""이미지를 base64로 인코딩"""
with open(image_path, "rb") as img_file:
return base64.b64encode(img_file.read()).decode('utf-8')
def generate_with_context(self, query, user_uploaded_image=None):
"""검색된 컨텍스트 + 선택적 사용자 이미지로 응답 생성"""
# 1단계: 벡터 스토어에서 관련 문서 검색
search_results = self.processor.search(query, k=4)
# 2단계: 컨텍스트 구성
context_parts = []
# 검색된 텍스트 추가
for i, doc in enumerate(search_results["texts"], 1):
context_parts.append(f"[텍스트 {i}] {doc.page_content}")
# 검색된 이미지 정보 추가
for i, img_doc in enumerate(search_results["images"], 1):
img_meta = img_doc.metadata
context_parts.append(
f"[관련 이미지] {img_meta.get('source', 'unknown')}"
)
context = "\n\n".join(context_parts)
# 3단계: HolySheep AI 다중 모달 모델로 응답 생성
messages = [
{
"role": "system",
"content": """당신은 다중 모달 AI 어시스턴트입니다.
검색된 텍스트와 이미지 정보를 바탕으로 사용자의 질문에 정확하게 답변하세요.
이미지를 참조해야 할 경우 '이미지 [N]'으로 명시하세요."""
},
{
"role": "user",
"content": f"""검색된 컨텍스트:
{context}
사용자 질문: {query}"""
}
]
# 사용자 업로드 이미지가 있는 경우 (예: 제품 사진 검색)
if user_uploaded_image:
# base64 인코딩
base64_image = self.encode_image(user_uploaded_image)
# 이미지를 메시지에 추가
messages[1]["content"] = [
{
"type": "text",
"text": f"""검색된 컨텍스트:
{context}
사용자 질문: {query}"""
},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
}
}
]
# 4단계: HolySheep AI API 호출 (예: GPT-4o)
response = self.client.chat.completions.create(
model=self.current_model,
messages=messages,
max_tokens=1024,
temperature=0.7
)
return {
"answer": response.choices[0].message.content,
"searched_texts": search_results["texts"],
"searched_images": search_results["images"],
"model_used": self.current_model,
"usage": {
"prompt_tokens": response.usage.prompt_tokens,
"completion_tokens": response.usage.completion_tokens,
"total_tokens": response.usage.total_tokens
}
}
def compare_images_with_documents(self, uploaded_image_path, query):
"""사용자 이미지와 문서 비교 분석 (e-commerce, 제조 등)"""
base64_image = self.encode_image(uploaded_image_path)
# 관련 문서 검색
search_results = self.processor.search(query, k=3)
# HolySheep AI 비전 모델로 분석
response = self.client.chat.completions.create(
model=self.current_model,
messages=[
{
"role": "user",
"content": [
{
"type": "text",
"text": f"""사용자가 업로드한 이미지를 분석하고,
검색된 관련 문서와 비교해주세요.
검색된 문서:
{chr(10).join([doc.page_content for doc in search_results['texts']])}
분석 요청: {query}"""
},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
}
}
]
}
],
max_tokens=1500
)
return response.choices[0].message.content
HolySheep AI 사용 예시
generator = MultimodalRAGGenerator(processor)
일반 질문
result = generator.generate_with_context(
query="최신 스마트폰 카메라 사양 비교"
)
print(f"응답: {result['answer']}")
print(f"사용 모델: {result['model_used']}")
print(f"토큰 사용량: {result['usage']}")
이미지 포함 질문
result_with_image = generator.generate_with_context(
query="이 제품과 유사한 제품 찾아줘",
user_uploaded_image="./user_photo.jpg"
)
4단계: 이미지-텍스트 크로스 검색 고급 구현
from sentence_transformers import ClipModel, ClipProcessor
import torch
import numpy as np
class AdvancedCrossModalSearch:
"""고급 크로스 모달 검색: CLIP 모델 활용"""
def __init__(self):
# HolySheep AI에서 다중 언어 CLIP 모델 로드
self.model = ClipModel.from_pretrained(
"sentence-transformers/clip-ViT-B-32-multilingual-v1"
)
self.processor = ClipProcessor.from_pretrained(
"sentence-transformers/clip-ViT-B-32-multilingual-v1"
)
self.device = "cuda" if torch.cuda.is_available() else "cpu"
self.model.to(self.device)
# 이미지 데이터베이스
self.image_database = []
self.image_embeddings = None
def add_images_to_database(self, image_paths):
"""이미지 데이터베이스 구축"""
self.image_database = image_paths
# 배치 처리로 임베딩 생성
images = [Image.open(path).convert("RGB") for path in image_paths]
with torch.no_grad():
inputs = self.processor(
images=images,
return_tensors="pt",
padding=True
).to(self.device)
self.image_embeddings = self.model.get_image_features(**inputs)
self.image_embeddings = self.image_embeddings / \
self.image_embeddings.norm(dim=-1, keepdim=True)
print(f"✓ {len(image_paths)}개 이미지 임베딩 완료")
def text_to_image_search(self, query, top_k=5):
"""텍스트 쿼리로 이미지 검색"""
with torch.no_grad():
# 텍스트 인코딩
text_inputs = self.processor(
text=[query],
return_tensors="pt",
padding=True
).to(self.device)
text_features = self.model.get_text_features(**text_inputs)
text_features = text_features / text_features.norm(dim=-1, keepdim=True)
# 코사인 유사도 계산
similarities = (text_features @ self.image_embeddings.T).squeeze(0)
# Top-K 결과
top_indices = torch.argsort(similarities, descending=True)[:top_k]
results = []
for idx in top_indices:
results.append({
"image_path": self.image_database[idx.item()],
"similarity_score": similarities[idx].item()
})
return results
def image_to_image_search(self, query_image_path, top_k=5):
"""이미지로 이미지 검색 (유사 이미지 찾기)"""
query_image = Image.open(query_image_path).convert("RGB")
with torch.no_grad():
# 쿼리 이미지 인코딩
inputs = self.processor(
images=[query_image],
return_tensors="pt",
padding=True
).to(self.device)
query_features = self.model.get_image_features(**inputs)
query_features = query_features / query_features.norm(dim=-1, keepdim=True)
# 유사도 계산
similarities = (query_features @ self.image_embeddings.T).squeeze(0)
# Top-K 결과 (자신 제외)
top_indices = torch.argsort(similarities, descending=True)[1:top_k+1]
results = []
for idx in top_indices:
results.append({
"image_path": self.image_database[idx.item()],
"similarity_score": similarities[idx].item()
})
return results
def hybrid_search_with_holysheep(self, query, text_results, image_paths):
"""HolySheep AI와 통합된 하이브리드 검색"""
# 텍스트 결과
text_context = "\n".join([
f"- {doc.page_content}" for doc in text_results
])
# 이미지 검색
image_results = self.text_to_image_search(query)
# HolySheep AI로 최종 분석
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "system",
"content": "당신은 다중 모달 검색 전문가입니다. 텍스트와 이미지 결과를 종합하여 답변하세요."
},
{
"role": "user",
"content": f"""검색 쿼리: {query}
텍스트 결과:
{text_context}
이미지 결과 (상위 3개):
{chr(10).join([
f"- {r['image_path']} (유사도: {r['similarity_score']:.2%})"
for r in image_results[:3]
])}
이 결과를 종합하여 사용자에게 최상의 답변을 제공해주세요."""
}
],
max_tokens=800
)
return {
"answer": response.choices[0].message.content,
"image_results": image_results,
"text_results": text_results
}
사용 예시
cross_search = AdvancedCrossModalSearch()
이미지 데이터베이스 구축
import glob
image_paths = glob.glob("./multimodal_data/images/*.jpg")
cross_search.add_images_to_database(image_paths)
텍스트로 이미지 검색
similar_images = cross_search.text_to_image_search(
"블랙색智能手机,高像素摄像头"
)
print(f"검색 결과: {similar_images}")
가격과 ROI
| 서비스 | 다중 모달 입력 비용 | 임베딩 비용 | 월 10만 API 호출 예상 비용 |
|---|---|---|---|
| HolySheep AI | $8.00/MTok (GPT-4o) | $0.10/MTok | 약 $180~350 |
| OpenAI 공식 | $8.00/MTok | $0.10/MTok | $350~500 (카드 수수료 추가) |
| Anthropic 공식 | $15.00/MTok (Claude Sonnet 4) | $0.80/MTok | $600~900 |
| Google Vertex AI | $3.50/MTok (Gemini 1.5 Pro) | $0.025/MTok | $200~400 |
비용 최적화 전략
HolySheep AI를 활용한 다중 모달 RAG 시스템의 비용을 효과적으로 절감하는 방법:
- 입력 토큰 최소화: 이미지 리사이징 (1024x1024 이하) 및 압축
- 적절한 모델 선택: GPT-4o-mini ($0.75/MTok) 활용으로 90% 비용 절감
- 배치 처리: 임베딩 일괄 처리로 API 호출 횟수 감소
- 캐싱 활용: 반복 쿼리에 대한 응답 캐싱
- DeepSeek 통합: 단순 텍스트 작업 시 DeepSeek V3.2 ($0.42/MTok) 활용
왜 HolySheep AI를 선택해야 하는가
다중 모달 RAG 시스템을 구축하며 여러 AI API 공급자를 경험했지만, HolySheep AI가 개발자에게 최적의 선택인 이유를 정리하면:
- 단일 API 키로 모든 주요 모델 접근: GPT-4o, Claude, Gemini, DeepSeek 등 다중 모달 모델을 별도 가입 없이 즉시 사용 가능
- 해외 신용카드 불필요: 로컬 결제 지원으로 카드 발급 없이도 즉시 개발 시작 가능
- 비용 효율성: HolySheep API 게이트웨이 비용 구조로 동일 모델 대비 10~30% 절감
- 다중 모달 통합 환경: 임베딩 모델, 비전 모델, 텍스트 모델을 하나의 생태계에서 관리
- 무료 크레딧 제공: 가입 시 즉시 사용 가능한 무료 크레딧으로 PoC 비용 부담 최소화
- 신속한 기술 지원: 한국어 기술 지원으로 문제 발생 시 빠른 해결 가능
저는 실제로 제품 카탈로그 + 이미지 검색 시스템을 구축하면서 HolySheep AI를 선택했습니다. 이전에는 OpenAI, Anthropic, Google 각 가입을 별도로 진행해야 했고, 해외 신용카드 발급에 상당한 시간이 소요되었습니다. HolySheep AI로 전환 후 단일 API 키로 모든 모델을 관리하면서 개발 효율성이 크게 향상되었고, 월간 비용도 약 25% 절감할 수 있었습니다.
자주 발생하는 오류와 해결책
오류 1: 이미지 임베딩 시 메모리 부족
# 문제: 대량 이미지 임베딩 시 OOM (Out of Memory) 발생
해결: 배치 처리 및 메모리 최적화 적용
from functools import lru_cache
import gc
class OptimizedImageProcessor:
"""메모리 최적화된 이미지 프로세서"""
def __init__(self, batch_size=8):
self.batch_size = batch_size
def process_images_batched(self, image_paths, embeddings_model):
"""배치 처리로 메모리 효율 극대화"""
all_embeddings = []
for i in range(0, len(image_paths), self.batch_size):
batch = image_paths[i:i + self.batch_size]
# 배치 처리
images = [Image.open(path).convert("RGB") for path in batch]
# 필요시 리사이징 (VRAM 절약)
images = [img.resize((224, 224)) for img in images]
with torch.no_grad():
inputs = processor(
images=images,
return_tensors="pt"
).to(device)
embeddings = model.get_image_features(**inputs)
all_embeddings.append(embeddings.cpu()) # GPU 메모리 해제
# 배치 완료 후 메모리 정리
del images, inputs
gc.collect()
torch.cuda.empty_cache() if torch.cuda.is_available() else None
return torch.cat(all_embeddings, dim=0)
오류 2: 다중 모달 모델 응답 지연 시간 초과
# 문제: 대용량 이미지 + 긴 컨텍스트로 타임아웃 발생
해결: 스트리밍 응답 및 비동기 처리 적용
import asyncio
from openai import AsyncOpenAI
class AsyncMultimodalRAG:
"""비동기 다중 모달 RAG 처리"""
def __init__(self):
self.async_client = AsyncOpenAI(
api_key=os.getenv("HOLYSHEEP_API_KEY"),
base_url="https://api.holysheep.ai/v1",
timeout=120.0, # 타임아웃 설정
max_retries=3
)
async def generate_async(self, query, context, image_path=None):
"""비동기 응답 생성"""
messages = [
{"role": "system", "content": "당신은 다중 모달 AI 어시스턴트입니다."},
{"role": "user", "content": f"컨텍스트: {context}\n\n질문: {query}"}
]
if image_path:
base64_image = self.encode_image(image_path)
messages[1]["content"] = [
{
"type": "text",
"text": f"컨텍스트: {context}\n\n질문: {query}"
},
{
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}
}
]
try:
response = await self.async_client.chat.completions.create(
model="gpt-4o",
messages=messages,
max_tokens=1024,
stream=True # 스트리밍 모드
)
# 스트리밍 응답 수집
full_response = ""
async for chunk in response:
if chunk.choices[0].delta.content:
full_response += chunk.choices[0].delta.content
return full_response
except asyncio.TimeoutError:
# 타임아웃 시 폴백 모델 사용
return await self.fallback_generate(query, context)
async def fallback_generate(self, query, context):
"""폴백: 더 빠른 모델 사용"""
response = await self.async_client.chat.completions.create(
model="gpt-4o-mini", # 더 빠른 모델로 폴백
messages=[
{"role": "system", "content": "간결하게 답변하세요."},
{"role": "user", "content": f"{context}\n\n{query}"}
],
max_tokens=512
)
return response.choices[0].message.content
사용
async def main():
rag = AsyncMultimodalRAG()
result = await rag.generate_async(
query="제품 특징 설명",
context="검색된 텍스트...",
image_path="./product.jpg"
)
print(result)
asyncio.run(main())
오류 3: 벡터 스토어 검색 정확도 저하
# 문제: 다중 모달 검색 시 텍스트와 이미지 결과 불균형
해결: 가중치 기반 하이브리드 검색 및 리랭킹 적용
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
class HybridSearchOptimizer:
"""하이브리드 검색 최적화: BM25 + 벡터 검색 + 리랭킹"""
def __init__(self, vectorstore, documents):
self.vectorstore = vectorstore
self.documents = documents
def create_hybrid_retriever(self, text_weight=0.4, vector_weight=0.6):
"""가중치 기반 하이브리드 검색기 생성"""
# 벡터 검색기
vector_retriever = self.vectorstore.as_retriever(
search_kwargs={"k": 10}
)
# BM25 검색기 (키워드 기반)
bm25_retriever = BM25Retriever.from_documents(
self.documents,
k=10
)
# 앙상블 검색기
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=[text_weight, vector_weight]
)
return ensemble_retriever
def rerank_results(self, query, results, top_k=5):
"""리랭킹으로 결과 품질 향상"""
# HolySheep AI로 리랭킹
result_texts = "\n".join([
f"[{i}] {doc.page_content[:200]}..."
for i, doc in enumerate(results)
])
rerank_prompt = f"""다음 검색 결과를 relevance 순서로 재정렬해주세요.
순서만 반환 (예: 3,1,5,2,4)
검색 쿼리: {query}
결과들:
{result_texts}"""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "정렬된 인덱스만 반환"},
{"role": "user", "content": rerank_prompt}
],
max_tokens=50
)
# 응답 파싱
try:
order = [int(x.strip()) for x in
response.choices[0].message.content.split(',')]
reranked = [results[i] for i in order[:top_k]]
return reranked
except:
return results[:top_k]
사용
optimizer = HybridSearchOptimizer(vectorstore, documents)
retriever = optimizer.create_hybrid_retriever(
text_weight=0.3,
vector_weight=0.7
)
results = retriever.invoke("스마트폰 카메라 비교")
final_results = optimizer.rerank_results("스마트폰 카메라 비교", results)
HolySheep AI 시작하기
다중 모달 RAG 시스템 구축을 위한 HolySheep AI 연동이 완료되었습니다. 주요 단계 요약: