Нейросеть собрала загрузку заказов: синтаксис чистый, тесты зелёные, на маленьком файле всё работает. При повторном запуске она начала прибавлять к суммам заказов лишнее, а упавший файл выгрузки просто заменился пустым. Если такое попадает в отчётность без ревью — выручка растёт без продаж, а данные о клиентах теряются без ошибок в мониторинге.
Суть события
Автор разбора на Habr поставил вопрос ребром: если модель уже пишет Python-пайплайны, зачем инженеру данных разбираться в самом языке? Ответ оказался не про синтаксис — а про то, что синтаксически корректный код может делать не то, что нужно бизнесу, и при этом не падать. Контрольный пример — загрузка заказов из CSV: код читает файл, складывает суммы, отправляет данные в базу. На короткой выгрузке всё работает. На длинной — поведение уже зависит от того, как написаны детали, которые модель часто упускает.
Сам посыл материала мы переводим на человеческий язык так: умение читать сгенерированный код — это не про «быть умнее модели», а про умение заметить тихую ошибку до того, как она уедет в отчёт. Потому что у ИИ-агента нет штрафа за тихий сбой: задача в Airflow помечена как успешная, мониторинг зелёный, файл выгрузки вроде бы создан. Деньги — отдельно, данные — отдельно, бизнес — отдельно.
Детали
Первый класс проблем — память и коллекции. Агент охотно использует `list()` над `DictReader`, чтобы «получить все строки». На маленьком файле это незаметно. На большой выгрузке — это решение, которое нужно отдельно обосновывать, а не повторять по шаблону. То же самое касается `+=` против `=` в SQL-выражении `ON CONFLICT DO UPDATE`: `set amount = orders.amount + EXCLUDED.amount_kopecks` формально валиден, дублей в таблице нет, а итоговая сумма после каждого перезапуска растёт. Синтаксис правильный, бизнес-цифра — фальшивая.
Второй класс — обработка ошибок. Агент часто оборачивает вызов в `try/except`, пишет в лог и идёт дальше. Для одной задачи это может быть ок, для всей загрузки — катастрофа: мониторинг не сработал, данные потеряны, никто не узнал. Отдельная история — атомарность записи. Режим `»w»` обнуляет файл в момент открытия. Если после этого источник отдаст 40 строк из 100 и упадёт, прежней выгрузки уже не будет — останется пустой или неполный файл. Решение через временный файл и `os.replace` занимает у модели пять строк, но без него каждый сбой — это потеря данных, которую заметят только в момент, когда она уже задела клиента.
Третий класс — повторные запуски. Если таблица не защищена уникальным ключом, любой повторный запуск пайплайна добавляет записи заново. В рекомендациях Airflow это называют прямо: задачи должны корректно переживать повторный запуск через UPSERT или работу с фиксированным интервалом. Но «корректно переживать» — это требование к коду, а не к модели. Модель его знает, но не считает приоритетом, пока её явно не попросят.
Контекст
Сама тема уже вышла за пределы инженерного разговора. Мы раньше разбирали, что агент без человека-оператора — это уже не фантастика, а операционный риск: чем больше полномочий у цепочки, тем важнее граница, на которой её останавливают. Здесь тот же поворот, только в менее заметной точке: не CRM и не API, а загрузка CSV. И чем меньше команда, тем выше шанс, что ревью этой загрузки просто никто не делает.
Для малого бизнеса и фрилансеров это превращается в конкретный финансовый сценарий. Владелец сервиса просит модель собрать пайплайн, тот работает, цифры в дашборде растут. Через месяц выясняется, что «рост выручки» — это повторный запуск после обрыва соединения. Данные о клиентах частично потеряны, отчётность пересдавать, объяснять налоговой разницу между «прибавилось» и «продалось». Это не страшилка — это нормальная стоимость того, что тихий сбой никто не проверил.
Отдельно стоит цена «доверия к тестам». Если модель пишет реализацию и сама же пишет под неё проверку, она подтвердит только то, что код соответствует её же ожиданиям. Полезный тест отвечает на конкретный бизнес-вопрос: что останется на диске, если источник оборвался на первой строке? Сколько записей попало в базу после повторного запуска? Что увидит следующий потребитель, если выгрузка была неполной? Эти вопросы модели задавать нужно каждый раз.
Что дальше
Если вы полагаетесь на ИИ-агента при работе с финансовыми данными, разумно встроить в процесс три конкретных шага. Первый — попросить модель перед каждой записью в базу явно описать, что произойдёт при повторном запуске и при падении посередине. Если в ответе «не знаю» или «скорее всего нормально» — это уже красный флаг. Второй — разделить подготовку и публикацию файла: новая версия пишется во временный каталог, в боевой файл попадает через атомарную замену. Это занимает пять строк, но закрывает целый класс потерь. Третий — добавить тест не на «код работает», а на «данные сохранились»: проверить, что после сбоя старая выгрузка на месте и временный каталог убран.
Полезное упражнение для команды — взять небольшую загрузку из CSV в PostgreSQL и провести её через четыре сценария: обычные данные, дубликат заказа, обрыв посреди загрузки, повторный запуск. Перед каждым прогоном записать ожидаемый результат, запустить, сравнить. Если результат отличается от ожидания — баг не в модели, а в вашем процессе ревью. И хорошо бы обнаружить это до того, как бизнес спросит, почему вчерашняя выручка выросла после перезапуска DAG.