AnleitungExperte

RAG für Bilder: Vision models und visuelle Suche

19. März 2026
25 Min. Lesezeit
Équipe Ailog

Umfassender Leitfaden zur Integration von Bildern in Ihr RAG-System: Vision models, multimodal embeddings, Indexierung und visuelle Suche mit GPT-4V, Claude Vision und CLIP.

RAG für Bilder: Vision-Modelle und visuelle Suche

Die traditionellen RAG-Systeme beschränken sich auf Text. Dabei sind viele Unternehmensinformationen visuell: Produktfotos, Screenshots, Grafiken, technische Zeichnungen. Image RAG erlaubt es, in diesen visuellen Inhalten mit derselben Präzision wie bei einem textuellen RAG zu indexieren und zu suchen.

Warum Bilder in den RAG integrieren?

Visuelle Daten im Unternehmen

  • E-commerce : 70% der Kaufentscheidungen werden durch Produktbilder beeinflusst
  • Support technique : Screenshots beschleunigen die Lösung von Tickets um 60%
  • Documentation : Eine Grafik ist oft mehr wert als eine Seite Text
  • Conformité : Baustellenfotos, Zustandsdokumentationen, visuelle Belege

Konkrete Anwendungsfälle

SecteurUsageExemple de requête
E-commerceRecherche visuelle"Trouve des robes similaires à cette photo"
ImmobilierAnalyse de biens"Montre-moi des cuisines équipées modernes"
Support ITDiagnostic"Quel est ce message d'erreur ?"
ManufacturingContrôle qualité"Cette pièce présente-t-elle un défaut ?"

Architektur eines Image RAG

Gesamtübersicht

┌─────────────────────────────────────────────────────────────┐
│                    IMAGE RAG PIPELINE                        │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌──────────┐    ┌──────────────┐    ┌──────────────────┐  │
│  │  Image   │───▶│   Vision     │───▶│   Embedding      │  │
│  │  Input   │    │   Model      │    │   (CLIP/SigLIP)  │  │
│  └──────────┘    └──────────────┘    └──────────────────┘  │
│       │                │                      │             │
│       │                ▼                      ▼             │
│       │         ┌──────────────┐    ┌──────────────────┐   │
│       │         │  Description │    │  Vector Store    │   │
│       │         │  textuelle   │    │  (Qdrant/Pine)   │   │
│       │         └──────────────┘    └──────────────────┘   │
│       │                │                      │             │
│       │                ▼                      ▼             │
│       │         ┌─────────────────────────────────┐        │
│       └────────▶│      Retrieval multimodal       │        │
│                 └─────────────────────────────────┘        │
│                                │                            │
│                                ▼                            │
│                 ┌─────────────────────────────────┐        │
│                 │      Génération (VLM/LLM)       │        │
│                 └─────────────────────────────────┘        │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Die zwei Ansätze

1. Description + RAG textuel

  • Das Vision-Model beschreibt das Bild in Text
  • Der Text wird klassisch indexiert
  • Einfacher, verliert jedoch visuelle Informationen

2. Native multimodale Embeddings

  • Das Bild wird direkt in einen Vektor konvertiert
  • Bewahrt die vollständige visuelle Information
  • Ermöglicht Bild-zu-Bild-Suche

Vision-Modelle für den RAG

Proprietäre Modelle

ModèleRésolution maxCoûtForces
GPT-4V2048x2048$0.00765/image (low)Raisonnement complexe, OCR excellent
Claude 3.5 Sonnet Vision8192x8192$0.003/imageAnalyse détaillée, sécurité
Gemini 1.5 ProIllimité$0.001315/imageMulti-images, contexte long

Open-Source-Modelle

ModèleParamsVRAMUsage
LLaVA 1.634B24GBDescription générale
CogVLM219B16GBCompréhension fine
InternVL276B48GBPerformance SOTA
Qwen-VL-Max72B48GBMultilingue

Multimodale Embedding-Modelle

ModèleDimensionLanguesOpen source
CLIP (OpenAI)512/768EN principalementOui
SigLIP384-1152MultilingueOui
Jina CLIP v2102489 languesOui
Cohere Embed v31024100+ languesNon

Praktische Implementierung

Étape 1 : Extraction et description des images

