Стендап Сьогодні
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
Пости з тегом #ПомічникШІ
01.05.2025
Штучний інтелект — хто виграє від нього найбільше?
Перше, виграють виробники потужностей. Всі великі виробники компʼютерів вже вийшли з “AI” пристроями. Дуже вчасно зʼявилася причина оновити компʼютер, бо якщо не дивитися на “AI”, то останніми часами компʼютери стали достатньо потужні, щоб не думати про наступний. (Бо в моєму дитинстві компʼютер оновлювали, щоб на ньому можна було подивитися фільм.)
“AI” це золота жила тому, що його можна продавати будь-кому — від малої дитини до панів в костюмах. Зокрема, подивимося на відеокарти. Ресурси для відеоігор досягли стелі якості, за якою їх нерентабельно виготовляти. Та й ринок все одно обмежений. А тепер можна скільки завгодно потужностей продати заради “АІ”.
Хоча понад усе виграють власники хмар. Бо, цілком очевидно, що ніж купувати дороге залізо, можна заплатити хмарі. Тому, коли зараз кажуть, що пристрої “з AI” не мають попиту, я гадаю, що споживачу хмари достатньо. Наперекір сумнівному ставленню хмарних компаній до етики — про яке можна судити вже з того, що вони вже тренують моделі навіть на піратському контенті.
Друге, це ринок стартапів. У тому вузькому сенсі, як продуктів, які будуються, щоб отримати інвестиції або продати задорого та швидше. Інвесторів легше переконати, коли за тобою стоїть Технологія Майбутнього, Яка Тільки Відтулила Двері Для Найрозумніших — хай то бізнес в інтернеті, соціальні мережі, блокчейн чи тепер AI. Тому серйозні стартапери не шукають революційних ідей, а застрибують в поточний Віз Революції та галасують якомога гучніше, що Віз справжній, а хто на нього закине грошей — поверне їх встократ.
Я поки не добрався до того, що ж все ж таки “AI” здатний чи не здатний робити, як-от генерувати красивий ввічливий лист, або, наприклад, підсумувати задовгий лист до його змісту. (Жартую.) Давайте так — багато на що здатний. Про це іншим разом.
09.05.2025
Пошук по каналу на сайті за допомогою Orama
Сьогодні зробив (не без допомоги Claude, зізнаюся) пошук по каналу. Вже кілька років про це думаю, але, знаєте як — пошук це велика задача, ніколи не було часу. А тут за півдня зміг зробити непогану версію, яку можна побачити прямо на сторінці каналу. (Шукайте рядок пошуку.)
Будь-який повнотекстовий пошук спочатку будує індекс, а потім шукає по ньому. Колись в мене на сайті вже був пошук, чисто фронтендовий, через Lunr.js - там індекс сидів прямо в коді скрипту. Втім, це значило, що для пошуку доводилося завантажувати кілька мегабайтів — фактично, весь зміст сайту. Це мені не подобалося. А окрім того, Lunr більше не підтримується.
Тож шукав рішення із бекендом. В Hugo є офіційний перелік, з яких я зупинився на Orama, бо вони обіцяли рішення на чистому JavaScript. (А ще Orama вміє векторизувати запити, що дає можливість шукати по синонімах — але тут поки проблеми.) Нагенерувати базовий код для Orama допоміг Claude, тож не довелося починати з нуля.
Моє рішення складається із чотирьох частин. Спочатку, під час побудови сайту Hugo генерує зміст JSON. Це для мене вже знайомий крок, бо так само працює OmniWOPE.
Потім, теж в скрипті постачі, запускається окремо індексатор. Він перебирає вхідний JSON та генерує величезний (22 Мб!) JSON індексу. Цей файл потрапляє в збірку серверних функцій Vercel.
Далі є функція /search
- вона завантажує той індекс з файлу та викликає пошук Orama — це вже досить прямолінійна дія.
Та нарешті, є фронтенд, який теж нагенерував Claude, бо мені не хотілося довго возитися із шаблонами. Фронтенд робить запити до API та виводить список результатів. Попросив Claude “no frameworks, use HTML DOM API” та в цілому отримав те що хотів. Потім додав “use css classes and html tags from post list page”, бо на початку він наробив власних стилів. Якось так.
Поки в цього пошуку є обмеження. Не знайшов, як в Orama мати документи різними мовами — тому поки є тільки українською. Пейджинацію поки не став робити. Але головне — що нарешті закрив навіть власну потребу, бо часто я банально не міг знайти статтю простим пошуком (їх, до речі, тільки-но перевалило за тисячу!). А Google чомусь надзвичайно погано індексує. (Треба і з цим ще помучитись.)
10.05.2025
Нова версія гему Headless та ШІ для розблокування проєктів
Сьогодні випустив оновлення для Headless. За всіма вимірами, це треба було зробити вже давно, але краще пізніше, ніж ніколи — принаймні, якщо люди все ще просять. (Я вже писав), що мені він давно не потрібний. Десь з рік тому до мене зверталася людина та пропонувала зайнятися підтримкою, та я навіть доступи надав, але… в неї теж поки не знайшлося часу, напевно? Історія класична. Десь з тиждень тому мені знову нагадали, що гем не працює з сучасним Ruby, тож вирішив взятись.
Як я себе змусив це зробити. Думаю, ну мені не хочеться - Cursor зможе. Успіхи з Cursor були різного рівня.
Замінити Travis CI на Github Actions - впорався на 95%. (Чомусь запхав у виконання тестів xvfb-run
, хоча вся суть мого гему, що він заміняє xvfb-run
для програм на Ruby.) Це чудово! Я вручну б довго сидів та розбирав синтаксис.
Оновити матрицю версій Ruby для CI - впорався на 100%. Теж гарно, бо це наче просто, але довелося б бігати по сторінках завантажень Ruby та JRuby.
Прибрати ключ конфігурації та перейменувати інший — десь 90%, майже все гарно, але трохи додумав зайвого. Втім, не так багато, щоб його було складно видалити.
Додати Rubocop - тут я б сказав 30% успіху — наче щось виходило, але конфігурації забагато та rubocop-rails
намагався теж впхати.
Виправити Rubocop - цього взагалі не раджу робити, хоча в мене були великі сподівання. Бо код псує більше, ніж виправляє. Причому псує в сенсі змінює зміст. А я зрештою замінив Rubocop на Standard - це надбудова над Rubocop із переконаним набором налаштувань. Окрім іншого, Standard добре виправляє помилки та підійде навіть в ролі автоформатувальника. Навіщо ШІ, коли є спеціалізований інструмент?
Якщо підбити підсумки, то агент ШІ допоміг зсунутися з мертвої точки та навіть закрити деякі необхідні, але рутинні оновлення. Та це безумовно успіх. Проєктів багато — мене мало. З агентом мене стає більше.
12.05.2025
Міграція інтеграційних тестів: погана задача для ШІ
Передісторія. Десь у 2019 зʼявився Chrome DevTools Protocol - протокол поглибленого керування браузером. Наприклад, він дозволяє прямо встановити кукі, або зробити знімок екрана. Гарна річ, дозволяє позбавитись посередника для автоматизації браузера. Зокрема (але не тільки) для інтеграційних тестів.
Невдовзі вийшов гем Cuprite для тестів на Ruby, який дозволяв позбавитися Selenium. Selenium - не найстабільніший пакет на світі, тому тоді це сприйняли з радістю та мігрували. Радикального виграшу не отримали, хоча поглиблене керування стало в пригоді. Минуло 6 років, та Cuprite так і не переміг Selenium, а до того ж його не дуже гарно підтримують. Інтеграційні тести, на жаль, це така галузь, де вчасна підтримка все вирішує, бо Chrome оновлюється постійно та десь щось ламає. От і зараз це стало великою проблемою… можна було б переїхати назад на Selenium, тільки це проблема ще більша. Питання: чи допоможе із цим впоратись ШІ?
Виправлення, широко кажучи, можна поділити на 3 категорії.
Різниця в пробілах. Для зручності в Capybara можна перевіряти не тільки сухий DOM, але і його текстовий зміст. Кожний із рушіїв по-своєму його будує (зверну увагу, що ніякого стандартного способу тут немає.) Це веде до купи абсолютно тривіальних помилок вигляду Foo\nBar
замість Foo Bar
. Я думав, що ШІ тут легко все поробить, але ні. Часто він або не розумів задачі, або заміняв надто багато, вигадував своє. Зробив висновок, що ні — дрібні, розсипані по коду виправлення ШІ робить погано. Я сам швидко зʼясував природу змін… от тільки робити їх вручну все одно довго та нудно.
Зміна API В Selenium за ці роки зʼявилася підтримка CDP. Втім, звісно, виклики не збігаються. Умовно, замість driver.set_cookie
треба писати driver.devtools.network.set_cookie
, та ще й термін передати числом, а не датою. Я сподівався, що “перероби на API Selenium” пройде, але ні. Навіть коли додав “читай цю сторінку із прикладами”. Зрештою виявилося, що я вручну з масовою заміною можу адаптувати виклики швидше, ніж вигадувати запит до ШІ.
Складніші зміни. Взагалі, мій перший план був такий: забирати з CI журнал невдалих тестів та передавати до Claude із додатковими інструкціями. Окрім вище описаних змін, були й менш зрозумілі. Наприклад, деколи Selenium відпрацьовує швидше (чи не чекає чогось?) та перевірка випереджує стан. Тут ШІ робив якісь незрозумілі кроки. Зокрема - спрощував тести, щоб ті проходили. Тобто з масовим виправленням без людського втручання точно успіху немає.
Якщо підсумувати, то ця міграція, про яку мені навіть казали “так може ШІ це швидко зробить?”, так і залишилась великою та складною задачею.
13.05.2025
Вкладки браузера — в Obsidian Canvas (скрипт)
Я якось писав, що хочу браузер, який буде інтегрований з базою знань. Таке можна потрохи робити. От, наприклад, коли я навідкривав вкладок для якогось дослідження, було б гарно всі їх скинути в Obsidian Canvas на майбутнє. Але ж не вручну? Накрутив собі за пів годинки скрипт, не без помічника ШІ.
Власне, майже всі запчастини в мене вже є, Я вже писав, як отримати список вкладок з Safari та генерувати Canvas зі списку, утиліту для чого pbcopy-chromium я вже публікував. Але одне рішення — на AppleScript, друге — на Ruby. Вирішив, що найбільш елегантно буде зібрати до купи на JavaScript for Mac Automation, про який я теж вже писав. Бо інакше інтеграція буде ще складніша, ніж частини.
Отже. AppleScript у JXA перекладається 1-до-1. Це, за моїм досвідом, найкраща задача для ШІ! Замість години копирсання поганою документацією та поступового налагодження — задля, фактично, “нульового” результату, бо ми тільки перекладаємо логіку на іншу мову — одна команда. Так само вдалося й перекласти генерацію канви з Ruby на JXA - причому, ба більше, ШІ відразу її автоматично “вписав” у попередній скрипт.
Це 80% роботи. Решта 80% була менш автоматичною. Ну, згенерувати команду для виклику pbcopy-chromium
вийшло, та це гарно, бо там не одна команда, а цілий ланцюг. От тільки як в нього передати зміст? ШІ зробив через echo
. Зрозуміло, що зі складним JSON від цього буде купа проблем. Тоді спробував через тимчасовий файл. ШІ нагенерував відповідні команди — включаючи mktemp
для генерації файлу — десь на 80%.
Але тепер залишилося найцікавіше, бо запис у файл з JXA не використовує UTF-8. Поради ШІ тут були безпомічні. Тоді знайшов на SO відповідь, як то зробити… мостом в Objective C? Дико, але працює!
Нарешті, про рефакторинг. Сьогодні ШІ накидав все в одну купу; наприклад, вище згадана побудова JSON для канви відбувалася прямо в циклі по вкладках браузера. Звісно, краще ділити логіку за намірами. Зате інструкція “розбий це на дві функції для того та для того” спрацювала.
Ще з суто ШІшного ексцесу (тобто такого, що я б сам не став робити) - генерація ID вузла через хеш змісту. Це я попросив зробити, але функцію воно нагенерувало само. Нічого бібліотечного готового немає. Вирішив, нехай залишається.
Знову, таку роботу я б сам не зробив, бо часу немає. Забрати скрипт можна тут.
14.05.2025
Чому копіпаста — це погано?
Метою написання коду завжди є те, щоб він був зрозумілим. З нуля ми пишемо код один раз, а дописуємо — всю решту часу. Незрозумілий код — це не краще, ніж невірний (бо, по-перше, звідки ти знаєш, що він вірний?) Отже, всякий код повинен насамперед легко читатись, а потім вже все інше.
Копіпаста (а саме, скопійований багато разів код) погана не тільки тим, що вона повторюється. Тоді можна було б її більш-менш ігнорувати. Значно гірше, що копіпаста рідко повторюється дослівно, та ми ніколи не знаємо, чи це так. Доводиться серед нудних повторюваних рядків “знайти 10 відмінностей”. Або — скоріше — просто проґавити.
З появою ШІ це тільки стало гостріше, бо ШІ, на відміну від людини, обробить весь текст з рівною увагою, а значить, найважливішими стануть ті рядки, що повторюються, хоча повинно бути навпаки. ШІ взагалі майстер “згладити нерівності”. А з іншого боку, ШІ залюбки згенерує вам скільки завгодно копіпасти, створивши собі ж пастку на майбутнє. Цьому треба активно запобігати.
Академічні рішення — всякі DRY та правильне структурування коду — на практиці не завжди вдається використати, бо не весь код можна, умовно, загорнути в функцію чи винести в окремий клас. Тому нагадаю ще про кодогенерацію - а саме, заміну “майже повторюваного” коду на шаблон.
16.05.2025
Reminders2JSON, а також ШІ як клей
Отже, вчора в коментарях зʼясували, що Apple Reminders технічно можна було б вивантажити в JSON через фреймворк EventKit. А сьогодні я вирішив, що це гарний проєкт для того, щоб погратися з ШІ, та майже витягнув його в App Store (!)
Чому гарний для ШІ? Бо я гарно розумію, що треба зробити, але це все одно багато роботи. Це проєкт-“клей”, тобто такий, де потрібно поєднати готові частини в спеціалізоване рішення. Я люблю цитувати статтю You can’t buy integration, але — здається, ШІ чудово виконує “склейку”.
В цьому випадку, я спочатку згенерував функції читання з EventKit та генерації JSON, потім — окремо — експорт будильників та графіків. Потім конфігурацію командного рядка. Потім конвертував застосунок командного рядка у SwiftUI (!) Створив набір значків потрібного розміру. Додав файли Fastlane для публікації. Та більшу частину всього цього зробив Claude.
Але на “інші 80%” пішло набагато більше часу. Наприклад, спочатку я хотів консольну утиліту. Але в моделі безпеки macOS вони не можуть отримати дозвіл на читання Reminders. (Бо ця модель розрахована на “товсті” застосунки, із всілякими підписами.) Та мені так і не вдалося це побороти, хоча наче можливість є — невідомо тільки як до неї прийти. Локально в XCode наче працює, але на іншій машині абсолютно відмовляється.
Промучився пару годин та вирішив зробити очевидне рішення — перетворити на графічний застосунок. Та тут ШІ впорався не тільки зі створенням інтерфейсу, але й, наприклад, із відкриттям діалогу для збереження файлу (ще одна склейка).
Сам застосунок дуже нудний — бере нагадування, зберігає в JSON. А, ще деякі атрибути нагадувань недоступні з EventKit - наприклад, групи списків. Ну то вже таке. Через пару днів має зʼявитися в App Store. А ось вже й в App Store!
19.05.2025
Perplexity - пошук в інтернеті, яким він повинен бути
Давайте відразу зазначимо: пошук в інтернеті з самого початку є чорним ящиком без чітко заданої поведінки. Тому пошук із соусом LLM не є чимсь що перегортає світ чи спотворює чистоту оригіналу. А тепер: Perplexity.
Perplexity це агент для пошуку в інтернеті. Коли ти задаєш йому запит, спочатку він генерує не один, а відразу декілька запитів до пошукових систем. Робить їх. Читає результати. Та видає зведену відповідь, в якій на кожне твердження є посилання на оригінал.
Виходить такий сендвіч з LLM: генерація запитів, пошук, зведення результатів. Це стає корисніше в подальших запитах — бо звісно, перший запит стає ниткою. Тому додаткові запитання можна вже ставити в контексті відповіді, а не ліпити пошук наново. Як старанна LLM, Perplexity згадає важливі параметри та додасть їх до запиту до пошукової системи.
Що мені подобається: такий підхід відтискає воду. Якщо традиційний пошук ще більш-менш легко шукати компʼютерні теми (англійською!), то побутові теми настільки сповнені SEO-води, що треба перебрати десятки сторінок, щоб щось зрозуміти. Perplexity це робить за мене. Також подобається деталізувати результати та заглиблюватися в тему. Мабуть, можна сказати, що найцікавіше починається в глибині.
Наприклад, вчора почав з того, які лампи потрібні для вирощування зелені, а потім перейшов до необхідної на мою площу потужності, відстані кріплення та власне штанг для світильників (бо грядка вертикальна.) А потім зміг переконатися, що ці штанги відносно нескладно зробити власноруч, які потрібні для того кріплення та де їх купити. Все це може за годину досліджень.
Окрім цього зрушив вчора ще може з десять проєктів завдяки тому, що міг швидко почати дослідження та отримати перші результати. Втім, треба бути обережним — захопитися неважливою, але цікавою темою теж стало легше.
29.05.2025
Агент ШІ: Від 0 до вайб-кодінгу
Часто доводиться чути, що використання ШІ в програмуванні — це обовʼязково радикальний відхід від норм. Це все одно, як думати, що якщо купиш болгарку, то нею треба буде різати все, від хліба до нігтів. Ось вам декілька сходинок поступово більшого використання ШІ — обирай ту, яка тобі комфортна.
1. Ставити питання щодо проєкту. Як працює X? Чому тут так написано? Яка різниця між А та B? ШІ здатний швидко обробити багато коду та дати чудові пояснення. При цьому ШІ не пише аніскілечки вашого коду, тому й ніяких ризиків немає. (До речі, тут та далі потрібний редактор з ШІ, як-от Cursor, а не просто чатбот без знання проєкту.)
2. Маніпуляція тексту. Моя улюблена функція поки — це скопіювати шлях до об’єкта в Google Console та попросити зробити з нього виклик CLI. Задачі такого рівня вимагають нудних ручних перетворень, а ШІ з ними порається дивовижно.
3. Локальні доповнення. Це коли тобі пропонує продовження рядка, який ти зараз пишеш. Я цим користуюся багато років з TabNine, але чесно кажучи, LLM краще радять, більш поглиблено.
4. Локальна генерація чи рефакторинг. Можна попросити згенерувати одну функцію, чи скелет класу, чи тесту. В Cursor для цього тиснеш Cmd+K
в потрібному місці. А ще - виділяєш текст, тиснеш Cmd+K
та рефакториш на місці. При цьому зміни не залишають область виділення, а якщо не сподобалося — можна відразу скасувати.
5. Покрокова генерація за інструкціями. Це коли ти агенту кажеш “згенеруй мені клас”, “згенеруй тести для нього”, “пересунь функцію в інший клас” - та коректуєш після кожного кроку. Виходить програмування в напівавтоматичному режимі — машина робить нудні речі, ми дописуємо важливі.
6. Покроковий рефакторинг за інструкціями. Я виділив в окрему сходинку, бо рефакторинг має більше ризиків попсувати код, тому потрібно ретельніше переглядати його результати. Зате в цілому можна робити навіть на кшталт “прибери повторення”, або “знайди схожу функцію в інших місцях проєкту та використай її”. Так що не слопом єдиним!
7. Генерувати плани за допомогою ШІ. Цим я сам ще не займався. Але технічно ШІ так само може генерувати план, як і код (або навіть краще.)
8. Піддатися та прийняти вайб. Ну слухайте, я досі не вірю, що хтось це робить навсправжки.
31.05.2025
Масштабний рефакторинг з агентом ШІ
Досяг поки для себе стелі використання помічника ШІ:
В мене є кілька проєктів для iOS, які використовують SwiftData. Мені він зовсім перестав подобатись, тому хочу переписати все на SQLite (GRDB). Але то вручну робити важко. Зате більшість змін робляться за аналогією, хоча не повною: наприклад, у SwiftData асоціації завантажуються автоматично, коли до них звертаєшся, а в GRDB варто наперед запитати все необхідне до купи.
Отже, що… думаю, напишу інструкцію для Cursor, нехай перекладе. Він технічно щось переклав — але до робочого результату було далеко.
Нормально вийшло перенести: структуру моделей — навіть міграції. Та всю оту нудну підготовку з імпортом пакетів, створенням підключення тощо. Решту змін довелося робити вручну, або давати значно точніші інструкції.
Найбільша перешкода для масштабного використання LLM в інженерії — нестабільність результатів. Нехай вони б навіть були гарні. От написав ти інструкцію. Запустив. Не сподобалося. Трохи відредагував. Та тепер можеш отримати зовсім інший шлях рішення. Причому немає явного шляху на це вплинути.
З маленькими змінами легше, здається, тому що менше варіантів розвʼязку, тому результат більш-менш (але не завжди!) відтворюється. Але зі змінами ось такого, проєктного, рівня в мене, наприклад, міграції то були в тому ж файлі, що модель, то в окремому файлі, то у файлі з підключенням. Та не обовʼязково це можна зафіксувати інструкцією — принаймні, не без появи інших небажаних змін.
Я гадаю, причина тут в тому, що будь-яка модель тренується на обмеженому наборі проєктів. В кожного проєкту — своя комбінація підходів. Кожен проєкт — локальний максимум видачі моделі. Коли наш запит перетинає умовну межу одного локального максимуму в інший, то результат зміниться повністю. Оце люто дратує, та я не думаю, що протидія існує.
А вихід є - обмежувати інструкції дрібними змінами. Це, для мене, поки і є сфера доцільного використання ШІ.