こんにちは、HolySheep AI 技術チームです。本日は、大規模言語モデルを活用した業務自動化において注目を集める「多模态 RAG(Multi-modal Retrieval-Augmented Generation)」の構築方法について、私が実際に支援したケーススタディを交えながら詳しく解説いたします。

ケーススタディ:東京のAIスタートアップ「MIRAI Analytics」の挑戦

私が技術支援させていただいている東京都海淀区に本社を置くAIスタートアップ企業 MIRAI Analytics は、金融機関の契約書分析システムを開発しています。同社は従来、複数の文書種別(契約書、領収書、構造図、契約条項メモ)を一枚のナレッジベースで管理する多模态 RAG システムの構築を目指しておりました。

業務背景

MIRAI Analytics の開発チームは每天数千件の契約書画像を解析し、関連条文との紐付けを行うシステムを構築する必要がありました。同社の要件は以下でした:

旧プロバイダの課題

MIRAI Analytics は以前、別のアジア系 AI API プロバイダーを利用しておりました。私も彼らと協議しましたが、以下の課題が顕在化しておりました:

HolySheep AI を選んだ理由

私が MIRAI Analytics に提案したのは HolySheep AI への移行でした。HolySheep AI は ¥1=$1 のレート設定(公式比85%節約)を提供しており、私の計算では画像処理コストだけでも月$800の削減が見込めました。さらに <50ms のレイテンシ、WeChat Pay/Alipay 対応、日本語技術サポートといった優位性が高く評価されました。

多模态 RAG アーキテクチャの設計

私が MIRAI Analytics と設計した多模态 RAG アーキテクチャは以下の通りです。画像とテキストを同一ベクトル空間で扱い、ハイブリッド検索を実現する点がポイントです。

システム構成図

┌─────────────────────────────────────────────────────────────────┐
│                     多模态 RAG システム構成                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐       │
│  │ 契約書画像    │    │ 判例テキスト   │    │ 契約書PDF    │       │
│  │ (JPEG/PNG)  │    │ (Markdown)   │    │ (スキーマ)   │       │
│  └──────┬───────┘    └──────┬───────┘    └──────┬───────┘       │
│         │                   │                   │               │
│         ▼                   ▼                   ▼               │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐       │
│  │ 画像エンベッド│    │ テキストエンベッド│    │ 構造化データ  │       │
│  │ embedding   │    │ embedding   │    │ メタデータ   │       │
│  └──────┬───────┘    └──────┬───────┘    └──────┬───────┘       │
│         │                   │                   │               │
│         └───────────────────┴───────────────────┘               │
│                             │                                   │
│                             ▼                                   │
│                   ┌─────────────────┐                            │
│                   │  ベクトルDB     │                            │
│                   │ (Pinecone/Weaviate) │                        │
│                   └────────┬────────┘                            │
│                            │                                    │
│         ┌──────────────────┼──────────────────┐                  │
│         ▼                  ▼                  ▼                  │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐          │
│  │  類似画像検索 │    │  類似テキスト │    │  スキーマ検索 │          │
│  │ (Image Sim) │    │ (Text Sim)  │    │ (BM25/Exact) │          │
│  └──────┬──────┘    └──────┬──────┘    └──────┬──────┘          │
│         │                  │                  │                  │
│         └──────────────────┼──────────────────┘                  │
│                            │                                    │
│                            ▼                                    │
│                   ┌─────────────────┐                            │
│                   │ リランキング    │                            │
│                   │ (Reranker)      │                            │
│                   └────────┬────────┘                            │
│                            │                                    │
│                            ▼                                    │
│                   ┌─────────────────┐                            │
│                   │  LLM生成       │                            │
│                   │ (Claude/GPT)   │                            │
│                   └─────────────────┘                            │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

実装コード:HolySheep AI による多模态 RAG

Step 1: 画像+テキスト混合ナレッジベースの構築

"""
多模态 RAG ナレッジベース構築スクリプト
HolySheep AI API を使用した画像・テキスト混合Embedding
"""

import base64
import json
import requests
from PIL import Image
from pathlib import Path
from typing import List, Dict, Any

HolySheep AI 設定

