Ana içeriğe geç

Multimodal RAG: Belgelerden Öğrenmeye Yönelik Uygulamalı Bir Rehber

OpenAI API ve ChromaDB vektör veritabanını kullanarak IKEA montaj talimatları üzerinde görsel Soru-Cevap sistemi için bir Multimodal RAG hattı oluşturmayı öğrenin.
· 11 dk. oku

Yapay Zeka ile Keşfedin

DIY IKEA mobilyası kurduğunuzu hayal edin. Talimatların 14. adımına bakıyorsunuz ama hangi vidanın nereye gideceğini çıkaramıyorsunuz. Diyagram bir şeyler gösteriyor ama kafanızda oturmuyor. 

Şöyle sorsanız: "14. adımdaki küçük metal parça ne işe yarıyor?", standart bir metin tabanlı geri getirme ile artırılmış üretim (RAG) sistemi burada yardımcı olamaz. Cevap sayfadaki herhangi bir metinde değil, diyagramın kendisinde. IKEA talimatları meşhur şekilde yazısızdır.

İşte bu noktada çok modlu (multimodal) RAG devreye girer.

Bu eğitimde, görüntüler, diyagramlar ve karma içerik içeren belgeler hakkında soruları yanıtlayabilen bir multimodal RAG sistemi kurmanızı adım adım göstereceğim. Test vakası olarak IKEA montaj talimatlarını kullanacağız; çünkü iyi bir stres testidir: çoğunlukla görsel, minimum metin ve insanların gerçekten yardım aradığı bir konu.

Tüm süreçte OpenAI modellerini kullanacağız: görüntüleri anlamak ve yanıtlar üretmek için GPT-4o, aranabilir vektörler oluşturmak için text-embedding-3-small. Farklı bir çerçeveyle RAG hatları kurmayı öğrenmek isterseniz LangChain ile RAG kursumuzu öneririm.

Sonunda, yerelde çalıştırabileceğiniz ve kendi belgelerinize uyarlayabileceğiniz çalışan bir sisteminiz olacak.

Multimodal RAG Nedir?

Multimodal RAG, standart RAG desenini yalnızca metinle sınırlı kalmayacak şekilde genişletir. Çekirdek fikir aynı kalır, ancak "bağlam" artık görselleri, tabloları, diyagramları ve diğer metin dışı içeriği de kapsar.

Bu neden önemli? Çünkü gerçek dünyadaki belgeler sadece metinden ibaret değildir.

Gerçekte nelerle çalıştığınızı düşünün: 

  • Bağlantı şemaları olan teknik kılavuzlar 
  • Deneysel grafikler içeren araştırma makaleleri 
  • Gelir grafikleri bulunan finansal raporlar
  • Bileşen görselleri olan ürün teknik özellikleri 

Yalnızca metni işleyen bir sistem eksik bilgiyle çalışır. Bu, bir tarife kitabını yalnızca malzeme listesini okuyup "nazikçe katlayın" ifadesinin fotoğraflarda nasıl göründüğünü görmezden gelerek anlamaya çalışmaya benzer.

Geleneksel RAG bir PDF’yi karakter akışı olarak ele alır. Metni çıkarır, parçalara böler, bu parçaları gömer ve işi biter. Görseller tamamen atlanır veya belki [IMAGE] yer tutucu belirteçlere dönüştürülür. Tablolar ise yapılarını kaybeden bozulmuş metin satırlarına döner.

Multimodal RAG farklı bir yaklaşım benimser: Görseller ya betimlenir ya da doğrudan gömülür, tablolar yapılandırılmış formatlara ayrıştırılır. Getirme sistemi, "ağ topolojisi diyagramı" gibi bir sorguyu hem ağ mimarisinin metinsel açıklamalarıyla hem de gerçek görsel diyagramlarla eşleştirebilir. Üretim modeli bir görsele bakıp neyi tasvir ettiğini analiz edebilir.

Boyut

Yalnızca Metin RAG

Multimodal RAG

Girdi türleri

Düz metin, belki markdown

Metin, görseller, tablolar, diyagramlar, karma belgeler

Neler gömülür

Metin parçaları

Metin parçaları artı görsel betimleri veya görsel gömüleri

Üretim modeli

Herhangi bir LLM

Görüntü-dil modeli (GPT-4o, Claude, Gemini)

En uygun olduğu durumlar

Metin ağırlıklı belgeler

