木曜日, 5月 15, 2025
ホームニューステックニュースCohere Embed 4で作る!パワポ資料に強いRAGシステム

Cohere Embed 4で作る!パワポ資料に強いRAGシステム


近年話題のRAG(Retrieval-Augmented Generation)ですが、「社内資料」や「業務ドキュメント」としてよく使われる パワポ(PowerPoint)資料 に対しても応用できたら便利だと思いませんか?

この記事では、
「Cohere Embed 4」 + 「Gemini」 + 「FAISS」 を使って、
パワポ資料向けRAGシステム を構築する手順を紹介します。

初心者でも動かしやすいように、今回は一連のシステムをライトに構築・解説します。

はじめに:自己紹介

はじめまして。株式会社NTTデータグループ 技術革新統括本部 Innovation技術部の 割田 祥(わりた あきら) と申します。
業務では ローカルLLMのビジネス適用 を目指したFine-Tuning技術やアーキテクチャ設計などの研究開発を行っています。

今回は本業とは少し離れてはいますが、Cohereが発表した最新の埋め込みモデルに触れてみたので、その内容をTech Blogとして書いてみました。よろしくお願いいたします。

この記事で扱うこと

  • Cohere Embed 4の導入と埋め込み生成
  • PDF化したパワポ資料の読み込み・画像化
  • FAISSでローカルベクトル検索
  • Gemini APIを使った応答生成(RAG)

この記事で扱わないこと

Furture-Workとさせてください。

  • 従来の埋め込みモデルとの精度比較
  • 最適なマルチモーダルLLMの選択
  • UI部分の構築

対象読者

  • RAGの基本はわかってきたけど、実際に使える用途を探している方
  • PowerPointをデータソースに使いたいと思っている方
  • CohereやGeminiを使った最新のマルチモーダルRAGを構築してみたい方

RAGとは?そしてなぜパワポ資料はやっかいなのか

まず簡単に、RAG(Retrieval-Augmented Generation)についておさらいしておきましょう。

🔍 RAGとは?

RAGは、検索(Retrieval)と生成(Generation)を組み合わせたアプローチです。
ざっくり言えば、「質問に対して関連する情報をまず探してきて、それをもとにLLMが回答を作る」 という流れになります。

たとえば以下のような構成を取ります:
[ユーザーの質問] → [検索を行い関連情報を取得] → [検索結果と質問を元にLLMが回答生成]

RAGは特に、社内データや非公開情報など「LLMの学習に含まれていない知識」を使いたい場面で非常に有効です。

📊 パワポ資料にRAGを適用する難しさ

しかし、パワポ資料をそのままRAGに使おうとすると、いくつかの難しさがあります。

⚠️ 主な課題:

  • 構造が自由すぎる
    → スライドごとに文字量・構成・言語がバラバラ。

  • テキスト抽出が不安定
    → OCRやpptxパーサーでは、レイアウト崩れや抜け落ちが起こりやすい。

  • 画像・図表の比率が高い
    → テキスト中心のRAGだと、そもそも記載内容を拾えないことがある。

こうした理由から、パワポ資料は 「いい感じに使いたいけど、テキストRAGでは精度が出にくい」 データソースとなっています。

💡 そこで画像RAG × Cohere Embed 4

今回のアプローチでは、パワポ資料を画像として扱い、Cohere Embed 4のマルチモーダル埋め込み機能を活用します。

画像そのものをベクトル化できることで、以下のような利点があります:

  • テキスト抽出をしなくて済む(OCR不要)
  • 図表やレイアウト情報も含んだ埋め込みが可能
  • 英語・日本語混在の資料にも強い(多言語対応)

Cohere Embed 4とは?画像も扱えるマルチモーダル埋め込みモデル

Cohere Embed 4は、2025年4月にリリースされた最新の埋め込みモデルで、テキストと画像の両方をベクトル化できるマルチモーダル対応が最大の特徴です。
これにより、パワポ資料のようなテキストと図表が混在するドキュメントも、OCRや複雑な前処理なしでそのまま埋め込み対象にできます。


