Сайт Романа ПарпалакаБлог202404

Codeium — нейросетевой помощник программиста

2 апреля 2024 года, 00:07

Попробовал в работе Codeium — нейросетевой помощник в написании кода. Его обзор уже был на хабре, так что я просто запишу свои наблюдения, не претендуя на полноту рассмотрения.

Как работает Codeium

Я установил его как плагин к PhpStorm. Для работы он требует войти в аккаунт, но регистрация бесплатна.

Пользователь взаимодействует с плагином двумя способами. Первый — автодополнение. Вы набираете код, останавливаетесь, и в этот момент нейросеть выдает возможное продолжение. Вот я написал название метода, остановился в начале пустого тела, и Codeium вывел серым предполагаемое начало кода:

После нажатия на tab и перевода строки нейросеть продолжает сочинять. Вот тут одним махом предлагает написать весь оставшийся код метода:

Нейросеть «поняла» из названия метода, что мне нужна версия алгоритма для вычисления расстояния Левенштейна между строками, корректно работающая с кодировкой UTF-8 (в PHP есть встроенная функция levenshtein(), но она правильно работает только для однобайтных кодировок). Идея алгоритма оказалась правильной, но с деталями не вышло: сравнение $a[$i - 1] === $b[$j - 1] берет не символы с соответствующими номерами, а байты. После исправления этого фрагмента на mb_substr($a, $i - 1, 1) === mb_substr($b, $j - 1, 1) код заработал правильно.

Второй способ взаимодействия — это чат. Он мне показался туповатым по сравнению с ChatGPT. Я так и не понял, лучше ли работают английские запросы, или можно писать по-русски. На скриншотах выше видны шорткаты для быстрой формулировки запросов в чате: Refactor, Explain, Docstring. Explain описывает на «человеческом» языке, что происходит в коде. Возможно, пригодится в командной работе, когда программист в основном разбирается в чужом коде, а не пишет свой. Я же пробовал Codeium на своем коде, о котором я и так всё знаю, так что описание мне не пригодилось.

Главный вау-эффект

Наибольшая помощь от «искусственного интеллекта» была в переписывании кода и конфигурации из одного формата в другой. Допустим, вы меняете формат какой-нибудь конфигурации из XML в JSON или заменяете множество вызовов одного API аналогичными вызовами другого. Из классических инструментов может помочь замена с помощью регулярных выражений или мультикурсор, да и то не всегда. В примере на скриншоте ниже поможет только ручное копирование каждого значения и ввод служебных символов. А с Codeium я скопировал старый код в новый файл, начал дописывать новый код, и он, распознав закономерность, стал предлагать в автодополнении правильное продолжение на основе старого кода.

Недостатки

Теперь о недостатках, куда же без них. Во-первых, Codeium может только добавлять код. Он не может предложить удалить какой-то фрагмент. Во-вторых, он подтормаживает. Тормозит и появление фрагмента для автодополнения, и последующее редактирование текста. Заметно, что автодополнение сделано не нативно — серый текст располагается не в какой-то выпадайке, а прямо внутри редактируемого текста. И если я не принимаю подсказу, нажимая tab, а продолжаю дописывать текст или передвигаю курсор стрелками, проходит заметное время, прежде чем серый текст удалится и появятся набираемые символы. А курсор при перемещении сначала попадает в серый текст, потом серый текст исчезает и курсор оказывается в нужном месте основного текста. После этого Codeium опять подумает и добавит новую версию серого текста с подсказкой. Даже если плагин не запутается и корректно допишет вводимые символы куда нужно и расположит курсор, такое поведение напрочь убивает мгновенную обратную связь при наборе текста и делает сам набор почти невозможным. Может эти недостатки — следствие ограниченного API плагинов в PhpStorm. Но сейчас всё работает не очень приятно.

Ненативность автодополнения проявляется еще, например, при переименовании. Вот здесь я переименовываю метод так, что PhpStorm заменит его вызовы по всему проекту. На этот режим указывает голубая рамка. Codeium умудряется дописать свое мнение еще и сюда, но сам PhpStorm о нем ничего не знает. Когда я применил подсказку пару недель назад и закончил переименовывать, PhpStorm заменил вызовы по всему проекту на недополненное несуществующее название. Сейчас при попытке воспроизведения tab в режиме переименования просто не работает, подсказка не применяется. То есть Codeium выдает свой вариант, но применить его никак нельзя.

По внешнему виду автодополнения непонятно, что это предложение помощника. Просто серый текст, неотличимый от комментария. В какой-то момент я переключался между вкладками и не заметил срабатывания автодополнения. Потом какое-то время смотрел на этот код и пытался понять, откуда он взялся, пока не осознал, что это автодополнение искусственного интеллекта.

Еще одна особенность текущего механизма взаимодействия: нет возможности оставить часть предложенного автодополнения, скажем, первые несколько слов. Можно только принять всё целиком и удалить лишнее.

Вывод

