@modular-prompt/experiment 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -369
- package/dist/config/dynamic-loader.js +2 -2
- package/dist/config/dynamic-loader.js.map +1 -1
- package/dist/runner/experiment.d.ts +8 -4
- package/dist/runner/experiment.d.ts.map +1 -1
- package/dist/runner/experiment.js +112 -106
- package/dist/runner/experiment.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/examples/tools-experiment.yaml +50 -37
- package/examples/tools-test-module.mjs +18 -24
- package/examples/tools-test-module.ts +19 -23
- package/package.json +8 -5
- package/skills/experiment/SKILL.md +313 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: experiment
|
|
3
|
+
description: modular-promptの実験フレームワーク(@modular-prompt/experiment)の使い方ガイド。プロンプトモジュールの比較・評価実験の設定、実行、評価器の定義を参照する。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 実験フレームワーク使い方ガイド
|
|
7
|
+
|
|
8
|
+
## 実験フレームワークとは
|
|
9
|
+
|
|
10
|
+
`@modular-prompt/experiment` は、複数のプロンプトモジュールを同一条件下で比較・評価するためのフレームワーク。YAML設定で実験を定義し、CLIまたはプログラマティックに実行できる。
|
|
11
|
+
|
|
12
|
+
### ユースケース
|
|
13
|
+
|
|
14
|
+
- **プロンプト比較**: 異なるプロンプト構造の効果を比較検証
|
|
15
|
+
- **モジュール分離検証**: モジュール化したプロンプトが同等の出力を生成するか確認
|
|
16
|
+
- **品質評価**: 繰り返し実行による出力の安定性・一貫性の評価
|
|
17
|
+
- **マルチモデルテスト**: 異なるLLMプロバイダーでの動作比較
|
|
18
|
+
|
|
19
|
+
## CLI
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# 設定検証・実行計画表示(まずこれで確認)
|
|
23
|
+
npx modular-experiment config.yaml --dry-run
|
|
24
|
+
|
|
25
|
+
# 実験実行
|
|
26
|
+
npx modular-experiment config.yaml
|
|
27
|
+
|
|
28
|
+
# 評価付き実行
|
|
29
|
+
npx modular-experiment config.yaml --evaluate
|
|
30
|
+
|
|
31
|
+
# 複数回実行(統計用)
|
|
32
|
+
npx modular-experiment config.yaml --repeat 10
|
|
33
|
+
|
|
34
|
+
# 特定モジュール・テストケースのみ
|
|
35
|
+
npx modular-experiment config.yaml --modules my-module --test-case "Basic Test"
|
|
36
|
+
|
|
37
|
+
# 詳細ログ出力
|
|
38
|
+
npx modular-experiment config.yaml --log-file experiment.jsonl --verbose
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### CLIオプション
|
|
42
|
+
|
|
43
|
+
| オプション | 説明 |
|
|
44
|
+
|-----------|------|
|
|
45
|
+
| `<config>` | 設定ファイルパス(YAML or TypeScript) |
|
|
46
|
+
| `--dry-run` | 実行計画のみ表示 |
|
|
47
|
+
| `--evaluate` | 評価フェーズを有効化 |
|
|
48
|
+
| `--repeat <count>` | 繰り返し回数(デフォルト: 1) |
|
|
49
|
+
| `--modules <names>` | カンマ区切りモジュール名フィルター |
|
|
50
|
+
| `--test-case <name>` | テストケース名フィルター |
|
|
51
|
+
| `--model <provider>` | モデルプロバイダーフィルター |
|
|
52
|
+
| `--evaluators <names>` | カンマ区切り評価器名フィルター |
|
|
53
|
+
| `--log-file <path>` | JSONLログファイルパス |
|
|
54
|
+
| `--verbose` | 詳細な内部操作を表示 |
|
|
55
|
+
|
|
56
|
+
## 設定ファイル(YAML)
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
# モデル定義
|
|
60
|
+
models:
|
|
61
|
+
gpt4o:
|
|
62
|
+
provider: openai
|
|
63
|
+
model: gpt-4o
|
|
64
|
+
capabilities: ["streaming", "tools", "structured"]
|
|
65
|
+
enabled: true
|
|
66
|
+
gemini:
|
|
67
|
+
provider: vertexai
|
|
68
|
+
model: gemini-2.0-flash-001
|
|
69
|
+
capabilities: ["tools", "fast"]
|
|
70
|
+
enabled: true
|
|
71
|
+
|
|
72
|
+
# ドライバー認証設定
|
|
73
|
+
drivers:
|
|
74
|
+
openai:
|
|
75
|
+
apiKey: ${OPENAI_API_KEY} # 環境変数
|
|
76
|
+
vertexai:
|
|
77
|
+
projectId: my-gcp-project
|
|
78
|
+
location: us-central1
|
|
79
|
+
|
|
80
|
+
# デフォルトオプション
|
|
81
|
+
defaultOptions:
|
|
82
|
+
temperature: 0.7
|
|
83
|
+
maxTokens: 2048
|
|
84
|
+
|
|
85
|
+
# テスト対象モジュール
|
|
86
|
+
modules:
|
|
87
|
+
- name: baseline
|
|
88
|
+
path: ./modules/baseline.ts # 設定ファイルからの相対パス
|
|
89
|
+
description: ベースラインプロンプト
|
|
90
|
+
- name: optimized
|
|
91
|
+
path: ./modules/optimized.ts
|
|
92
|
+
description: 最適化版プロンプト
|
|
93
|
+
|
|
94
|
+
# テストケース
|
|
95
|
+
testCases:
|
|
96
|
+
- name: 基本テスト
|
|
97
|
+
description: 基本的な動作確認
|
|
98
|
+
input: # module.compile に渡すコンテキスト
|
|
99
|
+
query: "TypeScriptの型推論について説明して"
|
|
100
|
+
models: [gpt4o] # オプション: 未指定時は全有効モデル
|
|
101
|
+
queryOptions: # オプション
|
|
102
|
+
temperature: 0.5
|
|
103
|
+
|
|
104
|
+
- name: ツール呼び出しテスト
|
|
105
|
+
input:
|
|
106
|
+
query: "東京の天気を調べて"
|
|
107
|
+
queryOptions:
|
|
108
|
+
tools:
|
|
109
|
+
- name: get_weather
|
|
110
|
+
description: 天気を取得
|
|
111
|
+
parameters:
|
|
112
|
+
type: object
|
|
113
|
+
properties:
|
|
114
|
+
city: { type: string }
|
|
115
|
+
required: [city]
|
|
116
|
+
|
|
117
|
+
# 評価器
|
|
118
|
+
evaluators:
|
|
119
|
+
- name: structured-output-presence # ビルトイン
|
|
120
|
+
- name: llm-requirement-fulfillment # ビルトイン
|
|
121
|
+
- name: custom-eval # 外部ファイル
|
|
122
|
+
path: ./evaluators/custom-eval.ts
|
|
123
|
+
|
|
124
|
+
# 評価設定
|
|
125
|
+
evaluation:
|
|
126
|
+
enabled: true
|
|
127
|
+
model: gpt4o # 評価に使うモデル
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### パス解決
|
|
131
|
+
|
|
132
|
+
設定ファイル内のパス(modules, evaluators等)は設定ファイルのディレクトリからの相対パスで解決される。`~/` でホームディレクトリ、絶対パスも使用可能。
|
|
133
|
+
|
|
134
|
+
## モジュール定義
|
|
135
|
+
|
|
136
|
+
テスト対象のモジュールファイルでは、PromptModule を直接 default export する:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
import type { PromptModule } from '@modular-prompt/core';
|
|
140
|
+
|
|
141
|
+
const module: PromptModule<{ query: string }> = {
|
|
142
|
+
objective: ['ユーザーの質問に回答する'],
|
|
143
|
+
instructions: [
|
|
144
|
+
'- 正確で分かりやすい説明を心がける',
|
|
145
|
+
(ctx) => `質問: ${ctx.query}`,
|
|
146
|
+
],
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export default module;
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
テストケースの `input` は実行時にコンテキストとして注入される。runner 内部で `defaultProcess` を使用してコンパイル・実行が行われる。
|
|
153
|
+
|
|
154
|
+
## 評価器
|
|
155
|
+
|
|
156
|
+
### ビルトイン評価器
|
|
157
|
+
|
|
158
|
+
**structured-output-presence** - コード評価器
|
|
159
|
+
- `structuredOutput` の存在と有効性を検証
|
|
160
|
+
- スコア: `(validCount / totalRuns) * 10`
|
|
161
|
+
|
|
162
|
+
**llm-requirement-fulfillment** - プロンプト評価器
|
|
163
|
+
- LLMが要件充足度を包括的に評価
|
|
164
|
+
- 評価基準: 要件充足度、パラメータ正確性、パラメータ完全性、論理的一貫性
|
|
165
|
+
- 評価用モデルの設定が必要(`evaluation.model`)
|
|
166
|
+
|
|
167
|
+
### カスタム評価器(コード)
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import type { CodeEvaluator, EvaluationContext, EvaluationResult } from '@modular-prompt/experiment';
|
|
171
|
+
|
|
172
|
+
export default {
|
|
173
|
+
name: 'json-validator',
|
|
174
|
+
description: 'JSON構造を検証',
|
|
175
|
+
|
|
176
|
+
async evaluate(context: EvaluationContext): Promise<EvaluationResult> {
|
|
177
|
+
const allValid = context.runs.every(run =>
|
|
178
|
+
run.queryResult.structuredOutput != null
|
|
179
|
+
);
|
|
180
|
+
return {
|
|
181
|
+
evaluator: 'json-validator',
|
|
182
|
+
moduleName: context.moduleName,
|
|
183
|
+
score: allValid ? 10 : 0,
|
|
184
|
+
reasoning: allValid ? '全実行でJSON出力あり' : 'JSON出力なし',
|
|
185
|
+
};
|
|
186
|
+
},
|
|
187
|
+
} satisfies CodeEvaluator;
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### カスタム評価器(プロンプト)
|
|
191
|
+
|
|
192
|
+
LLMに評価させる場合:
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
import type { PromptEvaluator, EvaluationContext } from '@modular-prompt/experiment';
|
|
196
|
+
import type { PromptModule } from '@modular-prompt/core';
|
|
197
|
+
|
|
198
|
+
const evaluationModule: PromptModule<EvaluationContext> = {
|
|
199
|
+
createContext: () => ({ moduleName: '', prompt: '', runs: [] }),
|
|
200
|
+
objective: ['出力の品質を0-10で評価する'],
|
|
201
|
+
instructions: [
|
|
202
|
+
'- 明確さ、正確さ、完全性を基準にする',
|
|
203
|
+
(ctx) => `対象モジュール: ${ctx.moduleName}`,
|
|
204
|
+
(ctx) => ctx.runs.map((run, i) =>
|
|
205
|
+
`実行${i + 1}: ${run.queryResult.content.slice(0, 500)}`
|
|
206
|
+
),
|
|
207
|
+
],
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
export default {
|
|
211
|
+
name: 'quality-evaluator',
|
|
212
|
+
description: '出力品質を評価',
|
|
213
|
+
module: evaluationModule, // baseEvaluationModuleと自動マージされる
|
|
214
|
+
} satisfies PromptEvaluator;
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## 主要な型
|
|
218
|
+
|
|
219
|
+
### TestCase
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
interface TestCase {
|
|
223
|
+
name: string;
|
|
224
|
+
description?: string;
|
|
225
|
+
input: any; // module.compileに渡すコンテキスト
|
|
226
|
+
models?: string[]; // 未指定時は全有効モデル
|
|
227
|
+
queryOptions?: Partial<QueryOptions>;
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### EvaluationContext
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
interface EvaluationContext {
|
|
235
|
+
moduleName: string;
|
|
236
|
+
prompt: string; // コンパイル済みプロンプト(文字列化)
|
|
237
|
+
runs: Array<{
|
|
238
|
+
queryResult: QueryResult;
|
|
239
|
+
}>;
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### EvaluationResult
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
interface EvaluationResult {
|
|
247
|
+
evaluator: string;
|
|
248
|
+
moduleName: string;
|
|
249
|
+
score?: number; // 0-10
|
|
250
|
+
reasoning?: string;
|
|
251
|
+
details?: Record<string, any>;
|
|
252
|
+
error?: string;
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## プログラマティック使用
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import {
|
|
260
|
+
loadExperimentConfig,
|
|
261
|
+
loadModules,
|
|
262
|
+
loadEvaluators,
|
|
263
|
+
ExperimentRunner,
|
|
264
|
+
DriverManager,
|
|
265
|
+
} from '@modular-prompt/experiment';
|
|
266
|
+
|
|
267
|
+
const { serverConfig, aiService, configDir } = loadExperimentConfig('config.yaml');
|
|
268
|
+
const modules = await loadModules(serverConfig.modules, configDir);
|
|
269
|
+
const evaluators = await loadEvaluators(serverConfig.evaluators, configDir);
|
|
270
|
+
|
|
271
|
+
const driverManager = new DriverManager();
|
|
272
|
+
const runner = new ExperimentRunner(
|
|
273
|
+
aiService,
|
|
274
|
+
driverManager,
|
|
275
|
+
modules,
|
|
276
|
+
serverConfig.testCases,
|
|
277
|
+
serverConfig.models,
|
|
278
|
+
5, // repeat count
|
|
279
|
+
evaluators,
|
|
280
|
+
evaluatorModel
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
const results = await runner.run();
|
|
284
|
+
await driverManager.cleanup();
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## 実験フロー
|
|
288
|
+
|
|
289
|
+
実験は3つのフェーズに分けて実行される:
|
|
290
|
+
|
|
291
|
+
### Phase 1: テスト計画の生成 (buildTestPlan)
|
|
292
|
+
- テストケース × モデル × モジュール の全組み合わせを展開
|
|
293
|
+
- 各組み合わせに順序番号(order)を付与して計画リストを作成
|
|
294
|
+
- コンパイル済みプロンプトを事前生成(ログ・評価用)
|
|
295
|
+
|
|
296
|
+
### Phase 2: 実行フェーズ (executePlan)
|
|
297
|
+
- **モデルごとにグループ化して実行**(モデル切り替えコストの最小化)
|
|
298
|
+
- 各モデルグループで:
|
|
299
|
+
- ドライバーを作成
|
|
300
|
+
- テストケース × モジュール の組み合わせを実行(`defaultProcess` を使用)
|
|
301
|
+
- モデルのテスト完了後にドライバーをクローズ
|
|
302
|
+
- **実行完了後、元の定義順にソート** (retire)
|
|
303
|
+
|
|
304
|
+
### Phase 3: 評価フェーズ (runEvaluationPhase)
|
|
305
|
+
- 評価器が有効な場合のみ実行
|
|
306
|
+
- 各モジュールの出力を評価器で採点
|
|
307
|
+
- 評価結果を表示
|
|
308
|
+
|
|
309
|
+
### 設計上の特徴
|
|
310
|
+
|
|
311
|
+
**アウトオブオーダー実行**: モデルごとにグループ化して実行することで、ローカルLLM(MLX等)のモデル切り替えコストを削減。実行後は元の定義順にソートして結果を返す。
|
|
312
|
+
|
|
313
|
+
**ドライバーキャッシング**: DriverManagerがモデル名をキーにドライバーをキャッシュ。同じモデルであればドライバーを再利用し、異なるモデルに切り替わると前のドライバーをcloseする。
|