﻿# Дифференциальные тесты API двух inference-движков

Дифференциальная проверка двух inference-движков: сравнение схем и terminal states, явный реестр различий и отделение качества текста от API.

Автор: Команда Retrivium
Обновлено: 2026-11-01
Канонический URL: https://retrivium.ai/ru/journal/provider-engine-differential-api-tests/
Language: ru

## Сформулировать общий контракт

Два движка могут объявлять совместимый endpoint и всё равно различаться по параметрам, значениям по умолчанию и дополнительным полям. Дифференциальный тест подаёт один fixture двум адаптерам и сравнивает только заранее выбранные свойства. Это не соревнование скорости и не доказательство одинакового качества модели. Перед запуском записывают пересечение поддерживаемых функций, версии интерфейсов и допустимые различия. Если одна сторона не умеет нужный режим, результатом становится неподдерживаемая возможность, а не случайное сравнение другого запроса. Особенно опасно незаметно удалить параметр только у одной стороны и затем объявить ответы эквивалентными по контракту.

## Зафиксировать envelope и ограничения

Базовые утверждения охватывают HTTP status, тип содержимого, обязательные JSON поля, идентификаторы и завершение последовательности. [OpenAPI 3.1.1](https://spec.openapis.org/oas/v3.1.1.html) помогает хранить версию схемы независимо от конкретного клиента. [Документация online serving vLLM](https://docs.vllm.ai/en/stable/serving/online_serving/) отдельно перечисляет поддерживаемые интерфейсы и ограничения; знакомое имя endpoint не означает поддержку каждого поля без исключений. Для второго движка требуется такой же версионированный паспорт. В тестовом отчёте сохраняют исходные ответы и результат нормализации. Без исходных данных нельзя понять, возникло ли расхождение на сервере или его создал слишком агрессивный адаптер тестовой системы.

## Нормализовать только объяснимые различия

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

## Разобрать расхождение генерации

Если envelope совпал, а текст отличается, следующим шагом проверяют модель, tokenizer, chat template, sampling и окружение исполнения. [Раздел воспроизводимости vLLM](https://docs.vllm.ai/en/stable/usage/reproducibility/) описывает ограничения повторяемости по версиям и оборудованию. Даже одинаковый seed не является универсальным обещанием побитового равенства между произвольными движками. Для tool calling проверяют структуру вызова и возможность разобрать аргументы, а не одинаковую пунктуацию пояснения. Для ограниченного вывода проверяют допустимый terminal state. Смысловое качество текста оценивают отдельным корпусом, чтобы протокольная проверка не смешивалась с субъективным выбором более удачной формулировки или случайной вариацией модели.

## Сохранить пригодный для решения артефакт

Итоговая матрица связывает fixture, версии обеих сторон, проверяемое свойство, результат и известное исключение. Небольшой ограниченный набор запускают до миграции; спорные случаи повторяют с сохранённым окружением и установленным пределом попыток. Дополняют контекст [сравнение SGLang и vLLM](/ru/journal/sglang-vs-vllm-serving/) и [vLLM и Ollama](/ru/journal/vllm-vs-ollama-serving/). Матрица позволяет принять конкретное решение о переносе клиентского сценария. Она не гарантирует совместимость с любой библиотекой, одинаковую токенизацию или производительность под нагрузкой. Такие утверждения требуют самостоятельных опытов, а список исключений должен оставаться видимым после успешной миграционной проверки.
