Как я ловлю галлюцинации LLM в коде: пайплайн проверок в CI
Habr ·

Месяца четыре назад мне на ревью пришел пулл‑реквест, в котором из цикла обновления частиц вызывалась функция FrameAllocator::TryReclaimTail(), с правильным префиксом, в нашем стиле именования и даже с комментарием над вызовом, где объяснялось, зачем хвост кадрового аллокатора надо подбирать именно здесь, и выглядело все это настолько по‑домашнему, что я пролистал дифф, поставил апрув и ушел обедать. На PC сборка прошла и тесты позеленели, потому что вызов сидел внутри старого профайлерного макроса, который на десктопе разворачивался в пустоту вместе со всем содержимым скобок, а через два дня ночной билд под консоль упал на линковке, и выяснилось, что такой функции в движке нет и никогда не было. Код, понятное дело, писался вместе с иишкой, и автор потом честно признался, что функцию он не искал, потому что «она выглядела так, будто ее лет восемь назад написал наш техлид», и в этой фразе, пожалуй, уместилась вся беда нейросетевого кода в старом проекте: стиль проекта модель схватывает за пару файлов, а вот что в проекте на самом деле есть, она помнит примерно так же, как я помню пароль от первой аськи. Ошибки, которые выглядят как ошибки, ловит компилятор, а выдуманный код, похожий на родной, спокойно проходит и мимо компилятора на одной из платформ, и мимо уставшего ревьювера, особенно если на дворе пятница и время обеда. Запрещать модели у нас никто не стал, потому что запрет сейчас работает примерно как запрет стековерфлоу году в две тысячи десятом, когда пользоваться им продолжают все, просто перестают в этом признаваться на ревью. Поэтому за полгода вокруг сборки наросла цепочка проверок, которая ловит большую часть того, что модель придумывает, и про которую меня с завидной регулярностью спрашивают в курилке после докладов, так что попробую рассказать, из чего она собрана и во что она нам обходится. Читать далее