Kılavuzlar, raporlar, sunumlar, görsel içeriği olan her şey

“Multimodal” hâlâ belirsiz bir şemsiye terim gibi geliyorsa, bu Multimodal Yapay Zekâ blogu somut örneklerle öz ve açıklayıcıdır.

Multimodal RAG Nasıl Çalışır?

Boru hattında yalnızca metin RAG’den daha çok hareketli parça vardır, ancak yapı benzerdir. Veriler işlenir ve gömülür, bir vektör deposuna yerleştirilir ve biri soru sorduğunda geri getirilir.

Multimodal RAG Pipeline

Akış şöyle:

Belge alımı ve ayrıştırma

Ham belgeler (PDF’ler, görseller, slaytlar) bileşen parçalarına ayrılır. Metni çıkarır, görselleri tespit eder, tabloları ayrıştırır ve her şeyin mekânsal olarak nasıl ilişkili olduğunu belirlersiniz. 5. sayfadaki bir diyagramın altında bir altyazı olabilir ve 4. sayfadaki metinde bir atıf bulunabilir. Bu ilişkileri yakalamanız gerekir.

İçerik ön işleme

Farklı içerik türleri farklı muamele gerektirir. Görseller için iki ana seçeneğiniz var: bir görsel modeli (ör. GPT-4o) kullanarak metin betimleri üretmek ya da bir multimodal kodlayıcı (örn. CLIP) ile görselleri doğrudan gömmek. Betimleme yaklaşımı daha basittir ve standart metin gömmeleriyle çalışır. Tablolar yapılandırılmış formatlara dönüştürülür veya doğal dilde özetlenir.

Bundan sonra her şey vektörlere dönüştürülür. Betimleme yaklaşımını kullanıyorsanız, tüm metninizi (orijinal metin artı üretilen görsel betimleri) standart bir metin gömme modeliyle gömersiniz. Kritik nokta, görsel içerikle ilgili sorguların artık bu betimlemelerle eşleşebilmesidir.

Dizinleme ve depolama 

Vektörler; kaynak belge, sayfa numarası, içerik türü ve görseller için orijinal dosyanın yolu gibi üst verilerle birlikte bir veritabanında saklanır. Daha sonra üretim aşamasında modeli görselle beslemek istediğinizde bu görsel yoluna ihtiyacınız olacak.

Getirme

Bir sorgu alındığında, aynı modeli kullanarak sorguyu gömün, en yakın komşuları arayın ve en iyi eşleşmeleri döndürün. Getirilen parçalar metne, görsellere veya her ikisine birden referans verebilir.

Üretim

Sorguyu, getirilen bağlamla birlikte bir görüntü-dil modeline aktarın. Getirilen parçalar görsellere referans veriyorsa, bu görselleri yükleyip isteme dahil edin. Model hem metin bağlamını hem de gerçek görselleri görür ve bir yanıt üretir.

Üretim adımı GPT-4o’nun gerçekten parladığı yerdir. Bir IKEA diyagramında vida yerleşimini inceleyip olanı sade bir dille açıklayabilir. Bir grafik okuyup eğilimi özetleyebilir. Metin betiminin kaçırabileceği teknik çizimlerdeki ayrıntıları fark edebilir.

Multimodal RAG’in Uygulanması

Haydi bunu inşa edelim. IKEA montaj talimatları hakkında soruları yanıtlayabilen bir sistem oluşturacağız; kurulumdan çalışan bir sorgu arayüzüne kadar adım adım ilerleyeceğiz.

Adım 0: Çerçeve ve araç seçimi

Bu eğitimde işleri basit tutuyoruz:

Bileşen

Seçim

Neden

Gömüler

text-embedding-3-small

Ucuz, iyi kalite, aynı API

Vektör deposu

ChromaDB

Yerelde çalışır, kurulum yok, kalıcı

Görsel modeli

GPT-4o

Görsel anlama konusunda sınıfının en iyisi

Üretim

GPT-4o

Aynı model, iki görevi de yönetir

Alternatifleri de kullanabilirsiniz. Ölçek gerekiyorsa vektör deposu için Pinecone veya Weaviate. Üretim için Claude veya Gemini iyi alternatiflerdir. Bu durumlarda genel mimari aynı kalır.

