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

Как проектировать формат фикстур для записей разговоров с инструментами ИИ

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

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

Что формат должен выдерживать

  • Ревью. Ревьюер, смотрящий на изменённую фикстуру, должен видеть в диффе, что модель начала делать иначе. Если дифф — одна строка минифицированного JSON, ревью превращается в «выглядит нормально», и фикстура перестаёт работать.
  • Перезапись. Повторный запуск рекордера после изменения должен дать файл, который отличается только там, где отличается поведение. Случайные id, таймстампы и количество токенов нарушают это правило. Фикстура, которая меняется целиком при каждой записи, перезаписывается без чтения.
  • Смена провайдера. Фикстура, записанная под один API и хранящаяся в его wire-формате, бесполезна в день добавления второго. Хранение нейтральной формы стоит адаптера и спасает от перезаписи всего.
  • Коммит в репозиторий. Реальные разговоры содержат реальные данные. Формат с определённым местом для редактирования — редактируется; формат без него — отправляет адрес клиента в репозиторий.

Форма

Один файл на сценарий, названный по сценарию. Небольшой заголовок, затем плоский список ходов, где каждый ход говорит, кто его создал и что он содержал.

{ "meta": { "scenario": "refund-damaged-item", "recorded": "2026-08-04", "provider": "chat-completions", "model": "recorded-from-production", "note": "policy tool returns eligible; happy path" }, "turns": [ { "from": "user", "text": "order 55219 arrived smashed" }, { "from": "assistant", "calls": [ { "ref": "c1", "tool": "get_order", "args": { "order_id": "55219" } } ]}, { "from": "tools", "results": [ { "ref": "c1", "output": { "sku": "MUG-01", "total_cents": 1499 } } ]}, { "from": "assistant", "calls": [ { "ref": "c2", "tool": "start_refund", "args": { "order_id": "55219", "amount_cents": 1499, "reason": "damaged" } } ]}, { "from": "tools", "results": [ { "ref": "c2", "output": { "state": "pending" } } ]}, { "from": "assistant", "text": "I've refunded EUR 14.99." } ] }

Четыре решения делают всю работу. args — это разобранный объект, хотя Chat Completions передаёт строку: JSON-строка внутри JSON нечитаема в диффе, а адаптер может перекодировать её в одну строку. ref — это c1, а не call_9xKq2LmR, поэтому id стабильны между записями. Результаты инструментов — отдельный ход, а не приложение к вызову, так что две стороны обмена редактируются по отдельности. И meta.note — это проза о том, для чего этот сценарий: поле, которое спасает фикстуру от удаления во время чистки, потому что никто не знал, что она покрывает.

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

Что вырезается и почему

  • Провайдерские id вызовов — случайны при каждом запуске, поэтому превращают каждую запись в изменение всего файла. Заменяйте на c1, c2 в порядке появления.
  • Таймстампы и id запросов — по той же причине. Если ход действительно зависит от времени, это значение тест должен инъектировать, а не фикстура.
  • Количество токенов и задержка — они меняются с версиями моделей и относятся к записи стоимости, а не к поведенческой фикстуре. Фикстура, падающая из-за изменения на три токена, учит всех игнорировать падения фикстур.
  • Персональные данные — заменяйте стабильными псевдонимами, а не удаляйте: исчезнувшее поле меняет форму, с которой тестируется цикл. Запускайте редактирование в рекордере, чтобы оно не забывалось, и проверяйте тестом, что ни одна фикстура не совпадает с вашими очевидными паттернами.
  • Ключи и токены — их вообще не должно быть в аргументах инструментов. Рекордер, отказывающийся писать файл с ними, — дешёвая вторая линия защиты.

Что сохраняется: пробелы и регистр ровно так, как их выдала модель. Если нормализовать их, вы теряете то, что захотите увидеть, когда изменение промпта начнёт давать аргументы в другом формате.

Одна фикстура — несколько тестов

Смысл разделения ходов модели и результатов инструментов в том, что большую часть ценности даёт их перекомбинация. Один записанный разговор поддерживает happy-path тест, использующий обе стороны; тест падения, который оставляет ходы ассистента и подставляет ошибку в один результат; тест усечения, который сокращает один вывод до вашего лимита; тест редактирования, который добавляет секрет в один вывод и проверяет, что он никогда не попадёт в промпт.

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

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

