Trung cấpHướng dẫnClaude APINguồn: Anthropic

Multi-Modal RAG với LlamaIndex + Claude Vision

Nghe bài viết
00:00

Điểm nổi bật

Nhấn để đến mục tương ứng

  1. 1 Để áp dụng kiến trúc multi-modal rag hiệu quả, bạn cần nắm rõ: Hai chiến lược chính: Image Captioning — Dùng Claude Vision để mô tả ảnh thành text, rồi index text đó. Đơn giản hơn, tiết kiệm chi phí. Multi-Modal Embedding — Embed trực tiếp ảnh thành vector cần model đặc biệt — đây là bước quan trọng giúp tối ưu quy trình làm việc với AI trong thực tế.
  2. 2 Điểm cần cân nhắc khi sử dụng step 1: image caption với claude vision: Claude Vision phân tích hình ảnh và tạo description chi tiết để index: """Encode image file thành base64 string.""" with openimage_path, "rb" as f: image_data f.read return base64.standard_b64encodeimage_data.decode"utf-8" context"": """ Dùng Claude Vision để tạo caption chi tiết cho ảnh. Args: image_path: Đường dẫn đến — không phải mọi trường hợp đều phù hợp, cần đánh giá bối cảnh cụ thể trước khi áp dụng.
  3. 3 Kết quả đo lường từ step 2: extract images từ pdf: # PyMuPDF output_dir"./extracted_images": """ Extract text và images từ PDF, tạo LlamaIndex documents. Returns: List of LlamaDocument objects text + image captions """ Pathoutput_dir.mkdirparentsTrue, exist_okTrue pdf_doc fitz.openpdf_path documents pdf_name Pathpdf_path.stem for page_num, page in enumeratepdf_doc, 1: # Extract — các chỉ số cụ thể này giúp bạn đánh giá chính xác hiệu quả trước khi đầu tư nguồn lực.
  4. 4 Khi triển khai step 3: index tất cả content, điều cốt lõi là image_pathsNone, pdf_pathsNone: """ Xây dựng unified index từ nhiều loại content. """ all_documents # Process text documents if text_docs: all_documents.extendtext_docs # Process standalone images if image_paths: for img_path in image_paths: printf"Processing image: img_path" caption caption_imageimg_path all_documents.appendLlamaDocume — hiểu đúng nguyên lý này giúp bạn tránh sai lầm phổ biến và đạt kết quả tốt hơn ngay từ đầu.
  5. 5 Về step 4: multi-modal query, thực tế cho thấy question, include_image_contextTrue: """ Query multi-modal index và trả về câu trả lời với source information. """ query_engine index.as_query_engine similarity_top_k5, response_mode"compact" response query_engine.queryquestion # Phân loại sources text_sources image_sources for node in response.source_nodes: doc_type node.metadata.get"type" — đây là con dao hai lưỡi nếu không hiểu rõ giới hạn và điều kiện áp dụng của nó.
A white robot is standing in front of a black background

Traditional RAG chỉ xử lý text. Nhưng thực tế, nhiều tài liệu quan trọng chứa hình ảnh, biểu đồ, sơ đồ, và screenshots. Multi-Modal RAG kết hợp LlamaIndex với Claude Vision để index và query trên cả text lẫn hình ảnh — mở ra khả năng hiểu tài liệu toàn diện hơn.

Ví dụ use cases: phân tích PDF kỹ thuật có biểu đồ, tìm kiếm trong thư viện ảnh sản phẩm, hoặc Q&A trên presentation slides.

Kiến trúc Multi-Modal RAG

Hai chiến lược chính:

  1. Image Captioning — Dùng Claude Vision để mô tả ảnh thành text, rồi index text đó. Đơn giản hơn, tiết kiệm chi phí.
  2. Multi-Modal Embedding — Embed trực tiếp ảnh thành vector (cần model đặc biệt). Tốt hơn cho visual similarity search.

Bài này tập trung vào Image Captioning — phổ biến và dễ implement hơn.

Cài đặt

pip install llama-index llama-index-llms-anthropic llama-index-embeddings-voyageai Pillow pymupdf
import os
import base64
import anthropic
from pathlib import Path
from PIL import Image
import io

from llama_index.core import Settings, VectorStoreIndex
from llama_index.core import Document as LlamaDocument
from llama_index.llms.anthropic import Anthropic
from llama_index.embeddings.voyageai import VoyageEmbedding

# Setup
claude = anthropic.Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))

Settings.llm = Anthropic(model="claude-opus-4-5", max_tokens=2048)
Settings.embed_model = VoyageEmbedding(
    model_name="voyage-3",
    voyage_api_key=os.environ.get("VOYAGE_API_KEY")
)

print("Multi-Modal RAG ready")

Step 1: Image Caption với Claude Vision

Claude Vision phân tích hình ảnh và tạo description chi tiết để index:

def encode_image_base64(image_path):
    """Encode image file thành base64 string."""
    with open(image_path, "rb") as f:
        image_data = f.read()
    return base64.standard_b64encode(image_data).decode("utf-8")

def caption_image(image_path, context=""):
    """
    Dùng Claude Vision để tạo caption chi tiết cho ảnh.

    Args:
        image_path: Đường dẫn đến image file
        context: Context bổ sung (tên tài liệu, page number...)

    Returns:
        String mô tả chi tiết về hình ảnh
    """
    # Xác định media type
    suffix = Path(image_path).suffix.lower()
    media_types = {
        ".jpg": "image/jpeg",
        ".jpeg": "image/jpeg",
        ".png": "image/png",
        ".gif": "image/gif",
        ".webp": "image/webp"
    }
    media_type = media_types.get(suffix, "image/jpeg")

    image_b64 = encode_image_base64(image_path)

    context_str = f"
Context: {context}" if context else ""

    response = claude.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "image",
                        "source": {
                            "type": "base64",
                            "media_type": media_type,
                            "data": image_b64
                        }
                    },
                    {
                        "type": "text",
                        "text": f"""Mô tả chi tiết hình ảnh này để dùng trong hệ thống tìm kiếm.