主な特徴

  • 高度なマルチモーダル対応
    テキストだけでなく、画像・表・グラフ・コード・図解などが混在する資料にも強く、複雑なPDFやスライド資料でも正確に検索・類似判定が可能です。

  • 圧倒的なコンテキスト長(128Kトークン)
    約200ページに相当する長文ドキュメントも、1つのベクトルとして処理可能です。例えば、財務報告書、製品マニュアル、契約書などの長文ドキュメントにもそのまま適用できます。

  • 100以上の言語に対応した多言語性
    日本語、アラビア語、韓国語、フランス語など、幅広い言語をカバーしており、グローバルで活用できます。

  • セキュリティ重視の業界向け最適化
    金融・医療・製造業などの機密性が高い業界のデータにも強く、VPCやオンプレミス環境でも導入可能です。

利用可能なプラットフォーム

また、各クラウドプロバイダでの提供状況は以下となっています。

  • Amazon Web Services
  • Microsoft Azure

パワポ資料向けRAGシステムの実装

「Cohere Embed 4」 + 「Gemini」 + 「FAISS」 を使用して、実際にパワポ資料向けRAGシステムを構築してみます。

具体的にはユーザの質問を元に、パワポPDFを画像化したものをベクトル検索し、マルチモーダルLLMを用いて回答生成を行います。


0. 前準備

検証環境

筆者の環境は以下となります。

  • Python: 3.12.6
  • OS: macOS Sequoia 15.4.1

使用するモデルと検索手法