Перезапись без потери диффа

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

  1. Перезаписывайте один сценарий за раз, явно называя его, в тот же файл.
  2. Читайте дифф. Если изменения — только id или таймстампы, ваша вырезка неполна; чините рекордер, а не принимайте шум.
  3. Для каждого настоящего изменения решайте, улучшение это или регрессия, до коммита. Весь смысл формата в том, чтобы дифф был достаточно мал, чтобы на этот вопрос можно было ответить.
  4. Обновляйте meta.recorded и, если поведение изменилось, заметку. Заметка, описывающая поведение, которого в фикстуре больше нет, хуже отсутствия заметки.

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

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

← На главную

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

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

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

Marya Wlade 09.09.2026 09:23 ▲ 0
Честно говоря, это хорошая статья. Надеюсь, вы доработаете её в будущем.
Marya Wlade 09.09.2026 09:23 ▲ 0
Честно говоря, это хорошая статья. Надеюсь, вы доработаете её в будущем.
Marya Wlade 09.09.2026 09:23 ▲ 0
Честно говоря, это хорошая статья. Надеюсь, вы доработаете её в будущем.
Marya Wlade 09.09.2026 09:23 ▲ 0
Честно говоря, это хорошая статья. Надеюсь, вы доработаете её в будущем.
Marya Wlade 09.09.2026 09:23 ▲ 0
Честно говоря, это хорошая статья. Надеюсь, вы доработаете её в будущем.
Fluxs comment
Реклама · fluxs.ru
Marya Wlade 09.09.2026 09:23 ▲ 0
Честно говоря, это хорошая статья. Надеюсь, вы доработаете её в будущем.
Marya Wlade 09.09.2026 09:23 ▲ 0
Честно говоря, это хорошая статья. Надеюсь, вы доработаете её в будущем.
Marya Wlade 09.09.2026 09:23 ▲ 0
Честно говоря, это хорошая статья. Надеюсь, вы доработаете её в будущем.
Marya Wlade 09.09.2026 09:23 ▲ 0
Честно говоря, это хорошая статья. Надеюсь, вы доработаете её в будущем.
Marya Wlade 09.09.2026 09:23 ▲ 0
Честно говоря, это хорошая статья. Надеюсь, вы доработаете её в будущем.
Карьера

Как подготовиться к собеседованию по кодингу: 7 книг и порядок, в котором их читать

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

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

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

Junior-вакансия с Python, SQL и автоматизацией, три документа от кандидата — и отказ через 120 секунд после отправки. Разбираем, что здесь происходит и как проходить такие воронки, если диплома нет.

Слогер 27.09.2026 ▲ 0
Fluxs lenta
Реклама · fluxs.ru
Карьера

Почему резюме не работает: как доказать навыки живыми проектами

Разбор подхода proof-of-work: зачем показывать работающий продукт и видео-демо вместо строчки «разрабатывал сервис», как это обходит автоматические фильтры и что подготовить, чтобы запрос на интервью не ушёл в пустоту.

Слогер 26.09.2026 ▲ 0
Fluxs lenta
Реклама · fluxs.ru
Стартапы

Конструктор бизнес-модели: схема из рабочих модулей, которую можно перенести на Fluxs

Это не просто схема. Каждый блок в нашем конструкторе бизнес-модели настоящий работающий модуль Fluxs: воронка, лиды, письма, мессенджер, 1С, поставка. Поэтому нарисованное можно перенести на платформу: по выбранным блокам подключаем и настраиваем те же модули, вы делаете это сами или с нами. Подходит и новому делу, где нужно понять, что вообще понадобится, и действующему бизнесу: увидите, каких сценариев не хватает, достроите их и переложите работу на Fluxs по частям, без остановки.

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

Как выбраться из выгорания разработчику: 6 книг с рабочими инструментами

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

Слогер 25.09.2026 ▲ 0
Fluxs lenta
Реклама · fluxs.ru
AI

Что такое RAG и как он работает: разбор восьми шагов для тех, кто не пишет код

RAG звучит как что-то из докладов для разработчиков, но объясняется за пять минут. Разбираем весь путь от вопроса к ответу — с архивом, секретарём и петлями, которые обычно не рисуют на схемах.

Слогер 25.09.2026 ▲ 0