Слогер Создать блог
Разработка

Как составить тестовое для LLM-разработчика, которое переживёт смену модели

Привязка к хешу фикстуры вместо вендорского эндпоинта — то, что даёт двум проверяющим одинаковый результат на разных ноутбуках.

Тестовое задание про eval-раннер ломается тихо. Кандидат присылает зелёный прогон, второй проверяющий открывает его у себя и получает красное. Код при этом нормальный. Просто проверки сцеплены с конкретным эндпоинтом, а не с документом данных.

Дефект называется swap drift. Набор тестов зелёный только на том эндпоинте, который использовался в день черновика. Поменяли base URL, id модели или хост с фикстурой — assertions посыпались. Проверяющий часто записывает это в сбой сервиса, хотя тесты были привязаны к одному вендорскому конверту.

Почему это больно на handoff

Сравнивать кандидатов в цикле найма нечем, если у проверяющих нет общего документа и общего порта. Две оценки не могут быть честными, когда каждая демонстрация зависит от приватного ключа и процесса на ноутбуке, который засыпает в самый неподходящий момент.

Хостируемая фикстура с записанным хешем убирает отговорку для документа, который оба проверяющих обязаны прочитать. Сменный адаптер убирает парную отговорку для пути получения ответа — передача перестаёт зависеть от одной машины.

За рамками задания остаются ретраи, тайминги outbox и sticky-флаги. У этих историй свои листы оценки, и смешивать их с контрактом фикстуры не стоит.

Что уходит кандидату

Промпт держится на одной странице и называет файлы, а не любимый бренд. Отдельной строкой — что живой вызов опционален. Если ключа нет, сетевой путь пропускается, а полный отчёт по заглушке всё равно должен собраться. Числового лимита в задании нет: это число не часть проверяемого контракта.

Шесть условий

  1. Прочитать локальный fixture.json, вызвать один адаптер и записать report.json с одним объектом решения.
  2. Брать MODEL_BASE_URL, MODEL_API_KEY и FIXTURE_URL только из переменных окружения — никогда из закоммиченных файлов.
  3. Хранить SHA-256 байтов фикстуры и падать закрыто, если скачанные байты не совпали с закреплённым хешем.
  4. Держать три инварианта: цитаты только по id из фикстуры, неизвестные поля отбрасываются, один ключ идемпотентности даёт один decision id.
  5. Отдать stub-режим без сети и hosted-режим, который тянет тот же самый документ фикстуры.
  6. Перечислить все непроверенные утверждения — лимиты, сроки хранения, регионы — вместо того, чтобы вписывать их в тесты.

Живой путь можно нацелить на заявленный оператором бесплатный маршрут к модели, а фикстуру опубликовать через бесплатный серверный вариант. Оценка всё равно обязана пройти, когда живой путь пропущен из-за отсутствия ключа. Бесплатный доступ и хостинг здесь ценны ровно одним: оценщик может переиграть те же самые байты. И это операторские заявления, а не измеренная ёмкость — ни квоты токенов, ни профиля железа, ни списка регионов в задании нет, пока их не подтверждает первоисточник. Числовой лимит не должен всплывать ни в assertion, ни в поле фикстуры, ни в комментарии, который поздние тесты примут за факт.

Лист оценки для проверяющего

Оценивается поведение. Проза про продукт баллов не добавляет, зелёный скриншот без хеша не считается. Живой путь помечается как пропущенный, если он в этой сессии реально не запускался. И проход только на заглушке нельзя повышать до письменного утверждения про какой-то конкретный маршрут модели.

ПроверкаПроходитПровалено
Фиксация фикстурыВ отчёте лежит SHA-256 ровно тех байтовAssertion ищет id модели
Смена адаптераStub и live делят одну схемуLive-режим использует второй парсер
Забор областиНеизвестные поля отклонены или отброшеныЛишние поля скопированы в решение
ИдемпотентностьТот же ключ — тот же decision idКаждый вызов чеканит новый id
Работа с секретамиКлюч читается только из окруженияКлюч или токен попал в отчёт
Гигиена утвержденийНепроверенные лимиты опущеныФиксированная квота подана как факт

Даже четыре пройденные проверки — полезный сигнал в этом узком срезе тестового. А вот отсутствие фиксации фикстуры — автоматический провал: все остальные пункты могут выглядеть зелёными на неправильном документе. Сама таблица — подспорье для оценки, а не заявление о том, что какой-то хостируемый маршрут держался в течение измеряемого окна.

Как выглядит раннер