Gömüler için neden CLIP veya ColPali kullanmıyoruz? Kullanabilirsiniz. Bunlar, önce metin betimi üretmeden görselleri doğrudan gömmenize olanak tanır. Ancak karmaşıklık katarlar ve çoğu zaman GPU gerektirirler. Betimleme yaklaşımı, yalnızca görsel benzerliği değil, anlamsal ayrıntıları yakalamak istediğiniz belge tarzı içerikler için iyi çalışır.

Adım 1: Ortamın kurulması

Projeyi kurmak için bağımlılıklar ve ortam değişkenleriyle başlayalım.

Bağımlılıkların kurulması

Öncelikle PDF işlemesi için poppler kurulu olmalı.

  • Ubuntu/Debian: sudo apt-get install poppler-utils

  • macOS ( Homebrew kullanarak): brew install poppler

  • Windows: sürüm sayfasından indirin ve PATH’e ekleyin

Sonra Python paketlerini kurun. ChromaDB’ye ek olarak, PDF’leri görsellere dönüştürmek için pdf2image, görsel işleme için pillow ve PDF dosyalarını indirmek için requests gerekecek.

pip install openai chromadb pdf2image pillow requests

API anahtarı ve dosyaların ayarlanması

Modelleri kullanmak için OpenAI API anahtarınızı bir ortam değişkeni olarak ayarlayın.

Unix/Linux/macOS:

export OPENAI_API_KEY="your-api-key-here"

Windows: 

setx OPENAI_API_KEY="your-api-key-here"

Şimdi proje yapısını kuralım ve örnek veriyi indirelim. Betikte indirme URL’leri zaten var, ancak önce PDF’lere göz atmak isterseniz hem MALM masa hem de MALM karyola için doğrudan bağlantılar burada. 

step1_setup.py adlı bir dosya oluşturun:

"""
Step 1: Setup and Download Sample Data
"""
import os
import requests

# Create directories
for d in ["data", "data/images", "data/cache"]:
    os.makedirs(d, exist_ok=True)
print("✓ Created directories")

# Download IKEA assembly instructions
SAMPLE_PDFS = {
    "malm_desk.pdf": "https://www.ikea.com/us/en/assembly_instructions/malm-desk-white__AA-516949-7-2.pdf",
    "malm_bed.pdf": "https://www.ikea.com/us/en/assembly_instructions/malm-bed-frame-low__AA-75286-15_pub.pdf",
}

for filename, url in SAMPLE_PDFS.items():
    filepath = f"data/{filename}"
    if not os.path.exists(filepath):
        print(f"Downloading {filename}...")
        response = requests.get(url, timeout=30)
        with open(filepath, "wb") as f:
            f.write(response.content)
        print(f"  ✓ Saved ({len(response.content) / 1024:.1f} KB)")
    else:
        print(f"✓ {filename} already exists")

İlk kurulumu tamamlamak için betiği çalıştırın:

python step1_setup.py

data/ klasörünüze IKEA PDF’lerinin indirildiğini görmelisiniz.

Adım 2: Belgelerin ön işlenmesi

IKEA talimatları zorludur. Çoğunlukla diyagramlardan oluşur ve çok az metin içerir. PDF sayfalarını görsellere dönüştürmemiz ve ardından her sayfanın ne gösterdiğini GPT-4o ile betimlememiz gerekiyor.

step2_preprocess.py oluşturun:

"""
Step 2: Preprocess Documents
Convert PDFs to images and generate descriptions with GPT-4o
"""
import os
import json
import base64
from pdf2image import convert_from_path
from openai import OpenAI

client = OpenAI()

DATA_DIR = "data"
IMAGES_DIR = "data/images"
CACHE_FILE = "data/cache/descriptions.json"


def convert_pdf_to_images(pdf_path):
    """Convert a PDF to page images."""
    pdf_name = os.path.splitext(os.path.basename(pdf_path))[0]
    images = convert_from_path(pdf_path, dpi=150)
    
    image_paths = []
    for i, image in enumerate(images):
        image_path = f"{IMAGES_DIR}/{pdf_name}_page_{i+1:03d}.png"
        image.save(image_path, "PNG")
        image_paths.append(image_path)
    
    return image_paths