BASE_URL = "https://api.holysheep.ai/v1" API_KEY = "YOUR_HOLYSHEEP_API_KEY" class MultimodalRAGBuilder: def __init__(self, api_key: str): self.api_key = api_key self.headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } def encode_image_to_base64(self, image_path: str) -> str: """画像をBase64エンコード""" with open(image_path, "rb") as img_file: return base64.b64encode(img_file.read()).decode('utf-8') def create_multimodal_embedding( self, text: str, image_path: str = None ) -> List[float]: """ HolySheep AI で画像+テキストのマルチモーダルEmbeddingを生成 画像がない場合はテキストのみ """ if image_path: # 画像がある場合:マルチモーダルEmbedding image_base64 = self.encode_image_to_base64(image_path) payload = { "input": { "text": text, "image": f"data:image/jpeg;base64,{image_base64}" }, "model": "multimodal-embed-v2", "encoding_format": "float" } else: # テキストのみ payload = { "input": text, "model": "text-embed-003", "encoding_format": "float" } response = requests.post( f"{BASE_URL}/embeddings", headers=self.headers, json=payload, timeout=30 ) if response.status_code != 200: raise Exception(f"Embedding生成失敗: {response.text}") return response.json()["data"][0]["embedding"] def build_knowledge_base( self, documents: List[Dict[str, Any]], vector_store: List[Dict] ) -> List[Dict]: """ナレッジベースの構築""" results = [] for idx, doc in enumerate(documents): print(f"処理中 {idx + 1}/{len(documents)}: {doc.get('title', 'Untitled')}") try: # Embedding生成(画像+テキスト) embedding = self.create_multimodal_embedding( text=doc["content"], image_path=doc.get("image_path") ) # ベクトルストアに追加 vector_entry = { "id": f"doc_{idx}", "values": embedding, "metadata": { "title": doc.get("title", ""), "content": doc["content"], "doc_type": doc.get("type", "text"), "source": doc.get("source", ""), "page": doc.get("page", 0) } } vector_store.append(vector_entry) results.append({"status": "success", "id": vector_entry["id"]}) except Exception as e: print(f"エラー: {doc.get('title', 'Untitled')} - {str(e)}") results.append({"status": "error", "error": str(e)}) return results

使用例

if __name__ == "__main__": builder = MultimodalRAGBuilder(API_KEY) # 契約書ドキュメントの例 documents = [ { "title": "業務委託契約書_2024", "content": "甲乙双方は以下の通り契約を締結する。第1条 業務範囲:本業務は软件开发・保守とする。", "image_path": "./docs/contract_scan.jpg", "type": "contract", "source": "files/contracts/001.pdf", "page": 1 }, { "title": "秘密保持誓約書_NDA", "content": "乙方は甲方から開示された情報を第三者に開示してはならない。", "image_path": None, "type": "nda", "source": "files/nda/002.pdf", "page": 1 } ] vector_store = [] results = builder.build_knowledge_base(documents, vector_store) print(f"ナレッジベース構築完了: {len(results)}件処理")

Step 2: ハイブリッド検索&LMM生成

"""
多模态 RAG 検索&LMM生成スクリプト
HolySheep AI で画像とテキストのハイブリッド検索を実行
"""

import requests
import json
from typing import List, Dict, Any, Tuple
from dataclasses import dataclass

HolySheep AI 設定

BASE_URL = "https://api.holysheep.ai/v1" API_KEY = "YOUR_HOLYSHEEP_API_KEY" @dataclass class SearchResult: content: str score: float doc_type: str source: str image_data: str = None class MultimodalRAGSearcher: def __init__(self, api_key: str): self.api_key = api_key self.headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } def calculate_similarity( self, vec_a: List[float], vec_b: List[float] ) -> float: """コサイン類似度の計算""" dot_product = sum(a * b for a, b in zip(vec_a, vec_b)) norm_a = sum(a * a for a in vec_a) ** 0.5 norm_b = sum(b * b for b in vec_b) ** 0.5 return dot_product / (norm_a * norm_b + 1e-10) def hybrid_search( self, query: str, vector_store: List[Dict], top_k: int = 5 ) -> List[SearchResult]: """ ハイブリッド検索:ベクトル類似度 + キーワード一致 """ # Step 1: クエリのEmbedding生成 query_payload = { "input": query, "model": "text-embed-003", "encoding_format": "float" } query_response = requests.post( f"{BASE_URL}/embeddings", headers=self.headers, json=query_payload, timeout=30 ) if query_response.status_code != 200: raise Exception(f"クエリEmbedding失敗: {query_response.text}") query_embedding = query_response.json()["data"][0]["embedding"] # Step 2: 全ドキュメントとの類似度計算 scored_docs = [] for doc in vector_store: similarity = self.calculate_similarity( query_embedding, doc["values"] ) # キーワード一致スコア(BM25簡略版) keyword_score = 0.0 query_terms = query.lower().split() content_lower = doc["metadata"]["content"].lower() for term in query_terms: if term in content_lower: keyword_score += 1.0 / len(query_terms) # 複合スコア(ベクトル0.7 + キーワード0.3) combined_score = 0.7 * similarity + 0.3 * keyword_score scored_docs.append({ "doc": doc, "combined_score": combined_score, "vector_score": similarity, "keyword_score": keyword_score }) # Step 3: スコア順でソート scored_docs.sort(key=lambda x: x["combined_score"], reverse=True) # Step 4: トップk件の返回 results = [] for item in scored_docs[:top_k]: doc = item["doc"] results.append(SearchResult( content=doc["metadata"]["content"], score=item["combined_score"], doc_type=doc["metadata"]["doc_type"], source=doc["metadata"]["source"], image_data=doc["metadata"].get("image_base64") )) return results def generate_response( self, query: str, context_results: List[SearchResult], model: str = "claude-sonnet-4.5" ) -> str: """ HolySheep AI LMM で回答生成 画像コンテキストがある場合はマルチモーダルプロンプトを使用 """ # コンテキスト文字列の構築 context_parts = [] for idx, result in enumerate(context_results): context_parts.append( f"[{idx + 1}] ({result.doc_type}) {result.content}\n" f" 出典: {result.source} | スコア: {result.score:.3f}" ) context_string = "\n\n".join(context_parts) # LLM プロンプト構築 if any(r.image_data for r in context_results): # マルチモーダルプロンプト(画像あり) payload = { "model": model, "max_tokens": 1024, "messages": [ { "role": "user", "content": [ { "type": "text", "text": f"""以下の契約書・書類データベースを検索した結果に基づいて、ユーザーの質問に回答してください。 【検索で得られた関連文書】 {context_string} 【ユーザーの質問】 {query} 回答は以下の構成で作成してください: 1. 関連条文の引用 2. 法的根拠の説明 3. 具体的な推奨事項 4. リスク評価(該当する場合) 必ず検索結果を根拠として引用し、推測による回答は避けてください。""" } ] } ] } else: # テキストのみプロンプト payload = { "model": model, "max_tokens": 1024, "messages": [ { "role": "system", "content": "あなたは契約書分析の専門家です。提供された文脈に基づいて正確でerioな回答を生成してください。" }, { "role": "user", "content": f"""【文脈】 {context_string} 【質問】 {query} 法的な観点から詳細に回答してください。""" } ] } response = requests.post( f"{BASE_URL}/chat/completions", headers=self.headers, json=payload, timeout=60 ) if response.status_code != 200: raise Exception(f"LMM生成失敗: {response.text}") return response.json()["choices"][0]["message"]["content"]

