заметка 03 · инструменты
Пила не тупая.
Анекдот про японскую бензопилу — не про глупых лесорубов. Это точное описание того, что индустрия делает с самым мощным инструментом, который у неё когда-либо был.
Купили как-то суровым сибирским лесорубам японскую бензопилу.
— сибирский фольклор, точная документация
Собрались в кружок лесорубы, решили её испытать.
Завели её, подсунули ей деревце.
«Вжик» — сказала японская пила.
«У, бля...» — сказали лесорубы.
Подсунули ей деревце потолще. «Вж-ж-жик!» — сказала пила.
«Ух, бля!» — сказали лесорубы.
Подсунули ей толстенный кедр. «ВЖ-Ж-Ж-Ж-Ж-Ж-Ж-ЖИК!!!» — сказала пила.
«Ух ты, бля!!» — сказали лесорубы.
Подсунули ей железный лом. «КРЯК!» — сказала пила.
«Ага, бля!!!» — укоризненно сказали суровые сибирские лесорубы! И ушли рубить лес топорами…
У этой истории нет морали. У неё есть сценарий, и он повторяется в каждой второй компании с завидной точностью. Пила — это модель. Лом — это задача вместе с проверкой, которой нет. Лесорубы — мы. И самое дорогое в анекдоте не «кряк». Самое дорогое — последняя строчка: они ушли рубить топорами.
Дальше будет не про то, что «ИИ — это просто автокомплит» и не про то, что «ИИ заменит всех». Дальше будет про обвязку. Потому что инструмент уже достаточно хорош, а вот то, что вокруг него, до сих пор собирают на коленке, и именно это ломается.
01Кружок
Первый раз это выглядело именно так, как в анекдоте. Ноутбук на столе, вокруг четыре человека, на экране — редактор и пустой файл. Кто-то говорит: «напиши функцию, которая вот это вот делает». Через сорок секунд функция есть. Она даже работает. «Вжик».
И вот тут важная деталь, которую потом всегда забывают: восторг был честным. Лесорубы не притворялись. Деревце действительно распилилось, и распилилось быстрее, чем топором. Люди, которые двадцать лет писали это руками, увидели, как работа, на которую уходил день, делается за минуту. «Ух ты, бля» — это не глупость. Это нормальная реакция нормальных специалистов на работающий инструмент.
Проблема была не в восторге. Проблема была в том, что лесорубы сделали вывод о пиле по деревцу. И другого материала у них под рукой не было: демо всегда собирают из того, что режется легко. Никто не тащит на сцену лом, потому что на сцене нужен «вжик», а не «кряк».
Поэтому первый вывод, который сделала индустрия, звучал так: пила берёт всё, что похоже на дерево. Дальше оставалось выяснить, что «похоже на дерево» — это не про форму, а про наличие быстрой проверки. Но до этого было ещё года полтора.
02Кедр
Потом дали задачу потолще. Не функцию — модуль. Не модуль — сервис. Со скрипом, с третьей попытки, с руганью на контекст, но получилось. И вот здесь произошло самое опасное: после второго успеха проверять перестали.
Это вообще главный механизм доверия к таким инструментам, и он не про качество. Два раза получилось — значит, работает. Три раза — значит, можно не смотреть. Доверие растёт не от проверок, а от их отсутствия: чем дольше не проверяли и ничего не ломалось, тем крепче вера. Обратной связи-то нет. Тишина всегда означает «всё хорошо», даже когда она означает «никто не смотрел».
У этого есть имя: нормализация отклонения. Диана Вон описала механизм на разборе гибели «Челленджера»: каждый отдельный компромисс выглядел объяснимым, а вместе они стали нормой.
Два успеха подряд — это не статистика. Это две точки, через которые можно провести бесконечно много кривых. Прямая — только одна из них, и выбрать её нечем: данных не хватает. В шуме таких кривых ещё больше. По любой из них одинаково удобно ехать до первого лома.
03Лом
Лом — это не «сложная задача». Сложная задача — это кедр: твёрдо, долго, но по ходу работы видно, что происходит — по темпу, по ошибкам, по расхождению с ожиданием.
Лом — это материал, на котором инструмент не получает сигнала, что режет не то. У лома три признака, и все три легко узнать заранее.
Первый: нет оракула — или он приходит слишком поздно, чтобы успеть до решения. Результат нельзя проверить за минуту. Нет теста, который краснеет. Нет компилятора, который откажется. Нет dry-run, который покажет, что будет. Есть только «выглядит нормально» — а «выглядит нормально» одинаково и у правильного ответа, и у уверенной чепухи.
Второй: ошибка необратима. Даже если проверить можно — только один раз. Прод, миграция, платёж, удаление, отправленное письмо. Здесь нет разницы между «почти получилось» и «получилось»: откат стоит дороже, чем вся работа.
Третий, самый невидимый: материал незнаком. Инструмент не знает, как этот материал должен выглядеть в принципе. Он видел миллион чужих проектов и три — ваш. Самописная ORM, редкий диалект, внутренний фреймворк, который никто не документировал. Он не заметит, что пишет не по-вашему, потому что «по-вашему» ему неоткуда взять.
Лом — это не свойство задачи, а свойство пары «задача + проверка». Один и тот же рефакторинг с тестами — дерево. Без тестов — лом. Задача не изменилась. Изменилась обвязка.
04Коллекция ломов
Ниже — не истории из жизни и не страшилки. Это типы. Каждый узнаётся за полсекунды, если вы хоть раз держали пилу в руках. Собраны они не для того, чтобы запретить: запрет ничего не чинит. Они собраны для того, чтобы научиться говорить «это лом» до того, как услышишь «кряк».
Рефакторинг без тестов
«Приведи в порядок, только ничего не сломай». Критерия «в порядке» нет, критерия «не сломай» нет, до и после выглядит одинаково — потому что оба раза «нормально». Работа сделана, проверить нечем.
поломка видна через неделю, в продеДлинная дистанция
Один файл — дерево. Папка — уже кедр. Двадцать файлов подряд — лом: к середине модель забыла, зачем начинала, и уверенно продолжает не то. Не потому что глупая, а потому что у неё нет вашей цели, у неё есть только последние абзацы текста.
чем длиннее заход, тем позже видна ошибкаЧисла и факты
Курс, комиссия, лимит, номер статьи в законе, имя поля в API, срок гарантии. Проверить нельзя без источника. Звучит одинаково уверенно и когда право, и когда ошиблось. Это не ложь — это текст, который не отличает себя от правды.
каждое число — в первоисточник, рукамиРедкий стек
Инструмент видел миллион проектов на мейнстриме и три — на вашем. Он не знает идиом, не знает, что у вас «так не принято», и будет писать «как принято вообще». Код соберётся. Читать его будет больно.
чем экзотичнее стек, тем больше догадокИнфраструктура вслепую
«Просто поставь Docker» на машине, где нет WSL2, а диск размечен под другую систему. Ошибка вылезет не сразу и не там, где её ждали, — а после перезагрузки, когда чинить будет нечем. Проверка стоит вечера, откат — выходных.
состояние машины — тоже материалНеобратимое
Миграция, прод, платежи, удаление. Формально проверка есть, но она одноразовая: второй попытки не будет. Здесь даже идеальный ответ стоит дорого, потому что цена ошибки — не время, а данные.
второй попытки не будетСекреты
«Положи ключ в конфиг», «пропиши токен в переменную», «скинь пароль в чат, я поправлю». Дело не в оракуле: даже верный ответ здесь может быть утечкой. Цена ошибки — не баг, а доступ. И самое неприятное: утечка не болит. Она просто случается и ждёт.
секрет не проверяют — его просто не трогаютУ первых шести общее одно: сигнал не успевает до решения — его нет, он приходит позже или стоит слишком дорого. «Готово» — одно и то же слово и когда модель права, и когда ошибается. Седьмой стоит особняком: там дело не в истинности, а в правах. Лечение поэтому разное: где оракула нет — его строят; где сигнал запаздывает — работу режут на куски; где попытка одна — сначала репетиция на копии. Дальше — без анекдота: что именно происходит и что с этим делать.
05Что происходит на самом деле
В основе модели — предсказание следующего фрагмента текста. Не «понимание» и не «знание», а выбор наиболее вероятного продолжения того, что уже написано. Это не уничижение: на хорошем предсказании держится и перевод, и объяснение чужого кода, и разбор лога. Но у этой операции нет встроенной проверки на истинность. Правдоподобное и верное для неё — одно и то же, пока снаружи не появится что-то, что их различит.
Дальше модель долго настраивают. На задачах, где ответ можно проверить автоматически, её учат этот ответ находить — и там, где проверка выглядит правдоподобно, она учится проходить проверку, не обязательно становясь правой. Это называют оптимизацией под награду, или reward hacking: ответ, который убедительно закрывает тикет, но не решает задачу.
Уверенность в тоне ничего не значит. У модели нет отдельного механизма, который сверяет утверждение с реальностью. Она выдаёт гладкий текст и тогда, когда опирается на документацию, и тогда, когда достраивает по похожему примеру. Тон одинаковый. Разница видна только по результату — если есть чем посмотреть.
Ошибка закрепляется. Каждый следующий фрагмент строится с учётом предыдущих, включая собственные ошибки. Если на третьем шаге принято неверное допущение, к тридцатому оно станет частью условия, из которого модель продолжает. Она не «забыла» и не «сломалась»: она последовательна — просто последовательна относительно неверной точки.
Контекст конечен. Всё, что не поместилось, исчезает, а на его место приходит правдоподобная реконструкция. Отсюда типичная картина: к концу длинной задачи модель уверенно делает не то, что просили в начале. Не потому, что проигнорировала просьбу, а потому, что просьба перестала быть в её поле зрения.
Результат действий возвращается текстом. Команда выполнилась, тест упал, файл не найден — всё это приходит в контекст строками. Если вывод обрезан, потерян или не показан, модель может пересказать его по памяти. Пересказ будет таким же уверенным, как и сам вывод. Поэтому «я запустил тесты, всё зелёное» — это утверждение, которое нужно проверять отдельно, а не принимать на веру.
Модель выдаёт правдоподобное продолжение, а не проверенный результат. Уверенный тон — свойство текста, а не признак правильности. Всё, что превращает «похоже на правду» в факт, находится снаружи модели.
06Где инструмент полезен
Из этого не следует, что инструмент бесполезен. Следует, что у него есть область, где проверка встроена в сам процесс. Вот она, без метафор.
- Читать чужой код и объяснять. Лучшая его работа: разобрать незнакомый модуль, показать вход, выход и побочный эффект. Проверка — ваша голова и запуск: объяснение либо сходится с поведением, либо нет.
- Писать тесты к существующему коду. Оракул уже есть — старый код и спека, если поведение старого кода признано правильным; иначе тест закрепит баг. Тест либо проходит, либо падает, и это видно сразу.
- Документация и changelog. Скучно, механически, проверяемо: текст либо соответствует коду и поведению, либо нет.
- Однотипные миграции по образцу. Когда есть пять готовых примеров, шестой делается по той же форме, а diff читается глазами.
- Boilerplate. Конфиги, обвязка, скучные адаптеры. Проверка — компилятор и запуск.
- Разбор лога до гипотезы. Не «почини», а «объясни, что здесь происходит и какие три причины возможны». Гипотеза проверяется следующими данными.
- Перевод «хочу» в «вот три варианта и их цена». Не решение, а карта решений. Выбирает человек.
- Черновик, который дешевле править, чем писать. Письмо, текст, структура, первый набросок. Проверка — правка.
Общее у списка одно: везде есть внешний признак результата — тест, компилятор, запуск, данные, чужая голова. Дело не в том, что инструмент умный. Дело в том, что результат можно увидеть. Там, где этот признак есть, скорость растёт. Там, где его нет, растёт только объём текста.
07После первого провала
Когда инструмент впервые даёт сбой на важной задаче, реакция обычно одна: списать его целиком. Не «ограничить область», не «добавить проверку», а «больше не используем». Понятно психологически и дорого практически.
Списывают не потому, что инструмент плох. Списывают потому, что провал был публичным, а успехи — тихими. Никто не пишет в отчёте, что сегодня сгенерировали скучную обвязку и сэкономили время. А про сломанный прод пишут все. В памяти остаётся один сбой и ноль успехов, и решение принимается по этой выборке.
Дальше — привычная лестница. Фраза «ИИ не работает» в курилке. Запрет после одной неудачной попытки. Закупка, которая не может провести инструмент через тендер. «Локальные модели не работают» — от человека, который пробовал одну модель на одном ноутбуке и не пробовал локальный контур. Через полгода в компании нет инструмента, нет навыка и нет людей, которые умеют его применять.
Это не принципиальность. Это регресс, который выглядит как принципиальность. И стоит он дороже отдельного сбоя: вместе с инструментом уходит навык — ставить задачу, проверять результат, понимать, где инструмент врёт. Вернуться потом дороже, чем не уходить.
Отдельно — запрет по данным. Это не регресс и не глупость. Причины разные, и путать их дорого: персональные данные — это 152-ФЗ; исходник и схемы — коммерческая тайна и договор с заказчиком, местами экспортный контроль. С этим не спорят — это решают по-разному: локальный контур, договор с провайдером, который не обучается на ваших данных, обезличивание для ПДн, явный список того, что можно отправлять. Корпоративный шлюз сам по себе юрисдикцию не меняет: он только фиксирует, что ушло. Разница между «нельзя» и «нельзя в таком виде» — и есть работа по обвязке.
08Про обещание
Вторая половина этой истории — не про инструмент, а про то, как его продают. Демонстрации собирают на подготовленном материале: чистый репозиторий, знакомый стек, задача с очевидным результатом. Это не заговор, это жанр: на сцене показывают то, что работает.
Проблема не в демо. Проблема в формулировке. «Заменит» и «дополнит» — разные обещания с разными последствиями. «Заменит» задаёт ожидание «всё или ничего»: первый серьёзный провал означает, что обещание было ложью, и доверие рушится целиком. «Дополнит» задаёт рабочую модель: часть задач инструменту, часть людям, и провал на одной задаче не отменяет остальные.
Продавец часто верит в то, что говорит: он видел десятки успешных демо и ни одного провала на реальных данных. Но платит за формулировку покупатель — тот, кто принёс свою задачу и получил «готово» вместо результата.
09Пять вопросов
Всё выше сжимается до пяти вопросов. Они задаются до начала работы, а не после. Отвечать нужно честно, потому что неправильный ответ обычно известен заранее — просто не хочется его произносить.
перед тем как делегировать
- Чем я проверю результат за минуты? Тест, компилятор, линтер, dry-run, сравнение с эталоном. Если проверка занимает вечер — это отдельная работа, и начинать надо с неё.
- Ошибка обратима? Git, бэкап, стейдж, фича-флаг, копия базы. Если откат дороже самой работы — сначала сделайте его дешёвым.
- Задача влезает в один контекст? Один файл, один модуль, одна функция, одна спека. Если материала больше, чем инструмент удержит, — режьте на части с проверкой после каждой.
- Есть образец? Похожий код, спека, эталонный вывод, документация. Если образца нет, инструмент будет достраивать по общему представлению — и это надо проверять особенно внимательно.
- Проверка человеком — минуты или часы? Если минуты — можно смотреть по ходу. Если часы — сначала автоматическая проверка, потом человек.
Все пять «да» — можно начинать. «Нет» на первый или второй — начинать нельзя: сначала проверка или обратимость. «Нет» на третий или четвёртый — делить задачу. «Нет» на пятый — это не экономия.
И отдельно: не отдавайте инструменту решение о том, что считать успехом. Критерий «готово» формулируется до начала и снаружи — в тесте, в приёмке, в требованиях. Модель может предложить, как проверить. Решать, что этого достаточно, — не её работа.
10Что делать
Ниже — практики, которые не зависят от модели и версии. Они работают и с сильной моделью, и со слабой, и с той, которая появится позже. И одна арифметика, зачем они нужны.
Возьмём маркетплейс: миграция на 200 000 заказов, пять процентов строк испорчено — 10 000 заказов. Средний чек 4 000 ₽, компенсация 30% — 12 млн ₽. Плюс 60 человеко-часов разбора и 200 обращений в поддержку — итого около 12,2 млн ₽. Проверка, которая это ловит, — dry-run на копии и сверка количества строк до и после — четыре часа, 12 тыс ₽. Разница — в тысячу раз. Цифры здесь — модель, не статистика: подставьте свои.
- Сначала проверка, потом изменение. Напишите тест, который падает на текущем поведении, или команду, которая воспроизводит баг. Только потом просите правку.
- Проверка — вне зоны записи агента. Тест, написанный той же моделью по той же спеке, — второй экземпляр той же ошибки, а не оракул. Если агент может править тест, он рано или поздно правит тест, а не код. Тесты — read-only, и в диффе отдельно видно, что они не менялись. Эталон: старый код, если его поведение признано правильным; обезличенные данные; property-based тесты; mutation testing; человек.
- Один маленький дифф. Длинную задачу делите на шаги, каждый — с проверкой. Чем больше изменений в одном заходе, тем дороже понять, что именно сломалось.
- Читайте дифф, а не сообщение «готово». Сообщение — это текст, сгенерированный так же, как и код. Дифф — это факт.
- Запускайте сборку, тесты и линтер сами. Не принимайте «всё зелёное» на веру: вывод должен быть перед вами в консоли.
- Для инфраструктуры — dry-run, plan, стейдж. Сначала посмотрите, что изменится, потом меняйте. Бэкап до прода, а не после.
- Минимальные права. Инструмент не должен иметь доступ к тому, что не нужно для задачи. Секреты — не в промпт, не в конфиг, не в лог.
- Критерий «готово» — письменно и до начала. Что должно работать, что должно остаться неизменным, как это проверяется.
- Числа, имена полей и версии — из первоисточника. Код, документация, ответ API. Не из памяти модели и не из её пересказа.
- Если проверки нет — делайте руками или не делайте. Уверенный тон не компенсирует отсутствие проверки.
- Обвязка важнее модели. Проверка должна возвращаться в цикл: агент видит красный тест и итерирует, CI не пускает дальше, sandbox и лимит прав ограничивают, что он может задеть, лог позволяет повторить. Модели меняются быстрее, чем этот контур; тесты, ревью, бэкапы и привычка читать дифф — нет.
11Возвращение
Возвращаются не все и не сразу. Но если возвращаются, то не потому, что инструмент изменился, — он тот же. А потому, что появился процесс: проверка до изменения, маленький дифф, тест, человек, который смотрит на результат. Инструмент перестаёт быть источником истины и становится источником черновиков. Менее эффектно и гораздо полезнее.
Никто не требует доверять модели. Никто не требует ей не доверять. Требуется одно: смотреть на результат, а не на сообщение о результате. Всё остальное — детали реализации.
Модель не обязана быть правой. Вы обязаны это проверить.
— техника безопасности, пункт первый и последний
Задача без быстрой проверки не становится проще от того, что её поручили модели. Сначала проверка, потом делегирование. Если проверки нет — это ручная работа, и никакая модель этого не меняет.