@modular-prompt/driver 0.8.0 → 0.8.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 +37 -540
- package/dist/driver-registry/registry.d.ts +1 -2
- package/dist/driver-registry/registry.d.ts.map +1 -1
- package/dist/driver-registry/registry.js +1 -2
- package/dist/driver-registry/registry.js.map +1 -1
- package/dist/mlx-ml/mlx-driver.d.ts +1 -0
- package/dist/mlx-ml/mlx-driver.d.ts.map +1 -1
- package/dist/mlx-ml/mlx-driver.js +28 -3
- package/dist/mlx-ml/mlx-driver.js.map +1 -1
- package/dist/mlx-ml/process/parameter-mapper.d.ts.map +1 -1
- package/dist/mlx-ml/process/parameter-mapper.js +4 -2
- package/dist/mlx-ml/process/parameter-mapper.js.map +1 -1
- package/dist/mlx-ml/process/process-communication.d.ts.map +1 -1
- package/dist/mlx-ml/process/process-communication.js +2 -7
- package/dist/mlx-ml/process/process-communication.js.map +1 -1
- package/dist/mlx-ml/process/types.d.ts +2 -0
- package/dist/mlx-ml/process/types.d.ts.map +1 -1
- package/dist/mlx-ml/tool-call-parser.d.ts +1 -0
- package/dist/mlx-ml/tool-call-parser.d.ts.map +1 -1
- package/dist/mlx-ml/tool-call-parser.js +262 -17
- package/dist/mlx-ml/tool-call-parser.js.map +1 -1
- package/package.json +6 -4
- package/skills/driver-usage/SKILL.md +432 -0
- package/src/mlx-ml/python/token_utils.py +75 -17
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modular-prompt/driver",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"files": [
|
|
14
14
|
"dist",
|
|
15
15
|
"scripts",
|
|
16
|
+
"skills",
|
|
16
17
|
"src/mlx-ml/python"
|
|
17
18
|
],
|
|
18
19
|
"dependencies": {
|
|
@@ -23,8 +24,8 @@
|
|
|
23
24
|
"google-auth-library": "^9.15.1",
|
|
24
25
|
"js-yaml": "^4.1.0",
|
|
25
26
|
"openai": "^5.19.1",
|
|
26
|
-
"@modular-prompt/core": "0.1.
|
|
27
|
-
"@modular-prompt/utils": "0.2.
|
|
27
|
+
"@modular-prompt/core": "0.1.13",
|
|
28
|
+
"@modular-prompt/utils": "0.2.4"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"@eslint/js": "^9.35.0",
|
|
@@ -54,7 +55,8 @@
|
|
|
54
55
|
"download-model": "node scripts/download-model.js",
|
|
55
56
|
"lint": "eslint src/**/*.ts",
|
|
56
57
|
"typecheck": "tsc --noEmit",
|
|
57
|
-
"
|
|
58
|
+
"copy-skills": "mkdir -p skills/driver-usage && cp ../../skills/driver-usage/SKILL.md skills/driver-usage/SKILL.md",
|
|
59
|
+
"clean": "rm -rf dist skills tsconfig.tsbuildinfo",
|
|
58
60
|
"postinstall": "node scripts/setup-mlx.js || true",
|
|
59
61
|
"setup-mlx": "node scripts/setup-mlx.js"
|
|
60
62
|
}
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: driver-usage
|
|
3
|
+
description: modular-promptのドライバー(AIDriver)の使い方ガイド。各ドライバーの初期化、Config、query/streamQuery、ツール定義、構造化出力、AIServiceによるモデル選択を参照する。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ドライバー使い方ガイド
|
|
7
|
+
|
|
8
|
+
## ドライバーとは
|
|
9
|
+
|
|
10
|
+
`@modular-prompt/driver` は、コンパイル済みプロンプト(CompiledPrompt)をAIモデルに送信し、結果を受け取るための統一インターフェースを提供する。各AIサービスのAPI差異をドライバー層が吸収するため、プロンプト側のコードを変えずにモデルを切り替えられる。
|
|
11
|
+
|
|
12
|
+
### 基本的な使い方
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { compile } from '@modular-prompt/core';
|
|
16
|
+
import { OpenAIDriver } from '@modular-prompt/driver';
|
|
17
|
+
|
|
18
|
+
const driver = new OpenAIDriver({ model: 'gpt-4o' });
|
|
19
|
+
const compiled = compile(myModule, context);
|
|
20
|
+
|
|
21
|
+
// 通常クエリ
|
|
22
|
+
const result = await driver.query(compiled);
|
|
23
|
+
console.log(result.content);
|
|
24
|
+
|
|
25
|
+
// ストリーミング
|
|
26
|
+
const { stream, result: resultPromise } = await driver.streamQuery(compiled);
|
|
27
|
+
for await (const chunk of stream) {
|
|
28
|
+
process.stdout.write(chunk);
|
|
29
|
+
}
|
|
30
|
+
const finalResult = await resultPromise;
|
|
31
|
+
|
|
32
|
+
await driver.close();
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## AIDriver インターフェース
|
|
36
|
+
|
|
37
|
+
全ドライバーが実装する共通インターフェース:
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
interface AIDriver {
|
|
41
|
+
query(prompt: CompiledPrompt, options?: QueryOptions): Promise<QueryResult>;
|
|
42
|
+
streamQuery(prompt: CompiledPrompt, options?: QueryOptions): Promise<StreamResult>;
|
|
43
|
+
close(): Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### QueryOptions
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
interface QueryOptions {
|
|
51
|
+
temperature?: number;
|
|
52
|
+
maxTokens?: number;
|
|
53
|
+
topP?: number;
|
|
54
|
+
stream?: boolean;
|
|
55
|
+
tools?: ToolDefinition[];
|
|
56
|
+
toolChoice?: ToolChoice;
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### QueryResult
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
interface QueryResult {
|
|
64
|
+
content: string; // テキストレスポンス
|
|
65
|
+
structuredOutput?: unknown; // 構造化出力(schema指定時)
|
|
66
|
+
usage?: {
|
|
67
|
+
promptTokens: number;
|
|
68
|
+
completionTokens: number;
|
|
69
|
+
totalTokens: number;
|
|
70
|
+
};
|
|
71
|
+
toolCalls?: ToolCall[]; // ツール呼び出し
|
|
72
|
+
finishReason?: FinishReason; // 'stop' | 'length' | 'error' | 'tool_calls'
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### StreamResult
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
interface StreamResult {
|
|
80
|
+
stream: AsyncIterable<string>; // テキストチャンクのストリーム
|
|
81
|
+
result: Promise<QueryResult>; // 最終結果(ストリーム完了後に解決)
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 各ドライバーのConfig
|
|
86
|
+
|
|
87
|
+
### OpenAIDriver
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { OpenAIDriver } from '@modular-prompt/driver';
|
|
91
|
+
|
|
92
|
+
const driver = new OpenAIDriver({
|
|
93
|
+
apiKey: process.env.OPENAI_API_KEY, // 環境変数で代替可
|
|
94
|
+
model: 'gpt-4o-mini', // デフォルト: 'gpt-4o-mini'
|
|
95
|
+
baseURL: 'https://...', // カスタムエンドポイント(オプション)
|
|
96
|
+
organization: '...', // Organization ID(オプション)
|
|
97
|
+
defaultOptions: {
|
|
98
|
+
temperature: 0.7,
|
|
99
|
+
maxTokens: 2000,
|
|
100
|
+
frequencyPenalty: 0, // OpenAI固有
|
|
101
|
+
presencePenalty: 0, // OpenAI固有
|
|
102
|
+
stop: ['---'], // 停止シーケンス
|
|
103
|
+
responseFormat: { type: 'json_object' },
|
|
104
|
+
seed: 42
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### AnthropicDriver
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { AnthropicDriver } from '@modular-prompt/driver';
|
|
113
|
+
|
|
114
|
+
const driver = new AnthropicDriver({
|
|
115
|
+
apiKey: process.env.ANTHROPIC_API_KEY, // 環境変数で代替可
|
|
116
|
+
model: 'claude-3-5-sonnet-20241022', // デフォルト
|
|
117
|
+
defaultOptions: {
|
|
118
|
+
maxTokens: 4096,
|
|
119
|
+
temperature: 0.7,
|
|
120
|
+
topK: 40, // Anthropic固有
|
|
121
|
+
stopSequences: ['---']
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### VertexAIDriver
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { VertexAIDriver } from '@modular-prompt/driver';
|
|
130
|
+
|
|
131
|
+
const driver = new VertexAIDriver({
|
|
132
|
+
project: 'my-gcp-project', // 環境変数 GOOGLE_CLOUD_PROJECT で代替可
|
|
133
|
+
location: 'us-central1', // デフォルト: 'us-central1'
|
|
134
|
+
model: 'gemini-2.0-flash-001', // デフォルト
|
|
135
|
+
temperature: 0.05,
|
|
136
|
+
defaultOptions: {
|
|
137
|
+
maxTokens: 1000,
|
|
138
|
+
topP: 0.95,
|
|
139
|
+
topK: 40
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Google Cloud認証(ADCまたはサービスアカウント)が必要。
|
|
145
|
+
|
|
146
|
+
### GoogleGenAIDriver
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
import { GoogleGenAIDriver } from '@modular-prompt/driver';
|
|
150
|
+
|
|
151
|
+
const driver = new GoogleGenAIDriver({
|
|
152
|
+
apiKey: process.env.GOOGLE_GENAI_API_KEY, // 必須
|
|
153
|
+
model: 'gemini-2.0-flash-exp',
|
|
154
|
+
temperature: 0.7,
|
|
155
|
+
defaultOptions: {
|
|
156
|
+
maxTokens: 2048,
|
|
157
|
+
topP: 0.95,
|
|
158
|
+
topK: 40,
|
|
159
|
+
thinkingConfig: { thinkingLevel: 'HIGH' } // GoogleGenAI固有
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
APIキーのみで利用可能(Google AI Studioから取得)。
|
|
165
|
+
|
|
166
|
+
### OllamaDriver
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { OllamaDriver } from '@modular-prompt/driver';
|
|
170
|
+
|
|
171
|
+
const driver = new OllamaDriver({
|
|
172
|
+
baseURL: 'http://localhost:11434/v1', // デフォルト
|
|
173
|
+
model: 'llama3.2' // デフォルト
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
OpenAI互換APIでローカルLLMにアクセス。
|
|
178
|
+
|
|
179
|
+
### MlxDriver
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { MlxDriver } from '@modular-prompt/driver';
|
|
183
|
+
|
|
184
|
+
const driver = new MlxDriver({
|
|
185
|
+
model: 'mlx-community/Llama-3.2-3B-Instruct-4bit', // 必須
|
|
186
|
+
defaultOptions: {
|
|
187
|
+
temperature: 0.7,
|
|
188
|
+
maxTokens: 500,
|
|
189
|
+
repetitionPenalty: 1.1, // MLX固有
|
|
190
|
+
repetitionContextSize: 20 // MLX固有
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// 使用後は必ずclose()(Pythonサブプロセス終了)
|
|
195
|
+
await driver.close();
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Apple Silicon専用。Python 3.11以上が必要。
|
|
199
|
+
|
|
200
|
+
### テスト・デバッグ用ドライバー
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
import { TestDriver, EchoDriver } from '@modular-prompt/driver';
|
|
204
|
+
|
|
205
|
+
// TestDriver: モックレスポンス
|
|
206
|
+
const testDriver = new TestDriver({
|
|
207
|
+
responses: ['応答1', '応答2'], // キューから順に返す
|
|
208
|
+
delay: 100 // レイテンシのシミュレート(ms)
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// レスポンスプロバイダ関数
|
|
212
|
+
const testDriver2 = new TestDriver({
|
|
213
|
+
responses: (prompt, options) => {
|
|
214
|
+
if (prompt.metadata?.outputSchema) {
|
|
215
|
+
return JSON.stringify({ result: 'ok' });
|
|
216
|
+
}
|
|
217
|
+
return 'テキスト応答';
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// EchoDriver: フォーマット済みプロンプトをそのまま返す(AI呼び出しなし)
|
|
222
|
+
const echoDriver = new EchoDriver({
|
|
223
|
+
format: 'debug', // 'text' | 'messages' | 'raw' | 'both' | 'debug'
|
|
224
|
+
includeMetadata: true
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## ツール定義(Function Calling)
|
|
229
|
+
|
|
230
|
+
### ToolDefinition
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
const tools: ToolDefinition[] = [
|
|
234
|
+
{
|
|
235
|
+
name: 'get_weather',
|
|
236
|
+
description: '指定都市の天気を取得',
|
|
237
|
+
parameters: {
|
|
238
|
+
type: 'object',
|
|
239
|
+
properties: {
|
|
240
|
+
city: { type: 'string', description: '都市名' },
|
|
241
|
+
unit: { type: 'string', enum: ['celsius', 'fahrenheit'] }
|
|
242
|
+
},
|
|
243
|
+
required: ['city']
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
];
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### ToolChoice
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
type ToolChoice =
|
|
253
|
+
| 'auto' // モデルが自動判断(デフォルト)
|
|
254
|
+
| 'none' // ツール使用禁止
|
|
255
|
+
| 'required' // 必ず1つ以上のツールを使用
|
|
256
|
+
| { name: string }; // 特定ツールを強制
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### ツール呼び出しの処理
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
const result = await driver.query(compiled, { tools, toolChoice: 'auto' });
|
|
263
|
+
|
|
264
|
+
if (result.toolCalls) {
|
|
265
|
+
for (const call of result.toolCalls) {
|
|
266
|
+
console.log(call.name); // 関数名
|
|
267
|
+
console.log(call.id); // 呼び出しID
|
|
268
|
+
console.log(call.arguments); // 引数オブジェクト
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
対応ドライバー: OpenAI、Anthropic、VertexAI、GoogleGenAI
|
|
274
|
+
|
|
275
|
+
### ツール結果の返し方(会話ループ)
|
|
276
|
+
|
|
277
|
+
ツール呼び出し結果をモデルに返す会話ループは利用者側で実装する。`QueryOptions.messages` にツール結果を含めて再クエリする。
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
const result1 = await driver.query(compiled, { tools, toolChoice: 'auto' });
|
|
281
|
+
|
|
282
|
+
if (result1.toolCalls) {
|
|
283
|
+
// ツールを実行して結果を収集
|
|
284
|
+
const toolResults = await Promise.all(
|
|
285
|
+
result1.toolCalls.map(async (tc) => {
|
|
286
|
+
const data = await executeFunction(tc.name, tc.arguments);
|
|
287
|
+
return {
|
|
288
|
+
role: 'tool' as const,
|
|
289
|
+
toolCallId: tc.id,
|
|
290
|
+
name: tc.name,
|
|
291
|
+
kind: 'data' as const, // 'text' | 'data' | 'error'
|
|
292
|
+
value: data
|
|
293
|
+
};
|
|
294
|
+
})
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
// ツール結果を含めて再クエリ
|
|
298
|
+
const result2 = await driver.query(compiled, {
|
|
299
|
+
tools,
|
|
300
|
+
messages: [
|
|
301
|
+
{ role: 'assistant', content: result1.content, toolCalls: result1.toolCalls },
|
|
302
|
+
...toolResults
|
|
303
|
+
]
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### ToolResultKind
|
|
309
|
+
|
|
310
|
+
ツール結果の種類を示すタグ:
|
|
311
|
+
- `'text'` - プレーンテキスト
|
|
312
|
+
- `'data'` - 構造化データ(オブジェクト等)
|
|
313
|
+
- `'error'` - エラー情報
|
|
314
|
+
|
|
315
|
+
## 構造化出力
|
|
316
|
+
|
|
317
|
+
プロンプトの `schema` セクションに JSONElement を定義すると、ドライバーが自動的に構造化出力を処理する。
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
const myModule: PromptModule = {
|
|
321
|
+
objective: ['ユーザー情報を抽出する'],
|
|
322
|
+
schema: [{
|
|
323
|
+
type: 'json',
|
|
324
|
+
content: {
|
|
325
|
+
type: 'object',
|
|
326
|
+
properties: {
|
|
327
|
+
name: { type: 'string' },
|
|
328
|
+
age: { type: 'number' }
|
|
329
|
+
},
|
|
330
|
+
required: ['name', 'age']
|
|
331
|
+
}
|
|
332
|
+
}]
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const result = await driver.query(compile(myModule, ctx));
|
|
336
|
+
const data = result.structuredOutput as { name: string; age: number };
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
ドライバーごとの実装方式:
|
|
340
|
+
- **ネイティブサポート**: OpenAI(`response_format`)、VertexAI / GoogleGenAI(`responseSchema`)
|
|
341
|
+
- **JSON抽出型**: Anthropic、MLX(プロンプト指示 + レスポンスからJSON抽出)
|
|
342
|
+
|
|
343
|
+
## AIService(モデル選択)
|
|
344
|
+
|
|
345
|
+
複数モデルを登録し、能力(capabilities)ベースで最適なモデルを自動選択する。
|
|
346
|
+
|
|
347
|
+
### 設定
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
import { AIService } from '@modular-prompt/driver';
|
|
351
|
+
|
|
352
|
+
const service = new AIService({
|
|
353
|
+
models: [
|
|
354
|
+
{
|
|
355
|
+
model: 'gpt-4o',
|
|
356
|
+
provider: 'openai',
|
|
357
|
+
capabilities: ['streaming', 'japanese', 'tools', 'structured'],
|
|
358
|
+
priority: 10,
|
|
359
|
+
cost: { input: 0.01, output: 0.03 }
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
model: 'claude-3-5-sonnet-20241022',
|
|
363
|
+
provider: 'anthropic',
|
|
364
|
+
capabilities: ['streaming', 'japanese', 'tools', 'reasoning'],
|
|
365
|
+
priority: 8
|
|
366
|
+
}
|
|
367
|
+
],
|
|
368
|
+
drivers: {
|
|
369
|
+
openai: { apiKey: process.env.OPENAI_API_KEY },
|
|
370
|
+
anthropic: { apiKey: process.env.ANTHROPIC_API_KEY }
|
|
371
|
+
},
|
|
372
|
+
defaultOptions: {
|
|
373
|
+
temperature: 0.7,
|
|
374
|
+
maxTokens: 2048
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### ModelSpec
|
|
380
|
+
|
|
381
|
+
```typescript
|
|
382
|
+
interface ModelSpec {
|
|
383
|
+
model: string;
|
|
384
|
+
provider: DriverProvider;
|
|
385
|
+
capabilities: DriverCapability[];
|
|
386
|
+
priority?: number; // 高いほど優先
|
|
387
|
+
disabled?: boolean; // 無効化フラグ
|
|
388
|
+
maxInputTokens?: number;
|
|
389
|
+
maxOutputTokens?: number;
|
|
390
|
+
maxTotalTokens?: number;
|
|
391
|
+
tokensPerMinute?: number; // TPM制限
|
|
392
|
+
requestsPerMinute?: number; // RPM制限
|
|
393
|
+
cost?: { input: number; output: number };
|
|
394
|
+
metadata?: Record<string, unknown>;
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### DriverCapability(能力フラグ)
|
|
399
|
+
|
|
400
|
+
| 能力 | 説明 |
|
|
401
|
+
|------|------|
|
|
402
|
+
| `streaming` | ストリーミング応答 |
|
|
403
|
+
| `local` | ローカル実行 |
|
|
404
|
+
| `fast` | 高速応答 |
|
|
405
|
+
| `large-context` | 大規模コンテキスト |
|
|
406
|
+
| `multilingual` | 多言語対応 |
|
|
407
|
+
| `japanese` | 日本語特化 |
|
|
408
|
+
| `coding` | コーディング特化 |
|
|
409
|
+
| `reasoning` | 推論・思考特化 |
|
|
410
|
+
| `chat` | チャット特化 |
|
|
411
|
+
| `tools` | ツール使用 |
|
|
412
|
+
| `vision` | 画像認識 |
|
|
413
|
+
| `audio` | 音声処理 |
|
|
414
|
+
| `structured` | 構造化出力 |
|
|
415
|
+
| `json` | JSON出力 |
|
|
416
|
+
| `function-calling` | 関数呼び出し |
|
|
417
|
+
|
|
418
|
+
### モデル選択
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
// 能力ベースでドライバーを自動作成
|
|
422
|
+
const driver = await service.createDriverFromCapabilities(
|
|
423
|
+
['japanese', 'streaming'],
|
|
424
|
+
{
|
|
425
|
+
preferLocal: true, // ローカル優先
|
|
426
|
+
preferProvider: 'anthropic', // 特定プロバイダー優先
|
|
427
|
+
excludeProviders: ['openai'],
|
|
428
|
+
preferFast: true, // 高速優先
|
|
429
|
+
lenient: true // 条件緩和モード(条件を後ろから減らして再検索)
|
|
430
|
+
}
|
|
431
|
+
);
|
|
432
|
+
```
|
|
@@ -124,7 +124,15 @@ def get_special_tokens(tokenizer):
|
|
|
124
124
|
"scratchpad": ("<|scratchpad|>", "<|/scratchpad|>"),
|
|
125
125
|
"analysis": ("<|analysis|>", "<|/analysis|>"),
|
|
126
126
|
"summary": ("<|summary|>", "<|/summary|>"),
|
|
127
|
-
"explanation": ("<|explanation|>", "<|/explanation|>")
|
|
127
|
+
"explanation": ("<|explanation|>", "<|/explanation|>"),
|
|
128
|
+
|
|
129
|
+
# tool_call バリエーション(追加)
|
|
130
|
+
"tool_call_explicit": ("<|tool_call_start|>", "<|tool_call_end|>"),
|
|
131
|
+
"tool_call_xml": ("<tool_call>", "</tool_call>"),
|
|
132
|
+
"tool_calls_section": ("<|tool_calls_section_begin|>", "<|tool_calls_section_end|>"),
|
|
133
|
+
"function_call_tags": ("<start_function_call>", "<end_function_call>"),
|
|
134
|
+
"longcat_tool_call": ("<longcat_tool_call>", "</longcat_tool_call>"),
|
|
135
|
+
"minimax_tool_call": ("<minimax:tool_call>", "</minimax:tool_call>"),
|
|
128
136
|
}
|
|
129
137
|
|
|
130
138
|
# 単体トークン(存在する場合のみ)
|
|
@@ -143,7 +151,10 @@ def get_special_tokens(tokenizer):
|
|
|
143
151
|
# 一般的なマークダウン風
|
|
144
152
|
"code_inline": "`",
|
|
145
153
|
"code_block_start": "```",
|
|
146
|
-
"code_block_end": "```"
|
|
154
|
+
"code_block_end": "```",
|
|
155
|
+
|
|
156
|
+
# ツール関連の単体トークン(追加)
|
|
157
|
+
"tool_calls_marker": "[TOOL_CALLS]",
|
|
147
158
|
}
|
|
148
159
|
|
|
149
160
|
# ペアトークンの処理
|
|
@@ -192,6 +203,24 @@ def detect_tool_call_format(tokenizer):
|
|
|
192
203
|
if hasattr(tokenizer, 'init_kwargs'):
|
|
193
204
|
tool_parser_type = tokenizer.init_kwargs.get('tool_parser_type')
|
|
194
205
|
|
|
206
|
+
# 既知パーサーからの逆引き(最優先)
|
|
207
|
+
KNOWN_TOOL_PARSERS = {
|
|
208
|
+
"json_tools": {"call_start": "<tool_call>", "call_end": "</tool_call>"},
|
|
209
|
+
"pythonic": {"call_start": "<|tool_call_start|>", "call_end": "<|tool_call_end|>"},
|
|
210
|
+
"function_gemma": {"call_start": "<start_function_call>", "call_end": "<end_function_call>"},
|
|
211
|
+
"mistral": {"call_start": "[TOOL_CALLS]", "call_end": ""},
|
|
212
|
+
"kimi_k2": {"call_start": "<|tool_calls_section_begin|>", "call_end": "<|tool_calls_section_end|>"},
|
|
213
|
+
"longcat": {"call_start": "<longcat_tool_call>", "call_end": "</longcat_tool_call>"},
|
|
214
|
+
"glm47": {"call_start": "<tool_call>", "call_end": "</tool_call>"},
|
|
215
|
+
"qwen3_coder": {"call_start": "<tool_call>", "call_end": "</tool_call>"},
|
|
216
|
+
"minimax_m2": {"call_start": "<minimax:tool_call>", "call_end": "</minimax:tool_call>"},
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if tool_parser_type and tool_parser_type in KNOWN_TOOL_PARSERS:
|
|
220
|
+
result = {"tool_parser_type": tool_parser_type}
|
|
221
|
+
result.update(KNOWN_TOOL_PARSERS[tool_parser_type])
|
|
222
|
+
return result
|
|
223
|
+
|
|
195
224
|
# chat_template テキストを取得
|
|
196
225
|
template = getattr(tokenizer, 'chat_template', None)
|
|
197
226
|
if not template and hasattr(tokenizer, 'init_kwargs'):
|
|
@@ -207,21 +236,36 @@ def detect_tool_call_format(tokenizer):
|
|
|
207
236
|
|
|
208
237
|
# テンプレートテキストからデリミタを抽出
|
|
209
238
|
if template:
|
|
210
|
-
# tool_call
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
#
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
239
|
+
# 複数のtool_call関連パターンを順に試行
|
|
240
|
+
tool_call_patterns = [
|
|
241
|
+
# <tool_call>...</tool_call>, <|tool_call|>...<|/tool_call|>
|
|
242
|
+
(r'<\|?tool_call\|?>', r'</?\|?tool_call\|?>|<\|?/tool_call\|?>'),
|
|
243
|
+
# <|tool_call_start|>...<|tool_call_end|>
|
|
244
|
+
(r'<\|tool_call_start\|>', r'<\|tool_call_end\|>'),
|
|
245
|
+
# <start_function_call>...<end_function_call>
|
|
246
|
+
(r'<start_function_call>', r'<end_function_call>'),
|
|
247
|
+
# <|tool_calls_section_begin|>...<|tool_calls_section_end|>
|
|
248
|
+
(r'<\|tool_calls_section_begin\|>', r'<\|tool_calls_section_end\|>'),
|
|
249
|
+
# <longcat_tool_call>...</longcat_tool_call>
|
|
250
|
+
(r'<longcat_tool_call>', r'</longcat_tool_call>'),
|
|
251
|
+
# <minimax:tool_call>...</minimax:tool_call>
|
|
252
|
+
(r'<minimax:tool_call>', r'</minimax:tool_call>'),
|
|
253
|
+
]
|
|
254
|
+
|
|
255
|
+
for start_pattern, end_pattern in tool_call_patterns:
|
|
256
|
+
start_match = re.search(start_pattern, template)
|
|
257
|
+
end_match = re.search(end_pattern, template)
|
|
258
|
+
if start_match and end_match:
|
|
259
|
+
result["call_start"] = start_match.group(0)
|
|
260
|
+
result["call_end"] = end_match.group(0)
|
|
261
|
+
break
|
|
262
|
+
|
|
263
|
+
# Mistral特殊ケース
|
|
264
|
+
if "call_start" not in result:
|
|
265
|
+
mistral_match = re.search(r'\[TOOL_CALLS\]', template)
|
|
266
|
+
if mistral_match:
|
|
267
|
+
result["call_start"] = "[TOOL_CALLS]"
|
|
268
|
+
result["call_end"] = ""
|
|
225
269
|
|
|
226
270
|
# tool_response タグの検出
|
|
227
271
|
resp_tags = re.findall(r'<[|/]?tool_response[|]?>', template)
|
|
@@ -325,6 +369,20 @@ def get_capabilities(tokenizer):
|
|
|
325
369
|
"features": get_tokenizer_features(tokenizer)
|
|
326
370
|
}
|
|
327
371
|
|
|
372
|
+
# tool_call_formatの情報をspecial_tokensに反映(補完)
|
|
373
|
+
features = capabilities.get("features", {})
|
|
374
|
+
chat_template = features.get("chat_template")
|
|
375
|
+
if chat_template:
|
|
376
|
+
tcf = chat_template.get("tool_call_format")
|
|
377
|
+
if tcf and tcf.get("call_start") and "tool_call" not in capabilities["special_tokens"]:
|
|
378
|
+
call_start = tcf["call_start"]
|
|
379
|
+
call_end = tcf.get("call_end", "")
|
|
380
|
+
if call_end: # ペアがある場合のみ
|
|
381
|
+
capabilities["special_tokens"]["tool_call"] = {
|
|
382
|
+
"start": {"text": call_start, "id": -1},
|
|
383
|
+
"end": {"text": call_end, "id": -1}
|
|
384
|
+
}
|
|
385
|
+
|
|
328
386
|
# チャット制約を検出して追加
|
|
329
387
|
chat_restrictions = detect_chat_restrictions(tokenizer)
|
|
330
388
|
if chat_restrictions:
|