Вышла новая модель — стоит побенчить
Обратная сторона деприкейта: новые модели тоже появляются молча. Пока вы залипли в фичах, провайдер выкатил модель дешевле/умнее/быстрее, а вы полгода платите за старую. Это не инцидент — поэтому push низкого приоритета (0–3, тихий), просто чтобы не пропустить.
Тот же scheduled-опрос /models, но
логика инвертирована: интересуют новые id, которых не было в прошлый раз.
Скелет: диф списка моделей
Заголовок раздела «Скелет: диф списка моделей»State-файл хранит множество ранее виденных id. Всё, чего в нём нет, — кандидат на бенчмарк.
import os, json, requests
STATE = "/tmp/known-models.json"
# префиксы семейств, которые вам интересны (чтобы не шуметь на служебных id)WATCH_PREFIXES = ("gpt-", "o1", "o3", "claude-")
def notify(title, msg, prio): requests.post(f"{os.environ['NOTIFLY_URL']}/message", params={"token": os.environ["NOTIFLY_TOKEN"]}, json={"title": title, "message": msg, "priority": prio}, timeout=5)
def list_model_ids(): r = requests.get("https://api.openai.com/v1/models", headers={"Authorization": f"Bearer {os.environ['PROVIDER_KEY']}"}, timeout=15) r.raise_for_status() return {m["id"] for m in r.json()["data"] if m["id"].startswith(WATCH_PREFIXES)}
def handler(event, context): current = list_model_ids() known = set(json.load(open(STATE))) if os.path.exists(STATE) else set()
# первый запуск — просто запоминаем, не спамим весь каталог if not known: json.dump(sorted(current), open(STATE, "w")) return {"statusCode": 200, "body": "seeded"}
fresh = sorted(current - known) if fresh: notify("🆕 Новые модели у провайдера", "Появились в /models:\n" + "\n".join(f"• {m}" for m in fresh) + "\n\nСтоит прогнать eval и сравнить цену/качество.", prio=2) # тихий информационный push json.dump(sorted(current | known), open(STATE, "w"))
return {"statusCode": 200, "body": json.dumps({"new": fresh})}priority=2 — это «когда будет минутка», без звука и вибрации. Именно то,
чего заслуживает новость «есть что побенчить», а не «всё сломалось».
Timer раз в день (0 10 * * ? *) — новые модели не появляются каждую минуту.
Автоматический мини-бенчмарк прямо в алёрте
Заголовок раздела «Автоматический мини-бенчмарк прямо в алёрте»Полезно не просто сказать «вышла модель», а сразу дать пару цифр. Гоняем крошечный eval на новом id и кладём результат в push:
def quick_bench(model_id: str) -> str: cases = [("2+2?", "4"), ("Столица Франции?", "Париж")] ok = 0 for q, expected in cases: out = ask_model(model_id, q) # ваш вызов провайдера ok += expected.lower() in out.lower() return f"smoke-eval: {ok}/{len(cases)}"
# внутри handler, для каждой fresh-модели:line = f"• {m} — {quick_bench(m)}"Полноценное сравнение с текущей прод-моделью — уже задача из eval-регрессии; здесь достаточно smoke-теста, чтобы понять, «живая» ли модель и стоит ли тратить на неё вечер.
Что положить в текст алёрта
Заголовок раздела «Что положить в текст алёрта»- список новых id (только интересных семейств, без служебных);
- по возможности — цена за 1M токенов и context window новой модели;
- результат smoke-eval, если гоняете;
- ссылка на release notes провайдера.