← Resources
TUTORIAL · 2026-02-12
LangChain不使用で本番RAGパイプラインを構築する(2026年版)
本番品質のRAGパイプラインは、プロバイダSDK、pgvector、リランカーを直接組み合わせれば数百行のコードで実装できます。LangChainの抽象化は、具体的な必要性が生じるまで先送りしましょう。
2026年、LangChainからの脱却が広がる理由
2026年までに、本番環境からLangChainを取り除くことは認知されたエンジニアリングパターンとなり、かつてエヴァンジェリストだったチームからの公開ポストモーテムも複数発表されています。指摘内容は一貫しています。モデルへ実際に送られる内容を覆い隠す層状の抽象化、マイナーバージョン間で頻発する破壊的変更、そしてラッパークラスの中を探検するデバッグセッション。
根本的な変化は、プロバイダSDKが成熟したことです。OpenAI、Anthropic、GoogleのSDKは、ストリーミング、構造化出力、ツール呼び出し、バッチ処理を一級機能として提供するようになりました。Voyage、Cohere、Jinaはエンベディングとリランキング向けのクリーンなRESTエンドポイントを公開しています。pgvectorを搭載したPostgresは、専用ベクトルDBなしで約1,000万ベクトル規模までのANN検索を処理できます。
大半のRAGワークロードでは、2023年に求められていたフレームワークは、今や4つの関数呼び出しと1つのSQLクエリに置き換わっています。2026年の妥当なデフォルトは、生のSDKから始め、実際の苦痛を感じてから薄いパイプライン抽象を加え、重量級フレームワークはオプトイン扱いとすることです。
すべてのRAGパイプラインに必要な5ステージ
フレームワークの有無に関わらず、すべての本番RAGシステムは同じ5ステージに分解されます。明示的に命名することで、コードのテストと部分置換が容易になります。
- 取り込み: ソース文書を読み込み、エンコーディングを正規化し、定型部分を除去する。
- チャンク化: 安定IDとソースメタデータ付きの検索単位に分割する。
- エンベディングと索引付け: チャンクをベクトルストアに符号化し、語彙索引も並行して構築する(ハイブリッド検索のため)。
- 検索とリランキング: 広い候補集合を取得し、クロスエンコーダリランカーで絞り込む。
- 生成と引用: 検索コンテキストを伴うプロンプトを組み立て、出典帰属付きで回答を返す。
各ステージを型付きの純粋関数として保ちます。検索ステージはどのLLMが生成するかを知るべきではなく、生成ステージはどのエンベディングモデルが使われたかを知るべきではありません。この分離こそフレームワークが約束しながら実現しないものです。なぜならフレームワークは不透明なチェーンオブジェクトを介してステージを結合するからです。自分で書けば半日で済み、アップグレードリスクのカテゴリを一つ消せます。
チャンキング戦略: セマンティック、再帰、エージェント型
チャンキングはRAG品質の大半が決まる場所です。2026年で支配的な3パターンを紹介します。
セパレータ階層(段落、文、文字)による再帰的文字分割がベースラインです。高速、決定論的、散文には十分です。セマンティックチャンキングは候補分割点をエンベディングし、エンベディングが近い隣接チャンクを統合することで、取り込みコストは高いものの話題的に首尾一貫した単位を生成します。エージェント型チャンキングは小さなLLMに分割点を提案させ、文字数より見出しや発話境界が重要な契約書や議事録のような構造化文書に向きます。
def recursive_chunk(text, max_chars=1200, overlap=150):
seps = ["\n\n", "\n", ". ", " "]
def split(s, depth=0):
if len(s) <= max_chars or depth == len(seps):
return [s]
parts, sep = [], seps[depth]
for p in s.split(sep):
parts.extend(split(p, depth + 1))
return parts
raw = split(text)
return [raw[i] + raw[i+1][:overlap] for i in range(len(raw)-1)] + [raw[-1]]
まず再帰から始め、計測し、評価で効果が確認できた文書クラスでのみセマンティックへ昇格させます。
エンベディングとリランカー: Voyage、BGE、Cohere
2026年のリトリーバ事情は、1年前より明確になりました。MongoDB傘下となったVoyage AIはvoyage-3-largeを汎用密モデルとして提供し、2026年初頭にRTEBリーダーボード上位を狙うMoEバリアントを含むvoyage-4ファミリーをリリースしました。Cohereのembed-v4はもう一方の本番フロントランナーです。オープン重みでのセルフホストには、BAAIのbge-m3が依然デフォルトです。100以上の言語にわたり密・疎・マルチベクトル検索を単一モデルで処理し、8192トークンのコンテキストを備えます。
リランキングでは、Cohereのrerank-v3.5が定番です。多言語対応、4096トークンチャンク、典型的なペイロードで約80〜150msのp50レイテンシ。Voyage rerank-2も競争力があり、すでにVoyageエンベディングを使っているならクリーンに統合できます。
実務上のルール: 密エンベッダ1つ、リランカー1つを選び、ペアをインターフェース背後で固定します。後から入れ替えてもインデックス再構築のコストで済み、書き直しにはなりません。
検索、生成、引用を配線する
pgvectorを用いれば、ハイブリッド検索と引用を素直なSQLで実現できます。チャンクを文書ID、エンベディング、語彙再現用のtsvectorと共に保存します。広い候補集合を取得しリランキングを行い、上位N件を明示的なソースID付きでLLMへ渡し、引用するよう指示します。
import psycopg, voyageai, cohere
vo, co = voyageai.Client(), cohere.Client()
def retrieve(query, k=40, top_n=8):
qvec = vo.embed([query], model="voyage-3-large").embeddings[0]
with psycopg.connect(DSN) as conn:
rows = conn.execute(
"SELECT id, doc_id, text FROM chunks ORDER BY embedding <=> %s LIMIT %s",
(qvec, k)).fetchall()
docs = [r[2] for r in rows]
ranked = co.rerank(model="rerank-v3.5", query=query, documents=docs, top_n=top_n)
return [rows[r.index] for r in ranked.results]
```
pgvectorはm=16、ef_construction=64のHNSWインデックスをデフォルトとし、テナントや時系列のプリフィルタを追加してANNスキャンの開始範囲を狭め、`ORDER BY embedding <=> $1`を必ず`LIMIT`と組み合わせます。検索済みチャンクをIDと共にLLMへ渡し、引用マーカーを出力するよう指示し、後処理でそれらを出典URLへ解決してください。
評価: ヒット率、MRR、忠実性
評価ハーネスのないRAGパイプラインは推測です。チューニング前にハーネスを構築してください。最小キットは、実際に想定する質問タイプを網羅した100〜500件のラベル付きクエリセットと3つの指標です。
上位K件ヒット率は、正しいチャンクが候補集合に入ったかを答え、検索品質を分離します。平均逆数順位(MRR)は正解チャンクがどれほど上位にランクされたかを捉え、リランカーが改善を期待される指標です。忠実性は、各生成主張を引用チャンクと比較するよう促されたLLM判定者が採点し、モデルがコンテキストを超えてハルシネーションしたかを捉えます。
ハーネスは変更ごとに走らせます。新しいチャンクサイズ、別のエンベッダ、プロンプト編集など。3つの指標を同一ダッシュボードで時系列プロットします。MRRが改善しても忠実性が低下した変更は、リランカーがディストラクタを表出させており、検索チューニングではなく生成プロンプトのガードレールが必要なサインです。
マネージドオーケストレータへ昇格すべき時
手作りパイプラインは、1チームが所有しステージ数が少ない間は保守可能です。マネージドオーケストレータが採算に合うのは、非エンジニアが検索をチューニングする必要が生じた時、文書クラスごとに多数のパイプラインを並行運用する時、再デプロイなしのバージョン管理された設定とA/Bルーティングが必要になった時です。
その段階での選択肢は、LlamaIndexやHaystackのような重量級フレームワークか、検索ステージを宣言的単位として露出する設定駆動型プラットフォームです。osFoundryに含まれるノーコードオーケストレーションエディタosStudioは後者のアプローチを採り、上記5ステージを一級設定オブジェクトとして扱い、Voyageのマネージドエンベディングとリランキングを単一プロキシ背後で提供します。LLM側はBYOKを保ちつつ、検索側でフレームワークロックインを回避できます。
有益な問いはフレームワーク有無ではなく、パイプライン設定がコードか設定かUIに値するかであり、その答えはチームの成長に応じて変わります。
Frequently asked questions
- RAGにベクトルDBは本当に必要ですか?
- 数百万ベクトルを超えるまでは、おそらく不要です。pgvectorを搭載したPostgresは、HNSWインデックス、tsvectorによるハイブリッド検索、テナントや時系列向けの標準SQLフィルタにより、約1,000万ベクトル規模まで快適に処理できます。すでに運用しているDBからバックアップ、レプリケーション、アクセス制御を継承できます。Qdrant、Milvus、Weaviateのような専用ベクトルDBが運用コストに見合うのは、シャード化された数十億規模のインデックス、極めて高いQPS下での専門的フィルタリング、pgvectorがまだ追いついていないマルチベクトル検索などが必要になった時です。pgvectorから始め、計測されたボトルネックが移行を強制する場合にのみ移行してください。
- リランカーはレイテンシに見合う価値がありますか?
- 検索重視のワークロードでは、ほぼ間違いなく「はい」です。Cohere rerank-v3.5やVoyage rerank-2のようなクロスエンコーダリランカーは、40〜100チャンクの候補集合でp50に通常80〜200ミリ秒を追加し、密検索単独に対しMRRを一貫して10〜30%引き上げます。レイテンシは後続のLLM呼び出し内に隠れ、通常ユーザ可視予算の大半を占めるのはそちらです。リランカーをスキップすべきなのは、エンドツーエンドで200ミリ秒未満が必要なオートコンプリート系のレイテンシクリティカルなフローか、候補集合がすでに小さく密ランキングで十分信頼できる場合のみです。
- チャンクオーバーラップをストレージ膨張なしに扱うには?
- 10〜15%程度の小さなオーバーラップを使い、テキストを複製するのではなく、ソース文書への文字オフセットとして保存します。検索時に必要なら隣接チャンクを取得してコンテキスト拡張できます。これによりインデックスを軽量に保ち、エンベディング時に同じトークンを二重支払いせずに済みます。生成向けにより豊富なコンテキストが必要なら、親文書パターンが有効です。検索精度のため小チャンクを索引化し、ヒットを親セクションへ解決してからLLMへ渡します。親ルックアップはインデックス付きクエリ一回で済み、レイテンシ増加は無視できる程度です。
- RAG品質を評価する最もシンプルな方法は?
- 100〜200件の代表的クエリと、検索されるべきチャンクIDのラベル付きセットを構築してください。検索ステージのみから上位Kヒット率とMRRを計算することで、検索品質を生成ノイズから分離します。忠実性については、各生成主張を引用チャンクと比較し、根拠あり/未支持を採点するようプロンプトされたLLM判定者を使用します。意味ある変更ごとに3つの数値を走らせ、退行をブロッカーとして扱います。この3指標構成は実務上のRAG退行の大半を捕捉し、片方の数値を最適化しながら別の数値を密かに損なうトラップを回避します。
Sources