AI検索エンジン再構築実践:セマンティック検索とLLM拡張検索アーキテクチャ

AI与大数据

概要

  • AI検索は従来の検索を覆しています:「キーワードマッチング」から「セマンティック理解+インテリジェント生成」へ、2026年のAI検索市場規模は$50億を突破
  • セマンティック検索3層アーキテクチャ:クエリ理解→ベクトル検索→LLMリランキング+生成、検索精度が35%以上向上
  • ベクトル検索エンジンの選定:Milvusは大規模向け、Qdrantは中小規模向け、Elasticsearch 8.xはハイブリッド検索向け
  • LLM拡張ランキング(リランキング)はAI検索の切り札です:Cross-EncoderリランキングによりNDCGを15%-25%向上可能
  • 本記事では、従来の検索からAI検索への完全な再構築ソリューションを提供します。Elasticsearch+Milvusデュアルエンジンアーキテクチャ付き

目次


AI検索:検索の次世代パラダイム

従来の検索 vs AI検索

次元 従来の検索(BM25) AI検索(セマンティック+LLM)
マッチング方式 キーワード完全一致 セマンティック類似度マッチング
クエリ理解 トークン化+同義語 意図認識+エンティティ抽出
ランキングシグナル TF-IDF+PageRank セマンティック関連性+ユーザー意図
結果表示 10個のブルーリンク 直接回答+引用ソース
複雑なクエリ 弱い(正確なキーワードが必要) 強い(自然言語を理解)
リアルタイム性 高い(インデックス事前構築) 中(リアルタイム推論が必要)

AI検索市場の状況

製品 タイプ コア技術 特徴
Perplexity AIネイティブ検索 RAG+LLM生成 引用ソース
Google SGE 従来+AI拡張 BERT+MUM 最強のエコシステム
Bing Chat 従来+AI拡張 GPT-4+Prometheus Microsoftエコシステム
秘塔AI検索 AIネイティブ検索 自社開発RAG 中国語最適化
夸克AI検索 従来+AI拡張 自社開発モデル モバイルファースト

セマンティック検索3層アーキテクチャ

┌──────────────────────────────────────────────────────────────┐
│              セマンティック検索3層アーキテクチャ                 │
│                                                                │
│  Layer 1: クエリ理解                                          │
│  ┌──────────────────────────────────────────────────────┐    │
│  │ ユーザークエリ → 意図認識 → エンティティ抽出 →       │    │
│  │ クエリ書き換え                                       │    │
│  │ 「K8sでGPUをどう設定するか」→ 意図:チュートリアル →  │    │
│  │ エンティティ:K8s,GPU                                 │    │
│  │ → 書き換え:「Kubernetes GPUスケジューリング設定       │    │
│  │ チュートリアル」                                     │    │
│  └──────────────────────────────────────────────────────┘    │
│                         ↓                                     │
│  Layer 2: マルチパス検索                                      │
│  ┌──────────────────────────────────────────────────────┐    │
│  │ ベクトル検索(Milvus) + キーワード検索(ES) +          │    │
│  │ ナレッジグラフ(Neo4j)                                │    │
│  │ 各パスのTop-K結果を統合 → 重複排除 → 候補セット      │    │
│  └──────────────────────────────────────────────────────┘    │
│                         ↓                                     │
│  Layer 3: LLMリランキング+生成                               │
│  ┌──────────────────────────────────────────────────────┐    │
│  │ Cross-Encoderリランキング → Top-N → LLMが回答+      │    │
│  │ 引用ソースを生成                                      │    │
│  └──────────────────────────────────────────────────────┘    │
└──────────────────────────────────────────────────────────────┘

クエリ理解の実装

class QueryUnderstanding:
    def __init__(self, llm_client, embedding_model):
        self.llm = llm_client
        self.embedding = embedding_model

    async def understand(self, query: str) -> dict:
        intent = await self._classify_intent(query)
        entities = await self._extract_entities(query)
        rewritten = await self._rewrite_query(query, intent, entities)
        query_embedding = self._embed(rewritten)

        return {
            "original_query": query,
            "intent": intent,
            "entities": entities,
            "rewritten_query": rewritten,
            "embedding": query_embedding,
        }

    async def _classify_intent(self, query: str) -> str:
        response = self.llm.chat.completions.create(
            model="Qwen/Qwen2.5-7B-Instruct",
            messages=[{
                "role": "user",
                "content": f"以下の検索クエリの意図を分類してください。カテゴリ名のみ出力:\nクエリ:{query}\nカテゴリ:チュートリアル/トラブルシューティング/製品比較/概念説明/最新ニュース"
            }],
            temperature=0.0, max_tokens=10,
        )
        return response.choices[0].message.content.strip()

    async def _rewrite_query(self, query: str, intent: str, entities: list) -> str:
        response = self.llm.chat.completions.create(
            model="Qwen/Qwen2.5-7B-Instruct",
            messages=[{
                "role": "user",
                "content": f"以下の検索クエリをセマンティック検索に適した形式に書き換えてください。書き換え結果のみ出力:\n元のクエリ:{query}\n意図:{intent}\nエンティティ:{entities}"
            }],
            temperature=0.0, max_tokens=100,
        )
        return response.choices[0].message.content.strip()

ベクトル検索エンジンの選定とデプロイ

エンジン比較

次元 Milvus 2.5 Qdrant 1.13 ES 8.x(kNN)
ベクトルインデックス HNSW/IVF/DiskANN HNSW HNSW
ハイブリッド検索 ✅(BM25+ベクトル) ✅(スパース+デンス) ✅(ネイティブBM25+kNN)
スケール 1億+ <5000万 1億+
レイテンシ(P50) 5ms 3ms 8ms
運用複雑度 高い 低い
エコシステム AI/MLエコシステム Rustエコシステム エンタープライズ検索エコシステム