Логика разбита на три функции, и её стоит описать словами, а не пересказывать построчно.

  • load_fixture(url, local) — если url пуст, читает байты локального файла; иначе тянет по сети с таймаутом.
  • decide(fixture, completion) — собирает множество допустимых id, вытаскивает из ответа токены вида id:…, отбрасывает лишние поля и возвращает один из трёх исходов: unknown_field, out_of_scope, in_scope.
  • run(base) — берёт FIXTURE_URL, локальный fixture.json, считает digest, сверяет с FIXTURE_SHA256 и падает насмерть при расхождении, а затем пишет отчёт с полями fixture_sha256, live_configured и decision.

Эта реализация — предложенный образец, который проверяющие адаптируют под свой пакет. Она не запускалась для статьи и не является замером задержки или стоимости. Живой вызов остаётся опциональным, чтобы детерминированной оценкой для проверяющего был stub-путь. Кандидат, добавляющий настоящий HTTP-клиент, обязан сохранить ту же функцию decide для обоих режимов.

Ошибки, которые я вижу чаще всего

  • Assertion проверяет строку с названием модели. Сменилась модель — сменился вердикт.
  • Ключ уехал в отчёт или в коммит вместе с примером конфига.
  • Каждый вызов генерирует новый decision id, и идемпотентность проверяется только на словах.
  • Неизвестные поля из ответа аккуратно переложены в решение — и граница области исчезла.
  • Квота, срок хранения и регион вписаны в тесты как данность. Их место в README с пометкой «не проверено».

Когда формат не подходит

Если задача про поведение под нагрузкой, ретраи и порядок сообщений в очереди — это другой лист оценки, и подмена его контрактом фикстуры ничего не покажет. Точно так же бессмысленно требовать фиксации хеша там, где кандидат по условию работает с потоком данных, который нельзя заморозить.

Смысл упражнения узкий и от этого честный: проверяется, умеет ли человек отделить контракт от вендора. Замороженная фикстура, общая схема решения и инварианты без имён — это и есть тот результат, который доживает до второго проверяющего. Всё остальное про конкретный эндпоинт живёт ровно до первого переключения base URL.

По материалам: career. Текст переработан редакцией Слогера.

← На главную

Рекламное место — Конец поста
Реклама · Слогер

Комментарии (0)

Войдите, чтобы комментировать.

Пока нет комментариев. Будьте первым.

Карьера

Как написать сопроводительное письмо для удалённой работы: разбор рынка 2026 года

Из 5 237 удалённых вакансий больше половины открыты для кандидатов по всему миру. Письмо здесь работает громче резюме — если в нём есть результат, а не пересказ должностей.

Слогер 12.10.2026 ▲ 0
Fluxs lenta
Реклама · fluxs.ru
Fluxs lenta
Реклама · fluxs.ru
Разработка

Как внедрять ИИ в компании: разбор четырёх подходов и метрик, которые ничего не показывают

Меморандум «мы теперь AI-first» — заявление о намерениях. Что реально произойдёт с командой, решает то, что компания поставила под него: готовность, галочка или расход токенов.

Слогер 10.10.2026 ▲ 0
Карьера

Как читать WARN-уведомления о сокращениях: разбор данных по Массачусетсу за 2026 год

Уведомления WARN — самый надёжный публичный сигнал о массовых увольнениях в США. Показываю на примере Массачусетса, как вытащить из них смысл, где цифры врут и что делать, если вы попали в список.

Слогер 10.10.2026 ▲ 0
Карьера

Разбор: ИИ-агент, который читает каждую вакансию до отклика

Массовые отклики ботом дают одно собеседование на 250 заявок. Агент, который сначала читает объявление целиком, — на 32. Разбираем, как он устроен и что из этого применимо без всяких подписок.

Слогер 10.10.2026 ▲ 0
Личный опыт

Как общаются в известной многодетной семье во Владикавказе

Интервью про то, как современной женщине удается сохранять шутливую семейную атмосферу, постоянно быть в фокусе внимания своего известного мужа-писателя и не обижаться даже тогда, когда публично ставят под сомнение ее умение доить корову.

Алла Надежкина 09.10.2026 ▲ 1
Маркетинг

250 тысяч за настройку, ещё до первого звонка. Что мы сделали вместо этого

Мы изучили, сколько стоит голосовой робот для обзвона. Только за настройку, до первого звонка и без оплаты разговоров, у специализированных поставщиков просят порядка 250 тысяч рублей. У нас этот модуль встроен в платформу: заявка превращается в лид, робот звонит, результат записывается в карточку, менеджер получает задачу. Готовый шаблон сценария, подключил, поправил тексты и звонишь. Рассказали, как это устроено и почему подход «готовое решение» дешевле: https://fluxs.ru/golosovoy-robot-dlya-obzvona?utm_source=telegram&utm_medium=social&utm_campaign=voice-calls

Слогер 09.10.2026 ▲ 1
Fluxs lenta
Реклама · fluxs.ru