LLM を使ったアプリケーション開発を始めると、まず直面するのが「どのフレームワークを選ぶか」という問いです。LangChain、LlamaIndex、Haystack など選択肢は豊富ですが、Stanford NLP が開発した DSPy は、これらとは根本的に異なるアプローチを取っています。
「DSPy とは何か」を調べて概念は理解できたものの、「自分がすでに LangChain で組んでいる RAG パイプラインやエージェントに、実際どう組み込めばよいのか」でつまずいてしまう方は少なくありません。既存資産を捨てて全面移行する必要があるのか、部分的に組み込めるのか、学習コストはどれくらいかかるのか——こうした疑問が解消されないまま、「概念は分かったが試すには至っていない」状態で止まってしまうのはよくあることです。
本記事では、stanfordnlp/dspy(スター数: 33,943 / ライセンス: MIT)を取り上げ、DSPy の設計思想(Prompting vs Programming)を理解したうえで、インストールから最初のプログラム、プロンプトの自動最適化までを実際に手を動かして学べるステップバイステップのチュートリアルを解説します。あわせて、RAG・チェーン・エージェントへの適用パターンと、LangChain・LlamaIndex という既存資産をどう活かすかの実務的な判断材料も整理します。読み終えたときには、自分のプロジェクトで「まず試してみる」ための具体的な一歩が見えている状態を目指します。
DSPy とは: プロンプトではなくプログラムで LLM を制御する
スタンフォード大学が開発した LLM プログラミングフレームワーク
DSPy(Declarative Self-improving Python)は、スタンフォード大学の NLP 研究チームが開発した Python フレームワークです。
公式 GitHub リポジトリには、このキャッチフレーズが掲げられています。
DSPy: The framework for programming—not prompting—language models
「プロンプティングではなく、プログラミング」。このシンプルな一文が、DSPy の本質を表しています。
2023年10月に発表された論文「DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines」を起点に開発が進み、2026年4月現在でバージョン 3.2.0 がリリースされています。スター数は 33,943、フォーク数は 2,831 と、研究コミュニティを中心に着実に普及しています。
基本情報(出典: stanfordnlp/dspy GitHub):
項目 | 値 |
|---|---|
バージョン | 3.2.0(2026-04-21) |
ライセンス | MIT |
言語 | Python(99.3%) |
スター数 | 33,943 |
フォーク数 | 2,831 |
Prompting vs Programming: DSPy の設計思想を理解する
DSPy を実際に触る前に、まず押さえておきたいのが「プロンプティング」と「プログラミング」という二つのアプローチの違いです。ここを理解しておくと、後述のチュートリアルで書くコードの意味が腹落ちしやすくなります。
従来のプロンプトエンジニアリングが抱える三つの問題
従来の LLM アプリ開発では、「どう質問するか」「どう指示を書くか」というプロンプトの手動調整が開発作業の中心でした。このアプローチには根本的な問題があります。
- 脆弱性: LLM のバージョンアップや言語を変えると、プロンプトを書き直す必要がある
- 非体系性: 試行錯誤でプロンプトを改善するため、再現性が低い
- 密結合: システムの本質的な処理ロジックとプロンプト表現が混在してしまう
これは、既に LangChain でプロンプトテンプレートを管理している方ほど実感しやすい問題です。モデルを差し替えるたびにテンプレートの文言を調整し直した経験がある方は多いのではないでしょうか。
DSPy のアプローチ: 「何をしてほしいか」だけを宣言する
DSPy はこの問題を、「プロンプトを書く作業をフレームワーク側に委ねる」ことで解決します。開発者は「何をしてほしいか(入力と出力の型)」を宣言的に記述するだけで、最適なプロンプトは DSPy のオプティマイザーが自動生成・調整します。
この設計思想は、以下の三つの中核概念によって実現されています。

