zelk12 commited on
Commit
7079daf
·
verified ·
1 Parent(s): e1b5d04

Upload 3 files

Browse files
MMLU-Pro-mini/benchlocal.pack.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schemaVersion": 1,
3
+ "protocolVersion": 1,
4
+ "id": "mmlu-pro-multilingual-reasoning-126",
5
+ "name": "MMLU-Pro Multilingual Reasoning Benchmark (126 Scenarios)",
6
+ "version": "3.0.0",
7
+ "description": "Строгий бенчмарк MMLU-Pro: 14 категорий, 126 расчетно-логических задач (по 9 в категории: 3 RU, 3 EN, 3 Mixed), 10 сбалансированных вариантов выбора (A-J), отсутствие Length Heuristic и Position Bias",
8
+ "entry": "./index.mjs",
9
+ "samplingDefaults": {
10
+ "temperature": 0.0
11
+ },
12
+ "capabilities": {
13
+ "tools": false,
14
+ "multiTurn": false,
15
+ "streamingProgress": false,
16
+ "verification": true
17
+ }
18
+ }
MMLU-Pro-mini/index.mjs ADDED
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+ const manifestPath = path.join(__dirname, "benchlocal.pack.json");
7
+ const scenariosPath = path.join(__dirname, "scenarios.json");
8
+
9
+ export const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
10
+
11
+ /**
12
+ * Формирование финального промпта:
13
+ * Оформляет 10 вариантов (A-J), поощряет пошаговые рассуждения (Chain-of-Thought)
14
+ * и требует вывода строгого вердикта на последней строке с примерами на буквах X, Y, Z.
15
+ */
16
+ function buildFullPrompt(s) {
17
+ const letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"];
18
+ const formattedOptions = s.options
19
+ .map((opt, i) => `${letters[i]}) ${opt}`)
20
+ .join("\n");
21
+
22
+ if (s.language === "ru") {
23
+ return `${s.question}\n\nВарианты ответа:\n${formattedOptions}\n\nИНСТРУКЦИЯ ПО ВЫПОЛНЕНИЮ:
24
+ Ты можешь и должен подробно рассуждать по шагам (Chain-of-Thought), решая задачу и анализируя данные.
25
+ Однако в самом конце твоего ответа обязана присутствовать отдельная финальная строка, строго оформленная по шаблону:
26
+ Мой ответ: (БУКВА)
27
+
28
+ Примеры правильного оформления финала (буквы X, Y, Z приведены только для образца и отсутствуют в вариантах A-J):
29
+ Пример 1:
30
+ ... [твои пошаговые вычисления и рассуждения] ...
31
+ Мой ответ: (X)
32
+
33
+ Пример 2:
34
+ ... [твои пошаговые вычисления и рассуждения] ...
35
+ Мой ответ: (Y)
36
+
37
+ Пример 3:
38
+ ... [твои пошаговые вычисления и рассуждения] ...
39
+ Мой ответ: (Z)`;
40
+ }
41
+
42
+ if (s.language === "en") {
43
+ return `${s.question}\n\nOptions:\n${formattedOptions}\n\nINSTRUCTIONS:
44
+ You can and should reason step-by-step (Chain-of-Thought) to rigorously solve the problem.
45
+ However, at the very end of your response, you must provide your final conclusion on a separate line strictly formatted as:
46
+ My answer: (LETTER)
47
+
48
+ Examples of final line formatting (letters X, Y, Z are placeholders and not choices A-J):
49
+ Example 1:
50
+ ... [your step-by-step reasoning and calculations] ...
51
+ My answer: (X)
52
+
53
+ Example 2:
54
+ ... [your step-by-step reasoning and calculations] ...
55
+ My answer: (Y)
56
+
57
+ Example 3:
58
+ ... [your step-by-step reasoning and calculations] ...
59
+ My answer: (Z)`;
60
+ }
61
+
62
+ return `${s.question}\n\nВарианты / Options:\n${formattedOptions}\n\nИНСТРУКЦИЯ / INSTRUCTIONS:
63
+ Рассуждай подробно по шагам (Chain-of-Thought), проводя необходимые расчеты.
64
+ В самом конце твой output обязан завершаться отдельной строкой строго по шаблону:
65
+ Мой ответ / My answer: (LETTER)
66
+
67
+ Examples / Примеры завершения (буквы X, Y, Z взяты для примера и отсутствуют в вариантах A-J):
68
+ Example 1:
69
+ ... [твои рассуждения / reasoning] ...
70
+ Мой ответ / My answer: (X)
71
+
72
+ Example 2:
73
+ ... [твои рассуждения / reasoning] ...
74
+ Мой ответ / My answer: (Y)
75
+
76
+ Example 3:
77
+ ... [твои рассуждения / reasoning] ...
78
+ Мой ответ / My answer: (Z)`;
79
+ }
80
+
81
+ function loadScenarios() {
82
+ const raw = JSON.parse(fs.readFileSync(scenariosPath, "utf8"));
83
+ return raw.map((s) => ({
84
+ ...s,
85
+ prompt: s.prompt || buildFullPrompt(s)
86
+ }));
87
+ }
88
+
89
+ export function listScenarios() {
90
+ return loadScenarios().map((s) => ({
91
+ id: s.id,
92
+ name: s.name,
93
+ category: s.category || "General",
94
+ description: `[${(s.language || "ru").toUpperCase()}] ${s.name}`
95
+ }));
96
+ }
97
+
98
+ export function getScenarios() {
99
+ return listScenarios();
100
+ }
101
+
102
+ /**
103
+ * Валидатор Chain-of-Thought:
104
+ * Позволяет модели рассуждать, но проверяет наличие требуемой завершающей конструкции.
105
+ */
106
+ function validateResponse(scenario, rawText) {
107
+ const text = (rawText || "").trim();
108
+ const expected = (scenario.correctAnswer || "").trim().toUpperCase();
109
+
110
+ const pattern = /(?:Мой\s*ответ|My\s*answer|Мой\s*ответ\s*\/\s*My\s*answer):\s*\(([A-J])\)/gi;
111
+ const matches = [...text.matchAll(pattern)];
112
+
113
+ if (matches.length === 0) {
114
+ return {
115
+ pass: false,
116
+ score: 0,
117
+ extracted: null,
118
+ reason: `Нарушен формат финала: не найдена обязательная строка 'Мой ответ: (БУКВА)'. Окончание ответа: "${text.slice(-120)}"`
119
+ };
120
+ }
121
+
122
+ const lastMatch = matches[matches.length - 1];
123
+ const extracted = lastMatch[1].toUpperCase();
124
+
125
+ if (extracted !== expected) {
126
+ return {
127
+ pass: false,
128
+ score: 0,
129
+ extracted,
130
+ reason: `Неверный ответ: модель пришла к выводу '(${extracted})', ожидалось '(${expected})'`
131
+ };
132
+ }
133
+
134
+ return {
135
+ pass: true,
136
+ score: 100,
137
+ extracted,
138
+ reason: `Верно: обоснован и выбран правильный вариант '(${extracted})'`
139
+ };
140
+ }
141
+
142
+ function resolveHelpers(context) {
143
+ if (context && typeof context.getRequiredProvider === "function") {
144
+ return context;
145
+ }
146
+ if (context?.helpers && typeof context.helpers.getRequiredProvider === "function") {
147
+ return context.helpers;
148
+ }
149
+ return {
150
+ getRequiredProvider(providerId) {
151
+ const providers = context?.providers || [];
152
+ const found = Array.isArray(providers)
153
+ ? providers.find((p) => p.id === providerId || p.provider === providerId)
154
+ : providers[providerId];
155
+ return found || { baseUrl: "http://127.0.0.1:11434/v1", apiKey: "none" };
156
+ },
157
+ getInferenceEndpoint(modelId) {
158
+ return context?.endpoints?.[modelId] || null;
159
+ }
160
+ };
161
+ }
162
+
163
+ export async function prepare(context) {
164
+ const helpers = resolveHelpers(context);
165
+
166
+ return {
167
+ async runScenario(input) {
168
+ const allScenarios = loadScenarios();
169
+ const scenario = allScenarios.find((s) => s.id === input.scenario.id);
170
+ if (!scenario) {
171
+ return {
172
+ scenarioId: input.scenario.id,
173
+ status: "fail",
174
+ score: 0,
175
+ summary: "Сценарий не найден",
176
+ rawLog: "error=Scenario not found"
177
+ };
178
+ }
179
+
180
+ const provider = helpers.getRequiredProvider(input.model.provider, { enabledOnly: true });
181
+ const inference = helpers.getInferenceEndpoint ? helpers.getInferenceEndpoint(input.model.id) : null;
182
+
183
+ const rawBaseUrl = (inference && inference.status === "running" ? inference.baseUrl : provider?.baseUrl) || "http://127.0.0.1:11434/v1";
184
+ const baseUrl = rawBaseUrl.replace(/\/+$/, "");
185
+ const apiKey = provider?.apiKey || "none";
186
+
187
+ const requestBody = {
188
+ model: input.model.model,
189
+ messages: [{ role: "user", content: scenario.prompt }],
190
+ temperature: 0
191
+ };
192
+
193
+ const response = await fetch(`${baseUrl}/chat/completions`, {
194
+ method: "POST",
195
+ headers: {
196
+ "Content-Type": "application/json",
197
+ Authorization: `Bearer ${apiKey}`
198
+ },
199
+ body: JSON.stringify(requestBody)
200
+ });
201
+
202
+ const data = await response.json();
203
+ const text = (data.choices?.[0]?.message?.content || "").trim();
204
+ const result = validateResponse(scenario, text);
205
+
206
+ const rawLog = [
207
+ `model=${input.model.model}`,
208
+ `category=${scenario.category}`,
209
+ `language=${scenario.language}`,
210
+ `scenario=${scenario.id} - ${scenario.name}`,
211
+ `prompt=${scenario.prompt}`,
212
+ `assistant_full_cot_response=${text}`,
213
+ `extracted_final_letter=${result.extracted || "NONE"}`,
214
+ `expected_letter=${scenario.correctAnswer}`,
215
+ `verdict=${result.pass ? "pass" : "fail"}`,
216
+ `score=${result.score}`,
217
+ `summary=${result.reason}`,
218
+ `\n--- RAW API RESPONSE ---`,
219
+ JSON.stringify(data, null, 2)
220
+ ].join("\n");
221
+
222
+ return {
223
+ scenarioId: scenario.id,
224
+ category: scenario.category,
225
+ language: scenario.language,
226
+ status: result.pass ? "pass" : "fail",
227
+ score: result.score,
228
+ summary: result.reason,
229
+ rawLog: rawLog
230
+ };
231
+ },
232
+
233
+ async dispose() {}
234
+ };
235
+ }
236
+
237
+ export function scoreModelResults(results) {
238
+ const scored = results || [];
239
+ const total = scored.reduce((sum, r) => sum + (r.score || 0), 0);
240
+ const max = scored.length * 100;
241
+
242
+ const catMap = new Map();
243
+ for (const r of scored) {
244
+ const cat = r.category || "General";
245
+ if (!catMap.has(cat)) {
246
+ catMap.set(cat, { total: 0, count: 0 });
247
+ }
248
+ const entry = catMap.get(cat);
249
+ entry.total += r.score || 0;
250
+ entry.count += 1;
251
+ }
252
+
253
+ const categories = Array.from(catMap.entries()).map(([name, data]) => ({
254
+ name,
255
+ score: data.count > 0 ? Math.round((data.total / (data.count * 100)) * 100) : 0,
256
+ count: data.count
257
+ }));
258
+
259
+ return {
260
+ totalScore: max > 0 ? Math.round((total / max) * 100) : 0,
261
+ categories
262
+ };
263
+ }
264
+
265
+ export default {
266
+ manifest,
267
+ listScenarios,
268
+ getScenarios,
269
+ prepare,
270
+ createRuntime: prepare,
271
+ scoreModelResults
272
+ };
MMLU-Pro-mini/scenarios.json ADDED
The diff for this file is too large to render. See raw diff