
Полная версия
Золотая лихорадка ИИ-агентов. Делегирование неопределённости
Принять результат не получается ни за час, ни за день: сверять его не с чем. Мешает не объём. Рядом с diff нечего положить, кроме вечернего «нормально», а оно не говорит ни «да», ни «нет».
И день идёт. Полоса солнца сползает со стола, и к полудню в комнате стоит ровный свет без теней. Встречу, назначенную на три, основатель переносит на завтра письмом в две строки. Шея затекает, от белого фона режет глаза, а он уже в третий раз открывает конечный автомат и читает его снизу вверх, будто в обратном порядке тот скажет что-то другое. Приходит письмо от клиента, который вчера спрашивал, когда появятся подписки: ну что, уже? Основатель пишет в ответ «готово» и стирает. Пишет «почти» и стирает тоже. Письмо остаётся без ответа.
После обеда он выходит пройтись вокруг дома, чтобы проветрить голову, и скоро возвращается: на улице думается о том же самом, только без экрана перед глазами. На краю стола листок, и к этому часу на нём полстраницы вопросов, которые начинаются одинаково: почему семь дней, почему поровну для всех, почему паузы нет. На каждый у него находится только встречный — а как надо? — и на встречный ответа нет тоже. Телефон с утра лежит экраном вниз: панель в нём больше ничего не покажет. Берёт он его только раз, когда звонит знакомый, вчера присвистнувший над списком коммитов, и спрашивает, чем кончилось. «Кончилось», — отвечает основатель и не находит, что прибавить. Кнопка, которой изменения принимают в основную ветку, весь день ждёт в углу экрана; нажать её — одно движение пальца. Он её не нажимает. В сумерках он зажигает настольную лампу, и там, где утром лежала полоса солнца, теперь жёлтый круг, а в нём листок с вопросами. К вечеру этот код он знает почти так же хорошо, как свой, и всё так же не может сказать ни «да», ни «нет».
Такие дни мы просиживали и над своими diff — с тем же ползунком, сжатым в чёрточку, с тем же третьим прочтением одного файла, с тем же письмом, которое никак не отправить. И так же, как он, мы не смогли бы объяснить постороннему, что нас держит: всё ведь работает.
Ближе к ночи меняется то, как он смотрит на экран. Утром перед ним была чужая работа, которую нужно проверить. Теперь он видит в ней свой завтрашний день. Если нажать кнопку, то однажды первого числа, когда у того, кто платит третий год, не пройдёт карта, продукт даст ему семь дней — ровно столько же, сколько вчерашнему новичку. Клиент напишет не ИИ-агенту, а основателю, и объяснять, почему семь дней, а не месяц, и почему поровну для всех, придётся ему, как объясняют своё. Когда позвонят с жалобой на отказ четвёртому сотруднику, основатель скажет «так у нас устроено» — о правиле, которое сам узнал сегодня утром. Письмо с вопросом «ну что, уже?» всё ещё открыто в соседнем окне. Ответить на него «готово» — значит поставить свою подпись под всеми двумястами четырнадцатью файлами. Каждая строчка на этом экране станет обещанием, которое его продукт даёт людям, и отвечать за каждое будет он.
Человек держит в руках решения, которых не принимал.
1.4. Над чем он работал
Ответ на вопрос, над чем тридцать один час работал ИИ-агент, кажется очевидным, и ещё вчера его, не задумываясь, дал бы кто угодно: над биллингом. Так было сказано в первых же словах задачи, об этом говорили строки коммитов — подписка, тариф, счёт, продление, — и в двухстах четырнадцати файлах нет ни одного, который не касался бы денег клиентов или того, кого куда пускать. Но вечерняя фраза состояла из двух половин. Первая, «переведи биллинг на подписки», называла, что сделать. Вторая, «сделай нормально», стояла на месте трёх ответов, которых у основателя не было, и в ночь она ушла пустой. Места в этой пустоте хватало на деньги всех его клиентов и на всё, что продукт им обещает. Снаружи её не было видно: фраза выглядела законченной, как письмо с подписью.
В коде такое место пустым остаться не может. Там нельзя написать «нормально»: где у клиента не прошла карта, должно стоять число дней, а где на тариф для троих приглашают четвёртого — момент, когда ему откажут. ИИ-агент не решал задачу про биллинг — он заполнял пустоту, оставленную вечерней фразой, правдоподобным содержимым. У пустоты была форма, форма трёх вопросов, и содержимое повторяет её в точности. Где вечером прятался вопрос о состояниях подписки, утром лежит новый каталог с конечным автоматом; где прятался вопрос о неудачном списании — семь дней и письмо; а на месте вопроса о границе биллинга и авторизации — готовая граница, проведённая правками в модуле авторизации.
Если смотреть на ночь отсюда, от вечерней фразы, каждый шаг на панели — открыл файл, поправил несколько строк, запустил тесты — укладывал в пустую половину фразы ещё немного, и к рассвету третьего дня места там не осталось. Пустота вернулась к основателю заполненной, и весь день он смотрел как раз на неё: туда, где должны были стоять его ответы, а стояли чужие.
Тридцать один час ушёл не на написание кода, а на выбор того, что должен был выбрать человек. Семь дней для того, у кого не прошла карта, и семь для всех поровну — для клиента третьего года и для вчерашнего новичка. Отказ четвёртому сотруднику в ту же секунду, когда нажата кнопка. Лето без паузы, и этот выбор не занял в diff ни одной строки. Закрытая подписка, при которой в свою работу можно смотреть, но ничего в ней нельзя тронуть. Каждый из этих выборов мог быть иным: четырнадцать дней или месяц, больше терпения тому, кто платит давно, отказ в день счёта, пауза до осени. Ни один не следовал из слова «нормально», ни один не был ошибкой, и каждый касался людей, которых основатель помнит по именам.
Чтобы код появился, кто-то должен был выбрать. Выбирал ИИ-агент, и опереться ему было не на что, кроме тех же шести слов. Выбирал на третьем часу и на двадцатом, пока основатель спал, звонил, ехал на другой конец города. Вечером за одним вопросом тянулись два других; ночью за одним выбором тянулись следующие. Раз в конечном автомате появилось состояние «закрыта», модулю авторизации понадобилось знать, что в этом состоянии можно, а чего нельзя, а тестам — чего ждать от модуля.
Ни в diff, ни на панели выбор ничем не выделялся. В diff семь дней — одна цифра в одной строке, и выглядит эта строка так же, как тысячи соседних, где переименована переменная или поправлен отступ. В записке, которой закончился прогон, семь дней числятся среди сделанного, в одном ряду с тем, где что лежит и как это проверить. Основатель думал, что панель, в отличие от почты, приносит только сделанную работу. Выбор она приносила в том же виде: короткой строкой коммита с зелёной галочкой справа. Рядом со словами его продукта в этих строках были только слова работы: добавлено, исправлено, перенесено, обновлено. Слова «выбрано» не было ни в одной.
Может быть, семь дней клиенту третьего года были отпущены как раз в ту минуту, когда основатель говорил в трубку «Уже делается», и коммит, на котором он вчера в сумерках задержался с улыбкой, был именно этим. Может быть, нет: по строке в списке этого не узнать. Тогда же, проходя список снизу вверх, он находил напротив каждого своего часа работу, которой не делал, и радовался. Список с тех пор не изменился. Напротив каждого его часа стоит выбор, которого он не делал.
Ночное восхищение от этого не становится ошибкой. ИИ-агент работал всерьёз, внимательно, не прерываясь ни на минуту, и что-то большое и правда происходило. Не была ошибкой и утренняя растерянность. Легко принять их за реакции на две разные вещи — на силу в телефоне и на чужой код в diff. Но вещь была одна, и её увидели дважды. Список коммитов, уходивший ночью за нижний край экрана, и ползунок, сжатый утром в короткую чёрточку, показывают одну и ту же длину. Телефон, который основатель две ночи не выпускал из рук, почти весь день пролежал экраном вниз, хотя в нём всё тот же список. То большое, что тридцать один час подтверждала панель, и есть решения, которых человек не принимал. Ночью панель показывала их размер, утром diff показал их содержимое.
В первую ночь ему казалось, что в его сутках стало больше часов, чем у всех остальных людей, и лишние часы работают на него. Лишние часы были. Уходили они на то, чтобы выбрать за него. Номер итерации, разряд, прибавившийся в счётчике токенов к четвёртому часу, зелёная полоса от первой строки до последней — всё это мерило одно: сколько пришлось выбрать там, где вечером осталась пустая половина фразы. Он владел силой, не знавшей ни усталости, ни сна, держал её в руке вместе с телефоном, и сила эта была настоящей. Сила, которой любовались ночью, оказывается мерой того, чего владелец задачи не знал.
Мы так же любовались и так же сидели — и долго не складывали одно с другим. Ночь помнилась отдельно, утро отдельно, как два разных случая из жизни ремесла: в одном мы гордились инструментом, в другом часами разбирали чужой код и винили в усталости объём. В наших телефонах всё ещё лежат снимки экрана с самыми длинными списками коммитов, те, что мы когда-то отправляли друзьям. На снимках ничего не изменилось: те же строки, та же сплошная зелёная полоса. Только теперь в каждой строке проступает ещё и то, чего мы тогда не решили, и отделить одно от другого уже не получается. Фраза «Он у меня работает вторые сутки» и сейчас верна, просто в ней слышно, чем он был занят. Гордость не прошла. Рядом с ней встало неудобство, и оно не проходит тоже.
Листок под лампой к ночи исписан почти до конца, и все вопросы на нём обращены к diff: почему семь дней, почему поровну, почему нет паузы. Новых среди них нет. Это вопросы из слова «нормально», только теперь у каждого есть чужой ответ. Одного вопроса там нет: почему в тот вечер шесть слов, за которыми не было ни одного ответа, легли так легко, что основатель опустил крышку ноутбука с приятным чувством, что работа пошла, и почему тридцать один час чужого выбора он носил в кармане как собственную силу и показывал за обедом знакомому. В diff об этом нет ни строки, а ему самому такой вопрос в голову не приходит. Незнание остаётся при нём таким же, каким было за кухонным столом, — без имени и без причины.
Позавчера у него не было ответа ни на один из трёх вопросов, и он этого не видел. Сегодня ответы лежат перед ним — двести четырнадцать файлов ответов, — и ни одного из них он не давал. Этого человека не существует, он собран из многих вечеров, и наших тоже. Число его ночи от этого не становится выдуманным. Его по-прежнему не округлить.
Тридцать один час — это не время работы ИИ-агента. Это размер того, чего вы не знали.
Глава 2. Длительность как признание
2.1. Словарь самообмана
«Мощь ИИ». «Он исследует». «Задача сложная». «ИИ-агент ищет оптимальное решение». «Посмотрим, что он придумает».
Эти фразы мы слышали много раз и много раз говорили сами. Их пишут под снимком панели прогона, когда счётчик токенов переваливает за очередной порог. Их произносят в разгар прогона, объясняя коллеге, почему ветка ещё не готова. Их говорят себе вечером, отправляя задачу, и среди ночи, когда встают посмотреть, как там идёт. Одну — с гордостью, другую — устало, третью — с любопытством, как о посылке, которую вот-вот принесут. Но ни одна из них не звучит как оправдание. Каждая звучит как хорошая новость. Глупости в них нет: так говорят люди, которые хорошо знают своё дело, и мы среди них. Нередко фразы идут и вместе, одной связной речью: «Задача сложная, он исследует, ищет оптимальное решение — вот она, мощь ИИ. Посмотрим, что он придумает». Каждая подпирает соседнюю, и вместе они убеждают.
Поэтому попробуем выслушать каждую по отдельности — без спора и без усмешки — и задать ей один вопрос: о чём ты на самом деле? Под каждой лежит не оценка и не настроение, а вполне конкретное незнание: несделанный выбор, неназначенный критерий, непонятая система. Его можно показать пальцем — вопросом, на который вечером никто не ответил.
Когда прогон идёт долго, его хочется назвать мощью или исследованием, и оба слова превращают саму длительность в достоинство: одно — в силу инструмента, другое — в работу познания. «Мощь ИИ» рождается у панели. Итерации сменяют друг друга, коммиты идут, счётчик токенов растёт, и к исходу суток ощущение, что владеешь силой, становится почти телесным. В нём нет ничего постыдного, и слово приходит само. Но что оно измеряет? В технике мощность — это работа, делённая на время: сильный двигатель делает то же дело быстрее слабого. Ночью мы восхищаемся мощью как раз за то, что дело длится долго. Это первая странность. Вторая в том, что работу считают от результата, а панель знает только расход: шаги, токены, коммиты. Она при этом не лжёт: всё это действительно было. Сколько сделано от целого и сколько осталось, она показать не может: и то и другое считается от финиша, а финиш никто не назначил. Что должно быть правдой в конце, чтобы мы сказали «готово»? Какой сценарий обязан пройти от начала до конца, от формы заказа до письма с подтверждением? Что у нынешних клиентов должно работать так же, как вчера? Какое число в отчёте должно сдвинуться и насколько? Пока ответа нет, мерить результат нечем, и мы меряем то, что меряется. Большой расход и получает имя мощи. Под этим словом лежит неназначенный критерий. По такой мере самой мощной была бы ночь, которая не кончается никогда.
«Он исследует» звучит, пока прогон ещё идёт и надо объяснить, что происходит: ветку пока не трогаем, он исследует. Слово взято из хорошего словаря — из лабораторий и экспедиций, где у работы всегда есть вопрос: его записывают одной строкой до начала, и по нему потом видно, что работа кончилась. Какой вопрос здесь? Где та строка, которую записали, отдавая задачу? Что мы будем знать завтра, чего не знаем сегодня? Честный ответ обычно неловок. Мы не знаем, кто, кроме модуля заказов, читает таблицу с адресами доставки. Не знаем, какой из двух похожих обработчиков уведомлений ещё вызывается, а какой остался от прошлой переделки. Не знаем, что сломается в ночном отчёте, если поменять формат даты. А раз строки нет, нет и признака, что работа кончилась: исследовать можно сколько угодно. Самое странное в этой фразе — её предмет. Это не дальний материк и не новое вещество, а наш собственный репозиторий, в котором мы работаем каждый день. Знания о своём же коде у нас нет, и слово «исследует» превращает непонятую систему в его занятие.
Обе фразы — похвала ИИ-агенту: одна хвалит его силу, другая — его любознательность. О задаче ни одна как будто ничего не сообщает. Но сведения о задаче в них есть, только записаны наоборот: вместо «нам нечем мерить» — мощь, вместо «мы не понимаем» — исследование.
Третья и четвёртая фразы ничего не хвалят. Они объясняют длительность и звучат трезвее, как инженерная оценка, поэтому им верят охотнее. «Задача сложная» переносит незнание на саму задачу и говорится так, будто сложность — свойство вроде веса: одна задача весит килограмм, другая центнер, и ничего с этим не поделать. Что именно в ней сложно? Чаще всего за этим словом стоят не трудные строки кода, а вопросы, на которые можно ответить по-разному. Можно ли менять структуру таблицы заказов, или прежние записи должны читаться как раньше? Должны ли старые версии мобильного приложения по-прежнему понимать ответы сервера? Где граница, за которую ИИ-агенту заходить нельзя, и что внутри неё разрешено ломать? На каждый вопрос есть два-три разумных ответа, и каждый ведёт к своему коду. Пока ни один не выбран, в задаче спрятана не одна задача, а несколько, наложенных друг на друга, и она действительно выглядит тяжёлой. Проверить это легко: стоит ответить на эти три вопроса, и задача на глазах становится проще, хотя в ней не изменилось ни строчки кода. Сложность, которую мы ей приписываем, — это число невыбранных ответов.
«ИИ-агент ищет оптимальное решение» переносит незнание на занятие ИИ-агента и звучит почти научно. Фраза обещает, что где-то уже есть лучший вариант и его осталось найти. «Оптимальное» — слово из математики, а в математике оно не стоит одно: оптимальное всегда оптимально по чему-то. По скорости, с которой пользователь проходит оформление? По числу изменённых файлов? По тому, насколько легко будет прочесть этот код через полгода? По стоимости серверов? Каждый признак даёт своё решение, и лучшее по одному нередко оказывается худшим по другому. Даже вопрос о шагах — с чего начать, что переписать целиком, что поправить точечно, в каком порядке выкатывать — не имеет ответа, пока не сказано, что значит «лучше»: кто бережёт время, начнёт с одного, кто бережёт читаемость — с другого. По какому признаку сравнивать, не сказал никто, и вся фраза значит только одно: ищет долго. Под ней — неназначенный критерий.
Пятая фраза отличается от остальных. В «посмотрим, что он придумает» нет ни силы, ни сложности, ни строгости. В ней впервые появляемся мы сами — и появляемся зрителями. «Посмотрим» говорят в зале кинотеатра, на трибуне, у окна перед грозой. А эту фразу чаще всего говорят последней, когда задача уже отправлена и остаётся только уйти. В ней заложена вся ночь. Её обычно произносят с лёгкой улыбкой, будто говорящий сам слышит, что сказал. Она почти прозрачна. Это не стиль постановки, а признание, и из пяти фраз только в этой его слышно без перевода. В остальных четырёх оно тоже есть, но его приходится доставать вопросами.
Если поставить пять фраз рядом, видно, что это не случайные оговорки, а то, как устроен язык. В четырёх из них нет того, кто отдал задачу: подлежащее в них — мощь, он, задача, ИИ-агент. В пятой говорящий есть, но только как тот, кто ждёт. Ни одна не говорит «я не выбрал», «я не понимаю», «я не сказал, что считать готовым», хотя любая из этих коротких фраз была бы точнее всех пяти. Каждая берёт пустое место и делает из него достоинство: невыбранное становится сложностью, непонятое — исследованием, неназначенное — мощью и оптимальностью, ожидание — интригой. И в каждой остаётся приоткрытая дверь: вдруг он найдёт, вдруг придумает.
Общее у них и время. Мощь и сложность стоят в настоящем, как свойства, которые были всегда: задача будто родилась сложной, а не стала такой, когда вопросы о ней остались без ответа. «Исследует» и «ищет» — тоже в настоящем, но как процесс, которому не видно конца. «Посмотрим» — в будущем. Прошедшего времени нет ни в одной. Ни одна из пяти фраз не говорит о вечере, когда задачу отдавали, хотя всё, что они закрывают, должно было решиться именно тогда.
Расскажем ту же ночь без этих фраз. Вечером мы не сказали, что будет считаться готовым. Не решили, что можно ломать. Не знаем, кто ещё читает нашу таблицу. Не назвали, что значит «лучше». Посмотрим. Ни одно слово здесь не ложно, и ни одно не противоречит пяти фразам. Ночь та же, и часы на панели те же, изменились только слова: хорошая новость превратилась в перечень несделанного. Язык, которым мы говорим о долгих прогонах, устроен так, чтобы незнание звучало как возможность.
Такие фразы — маски: привычные слова, которыми незнание выдаётся за возможность. Лгать маске для этого не нужно, достаточно закрыть то, что под ней. Произносим мы её вслух, для других, но прячем незнание прежде всего от самих себя: первым эти слова слышит тот, кто их говорит. Изнутри это выглядит буднично. Мы садимся дописать к задаче, что будет считаться готовым, начинаем фразу и упираемся в вопрос, что делать с заказами, оформленными по старым правилам. Ответа нет, и в голове сама собой звучит: задача сложная. Вопрос не решён, но уже и не мешает. Строка остаётся недописанной, задача уходит, а мы искренне уверены, что всё учли. Коллега, услышав «он исследует», ещё может переспросить: что именно? Себя мы не переспрашиваем. Поэтому словарь этот — словарь не обмана, а самообмана. Называть длительность мощью, исследованием или сложностью задачи — самообман.
Всё, что нашлось под пятью масками, одного рода. Такого же рода было незнание, которое тридцать один час светилось силой на панели основателя и утром обернулось двумястами четырнадцатью изменёнными файлами: то самое, чего он не знал. Его вопросы были о другом — о состояниях подписки, о неудачном списании, о границе между биллингом и авторизацией, — но устроены так же. И имя у всего этого одно — неопределённость: всё, что на момент передачи задачи не известно и не решено. Слово длинное и неуклюжее, и в этом его честность: в нём нет ни похвалы, ни обещания.
Долгий прогон — всегда неопределённость в том или ином виде: несделанный выбор, неназначенный критерий, непонятая система, а чаще всё сразу. Не иногда, не в неудачную ночь, не у тех, кто плохо ставит задачи, — всегда. Хорошая новость, которой звучала каждая из пяти фраз, была новостью о ней. Мы называли её мощью, исследованием, сложностью, оптимальным решением и интригой, но под каждым из пяти имён прогон двигала она. У долгого прогона нет другого топлива.
2.2. Чёткая задача, которая идёт сутки
Задача была короче некуда: добавить в API ещё один метод, по образцу соседних. В ней не было ни одного расплывчатого слова, и понять её неправильно, казалось, невозможно. Мы отдали её вечером, рассчитывая утром первым делом прочитать короткий diff и закрыть вопрос. Прогон по ней шёл сутки. Ошибки в самой формулировке потом так и не нашлось: слова стояли на своих местах, и каждое значило ровно то, что мы имели в виду.
Удивление здесь законное. Интуиция «чётко поставил — быстро получил» верна, и каждый, кто отдавал такие задачи, знает это по опыту. Тест упал после вчерашнего переименования функции: ИИ-агент читает сообщение об ошибке, находит старое имя ещё в двух местах, правит, запускает тесты, и через пять минут всё снова зелёное. Форма регистрации принимает адрес почты без домена: добавить валидацию и тест на неё — минуты. В библиотеке журналирования закрыли уязвимость: обновить зависимость, запустить тесты, закоммитить. Ни одной из этих задач не нужно больше нескольких минут: правка сделана — и прогон окончен. Быстрыми их делает не только малый объём. В каждой уже всё решено. Упавший тест сам говорит, что считать правильным. Адрес без домена — не адрес, спорить тут не о чем. Номер новой версии назван, а старые тесты покажут, сломалось ли что-нибудь. Такая задача приходит вместе со своим критерием, и остаётся только сделать.
Шкала на этом не кончается. Бывают задачи по-настоящему большие: модуль загрузки файлов, который режет большой файл на части, докачивает их после обрыва связи и сверяет собранное с отправленным. Если заранее решено, какого размера части, где держать недокачанное и сколько его хранить, и назначен признак готовности — скажем, файл в несколько гигабайт доходит целым через соединение, которое трижды рвут посреди загрузки, — такой модуль занимает несколько часов. Кода в нём много, тестов много, и ИИ-агент всё это время работает, а не топчется на месте: пишет разбиение на части, докачку и сверку, запускает тесты с оборванным соединением, чинит то, что они находят. Каждый час прогона виден в коде. Эти часы — не долгий прогон. Это норма: ровно столько требует объём.
Отсюда мера. Если решение известно, устройство выбрано, критерий назначен, задаче хватает времени, соразмерного её объёму: минут на правку, нескольких часов на сложный модуль. Долгий прогон — тот, что длится дольше, чем требует объём задачи, в которой всё это уже решено. Восемь часов на модуль загрузки — не долгий прогон. Восемь часов на валидацию одного поля — долгий. Сами по себе сутки ещё не мера: сутки на что? Мерой их делает шкала: только рядом с ней видно, какая часть часов ушла на объём, а какая — на что-то другое.
Теперь поставим рядом другие задачи из той же недели, тоже в одну строку. Обновить библиотеку, которая сжимает картинки, — в одном сервисе это заняло минуты, а в соседнем прогон шёл до конца следующего дня. Добавить валидацию — минуты; добавить метод API «по образцу соседних» — сутки. Модуль загрузки по выбранному устройству — несколько часов, а удаление учётной записи, работа в разы меньше, шло сутки с лишним. Вторая задача в каждой паре, когда мы её писали, казалась ничуть не менее чёткой, чем первая, и писалась так же быстро. Такие пары мы встречаем то и дело, когда отдаём ИИ-агенту мелкие задачи пачкой: почти все возвращаются за минуты, а одна-две не возвращаются и через сутки.
Утром diff у суточных задач оказывается не больше, чем у их быстрых пар. В соседнем сервисе — только новый номер версии. Новый метод — не длиннее любого из соседей. Удаление учётной записи — десяток файлов. Объём сопоставимый, а то и меньше; время несравнимое. Проще всего списать разницу на случай: не повезло, ночь не задалась, прогон свернул не туда. Или сказать, что задача оказалась сложнее, чем выглядела, и тем самым вернуть маску, без которой только что обходились. Но ИИ-агент был тот же, что днём справлялся за минуты, и ставили задачи мы не хуже.









