@modular-prompt/process 0.5.9 → 0.5.11
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/docs/UTILITIES.md +845 -0
- package/docs/WORKFLOW_LOG_CONVENTIONS.md +207 -0
- package/package.json +6 -4
|
@@ -0,0 +1,845 @@
|
|
|
1
|
+
# Utilities
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
`@modular-prompt/utils`パッケージは、Moduler Promptシステムで使用される共通ユーティリティを提供します。主要な機能として、ドライバレジストリとログシステムが含まれています。
|
|
6
|
+
|
|
7
|
+
## ログシステム (Logger System)
|
|
8
|
+
|
|
9
|
+
### 概要
|
|
10
|
+
|
|
11
|
+
`@modular-prompt/utils`のログシステムは、構造化ログ出力とログレベル制御機能を提供します。開発・本番環境での適切なログ出力を支援します。
|
|
12
|
+
|
|
13
|
+
### なぜログシステムが必要か
|
|
14
|
+
|
|
15
|
+
1. **環境別の出力制御**: 本番環境では最小限のログ、開発環境では詳細なデバッグ情報を出力
|
|
16
|
+
2. **構造化データの記録**: 文字列だけでなく、オブジェクトとして情報を記録し、後から解析しやすくする
|
|
17
|
+
3. **パフォーマンスへの配慮**: ログレベルによって出力を制御し、不要な処理を避ける
|
|
18
|
+
4. **モジュール識別**: プレフィックスにより、どのモジュールからのログかを明確にする
|
|
19
|
+
|
|
20
|
+
### 基本コンポーネント
|
|
21
|
+
|
|
22
|
+
1. **Logger**: メインのログ出力クラス
|
|
23
|
+
2. **ログレベル**: quiet, error, warn, info, verbose, debug の階層制御
|
|
24
|
+
3. **プレフィックス**: ログメッセージに自動的に付与される識別子
|
|
25
|
+
4. **コンテキスト**: ログの発生源を特定するための識別子(例: runner/evaluator/experiment)
|
|
26
|
+
5. **ログエントリ蓄積**: メモリ内にログを保持し、後から検索・分析できる機能
|
|
27
|
+
6. **JSONL出力**: ログをJSONL形式でファイルに出力する機能
|
|
28
|
+
|
|
29
|
+
### ログレベル階層
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { LogLevel } from '@modular-prompt/utils';
|
|
33
|
+
|
|
34
|
+
type LogLevel = 'quiet' | 'error' | 'warn' | 'info' | 'verbose' | 'debug';
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**ログレベルの詳細** (数値が小さいほど重要):
|
|
38
|
+
|
|
39
|
+
| レベル | 数値 | 用途 | 含まれる出力 |
|
|
40
|
+
|--------|------|------|--------------|
|
|
41
|
+
| `quiet` | 0 | 出力なし | - |
|
|
42
|
+
| `error` | 1 | エラーのみ | ERROR |
|
|
43
|
+
| `warn` | 2 | 警告以上 | ERROR + WARN |
|
|
44
|
+
| `info` | 3 | 情報以上(デフォルト) | ERROR + WARN + INFO |
|
|
45
|
+
| `verbose` | 4 | 詳細情報以上 | ERROR + WARN + INFO + VERBOSE |
|
|
46
|
+
| `debug` | 5 | すべて(デバッグ含む) | ERROR + WARN + INFO + VERBOSE + DEBUG |
|
|
47
|
+
|
|
48
|
+
**ログレベルの選び方**:
|
|
49
|
+
- **本番環境**: `quiet`または`error` - エラーのみ記録
|
|
50
|
+
- **ステージング環境**: `info` - 正常な動作も含めて記録(デフォルト)
|
|
51
|
+
- **詳細ログが必要な場合**: `verbose` - CLIツールの--verboseオプションに相当
|
|
52
|
+
- **開発環境**: `debug` - すべての情報を記録してデバッグに活用
|
|
53
|
+
|
|
54
|
+
**環境変数による設定**:
|
|
55
|
+
```bash
|
|
56
|
+
export MODULAR_PROMPT_LOG_LEVEL=debug
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## API
|
|
60
|
+
|
|
61
|
+
### Loggerの初期化と設定
|
|
62
|
+
|
|
63
|
+
#### 基本的な初期化
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { Logger, logger } from '@modular-prompt/utils';
|
|
67
|
+
|
|
68
|
+
// デフォルトインスタンスを使用(すぐに使える)
|
|
69
|
+
logger.info('Application started');
|
|
70
|
+
|
|
71
|
+
// カスタムインスタンスを作成
|
|
72
|
+
const customLogger = new Logger({
|
|
73
|
+
level: 'debug',
|
|
74
|
+
prefix: 'MyModule',
|
|
75
|
+
context: 'runner',
|
|
76
|
+
accumulate: true,
|
|
77
|
+
maxEntries: 1000,
|
|
78
|
+
logFile: './logs/app.jsonl'
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// エイリアスを使ったインポートも可能
|
|
82
|
+
import { logger as defaultLogger } from '@modular-prompt/utils';
|
|
83
|
+
defaultLogger.info('Using default logger with alias');
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
#### 設定オプション
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
interface LoggerConfig {
|
|
90
|
+
level: LogLevel; // 出力するログレベル(デフォルト: 'info')
|
|
91
|
+
accumulateLevel: LogLevel; // 蓄積するログレベル(デフォルト: 'debug')
|
|
92
|
+
isMcpMode: boolean; // MCPモード(stdout汚染防止、デフォルト: false)
|
|
93
|
+
prefix?: string; // ログプレフィックス
|
|
94
|
+
context?: string; // ログコンテキスト(runner/evaluator等)
|
|
95
|
+
accumulate: boolean; // ログ蓄積モード(デフォルト: false)
|
|
96
|
+
maxEntries: number; // 蓄積する最大エントリ数(デフォルト: 1000)
|
|
97
|
+
logFile?: string; // JSONL出力先パス
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### グローバル設定とインスタンス設定
|
|
102
|
+
|
|
103
|
+
Logger は2層の設定構造を持ちます:
|
|
104
|
+
|
|
105
|
+
1. **グローバル設定**: すべてのLoggerインスタンスで共有される設定
|
|
106
|
+
2. **インスタンス設定**: 特定のインスタンスのみに適用される設定(グローバル設定より優先)
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// グローバル設定を変更(全インスタンスに影響)
|
|
110
|
+
Logger.configure({ level: 'debug' });
|
|
111
|
+
|
|
112
|
+
// インスタンス設定を変更(このインスタンスのみに影響)
|
|
113
|
+
const logger = new Logger();
|
|
114
|
+
logger.configure({ level: 'verbose' }); // このインスタンスだけverbose
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### コンテキスト付きロガーの作成
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const baseLogger = new Logger({ prefix: 'app' });
|
|
121
|
+
const apiLogger = baseLogger.context('api'); // context: 'api'
|
|
122
|
+
const dbLogger = baseLogger.context('db'); // context: 'db'
|
|
123
|
+
|
|
124
|
+
// インスタンス設定は引き継がれ、contextのみが変更される
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### ログ出力メソッド
|
|
128
|
+
|
|
129
|
+
#### logger.error()
|
|
130
|
+
**用途**: システムエラーや例外など、即座に対応が必要な問題を記録
|
|
131
|
+
**出力条件**: `error`レベル以上で出力(ほぼすべてのレベルで出力)
|
|
132
|
+
**出力先**: `console.error` (stderr)
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
logger.error('Critical error occurred:', error);
|
|
136
|
+
logger.error('Database connection failed', { host: 'localhost', port: 5432 });
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### logger.warn()
|
|
140
|
+
**用途**: 非推奨機能の使用、設定の不備など、将来的に問題となる可能性がある事象を記録
|
|
141
|
+
**出力条件**: `warn`レベル以上で出力
|
|
142
|
+
**出力先**: `console.warn` (stderr)
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
logger.warn('Deprecated API usage detected');
|
|
146
|
+
logger.warn('Configuration missing:', { key: 'API_KEY' });
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### logger.info()
|
|
150
|
+
**用途**: 正常な処理の開始・終了、重要な状態変化など、システムの動作を追跡するための情報
|
|
151
|
+
**出力条件**: `info`レベル以上で出力(デフォルト設定で出力される)
|
|
152
|
+
**出力先**: `console.log` (stdout)
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
logger.info('Processing file:', fileName);
|
|
156
|
+
logger.info('Analysis completed successfully');
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### logger.verbose() / logger.log()
|
|
160
|
+
**用途**: より詳細な処理内容、中間状態など、通常運用では不要だが調査時に有用な情報(CLIの--verboseオプション相当)
|
|
161
|
+
**出力条件**: `verbose`レベル以上で出力
|
|
162
|
+
**出力先**: `console.log` (stdout)
|
|
163
|
+
**注意**: `log()`は`verbose()`のエイリアスです
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
logger.verbose('Detailed processing information');
|
|
167
|
+
logger.verbose('Cache hit for key:', cacheKey);
|
|
168
|
+
logger.log('Module initialization complete with options:', options);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### logger.debug()
|
|
172
|
+
**用途**: 変数の内容、関数の引数、内部状態など、開発・デバッグ時のみ必要な詳細情報
|
|
173
|
+
**出力条件**: `debug`レベルで出力
|
|
174
|
+
**出力先**: `console.log` (stdout)
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
logger.debug('Function called with params:', { param1, param2 });
|
|
178
|
+
logger.debug('Internal state:', state);
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### ログエントリの蓄積と取得
|
|
182
|
+
|
|
183
|
+
#### ログエントリの蓄積
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
const logger = new Logger({
|
|
187
|
+
accumulate: true, // ログ蓄積を有効化
|
|
188
|
+
accumulateLevel: 'debug', // debugレベル以上を蓄積(デフォルト)
|
|
189
|
+
maxEntries: 1000 // 最大1000エントリまで保持
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
logger.info('This will be accumulated');
|
|
193
|
+
logger.debug('This will also be accumulated');
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### ログエントリの取得
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
// 全ログエントリを取得(現在のcontextのみ)
|
|
200
|
+
const entries = logger.getLogEntries();
|
|
201
|
+
|
|
202
|
+
// フィルタリングして取得
|
|
203
|
+
const errorEntries = logger.getLogEntries({
|
|
204
|
+
level: 'error', // errorレベルのみ
|
|
205
|
+
since: new Date('2024-01-01'), // 指定日時以降
|
|
206
|
+
limit: 100, // 最大100件
|
|
207
|
+
search: 'database', // 'database'を含むもの
|
|
208
|
+
filterByContext: true // 現在のcontextのみ(デフォルト: true)
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// 複数レベルを取得
|
|
212
|
+
const importantEntries = logger.getLogEntries({
|
|
213
|
+
level: ['error', 'warn'], // errorまたはwarnレベル
|
|
214
|
+
filterByContext: false // 全contextから取得
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
#### ログエントリの構造
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
interface LogEntry {
|
|
222
|
+
timestamp: string; // ISO形式のタイムスタンプ
|
|
223
|
+
level: LogLevel; // ログレベル
|
|
224
|
+
prefix?: string; // パッケージ識別子(experiment/MLX等)
|
|
225
|
+
context?: string; // コンテキスト名
|
|
226
|
+
message: string; // メッセージ
|
|
227
|
+
args?: any[]; // 追加引数
|
|
228
|
+
formatted: string; // フォーマット済みメッセージ
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
#### ログ統計情報の取得
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
const stats = logger.getLogStats();
|
|
236
|
+
// {
|
|
237
|
+
// totalEntries: 150,
|
|
238
|
+
// entriesByLevel: {
|
|
239
|
+
// quiet: 0,
|
|
240
|
+
// error: 5,
|
|
241
|
+
// warn: 10,
|
|
242
|
+
// info: 80,
|
|
243
|
+
// verbose: 30,
|
|
244
|
+
// debug: 25
|
|
245
|
+
// },
|
|
246
|
+
// oldestEntry: '2024-01-01T10:00:00.000Z',
|
|
247
|
+
// newestEntry: '2024-01-01T12:00:00.000Z'
|
|
248
|
+
// }
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
#### ログエントリのクリア
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
logger.clearLogEntries(); // メモリ内のログエントリをクリア
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### 命名規約
|
|
258
|
+
|
|
259
|
+
プロジェクト全体でログを区別しやすくするため、`prefix`と`context`の命名規約を定めます。
|
|
260
|
+
|
|
261
|
+
#### prefix の規約
|
|
262
|
+
|
|
263
|
+
**目的**: パッケージを識別する
|
|
264
|
+
**形式**: パッケージごとに1つの`prefix`を持つ
|
|
265
|
+
**推奨される prefix**:
|
|
266
|
+
|
|
267
|
+
| パッケージ | prefix |
|
|
268
|
+
|-----------|--------|
|
|
269
|
+
| `@modular-prompt/experiment` | `experiment` |
|
|
270
|
+
| `@modular-prompt/simple-chat` | `simple-chat` |
|
|
271
|
+
| `@modular-prompt/process` | `process` |
|
|
272
|
+
| `@modular-prompt/driver` (MLXドライバー) | `MLX` |
|
|
273
|
+
| `@modular-prompt/utils` (DriverRegistry) | `DriverRegistry` |
|
|
274
|
+
|
|
275
|
+
#### context の規約
|
|
276
|
+
|
|
277
|
+
**目的**: モジュール/機能を識別する
|
|
278
|
+
**形式**: フラット形式または階層形式
|
|
279
|
+
|
|
280
|
+
**フラット形式**: `{モジュール名}`
|
|
281
|
+
```typescript
|
|
282
|
+
// 例:
|
|
283
|
+
context: 'runner'
|
|
284
|
+
context: 'driver'
|
|
285
|
+
context: 'default'
|
|
286
|
+
context: 'evaluator'
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**階層形式**: `{ベース}:{区分}:{識別子}:{タイプ}`
|
|
290
|
+
```typescript
|
|
291
|
+
// 例:
|
|
292
|
+
context: 'agentic:task:1:planning'
|
|
293
|
+
context: 'agentic:task:2:outputMessage'
|
|
294
|
+
context: 'experiment:run:baseline:evaluation'
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
階層形式では、コロン(`:`)で区切ることで後からフィルタリングや集計が容易になります。
|
|
298
|
+
|
|
299
|
+
**制約**:
|
|
300
|
+
- 同一パッケージ内で`context`名が重複しないこと
|
|
301
|
+
- 異なるパッケージ間では`prefix`で区別されるため、`context`の重複は許容される
|
|
302
|
+
|
|
303
|
+
#### ベースロガーパターン
|
|
304
|
+
|
|
305
|
+
各パッケージでは、以下のパターンでLoggerを使用することを推奨します:
|
|
306
|
+
|
|
307
|
+
1. **パッケージごとのベースロガーを作成** (`logger.ts`等で定義)
|
|
308
|
+
```typescript
|
|
309
|
+
// packages/experiment/src/logger.ts
|
|
310
|
+
import { Logger } from '@modular-prompt/utils';
|
|
311
|
+
|
|
312
|
+
export const logger = new Logger({
|
|
313
|
+
prefix: 'experiment',
|
|
314
|
+
context: 'main'
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
2. **各モジュールで`.context()`を使って派生インスタンスを作成**
|
|
319
|
+
```typescript
|
|
320
|
+
// packages/experiment/src/run-comparison.ts
|
|
321
|
+
import { logger as baseLogger } from './logger';
|
|
322
|
+
|
|
323
|
+
const logger = baseLogger.context('runner');
|
|
324
|
+
logger.info('Runner started');
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
3. **ワークフロー関数では独自のLoggerインスタンスを作成してもよい**
|
|
328
|
+
その場合も`prefix`は必ず設定すること。
|
|
329
|
+
```typescript
|
|
330
|
+
const logger = new Logger({
|
|
331
|
+
prefix: 'process',
|
|
332
|
+
context: 'default'
|
|
333
|
+
});
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
#### 現状の課題
|
|
337
|
+
|
|
338
|
+
プロジェクト全体でLoggerの使用状況を調査した結果、以下の課題が確認されています:
|
|
339
|
+
|
|
340
|
+
**未整備の箇所**:
|
|
341
|
+
- `DriverRegistry`で`context`が使われていない
|
|
342
|
+
- trace writerで設定なしのLoggerが使われている
|
|
343
|
+
|
|
344
|
+
**改善済みの項目**:
|
|
345
|
+
- ~~MLXドライバーの`context: 'process'`が紛らわしい問題~~ → trace writerがprefixを考慮するようになったため、`MLX_process.log`として出力され、区別可能になりました
|
|
346
|
+
- ~~`@modular-prompt/process` パッケージで`prefix`が設定されていない問題~~ → 全ワークフローに `prefix: 'process'` を追加済み
|
|
347
|
+
|
|
348
|
+
**trace出力のファイル名ルール**:
|
|
349
|
+
- trace writerは `prefix` と `context` を組み合わせてファイル名を生成します
|
|
350
|
+
- prefix あり + context あり: `{prefix}_{context}.log` (例: `MLX_driver.log`, `MLX_process.log`)
|
|
351
|
+
- prefix あり + context なし: `{prefix}.log` (例: `DriverRegistry.log`)
|
|
352
|
+
- prefix なし + context あり: `{context}.log` (例: `default.log`, `agentic.log`)
|
|
353
|
+
- prefix なし + context なし: `unknown.log`
|
|
354
|
+
- context の `:` は `_` に置換されます(例: `agentic:task:1:planning` → `agentic_task_1_planning.log`)
|
|
355
|
+
|
|
356
|
+
これらの課題は今後段階的に修正する予定です。
|
|
357
|
+
|
|
358
|
+
### JSONL形式でのファイル出力
|
|
359
|
+
|
|
360
|
+
#### ファイル出力の設定
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
const logger = new Logger({
|
|
364
|
+
logFile: './logs/application.jsonl' // JSONL出力先
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
logger.info('This will be queued for file output');
|
|
368
|
+
logger.error('This will also be queued');
|
|
369
|
+
|
|
370
|
+
// ファイルに書き出す(非同期)
|
|
371
|
+
await logger.flush();
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
#### フラッシュオプション
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
// 全contextのログをファイルに書き出す(デフォルト)
|
|
378
|
+
await logger.flush({ filterByContext: false });
|
|
379
|
+
|
|
380
|
+
// 現在のcontextのみファイルに書き出す
|
|
381
|
+
await logger.flush({ filterByContext: true });
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
#### JSONL形式の例
|
|
385
|
+
|
|
386
|
+
```json
|
|
387
|
+
{"timestamp":"2024-01-01T10:00:00.000Z","level":"info","prefix":"experiment","context":"runner","message":"Processing started","formatted":"2024-01-01T10:00:00.000Z INFO [experiment] Processing started"}
|
|
388
|
+
{"timestamp":"2024-01-01T10:00:05.000Z","level":"error","prefix":"experiment","context":"runner","message":"Error occurred","args":[{"code":"ERR_001"}],"formatted":"2024-01-01T10:00:05.000Z ERROR [experiment] Error occurred {\"code\":\"ERR_001\"}"}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### MCPモードのサポート
|
|
392
|
+
|
|
393
|
+
MCPサーバーとして動作する際、stdout汚染を防ぐためのモードです。
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
const logger = new Logger({
|
|
397
|
+
isMcpMode: true // MCPモードを有効化
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
// MCPモード時は、errorのみstderrに出力され、他のレベルは抑制される
|
|
401
|
+
logger.error('This will be output to stderr');
|
|
402
|
+
logger.info('This will be suppressed in MCP mode');
|
|
403
|
+
|
|
404
|
+
// ただし、accumulateやlogFileは通常通り動作する
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## DriverRegistryでの使用例
|
|
408
|
+
|
|
409
|
+
DriverRegistryクラスは内部でLoggerを使用して、モデルの選択とドライバー作成プロセスを追跡します:
|
|
410
|
+
|
|
411
|
+
```typescript
|
|
412
|
+
import { DriverRegistry } from '@modular-prompt/driver';
|
|
413
|
+
import { Logger } from '@modular-prompt/utils';
|
|
414
|
+
|
|
415
|
+
// DriverRegistryは内部でLoggerを使用
|
|
416
|
+
const registry = new DriverRegistry();
|
|
417
|
+
|
|
418
|
+
// モデルを登録
|
|
419
|
+
registry.registerModel({
|
|
420
|
+
model: 'llama-3.3-70b',
|
|
421
|
+
provider: 'mlx',
|
|
422
|
+
capabilities: ['local', 'fast', 'japanese']
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
// モデル選択時のログ出力例(prefix付き)
|
|
426
|
+
// 2024-01-01T10:00:00.000Z INFO [DriverRegistry] Selected model: llama-3.3-70b (mlx)
|
|
427
|
+
// 2024-01-01T10:00:00.000Z INFO [DriverRegistry] Reason: Local execution preferred
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## 使用パターン
|
|
431
|
+
|
|
432
|
+
### 1. モジュール固有のロガー
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
class MyModule {
|
|
436
|
+
private logger: Logger;
|
|
437
|
+
|
|
438
|
+
constructor() {
|
|
439
|
+
this.logger = new Logger({
|
|
440
|
+
prefix: 'MyModule',
|
|
441
|
+
level: 'info'
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
async process(data: any) {
|
|
446
|
+
this.logger.info('Processing started');
|
|
447
|
+
|
|
448
|
+
try {
|
|
449
|
+
const result = await this.doWork(data);
|
|
450
|
+
this.logger.info('Processing completed', { itemsProcessed: result.count });
|
|
451
|
+
return result;
|
|
452
|
+
|
|
453
|
+
} catch (error) {
|
|
454
|
+
this.logger.error('Processing failed:', error);
|
|
455
|
+
throw error;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### 2. コンテキスト別ロガーの使用
|
|
462
|
+
|
|
463
|
+
```typescript
|
|
464
|
+
class ExperimentRunner {
|
|
465
|
+
private logger: Logger;
|
|
466
|
+
|
|
467
|
+
constructor() {
|
|
468
|
+
this.logger = new Logger({
|
|
469
|
+
prefix: 'Experiment',
|
|
470
|
+
context: 'runner',
|
|
471
|
+
accumulate: true,
|
|
472
|
+
accumulateLevel: 'verbose'
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
async runExperiment(name: string) {
|
|
477
|
+
const expLogger = this.logger.context(`experiment:${name}`);
|
|
478
|
+
|
|
479
|
+
expLogger.info('Starting experiment');
|
|
480
|
+
|
|
481
|
+
// 各コンポーネントに専用コンテキストを付与
|
|
482
|
+
const evalLogger = expLogger.context('evaluator');
|
|
483
|
+
evalLogger.verbose('Evaluator initialized');
|
|
484
|
+
|
|
485
|
+
// 後からcontextでフィルタリング可能
|
|
486
|
+
const expLogs = expLogger.getLogEntries({
|
|
487
|
+
filterByContext: true // このコンテキストのみ
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### 3. デバッグ出力と詳細ログ
|
|
494
|
+
|
|
495
|
+
```typescript
|
|
496
|
+
function analyzeData(data: any, logger: Logger) {
|
|
497
|
+
// 詳細情報(verbose)
|
|
498
|
+
logger.verbose('Starting data analysis', {
|
|
499
|
+
dataSize: data.length,
|
|
500
|
+
dataType: typeof data
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
// デバッグ情報(debug)
|
|
504
|
+
logger.debug('Input data structure:', {
|
|
505
|
+
type: typeof data,
|
|
506
|
+
keys: Object.keys(data),
|
|
507
|
+
sample: data.slice(0, 3)
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
const result = performAnalysis(data);
|
|
511
|
+
|
|
512
|
+
logger.debug('Analysis result:', {
|
|
513
|
+
itemsAnalyzed: result.items.length,
|
|
514
|
+
processingTime: result.duration
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
logger.verbose('Analysis completed successfully');
|
|
518
|
+
return result;
|
|
519
|
+
}
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### 4. エラーハンドリングとログ
|
|
523
|
+
|
|
524
|
+
```typescript
|
|
525
|
+
async function robustOperation(input: any) {
|
|
526
|
+
const logger = new Logger({ prefix: 'RobustOp' });
|
|
527
|
+
|
|
528
|
+
logger.info('Operation started');
|
|
529
|
+
|
|
530
|
+
try {
|
|
531
|
+
const result = await riskyOperation(input);
|
|
532
|
+
logger.info('Operation succeeded');
|
|
533
|
+
return result;
|
|
534
|
+
|
|
535
|
+
} catch (error) {
|
|
536
|
+
logger.error('Operation failed:', {
|
|
537
|
+
error: error.message,
|
|
538
|
+
input: typeof input,
|
|
539
|
+
stack: error.stack
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
throw error;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### 5. ログの蓄積と分析
|
|
548
|
+
|
|
549
|
+
```typescript
|
|
550
|
+
async function processWithLogging() {
|
|
551
|
+
const logger = new Logger({
|
|
552
|
+
prefix: 'Processor',
|
|
553
|
+
accumulate: true,
|
|
554
|
+
accumulateLevel: 'debug',
|
|
555
|
+
maxEntries: 5000,
|
|
556
|
+
logFile: './logs/process.jsonl'
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
// 処理実行
|
|
560
|
+
await performHeavyWork(logger);
|
|
561
|
+
|
|
562
|
+
// ログ統計を取得
|
|
563
|
+
const stats = logger.getLogStats();
|
|
564
|
+
console.log(`Total logs: ${stats.totalEntries}`);
|
|
565
|
+
console.log(`Errors: ${stats.entriesByLevel.error}`);
|
|
566
|
+
|
|
567
|
+
// エラーのみ抽出
|
|
568
|
+
const errors = logger.getLogEntries({ level: 'error' });
|
|
569
|
+
|
|
570
|
+
// ファイルに書き出し
|
|
571
|
+
await logger.flush();
|
|
572
|
+
|
|
573
|
+
return stats;
|
|
574
|
+
}
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
### 6. グローバル設定とインスタンス設定の組み合わせ
|
|
578
|
+
|
|
579
|
+
```typescript
|
|
580
|
+
// アプリケーション起動時にグローバル設定
|
|
581
|
+
Logger.configure({
|
|
582
|
+
level: 'info',
|
|
583
|
+
isMcpMode: process.env.MCP_MODE === 'true'
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
// 各モジュールは独自の設定を追加
|
|
587
|
+
const driverLogger = new Logger({ prefix: 'Driver' });
|
|
588
|
+
const apiLogger = new Logger({ prefix: 'API', level: 'verbose' }); // このインスタンスのみverbose
|
|
589
|
+
|
|
590
|
+
// テスト時だけデバッグモードに
|
|
591
|
+
if (process.env.NODE_ENV === 'test') {
|
|
592
|
+
Logger.configure({ level: 'debug' });
|
|
593
|
+
}
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### 7. QueryLogger(ドライバー実装用)
|
|
597
|
+
|
|
598
|
+
`QueryLogger` は Logger の accumulate 機能を活用し、クエリ実行中のログをスコープして `QueryResult` に付与するヘルパーです。
|
|
599
|
+
|
|
600
|
+
```typescript
|
|
601
|
+
import { QueryLogger } from '@modular-prompt/driver';
|
|
602
|
+
|
|
603
|
+
class MyDriver implements AIDriver {
|
|
604
|
+
private queryLogger = new QueryLogger('MyDriver');
|
|
605
|
+
|
|
606
|
+
async query(prompt, options) {
|
|
607
|
+
this.queryLogger.mark(); // クエリ開始を記録
|
|
608
|
+
try {
|
|
609
|
+
const result = await callApi(prompt);
|
|
610
|
+
return { ...result, ...this.queryLogger.collect() };
|
|
611
|
+
} catch (error) {
|
|
612
|
+
this.queryLogger.log.error('Query error:', error.message);
|
|
613
|
+
return { content: '', finishReason: 'error', ...this.queryLogger.collect() };
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
- `mark()`: ログ収集の開始時刻をリセット
|
|
620
|
+
- `log`: 内部の Logger インスタンスへのアクセス(`error()`, `warn()`, `info()` 等)
|
|
621
|
+
- `collect()`: `mark()` 以降のログエントリを `{ logEntries?, errors? }` として返却
|
|
622
|
+
|
|
623
|
+
詳細は [Driver APIリファレンス](./DRIVER_API.md) のドライバー実装者向けログ規約を参照してください。
|
|
624
|
+
|
|
625
|
+
## 設定とベストプラクティス
|
|
626
|
+
|
|
627
|
+
### 1. 環境別ログレベル設定
|
|
628
|
+
|
|
629
|
+
```typescript
|
|
630
|
+
// 本番環境
|
|
631
|
+
const productionLogger = new Logger({
|
|
632
|
+
level: 'error', // エラーのみ
|
|
633
|
+
accumulate: false
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
// ステージング環境
|
|
637
|
+
const stagingLogger = new Logger({
|
|
638
|
+
level: 'info', // 情報レベル以上
|
|
639
|
+
accumulate: true,
|
|
640
|
+
accumulateLevel: 'warn', // 警告以上を蓄積
|
|
641
|
+
logFile: './logs/staging.jsonl'
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
// 開発環境
|
|
645
|
+
const developmentLogger = new Logger({
|
|
646
|
+
level: 'debug', // すべてのログ
|
|
647
|
+
accumulate: true,
|
|
648
|
+
accumulateLevel: 'debug'
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
// テスト環境
|
|
652
|
+
const testLogger = new Logger({
|
|
653
|
+
level: 'quiet', // 出力なし
|
|
654
|
+
accumulate: true, // ただし蓄積はする
|
|
655
|
+
accumulateLevel: 'info'
|
|
656
|
+
});
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
### 2. 構造化ログの活用
|
|
660
|
+
|
|
661
|
+
```typescript
|
|
662
|
+
// ❌ 避けるべき:文字列での情報埋め込み
|
|
663
|
+
logger.info(`User ${userId} performed action ${action} at ${timestamp}`);
|
|
664
|
+
|
|
665
|
+
// ✅ 推奨:構造化されたデータ
|
|
666
|
+
logger.info('User action performed', {
|
|
667
|
+
userId,
|
|
668
|
+
action,
|
|
669
|
+
timestamp,
|
|
670
|
+
metadata: {
|
|
671
|
+
sessionId,
|
|
672
|
+
userAgent
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
JSONL出力時、構造化データはそのまま`args`フィールドに保存されます:
|
|
678
|
+
|
|
679
|
+
```json
|
|
680
|
+
{
|
|
681
|
+
"timestamp": "2024-01-01T10:00:00.000Z",
|
|
682
|
+
"level": "info",
|
|
683
|
+
"message": "User action performed",
|
|
684
|
+
"args": [{"userId": "123", "action": "login", "timestamp": "2024-01-01T10:00:00Z"}]
|
|
685
|
+
}
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
### 3. パフォーマンス考慮
|
|
689
|
+
|
|
690
|
+
```typescript
|
|
691
|
+
// ⭕ 通常のケース - メソッドを直接呼び出す
|
|
692
|
+
logger.debug('User action:', { userId, action, timestamp });
|
|
693
|
+
logger.verbose('Cache status:', { hits: cacheHits, misses: cacheMisses });
|
|
694
|
+
|
|
695
|
+
// ログレベルによって自動的に出力が制御される
|
|
696
|
+
// レベル外の場合、内部で早期リターンされるため、パフォーマンスへの影響は最小限
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
**推奨事項**:
|
|
700
|
+
- ログメソッドは直接呼び出す(内部で出力判定が行われる)
|
|
701
|
+
- 巨大データは要約やサンプルのみログに出力
|
|
702
|
+
- 出力レベルと蓄積レベルを分けて設定可能(例: 出力は`info`、蓄積は`debug`)
|
|
703
|
+
|
|
704
|
+
### 4. 大量データのログ
|
|
705
|
+
|
|
706
|
+
```typescript
|
|
707
|
+
// ❌ 大量データの直接ログ
|
|
708
|
+
logger.debug('All data:', massiveArray);
|
|
709
|
+
|
|
710
|
+
// ✅ サマリー情報のみログ
|
|
711
|
+
logger.debug('Data summary:', {
|
|
712
|
+
count: massiveArray.length,
|
|
713
|
+
sample: massiveArray.slice(0, 3),
|
|
714
|
+
types: [...new Set(massiveArray.map(item => typeof item))]
|
|
715
|
+
});
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
### 5. ログの蓄積容量管理
|
|
719
|
+
|
|
720
|
+
```typescript
|
|
721
|
+
const logger = new Logger({
|
|
722
|
+
accumulate: true,
|
|
723
|
+
maxEntries: 1000, // 最大1000エントリ
|
|
724
|
+
accumulateLevel: 'info' // infoレベル以上を蓄積
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
// 古いエントリは自動的に削除される(FIFO)
|
|
728
|
+
// 必要に応じて手動でクリア
|
|
729
|
+
logger.clearLogEntries();
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
### 6. MCPモードとファイル出力の組み合わせ
|
|
733
|
+
|
|
734
|
+
MCPサーバーとして動作する際、stdoutを汚染せずにログを記録できます:
|
|
735
|
+
|
|
736
|
+
```typescript
|
|
737
|
+
const logger = new Logger({
|
|
738
|
+
isMcpMode: true, // stdout汚染を防ぐ
|
|
739
|
+
accumulate: true, // メモリに蓄積
|
|
740
|
+
logFile: './logs/mcp-server.jsonl' // ファイルにも出力
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
// errorのみstderrに出力され、他は抑制される
|
|
744
|
+
logger.error('Critical error'); // stderr出力 + 蓄積 + ファイル
|
|
745
|
+
logger.info('Processing...'); // 蓄積 + ファイルのみ(stdout出力なし)
|
|
746
|
+
|
|
747
|
+
// 定期的にファイルに書き出し
|
|
748
|
+
setInterval(() => logger.flush(), 5000);
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
## 実装ファイル
|
|
752
|
+
|
|
753
|
+
- **Logger実装**: `packages/utils/src/logger/logger.ts`
|
|
754
|
+
- **Loggerエクスポート**: `packages/utils/src/logger/index.ts`
|
|
755
|
+
- **Loggerテスト**: `packages/utils/src/logger/logger.test.ts`
|
|
756
|
+
- **利用例**:
|
|
757
|
+
- `packages/driver/src/driver-registry/registry.ts` - DriverRegistry
|
|
758
|
+
- `packages/driver/src/mlx-ml/mlx-driver.ts` - MLXドライバー
|
|
759
|
+
- `packages/experiment/src/run-comparison.ts` - 実験フレームワーク
|
|
760
|
+
- `packages/simple-chat/src/cli.ts` - チャットCLI
|
|
761
|
+
|
|
762
|
+
## Usage集計ユーティリティ
|
|
763
|
+
|
|
764
|
+
`@modular-prompt/process` パッケージは、複数のクエリやタスクのusage情報を集計するためのユーティリティ関数を提供します。
|
|
765
|
+
|
|
766
|
+
### aggregateUsage()
|
|
767
|
+
|
|
768
|
+
複数の usage オブジェクトを合算します。リトライや複数タスクのusageを集計する際に使用します。
|
|
769
|
+
|
|
770
|
+
```typescript
|
|
771
|
+
import { aggregateUsage } from '@modular-prompt/process/workflows/usage-utils';
|
|
772
|
+
|
|
773
|
+
const usage1 = { promptTokens: 100, completionTokens: 50, totalTokens: 150 };
|
|
774
|
+
const usage2 = { promptTokens: 200, completionTokens: 80, totalTokens: 280 };
|
|
775
|
+
|
|
776
|
+
const total = aggregateUsage([usage1, usage2]);
|
|
777
|
+
// { promptTokens: 300, completionTokens: 130, totalTokens: 430 }
|
|
778
|
+
|
|
779
|
+
// undefined は無視される
|
|
780
|
+
const partialTotal = aggregateUsage([usage1, undefined, usage2]);
|
|
781
|
+
// { promptTokens: 300, completionTokens: 130, totalTokens: 430 }
|
|
782
|
+
|
|
783
|
+
// すべて undefined の場合は undefined を返す
|
|
784
|
+
const noUsage = aggregateUsage([undefined, undefined]);
|
|
785
|
+
// undefined
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
`aggregateUsage` は `promptTokens` / `completionTokens` / `totalTokens` のみ合算します。`cacheReadTokens` / `cacheWriteTokens` は現時点では合算しません。
|
|
789
|
+
|
|
790
|
+
### buildQueryUsage()(@modular-prompt/driver)
|
|
791
|
+
|
|
792
|
+
単一クエリの usage オブジェクトを組み立てるヘルパー。カスタムドライバー実装で利用します。
|
|
793
|
+
|
|
794
|
+
```typescript
|
|
795
|
+
import { buildQueryUsage } from '@modular-prompt/driver';
|
|
796
|
+
|
|
797
|
+
const usage = buildQueryUsage({
|
|
798
|
+
promptTokens: 100,
|
|
799
|
+
completionTokens: 20,
|
|
800
|
+
cacheReadTokens: 80,
|
|
801
|
+
cacheWriteTokens: 0,
|
|
802
|
+
});
|
|
803
|
+
// { promptTokens: 100, completionTokens: 20, totalTokens: 120, cacheReadTokens: 80 }
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
詳細は [Driver APIリファレンス](./DRIVER_API.md#共通ユーティリティquery-utils) を参照。
|
|
807
|
+
|
|
808
|
+
### aggregateLogEntries()
|
|
809
|
+
|
|
810
|
+
複数の LogEntry 配列をフラット化します。全タスク・全クエリのログを1つの配列にまとめる際に使用します。
|
|
811
|
+
|
|
812
|
+
```typescript
|
|
813
|
+
import { aggregateLogEntries } from '@modular-prompt/process/workflows/usage-utils';
|
|
814
|
+
|
|
815
|
+
const logs1 = [
|
|
816
|
+
{ level: 'info', message: 'Task 1 started', timestamp: '...' },
|
|
817
|
+
{ level: 'info', message: 'Task 1 completed', timestamp: '...' }
|
|
818
|
+
];
|
|
819
|
+
const logs2 = [
|
|
820
|
+
{ level: 'info', message: 'Task 2 started', timestamp: '...' }
|
|
821
|
+
];
|
|
822
|
+
|
|
823
|
+
const allLogs = aggregateLogEntries([logs1, logs2]);
|
|
824
|
+
// [
|
|
825
|
+
// { level: 'info', message: 'Task 1 started', ... },
|
|
826
|
+
// { level: 'info', message: 'Task 1 completed', ... },
|
|
827
|
+
// { level: 'info', message: 'Task 2 started', ... }
|
|
828
|
+
// ]
|
|
829
|
+
|
|
830
|
+
// undefined は無視される
|
|
831
|
+
const partialLogs = aggregateLogEntries([logs1, undefined]);
|
|
832
|
+
// logs1 のコピー
|
|
833
|
+
|
|
834
|
+
// すべて undefined の場合は undefined を返す
|
|
835
|
+
const noLogs = aggregateLogEntries([undefined, undefined]);
|
|
836
|
+
// undefined
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
**実装ファイル**: `packages/process/src/workflows/usage-utils.ts`
|
|
840
|
+
|
|
841
|
+
## 関連ドキュメント
|
|
842
|
+
|
|
843
|
+
- [Architecture](./ARCHITECTURE.md) - システム全体のアーキテクチャ
|
|
844
|
+
- [Driver API](./DRIVER_API.md) - ドライバAPIの詳細
|
|
845
|
+
- [Process Module Guide](./PROCESS_MODULE_GUIDE.md) - WorkflowResultの詳細
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# ワークフローログ規約
|
|
2
|
+
|
|
3
|
+
ワークフロー実装者向けの Logger 使用規約。
|
|
4
|
+
Logger の仕様詳細については [UTILITIES.md](./UTILITIES.md) を参照してください。
|
|
5
|
+
|
|
6
|
+
## 概要
|
|
7
|
+
|
|
8
|
+
`@modular-prompt/process` パッケージのワークフロー関数は、`@modular-prompt/utils` の Logger を使用して実行ログを記録します。この規約は、ワークフロー実装者が一貫した方法でログを出力するためのガイドラインです。
|
|
9
|
+
|
|
10
|
+
## context 命名規則
|
|
11
|
+
|
|
12
|
+
ワークフロー関数は Logger インスタンスの `context` 名で自身を識別します。
|
|
13
|
+
|
|
14
|
+
### 基本形
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
{workflow名}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**例:**
|
|
21
|
+
- `default`
|
|
22
|
+
- `stream`
|
|
23
|
+
- `agentic`
|
|
24
|
+
|
|
25
|
+
### 階層形
|
|
26
|
+
|
|
27
|
+
複雑なワークフロー(複数の処理単位を持つもの)では、階層的な context を使用します。
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
{workflow名}:{区分}:{識別子}:{タイプ}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**例:**
|
|
34
|
+
- `agentic:task:1:planning`
|
|
35
|
+
- `agentic:task:2:think`
|
|
36
|
+
- `agentic:task:3:outputMessage`
|
|
37
|
+
|
|
38
|
+
**規則:**
|
|
39
|
+
- 階層の区切りは `:` を使用
|
|
40
|
+
- 階層の深さはワークフローが自由に決定可能
|
|
41
|
+
- 各階層の意味はワークフローが定義
|
|
42
|
+
|
|
43
|
+
## メッセージ prefix 規則
|
|
44
|
+
|
|
45
|
+
ログメッセージの先頭に `[tag]` を付与して、エントリの種別を示します。
|
|
46
|
+
|
|
47
|
+
| prefix | 意味 | 内容 |
|
|
48
|
+
|--------|------|------|
|
|
49
|
+
| `[start]` | 処理単位の開始 | 説明テキスト |
|
|
50
|
+
| `[end]` | 処理単位の完了 | なし、または所要時間等 |
|
|
51
|
+
| `[prompt]` | ドライバーに送るプロンプト | CompiledPrompt の JSON |
|
|
52
|
+
| `[output]` | ドライバーからの応答 | 応答テキスト |
|
|
53
|
+
| `[tool:call]` | ツール呼び出し要求 | ツール名と引数 |
|
|
54
|
+
| `[tool:result]` | ツール呼び出し結果 | ツール名と結果 |
|
|
55
|
+
|
|
56
|
+
**注意:**
|
|
57
|
+
- prefix のないメッセージは自由記述とします
|
|
58
|
+
- prefix は必ず角括弧 `[]` で囲みます
|
|
59
|
+
- prefix と本文の間にスペースを入れます
|
|
60
|
+
|
|
61
|
+
## ログレベルの使い分け
|
|
62
|
+
|
|
63
|
+
| レベル | 用途 | 使用例 |
|
|
64
|
+
|--------|------|--------|
|
|
65
|
+
| `info` | 処理の進行状況 | `[start]`, `[end]` |
|
|
66
|
+
| `verbose` | 入出力の内容 | `[prompt]`, `[output]` |
|
|
67
|
+
| `debug` | 詳細情報 | `[tool:call]`, `[tool:result]`、内部状態 |
|
|
68
|
+
|
|
69
|
+
## ワークフロー実装の責務
|
|
70
|
+
|
|
71
|
+
ワークフロー実装者は以下を実装する必要があります:
|
|
72
|
+
|
|
73
|
+
### 1. Logger インスタンスの作成
|
|
74
|
+
|
|
75
|
+
モジュールスコープで `new Logger({ context: '...' })` を作成します。
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { Logger } from '@modular-prompt/utils';
|
|
79
|
+
|
|
80
|
+
const logger = new Logger({ context: 'myWorkflow' });
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 2. 処理単位の開始・完了ログ
|
|
84
|
+
|
|
85
|
+
処理単位の開始時に `[start]` を、完了時に `[end]` を出力します。
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
logger.info('[start] Processing workflow');
|
|
89
|
+
// ... 処理 ...
|
|
90
|
+
logger.info('[end] Workflow completed');
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 3. ドライバー呼び出しのログ
|
|
94
|
+
|
|
95
|
+
ドライバー呼び出しの前後で `[prompt]` と `[output]` を出力します。
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
const compiledPrompt = compile(module, context);
|
|
99
|
+
logger.verbose('[prompt]', JSON.stringify(compiledPrompt, null, 2));
|
|
100
|
+
|
|
101
|
+
const result = await driver.query(compiledPrompt);
|
|
102
|
+
logger.verbose('[output]', result.output);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 4. ツール呼び出しのログ
|
|
106
|
+
|
|
107
|
+
ツール呼び出しがある場合は `[tool:call]` と `[tool:result]` を出力します。
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
logger.debug('[tool:call]', toolName, JSON.stringify(args));
|
|
111
|
+
const toolResult = await executeTool(toolName, args);
|
|
112
|
+
logger.debug('[tool:result]', toolName, JSON.stringify(toolResult));
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 5. 階層化された Logger の作成(必要な場合)
|
|
116
|
+
|
|
117
|
+
階層化が必要な場合(agenticProcess のタスクなど)は、context を切り替えた Logger インスタンスを作成します。
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const baseLogger = new Logger({ context: 'agentic' });
|
|
121
|
+
|
|
122
|
+
// タスク 1 用の Logger
|
|
123
|
+
const task1Logger = baseLogger.context(`task:1:planning`);
|
|
124
|
+
task1Logger.info('[start] Planning task');
|
|
125
|
+
|
|
126
|
+
// タスク 2 用の Logger
|
|
127
|
+
const task2Logger = baseLogger.context(`task:2:think`);
|
|
128
|
+
task2Logger.info('[start] Think task');
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## trace 側の責務
|
|
132
|
+
|
|
133
|
+
trace 機能(Logger の蓄積機能を利用する側)は以下の責務を持ちます:
|
|
134
|
+
|
|
135
|
+
- Logger の蓄積機能でエントリを収集する
|
|
136
|
+
- context でグループ化してファイルに書き出す
|
|
137
|
+
- ファイル形式やディレクトリ構造は trace 側が決定する
|
|
138
|
+
|
|
139
|
+
**重要**: ワークフロー側は trace の存在を知りません。ワークフロー実装者は Logger にログを出力するだけで、trace 機能の実装や設定については関知しません。
|
|
140
|
+
|
|
141
|
+
## 実装例
|
|
142
|
+
|
|
143
|
+
### シンプルなワークフロー
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import { Logger } from '@modular-prompt/utils';
|
|
147
|
+
import { compile } from '@modular-prompt/core';
|
|
148
|
+
|
|
149
|
+
const logger = new Logger({ context: 'simple' });
|
|
150
|
+
|
|
151
|
+
export async function simpleProcess(
|
|
152
|
+
driver: AIDriver,
|
|
153
|
+
module: PromptModule,
|
|
154
|
+
context: Context
|
|
155
|
+
): Promise<QueryResult> {
|
|
156
|
+
logger.info('[start] Simple workflow');
|
|
157
|
+
|
|
158
|
+
const compiledPrompt = compile(module, context);
|
|
159
|
+
logger.verbose('[prompt]', JSON.stringify(compiledPrompt, null, 2));
|
|
160
|
+
|
|
161
|
+
const result = await driver.query(compiledPrompt);
|
|
162
|
+
logger.verbose('[output]', result.output);
|
|
163
|
+
|
|
164
|
+
logger.info('[end] Simple workflow completed');
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 階層化されたワークフロー
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
import { Logger } from '@modular-prompt/utils';
|
|
173
|
+
|
|
174
|
+
const logger = new Logger({ context: 'agentic' });
|
|
175
|
+
|
|
176
|
+
export async function agenticProcess(
|
|
177
|
+
driver: AIDriver,
|
|
178
|
+
module: PromptModule,
|
|
179
|
+
context: Context
|
|
180
|
+
): Promise<QueryResult> {
|
|
181
|
+
logger.info('[start] Agentic workflow');
|
|
182
|
+
|
|
183
|
+
const tasks = [
|
|
184
|
+
{ id: 1, type: 'planning' },
|
|
185
|
+
{ id: 2, type: 'think' },
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
for (const task of tasks) {
|
|
189
|
+
const taskLogger = logger.context(`task:${task.id}:${task.type}`);
|
|
190
|
+
taskLogger.info('[start]', `Task ${task.id}: ${task.type}`);
|
|
191
|
+
|
|
192
|
+
// タスク実行
|
|
193
|
+
const result = await executeTask(driver, task);
|
|
194
|
+
taskLogger.verbose('[output]', result.output);
|
|
195
|
+
|
|
196
|
+
taskLogger.info('[end]', `Task ${task.id} completed`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
logger.info('[end] Agentic workflow completed');
|
|
200
|
+
return finalResult;
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## 関連ドキュメント
|
|
205
|
+
|
|
206
|
+
- [UTILITIES.md](./UTILITIES.md) - Logger の詳細仕様
|
|
207
|
+
- [agentic-workflow/DESIGN.md](../src/workflows/agentic-workflow/DESIGN.md) - Agentic Workflow v2 の設計文書(階層化されたログの実例)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modular-prompt/process",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.11",
|
|
4
4
|
"description": "Process module for modular prompt framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -21,11 +21,12 @@
|
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
23
|
"dist/**/*",
|
|
24
|
-
"README.md"
|
|
24
|
+
"README.md",
|
|
25
|
+
"docs"
|
|
25
26
|
],
|
|
26
27
|
"dependencies": {
|
|
27
28
|
"@modular-prompt/core": "0.3.0",
|
|
28
|
-
"@modular-prompt/driver": "0.
|
|
29
|
+
"@modular-prompt/driver": "0.17.1",
|
|
29
30
|
"@modular-prompt/utils": "0.3.5"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
@@ -68,6 +69,7 @@
|
|
|
68
69
|
"test:run": "vitest run",
|
|
69
70
|
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
70
71
|
"lint": "eslint src",
|
|
71
|
-
"typecheck": "tsc --noEmit"
|
|
72
|
+
"typecheck": "tsc --noEmit",
|
|
73
|
+
"copy-docs": "node ../../scripts/copy-package-docs.mjs process"
|
|
72
74
|
}
|
|
73
75
|
}
|