{"product_id":"multi-modal-rag-với-llamaindex-claude-vision","title":"Multi-Modal RAG với LlamaIndex + Claude Vision","description":"\n\u003cp\u003eTraditional RAG chỉ xử lý text. Nhưng thực tế, nhiều tài liệu quan trọng chứa \u003cstrong\u003ehình ảnh, biểu đồ, sơ đồ, và screenshots\u003c\/strong\u003e. \u003cstrong\u003eMulti-Modal RAG\u003c\/strong\u003e 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.\u003c\/p\u003e\n\n\u003cp\u003eVí 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\u0026amp;A trên presentation slides.\u003c\/p\u003e\n\n\u003ch2\u003eKiến trúc Multi-Modal RAG\u003c\/h2\u003e\n\n\u003cp\u003eHai chiến lược chính:\u003c\/p\u003e\n\n\u003col\u003e\n  \u003cli\u003e\n\u003cstrong\u003eImage Captioning\u003c\/strong\u003e — 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í.\u003c\/li\u003e\n  \u003cli\u003e\n\u003cstrong\u003eMulti-Modal Embedding\u003c\/strong\u003e — Embed trực tiếp ảnh thành vector (cần model đặc biệt). Tốt hơn cho visual similarity search.\u003c\/li\u003e\n\u003c\/ol\u003e\n\n\u003cp\u003eBài này tập trung vào Image Captioning — phổ biến và dễ implement hơn.\u003c\/p\u003e\n\n\u003ch2\u003eCài đặt\u003c\/h2\u003e\n\n\u003cpre\u003e\u003ccode\u003epip install llama-index llama-index-llms-anthropic llama-index-embeddings-voyageai Pillow pymupdf\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003cpre\u003e\u003ccode\u003eimport os\nimport base64\nimport anthropic\nfrom pathlib import Path\nfrom PIL import Image\nimport io\n\nfrom llama_index.core import Settings, VectorStoreIndex\nfrom llama_index.core import Document as LlamaDocument\nfrom llama_index.llms.anthropic import Anthropic\nfrom llama_index.embeddings.voyageai import VoyageEmbedding\n\n# Setup\nclaude = anthropic.Anthropic(api_key=os.environ.get(\"ANTHROPIC_API_KEY\"))\n\nSettings.llm = Anthropic(model=\"claude-opus-4-5\", max_tokens=2048)\nSettings.embed_model = VoyageEmbedding(\n    model_name=\"voyage-3\",\n    voyage_api_key=os.environ.get(\"VOYAGE_API_KEY\")\n)\n\nprint(\"Multi-Modal RAG ready\")\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eStep 1: Image Caption với Claude Vision\u003c\/h2\u003e\n\n\u003cp\u003eClaude Vision phân tích hình ảnh và tạo description chi tiết để index:\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003edef encode_image_base64(image_path):\n    \"\"\"Encode image file thành base64 string.\"\"\"\n    with open(image_path, \"rb\") as f:\n        image_data = f.read()\n    return base64.standard_b64encode(image_data).decode(\"utf-8\")\n\ndef caption_image(image_path, context=\"\"):\n    \"\"\"\n    Dùng Claude Vision để tạo caption chi tiết cho ảnh.\n\n    Args:\n        image_path: Đường dẫn đến image file\n        context: Context bổ sung (tên tài liệu, page number...)\n\n    Returns:\n        String mô tả chi tiết về hình ảnh\n    \"\"\"\n    # Xác định media type\n    suffix = Path(image_path).suffix.lower()\n    media_types = {\n        \".jpg\": \"image\/jpeg\",\n        \".jpeg\": \"image\/jpeg\",\n        \".png\": \"image\/png\",\n        \".gif\": \"image\/gif\",\n        \".webp\": \"image\/webp\"\n    }\n    media_type = media_types.get(suffix, \"image\/jpeg\")\n\n    image_b64 = encode_image_base64(image_path)\n\n    context_str = f\"\nContext: {context}\" if context else \"\"\n\n    response = claude.messages.create(\n        model=\"claude-opus-4-5\",\n        max_tokens=1024,\n        messages=[\n            {\n                \"role\": \"user\",\n                \"content\": [\n                    {\n                        \"type\": \"image\",\n                        \"source\": {\n                            \"type\": \"base64\",\n                            \"media_type\": media_type,\n                            \"data\": image_b64\n                        }\n                    },\n                    {\n                        \"type\": \"text\",\n                        \"text\": f\"\"\"Mô tả chi tiết hình ảnh này để dùng trong hệ thống tìm kiếm.\nBao gồm:{context_str}\n- Loại hình ảnh (biểu đồ, sơ đồ, ảnh, screenshot, v.v.)\n- Nội dung chính và các elements quan trọng\n- Số liệu, text, labels nếu có\n- Màu sắc, trend, pattern đáng chú ý\n- Ý nghĩa hoặc insight từ hình ảnh\n\nViết mô tả đầy đủ bằng tiếng Việt để có thể search được.\"\"\"\n                    }\n                ]\n            }\n        ]\n    )\n\n    return response.content[0].text\n\n# Test với ảnh mẫu\n# caption = caption_image(\"chart.png\", context=\"Revenue chart from Q1 2024 report\")\n# print(caption)\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eStep 2: Extract Images từ PDF\u003c\/h2\u003e\n\n\u003cpre\u003e\u003ccode\u003eimport fitz  # PyMuPDF\n\ndef extract_pdf_content(pdf_path, output_dir=\".\/extracted_images\"):\n    \"\"\"\n    Extract text và images từ PDF, tạo LlamaIndex documents.\n\n    Returns:\n        List of LlamaDocument objects (text + image captions)\n    \"\"\"\n    Path(output_dir).mkdir(parents=True, exist_ok=True)\n\n    pdf_doc = fitz.open(pdf_path)\n    documents = []\n    pdf_name = Path(pdf_path).stem\n\n    for page_num, page in enumerate(pdf_doc, 1):\n        # Extract text từ page\n        page_text = page.get_text()\n        if page_text.strip():\n            documents.append(LlamaDocument(\n                text=page_text,\n                metadata={\n                    \"source\": pdf_name,\n                    \"type\": \"text\",\n                    \"page\": page_num\n                }\n            ))\n\n        # Extract images từ page\n        image_list = page.get_images(full=True)\n        for img_idx, img in enumerate(image_list):\n            xref = img[0]\n            base_image = pdf_doc.extract_image(xref)\n            image_bytes = base_image[\"image\"]\n            image_ext = base_image[\"ext\"]\n\n            # Lưu image\n            image_path = f\"{output_dir}\/{pdf_name}_p{page_num}_img{img_idx}.{image_ext}\"\n            with open(image_path, \"wb\") as f:\n                f.write(image_bytes)\n\n            # Tạo caption với Claude Vision\n            print(f\"  Captioning image: page {page_num}, image {img_idx}\")\n            caption = caption_image(\n                image_path,\n                context=f\"Page {page_num} of {pdf_name}\"\n            )\n\n            # Tạo document từ caption\n            documents.append(LlamaDocument(\n                text=f\"[IMAGE DESCRIPTION - Page {page_num}]\n{caption}\",\n                metadata={\n                    \"source\": pdf_name,\n                    \"type\": \"image\",\n                    \"page\": page_num,\n                    \"image_path\": image_path\n                }\n            ))\n\n    pdf_doc.close()\n    print(f\"Extracted {len(documents)} documents from {pdf_name}\")\n    return documents\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eStep 3: Index tất cả Content\u003c\/h2\u003e\n\n\u003cpre\u003e\u003ccode\u003edef build_multimodal_index(text_docs=None, image_paths=None, pdf_paths=None):\n    \"\"\"\n    Xây dựng unified index từ nhiều loại content.\n    \"\"\"\n    all_documents = []\n\n    # Process text documents\n    if text_docs:\n        all_documents.extend(text_docs)\n\n    # Process standalone images\n    if image_paths:\n        for img_path in image_paths:\n            print(f\"Processing image: {img_path}\")\n            caption = caption_image(img_path)\n            all_documents.append(LlamaDocument(\n                text=f\"[IMAGE: {Path(img_path).name}]\n{caption}\",\n                metadata={\n                    \"source\": Path(img_path).name,\n                    \"type\": \"image\",\n                    \"image_path\": img_path\n                }\n            ))\n\n    # Process PDFs\n    if pdf_paths:\n        for pdf_path in pdf_paths:\n            print(f\"\nProcessing PDF: {pdf_path}\")\n            docs = extract_pdf_content(pdf_path)\n            all_documents.extend(docs)\n\n    print(f\"\nTotal documents to index: {len(all_documents)}\")\n\n    # Tạo vector index\n    index = VectorStoreIndex.from_documents(\n        all_documents,\n        show_progress=True\n    )\n\n    return index\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eStep 4: Multi-Modal Query\u003c\/h2\u003e\n\n\u003cpre\u003e\u003ccode\u003edef multimodal_rag_query(index, question, include_image_context=True):\n    \"\"\"\n    Query multi-modal index và trả về câu trả lời với source information.\n    \"\"\"\n    query_engine = index.as_query_engine(\n        similarity_top_k=5,\n        response_mode=\"compact\"\n    )\n\n    response = query_engine.query(question)\n\n    # Phân loại sources\n    text_sources = []\n    image_sources = []\n\n    for node in response.source_nodes:\n        doc_type = node.metadata.get(\"type\", \"text\")\n        if doc_type == \"image\":\n            image_sources.append(node)\n        else:\n            text_sources.append(node)\n\n    result = {\n        \"answer\": response.response,\n        \"text_sources\": len(text_sources),\n        \"image_sources\": len(image_sources),\n        \"source_details\": [\n            {\n                \"type\": node.metadata.get(\"type\"),\n                \"source\": node.metadata.get(\"source\"),\n                \"page\": node.metadata.get(\"page\"),\n                \"score\": node.score\n            }\n            for node in response.source_nodes\n        ]\n    }\n\n    return result\n\n# Ví dụ sử dụng\ntext_documents = [\n    LlamaDocument(\n        text=\"Doanh thu Q1 2024 của công ty đạt 5.2 tỷ đồng, tăng 23% so với Q1 2023.\",\n        metadata={\"source\": \"annual_report\", \"type\": \"text\", \"page\": 1}\n    ),\n    LlamaDocument(\n        text=\"Biểu đồ tăng trưởng cho thấy xu hướng tích cực trong 4 quý liên tiếp.\",\n        metadata={\"source\": \"annual_report\", \"type\": \"text\", \"page\": 2}\n    )\n]\n\n# Build index (trong thực tế sẽ include images và PDFs)\nindex = VectorStoreIndex.from_documents(text_documents, show_progress=False)\n\n# Query\nresult = multimodal_rag_query(\n    index,\n    \"Doanh thu Q1 2024 tăng bao nhiêu phần trăm?\"\n)\nprint(f\"Answer: {result['answer']}\")\nprint(f\"Sources: {result['text_sources']} text, {result['image_sources']} images\")\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eAdvanced: Query với hình ảnh\u003c\/h2\u003e\n\n\u003cp\u003eBạn cũng có thể query bằng cách gửi ảnh — tìm documents liên quan đến hình ảnh:\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003edef query_with_image(index, image_path, question=\"\"):\n    \"\"\"\n    Query index sử dụng image làm query (kết hợp với text question).\n    \"\"\"\n    # Tạo caption cho query image\n    image_caption = caption_image(image_path)\n\n    # Kết hợp caption với question\n    combined_query = image_caption\n    if question:\n        combined_query = f\"{question}\n\nHình ảnh liên quan: {image_caption}\"\n\n    return multimodal_rag_query(index, combined_query)\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eKết luận\u003c\/h2\u003e\n\n\u003cp\u003eMulti-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.\u003c\/p\u003e\n\n\u003cp\u003eBước tiếp theo: Khám phá \u003ca href=\"\/collections\/nang-cao\"\u003eRouter Query Engine\u003c\/a\u003e để tự động chọn index phù hợp, hoặc đọc về \u003ca href=\"\/collections\/nang-cao\"\u003eSubQuestion Engine\u003c\/a\u003e để phân tách câu hỏi phức tạp thành sub-queries.\u003c\/p\u003e\n\n\u003chr\u003e\n\u003ch3\u003eBài viết liên quan\u003c\/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"\/products\/llamaindex-claude-rag-pipeline-c%C6%A1-b%E1%BA%A3n\"\u003eLlamaIndex + Claude — RAG pipeline cơ bản\u003c\/a\u003e\u003c\/li\u003e\n\u003cli\u003e\u003ca href=\"\/products\/b%E1%BA%AFt-d%E1%BA%A7u-v%E1%BB%9Bi-claude-vision-g%E1%BB%ADi-hinh-%E1%BA%A3nh-qua-api\"\u003eBắt đầu với Claude Vision — Gửi hình ảnh qua API\u003c\/a\u003e\u003c\/li\u003e\n\u003cli\u003e\u003ca href=\"\/products\/multi-document-agent-truy-v%E1%BA%A5n-nhi%E1%BB%81u-tai-li%E1%BB%87u-v%E1%BB%9Bi-llamaindex\"\u003eMulti-Document Agent — Truy vấn nhiều tài liệu với LlamaIndex\u003c\/a\u003e\u003c\/li\u003e\n\u003cli\u003e\u003ca href=\"\/products\/claude-vision-phan-tich-hinh-%E1%BA%A3nh-v%E1%BB%9Bi-ai\"\u003eClaude Vision — Phân tích hình ảnh với AI\u003c\/a\u003e\u003c\/li\u003e\n\u003cli\u003e\u003ca href=\"\/products\/autonomous-coding-agent-ai-t%E1%BB%B1-vi%E1%BA%BFt-code-t%E1%BB%AB-spec\"\u003eAutonomous Coding Agent — AI tự viết code từ spec\u003c\/a\u003e\u003c\/li\u003e\n\u003c\/ul\u003e","brand":"Minh Tuấn","offers":[{"title":"Default Title","offer_id":47721908142292,"sku":null,"price":0.0,"currency_code":"VND","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0821\/0264\/9044\/files\/multi-modal-rag-v_i-llamaindex-claude-vision_2aee9388-04c0-475a-8e49-6a9712a22116.jpg?v=1774521819","url":"https:\/\/claude.vn\/products\/multi-modal-rag-v%e1%bb%9bi-llamaindex-claude-vision","provider":"CLAUDE.VN","version":"1.0","type":"link"}