В процессе работы перевешивают то достоинства нейросетевого помощника, то его недостатки. Забавно наблюдать, как нейросеть «читает» твои мысли, выдавая ровно тот код, который ты сам собрался написать. Правда, происходит такое не всегда. Когда нейросеть предлагает нужные фрагменты кода, их надо тщательно проверить, как за программистом-стажером. В то же время при рефакторинге встроенными в PhpStorm инструментами я отключал Codeium, потому что тогда его подсказки бесполезны, а подтормаживания интерфейса мешают.

В общем, перспективы большие. Пользовательский опыт сейчас страдает. Пробуйте сами.

Да, и не забывайте о вопросах безопасности. Наверняка Codeium отправляет всё редактируемое на свои серверы. Я пробовал его на открытом опубликованном коде своего движка, так что дополнительно ничего «утечь» не может. Если хотите попробовать на работе — проконсультируйтесь с вашим отделом по информационной безопасности.

    Оставить комментарий

Некоторые возможности регулярных выражений, о которых мало кто знает

6 апреля 2024 года, 20:03

На примере задачи с поиском определенных последовательностей символов в строке расскажу о некоторых не очень известных возможностях регулярных выражений.

Условие задачи

Нужно найти в строке символы i, b, u, d, перед которыми расположено нечетное количество обратных слешей, например \I или \\\b.

Мотивация

Расскажу, откуда появилась эта задача. В свой поисковый движок Rose я добавил поддержку простейшего форматирования в сниппетах: курсив, жирный шрифт, верхние и нижние индексы. Благодаря этому формула y = ex в сниппете отображается правильно (без форматирования было бы y = ex):

Я не хотел хранить текст сниппетов с частично вырезанными HTML-тегами и придумал свою разметку. Последовательность символов \i включает курсивное начертание, последовательность \I отключает. Аналогично с остальным форматированием. При этом, чтобы хранить сам символ обратного слеша, его нужно продублировать для экранировки (\\). Таким образом, формула из примера выше хранится в сниппетах как \iy\I = e\u\ix\I\U.

Как видно на скриншоте выше, сниппеты собираются из отдельных предложений, а форматирование может распространяться за их границы. Например, я могу выделить курсивом целый абзац, тогда \i будет в начале первого предложения, а \I — в конце последнего. Поэтому важно после разбиения текста на предложения убедиться, что всё открытое форматирование корректно завершено в текущем предложении и перенесено на следующее, и нет завершения неоткрытого форматирования. Для этого как раз и нужна сформулированная задача.

Решение

Я составил такую регулярку: #\\(?:\\(*SKIP)\\)*\K[ibud]#i. Давайте разберем ее по шагам.

  1. Регулярка начинается с символа обратного слеша. Нужно помнить, что в регулярных выражениях он имеет специальное значение, и сам по себе должен быть экранирован.
  2. Дальше идет группа (?:...) без захвата, то есть ее содержимое не попадает в итоговый массив результатов $matches.
  3. Внутри группы находятся два обратных слеша, а сама группа указана с квантификатором *, означающим её повторение любого количества раз, включая нулевое. Таким образом уже разобранная часть регулярки должна срабатывать на нечетном количестве слешей.
  4. Внутри группы также расположена управляющая последовательность бэктрекинга (*SKIP). Она обозначает некоторую границу и дает инструкции движку регулярных выражений, чтобы он не переходил эту границу при переборе возможных повторений, задаваемых квантификатором *, а также сразу переходил к ней в исходной строке, если было только частичное совпадение с регуляркой. Без этой управляющей последовательности мы бы получили ложное совпадение на строке \\i с четным количеством слешей. Действительно, в ней на первом проходе, начиная с первого символа \\i, совпадения нет из-за четного количества слешей. Но дальше мы получим совпадение, начиная со второго символа: \\i. (*SKIP) же задает границу между вторым слешем и следующим символом, поэтому движок регулярок при работе не будет проверять совпадение со второго символа, а сразу перейдет к третьему. В англоязычной литературе для подобных управляющих последовательностей используется термин Backtracking Control Verbs, среди них есть и другие полезные возможности.
  5. Следующей идет последовательность \K. Она убирает из результатов общего совпадения всё, что было до нее. Таким образом, в $matches[0] попадет только оставшаяся часть совпадения, без слешей.
  6. Наконец, мы требуем, чтобы после нечетного количества слешей был один из управляющих символов [ibud]. Так как у регулярки указан модификатор i, совпадение будет в любом регистре.

Если не использовать жемчужину этой регулярки, (*SKIP), можно сочинить выражение с ретроспективной проверкой (lookbehind): #(?<=^|[^\\])\\(?:\\\\)*\K[ibud]#i. Правда, оно будет менее эффективно на строках с обратным слешем. Ну а наивное выражение #(?:^|[^\\])\\(?:\\\\)*\K[ibud]#i будет медленнее на любых строках, так как не начинается с фиксированного символа обратного слеша.

При применении регулярных выражений не нужно забывать о дополнительном экранировании слешей по требованиям синтаксиса языка программирования. Итоговый код на PHP получается таким:

preg_match_all('#\\\\(?:\\\\(*SKIP)\\\\)*\K[ibud]#i', $text, $matches);

foreach ($matches[0] as $match) {
    // в $match будет один из символов ibudIBUD
}
    Оставить комментарий

← сюда туда →

Поделиться
Записи