def describe_page(image_path):
    """Use GPT-4o to describe an instruction page."""
    with open(image_path, "rb") as f:
        base64_image = base64.b64encode(f.read()).decode("utf-8")
    
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "system",
                "content": """Describe this IKEA assembly instruction page in detail.
Include: step numbers, parts shown, tools needed, actions demonstrated, 
quantities (like "2x"), warnings, and part numbers if visible.
This description will help people find this page when they have questions."""
            },
            {
                "role": "user",
                "content": [
                    {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{base64_image}"}},
                    {"type": "text", "text": "Describe this instruction page."}
                ]
            }
        ],
        max_tokens=500
    )
    return response.choices[0].message.content


def main():
    # Load cache if exists
    cache = {}
    if os.path.exists(CACHE_FILE):
        with open(CACHE_FILE, "r") as f:
            cache = json.load(f)
    
    all_pages = []
    
    # Process each PDF
    for pdf_file in os.listdir(DATA_DIR):
        if not pdf_file.endswith(".pdf"):
            continue
        
        print(f"\nProcessing {pdf_file}...")
        pdf_path = f"{DATA_DIR}/{pdf_file}"
        
        # Convert to images
        print("  Converting to images...")
        image_paths = convert_pdf_to_images(pdf_path)
        print(f"  ✓ {len(image_paths)} pages")
        
        # Generate descriptions
        print("  Generating descriptions with GPT-4o...")
        for i, image_path in enumerate(image_paths):
            if image_path in cache:
                description = cache[image_path]
                status = "cached"
            else:
                description = describe_page(image_path)
                cache[image_path] = description
                # Save cache after each page
                with open(CACHE_FILE, "w") as f:
                    json.dump(cache, f, indent=2)
                status = "generated"
            
            all_pages.append({
                "source_pdf": pdf_file,
                "page_number": i + 1,
                "image_path": image_path,
                "description": description
            })
            print(f"    Page {i+1}/{len(image_paths)} [{status}]")
    
    # Save all page data
    with open("data/cache/all_pages.json", "w") as f:
        json.dump(all_pages, f, indent=2)
    
    print(f"\n✓ Processed {len(all_pages)} pages total")


if __name__ == "__main__":
    main()

Fonksiyonlar şunları yapıyor:

  • convert_pdf_to_images(pdf_path): her PDF sayfasını pdf2image ile 150 DPI’de PNG olarak oluşturur. Seçilebilir metni olmayan diyagramları çıkarır ve malm_desk_page_001.png gibi tutarlı adlarla kaydeder.

  • describe_page(image_path): görseli base64 olarak kodlayıp özel bir sistem istemiyle GPT-4o’ya gönderir. Model, anlamsal arama için adımlar, parçalar ve adetleri yakalayan ayrıntılı bir metin betimi döndürür.

  • main(): her şeyi orkestre eder: Yeniden işlemeyi önlemek için önbelleğe alınmış betimleri yükler, PDF’leri görsellere dönüştürür, gerektiğinde yeni betimler üretir, artımlı önbellek kaydeder ve dizinleme için üst verilerle all_pages.json çıktısını verir.

Betiği şöyle çalıştırın:

python step2_preprocess.py

Bu adım birkaç dakika sürer. GPT-4o her sayfayı analiz edip ayrıntılı bir betim üretir. Betimler önbelleğe alınır; bu nedenle tekrar çalıştırırsanız, zaten işlenen sayfalar atlanır.

Burada ne oluyor? Görsel içeriği aranabilir metne dönüştürüyoruz. Biri "Ayakları nasıl takarım?" diye sorduğunda, getirici bu betimlemeleri arayıp ayak takmadan bahseden sayfaları bulur; orijinal sayfada hiç metin olmasa bile.

Temel hattı kurduktan sonra, sıradaki kazanımlar; hibrit arama, yeniden sıralama veya sorgu yeniden yazma gibi getirme tekniklerinden gelir. Bunlara aşina olmak için Gelişmiş RAG Teknikleri blogunu okuyun.

Adım 3: Çok modlu verilerin depolanması ve dizinlenmesi

Şimdi betimleri gömüp ChromaDB’de saklayacağız.

step3_index.py oluşturun:

"""
Step 3: Create Embeddings and Index
"""
import os
import json
from openai import OpenAI
import chromadb

client = OpenAI()

PAGES_FILE = "data/cache/all_pages.json"
CHROMA_DIR = "data/chroma_db"
COLLECTION_NAME = "ikea_instructions"


def get_embedding(text):
    """Get embedding from OpenAI."""
    response = client.embeddings.create(
        model="text-embedding-3-small",
        input=text
    )
    return response.data[0].embedding