モデル/検索手法 用途
Cohere Embed 4 埋め込み生成
FAISS ベクトル検索
Gemini(gemini-2.5-pro-exp-03-25 応答生成(RAG)

使用ライブラリ

ライブラリ名 用途 バージョン(執筆時点)
cohere Cohere Embed 4 API を使ったベクトル生成 5.15.0
google-genai Gemini API の呼び出し・応答生成 1.13.0
faiss-cpu ローカルでのベクトル検索 1.11.0
pymupdf (fitz) PDFスライドの画像変換 1.25.5
python-dotenv APIキーなどの環境変数の管理 1.1.0
tqdm プログレスバー表示(埋め込み時など) 4.67.1

以下のコマンドでインストールしています。

$ pip install cohere google-genai python-dotenv tqdm faiss-cpu pymupdf

ディレクトリ構成

以下のディレクトリを作成しています。

code/
├── sample.py      
├── .env           
├── slides/        
│   └── company-profile.pdf
└── images/        
  • sample.py:パワポPDFのスライド画像化 → ベクトル化 → FAISS検索 → 応答までを一貫して実行。
  • .env:各APIキーを定義。
  • slides/:RAG検索対象となるPowerPoint資料(PDF)。
  • images/slides/ のPDFをスライドごとに画像化したものを出力。検索対象ベクトルとして使われます。

検索対象のパワポPDFファイル

検索対象となるパワポPDFファイルは以下のものとしました。

理由としては、図表を多く含むパワポ資料で、一般的なテキストRAGの苦手とする文書であるからです。

APIキーの準備

今回は Cohere PlatformGoogle AI Studio を使用します。どちらもFreeプランを使用しています。

各プラットフォームの手順に従ってAPIキーを発行し、.env ファイルに記載します。

.env

COHERE_API_KEY="Cohere Platformで発行したキー">
GEMINI_API_KEY="Google AI Studioで発行したキー">

1. パワポPDFのpng画像化

PDF内のスライドをそれぞれpngファイルに変換する関数 convert_pdf_to_images を実装します。
ライブラリとしては、pymupdfを使用しました。

sample.py

from pathlib import Path
import fitz

def convert_pdf_to_images(pdf_path, output_dir, zoom=2.0):
    """
    指定されたPDFファイルをスライド単位で画像(PNG)に変換する関数です。

    Parameters:
    ----------
    pdf_path : str or Path
        入力PDFファイルのパス。PowerPointからエクスポートしたPDFを想定しています。

    output_dir : str or Path
        変換後のPNG画像を保存するディレクトリ。存在しない場合は自動で作成されます。
    
    zoom : float (default=2.0)
        出力画像の拡大率。2.0 はおおよそ 200dpi 相当です。高精度な画像ベクトル化を行いたい場合に調整可能です。

    Returns:
    -------
    image_paths : list of str
        変換された各スライド画像(PNG)のファイルパス一覧。
        ファイル名は `_.png` の形式になります。
    """
    output_dir = Path(output_dir)
    output_dir.mkdir(parents=True, exist_ok=True)

    pdf_name = Path(pdf_path).stem  

    doc = fitz.open(pdf_path)
    image_paths = []

    for i, page in enumerate(doc):
        mat = fitz.Matrix(zoom, zoom)
        pix = page.get_pixmap(matrix=mat)
        image_path = output_dir / f"{pdf_name}_{i+1}.png"
        pix.save(str(image_path))
        image_paths.append(str(image_path))

    doc.close()
    return image_paths

2. 画像のベクトル化

Cohere Embed 4 を使用して、画像のベクトル化を行う関数 get_image_embedding を実装します。
Cohere Platformの公式ドキュメントを参考に実装しました。

sample.py

import cohere
import base64
from dotenv import load_dotenv

load_dotenv()

co = cohere.ClientV2()



def get_image_embedding(image_path):
    """
    指定した画像ファイル(PNG)を Cohere Embed 4 を使ってベクトル化する関数です。
    画像は base64 形式でエンコードされた上で、Cohere API に送信され、画像内容に基づいた埋め込みベクトル(数値ベクトル)が返されます。

    Parameters:
    ----------
    image_path : str or Path
        ベクトル化したい画像ファイルのパス。
        今回はスライドをPNGに変換した画像が対象です。

    Returns:
    -------
    response : cohere.EmbedByTypeResponseEmbeddings
        Cohere API から返されるレスポンスオブジェクト。
        ベクトルは `response.embeddings.float_[0]` から取得できます。
    """
    with open(image_path, "rb") as f:
        image_data = f.read()
    stringified_buffer = base64.b64encode(image_data).decode("utf-8")
    content_type = "image/png"
    image_base64 = f"data:{content_type};base64,{stringified_buffer}"

    response = co.embed(
        model="embed-v4.0",
        input_type="image",
        embedding_types=["float"],
        images=[image_base64],
    )
    return response

3. FAISSインデックスの作成と検索機能の実装

FAISSによるベクトル検索処理のための関数を実装します。build_faiss_index関数で画像ベクトルのFAISSインデックスを構築し、search_faiss_with_text関数でCohere Embed 4 を使用したテキストによる画像のベクトル検索を行います。

sample.py

import faiss
import numpy as np
from pathlib import Path
from tqdm import tqdm

load_dotenv()

co = cohere.ClientV2()

def build_faiss_index(image_paths):
    """
    画像ファイルから埋め込みベクトルを生成し、それらを使って FAISS のインデックスを構築する関数です。

    Cohere Embed 4 でベクトル化されたスライド画像をローカル環境で検索可能にするために、
    FAISS(Facebook AI Similarity Search)を使ってインメモリのベクトル検索インデックスを生成します。

    Parameters:
    ----------
    image_paths : list of str or Path
        ベクトル化したい画像ファイル(今回はPNG)のパスのリスト。

    Returns:
    -------
    index : faiss.IndexFlatL2
        L2距離(ユークリッド距離)を用いたFAISSのベクトル検索インデックス。
    
    image_paths : list of str
        元の画像パスリスト(検索結果とインデックス番号を対応させるために返します)。
    """
    vectors = []
    for path in tqdm(image_paths, desc="埋め込み生成中"):
        res = get_image_embedding(path)
        embedding = res.embeddings.float_[0]
        vectors.append(np.array(embedding, dtype="float32"))

    index = faiss.IndexFlatL2(len(vectors[0]))
    index.add(np.stack(vectors))
    return index, image_paths

def search_faiss_with_text(index, image_paths, text_query, k=3):
    """
    テキストクエリに基づいて、FAISSインデックス内の画像との類似検索を行う関数です。

    Cohere Embed 4 を使用して、ユーザーのテキストクエリを埋め込みベクトルに変換し、
    すでに登録されたスライド画像のベクトルと比較して、意味的に近い画像を上位k件まで返します。

    Parameters:
    ----------
    index : faiss.Index
        事前に構築されたFAISSインデックス(画像のベクトルが登録済み)。

    image_paths : list of str
        FAISSインデックスに対応する画像ファイルのパスリスト。検索結果とファイルの対応づけに使います。

    text_query : str
        類似画像を探したい自然言語クエリ。

    k : int (default=3)
        検索して取得する類似画像の件数。上位k件をスコア順に返します。

    Returns:
    -------
    List[str]
        類似度の高い画像ファイルのパスリスト(最大k件)。

    """
    response = co.embed(
        model="embed-v4.0",
        input_type="text",
        embedding_types=["float"],
        texts=[text_query],
    )
    query_vec = np.array(response.embeddings.float_[0], dtype="float32").reshape(1, -1)
    D, I = index.search(query_vec, k)

    return [image_paths[i] for i in I[0]]

4. Geminiによる応答生成機能の実装

マルチモーダルLLM Gemini(今回はgemini-2.5-pro-exp-03-25)による応答生成機能を実装します。

使用するモデルgemini-2.5-pro-exp-03-25は複数枚の画像入力が可能なため、今回は上位3件の検索結果をすべて入れる実装としました。

実装は、Gemini API公式ドキュメントを参考にしました。

また、パワポ画像に関する応答をするように、system_instructionを入れています。

sample.py

import os
from dotenv import load_dotenv
from pathlib import Path
from google import genai
from google.genai import types



def generate_answer_with_gemini(image_paths, text_prompt):
    """
    複数の画像とテキストプロンプトを使って、Google Gemini API によるマルチモーダル応答を生成する関数です。

    指定された画像群(例:検索結果のスライド画像)と自然言語プロンプトを組み合わせて、
    Gemini モデルに送信し、画像に基づいた自然言語の回答を取得します。

    Parameters:
    ----------
    image_paths : list of str or Path
        入力画像ファイルのパスリスト。FAISSで検索されたスライド画像のパス群。

    text_prompt : str
        Geminiモデルに渡す自然言語のプロンプト(質問)。

    Returns:
    -------
    response_text : str
        Gemini APIから返された応答。API呼び出しに失敗した場合はエラーメッセージを返します。

    Notes:
    -----
    - 画像はすべてバイナリとして読み込み、`Part.from_bytes()` でGemini形式のマルチモーダル入力に変換されます。
    - `model="gemini-2.5-pro-exp-03-25"` を使用しています(複数画像対応)。
    - `system_instruction` によって、「スライド画像に基づく回答」のような文脈を指示しています。
    - 環境変数 `GEMINI_API_KEY` が `.env` に設定されている必要があります。
    - API呼び出し時にエラーが発生した場合は例外をキャッチし、ユーザー向けのエラーメッセージを返します。
    """
    load_dotenv()
    api_key = os.getenv("GEMINI_API_KEY")
    if not api_key:
        raise ValueError("GEMINI_API_KEY is not set in the environment.")

    client = genai.Client(api_key=api_key)
    contents = [text_prompt]

    for path in image_paths:
        mime_type = "image/png" if path.endswith(".png") else "image/jpeg"
        with open(path, "rb") as f:
            image_bytes = f.read()
        part = types.Part.from_bytes(data=image_bytes, mime_type=mime_type)
        contents.append(part)

    try:
        response = client.models.generate_content(
            model="gemini-2.5-pro-exp-03-25",
            contents=contents,
            config=types.GenerateContentConfig(
                system_instruction="あなたはスライド画像に関する質問に答えるAIアシスタントです。スライド画像の内容を理解し、質問に答えてください。回答にはスライド画像の内容のみを使用してください。",
                ),
            )
        return response.text
    except Exception as e:
        return f"[Gemini APIエラー] {str(e)}"

5. 結合

1~4で実装した関数をまとめて、コマンドラインから質問を入力しそれに基づく回答を生成するように実装します。

sample.py

if __name__ == "__main__":
    slides_dir = Path("./slides")
    images_dir = Path("./images")
    all_image_paths = []

    for pdf_file in slides_dir.glob("*.pdf"):
        image_paths = convert_pdf_to_images(pdf_file, images_dir)
        all_image_paths.extend(image_paths)

    print(f"{len(all_image_paths)} 枚のスライド画像を生成しました。")
    print("画像を埋め込んでFAISSインデックスを構築中...")
    index, img_list = build_faiss_index(all_image_paths)
    print("FAISSインデックスの構築が完了しました。")
    
    while True:
        text_query = input("テキストクエリを入力してください(終了するには 'quit' と入力): ")
        if text_query.strip().lower() == "quit":
            print("終了します。")
            break

        results = search_faiss_with_text(index, img_list, text_query)
        print("テキストクエリによる類似画像:")
        for r in results:
            print(r)

        print("\nGeminiによる回答:")
        answer = generate_answer_with_gemini(results, text_query)
        print(answer)

ここまですべての処理をまとめたコードは以下になります。

すべてをまとめたコード

sample.py

import os
import cohere
import base64
from dotenv import load_dotenv
from pathlib import Path
import fitz  
from google import genai
from google.genai import types
from tqdm import tqdm
import faiss
import numpy as np


load_dotenv()
co = cohere.ClientV2()

def convert_pdf_to_images(pdf_path, output_dir, zoom=2.0):
    """
    指定されたPDFファイルをスライド単位で画像(PNG)に変換する関数です。

    Parameters:
    ----------
    pdf_path : str or Path
        入力PDFファイルのパス。PowerPointからエクスポートしたPDFを想定しています。

    output_dir : str or Path
        変換後のPNG画像を保存するディレクトリ。存在しない場合は自動で作成されます。
    
    zoom : float, optional (default=2.0)
        出力画像の拡大率。2.0 はおおよそ 200dpi 相当です。高精度な画像ベクトル化を行いたい場合に調整可能です。

    Returns:
    -------
    image_paths : list of str
        変換された各スライド画像(PNG)のファイルパス一覧。
        ファイル名は `_.png` の形式になります。
    """
    output_dir = Path(output_dir)
    output_dir.mkdir(parents=True, exist_ok=True)

    pdf_name = Path(pdf_path).stem  

    doc = fitz.open(pdf_path)
    image_paths = []

    for i, page in enumerate(doc):
        mat = fitz.Matrix(zoom, zoom)
        pix = page.get_pixmap(matrix=mat)
        image_path = output_dir / f"{pdf_name}_{i+1}.png"
        pix.save(str(image_path))
        image_paths.append(str(image_path))

    doc.close()
    
    
    return image_paths


def get_image_embedding(image_path):
    """
    指定した画像ファイル(PNGなど)を Cohere Embed 4 を使ってベクトル化する関数です。

    画像は base64 形式でエンコードされた上で、Cohere API に送信され、画像内容に基づいた埋め込みベクトル(数値ベクトル)が返されます。
    このベクトルは類似検索やRAGのコンテキスト選択などに利用可能です。

    Parameters:
    ----------
    image_path : str or Path
        ベクトル化したい画像ファイルのパス。
        一般的には、スライドをPNGに変換した画像が対象です。

    Returns:
    -------
    response : cohere.EmbedByTypeResponse
        Cohere API から返されるレスポンスオブジェクト。
        ベクトルは `response.embeddings.float_[0]` から取得できます。
    """
    with open(image_path, "rb") as f:
        image_data = f.read()
    stringified_buffer = base64.b64encode(image_data).decode("utf-8")
    content_type = "image/png"  
    image_base64 = f"data:{content_type};base64,{stringified_buffer}"

    response = co.embed(
        model="embed-v4.0",
        input_type="image",
        embedding_types=["float"],
        images=[image_base64],
    )
    return response



def generate_answer_with_gemini(image_paths, text_prompt):
    """
    複数の画像とテキストプロンプトを使って、Google Gemini API によるマルチモーダル応答を生成する関数です。

    指定された画像群(例:検索結果のスライド画像)と自然言語プロンプトを組み合わせて、
    Gemini モデルに送信し、画像に基づいた自然言語の回答を取得します。

    Parameters:
    ----------
    image_paths : list of str or Path
        入力画像ファイルのパスリスト。通常は、FAISSで検索されたスライド画像群。

    text_prompt : str
        Geminiモデルに渡す自然言語のプロンプト(質問・指示文)。

    Returns:
    -------
    response_text : str
        Gemini APIから返された自然言語応答。API呼び出しに失敗した場合はエラーメッセージを返します。

    Notes:
    -----
    - 画像はすべてバイナリとして読み込み、`Part.from_bytes()` でGemini形式のマルチモーダル入力に変換されます。
    - `model="gemini-2.5-pro-exp-03-25"` を使用しています(複数画像対応)。
    - `system_instruction` によって、「スライド画像に基づく回答」のような文脈を指示しています。
    - 環境変数 `GEMINI_API_KEY` が `.env` に設定されている必要があります。
    - API呼び出し時にエラーが発生した場合は例外をキャッチし、ユーザー向けのエラーメッセージを返します。
    """
    load_dotenv()
    api_key = os.getenv("GEMINI_API_KEY")
    if not api_key:
        raise ValueError("GEMINI_API_KEY is not set in the environment.")

    client = genai.Client(api_key=api_key)
    contents = [text_prompt]

    for path in image_paths:
        mime_type = "image/png" if path.endswith(".png") else "image/jpeg"
        with open(path, "rb") as f:
            image_bytes = f.read()
        part = types.Part.from_bytes(data=image_bytes, mime_type=mime_type)
        contents.append(part)

    try:
        response = client.models.generate_content(
            model="gemini-2.5-pro-exp-03-25",
            contents=contents,
            config=types.GenerateContentConfig(
                system_instruction="あなたはスライド画像に関する質問に答えるAIアシスタントです。スライド画像の内容を理解し、質問に答えてください。回答にはスライド画像の内容のみを使用してください。",
                ),
            )
        return response.text
    except Exception as e:
        return f"[Gemini APIエラー] {str(e)}"






def build_faiss_index(image_paths):
    """
    画像ファイルから埋め込みベクトルを生成し、それらを使って FAISS のインデックスを構築する関数です。

    Cohere Embed 4 でベクトル化されたスライド画像をローカル環境で検索可能にするために、
    FAISS(Facebook AI Similarity Search)を使ってインメモリのベクトル検索インデックスを生成します。

    Parameters:
    ----------
    image_paths : list of str or Path
        ベクトル化したい画像ファイル(PNG形式など)のパスのリスト。

    Returns:
    -------
    index : faiss.IndexFlatL2
        L2距離(ユークリッド距離)を用いたFAISSのベクトル検索インデックス。
    
    image_paths : list of str
        元の画像パスリスト(検索結果とインデックス番号を対応させるために返します)。
    """
    vectors = []
    for path in tqdm(image_paths, desc="埋め込み生成中"):
        res = get_image_embedding(path)
        embedding = res.embeddings.float_[0]
        vectors.append(np.array(embedding, dtype="float32"))

    index = faiss.IndexFlatL2(len(vectors[0]))
    index.add(np.stack(vectors))
    return index, image_paths

def search_faiss_with_text(index, image_paths, text_query, k=3):
    """
    テキストクエリに基づいて、FAISSインデックス内の画像との類似検索を行う関数です。

    Cohere Embed 4 を使用して、ユーザーのテキストクエリを埋め込みベクトルに変換し、
    すでに登録されたスライド画像のベクトルと比較して、意味的に近い画像を上位k件まで返します。

    Parameters:
    ----------
    index : faiss.Index
        事前に構築されたFAISSインデックス(画像のベクトルが登録済み)。

    image_paths : list of str
        FAISSインデックスに対応する画像ファイルのパスリスト。検索結果とファイルの対応づけに使います。

    text_query : str
        類似画像を探したい自然言語クエリ。

    k : int (default=3)
        検索して取得する類似画像の件数。上位k件をスコア順に返します。

    Returns:
    -------
    List[str]
        類似度の高い画像ファイルのパスリスト(最大k件)。

    """
    response = co.embed(
        model="embed-v4.0",
        input_type="text",
        embedding_types=["float"],
        texts=[text_query],
    )
    query_vec = np.array(response.embeddings.float_[0], dtype="float32").reshape(1, -1)
    D, I = index.search(query_vec, k)
    return [image_paths[i] for i in I[0]]


if __name__ == "__main__":
    slides_dir = Path("./slides")
    images_dir = Path("./images")
    all_image_paths = []

    for pdf_file in slides_dir.glob("*.pdf"):
        image_paths = convert_pdf_to_images(pdf_file, images_dir)
        all_image_paths.extend(image_paths)

    print(f"{len(all_image_paths)} 枚のスライド画像を生成しました。")
    print("画像を埋め込んでFAISSインデックスを構築中...")
    index, img_list = build_faiss_index(all_image_paths)
    print("FAISSインデックスの構築が完了しました。")
    
    while True:
        text_query = input("テキストクエリを入力してください(終了するには 'quit' と入力): ")
        if text_query.strip().lower() == "quit":
            print("終了します。")
            break

        results = search_faiss_with_text(index, img_list, text_query)
        print("テキストクエリによる類似画像:")
        for r in results:
            print(r)

        print("\nGeminiによる回答:")
        answer = generate_answer_with_gemini(results, text_query)
        print(answer)

6. 実行

以下のコマンドで、sample.pyファイルを実行します。

実行後、以下のように処理が進みます。

  1. pymupdfによるパワポPDFの画像変換
  2. FAISSインデックスの作成
  3. コマンドラインでのテキストクエリを入力してください(終了するには 'quit' と入力): の表示

処理3が行われたら実際にパワポPDFに関する質問を入力し、Enterキーを押してください。
終了する際はquitと入力してEnterキーを押してください。


パワポ資料向けRAGシステムの実行例

実際に質問を入力してみた例をご紹介します。

入力した質問

NTTデータの強みはなんですか

検索結果

テキストクエリによる類似画像:
images/company-profile_6.png
images/company-profile_7.png
images/company-profile_11.png
実際のスライド画像
  • company-profile_6.png
  • company-profile_7.png
  • company-profile_11.png

Geminiによる回答

NTTデータの強みは、スライドによると以下の点が挙げられます。

1.  **Foresight 起点の目利き力:** 社会や業界、顧客の変化、そしてあるべき姿に基づき、戦略を考え、最適な技術を提案する力。
2.  **We Create つくる力:** 幅広い業界のお客様とのビジネスを通じた豊富な業務ノウハウと高度な開発力。
3.  **システム管理/運用力:** 社会基盤となる重要なITシステムの安定的な稼働を実現してきたシステム管理・運用力。
4.  **We Connect つなぐ力:** データセンター、ネットワーク、マネージドサービスを主としたEdge to Cloudのサービス・オペレーション力。
5.  **人材・組織力:** 19万人超のあらゆる分野に精通するプロフェッショナル集団と、組織のフル活用によりプロジェクトを完遂する力。

また、競争優位性・差別化要因としては以下の点も挙げられています。

*   **多様性を持つビジネスポートフォリオ:** 幅広い国・地域/業種で事業を可能とする。
*   **世界最高水準のエンジニアリング力:** 新技術活用を含む。
*   **マネジメント力:** 大規模なプロジェクトをまとめる力。
*   **グローバル有数のインフラサービスプレイヤー:** データセンターやネットワーク等。
*   **顧客との長期にわたる揺るぎない関係性 (Long-Term Relationships)**

さらに、市場でのポジションや実績も強みとして示されています。

*   **グローバルブランド力:** IT Services brands 第6位。
*   **日本市場におけるリーダーシップ:** 日本市場ITサービス市場ランキング 第1位。
*   **世界トップレベルのデジタル技術:** 生成AIをはじめとする各種リーダー評価を多数獲得。
*   **データセンター事業者シェア:** 世界第3位。
*   **ITサービス提供の歴史:** 57年。

分析

今回はテキスト・画像両方のベクトル化にCohere Embed 4を使用しましたが、質問の内容に沿ったスライドを検索することができました。
これまではパワポ資料のスライドを検索するためにはOCR等を必要としていましたが、新たにベクトル検索も選択肢の1つになり得ると思います。

また、Gemini-2.5のマルチモーダル性能により、「強み」という漠然としたワードを理解し、スライド内容から「競争優位性・差別化要因」「市場でのポジションや実績」といった部分を回答できています。

実際のスライド画像内容との対応

回答の各部分について、スライド画像の赤枠内の記載が対応しています。


1.  **Foresight 起点の目利き力:** 社会や業界、顧客の変化、そしてあるべき姿に基づき、戦略を考え、最適な技術を提案する力。
2.  **We Create つくる力:** 幅広い業界のお客様とのビジネスを通じた豊富な業務ノウハウと高度な開発力。
3.  **システム管理/運用力:** 社会基盤となる重要なITシステムの安定的な稼働を実現してきたシステム管理・運用力。
4.  **We Connect つなぐ力:** データセンター、ネットワーク、マネージドサービスを主としたEdge to Cloudのサービス・オペレーション力。
5.  **人材・組織力:** 19万人超のあらゆる分野に精通するプロフェッショナル集団と、組織のフル活用によりプロジェクトを完遂する力。

company-profile_7.png


また、競争優位性・差別化要因としては以下の点も挙げられています。

*   **多様性を持つビジネスポートフォリオ:** 幅広い国・地域/業種で事業を可能とする。
*   **世界最高水準のエンジニアリング力:** 新技術活用を含む。
*   **マネジメント力:** 大規模なプロジェクトをまとめる力。
*   **グローバル有数のインフラサービスプレイヤー:** データセンターやネットワーク等。
*   **顧客との長期にわたる揺るぎない関係性 (Long-Term Relationships)**

company-profile_6.png


さらに、市場でのポジションや実績も強みとして示されています。

*   **グローバルブランド力:** IT Services brands 第6位。
*   **日本市場におけるリーダーシップ:** 日本市場ITサービス市場ランキング 第1位。
*   **世界トップレベルのデジタル技術:** 生成AIをはじめとする各種リーダー評価を多数獲得。
*   **データセンター事業者シェア:** 世界第3位。
*   **ITサービス提供の歴史:** 57年。

company-profile_11.png

company-profile_7.png

company-profile_6.png

まとめと今後の展望

今回は、Cohere Embed 4とGeminiを組み合わせて、「パワポ資料に強いRAGシステム」を作ってみました。

OCRで文字を拾うのではなく、スライド全体を“意味ごと”ベクトル化して検索できるのがポイントです。
これにより、テキストが少ない資料や、図表・レイアウトが中心のスライドでも、意味的な検索&回答が可能になります。

今回作ったものを応用して、こんな使い方もできるのではないかと考えます:

  • 社内の提案資料や研修スライドを対象に、「あの内容どこにあったっけ?」をすぐ見つける検索システム
  • 決算説明スライドの中から、過去の実績や戦略を自然言語で検索 → 自動でまとめてくれる分析補助
  • PowerPointで作られた学習コンテンツに質問して、AIがわかりやすく答えてくれる社内QAボット
  • サポート部門向けに、製品資料スライドをもとにした問い合わせ対応支援ツールとして活用

「パワポ資料のRAGは難しい」と言われていますが、 マルチモーダルな手法を使えば、まだまだいろいろな可能性があるな と感じました。

興味を持った方はぜひ、手元の環境・資料で試してみてください!
コメント・フィードバックもお待ちしてます 🙌

参考URL



Source link

Views: 2

RELATED ARTICLES

返事を書く

あなたのコメントを入力してください。
ここにあなたの名前を入力してください

- Advertisment -

インモビ転職