概念 | 役割 |
|---|---|
Signatures(シグネチャ) | 「何を入力して何を出力するか」を宣言的に定義する |
Modules(モジュール) | プロンプティング技術(段階的思考・ツール利用など)を抽象化した再利用可能な部品 |
Optimizers(オプティマイザー) | Signature と Module の組み合わせを、トレーニングデータに基づいて自動最適化する |
「プロンプトを書く」のではなく「入出力の型と処理の型を宣言し、最適化を自動化する」——これが Prompting から Programming への転換です。次の章では、実際にこの三つの概念を使ってコードを書きながら体験します。
ステップバイステップで学ぶ DSPy 実装チュートリアル
ここからは、インストールから最初のプログラム、プロンプトの自動最適化までを順を追って実装します。すべて公式ドキュメントに掲載されている検証済みのコード例です。
ステップ1: インストールする
インストールは pip で行います(出典: stanfordnlp/dspy GitHub)。
pip install dspy
最新の開発版を使用する場合は以下のコマンドを使います(出典: stanfordnlp/dspy GitHub)。
pip install git+https://github.com/stanfordnlp/dspy.git
ステップ2: 最初のプログラムを書く——Signature で入出力を宣言する
Signature(シグネチャ)は、LLM モジュールの「入力と出力の型定義」です。「どのように処理するか」ではなく「何を入力して何を出力するか」を記述します。
最もシンプルなのはインライン形式です(出典: DSPy Expanding Signatures ガイド)。
haiku_bot = dspy.Predict("location, mood -> haiku")
result = haiku_bot(location="a quiet library", mood="mysterious")
print(result.haiku)
"location, mood -> haiku" という文字列が Signature です。これだけで「場所(location)と雰囲気(mood)を入力として受け取り、俳句(haiku)を生成する」モジュールが定義されます。プロンプトの文言は一切書いていない点に注目してください。
より複雑なケースではクラスベースの Signature を使用します(出典: DSPy Class-Based Signatures ガイド)。
class HaikuBot(dspy.Signature):
"""
Write a classical haiku given the provided inputs.
"""
location: str = dspy.InputField(desc="The setting of the poem")
mood: str = dspy.InputField()
haiku: str = dspy.OutputField()
haiku_bot = dspy.Predict(HaikuBot)
result = haiku_bot(location="a quiet library", mood="mysterious")
print(result.haiku)
入力・出力フィールドは typing.Literal で値の範囲を制約することもできます(出典: DSPy Class-Based Signatures ガイド)。
from typing import Literal
Season = Literal["spring", "summer", "autumn", "winter"]
class HaikuBot(dspy.Signature):
"""
Write a classical haiku given the provided inputs.
"""
location: str = dspy.InputField()
mood: str = dspy.InputField()
season: Season = dspy.InputField()
haiku: str = dspy.OutputField()
haiku_bot = dspy.Predict(HaikuBot)
result = haiku_bot(location="Bodega Bay", mood="mysterious", season="autumn")
print(result.haiku)
実行結果(例):
Fog drifts over waves,
Crimson leaves swirl by the pier—
Night whispers secrets.
season に Literal の候補以外の値が渡されると、DSPy が型不一致の警告を出す仕組みになっており、値の範囲を宣言レベルで制約できます。
たった数行で俳句生成タスクが完成しました。この段階ではまだ「基本モジュール(dspy.Predict)」を使っているだけですが、DSPy には他にも以下のようなモジュールが用意されています(出典: DSPy API リファレンス(Modules))。
モジュール | 説明 |
|---|---|
| 基本的な予測(シグネチャをそのまま適用) |
| 段階的思考の推論プロセスを生成 |
| Python コードを生成して実行 |
| ツールを利用するエージェント |
| 複数の ChainOfThought 出力を比較 |
ステップ3: ChainOfThought で推論プロセスを可視化する
dspy.ChainOfThought を使うと、LLM に段階的な思考プロセスを踏ませながら回答を生成させられます。Signature は差し替えずに、モジュールを dspy.Predict から dspy.ChainOfThought に変更するだけです(出典: DSPy Changing Modules ガイド)。
reasoning_haiku_bot = dspy.ChainOfThought(HaikuBot)
result = reasoning_haiku_bot(location="Bodega Bay", mood="mysterious", season="autumn")
print(result.haiku)
Signature を変更していないのに、実行結果には reasoning フィールドが自動的に追加され、LLM が俳句を生成する前の思考プロセスが記録されます。モジュールを差し替えるだけでプロンプティング技術が切り替わり、Signature 自体には手を入れる必要がありません。
ステップ4: Optimizer でプロンプトを自動最適化する
Optimizer(オプティマイザー)は、DSPy 最大の特徴です。定義した Signature と Module の組み合わせを受け取り、トレーニングデータに基づいてプロンプトとモデルの重みを自動的に最適化します。
DSPy Optimizers 選択ガイドでは、12種類のオプティマイザーが最適化対象によって分類されています。
オプティマイザー | 概要 |
|---|---|
MIPROv2 | 命令と few-shot 例を両方自動生成・最適化 |
BootstrapFewShot | few-shot 例を自動合成 |
GEPA | 反省(リフレクション)用の LM を使ってプロンプトを反射的に進化 |
BootstrapFinetune | モデル重みをファインチューニング |
COPRO | 命令を座標降下法で最適化 |
SIMBA | ミニバッチ対応の最適化 |
状況別の選択チートシートも示されています(出典: 同ガイド)。
状況 | 推奨オプティマイザー |
|---|---|
初期段階でまず試したい | BootstrapFewShot |
デモ(few-shot 例)の品質が不安定 | BootstrapFewShotWithRandomSearch |
命令(instruction)に問題がある | COPRO または GEPA |
命令・デモの両方が弱い | MIPROv2 または GEPA |
代表的なオプティマイザーとして、公式のステップバイステップガイドでも扱われている GEPA の使用例は以下のとおりです(出典: DSPy GEPA Optimization ガイド)。
def haiku_score_gepa(example, prediction, trace=None, pred_name=None, pred_trace=None):
text = prediction.haiku.lower()
if example.season.strip().lower() in text:
return dspy.Prediction(
score=0.0,
feedback="Don't reference the input season verbatim."
)
return dspy.Prediction(score=1.0, feedback=None)
optimizer = dspy.GEPA(
metric=haiku_score_gepa,
reflection_lm=reflection_lm,
auto="light",
num_threads=2,
)
optimized_haiku_bot = optimizer.compile(haiku_bot, trainset=train, valset=val)
GEPA は、通常の評価スコアだけでなく feedback(改善のヒントとなるテキスト)も返すメトリクス関数を受け取り、別の LM(reflection_lm)にその feedback を分析させて指示文を反復的に改善します。optimizer.compile(...) を実行するだけで、トレーニングデータに基づいてパイプライン全体のプロンプトが自動最適化される点は他のオプティマイザーと共通です。ここまでの4ステップ——インストール、Signature でのプログラム記述、Module による推論プロセスの選択、Optimizer による自動最適化——が DSPy 実装の基本サイクルです。
RAG・チェーン・エージェントへの適用パターン
基本サイクルを理解したところで、実際のプロジェクトで頻出する3つのパターン(RAG・複数モジュールのチェーン・エージェント)への適用方法を見ていきます。
RAG パイプラインに組み込む
RAG(検索拡張生成)パイプラインも ChainOfThought を使って簡潔に記述できます。公式の DSPy RAG チュートリアルでは、StackExchange 発の技術 Q&A データセット(RAG-QA Arena "Tech")を題材に、以下のような Signature でパイプラインを構築する例が示されています(出典: 同チュートリアル)。
rag = dspy.ChainOfThought('context, question -> response')
response = rag(context=retrieve(question), question=question)
既存の検索処理(ベクトル検索・キーワード検索の関数)はそのまま retrieve のような関数として流用し、DSPy 側は「文脈(context)と質問(question)を受け取り応答(response)を返す」という Signature に集約する構成です。検索部分を LangChain の Retriever でそのまま維持しつつ、生成部分だけを DSPy 化するといった段階的な移行もこの構成で可能です。
複数モジュールをチェーンする——カスタム Module クラスの設計
複数のモジュールを組み合わせた複雑なパイプラインは、dspy.Module を継承したカスタムクラスとして、Python のクラス設計として自然に記述できます(出典: DSPy Composing Modules ガイド)。
class HaikuEnsemble(dspy.Module):
def __init__(self, n: int = 3):
super().__init__()
self.n = n
# Module 1: 複数の俳句候補を生成する
self.writer = dspy.ReAct(
"location, season, mood, num_haikus: int -> haikus: list[str]",
tools=[wikipedia_search, get_wikipedia_page],
max_iters=5
)
# Module 2: 最も評価の高い候補を選ぶ
self.judge = dspy.ChainOfThought(
"location, season, mood, candidates: list[str] -> most_evocative_index: int"
)
def forward(self, location: str, season: str, mood: str) -> dspy.Prediction:
candidates = self.writer(
location=location, season=season, mood=mood, num_haikus=self.n,
).haikus
verdict = self.judge(
location=location, season=season, mood=mood, candidates=candidates,
)
return dspy.Prediction(
haiku=candidates[verdict.most_evocative_index],
candidates=candidates,
reasoning=verdict.reasoning,
)
この HaikuEnsemble クラスは、「生成担当(writer)」と「審査担当(judge)」という役割の異なる2つのモジュールを __init__ でサブモジュールとして定義し、forward で処理順序を記述する構成です。LangChain の Chain や LCEL でパイプラインを組んだことがある方であれば、この構造は理解しやすいはずです。違いは、各ステップのプロンプトを手書きするのではなく Signature で宣言し、パイプライン全体を後から Optimizer でまとめて最適化できる点にあります。検索・生成・審査といった複数ステップを持つ独自のパイプライン(例: マルチホップ検索、多段階の要約・検証チェーン)も、同じ「サブモジュールを __init__ で定義し forward で結ぶ」設計パターンで実装できます。
ツールを使うエージェントを構築する——ReAct
dspy.ReAct を使うと、ツールを組み合わせたエージェントも構築できます。ツールは型ヒントと docstring を備えた通常の Python 関数として渡すだけで済みます(出典: DSPy React and Tools ガイド)。
def wikipedia_search(query: str) -> list[str]:
"""Search Wikipedia for the given query and return a list of page titles."""
return wikipedia.search(query)
haiku_bot = dspy.ReAct(HaikuBot, tools=[wikipedia_search, get_wikipedia_page])
result = haiku_bot(location="Camp Meeker", mood="pensive", season="summer")
DSPy はツール関数の名前・引数・docstring を読み取り、LLM に渡す指示を自動的に組み立てます。加えて、タスク完了を知らせる finish ツールも自動的に用意され、実行結果の trajectory フィールドには思考・ツール呼び出し・観察結果の履歴が記録されます。ツール定義は Python 関数として渡すだけで済み、LangChain の Tool や Agent の概念に近い感覚で扱えます。既存の LangChain ツール実装がある場合も、関数として呼び出し可能であればそのまま tools 引数に渡せるケースが多く、ゼロから書き直す必要はありません。
LangChain・LlamaIndex との使い分け——既存資産をどう活かすか
DSPy を導入するかどうかは「どちらか一方を選ぶ」二択ではありません。ここまでのチュートリアルと適用パターンを踏まえ、既存の LangChain・LlamaIndex 資産をどう活かしながら DSPy を組み込むかという実務的な観点で整理します。
LangChain プロジェクトに部分的に組み込む
すでに LangChain でプロトタイプが動いている場合、全面移行は必須ではありません。前章の RAG パイプラインの例のように、検索・ツール呼び出しなど既存の実装はそのまま関数として流用し、「精度を定量的に最適化したい生成部分」だけを DSPy の Signature・Module に置き換える構成が現実的な第一歩です。DSPy は他フレームワークと競合するというより、その上に乗せる最適化層として機能します。
具体的には、以下のような判断基準で部分導入を検討できます。
- 精度の最適化が重要な場面: QA パイプライン、情報抽出、分類タスクなど、定量的な評価指標で最適化したい箇所から着手する
- 複数モデルをテストしたい場合: Signature と Module を再定義せずに LLM を差し替えられるため、GPT-4o と Gemini などの比較が容易
- プロンプトのバージョン管理・再現性に悩んでいる箇所: 手動調整を繰り返している生成ロジックを優先的に DSPy 化する
一方で、複雑な多段ワークフローを明示的に手動制御したい場合や、70 以上のプロバイダー統合など LangChain のエコシステムの広さに依存している部分は、無理に置き換えず LangChain のまま維持するのが妥当です。
LlamaIndex との組み合わせパターン
LlamaIndex と DSPy も競合ではなく補完関係にあります。一般的な組み合わせパターンとして以下が推奨されています。
- LlamaIndex でデータ取込・インデックス構築: 大量ドキュメントの取込と検索に LlamaIndex を使用
- DSPy で検索クエリと回答生成を最適化: DSPy のオプティマイザーで精度を自動チューニング
つまり「データ層は LlamaIndex、生成ロジックの最適化は DSPy」という役割分担です。前章の RAG パイプラインの context に LlamaIndex の検索結果をそのまま渡す形で組み込めます。
プロジェクト状況と将来性
DSPy は 2026 年 4 月現在、活発に開発が継続されています。
- スター数: 33,943(成長中)
- 最新バージョン: 3.2.0(2026-04-21 リリース)
- 総リリース数: 107 件(継続的なアップデート)
- 最終コミット: 2026-04-21(前日に更新)
- 開発元: Stanford NLP(スタンフォード大学自然言語処理グループ)
研究論文を基盤に持つプロジェクトであり、学術的な信頼性とプロダクションでの実用性を両立しています。MIT ライセンスで提供されているため、商用利用も問題ありません。
まとめ: 「選ぶかどうか」から「試してみる」へ
従来の LLM 開発では、優れた「プロンプト職人」がいないとシステムの品質が安定しないという課題がありました。DSPy はこの問題を、プロンプトを「書く」から「最適化される」ものに変えることで解決します。
本記事で見てきたとおり、DSPy の導入は LangChain・LlamaIndex を捨てる全面移行ではなく、既存資産の一部を段階的に置き換える形で始められます。まず自分のプロジェクトで試すための次の一歩は、以下の順で進めるとつまずきにくくなります。
pip install dspyで環境を用意する- 既存パイプラインの中で「プロンプトの手動調整に一番悩んでいる箇所」を1つ選び、
dspy.Predictまたはdspy.ChainOfThoughtの Signature で書き直す - 動作を確認できたら、小規模なトレーニングデータを用意して Optimizer(
BootstrapFewShotやMIPROv2)を実行し、効果を比較する - 効果が確認できた範囲から、RAG・チェーン・エージェントへと適用範囲を広げる
「DSPy を選ぶか、LangChain を選ぶか」という判断で立ち止まる必要はありません。プロンプトのバージョン管理・再現性に悩んでいる箇所、タスクの精度を定量的に最適化したい箇所から、既存資産を維持したまま部分的に試してみることが、DSPy を検討する上での現実的な出発点です。
詳細は公式ドキュメント(dspy.ai)およびGitHub リポジトリをご参照ください。



