> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sambanova.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# DSPy

> [!NOTE]
>
> **本ガイドで構築するもの:** SambaCloud でホストされているモデル上で動作する DSPy プログラムを構築します。基本的な予測、ツール呼び出しエージェント、構造化出力、プロンプトオプティマイザーの実行について、動作確認済みの例を掲載しています。

## 概要

[DSPy](https://dspy.ai/) は、言語モデルをプロンプトで操作するのではなく、プログラミングで扱うための Stanford NLP 発のフレームワークです。宣言的なシグネチャ (signature) をプロンプトにコンパイルし、そのプロンプトを評価指標と訓練セット (training set) に照らして自動的に最適化できます。SambaCloud と接続することで、以下のことが可能になります。

> [card] フレームワーク変更不要
>
> `dspy.LM` は、`openai/` プレフィックス付きのモデル名と `api_base`・`api_key` を受け付けるため、接続先を SambaCloud に向ける作業は、コードの変更ではなく設定の変更だけで済みます。

> [card] ツール呼び出しエージェント
>
> `dspy.ReAct` は、通常の Python 関数をツールとしてラップし、モデルに対する reasoning と acting (行動) のループを実際に実行します。

> [card] 構造化出力
>
> Pydantic モデルをシグネチャの出力フィールドとして宣言すると、検証済みのオブジェクトが返されます。

> [card] プロンプト最適化
>
> `BootstrapFewShot` などのオプティマイザーは、SambaCloud に対して実際に推論を実行し、少数のラベル付きの例からより良いプロンプトをコンパイルします。推論中心の利用プロファイルによく適合する使い方です。

## 前提条件

* [SambaCloud アカウント](https://cloud.sambanova.ai/?utm_source=dspy\&utm_medium=external\&utm_campaign=cloud_signup)と、[SambaCloud ポータル](https://cloud.sambanova.ai/apis?utm_source=dspy\&utm_medium=external\&utm_campaign=cloud_signup) で取得した API キー
* Python 3.10 以上
* Python の仮想環境に関する基本的な知識

## セットアップ

**1. 仮想環境の作成と有効化**

```bash macOS / Linux theme={}
python3 -m venv .venv
source .venv/bin/activate
```

```powershell Windows theme={}
python -m venv .venv
.venv\Scripts\Activate.ps1
```

**2. DSPy のインストール**

```bash theme={}
pip install dspy
```

**3. SambaCloud API キーのエクスポート**

```bash theme={}
export SAMBANOVA_API_KEY="your-sambacloud-api-key"
```

> [!WARNING]
>
> API キーは決してソース管理にコミットしないでください。`.env` ファイルまたはシェルのシークレット管理ツールを使用してください。

## 使用例: 基本的な予測

`dspy.LM` は、内部で LiteLLM を経由してリクエストをルーティングします。モデル名に `openai/` プレフィックスを付け、`api_base` と `api_key` を渡すことで、SambaCloud にルーティングされます。

```python basic_example.py theme={}
import os
import dspy

lm = dspy.LM(
    "openai/MiniMax-M3",
    api_base="https://api.sambanova.ai/v1",
    api_key=os.environ["SAMBANOVA_API_KEY"],
)
dspy.configure(lm=lm)

class QA(dspy.Signature):
    """Answer the question."""
    question: str = dspy.InputField()
    answer: str = dspy.OutputField()

predict = dspy.Predict(QA)
result = predict(question="What is the capital of Japan?")
print(result.answer)
```

実行します。

```bash theme={}
python basic_example.py
```

```text Output theme={}
Tokyo
```

> [!NOTE]
>
> `"MiniMax-M3"` は、[SambaCloud 対応モデル](https://docs.sambanova.ai/docs/ja/models/sambacloud-models.md) ページに記載されている任意のモデルに差し替えられます。その際も `openai/` プレフィックスはそのまま残してください。

## 使用例: ReAct によるツール呼び出し

`dspy.ReAct` は、通常の Python 関数をツールに変換し、reasoning と acting のループを実行します。モデルが呼び出すツールを決定し、DSPy がそれを実行して結果をモデルに戻す、という流れを、モデルが完了するまで繰り返します。

```python react_example.py theme={}
import os
import dspy

lm = dspy.LM(
    "openai/MiniMax-M3",
    api_base="https://api.sambanova.ai/v1",
    api_key=os.environ["SAMBANOVA_API_KEY"],
)
dspy.configure(lm=lm)

def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"It is sunny and 22C in {city}."

agent = dspy.ReAct("question -> answer", tools=[get_weather])
result = agent(question="What's the weather like in Tokyo right now?")
print(result.answer)
```

実行します。

```bash theme={}
python react_example.py
```

```text Output theme={}
The current weather in Tokyo is sunny with a temperature of 22°C (about 72°F). It sounds like a pleasant day!
```

> [accordion] 軌跡全体の確認 (result.trajectory)
>
> `ReAct` は、すべての思考 (thought)、ツール呼び出し、観測 (observation) を `result.trajectory` に記録します。これにより、モデルがもっともらしい回答を推測したのではなく、実際に `get_weather` を呼び出したことを確認できます。
>
> ```text theme={}
> {
>     'thought_0': 'The user is asking about the current weather in Tokyo. I should use the get_weather tool to fetch this information.',
>     'tool_name_0': 'get_weather',
>     'tool_args_0': {'city': 'Tokyo'},
>     'observation_0': 'It is sunny and 22C in Tokyo.',
>     'thought_1': "I have the weather information for Tokyo. It's sunny and 22C. I can now finish the task and provide the answer to the user.",
>     'tool_name_1': 'finish',
>     'tool_args_1': {},
>     'observation_1': 'Completed.',
> }
> ```

## 使用例: 構造化出力

シグネチャの出力フィールドの型として Pydantic モデルを宣言します。DSPy はこの処理に API の `response_format` パラメータを使用しません。JSON スキーマをプロンプトに直接書き込み、モデルの応答を自らパースするため、ネイティブの構造化出力に対応していないモデルでも動作します。

```python structured_example.py theme={}
import os
import dspy
from pydantic import BaseModel

lm = dspy.LM(
    "openai/MiniMax-M3",
    api_base="https://api.sambanova.ai/v1",
    api_key=os.environ["SAMBANOVA_API_KEY"],
)
dspy.configure(lm=lm)

class CityInfo(BaseModel):
    city: str
    country: str

class Extract(dspy.Signature):
    """Extract structured location info from text."""
    text: str = dspy.InputField()
    info: CityInfo = dspy.OutputField()

extractor = dspy.Predict(Extract)
result = extractor(text="Paris is the capital of France.")
print(result.info)
```

実行します。

```bash theme={}
python structured_example.py
```

```text Output theme={}
city='Paris' country='France'
```

> [accordion] DSPy が実際に SambaCloud に送信する内容
>
> `lm.history[-1]["messages"]` を確認すると、実際のリクエストの中身がわかります。JSON スキーマは `response_format` パラメータとして送信されるのではなく、システムプロンプト内にテキストとして埋め込まれています。
>
> ```text System message (excerpt) theme={}
> Your input fields are:
> 1. `text` (str):
> Your output fields are:
> 1. `info` (CityInfo):
> ...
> [[ ## info ## ]]
> {info}        # note: the value you produce must adhere to the JSON schema: {"type": "object", "properties": {"city": {"type": "string", "title": "City"}, "country": {"type": "string", "title": "Country"}}, "required": ["city", "country"], "title": "CityInfo"}
> ```
>
> その後、DSPy はモデルが整形して返したテキスト応答をパースし、Pydantic モデルに照らして検証します。この処理によって、文章としての出力が、`result.info` が返す `CityInfo(...)` オブジェクトに変換されます。

## 使用例: プログラムの最適化

オプティマイザーは、訓練セットに対して実際に推論を実行し、評価指標を改善する例を残すことで、プログラムをコンパイルします。最もシンプルなオプティマイザーが `BootstrapFewShot` です。

```python optimize_example.py theme={}
import os
import dspy

lm = dspy.LM(
    "openai/MiniMax-M3",
    api_base="https://api.sambanova.ai/v1",
    api_key=os.environ["SAMBANOVA_API_KEY"],
)
dspy.configure(lm=lm)

class QA(dspy.Signature):
    """Answer the question with a single word."""
    question: str = dspy.InputField()
    answer: str = dspy.OutputField()

trainset = [
    dspy.Example(question="What is the capital of France?", answer="Paris").with_inputs("question"),
    dspy.Example(question="What is the capital of Japan?", answer="Tokyo").with_inputs("question"),
    dspy.Example(question="What is the capital of Italy?", answer="Rome").with_inputs("question"),
]

def exact_match(example, pred, trace=None):
    return example.answer.lower() in pred.answer.lower()

program = dspy.Predict(QA)
optimizer = dspy.BootstrapFewShot(metric=exact_match, max_bootstrapped_demos=2)
optimized = optimizer.compile(program, trainset=trainset)

result = optimized(question="What is the capital of Germany?")
print(result.answer)
print(f"Demos in compiled program: {len(optimized.demos)}")
```

実行します。

```bash theme={}
python optimize_example.py
```

```text Output theme={}
Bootstrapped 2 full traces after 2 examples for up to 1 rounds, amounting to 2 attempts.
Berlin
Demos in compiled program: 3
```

> [!NOTE]
>
> オプティマイザーの実行では、評価時にプログラム自体が行う呼び出しに加えて、ブートストラップ試行 1 回につき SambaCloud への実際の推論呼び出しが 1 回発生します。DSPy は設計上、このように推論量の多い利用プロファイルを持ちます。そのため DSPy のコストは、コンパイル済みプログラムがその後呼び出される頻度だけでなく、訓練セットのサイズやオプティマイザーのラウンド数に応じて増加します。

## 参考情報

> [card] [DSPy リポジトリ](https://github.com/stanfordnlp/dspy)
>
> DSPy のソースコード、サンプル、リリースノート。

> [card] [DSPy ドキュメント](https://dspy.ai/)
>
> シグネチャ、モジュール、オプティマイザー、評価を扱う公式ガイド。

> [card] [対応モデル](https://docs.sambanova.ai/docs/ja/models/sambacloud-models.md)
>
> SambaCloud で現在利用可能なモデルの一覧。

> [card] [Function calling と JSON モード](https://docs.sambanova.ai/docs/ja/features/function-calling.md)
>
> ツール呼び出しと構造化出力にネイティブ対応している SambaCloud モデルの一覧。

## トラブルシューティング

> [accordion] ModuleNotFoundError: No module named 'dspy'
>
> `pip install dspy` でインストールし、仮想環境が有効化されていることを確認してください。`which python3` の出力が `.venv` 内を指している必要があります。

> [accordion] KeyError: SAMBANOVA\_API\_KEY
>
> 実行前にキーをエクスポートしてください: `export SAMBANOVA_API_KEY="your-key"`。`echo $SAMBANOVA_API_KEY` で確認できます。

> [accordion] LMInvalidRequestError: Unmapped LLM provider for this endpoint
>
> モデル名に `openai/` プレフィックスが付いていません。DSPy は LiteLLM を経由してルーティングしており、LiteLLM はこのプレフィックスでリクエスト形式を判別します。`"MiniMax-M3"` ではなく `"openai/MiniMax-M3"` を使用してください。

> [accordion] LMAuthError: Incorrect API key provided
>
> `SAMBANOVA_API_KEY` のキーが誤っているか、失効しています。[SambaCloud ポータル](https://cloud.sambanova.ai/apis?utm_source=dspy\&utm_medium=external\&utm_campaign=cloud_signup) で新しいキーを生成し、再度エクスポートしてください。

> [accordion] ReAct エージェントがツールを呼び出さずに回答する
>
> `dspy.ReAct` は API ネイティブの Function calling (関数呼び出し) を使用しません。プロンプト内でツールを説明し、モデルの返答をパースして、実行するツールを決定します。モデルが回答を推測で返している場合は、`result.trajectory` に `tool_name_0` エントリがあるか確認したうえで、`dspy.inspect_history(n=1)` を実行して実際のプロンプトと返答を確認してください。ツールには明確な docstring と型ヒントを与えてください。モデルに見えるのはそのテキストだけです。

> [accordion] AdapterParseError: Adapter ChatAdapter failed to parse the LM response
>
> モデルの返答が、DSPy の期待するフィールド形式に従っていませんでした。`dspy.inspect_history(n=1)` を実行して生の応答を確認してください。通常は再試行すると成功します。失敗が続く場合は、[対応モデル](https://docs.sambanova.ai/docs/ja/models/sambacloud-models.md) ページから別のモデルをお試しください。