ES 8.x kNN検索

from elasticsearch import Elasticsearch

es = Elasticsearch("http://localhost:9200")

mapping = {
    "mappings": {
        "properties": {
            "title": {"type": "text", "analyzer": "ik_max_word"},
            "content": {"type": "text", "analyzer": "ik_max_word"},
            "embedding": {
                "type": "dense_vector",
                "dims": 1536,
                "index": True,
                "similarity": "cosine",
                "index_options": {"type": "hnsw", "m": 32, "ef_construction": 256},
            },
            "source": {"type": "keyword"},
            "published_at": {"type": "date"},
        }
    }
}

es.indices.create(index="knowledge_base", body=mapping)

def hybrid_search(query: str, query_embedding: list, top_k: int = 20):
    result = es.search(
        index="knowledge_base",
        body={
            "size": top_k,
            "query": {
                "bool": {
                    "should": [
                        {
                            "script_score": {
                                "query": {"match_all": {}},
                                "script": {
                                    "source": "cosineSimilarity(params.query_vector, 'embedding') + 1.0",
                                    "params": {"query_vector": query_embedding},
                                },
                            }
                        },
                        {
                            "multi_match": {
                                "query": query,
                                "fields": ["title^3", "content"],
                                "type": "best_fields",
                            }
                        },
                    ]
                }
            },
        },
    )
    return [hit["_source"] for hit in result["hits"]["hits"]]

LLM拡張ランキング:リランキング

Cross-Encoderリランキング

from sentence_transformers import CrossEncoder

class SemanticReranker:
    def __init__(self, model_name: str = "BAAI/bge-reranker-v2-m3"):
        self.model = CrossEncoder(model_name, max_length=512)

    def rerank(self, query: str, documents: list[dict], top_k: int = 5) -> list[dict]:
        pairs = [(query, doc["content"][:512]) for doc in documents]
        scores = self.model.predict(pairs)

        for doc, score in zip(documents, scores):
            doc["rerank_score"] = float(score)

        documents.sort(key=lambda x: x["rerank_score"], reverse=True)
        return documents[:top_k]

LLM回答生成

class AISearchGenerator:
    def __init__(self, llm_client):
        self.llm = llm_client

    async def generate_answer(self, query: str, contexts: list[dict]) -> dict:
        context_text = "\n\n".join(
            f"[ソース{i+1}] {c['title']}\n{c['content'][:500]}"
            for i, c in enumerate(contexts)
        )

        response = self.llm.chat.completions.create(
            model="Qwen/Qwen2.5-7B-Instruct",
            messages=[{
                "role": "system",
                "content": "提供された検索結果に基づいてユーザーの質問に回答してください。各事実にはソース番号を付記してください。検索結果が不十分な場合はその旨を記載してください。"
            }, {
                "role": "user",
                "content": f"質問:{query}\n\n検索結果:\n{context_text}"
            }],
            temperature=0.3, max_tokens=1024,
        )

        answer = response.choices[0].message.content
        return {"answer": answer, "sources": contexts[:5]}

リランキングの効果

方法 NDCG@10 MRR@10 レイテンシ
BM25のみ 0.62 0.58 5ms
ベクトル検索のみ 0.71 0.67 8ms
BM25+ベクトルハイブリッド 0.78 0.74 12ms
ハイブリッド+Cross-Encoder 0.89 0.85 35ms

AI検索本番デプロイ:ES+Milvusデュアルエンジン

デプロイアーキテクチャ

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ai-search-api
  namespace: ai-search
spec:
  replicas: 3
  selector:
    matchLabels:
      app: ai-search-api
  template:
    spec:
      containers:
        - name: search-api
          image: myregistry/ai-search-api:v1.0
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: "2"
              memory: 4Gi
            limits:
              cpu: "4"
              memory: 8Gi
          env:
            - name: ELASTICSEARCH_URL
              value: "http://elasticsearch:9200"
            - name: MILVUS_URI
              value: "http://milvus-svc:19530"
            - name: LLM_URL
              value: "http://vllm:8000/v1"
            - name: RERANKER_MODEL
              value: "BAAI/bge-reranker-v2-m3"

検索パフォーマンスベンチマーク

指標 従来の検索 AI検索
検索レイテンシ(P50) 5ms 35ms
検索精度(NDCG@10) 0.62 0.89
回答生成レイテンシ N/A 800ms
ユーザー満足度 3.2/5 4.5/5
ゼロ結果率 12% 2%

まとめと関連記事

AI検索は「キーワードマッチング」から「セマンティック理解+インテリジェント生成」へと進化しています。3層アーキテクチャ(クエリ理解→マルチパス検索→LLMリランキング+生成)により、検索精度が0.62から0.89に向上します。ES+Milvusデュアルエンジンは本番デプロイの標準構成です。

再構築の要点まとめ

  1. AI検索3層アーキテクチャ:クエリ理解→マルチパス検索→LLMリランキング+生成
  2. クエリ書き換えはセマンティック検索の第一歩であり、口語的なクエリを検索に適した形式に変換します
  3. ES 8.x kNNはハイブリッド検索をサポートし、従来の検索からAI検索へのアップグレードに適しています
  4. Cross-EncoderリランキングによりNDCGを15%-25%向上できます
  5. AI検索のレイテンシは35ms(検索)+800ms(生成)であり、レイテンシと精度のトレードオフが必要です

関連記事

権威ある参考資料

ブラウザローカルツールを無料で試す →

#AI搜索引擎#语义搜索#向量检索引擎#LLM搜索增强#搜索架构重构#2026