DEVELOPERpython
import base64 from openai import OpenAI def describe_image_for_rag(image_path: str, context: str = "") -> dict: """ Erzeugt eine RAG-optimierte Beschreibung eines Bildes. """ client = OpenAI() # Das Bild in base64 kodieren with open(image_path, "rb") as f: image_data = base64.b64encode(f.read()).decode("utf-8") # Den MIME-Typ bestimmen mime_type = "image/jpeg" if image_path.endswith((".jpg", ".jpeg")) else "image/png" prompt = """Analyse cette image pour un système RAG. Fournis: 1. **Description générale** (2-3 phrases) 2. **Éléments clés** (liste à puces des objets/concepts importants) 3. **Texte visible** (tout texte lisible dans l'image) 4. **Métadonnées suggérées** (catégorie, tags pertinents) Sois exhaustif mais concis. L'objectif est de permettre la recherche textuelle sur cette image.""" if context: prompt += f"\n\nContexte additionnel: {context}" response = client.chat.completions.create( model="gpt-4o", messages=[ { "role": "user", "content": [ {"type": "text", "text": prompt}, { "type": "image_url", "image_url": { "url": f"data:{mime_type};base64,{image_data}", "detail": "high" } } ] } ], max_tokens=1000 ) description = response.choices[0].message.content return { "image_path": image_path, "description": description, "model": "gpt-4o", "tokens_used": response.usage.total_tokens }

Étape 2 : Embeddings multimodaux avec CLIP

DEVELOPERpython
import torch from PIL import Image from transformers import CLIPProcessor, CLIPModel class MultimodalEmbedder: def __init__(self, model_name: str = "openai/clip-vit-large-patch14"): self.device = "cuda" if torch.cuda.is_available() else "cpu" self.model = CLIPModel.from_pretrained(model_name).to(self.device) self.processor = CLIPProcessor.from_pretrained(model_name) def embed_image(self, image_path: str) -> list[float]: """Erzeugt ein Embedding für ein Bild.""" image = Image.open(image_path).convert("RGB") inputs = self.processor(images=image, return_tensors="pt").to(self.device) with torch.no_grad(): embedding = self.model.get_image_features(**inputs) # Für Kosinusähnlichkeit normalisieren embedding = embedding / embedding.norm(dim=-1, keepdim=True) return embedding.cpu().squeeze().tolist() def embed_text(self, text: str) -> list[float]: """Erzeugt ein Embedding für Text (im selben Raum wie die Bilder).""" inputs = self.processor(text=[text], return_tensors="pt", padding=True).to(self.device) with torch.no_grad(): embedding = self.model.get_text_features(**inputs) embedding = embedding / embedding.norm(dim=-1, keepdim=True) return embedding.cpu().squeeze().tolist() def compute_similarity(self, image_path: str, text: str) -> float: """Berechnet die Ähnlichkeit Bild-zu-Text.""" img_emb = torch.tensor(self.embed_image(image_path)) txt_emb = torch.tensor(self.embed_text(text)) return (img_emb @ txt_emb).item()

Étape 3 : Indexation dans Qdrant