def main():
    # Load page descriptions
    with open(PAGES_FILE, "r") as f:
        pages = json.load(f)
    print(f"Loaded {len(pages)} pages")
    
    # Initialize ChromaDB with persistent storage
    chroma_client = chromadb.PersistentClient(path=CHROMA_DIR)
    
    # Delete existing collection if present
    try:
        chroma_client.delete_collection(name=COLLECTION_NAME)
    except:
        pass
    
    collection = chroma_client.create_collection(
        name=COLLECTION_NAME,
        metadata={"hnsw:space": "cosine"}
    )
    print(f"Created collection: {COLLECTION_NAME}")
    
    # Index each page
    print("\nCreating embeddings...")
    for i, page in enumerate(pages):
        # Combine source info with description
        text_to_embed = f"Source: {page['source_pdf']}, Page {page['page_number']}\n\n{page['description']}"
        
        embedding = get_embedding(text_to_embed)
        
        collection.add(
            ids=[f"page_{i}"],
            embeddings=[embedding],
            documents=[page["description"]],
            metadatas=[{
                "source_pdf": page["source_pdf"],
                "page_number": page["page_number"],
                "image_path": page["image_path"]
            }]
        )
        
        if (i + 1) % 5 == 0 or i == len(pages) - 1:
            print(f"  Indexed {i + 1}/{len(pages)} pages")
    
    print(f"\n✓ Index created with {collection.count()} documents")
    
    # Quick retrieval test
    print("\nTesting retrieval...")
    test_query = "How do I attach the legs?"
    query_embedding = get_embedding(test_query)
    results = collection.query(query_embeddings=[query_embedding], n_results=2)
    
    print(f"Query: '{test_query}'")
    for meta in results["metadatas"][0]:
        print(f"  → {meta['source_pdf']}, Page {meta['page_number']}")


if __name__ == "__main__":
    main()

Burada get_embedding(text) fonksiyonu, betim ve kaynak bilgisindeki metni OpenAI’nin text-embedding-3-small modeliyle yoğun bir vektöre dönüştürür. 1536 boyutlu bu vektörler, benzerlik araması için anlamsal anlamı yakalayabilir.

main(), önceki adımdaki all_pages.json dosyasından işlenmiş sayfaları yükler, kalıcı depolamayla ChromaDB’yi başlatır, koleksiyonu silip yeniden oluşturur, her sayfa için gömmeler üretir, bunları zengin üst verilerle (kaynak, sayfa numarası, görsel yolu) saklar ve dizinlemenin çalıştığını doğrulamak için hızlı bir getirme testi yapar.

Çalıştırın:

python step3_index.py

Üst veriler burada önemlidir. image_path’i saklarız ki daha sonra üretim sırasında gerçek görseli geri getirip GPT-4o’ya gösterebilelim. Aranan şey betimdir, ancak gösterilen şey görseldir.

Adım 4: RAG hattının kurulması

İşte tam multimodal RAG hattı. Bir sorgu gömülür, ilgili sayfalar getirilir, görseller yüklenir ve GPT-4o metin betimleri ile görsellere dayanarak bir yanıt üretir.

step4_query.py oluşturun:

"""
Step 4: Query the Multimodal RAG System
"""
import os
import sys
import base64
from openai import OpenAI
import chromadb

client = OpenAI()

CHROMA_DIR = "data/chroma_db"
COLLECTION_NAME = "ikea_instructions"
TOP_K = 3

# Initialize ChromaDB
chroma_client = chromadb.PersistentClient(path=CHROMA_DIR)


def get_embedding(text):
    """Get embedding from OpenAI."""
    response = client.embeddings.create(
        model="text-embedding-3-small",
        input=text
    )
    return response.data[0].embedding


def retrieve(query, top_k=TOP_K):
    """Find relevant instruction pages."""
    collection = chroma_client.get_collection(name=COLLECTION_NAME)
    query_embedding = get_embedding(query)
    
    results = collection.query(
        query_embeddings=[query_embedding],
        n_results=top_k,
        include=["documents", "metadatas"]
    )
    return results


