diff --git a/ars_opd/configs.py b/ars_opd/configs.py index 2ef14e4..67a8d48 100644 --- a/ars_opd/configs.py +++ b/ars_opd/configs.py @@ -125,17 +125,17 @@ class TeacherGenConfig: top_p: float = 0.95 """MiniMax M 系官方推荐采样参数:temperature=1.0, top_p=0.95。""" - max_tokens: int = 8192 - """teacher 单条回复的 token 上限。非显然约束:M3 的思考段也计入此额度, - 设太小会把解答挤没(只剩被截断的思考);student 侧超长解答由 collator 的 - completion 预算兜住,这里宁可给足。""" + max_tokens: int = 16384 + """teacher 单条回复的 token 上限。这是上限不是目标——按实际生成量计费, + 放大它不增加正常解答的成本,只给最难的题留出写完的空间(8192 时 59 条实测 + 截断 2 条)。非显然约束:M3 的思考段也计入此额度,设太小会把解答挤没。""" strip_think: bool = True """剥离 content 开头的 ... 思考段。SFT 的监督目标是最终 解答;student 以 enable_thinking=False 训练,学思考段会与模板约定矛盾。""" - concurrency: int = 8 - """并发请求数(线程池大小)。""" + concurrency: int = 16 + """并发请求数(线程池大小)。上限看网关的承受力,报 429 就调小。""" max_retries: int = 3 """单请求的网络级重试次数(openai 客户端内建指数退避)。""" diff --git a/ars_opd/teacher.py b/ars_opd/teacher.py index 79c1f85..56f43fc 100644 --- a/ars_opd/teacher.py +++ b/ars_opd/teacher.py @@ -16,6 +16,7 @@ from __future__ import annotations import json import os import re +import time from concurrent.futures import ThreadPoolExecutor, as_completed from pathlib import Path @@ -140,6 +141,7 @@ def generate_completions( failures: list[tuple[str, str]] = [] finished = 0 + start = time.monotonic() # 写盘收口在主线程(as_completed 消费端),工作线程只跑网络请求—— # 多线程同写一个文件句柄会交错损坏 JSONL with open(path, "a", encoding="utf-8") as f: @@ -155,7 +157,15 @@ def generate_completions( finally: finished += 1 if finished % 20 == 0 or finished == len(todo): - print(f"[teacher] {finished}/{len(todo)} 完成", flush=True) + elapsed = time.monotonic() - start + rate = finished / elapsed * 60 # 条/分 + eta = (len(todo) - finished) / rate if rate > 0 else 0 + print( + f"[teacher] {finished}/{len(todo)} 完成 | " + f"{rate:.1f} 条/分 | 已用 {elapsed / 60:.1f} 分 | " + f"预计剩余 {eta:.0f} 分", + flush=True, + ) record = { "key": key, "completion": completion,