Bao gồm:{context_str}
- Loại hình ảnh (biểu đồ, sơ đồ, ảnh, screenshot, v.v.)
- Nội dung chính và các elements quan trọng
- Số liệu, text, labels nếu có
- Màu sắc, trend, pattern đáng chú ý
- Ý nghĩa hoặc insight từ hình ảnh

Viết mô tả đầy đủ bằng tiếng Việt để có thể search được."""
                    }
                ]
            }
        ]
    )

    return response.content[0].text

# Test với ảnh mẫu
# caption = caption_image("chart.png", context="Revenue chart from Q1 2024 report")
# print(caption)

Step 2: Extract Images từ PDF

import fitz  # PyMuPDF

def extract_pdf_content(pdf_path, output_dir="./extracted_images"):
    """
    Extract text và images từ PDF, tạo LlamaIndex documents.

    Returns:
        List of LlamaDocument objects (text + image captions)
    """
    Path(output_dir).mkdir(parents=True, exist_ok=True)

    pdf_doc = fitz.open(pdf_path)
    documents = []
    pdf_name = Path(pdf_path).stem

    for page_num, page in enumerate(pdf_doc, 1):
        # Extract text từ page
        page_text = page.get_text()
        if page_text.strip():
            documents.append(LlamaDocument(
                text=page_text,
                metadata={
                    "source": pdf_name,
                    "type": "text",
                    "page": page_num
                }
            ))

        # Extract images từ page
        image_list = page.get_images(full=True)
        for img_idx, img in enumerate(image_list):
            xref = img[0]
            base_image = pdf_doc.extract_image(xref)
            image_bytes = base_image["image"]
            image_ext = base_image["ext"]

            # Lưu image
            image_path = f"{output_dir}/{pdf_name}_p{page_num}_img{img_idx}.{image_ext}"
            with open(image_path, "wb") as f:
                f.write(image_bytes)

            # Tạo caption với Claude Vision
            print(f"  Captioning image: page {page_num}, image {img_idx}")
            caption = caption_image(
                image_path,
                context=f"Page {page_num} of {pdf_name}"
            )

            # Tạo document từ caption
            documents.append(LlamaDocument(
                text=f"[IMAGE DESCRIPTION - Page {page_num}]
{caption}",
                metadata={
                    "source": pdf_name,
                    "type": "image",
                    "page": page_num,
                    "image_path": image_path
                }
            ))

    pdf_doc.close()
    print(f"Extracted {len(documents)} documents from {pdf_name}")
    return documents

Step 3: Index tất cả Content

def build_multimodal_index(text_docs=None, image_paths=None, pdf_paths=None):
    """
    Xây dựng unified index từ nhiều loại content.
    """
    all_documents = []

    # Process text documents
    if text_docs:
        all_documents.extend(text_docs)

    # Process standalone images
    if image_paths:
        for img_path in image_paths:
            print(f"Processing image: {img_path}")
            caption = caption_image(img_path)
            all_documents.append(LlamaDocument(
                text=f"[IMAGE: {Path(img_path).name}]
{caption}",
                metadata={
                    "source": Path(img_path).name,
                    "type": "image",
                    "image_path": img_path
                }
            ))

    # Process PDFs
    if pdf_paths:
        for pdf_path in pdf_paths:
            print(f"
Processing PDF: {pdf_path}")
            docs = extract_pdf_content(pdf_path)
            all_documents.extend(docs)

    print(f"
Total documents to index: {len(all_documents)}")

    # Tạo vector index
    index = VectorStoreIndex.from_documents(
        all_documents,
        show_progress=True
    )

    return index

Step 4: Multi-Modal Query

def multimodal_rag_query(index, question, include_image_context=True):
    """
    Query multi-modal index và trả về câu trả lời với source information.
    """
    query_engine = index.as_query_engine(
        similarity_top_k=5,
        response_mode="compact"
    )

    response = query_engine.query(question)

    # Phân loại sources
    text_sources = []
    image_sources = []

    for node in response.source_nodes:
        doc_type = node.metadata.get("type", "text")
        if doc_type == "image":
            image_sources.append(node)
        else:
            text_sources.append(node)

    result = {
        "answer": response.response,
        "text_sources": len(text_sources),
        "image_sources": len(image_sources),
        "source_details": [
            {
                "type": node.metadata.get("type"),
                "source": node.metadata.get("source"),
                "page": node.metadata.get("page"),
                "score": node.score
            }
            for node in response.source_nodes
        ]
    }

    return result

# Ví dụ sử dụng
text_documents = [
    LlamaDocument(
        text="Doanh thu Q1 2024 của công ty đạt 5.2 tỷ đồng, tăng 23% so với Q1 2023.",
        metadata={"source": "annual_report", "type": "text", "page": 1}
    ),
    LlamaDocument(
        text="Biểu đồ tăng trưởng cho thấy xu hướng tích cực trong 4 quý liên tiếp.",
        metadata={"source": "annual_report", "type": "text", "page": 2}
    )
]

# Build index (trong thực tế sẽ include images và PDFs)
index = VectorStoreIndex.from_documents(text_documents, show_progress=False)

# Query
result = multimodal_rag_query(
    index,
    "Doanh thu Q1 2024 tăng bao nhiêu phần trăm?"
)
print(f"Answer: {result['answer']}")
print(f"Sources: {result['text_sources']} text, {result['image_sources']} images")

Advanced: Query với hình ảnh

Bạn cũng có thể query bằng cách gửi ảnh — tìm documents liên quan đến hình ảnh:

def query_with_image(index, image_path, question=""):
    """
    Query index sử dụng image làm query (kết hợp với text question).
    """
    # Tạo caption cho query image
    image_caption = caption_image(image_path)

    # Kết hợp caption với question
    combined_query = image_caption
    if question:
        combined_query = f"{question}

Hình ảnh liên quan: {image_caption}"

    return multimodal_rag_query(index, combined_query)

Kết luận

Multi-Modal RAG mở rộng khả năng của RAG truyền thống sang thế giới visual. Claude Vision đặc biệt mạnh trong việc hiểu biểu đồ, sơ đồ kỹ thuật, và screenshots — tạo ra captions phong phú có thể search được.

Bước tiếp theo: Khám phá Router Query Engine để tự động chọn index phù hợp, hoặc đọc về SubQuestion Engine để phân tách câu hỏi phức tạp thành sub-queries.


Bài viết liên quan

Tính năng liên quan:MultimodalVisionRAGLlamaIndexImage Understanding

Bai viet co huu ich khong?

Bản quyền thuộc về tác giả. Vui lòng dẫn nguồn khi chia sẻ.

Bình luận (0)
Ảnh đại diện
Đăng nhập để bình luận...
Đăng nhập để bình luận
  • Đang tải bình luận...

Đăng ký nhận bản tin

Nhận bài viết hay nhất về sản phẩm và vận hành, gửi thẳng vào hộp thư của bạn.

Bảo mật thông tin. Hủy đăng ký bất cứ lúc nào. Chính sách bảo mật.