def generate_answer(query, retrieved_results):
    """Generate answer using GPT-4o with retrieved images."""
    if not retrieved_results["ids"][0]:
        return "No relevant pages found.", []
    
    # Build image content for GPT-4o
    image_content = []
    sources = []
    
    for doc, metadata in zip(retrieved_results["documents"][0], retrieved_results["metadatas"][0]):
        image_path = metadata["image_path"]
        
        if not os.path.exists(image_path):
            continue
        
        with open(image_path, "rb") as f:
            base64_image = base64.b64encode(f.read()).decode("utf-8")
        
        image_content.append({
            "type": "image_url",
            "image_url": {"url": f"data:image/png;base64,{base64_image}"}
        })
        image_content.append({
            "type": "text",
            "text": f"[Page {metadata['page_number']} from {metadata['source_pdf']}]"
        })
        
        sources.append(f"{metadata['source_pdf']}, Page {metadata['page_number']}")
    
    # Generate with GPT-4o
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "system",
                "content": """You answer questions about IKEA assembly based on instruction pages.
Be specific, reference page numbers when helpful, and say if something isn't clear from the images."""
            },
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": f"Question: {query}\n\nRelevant instruction pages:"},
                    *image_content,
                    {"type": "text", "text": "Answer based on these pages."}
                ]
            }
        ],
        max_tokens=600
    )
    
    return response.choices[0].message.content, sources


def answer_question(query):
    """Full RAG pipeline."""
    print(f"\nQuery: {query}")
    print("-" * 50)
    
    print("Retrieving relevant pages...")
    results = retrieve(query)
    print(f"  Found {len(results['ids'][0])} pages")
    
    print("Generating answer...")
    answer, sources = generate_answer(query, results)
    
    return answer, sources


def main():
    # Check index exists
    try:
        collection = chroma_client.get_collection(name=COLLECTION_NAME)
        print(f"Connected to index ({collection.count()} documents)")
    except:
        print("ERROR: Index not found. Run step2_index.py first.")
        return
    
    # Single query from command line
    if len(sys.argv) > 1:
        query = " ".join(sys.argv[1:])
        answer, sources = answer_question(query)
        print(f"\nAnswer:\n{answer}")
        print(f"\nSources: {', '.join(sources)}")
        return
    
    # Interactive mode
    print("\nAsk questions about IKEA assembly. Type 'quit' to exit.\n")
    
    while True:
        try:
            query = input("Question: ").strip()
        except KeyboardInterrupt:
            break
        
        if not query or query.lower() in ["quit", "exit"]:
            break
        
        answer, sources = answer_question(query)
        print(f"\nAnswer:\n{answer}")
        print(f"\nSources: {', '.join(sources)}\n")


if __name__ == "__main__":
    main()

Temel fonksiyonların açıklaması:

  • get_embedding(text): text-embedding-3-small kullanarak sorgu için bir vektör gömme üretir; bu sayede ChromaDB’de anlamsal benzerlik araması yapılabilir.​

  • retrieve(query, top_k=TOP_K): sorguyu gömer, koleksiyonda en yakın top-k komşuyu arar ve include=["documents", "metadatas"] ile belgeleri ve üst verileri (ör. görsel yolları) döndürür.​

  • generate_answer(query, retrieved_results): en iyi görselleri base64 olarak yükler, sayfa etiketleri ve görselleri iç içe geçirerek multimodal bir GPT-4o istemi kurar ve IKEA’ya özgü ayrıntılı bir yanıt üretir.​

  • answer_question(query): getirme ve üretimi orkestre eder, ilerleme günlüğü verir.

  • main(): dizinin varlığını doğrular, CLI tekli sorguları veya etkileşimli sohbet modunu destekler (“quit”, “exit” veya Ctrl+C ile çıkış).

Adım 5: RAG hattını çalıştırma

Betiği çalıştırıp sorunuzu yazabilir veya doğrudan belirli bir soruyla çalıştırabilirsiniz, örneğin:

python step4_query.py "How do I attach the legs to the desk?"
Retrieving relevant pages...
Found 3 pages
Generating answer...

Answer:
To attach the legs to the MALM desk, follow these steps shown on pages 5-6:

