Вайб-кодинг
На прошлой неделе я опять был во Франции. Когда ты во Франции, твоя главная цель — ВКУСНО ЖРАТЬ. Потому что во Франции ЖРАТЬ лучшее в мире.
Но есть одна проблема: если ты идёшь не в туристическую забегаловку, а в аутентичный ресторанчик в любом французском городе, в лучшем случае (когда у владельца хороший почерк и он проснулся в хорошем настроении) его меню будет выглядеть примерно так:
Кто не был во Франции, я даже уточню: даже если вы просите «меню», вам не дают красивую книжку с картинками, как вы привыкли. Вам литералли ставят на стол вот такую черную доску с написанными белым мелом блюдами дня (на французском). Сильвупле, мёсьё! Ду вин пур ле дамэ?
Да, нам обычно везёт, и с нами обычно есть друзья, говорящие по-французски. Но иногда бывают ситуации, когда ВКУСНО ЖРАТЬ хочется, а друзей рядом нет.
Так я как-то давно придумал идею для стартапа.
У ChatGPT (и аналогов) есть интересная особенность — они на удивление хорошо распознают рукописный текст. Даже если это каракули какого-нибудь доктора или протокол полиции на сербском языке (не спрашивайте откуда я это знаю). Прям на голову выше любых старых OCR приложений.
Так вот во время последней поездки по Франции меня озарила максимально тупая и гениальная мысль:
Надо сделать приложение, которым фотографируешь меню ресторана, а оно тебе возвращает список блюд с описаниями на понятном тебе языке и фотографиями как они реально выглядят. И рейтингом... И...
Уверен ли я, что таких приложений уже существует минимум пара сотен тысяч в аппсторе? Конечно же да. Волнует ли меня это? Нет))00)
Так что здесь мы переходим непосредственно к теме поста — вайб-кодингу!
Я не знаю кто придумал сам термин вайб-кодинг, но популярным он стал после твита Andrej Karpathy:
Идея вайб-кодинга в том, что с появлением LLM-инструментов генерации кода и даже целых проектов, как например Claude Sonnet или Cursor (я писал о нем в Итогах Года), у любителей попрограммировать что-нибудь вечером открылся новый способ программирования — с помощью чата с LLM или даже голоса.
Вы открываете Cursor или любую другую AI IDE, создаете чистый проект и начинаете прямо сообщениями в чат ему написывать о том, что вы хотите получить.
Например, я начал с такого промпта:
Create me a React app from scratch. The idea is to have an app which can take a photo of a menu in a restaurant, translate it and then show a list of food with photos of this food from the internet. It must be a PWA with a button opening camera or choosing a photo from gallery which then sends it to ChatGPT to parse text, create a list of items (including categories and prices) and then uses some image API to find images for the food name in the internet. User can see the list and click on items opening more images and description of the dish
Дальше я отправляю свой промпт в Le Chat Sonnet...
И волшебство GenAI магическим образом генерирует мне...
какое-то говно.
Структура проекта отвратительная, всё запихано в один компонент, к OpenAI API он ходит через REST вместо стандартной либы, никакого разделения по экранам, индикации процесса, сотни запросов бегают туда-сюда без кеширования, короче как будто бы джун писал. Здоровый человек этим пользоваться не сможет.
Хотя мне нравится, что оно взяло React + Vite + MUI. Я хоть и бекендер, но поцаны-фронтендеры во дворе рассказывали, что для прототипов это выбор солидного джентельмена.
А еще оно ЗАПУСКАЕТСЯ!
Если сделать npm create/install, как он просит, то npm run dev реально запустит вам (почти) рабочий проект, где просто руками надо будет изменить пару api-ключиков в конфиге и подставить современные версии OpenAI-моделей.
В целом, оно работает.
Но теперь вы понимаете, что с LLM надо разговаривать не как сеньор с сеньором, а как сеньор с джуном. Вы начинаете формулировать свои мысли более конкретно.
Каждый экран, каждая кнопка, каждый лаяут, размеры кнопок и иконок на каждом экране, положение меню, кнопки «назад» и даже выбор фреймворка — всё должно быть вами упомянуто и описано.
Как будто пишешь тикет в Джире для ОЧЕНЬ тупого разработчика. Только результат появляется сразу, а не через пару месяцев созвонов и выборов CSS-фреймворка.
Нельзя сразу требовать от LLM чего-то сложного. Иначе он устанет и сломается на полпути (прям как реальный программист). Нужно придумать и описать тот самый MVP, чтобы результат первой итерации был одновременно максимально простым и базовым, но при этом запускался, работал и решал свою основную задачу.
Короче, теперь вы как будто работаете продакт-менеджером для LLM. Добро пожаловать! Надеюсь настоящие продакты еще не поняли, что программисты им больше не нужны...
Ладно.
По итогу я удаляю проект, создаю новый и пишу следующий промпт в Claude 3.5 Sonnet:
Да начнется вайб-кодинг!
Окей, на этот раз он сгенерировал мне на первый взгляд достойную структуру приложения. Четыре экрана, индикаторы загрузки, URL-роутинг, даже отдельную модельку-сервис создал, которая обрабатывает бизнес-логику меню. Как будто бы курс «Стань Веб-Разработчиком за 13 дней» пройден не зря. Плюс вайб!
📝 Note: когда я писал этот пост и запускал свои промпты еще раз, чтобы сделать скриншоты — каждый раз они мне давали разный результат, иногда вплоть до нерабочего проекта. Так что если у вас не получается повторить — просто меняйте запрос и бейтесь с ним до победного!
На первом экране можно выбрать фотографию меню из галереи или открыть камеру, на втором происходит анализ с красивым лоадером от Material UI, на третьем показывается само меню с изображениями блюд.
Иконку для приложения я тоже сгенерировал с помощью DALL-E, попросив добавить ей немного французского вайба. Получилось дешевое говно, но под вайб подходит. Усы он красиво нарисовал.
Первое, что бросается в глаза — очень плохо написан промпт. Результат даже не парсится, потому что ChatGPT возвращает не JSON, а просто текстовый ответ в Markdown. Но это было ожидаемо, LLM пока плохо пишут промпты для других LLM.
Потому мы поправим промпт руками, используя все наши небольшие знания о Prompt Engineering из других статей. Примерно вот так:
Второе, что мне не понравилось – он решил использовать Unsplash для поиска изображений. Unsplash хорош, но для нашего юзкейса подходит плохо, потому что там в основном стоковые изображения, а мы хотим реальные как из поиска Гугла. Но гугл, я слышал, дерёт много денег за свой API, может попробуем Bing?
Прям так и пишем ему:
Код получился рабочим, но нам надо где-то взять ключ API от Bing Search. Для этого мне пришлось зарегистрироваться в Microsoft Azure, пройти 8 кругов верификаций, ввести данные всех кредитных карт, загрузить фотографию своей собаки, грязных трусов и заложить дом в ипотеку.
Даже несмотря на это, у меня ничего не получилось. Azure просто падал со случайными ошибками в консоли и даже не дал мне создать тестовый API ключ для поиска изображений. Я ничего не понял. В этом вопросе, к сожалению, LLM нам пока не помогут — это минус вайб.
Просто забьем на это. Microsoft как обычно сделали говно. Интерфейс Azure отвратителен.
Выбрасываем Bing, просим Cursor всё переписать на Google API. Он хотя бы не падал с ошибками и выдал мне тестовый ключ на 10К запросов. Картинки заработали.
Чтобы чекнуть вайб, обратимся к проблеме попроще.
Да, я хочу полностью local-first и serverless приложение. Однако, для распознания фоток через ChatGPT нам нужно где-то взять ключ от OpenAI, не хранить же его в коде в открытую.
Так что я подумал, что для бесплатного прототипа спрашивать юзера ввести ключ от ChatGPT — в целом норм. Пусть сами платят за ChatGPT по мере использования. Потом сделаем платную версию со своим ключом.
Прошу Cursor модифицировать экран анализа меню так, чтобы он спрашивал OpenAI ключ и сохранял его в локальное хранилище для дальнейших запросов.
Применяем, сохраняем, применяем — да, работает! Плюс вайб!
Но чего-то еще не хватает...
После загрузки изображения нам долго показывается экран «Analyzing image...» во время которого происходит много магии типа конвертации картинки в base64, загрузки её через OpenAI API, и получения длиннющего JSON'а в ответ.
Процесс занимает секунд 20-30 — а это крайне грустно для пользователя. Он может заскучать, впасть в депрессию, пойти смотреть PornHub или вступить в партию Зелёных — а это точно минус вайб.
Самым простым UX решением в это время будет показать ему загруженную картинку, чтобы он в неё втыкал и не скучал!
Попросим:
Вот теперь экран загрузки выглядит поинтереснее. Можно смотреть на свежую фотку и пытаться самому прочитать названия, пока там LLM пыхтят-стараются...
Оффтопик: я только сейчас понял, что ведь Франция — единственная страна в ЕС, у которой есть свой GenAI. Я уверен, это потому что они тоже им свои менюшки читают!
Окей, всё как-то даже работает, но ощущение от нашего нового «стартапа» пока какое-то не то!
Наверное потому что он выглядит как вырвиглазное говно, как будто его айтишники писали.
Я из своего опыта знаю, что MUI по-умолчанию выглядит всегда, мягко говоря, аскетично. Просто он ждет когда вы пропишете ему в табло какую-нибудь весёлую тему!
Но я понятия не имею какие темы сейчас в моде, а гугление «material ui themes» выдает кучу платных шаблонов за $66, а платить деньги капиталистам — это минус вайб.
Так что мы применим магию LLM снова и просто попросим его: «чот наше приложение выглядит как говно, дай ему красивую модную современную тему для MUI». Не смейтесь, это работает.
Ма-а-а-аксимальный плюс вайб!
Работает херово, но зато красиво!
Только, блин, подождите. Какая-то ошибка вылезла. Но мы уже так разогнались на вайбе, что приговорили три бутылочки пивандрия, так что не дело это самим разбираться что произошло, пусть кнопка «Починить с AI» работает за нас.
Вот теперь другое дело!
Наш «стартап» почти готов к выкладыванию на гитхаб и собиранию лайков в твиттере. Он реально работает как я хотел — берёт фотку, берет ключ от ChatGPT, парсит меню, делит его на категории, показывает список блюд с их фотками, даже рассказывает про ингредиенты, историю блюда и аллергены.
Веганам или аллергикам можно прям сразу платную подписку продавать. Или упороться по в B2B и генерировать ресторанам красивые AI меню с фотками на каждый день.
Но все-таки остается один нюансик, который не даёт мне права выложить это всё на Github Pages и порадовать вас всех — там всё еще используется Google Image Search, который стоит $5 за 1000 запросов.
Я даже провёл отдельный рисёрч с моими вымышленными друзьями-профессионалами из ChatGPT Pro. Оказывается, в современном интернете реально не существует открытого и бесплатного API для поиска картинок.
Полный пиздец.
Нет, вы просто вдумайтесь. Мы научились запускать автомобили в космос, ездить 500 км/ч на поездах, изобрели искусственный интеллект, но ДО СИХ ПОР у нас нет способа бесплатно найти картинки омлета с беконом по запросу «омлет с беконом». Google, Bing, и прочие хотят за такую роскошь $5 за 1000 запросов.
1000 запросов — это смех. Если в вашем меню хотя бы 100-200 блюд, то за каждую фотку вы должны заплатить гуглу ОДИН доллар. Пиздец. Так мы стартап не сделаем. Минус вайб.
Я сожрал 2500 из своих 10К бесплатных запросов просто за пару часов разработки. А просить юзера принести еще и API ключ от Google — сразу мертвая идея, я сам несколько часов потратил на его получение.
Я даже пытался найти другие решения. Я пытался забить на фотографии и генерировать картинки блюд из меню через DALL-E, но там очень драконьи лимиты, одна картинка генерируется секунд двадцать, а все меню займет пару часов и много десятков долоров по цене.
Я пытался использовать Web Scraping вместо API, но тут ни Sonnet, ни ChatGPT, мне не помог — ни один поисковик (даже сраный Pinterest) не дает нормально скрапить изображения по запросу.
А вижуал — это самое главное в стартапе. Ты можешь сколько угодно круто распознавать каракули французских рестораторов, но если ты не можешь показать картинки их блюд — ты проиграл.
Так вот я тоже проиграл. Пака!
Код я, конечно, выложу, но демо не будет: https://github.com/vas3k/stuff/tree/master/javascript/aimenu
Дальше я начал играться со своим новым стартапом и просить Cursor и Sonnet улучшать его всё больше и больше. Я добавил dataService, который кешировал данные в модели, сохранял их в Local Storage и даже позволял из него посмотреть историю сканирований.
Я расширил промпт, чтобы ChatGPT возвращал мне еще и историю блюда, из какого оно региона и как его едят.
Пытался поиграть с ранжированием, типа просить ChatGPT проставить каждому блюду в меню рейтинг по нескольким параметрам, чтобы я мог выбрать самое интересное блюдо в этом ресторане. Но получилось говно и я забил на эту идею.
Чот вайб к этому моменту уже ушел.
Жаль у нас не получилось стартапа, но всё равно я очень круто провёл вечер!
Подводя итоги, у меня есть три вывода:
1. Чем дольше вы общаетесь с LLM, тем хуже он пишет код.
Недавно где-то читал рисерч, что чат с LLM лучше время от времени «перезапускать», потому что он «тупеет» с ростом истории или размера контекста. В вайб-кодинге это прям хорошо видно — со временем он начинает больше «портить» код, чем помогать.
Если в самом начале вы вносите буквально 1-2 правочки в сгенерированный код, чтобы всё заработало, то теперь уже приходится переписывать 10-20% LLM лапши каждый раз.
В какой-то момент баланс смещается с «я дофига продуктивный, LLM мне помогает кодить» в сторону «какого фига я трачу больше времени на исправление его ошибок, чем на написание кода».
LLM — это реально кодинг с джуном :)
2. Когда проект перерастает стадию «прототипа», с ним опять становится проще работать «по-старинке».
С одной стороны, разрабы Cursor проделали неплохую работу по запихиванию всего необходимого в контекст LLM, включая зависимости, соседние модули, итд. При желании можно добавить туда что угодно еще, сославшись на файл или целую папку через "@". Так что если он у вас что-то «не знает» — это skill issue.
С другой же стороны, контекст LLM всё равно ограничен. И из предыдущего пункта мы знаем, что ограничен не столько технически (лимит токенов довольно высокий у современных моделей), сколько тем плавающим моментом, когда модель начинает магически «тупеть».
Так что «рисовать большим мазками» из общего чата получается хорошо на маленьких проектах (или микросервисах), но когда они вырастают хотя бы до уровня продакшен-аппа — больше времени начинаешь тратить на очистку кода от мусора, чем если бы писал его с нуля.
Так что в средне-больших проектах, вместо большого чата, я начинаю чаще использовать LLM-редактирование непосредственно внутри файла (Cmd+K которое) и накладываю изменения постепенно, контролируя каждый шаг.
Типа «перепиши мне эту функцию так, чтобы принимала на вход не объект файла, а сырые байты» или «добавь индикатор загрузки в этот react-компонент». Ну, короче, стандартное программирование с LLM, мне кажется уже все на него перешли.
Но это уже не вайб-кодинг.
3. Нас всех ждет куча говно-вайб-кода в продакшене.
Сейчас вайб-кодинг станет популярным и мы все потонем в куче говно-прототипов и ужасных по качеству коммитов на гитхабе. Вангую, что термин приобретёт супер-негативную окраску и вайб-кодеров будут гнать из уважаемых мест ссаными тряпками.
Так что дома с прототипами развлекаться — это одно, а тащить вайб-код в прод — уже совсем другое. Но как и с любым попсовым инструментом это неизбежно.
Если я все-таки решу допилить свою эту идею и сделать из нее продакшен сервис — я перепишу всё с нуля. Тоже не без помощи AI, конечно, но уже под полным своим контролем за фронтендом и бекендом.
И платным доступом, конечно же! :3