今回の論文
今回取り上げるのは、Omar Khattab、Arnav Singhvi、Paridhi Maheshwari らによる 2023 年の論文「DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines」です。公開元は arXiv で、研究分野は LLM アプリケーション基盤、プロンプト最適化、RAG やマルチステップ推論のパイプライン設計です。URL は https://doi.org/10.48550/arXiv.2310.03714 です。
この論文を選んだ理由は、単発のプロンプト改善ではなく、LLM を使ったアプリ全体をどう設計し、どう自動改善するかに踏み込んでいるからです。RAG、エージェント、要約、検索支援などは、モデル単体の性能よりも、呼び出し方や中間ステップの設計が品質を左右します。DSPy はそこをコードとして扱い、評価指標に合わせて最適化する発想が明快で、実装にもつなげやすいです。
どんな技術か
DSPy は、LLM アプリを「長いプロンプト文字列」ではなく、「入力と出力が定義されたモジュールの組み合わせ」として書くためのプログラミングモデルです。開発者は、質問から答えを返す、文脈から検索クエリを作る、複数の候補を比較して最終回答を選ぶ、といった処理を宣言的に記述します。
重要なのは、DSPy が単なるラッパーではないことです。書いたパイプラインに対してコンパイラを走らせると、評価指標が上がるように few-shot 例、推論の型、デモンストレーション、場合によっては小型モデルのファインチューニングまで自動で組み合わせます。つまり DSPy は、LLM アプリを「書いて終わり」ではなく「コンパイルして改善する対象」に変える技術です。
課題
この技術が解決しようとしているのは、LLM アプリ開発が手作業のプロンプト調整に寄りすぎていることです。現場では、1 本の長いシステムプロンプトに命令や例を足し引きしながら品質を上げることが多いですが、この方法はかなり不安定です。
難しいのは、LLM アプリが 1 回の生成で終わらないことです。質問理解、検索、再検索、要約、推論、最終回答のように複数段がつながると、どこを改善すべきかが見えにくくなります。既存の方法では、各段に人手で prompt template を書き、失敗したらまた文章を直す、という反復になりがちです。
このやり方の限界は、再利用性と移植性の低さです。あるモデルでは効いた prompt が別のモデルでは崩れますし、タスクが変わるとまた書き直しになります。さらに、RAG やエージェントでは検索クエリの作り方、中間推論の形式、候補比較の仕方など、改善ポイントが複数あるため、局所最適に陥りやすいです。
なぜこの課題を解く必要があるかというと、実際の AI システムでは「どのモデルを使うか」より「どう組み合わせるか」が競争力になるからです。社内検索、複雑な QA、カスタマーサポート、業務自動化では、少しの設計差が精度とコストを大きく左右します。DSPy は、その設計自体を最適化可能な対象にすることで、属人的な調整を減らそうとしています。
用語解説
- 宣言的モジュール
- 処理の中身を細かく書くのではなく、「何を入れて何を返すか」を中心に定義する部品です。DSPy ではこの抽象化により、プロンプトそのものではなくタスクの役割を先に固定できます。
- Signature
- DSPy における入出力仕様です。たとえば `question -> answer` のように書きます。この論文では、プロンプトを直接書く代わりに Signature をもとに適切な実行形へ変換する点が重要です。
- Few-shot 例
- モデルに見本として渡す入出力例です。通常は人手で選びますが、DSPy ではコンパイル時にタスクに合う例を自動で集めたり組み替えたりして性能を上げます。
- Teleprompter
- DSPy で使われる最適化器の総称です。評価指標と訓練例を見ながら、各モジュールに与えるデモ例や構成を更新します。DSPy の「自己改善」の中心部分です。
- マルチホップ QA
- 1 回の検索や推論だけでは答えに届かず、複数の文書や推論段階をまたいで答える問題です。DSPy の効果が出やすい典型例で、RAG やエージェントの理解にもつながります。
技術の仕組み
DSPy の基本アイデアは、プロンプトを書くことをやめて、LLM 呼び出しを型付きのモジュールとして扱うことです。そのうえで、モジュール単位の振る舞いをコンパイラが最適化します。
基本アイデア
通常の LLM 開発では、「こう答えてください」「この形式で出力してください」「以下の例を参考にしてください」といった長い文字列を人が用意します。DSPy では、そうした命令文をアプリ本体に埋め込む代わりに、「質問を受けて答えを返す」「文脈から検索クエリを返す」といった役割だけを宣言します。
この宣言をもとに、DSPy は内部でプロンプトやデモ例を構成します。さらに、評価関数を使って、より良い構成へ再コンパイルできます。ここが従来のチェーンライブラリとの大きな違いです。
モデル構造
論文では DSPy の中核を 3 つの抽象化で説明しています。
1. Signatures
Signature は入出力仕様です。question -> answer や context, question -> search_query のように書きます。これにより、開発者は「どんな役割の変換か」を定義し、具体的な prompt wording から距離を取れます。
2. Modules
Module は Signature を使って実際の処理を行う部品です。単純な Predict だけでなく、ChainOfThought のような推論付きモジュールや、複数候補を比較するモジュールもあります。これらを Python の制御フローでつなぐことで、RAG やマルチステップ推論を表現できます。
3. Teleprompters
Teleprompter は最適化器です。訓練例と評価指標を受け取り、各モジュールにどんな few-shot 例を持たせるか、どの構成がよいかを探索します。論文では bootstrapping や random search、ensemble、さらに小型モデル向けの finetuning まで扱っています。
学習方法
DSPy 自体は 1 つの学習アルゴリズムではなく、LLM パイプラインを改善するための最適化フレームワークです。論文の中心は、各モジュールが高品質なデモ例を自分で集める bootstrapping にあります。
処理の流れは大まかに次のとおりです。
1. 初期パイプラインを実行する
まずは最小限の Signature と Module だけでパイプラインを動かします。この時点では、人手の長いプロンプトはありません。
2. 評価指標で良い実行例を選ぶ
GSM8K なら正答率、HotPotQA なら answer exact match や passage retrieval accuracy のような指標を使い、どの実行結果が良いかを判定します。
3. 良い中間結果をデモ例として再利用する
性能が良かった実行トレースから、各モジュールにとって有益な入出力例を取り出し、few-shot 例として組み込みます。これにより、モジュールごとの prompt がタスクに適応していきます。
4. 必要なら複数候補や小型モデルへ展開する
論文では、ブートストラップした複数プログラムを ensemble したり、その結果を教師として T5-Large を finetune したりしています。つまり DSPy は、単なる ICL 最適化だけでなく、蒸留やコスト最適化の入口にもなります。
推論方法とデータの扱い方
DSPy は推論時にもモジュール構造を活かします。たとえば HotPotQA のマルチホップ構成では、まず質問と現在の文脈から検索クエリを作り、検索で得た文書を文脈に追加し、その文脈を使って次の検索や最終回答へ進みます。これは RAG を「1 回検索して終わり」ではなく、「検索方針も含めて推論する流れ」に変える設計です。
また、データの扱い方にも特徴があります。訓練データが大量になくても、少数の labeled examples と未ラベル質問から、良い実行トレースを回収して改善できます。これは、小規模チームが現場データで品質改善を回す上でも現実的です。
実験と結果
論文では 2 つの大きなケーススタディを行っています。1 つは数式入り文章題の GSM8K、もう 1 つはマルチホップ質問応答の HotPotQA です。どちらも、単発の 1 回生成ではなく、推論や検索の設計が効くタスクです。
GSM8K で何を検証したのか
GSM8K では、単純な Predict、推論付きの ChainOfThought、複数候補を比較する reflection という 3 種類のプログラムを用意し、それぞれを few-shot、bootstrap、ensemble などで最適化したときの違いを見ています。評価指標は正答率です。
論文では、GPT-3.5-turbo-instruct を使った vanilla プログラムが、コンパイルなしでは test 25.2% だったのに対し、bootstrap×2 で 61.7%、CoT + bootstrap で 72.9%、reflection + bootstrap で 76.0%、CoT + ensemble で 81.6% まで上がっています。Llama2-13b-chat でも、vanilla の test 9.4% が bootstrap×2 で 36.5%、reflection + ensemble で 46.9% まで改善しています。
ここから言えるのは、DSPy の効果は単なる「少しプロンプトが良くなる」レベルではなく、特に小さめのモデルや素朴な構成をかなり底上げできる点です。しかも、人手で長い reasoning 例を大量に書き込まなくても改善しているのが重要です。
HotPotQA で何を検証したのか
HotPotQA では、通常の few-shot、CoT 付き RAG、そして 2 回の検索ホップを持つ multihop プログラムを比較しています。評価指標は answer exact match と、関連文書のペアを正しく回収できたかを見る passage accuracy です。
GPT-3.5-turbo-instruct では、multihop fewshot の test answer EM が 31.2%、passage accuracy が 40.8% でしたが、bootstrap 後は answer EM 39.6%、passage accuracy 43.8% に改善しています。さらに ensemble では test answer EM 45.6% に達しています。Llama2-13b-chat でも、multihop fewshot の 31.3% から bootstrap で 36.4%、ensemble で 41.0% へ伸びています。
この結果が示すのは、RAG の品質改善では「検索器を強くする」だけでなく、「検索クエリをどう段階的に作るか」「中間文脈をどう使うか」を最適化することが効くという点です。論文でも、単純な CoT_RAG より multihop 構成の方が良かったと報告しています。
小型モデルへの展開
論文ではさらに、ブートストラップ済みの multihop プログラムを教師として T5-Large を finetune しています。この compiled T5-Large は、200 件の labeled inputs と 800 件の unlabeled questions で、HotPotQA の dev で answer EM 39.3%、passage accuracy 46.0% を達成したと報告されています。
ここは実務的にかなり重要です。高価な API モデルで改善手順を見つけ、その知識を安価なモデルへ移す、という流れが見えているからです。SaaS や社内ツールで推論コストを下げたい場合の設計指針になります。
何に使える?
DSPy の強みは、LLM アプリの品質改善をコードレベルで回せることです。研究用途だけでなく、実装や運用の観点でも使い道があります。
RAG の検索クエリ最適化
RAG では、最終回答の品質より前に、適切な検索クエリを出せるかが重要です。DSPy のように context, question -> search_query を明示的なモジュールにすると、検索段の改善を独立して回せます。FAQ 検索、社内文書検索、技術文書サポートで特に有効です。
エージェントの中間ステップ改善
エージェントは、計画、検索、ツール実行、検証、最終回答の各段で失敗します。DSPy 的に各段を module 化しておけば、どの段のデモ例や指示を改善すべきかが見えやすくなります。単一の巨大 prompt に全部押し込むより、保守しやすいです。
小型モデルを使うプロダクトの品質底上げ
論文では Llama2-13b-chat や T5-Large でも改善が出ています。これは、推論コストを抑えたいプロダクトに向いています。まず強いモデルで良い実行例を集め、次にそれを使って小型モデルのパイプラインをコンパイルする、という戦略が取れます。
業務ごとの評価関数を持つ社内ツール
たとえば問い合わせ分類、契約書要約、レポート生成、チケット振り分けのようなタスクでは、独自の正解基準があります。DSPy は評価指標を前提に最適化するので、業務 KPI と接続しやすいです。ここは論文の直接検証範囲を少し超えますが、考え方としてかなり応用しやすい部分です。
開発や事業へのヒント
この論文から得られるヒントは、LLM アプリを「いい prompt を見つける仕事」として捉えないことです。むしろ、計測可能なパイプラインを設計し、その構成を改善できる状態にしておくことが重要です。
まず prompt ではなく I/O を設計する
自分で AI アプリを作るなら、最初に考えるべきは prompt の言い回しではなく、各段が何を入力して何を返すかです。これが明確だと、後から最適化や差し替えがしやすくなります。DSPy はその考え方をかなり強く後押ししています。
評価指標を先に決める
既存サービスを改善する場合も、良い出力とは何かを数値やルールで定義しないと、自己改善は回りません。答えの正確性、検索ヒット率、要約形式の一致、問い合わせカテゴリの正解率など、事業に近い評価軸を先に作ることが重要です。
小規模プロダクトでも段階的に導入できる
DSPy の発想は大規模研究チーム専用ではありません。小規模でも、まず 2 段か 3 段の LLM 処理を分離し、失敗ログを見ながら few-shot 例を見直すだけでかなり整理されます。全部を自動コンパイルしなくても、「モジュール化して評価する」という発想だけで恩恵があります。
今後注目すべき方向性
今後は、プロンプトエンジニアリング単体よりも、評価指標付きの LLM パイプライン設計が重要になりそうです。RAG、エージェント、ワークフロー自動化が広がるほど、どの中間ステップをどう最適化するかが差別化要因になります。DSPy はその初期形として見ると理解しやすいです。
限界
DSPy にも限界があります。まず、評価関数が弱いと最適化の方向がぶれます。正答率や exact match のように明確な指標があるタスクでは強いですが、自由度の高い生成では「何を良しとするか」の設計が難しくなります。
計算コストにも注意が必要です。コンパイル時には複数の候補プログラムを走らせ、評価し、良いトレースを集めるため、単発の prompt 調整より計算量は増えます。論文では tens of minutes で済むとしていますが、実タスクではデータ量と評価器の重さに依存します。
また、実装の抽象化に慣れが必要です。単純な API 呼び出しより設計自由度が高いぶん、Signature をどう切るか、どの単位で module を分けるか、どこを評価するかが難しいです。モジュール分割が悪いと、かえって最適化しにくくなります。
さらに、論文の実験は主に QA と検索を中心にしています。コード生成、長期エージェント運用、複雑な業務フローでどこまで同じように効くかは、追加検証が必要です。ここは今後の発展を見るべき点です。
よくある質問
Q. DSPy は LangChain や LlamaIndex と何が違うのですか?
A. それらが主にチェーンやツール接続の実装基盤であるのに対し、DSPy はパイプラインを評価指標に合わせて最適化するところまで含みます。特に、手書き prompt を減らし、モジュール単位で自己改善させる点が違います。
Q. DSPy は RAG 専用の技術ですか?
A. いいえ。RAG との相性は良いですが、本質は LLM 呼び出しを宣言的に記述し、その構成を最適化することです。推論付き QA、要約、分類、エージェントなどにも応用できます。
Q. 小さなデータしかなくても使えますか?
A. 使える可能性があります。論文でも少数の labeled examples を起点に bootstrapping しています。ただし、評価指標が弱い場合は改善の方向が不安定になるので、最低限の検証セットは必要です。
Q. 既存の prompt を全部捨てて DSPy に移行すべきですか?
A. いきなり全部置き換える必要はありません。まずは検索クエリ生成や回答整形のような一部の処理を module 化し、どこが改善しやすいかを見るのが現実的です。
Q. 事業として見ると、どこに価値がありますか?
A. 一番の価値は、品質改善を属人化させにくいことです。高価なモデルを増やす前に、既存の LLM パイプラインを構造的に改善できるため、精度とコストの両方を詰めやすくなります。
今日の学び
この論文は、LLM アプリ開発が手作業のプロンプト調整に依存しすぎているという課題を扱いました。そこに対して、DSPy は LLM 呼び出しを宣言的モジュールとして記述し、評価指標に基づいてパイプラインをコンパイルし直すことで解こうとしています。
得られるヒントは、AI アプリの競争力はモデル選定だけでなく、パイプラインの設計と改善ループにあるということです。RAG でもエージェントでも、まず処理を分解し、評価可能にし、改善を回せる形へ落とし込むことが重要だとわかります。