1. First, insert the wooden dowels into the pre-drilled holes on the leg 
   pieces (you'll see "4x" indicating four dowels are needed)

2. Apply the cam locks to the desk top using the Phillips screwdriver

3. Align each leg with the corresponding holes on the underside of the desk

4. Tighten the cam locks by rotating them clockwise until the legs are 
   firmly attached

The instructions show this should be done with the desk top face-down on 
a soft surface to avoid scratching.

Sources: malm_desk.pdf, Page 5, malm_desk.pdf, Page 6, malm_desk.pdf, Page 7

Güzel görünüyor! Sistem, betimlere göre sayfaları getiriyor, gerçek görselleri yüklüyor ve GPT-4o diyagramlara doğrudan bakarak bir yanıt üretiyor.

Multimodal RAG Değerlendirmesi

Bir multimodal RAG sistemi kurmak bir şeydir. İyi çalışıp çalışmadığını bilmek başka bir şey. Bunu üretimde güvenilir şekilde çalıştırmak ise bir katman daha zorluk ekler. 

Standart RAG ölçütleri hâlâ geçerlidir, ancak görsel içerik için bunları genişletmeniz gerekir.

Getirme kalitesi

Precision@k, getirilen sayfalarınızın kaçının gerçekten ilgili olduğunu ölçer. İlk k’da alakasız sayfaları cezalandırır, ancak üretim için kilit görselin elde edilmesi, mükemmel top-k’ya ulaşmaktan daha önemlidir.

Recall@k, doğru sayfaların ilk k sonucunuzda ne sıklıkla göründüğünü ölçer. IKEA RAG kullanımınız için daha ilgili olan budur; çünkü sistemin ilk k (ör. k=3) sonuçta en az bir ilgili sayfayı bulmasını isteriz. Böylece GPT-4o, diğer sonuçlar gürültü olsa bile doğru yanıt için görsel bağlam alır. 

IKEA sistemimiz için, yaklaşık 50 soruluk bir test seti oluşturup her biri için “doğru” sayfaları etiketlersiniz. Sonra şu fonksiyonla değerlendirebilirsiniz:

def evaluate_retrieval(test_cases, top_k=3):
    """
    test_cases: [{"query": str, "relevant_pages": ["image_path1", ...]}]
    """
    hits = 0
    for test in test_cases:
        results = retrieve(test["query"], top_k=top_k)
        retrieved = [m["image_path"] for m in results["metadatas"][0]]
        if any(p in retrieved for p in test["relevant_pages"]):
            hits += 1
    return hits / len(test_cases)

Üretim kalitesi

Otomatik olarak ölçülmesi daha zor olan şey üretim kalitesidir. 

Yanıtları doğruluk ve faydalılık açısından insanlar değerlendirebilir veya bir LLM’i hakem olarak kullanıp yanıtların kaynak görsellere göre doğru olup olmadığını ölçebilirsiniz. 

Numaralandırılmış adımlar içeren diyagramlarda, modelin doğru adım numaralarını atayıp atamadığını doğrulayın.

Multimodal’e özgü kontroller

İlave değerlendirmeler şu soruları yanıtlayabilir:

  • Cevap görsel olduğunda sistem görsel tabanlı yanıtları bulabiliyor mu? 

  • Model bir görseldeki bir şeye atıfta bulunduğunda, bu atıf doğru mu? 

Bunlar, en azından bir sorgu örneklemi için, manuel inceleme gerektirir.

Multimodal RAG İçin En İyi Uygulamalar

Üretime hazır bir multimodal RAG hattı kurmak istiyorsanız, akılda tutulması gereken birkaç nokta var:

  • Ön işleme maliyetleri artar: Görsel betimleme için yapılan görsel çağrılar pahalı kısımdır. Büyük bir belge külliyatı için, yoğun olmayan saatlerde toplu işlem yapın ve betimleri agresif şekilde önbelleğe alın. Kalite kullanım durumunuza uygunsa (bizim örneğimizde olduğu gibi GPT-4o-mini gibi) daha ucuz bir modeli betimleme üretimi için değerlendirin.

  • Sorgu gecikmesi önemlidir: Görsellerle GPT-4o, sorgu başına 5 ila 10 saniye sürer. Akış, kullanıcıların kısmi sonuçları hızlıca görmesine yardımcı olur; sık sorulan sorguların önbelleğe alınması tekrar eden sorularda işe yarar. 5 yerine 2 sayfa getirmek, yeterli bağlam varsa, belirteç açısından fark yaratabilir.

  • Doğru şeyleri izleyin: Getirme gecikmesini (küçük koleksiyonlar için 100 ms altı olmalı), üretim gecikmesini (görsellerle 5-10 saniye beklenir), sorgu başına API maliyetlerini ve topluyorsanız kullanıcı geri bildirimini takip edin.

  • Hata yönetimi kurtarır: Şeyler bozulur. Aşağıdaki kod parçasında olduğu gibi geri dönüşler oluşturun.

def answer_question_safe(query):
    """Wrapper with error handling."""
    try:
        return answer_question(query)
    except Exception as e:
        print(f"Error: {e}")
        # Fall back to text-only using descriptions
        results = retrieve(query)
        if results["documents"][0]:
            context = results["documents"][0][0][:500]
            return f"Based on the instructions: {context}...", []
        return "Sorry, couldn't process that question.", []

Boru hattınız birden çok adım atmak zorundaysa (ara → doğrula → yeniden ara → yanıtla), ajan tabanlı RAG desenleri bunu temiz bir şekilde yapılandırmanıza yardımcı olur.

Sonuç

Multimodal RAG, gerçek dünyadaki belgelerde yer alan görseller, diyagramlar, tablolar ve grafikler de dahil olmak üzere içeriklerin tüm yelpazesini işlemek için geri getirme ile artırılmış üretimi genişletir. 

Metin ağırlıklı bir yaklaşımın işe yaramayacağı, son derece görsel IKEA talimatlarını sorgulamak için bunu başarıyla kullandık. Tüm boru hattı, API çağrıları dışında yerelde çalışır.

Önemli içgörü şudur: Bunun çalışması için karmaşık multimodal gömelere ihtiyacınız yok. Görsel içeriğin iyi metin betimlerini üreterek, ilgili görselleri bulmak için standart metin getirmeyi kullanabilir, ardından üretim aşamasında asıl işi bir görüntü-dil modeline bırakabilirsiniz.

Burada ele aldıklarımızı temel alarak ilerlemek isterseniz, bugün Yapay Zekâ Mühendisi kariyer yolculuğunuza başlayın!

Multimodal RAG SSS

Multimodal RAG hangi veri türlerini işleyebilir?

Görseller, grafik, tablo ve diyagram içeren PDF’ler, ses (deşifreler aracılığıyla) ve video ana kareleri. Temelde, bir soruyu yanıtlarken yapay zekânın referans vermesini isteyeceğiniz her tür içerik.

Farklı modaliteler için ayrı vektör veritabanlarına ihtiyacım var mı?

Gerekmez. Üretim sistemlerinin çoğu, birleşik bir gömme uzayı olan tek bir vektör deposu kullanır. Her şeyi aynı boyutta bir uzaya gömerek, getirme işlemini içerik türleri arasında da çalışır hâle getirebilirsiniz.

Tüm boru hattı için OpenAI kullanabilir miyim?

Evet. GPT-4o hem görsel anlama hem de yanıt üretimini yönetir; text-embedding-3-small ise vektör tarafını üstlenir. OpenAI ekosisteminden çıkmadan eksiksiz bir multimodal RAG sistemi kurabilirsiniz.

Multimodal RAG’de en büyük zorluk nedir?

Hizalama. Metin, görsel ve yapılandırılmış verileri aynı gömme uzayında bir arada tutmak; böylece getirme işleminin gerçekten modaliteler arasında çalışması. Parçalama (chunking) stratejisi de buna çok yakındır.

Çalıştırmanın maliyeti ne kadar?

Buradaki IKEA eğitiminde toplamda yaklaşık 2 $ bekleyin. Pahalı kısım, ön işleme sırasında görsellerin betimlenmesi için yapılan GPT-4o çağrılarıdır. Dizinlendikten sonra sorgular ucuzdur.

Josep Ferrer

Yazar

Josep Ferrer

Josep, Avrupa projelerine odaklanan serbest bir Veri Bilimcidir; veri depolama, işleme, ileri analitik ve etkili veri hikâyeleştirme konularında uzmandır. 

Eğitmen olarak Navarra Üniversitesi'nin Yüksek Lisans programında Büyük Veri dersleri vermekte ve Medium, KDNuggets ve DataCamp gibi platformlarda yayımladığı makalelerle görüşlerini paylaşmaktadır. Josep ayrıca Databites bülteninde (databites.tech) Veri ve Teknoloji üzerine yazmaktadır. 

Katalonya Politeknik Üniversitesi'nden Mühendislik Fiziği lisans derecesine ve Pompeu Fabra Üniversitesi'nden Akıllı Etkileşimli Sistemler yüksek lisans derecesine sahiptir.

Konular

İlgili