Почему зелёные тесты не гарантируют безопасность кода от LLM

Habr AI · оригинал

Материал подготовлен автоматизированной редакционной системой. Факты можно сверить по указанному первоисточнику.

Автор описывает инструмент confidence-scorer, который выявляет скрытые изменения поведения функций при правках нейросетей через дифференциальное тестирование. Система комбинирует детерминированные проверки с AI-ревью, чтобы блокировать опасные мержи даже при формально успешном проходе тестов.

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

Типичная проблема при интеграции кода, написанного LLM, заключается в том, что модель может «упростить» логику, нарушив неявные контракты. Линтеры молчат, тесты проходят, а ревьюер видит аккуратный дифф. Однако через неделю выясняется, что функция начала принимать недопустимые значения. В таких случаях автотесты часто написаны той же моделью, что и код, поэтому они подтверждают лишь то, что модель сделала задуманное, но не то, что код ведёт себя так же, как раньше.

Для решения этой задачи был разработан инструмент confidence-scorer. Его ядро — дифференциальное тестирование: система извлекает старую и новую версии каждой изменённой функции, запускает их на одних и тех же входах и ищет расхождения. Если поведение изменилось, инструмент генерирует конкретный контрпример и блокирует мерж. Это свойство «ведёт себя как раньше» универсально и не требует ручного написания сложных тестовых сценариев.

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

Важно отметить, что сгенерированный моделью код не исполняется напрямую. Вместо этого LLM возвращает JSON-спецификацию генератора входов из фиксированного набора типов. Это исключает риск выполнения вредоносного кода. Технические сбои, такие как ошибки импорта или таймауты, помечаются как error и не искажают итоговый скор, оставаясь видимыми в отчёте.

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

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

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