使用例

if __name__ == "__main__": searcher = MultimodalRAGSearcher(API_KEY) # 検索クエリ query = "業務委託契約における瑕疵担保責任の期間は多久ですか?" # ベクトルストア(前述の構築スクリプトで生成したものをロード) # vector_store = load_vector_store("vector_store.json") # ハイブリッド検索実行 results = searcher.hybrid_search(query, vector_store, top_k=3) print(f"検索完了: {len(results)}件の結果") for r in results: print(f" - {r.doc_type}: {r.content[:50]}... (スコア: {r.score:.3f})") # 回答生成 # response = searcher.generate_response(query, results) # print(response)

移行手順:カナリアデプロイメント

私が MIRAI Analytics と実施した移行手順は、安全なカナリアデプロイメント方式进行いました。

Step 1: base_url と API キーの置換

# 旧構成(別のアジア系プロバイダー)
export OPENAI_API_BASE="https://api.asian-provider.com/v1"
export OPENAI_API_KEY="old_provider_key_xxxxx"

新構成(HolySheep AI)

export HOLYSHEEP_API_BASE="https://api.holysheep.ai/v1" export HOLYSHEEP_API_KEY="YOUR_HOLYSHEEP_API_KEY"

Step 2: キーローテーションスクリプト

#!/bin/bash

カナリア移行スクリプト

MIRAI Analytics での実際の運用を再現

set -e

環境変数読み込み

source .env.holysheep

現在のトラフィック配分(旧:新)

CURRENT_OLD=100 CURRENT_NEW=0 TARGET_OLD=0 TARGET_NEW=100 echo "=== HolySheep AI カナリア移行開始 ===" echo "フェーズ 1: 5% トラフィック転送"

Nginx/ロードバランサー設定更新(例)

cat > /etc/nginx/conf.d/canary_upstream.conf << 'EOF' upstream backend { server old-provider.api:443 weight=95; server api.holysheep.ai:443 weight=5; } upstream backend_safe { # HolySheep のみ server api.holysheep.ai:443 weight=1; } EOF

監視期間(72時間)

sleep 72h echo "フェーズ 2: 25% トラフィック転送"

weight 調整

old: 75, new: 25

sleep 48h echo "フェーズ 3: 50% トラフィック転送"

old: 50, new: 50

sleep 48h echo "フェーズ 4: 100% 完全移行"

nginx リロードして新構成適用

systemctl reload nginx

echo "=== 移行完了 ===" echo "旧プロバイダー: $CURRENT_OLD% -> $TARGET_OLD%" echo "HolySheep AI: $CURRENT_NEW% -> $TARGET_NEW%"

移行後30日の実測値

MIRAI Analytics での移行後30日間の私が計測した実績値は以下の通りです:

HolySheep AI の2026年 pricing (/MTok) は以下の通りです:

よくあるエラーと対処法

私が MIRAI Analytics の移行支援中に遭遇した