DEVELOPERpython
from qdrant_client import QdrantClient from qdrant_client.models import ( VectorParams, Distance, PointStruct, Filter, FieldCondition, MatchValue ) class ImageRAGIndex: def __init__(self, collection_name: str = "image_rag"): self.client = QdrantClient(url="http://localhost:6333") self.collection_name = collection_name self.embedder = MultimodalEmbedder() def create_collection(self, vector_size: int = 768): """Erstellt die Collection mit zwei Vektorräumen.""" self.client.recreate_collection( collection_name=self.collection_name, vectors_config={ # Visuelles Embedding (CLIP) "visual": VectorParams( size=vector_size, distance=Distance.COSINE ), # Textuelles Embedding (Beschreibung) "textual": VectorParams( size=1536, # Ada-002 oder ähnlich distance=Distance.COSINE ) } ) def index_image( self, image_id: str, image_path: str, description: str, text_embedding: list[float], metadata: dict = None ): """Indexiert ein Bild mit seinen beiden Embeddings.""" visual_embedding = self.embedder.embed_image(image_path) point = PointStruct( id=hash(image_id) % (2**63), vector={ "visual": visual_embedding, "textual": text_embedding }, payload={ "image_id": image_id, "image_path": image_path, "description": description, **(metadata or {}) } ) self.client.upsert( collection_name=self.collection_name, points=[point] ) def search_by_text(self, query: str, limit: int = 5) -> list[dict]: """Suche mittels textueller Anfrage.""" query_embedding = self.embedder.embed_text(query) results = self.client.search( collection_name=self.collection_name, query_vector=("visual", query_embedding), # CLIP text -> visual limit=limit ) return [ { "image_path": r.payload["image_path"], "description": r.payload["description"], "score": r.score } for r in results ] def search_by_image(self, image_path: str, limit: int = 5) -> list[dict]: """Suche nach ähnlichen Bildern.""" query_embedding = self.embedder.embed_image(image_path) results = self.client.search( collection_name=self.collection_name, query_vector=("visual", query_embedding), limit=limit ) return [ { "image_path": r.payload["image_path"], "description": r.payload["description"], "score": r.score } for r in results ]

Étape 4 : Génération avec contexte visuel

DEVELOPERpython
def generate_with_images( query: str, retrieved_images: list[dict], client: OpenAI ) -> str: """ Erzeugt eine Antwort unter Verwendung der abgerufenen Bilder als Kontext. """ # Den multimodalen Inhalt vorbereiten content = [ { "type": "text", "text": f"""Tu es un assistant qui répond aux questions en utilisant les images fournies comme source d'information. Question de l'utilisateur: {query} Images disponibles:""" } ] # Jedes Bild mit seiner Beschreibung hinzufügen for i, img in enumerate(retrieved_images[:3], 1): # Max 3 Bilder with open(img["image_path"], "rb") as f: img_data = base64.b64encode(f.read()).decode("utf-8") content.append({ "type": "text", "text": f"\n**Image {i}** (score: {img['score']:.2f}):\n{img['description']}" }) content.append({ "type": "image_url", "image_url": { "url": f"data:image/jpeg;base64,{img_data}", "detail": "low" # Tokens sparen } }) content.append({ "type": "text", "text": "\n\nRéponds à la question en te basant uniquement sur ces images. Si les images ne permettent pas de répondre, dis-le clairement." }) response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": content}], max_tokens=1000 ) return response.choices[0].message.content

Erweiterte Optimierungen

Chunking hochauflösender Bilder

Für sehr große Bilder (Pläne, Schaubilder) in Kacheln schneiden:

DEVELOPERpython
from PIL import Image def tile_large_image(image_path: str, tile_size: int = 512, overlap: int = 64): """Zerteilt ein großes Bild in überlappende Kacheln.""" img = Image.open(image_path) width, height = img.size tiles = [] for y in range(0, height - overlap, tile_size - overlap): for x in range(0, width - overlap, tile_size - overlap): box = (x, y, min(x + tile_size, width), min(y + tile_size, height)) tile = img.crop(box) tiles.append({ "tile": tile, "position": (x, y), "original_size": (width, height) }) return tiles

Hybride Suche Bild + Text

DEVELOPERpython
def hybrid_image_search( query: str, text_embedding: list[float], index: ImageRAGIndex, alpha: float = 0.7 # Gewicht visuell vs. textuell ) -> list[dict]: """Kombiniert visuelle und textuelle Suche.""" # Visuelle Suche (CLIP) visual_results = index.search_by_text(query, limit=20) # Textuelle Suche (auf den Beschreibungen) text_results = index.client.search( collection_name=index.collection_name, query_vector=("textual", text_embedding), limit=20 ) # Scores mit RRF zusammenführen combined_scores = {} for rank, r in enumerate(visual_results): img_id = r["image_path"] combined_scores[img_id] = combined_scores.get(img_id, 0) + alpha / (rank + 60) for rank, r in enumerate(text_results): img_id = r.payload["image_path"] combined_scores[img_id] = combined_scores.get(img_id, 0) + (1 - alpha) / (rank + 60) # Nach kombiniertem Score sortieren sorted_results = sorted(combined_scores.items(), key=lambda x: x[1], reverse=True) return [{"image_path": path, "score": score} for path, score in sorted_results[:5]]

Benchmarks und Kosten

Retrieval-Performance

MéthodePrecision@5Recall@10Latence
Description seule0.720.8150ms
CLIP seul0.780.8530ms
Hybride0.840.9180ms

Kosten pro indexiertem Bild

ÉtapeCoût estiméNotes
Description GPT-4V$0.01-0.03Selon taille et détail
Embedding CLIP$0 (local)GPU recommandé
Stockage Qdrant~$0.0001Par vecteur/mois

Vergleich der Embedding-Modelle

ModèleZero-shot accuracyMultilingueVitesse
CLIP ViT-L/1475.5%NonRapide
SigLIP So400m83.1%OuiMoyen
Jina CLIP v281.2%OuiRapide

Fallstricke und Lösungen

Problème 1 : Images avec peu de contenu visuel

Symptôme : Screenshots mit viel Text werden von CLIP schlecht indexiert.

Solution : Explizites OCR + textuelle Indexierung.

DEVELOPERpython
import pytesseract def extract_text_from_image(image_path: str) -> str: """Extrahiert Text aus einem Bild mittels OCR.""" img = Image.open(image_path) text = pytesseract.image_to_string(img, lang='fra+eng') return text.strip()

Problème 2 : Doublons visuels

Symptôme : Mehrere nahezu identische Bilder verschmutzen die Ergebnisse.

Solution : Deduplizierung per Ähnlichkeit.

DEVELOPERpython
def deduplicate_images(embeddings: list, threshold: float = 0.95): """Entfernt zu ähnliche Bilder.""" keep = [] for i, emb in enumerate(embeddings): is_duplicate = False for j in keep: similarity = cosine_similarity(emb, embeddings[j]) if similarity > threshold: is_duplicate = True break if not is_duplicate: keep.append(i) return keep

Problème 3 : Contexte visuel vs textuel contradictoire

Symptôme : Die generierte Beschreibung widerspricht dem Bild.

Solution : Kreuzvalidierung und Vertrauensscore.

Integration mit Ailog

Ailog unterstützt nativ die Indexierung von Bildern in euren Knowledge Bases:

  1. Upload : Bilder per Drag & Drop in die Oberfläche ziehen
  2. Analyse automatique : Vision-Model zur Inhaltsextraktion
  3. Indexation hybride : Visuelle + textuelle Embeddings
  4. Recherche unifiée : Eine einzige Anfrage für Text und Bilder

Essayez l'Image RAG sur Ailog - Keine Konfiguration erforderlich.

FAQ

CLIP erzeugt multimodale Embeddings, die Bild-zu-Bild- und Text-zu-Bild-Suche direkt ermöglichen. GPT-4V analysiert und beschreibt Bilder in detailliertem Text. Praktisch kombiniert man beides: CLIP für schnelles retrieval und GPT-4V für tiefgehende Analyse und kontextuelle Antwortgenerierung.
Rechnet mit etwa 10–30 Dollar für 1000 Bilder mit GPT-4V (Beschreibung) plus den CLIP-Embeddings (lokal kostenlos). Die Hauptkosten entstehen durch die initiale Beschreibung. Nach der Indexierung kosten die Suchen nur noch die Embeddings der Anfrage und die Kosten für die Antwortgenerierung.
Ja, aber mit Einschränkungen. CLIP kann auf CPU laufen (langsamer), und man kann Cloud-APIs (OpenAI, Anthropic) für die Vision-Models nutzen. Für produktive Systeme mit vielen Bildern beschleunigt ein GPU die Initialindexierung erheblich und reduziert langfristig die Kosten.
Vision-Modelle wie GPT-4V haben ein exzellentes eingebautes OCR, aber für textlastige Dokumente kombiniert man die Ansätze: Text via dediziertem OCR (Tesseract, Azure Document Intelligence) extrahieren und separat indexieren. Das verbessert die textuelle Suche und erhält gleichzeitig den visuellen Kontext.
Absolument. C'est même un cas d'usage idéal. Indexez les photos produits avec leurs descriptions générées, puis permettez aux clients de rechercher visuellement ("trouve des robes similaires"). Pour les grands catalogues, utilisez Qdrant ou Pinecone avec des index optimisés pour les recherches à grande échelle.

Verwandte Guides

Tags

RAGmultimodalvisionimagesGPT-4VClaude VisionCLIPembeddings

Verwandte Artikel

Ailog Assistant

Ici pour vous aider

Salut ! Pose-moi des questions sur Ailog et comment intégrer votre RAG dans vos projets !