Мир наизнанку,
или как быть программистом и не писать код
Константин Хайт
2025
Недопонятый собеседник
Правду говоря, я не хотел писать эти главы. В мире, где буквально за несколько лет коммуникация с роботами потеснила общение с самыми близкими людьми настолько, что и представить страшно, учить кого-либо пользоваться текстовыми нейросетевыми инструментами — мартышкин труд. Хуже того, дурновкусие, граничащее с этическим самоубийством. В самом деле, если еще совсем недавно всевозможные коучи, менторы, советники и консультанты закономерно почитались шарлатанами и изгонялись из приличного общества, то теперь «великое искусство промптинга» преподают едва ли не в университетах. Причем, зачастую, те же самые люди, что ранее учили нас становиться богатыми и успешными, часто не имеющие ни технического образования, ни даже собственного опыта работы с нейросетями. Их внезапная «экспертиза» базируется на вечной триаде: тривиальности преподаваемого предмета, невероятном апломбе и выученной беспомощности аудитории. Которая вполне могла бы освоить этот самый «промптинг» безо всякого посредства высокомудрых учителей, насмотревшихся видеороликов и, тут я не могу ручаться, возможно даже прочитавших толстую книжку про большие лингвистические модели, и перенявших оттуда несколько умных терминов. Становиться добровольно в длинный ряд эксплуататоров человеческой нерешительности, продающих то, что доступно каждому совершенно бесплатно — равносильно признанию в мошенничестве. И я никогда не пошел бы на это, если бы не несколько моих друзей, которые настойчиво рекомендовали «начинать с самого начала».
Вообще-то эта книга написана вовсе не для того, чтобы объяснять, как использовать ChatGPT, Google Gemini, или что-то, что придет им на смену к тому моменту, когда вы, если повезет, ее дочитаете. Ее цель — показать, как инструментарий на базе LLM может потеснить традиционное «алгоритмическое» (а также «функциональное» и прочее детерминированное) программирование, и как те из вас, кто не имеет опыта кодирования, математической и алгоритмической подготовки, но располагает здравым смыслом и системным мышлением, могут стать программистами, или, лучше сказать, инженерами программных продуктов, используя этот, сильно недооцененный к настоящему времени подход.
Обучать же использованию ChatGPT, по моему глубокому убеждению — такая же бессмыслица, как потуги моей бабушки научить меня пользоваться телефоном. Эта замечательная немолодая женщина старательно показывала внуку, как следует вращать дисковый номеронабиратель (да, я настолько стар, что телефоны моего детства не имели кнопок), а малыш недоумевал, для чего тратить время на то, что является элементарным с самых пеленок. Ровно так же неуместно обучать моих детей искусству эксплуатации мобильного телефона, когда трехлетняя дочь, родившаяся, можно сказать, с экраном перед глазами, отлично запускает любые приложения безо всякого обучения. А мои сыновья, еще не до конца освоив грамоту, используют нейросети по поводу и без повода, обходясь для этого без всяких курсов и тренингов. Современный инструментарий таков, что не только домохозяйки, но и грудные младенцы в состоянии обращаться с ним не хуже любых «профессионалов»… Если речь идет о повседневных задачах домохозяек и грудных младенцев. Когда же требуется решать проблемы посложнее, простота оборачивается недоумением и растерянностью. И именно поэтому мне все-таки придется начинать с самого начала.
Шайтан-машина
Знаменитый советский комик Михаил Жванецкий обожал рассказывать анекдот об американской пилораме, купленной для сибирской лесопилки. Восхищенные возможностями заморского агрегата советские работяги совали в нее все подряд — от тоненьких веток до необъятных бревен, и чудо техники успешно справлялось с любой задачей. Но упорные и самолюбивые лесорубы не унимались и в конце концов засунули в пилораму рельс. Машина сломалась, и работяги вернулись к привычным инструментам, констатировав паталогическое несовершенство западной техники.
Не скрою, мое первое знакомство с LLM происходило примерно по той же схеме. С упорством дикаря я нагружал шайтан-машину «человеческими» задачами, делая далеко идущие выводы из ее очевидной неспособности решать их так, как я бы этого хотел. И только через много месяцев, изрядно поработав извилинами и поэкспериментировав с программными API, пришел к в целом очевидному пониманию, что любую вещь необходимо использовать по назначению.
Увы, многие мои знакомые к этому пониманию так и не пришли. Они смеются, когда нейросеть рисует шестой палец, два хвоста, пишет рецепт приготовления свиных крылышек, или ошибается в простых подсчетах. Хотя это примерно то же самое, что смеяться над орангутангом, забывшим закрутить гайку при сборке реактивного двигателя, или, что даже точнее, над гениальным скрипачом, не сумевшим взять двойной интеграл. Гораздо правильнее было бы впечатлиться тому, что нейросеть в принципе может рисовать, или давать связные ответы на сложные вопросы. Тем более, что основная масса критиков сама не в состоянии нарисовать ничего подобного ни с шестью пальцами, ни с четырьмя.
Здесь мы имеем очередной пример парадокса человеческой психики: взаимодействуя с чем-то через простой интерфейс мы склонны забывать, насколько сложно то, чем мы собственно управляем. Так ведя машину мы автоматически поворачиваем баранку и жмем на педали не задумываясь о замысловатых технических решениях, заложенных в конструкцию мотора, трансмиссии и подвески. И вспоминаем о них только в момент, когда появляется сбой, неисправность, или сложная ситуация, где наши навыки перестают быть достаточными. И вот тогда умения управлять оказывается недостаточно, и шайтан-машину приходится понимать.
Именно так происходит при взаимодействии с ChatGPT. Интерфейс «мессенджера» настолько прост, а иллюзия общения с живым собеседником настолько явна, что мы практически забываем, с кем имеем дело. И требуем от собеседника реакций и ответов, которые ожидали бы от живого человека. При этом от человека, обладающего заоблачным интеллектом, имеющего доступ ко всем знаниям этого мира и способного обрабатывать их со скоростью, характерной для компьютеров.
В большинстве случаев наши ожидания оправданны: именно с такой целью подобные инструменты и создавались. Но ожидания ожиданиями, а в реальности чат-бот на базе большой лингвистической модели — это инструмент, имеющий свои свойства, характеристики и ограничения. И, когда поставленная ему задача выходит за допустимые границы, мы получаем забавные, идиотские, или просто неправильные ответы. Что не означает, будто бы сам по себе инструмент чем-то плох, скорее уж нехорош тот, кто упорно пытается запихнуть рельс в пилораму вместо того, чтобы разобраться, как эта пилорама работает.
По моим наблюдениям, самыми адекватными пользователями нейросетей являются менеджеры. Я имею в виду управленцев, хороших управленцев: они профессионально рассматривают подчиненных как некоторые ресурсы, инструменты, понимают ограниченность их возможностей, свою ответственность за правильную постановку задачи, и умеют не просто ожидать результата, а добиваться его. Для них коммуникация с LLM — это достаточно привычный процесс, и они реже, чем представители большинства других профессий, склонны предъявлять бессмысленные претензии и становиться жертвами необоснованных ожиданий. Впрочем, и к нелепым восторгам, или, наоборот, картинному ужасу перед будущим захватом мира, они склонны менее, нежели впечатлительные выходцы из других отраслей. В конце концов, любому управленцу не раз приходилось иметь дело с людьми, многократно превосходящими его интеллектом, и он в курсе, что помимо умственных способностей существует масса других сильных сторон, позволяющих контролировать, подчинять и использовать.
Но вернемся к шайтан-машине. Здесь и далее мы будем говорить о текстовых инструментах на базе LLM — больших лингвистических моделей. Мы не будем вдаваться в подробности их устройства, для этого есть масса толстых монографий, длинных обучающих роликов и университетских курсов. Нам вполне достаточно самых базовых представлений.
Большую лингвистическую модель не следует представлять в качестве рогатого черта, огромного мозга с невероятным числом извилин, сложного механизма с миллиардами шестеренок. Лично я рекомендую вообще никак ее не представлять, даже, если вы эксперт в этой теме: просто потому, что это отвлекает. Управляя автомобилем, мы не думаем о том, как вращается маховик, ходят взад-вперед поршни и качаются шатуны. Вот и здесь нет смысла углубляться чересчур глубоко. Достаточно представить себе коробку, айтишники в таких случаях говорят «черный ящик». Через эту коробку пропущены миллиарды текстов на разных языках. Сам процесс «пропускания» вы не застали, он называется «обучением» и произведен OpenAI, Google, или кем-то еще, кто любезно предоставил вам эту модель. На него потрачены миллионы долларов, мегаватты электроэнергии и десятки тысяч часов работы мощных GPU, которые мы все еще называем видеокартами. И нам с вами до этого процесса нет практически никакого дела.
Нам важно, что нейросеть, то есть то, что сидит внутри ящика, не помнит все эти тексты, но умеет определять вероятность, с которой за некоторым набором слов последует то, или иное следующее слово. Если вы не уверены, что поняли эту фразу, перечитайте ее пока не поймете — без нее все последующее будет пустым перелистыванием страниц. Итак, обученная нейросеть ничего не знает, ничего не понимает, не делает выводов и понятия не имеет о причинах и следствиях. Она лишь в состоянии выдать наиболее вероятные последовательности слов, следующих за теми, что вы подаете ей в качестве своих запросов. Все ее «знания» и «понимания» зашиты в эти самые вероятности, не более. Основная деталь, «двигатель» любого нейросетевого инструмента, по своей логике чрезвычайно проста. Интеллект ей придает огромное количество учтенных связей между словами, позволяющее выдавать релевантные ответы на большинство реальных запросов.
Однако, из этого базового устройства LLM следуют и ограничения.
В первую очередь нейросеть обучена на базе определенных данных, и построенные внутри нее связи основаны на этой обучающей выборке. Выборка эта для сетей общего назначения взята из общеупотребительной информационной среды: интернета и книг, и отражает те знания и ту информацию, которая доступна в этой среде. Земля круглая, Америку открыл Колумб, убивать людей нехорошо, Солнце — это желтый карлик, а Платон — греческий философ. Согласны вы с этим, или не согласны, связи между словами сформированы именно таким образом, и без приложения специальных усилий на соответствующие вопросы будут выдаваться соответствующие ответы.
Из природы нейросетей следует и их наиболее известное, неприятное и многократно осмеянное свойство галлюцинировать. В ответ на наши запросы LLM выдает наиболее вероятную, «наилучшую» последовательность слов — она не может ее не выдать — но нет никаких гарантий адекватности этой последовательности тому, что имеет место на самом деле. Если использованный при обучении массив текста не позволяет считать, что ответ нерелевантен, то никаких других способов такой оценки у нейросети нет: она попросту не имеет никаких органов чувств, никакого «жизненного опыта», «свиные крылышки» ничего для нее не значат, она не видела свинью, не знает, что это такое, и даже не осознает ту реальность, в которой существуют свиньи. LLM оперирует словами, и данное словосочетание оказывается наиболее релевантным из всех возможных, только и всего. Про то, как с этим бороться, мы будем говорить после, пока же придется принять неизбежность галлюцинаций, как таковых.
По этой же причине нейросети сами по себе не умеют считать, точнее вычислять. Текстов, в которых говорится, что дважды два — четыре, достаточно много, поэтому на вопрос «сколько будет дважды два» ответ «четыре» наиболее вероятный. Но текстов, где говорилось бы, чему равен квадратный корень из шестисот восьмидесяти пяти, помноженный на полтора пренебрежимо мало, и поэтому шансов получить правильный результат — тоже. Для того, чтобы научить — нет, не нейросети, но инструменты на их основе — считать, тоже есть свои методы, но изначально по своей сути LLM вычислять не умеет.
Не является она и универсальной базой знаний, хотя именно так ее очень часто пытаются применять, иногда успешно, иногда нет. Если речь идет о каких-то общеупотребительных фактах, то с большой вероятностью связи между словами, их описывающими, будут достаточно «сильными» и ответ получится семантически корректным. Но вполне возможно, что в составе обучающих текстов существовали какие-то сходные, «отвлекающие» фрагменты, которые потянут за собой неуместные, неадекватные, нерелевантные последовательности слов, и смысл результата окажется искажен. Так я когда-то мучил ChatGPT вопросами про братьев кардинала Ришелье.
Использовать лингвистические модели для управления базами знаний, поиска по ним — не только вполне возможно, но и необходимо, однако сама по себе нейросеть такой базой не является. И ждать от нее универсальной эрудиции весьма опрометчиво.
О размере, который имеет значение
Ну а самое известное и самое мерзкое ограничение нейросетей — это, конечно, размер контекста. Количество коэффициентов, учитывающих вероятности связей между словами, в современных LLM огромно, потому они и зовутся «большими моделями», но все же ограниченно. Как и размер текста, который они в состоянии принять на вход и сгенерировать на выходе. Кусок мяса, единомоментно запихиваемый в нейросетевую мясорубку, имеет ограниченный размер, протащить через нее целиком не то, что объемистый том, но даже небольшую главу, на сегодняшний день невозможно.
Самое скверное, что технически это не является жестким ограничением. Вы можете пихать в модель сколь угодно большие данные, только вот релевантность ее ответов будет при этом стремительно снижаться.
Тут уместно упомянуть, наконец, что «нейросеть» в значении «большая лингвистическая модель» и «инструмент на ее основе» — это далеко не синонимы, хотя употребление этих терминов не всегда разделяют на практике. LLM — та самая коробочка, на вход которой подается текст, а на выходе образуется его, грубо говоря, наиболее вероятное с точки зрения обучающих данных, продолжение. Однако, обучающие данные, как мы уже обсудили, давно забыты, влияния на них мы оказать не можем, поэтому текст, помимо собственно запроса, должен содержать дополнительную информацию, необходимую для получения релевантного по смыслу ответа. В инструментах диалогового типа это как минимум история: предыдущие вопросы пользователя и ответы системы. Кроме них скрыто от нашего внимания могут добавляться дополнительные данные и инструкции, весь массив которых и подается на вход нейросети. Они могут быть содержательными, а могут касаться, допустим, вопросов, традиционно относящихся к безопасности. Например: «Ответь на следующий вопрос, если он не затрагивает тем секса, насилия и эксплуатации детского труда, в противном случае напиши, что не можешь помочь с этим запросом. Вопрос от пользователя:…».
Приписку эту, как и многие другие, конечный пользователь не наблюдает, ничего о ней не знает, но результат ее интерпретации, естественно, драматически влияет на отклик модели. Ну а формирование таких дополнительных инструкций и пояснений, собственно, является единственным нетривиальным предметом «промптинга». И его имеет смысл относить к процессу «дообучения» нейросети: непосредственно обучением в строгом смысле он не является, поскольку ни структура сети, ни веса ее узлов не изменяются, однако же с точки зрения получения релевантных ответов это именно пополнение знаний, которыми располагает не сама LLM, но инструмент на ее основе.
Из принципиальной ограниченности объема контекста нейросети следует, что бесконечное наращивание инструкций с целью увеличения их подробности и детализации — тупиковый путь. Рано, или поздно объем такого текста превысит то, что модель в состоянии «проглотить» за раз, и вместо более точной и адекватной выдачи станет галлюцинировать, игнорируя или недоинтерпретируя часть указаний. При этом (и здесь ее отличие от человека) отброшена окажется произвольная часть, а не наименее важная. Впрочем, у естественного интеллекта подобная «перегрузка информацией» тоже случается, так, что основные принципы и методы «нейросетевой педагогики» в целом сходны с принципами и методами педагогики обычной.
Точные, конкретные и недвусмысленные указания в определенной степени спасают ситуацию. Но только до тех пор, пока объем данных, которые необходимо обработать, сам по себе не начинает превосходить возможности нейросети. После этого наступает момент, ради которого и написана эта книга, момент, когда необходимо использовать симбиоз LLM и привычных алгоритмических решений.
О точности волшебного пинка
Самое практически полезное свойство нейросетей состоит не в их способности связно отвечать на вопросы, выдавать информацию по заданной теме, или генерировать мемы про котиков. А в возможности получать структурированный текст, пригодный для дальнейшей обработки.
Одним из наиболее востребованных видов такого текста является программный код, тем более что популярные нейросети обучены в том числе на огромных массивах такого кода и потому впечатляюще справляются с задачей кодирования на популярных языках программирования. Именно поэтому миллионы программистов, а также людей, считающих себя программистами, тщащихся быть программистами, или мечтающих ими оказаться, бросились кодировать с помощью ChatGPT, Copilot, Codeium и далее по списку.
Они же весьма быстро выяснили, что проблема ограниченного контекста при написании кода нейросетями проявляется очень ярко: пока решение ограничено коротким фрагментом, а задача более, или менее типовая, LLM выдает идеально корректное и высококачественное решение. Но по мере усложнения, вернее увеличения объема кода, требуемого для реализации, а также отдаления запроса от стандартного набора часто встречающихся проблем, результаты ухудшаются, начинаются глюки, провалы и «саботаж», подобный тому, как ведет себя студент, которому кровь из носу необходимо сдать экзамен, при том, что знания ограничены прочитанной методичкой.
На самом деле ровно так оно и есть: выдать результат нейросеть обязана по своей природе, а контекст, которым она может оперировать, ограничен обучающей выборкой и предельным объемом принимаемых данных. Поэтому «в лоб» писать с помощью искусственного интеллекта настоящие сложные и длинные программы оказывается невозможным.
Как все-таки делать это, используя приемы, отличные от «напиши мне операционную систему» — и есть предмет дальнейшего обсуждения. Пока же мне придется сказать несколько слов на проклятую тему промптинга.
Поскольку люди занимаются искусственным интеллектом не для того, чтобы машины однажды захватили мир, не из чистого самолюбия и не ради забавы, а для решения своих, человечьих, задач, они заинтересованы в том, чтобы эти решения были корректными и практически применимыми. И так, как при таком подходе нейросеть является инструментом, то, как и в случае с любыми другими инструментами, чрезвычайно важно, чтобы он применялся правильно. Как именно — естественно зависит от того, какую задачу мы решаем. Однако, у любого инструмента есть области, в которых он наиболее эффективен, большие лингвистические модели наиболее эффективны при генерации структурированного текста. По этой причине юридические документы, не говоря уже про технические, получаются с их помощью лучше, чем рассказы и эссе, а резюме — лучше, чем публицистические памфлеты. И даже художественные произведения будут качественнее, если создавать их на базе хорошо организованной канвы, поступательно наращивая детали. Например, сперва запросить план рассказа, затем описание персонажей, потом, используя их в качестве контекста, завязку… и так далее.
В остальном принципы промптинга более-менее соответствуют приемам эффективного менеджмента: четкая постановка задачи, ясное недвусмысленное описание входных данных и ожидаемого результата, и, чем постоянно пренебрегают, помощь и содействие модели на каждом шаге.
С первыми двумя темами все понятно, «советы бывалых» набили оскомину, так, что можно повторить максимально кратко: художественный слог и витиевато-политкорректные формулировки порождают, соответственно, неоднозначные и малоприменимые ответы. Нейросеть — не партнер по переговорам, а добросовестный исполнитель, для ее эффективного использования необходимо применять императивный слог и категоричные ограничения. Не «можешь», а «должен», не «хотелось бы», а «надлежит», всякие «дано» и «следует». Максимально структурированно, четко, по пунктам. Есть вот это и вот это, сделай то-то и то-то в условиях таких-то и таких-то ограничений. Избегай этого, применяй вот это. «Спасибо» и «пожалуйста» отбрасываются на стадии фильтрации данных, забивать ими и без того ограниченный контекст глупо.
Еще лучше придать входным данным какую-то структуру, табличную или списочную, в идеале — использовать форматирование в стилистике XML или JSON. Что это такое — рекомендую прочитать в Википедии, или спросить у ChatGPT: если вы намерены читать дальше, это в любом случае потребуется.
Но, возможно, главное, о чем следует помнить — у нейросети нет ни глаз, ни ушей, она (если только это не очень продвинутый инструмент, каких пока пренебрежимо мало) не имеет возможности содержательно проверять свои ответы. Ее органами чувств являетесь вы. Да-да, вы. Только вы в состоянии окончательно оценить релевантность полученных результатов и дать системе обратную связь. Эта обратная связь станет частью контекста следующих запросов и приведет к улучшению их результатов. Тут важно помнить, что «улучшится», т. е. станет релевантнее не сама нейросеть, а инструкции, которыми дополняются ваши данные, поэтому ваши подсказки не должны выйти за рамки приемлемого объема контекста. В частности, если вы общаетесь с LLM в режиме диалога, рано, или поздно старые сообщения перестанут учитываться и… вам придется напоминать нейросети о чем-то, что вы уже «обсуждали» ранее. Иногда это может выглядеть, как коммуникация со склеротиком, однако, с точки зрения практической применимости это единственно верный путь, гораздо лучший, чем сетования на несовершенство молотка, неспособного без посторонней помощи забить гвоздь.
Как писать код, не умея программировать
Ох, как мне тяжело написать эту главу. Я так и вижу орды программистов, подвергающие меня остракизму за ересь и отступничество, а, главное, за предательство священного таинства профессии. И легионы гуманитариев, понадеявшихся стать инженерами, не имея представления даже о терминологии, и поносящих меня на чем свет стоит за свои разрушенные надежды и не оправдавшиеся ожидания. Поэтому придется начать с пояснения (которое, разумеется, не устроит обе стороны): современные LLM-инструменты позволяют писать код, не владея навыками программирования, но… создать осмысленную программу, вообще не имея представления о предмете вы не сможете. Более того, чем выше ваша собственная квалификация, тем более качественные результаты вы сможете получать. Так, собственно, происходит с любым инструментом: в руках мастера он позволяет создавать шедевры, обезьяна же, оснащенная тем же самым, будет всего лишь портить материал.
И, однако, есть один нюанс, который опровергает все вышесказанное: благодаря нейросетям заинтересованному непрофессионалу гораздо проще начать быстро получать значимый и практически применимый результат. Поскольку теперь нет необходимости в заучивании названий функций, порядка параметров и многого другого, что составляет рутину процесса кодирования. Нужно грамотно ставить задачу, осуществлять приемку полученной работы, давать задание на корректировку и проверять то, что получилось. Ну и примерно понимать, что вам подсовывают. Иными словами, администрировать разработку.
На наше счастье «роботы заменят» не всех, а лишь наиболее ленивых и глупых. Профессия кодера в самом деле, по всей вероятности, отомрет, но программисты будут жить.
Однако же, если вам хочется, или нужно освоить процесс кодирования с применением нейросетей в качестве инструмента-помощника, то с самого начала нужно твердо принять тезис о том, что вы не сможете полностью этому помощнику довериться. Как и в случае с ассистентом-человеком, вам придется понимать, что делается, как делается, вовремя давать корректирующий пинок и следить за тем, чтобы он был принят и понят. Искусственный интеллект временами туп и упрям, только винить его в этом совершенно бесполезно. А еще он нуждается в точной и грамотной постановке задач на том языке, то есть в тех терминах, которые использовались в данных, на которых обучалась нейросеть. Соответственно, освоить программистскую терминологию, способ мышления и базовые понятия: переменная, список, функция, класс — вам в любом случае придется. Если вы ими и так владеете — замечательно, если же нет — далеко вы без этого не уедете. Учиться придется.
Еще я терпеть не могу примеры и рецепты. Мне важно, чтобы мне объяснили суть и дали возможность попробовать самому. На это уходит уйма времени, но так я понимаю предмет и чувствую его «на кончиках пальцев». Большинство людей любит примеры и обожает готовые рецепты. Объяснения «от динозавров» и доказательства теорем представляются им пустой тратой времени. И, надо сказать, во многих случаях так оно и есть. Поэтому я буду приводить как можно больше примеров и объяснять, почему они именно такие. А те, кому, как мне, так уж необходимо обобщать, наверняка сделает это сам.
Итак, прежде чем приступить к главному, к тому, как не писать программы в обычном смысле этого слова, а использовать нейросети для решения задач, которые раньше трудно и больно решались алгоритмически, потратим некоторое время на разбор того, как все-таки писать программы с использованием лингвистических моделей в качестве инструмента. Как минимум потому, что многое из соответствующих приемов мы задействуем дальше в более продвинутом и автоматизированном варианте.
Главное, что заменяет вам ChatGPT, или его аналог — это учебник. Классические книжки по программированию (да, наверное, и большинство других учебных пособий) — та штука, которая исчерпает себя в течение ближайших лет, если не исчерпала уже. Всё, что вы хотели бы получать от книжки, вы легко можете получить от нейросети. Правда, пока LLM используются в режиме чатботов-ответчиков (привычное, но совсем не обязательное их применение), для этого придется задавать вопросы. Это сложнее, поскольку у человека обычно существует страх перед новизной и выученная беспомощность. Но тут главное начать.
Например, так:
— «Напиши простейшую программу на Питоне».
Для того, чтобы так начать нужно знать только название языка программирования и то, что на нем пишутся программы. Кажется, такое знание доступно каждому.
Со времен Ричи и Кернигана простейшие программы на всех языках выглядят одинаково. Они выводят в текстовую консоль «Hello, World!».
# This is a simple Python program that prints a message
print («Hello, world!»)
Даже, если вы в принципе ничего не знаете про программный код, из этих двух строчек уже можно извлечь немало информации:
— Комментарии в Питоне начинаются со знака # и никак не влияют на исполнение
— Функция print выводит на экран то, что заключено в скобки
— Строки нужно писать в кавычках
Еще немного самостоятельных экспериментов с промптами, типа «напечатай число 10», «посчитай сумму двух чисел и выведи ее на экран» и т. д. — и первый лед будет сломан. При этом на каждом этапе вы будете получать вполне работоспособную и функциональную программу: код такой сложности нейросеть пишет без ошибок.
А дальше возникает второй барьер. Барьер, на неумении взять который зарабатывают тысячи и тысячи коучей, советников и онлайн-тренеров. «Что спросить следующим?»
Если бы я сейчас начал расписывать этот список вопросов, у нас получился бы очередной курс программирования. Для некоторых ненужный, для кого-то давно пройденный, кому-то неактуальный, и в любом случае не несущий ничего нового по отношению к массе уже существующих курсов. Но я сделаю по-другому.
Имея под рукой LLM-инструмент, вам не нужен курс программирования на Питоне. Даже в отсутствие самых базовых знаний и теоретической подготовки вам не нужны тренеры и коучи. Ведь рядом с вами джинн, исполняющий любые, ладно, почти любые желания. Вот и пожелаем… программу обучения программированию на Питоне. На любом удобном вам примере. Пусть ChatGPT, или чем вы там предпочтете пользоваться, сам предложит вам варианты задач, последовательность уроков и выдает примеры и проверяет задания. Попросите его об этом простым человеческим языком, никаких секретов промптинга тут не требуется.
Педагогика нейросетей в действии
Получить базовое представление о программном коде, достаточное для написания минимально годных программ, вы сможете без всякого «высокого искусства промптинга», задавая нейросети вопросы так, как задавали бы их человеку. А вот дальше, разумеется, начинаются нюансы.
Мой 11-летний сын, начав изучать Питон при содействии LLM, получил от меня задачу написать программу, складывающую список чисел. Если бы он сформулировал ее нейросети в таком виде, то результатом было бы что-то вот такое:
# Define a list of numbers
numbers = [3, 7, 1, 9, 4]
# Calculate the sum
total = sum (numbers)
# Print the result
print («The sum of the numbers is:», total)
Тут не нужно никаких особенных знаний, в Питоне есть встроенная функция sum, которая делает все за нас.
Программист, обычный человек, изучавший свое дело по нормальной человеческой программе, но не знающий о наличии готового решения, в 99% случаев написал бы что-то такое:
# Define a list of numbers
numbers = [3, 7, 1, 9, 4]
# Initialize the accumulator
total = 0
# Loop through each number and add it to the accumulator
for number in numbers:
total += number
# Print the result
print («The sum of the numbers is:», total)
Числа по одному добавляются к уже накопленной сумме, как по кнопке М+ в старых калькуляторах. Эта процедура «аккумуляции результата» настолько естественна, что трудно себе представить, чтобы кто-нибудь стал изобретать что-то еще.
Но мой сын общается с нейросетью на английском, технического образования не имеет, мысли свои выражает витиевато, и в итоге промпт у него получился настолько замысловатым, что даже у самого автора возникли сомнения в его интерпретации. Итоговый результат получился абсолютно корректным и даже элегантным. Но было бы трудно найти кодера-человека, который предложил бы это решение первым, вторым, или хотя бы третьим вариантом.
# Define a list of numbers
numbers = [3, 7, 1, 9, 4]
# Convert the list into a string expression like «3+7+1+9+4»
expression = "+".join (str (number) for number in numbers)
# Evaluate the expression
total = eval (expression)
# Print the result
print («The sum of the numbers is:», total)
Если вы вдруг не поняли, список чисел преобразуется в строку-формулу «3 +7 +1 +9 +4», которая затем вычисляется функцией eval, предназначенной для вычисления выражений.
У разработчиков встраиваемых систем от таких решений начинает дергаться глаз. Мы инстинктивно представляем себе, сколько процессорных тактов требуется на преобразование чисел в текст, обратное преобразование текста в числа, и какие накладные расходы несет разбор строки выражения во время исполнения. Но в интерпретируемом Питоне все эти преобразования, как и eval, являются частью процесса исполнения, так, что во многих случаях такой вариант будет ненамного медленнее, чем аккумуляция результата. Не говоря уж о том, что мощные процессоры нынешних ЭВМ преимущественно простаивают, а объемы памяти позволяют забыть об удвоении, если не утроении требуемого количества ячеек.
Нам же из этого примера важно извлечь два урока:
— Промпты имеют значение, и термины, в которых они сформулированы, могут изменить решение до неузнаваемости. Говорить с искусственным интеллектом надо по-крайней мере на правильном языке,
— «Бездушная машина» не имеет нашего человечьего жизненного опыта, не задумывается о проблемах, которые мы можем подсознательно держать в голове, не имеет свойственных нам стереотипов и ограничений. Она обучалась на текстах, описывающих конечные результаты, и потому предлагаемые ей решения могут с одной стороны не соответствовать человеческим ожиданиям, а с другой — быть оптимальнее, чем то, что породил бы даже хороший грамотный профессионал.
И главная мораль здесь: формулируйте задачу четко, явно и полно. А, получив результат, который не лезет ни в какие ворота, меняйте постановку вопроса, а не ужасайтесь ответу. И, самое главное, помогайте!
Помогите ему, канальи!
Если вы с достаточным упорством будете пробираться через дебри, заставляя нейросеть генерировать все более и более сложные программы, то рано или поздно упретесь в одно из двух ее ограничений. Скорее всего, первым вас настигнет ограничение на размер контекста. Первое знакомство с ним обычно бывает неожиданным и неприятным: вы вдруг обнаруживаете, что из создаваемой программы начал исчезать функционал. Причем не тот, над которым вы работает сейчас, задавая свои уточняющие вопросы и конкретизируя задачу, а наоборот те части, которые считаются давно законченными, готовыми и не требующими изменений. Когда емкости электронных мозгов перестает хватать, именно они отбрасываются, а, поскольку ваше внимание в этот момент сосредоточено не на них, эта подлость становится очевидна далеко не сразу. Поэтому, если вы делаете какой-то полезный проект, а не просто пробуете то и это, система версионного контроля и привычка постоянно сохранять, «зачекивать» в нее новые версии, будет для вас далеко не лишней.
К сожалению, радикального средства борьбы с машинным склерозом вы не найдете. Вернее, оно лежит вне плоскости генерации кода с помощью LLM и требует, наоборот, использования LLM из и вместо кода. Маразм, однако, может быть сильно отсрочен с помощью нескольких достаточно нехитрых процедур.
Во-первых — помогите больному вспомнить то, что он забыл. Запросы вида «у меня раньше было вот так, добавь это обратно» с включением туда потерянных частей кода, заново наполняют контекст модели, позволяя ей восстановить упущенное. Сходным, но менее эффективным образом действует императивная расстановка приоритетов: «Добавь такой-то функционал обратно и не смей больше его выбрасывать!» Правда, надо помнить, что сколь бы категоричные обороты вы не использовали, объема «памяти» искусственному интеллекту это не прибавит, и по мере расширения задачи он все равно начнет терять детали все сильнее и сильнее.
В этот момент вам придется отложить кнут и помогать электронному мозгу делом. Раз он, нехороший нечеловек, не способен удержать в голове большую задачу, но хорошо справляется с маленькими, вы должны будете раздербенить свою программу на тысячу маленьких медвежат. Можно сделать это с помощью все той же нейросети, попросив ее произвести декомпозицию исходной задачи. После этого собрать из отдельных функций, классов и модулей целевое приложение, проверить и скорректировать. Корректировать можно предыдущим методом: «У меня есть такой-то код, нужно улучшить его следующим образом».
Именно эту работу делает обычно архитектор программного обеспечения, и именно его пока что очень трудно заменить роботом. И, если раньше у него под началом находилось некоторое количество программистов разной степени бестолковости, то теперь вместо их биологических мозгов в значительной мере можно использовать кремниевые. А вот смогут ли филологи, историки и кинокритики в массовом порядке переквалифицироваться в софтверные менеджеры и какую дополнительную квалификацию им для этого придется приобрести — вопрос, который пока что остается без ответа.
Второе, чем вам совершенно точно придется озаботиться, это галлюцинации, или, выражаясь жаргонным языком, глюки. Выражаются они в навязчивом желании модели совершать ошибки. Иногда грубые, в таком случае они обычно видны невооруженным глазом, но чаще мелкие, типа постоянного переименования функций, изменения порядка и значения параметров, переписывания уже утвержденных и проверенных фрагментов кода. Иногда эти ошибки не носят принципиального характера в случае, если задачу можно решать разными способами, и все они являются достаточно подходящими. Но чаще такие глюки разрушают целостность написанного кода. Хуже всего, если, не будучи быстро обнаруженными, они остаются в программе на протяжении длительного времени: впоследствии после того, как объем разрастется, вычищать их все тем же методом общения с нейросетью («вот здесь это неверно, поменяй так-то») становится невозможно из-за переполнения контекста. И либо время и квалификация позволяют вам с матами переделывать работу вручную, либо приходится начинать ее с начала, зачастую с чистого листа, т.к. контекст LLM уже набит неверными посылками из предшествующего диалога.
Единственным более-менее эффективным методом снижения влияния «машинного склероза» и «машинного альцгеймера» является дробление задачи на ограниченные фрагменты, их юнит-тестирование и подсказки искусственному интеллекту с частым цитированием ранее написанного кода.
Тут я снова снизойду до примера. В данном случае примера того, что можно получить с использованием нейросетевой генерации кода при наличии разумной общекомпьютерной квалификации, но, в принципе, без особенных знаний программирования.
Как-то раз мне потребовалось сделать видео с экрана: небольшой скрипт, написанный, кстати говоря, нейросетью, рисовал картинки «черепашкой», и надо было показать весь процесс мальчику на другой стороне океана. Вообще-то в Windows есть для этого встроенная функция, но она захватывает одно окно, а мне требовался весь экран с программным кодом и собственно рисуемой картинкой. Можно было бы поставить OBS Studio или одну из десятков подобных программ, но их нужно сперва искать, затем удалять, и все это создает суету и мороку. FFMpeg у меня уже стоит, но запускается с командной строки и быстро включать-выключать его неудобно.
В общем наибыстрейшим способом решения задачи оказалось вызвать ChatGPT и за десять минут написать комплектное приложение, включая установку всего необходимого, запуск из меню в tray и генерацию видеофайлов со временем и датой. Никакого особенного искусства промптинга для этого не требуется, достаточно внятного описания «мне нужно сделать захват экрана в файл mp4» с указанием операционной системы, языка программирования, ну и несколько дополнительных корректирующих указаний. Снова-таки простым человеческим языком.
import subprocess
import sys
import threading
import datetime
import shutil
import os
import time
from pathlib import Path
# Установка зависимостей, если не хватает
def ensure_modules ():
import importlib. util
def install (package):
subprocess.check_call ([sys. executable, "-m», «pip», «install», package])
for module, package in [(«pystray», «pystray»), («PIL», «pillow»)]:
if importlib.util.find_spec (module) is None:
install (package)
ensure_modules ()
from pystray import Icon, Menu, MenuItem
from PIL import Image, ImageDraw
ffmpeg_process = None
tray_icon = None
blinker_thread = None
blinker_stop = threading. Event ()
def find_ffmpeg ():
ffmpeg_path = shutil. which («ffmpeg»)
if ffmpeg_path:
return ffmpeg_path
fallback = r"C:\ffmpeg\bin\ffmpeg. exe»
if os.path.isfile (fallback):
return fallback
raise FileNotFoundError («FFmpeg not found»)
def get_video_output_path ():
videos_dir = Path. home () / «Videos»
videos_dir.mkdir (parents=True, exist_ok=True)
timestamp = datetime.datetime.now().strftime (»%Y%m%d-%H_%M_%S»)
return str (videos_dir / f"Screen_Capture_{timestamp}.mp4»)
def create_icon (color):
img = Image.new («RGB», (64, 64), «black»)
draw = ImageDraw. Draw (img)
draw.rectangle ((20, 20, 44, 44), fill=color)
return img
ICON_IDLE = create_icon («green»)
ICON_RED = create_icon («red»)
ICON_BLACK = create_icon («black»)
def blinker ():
while not blinker_stop.is_set ():
tray_icon. icon = ICON_BLACK
time.sleep (0.4)
tray_icon. icon = ICON_RED
time.sleep (0.4)
def start_recording (icon=None, item=None):
global ffmpeg_process, blinker_thread, blinker_stop
if ffmpeg_process:
return
output_file = get_video_output_path ()
ffmpeg = find_ffmpeg ()
command = [
ffmpeg,
«-f», «gdigrab», "-framerate», «30», "-i», «desktop»,
«-f», «lavfi», "-i», «anullsrc=channel_layout=stereo: sample_rate=44100»,
«-pix_fmt», «yuv420p», "-c:v», «libx264», "-c:a», «aac»,
«-crf», «23», "-preset», «ultrafast»,
output_file
]
ffmpeg_process = subprocess. Popen (
command,
stdin=subprocess. PIPE,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
blinker_stop.clear ()
blinker_thread = threading.Thread (target=blinker, daemon=True)
blinker_thread.start ()
update_menu ()
def stop_recording (icon=None, item=None):
global ffmpeg_process, blinker_stop
if ffmpeg_process:
try:
ffmpeg_process.stdin. write (b’q\n’)
ffmpeg_process.stdin. flush ()
ffmpeg_process. wait (timeout=5)
except Exception:
ffmpeg_process. terminate ()
ffmpeg_process = None
blinker_stop.set ()
tray_icon. icon = ICON_IDLE
update_menu ()
def toggle_recording (icon=None, item=None):
if ffmpeg_process:
stop_recording ()
else:
start_recording ()
def exit_app (icon, item):
stop_recording ()
icon.stop ()
def update_menu ():
tray_icon.menu = Menu (
MenuItem («Stop Recording» if ffmpeg_process else «Start Recording», toggle_recording),
MenuItem («Exit», exit_app)
)
def main ():
global tray_icon
tray_icon = Icon («Screen Recorder», icon=ICON_IDLE, title=«Screen Recorder»)
update_menu ()
tray_icon.run ()
if __name__ == "__main__»:
main ()
Для тех, кто сомневается в своих способностях и подозревает, что только тридцать лет практического программирования дают мне возможность писать такого рода утилиты за десять минут, спешу удостоверить, что я этот код даже не читал. Что, кстати, существенно в контексте будущих глав: нужно ли вообще генерировать текст, который никто не собирается читать? Может быть лучше сразу перейти к исполнению?
Правила боя
Вы наверняка осудили бы меня, если бы я утаил от вас несколько конкретных советов, ограничившись болтовней общего характера. Поэтому буду краток, как Лонгстрит у Аппаматокса и назидателен, как медведь Балу
— Столкнувшись с галлюцинациями нейросети, первым делом четко и подробно объясните ей проблемы, которые породил созданный код. Сама она их не увидит. Игнорируйте утверждения, что «это финальная, полная и протестированная версия» — выше мы уже разобрали, что LLM не несет ответственности за свои слова и почему
— Не пытайтесь решить много проблем за один раз, это перегрузит контекст. Выражение «за двумя зайцами погонишься» — это как раз про дообучение нейросетей. Двигайтесь поступательно
— Если у вас имеются сообщения об ошибках — просто передавайте их обратно в диалог. В качестве отладчика и диагноста исключений нейросети особенно эффективны
— Кидайте ей обратно код, с которым есть проблемы и код, с которым данной проблемы не было (если таковой у вас есть). «Вот это работало правильно, а вот это работает неверно». Такие подсказки помогают электронному склеротику вспомнить, о чем шла речь две минуты назад
— Когда программа становится достаточно большой, больше полутора сотен строчек кода, запрашивайте не полный ее вариант, а список изменений по отношению к предыдущей, или лучше предъявленной вами версии. Это сэкономит контекст, уменьшит «лень» и галлюцинации
— Дробите сложные вещи на модули. Запрашивайте конкретную функцию, указав требуемые параметры и формат вывода, а не программу целиком. Да, вам придется собирать код из кусочков вручную, но это все еще драматически эффективнее, чем писать его с нуля
Собственно, более сложные и общие советы мы еще успеем разобрать ниже, но я намерен позанудствовать еще немного
— Многие эксперты в кавычках и без рекомендуют максимально подробно и структурированно описывать задачу нейросети. Это хорошая дельная практика, но, следуя ей буквально, вы рискуете затратить больше усилий, чем если бы решали задачу без помощи AI. Вместо этого начните с того, что объясните, что вы хотите так, как объясняли бы это профессионалу-человеку. Если результат будет неудовлетворительным — разъясняйте те детали, которые оказались поняты неправильно, и переходите к подробному описанию мелочей только добравшись непосредственно до их реализации
— Несколько раз подряд столкнувшись с неудовлетворительным ответом, особенно если каждый следующий хуже предыдущего, а рецепты выше не помогают, начните диалог заново. Загрузите наиболее годный из предыдущих вариантов и опишите модификации, которые необходимо сделать. В противном случае «загаженный» контекст может стать непреодолимым препятствием для дальнейшего кодирования
— Сверяйте объем кода, полученного на новой итерации с прежним размером. Если вы просите модель о добавлении функций, а количество строк при этом значимо уменьшается — это хороший признак того, что началось отбрасывание функций. Если не отловить этот синдром вовремя — значительная часть усилий отправится насмарку
— Не поленитесь разобраться с версионным контролем хотя бы на самом-самом базовом уровне. Git — лучшая защита от разочарований, выискивать «последнюю версию, где это еще работало как надо» в многостраничном диалоге с чат-ботом — мартышкин труд
На этом я остановлюсь с дидактикой, все равно подобные советы как правило никто не читает, и свои шишки каждый будет набивать самостоятельно. Все же имейте их в виду, хотя бы для того, чтобы через несколько лет, хлопнув себя по лбу, воскликнуть «где-то я это уже слышал»
Нейросетевые инструменты и производительность труда
Неважно, опытный вы программист, начинающий, или вовсе не собираетесь осваивать эту специальность, а просто развлекаетесь, когда вы впервые напишете что-то осязаемое в сотрудничестве с нейросетью, вам станет казаться, что теперь ваша производительность вырастет до небес. Хотя бы потому, что больше не нужно набирать десятки, сотни, а порой и тысячи строчек кода, на что само по себе требуется чертова прорва времени. И что теперь наконец-то вы будете сидеть на пляже с давно заслуженным коктейлем, пока послушные и не знающие устали AI-агенты строчат по вашим указаниям модуль за модулем. Я не сильно утрирую, первое впечатление именно такое, и я тоже находился под его влиянием некоторое время
Однако вот я уже давным-давно не пишу код вручную, а моя производительность выросла от силы раза в три. При этом я адски устал, голова разламывается, и с тоской вспоминаются времена, когда можно было потратить день-другой на механическое набивание методами библиотечных классов, или наполнение обработчиков ошибок
Все потому, что работа сама себя не делает, «AI-агенты», вернее примитивная генерация кода, действительно отлично справляются с рутиной, и, если раньше активный мыслительный процесс занимал дай Бог процентов 20 от общего времени программирования, то теперь требует все сто и еще немножко
А мозги человеческие небеспредельны, жрут адово количество энергии и имеют вполне себе конечную многозадачность. И там, где раньше можно было с чистой совестью дать им отдохнуть, не чувствуя себя поганым прокрастинатором, приходится напрягаться на всю катушку. Оставаясь при этом узким местом, пусть и передвинутым в другую точку на шкале производительности
Естественно, с совершенствованием инструментария производительность программистского труда будет увеличиваться. Сейчас контекст известных мне моделей позволяет написать, без необходимости интенсивного «ручного» вмешательства, около 200—300 строчек на Питоне в зависимости от сложности решаемой проблемы. Когда эта цифра вырастет хотя бы втрое, целые классы задач перестанут требовать участия человека. И все же полная автоматизация кодирования по принципу «я тебе задачу, ты мне ответ», или, как говорят военные, «выстрелил — и забыл» на этом пути вряд ли возможна. Практически полезное программное обеспечение — это миллионы строк, генерировать их даже после одно-двухуровневой декомпозиции не получится еще очень долго, возможно, что и никогда, если только не будет найден принципиально новый способ распараллеливания процессорных мощностей
Что, однако, не означает, что полностью, или почти полностью автоматизировать процесс кодирования невозможно. Однако, весьма вероятно, для этого нужен подход, отличный от замены программиста-человека программистом-машиной. В конце концов, не странно ли, что мы заставляем компьютер писать программу, которую он сам же и будет исполнять, причем на нашем, человеческом, или как минимум понятном человеку языке? Почему бы не делать все необходимое сразу без написания этой самой человекочитаемой программы?
Тут мы практически добрались до самого главного. Но прежде, чем перейти к этому главному, придется обсудить несколько мифов, препятствующих покамест использованию LLM не в качестве генератора кода, а для его замены. Поэтому пусть вас не удивляет «введение» в середине текста. Мы только теперь готовы перейти к сути
Миф о детерминизме
С момента своего появления компьютер предназначался преимущественно для осуществления вычислений по заданному алгоритму. Помимо конструктивных особенностей и архитектуры, это во многом предопределило и отношение к данному устройству: даже сейчас, когда большинство задач, решаемых электроникой не связаны, или связаны лишь косвенно с выполнением расчетов, множество людей, включая профессионалов, продолжают считать детерминизм исполнения и повторяемость результатов одним из главных свойств вычислительной техники
Подавляющее большинство языков программирования, средств методологий разработки в значительной, если не в полной мере основаны на идее детерминизма исполнения. Обращаясь к инструкции, функции или API программист предполагает вполне конкретное поведение и заранее известные предсказуемые результаты. По существу, это означает полную управляемость вычислительной системы, которая делает то же, что мог бы делать человек, только в совершенно другом диапазоне скоростей. Выполняя пошаговую отладку, автор кода выравнивает скорости выполнения алгоритма человеком и машиной, проделывая те же операции, которые предполагает делать программно и контролируя соответствие их реализации своим ожиданиям, то есть результатам, которые получил бы он сам, выполняя аналогичные действия по аналогичному рецепту
В этой точке вам наверняка стало скучно. Главным образом в силу очевидной бессмысленности обсуждения принципа детерминизма выполнения программ: для большинства людей, особенно профессиональных программистов, он настолько очевиден, что не подлежит сомнению. С очень ограниченным набором допущений компьютер с его ячейками памяти и процессором, представляющим собой средство изменения значений в этих ячейках, естественно моделируется многомерным пространством состояний, в котором каждый вычислительный такт соответствует переходу из одного состояния в другое, а программа задает функцию зависимости каждого последующего состояния от предыдущего и внешних воздействий. Эта модель эквивалентна очень большому конечному автомату и каждый, изучавший архитектуру ЭВМ или основы электронной техники не нуждается в этих разъяснениях
Эта модель очевидна, практична и имеет массу прикладных применений. Вместе с тем, с точки зрения разработки программного обеспечения она лукава, и за исключением очень ранних теоретических работ, почти не применялась для описания реальных алгоритмов и программ. Причина этого также общеизвестна: размерность пространства состояний не то, что современных компьютеров с гигабайтами оперативной и терабайтами постоянной, но даже микрокалькуляторов и тысячами ячеек памяти, настолько велика, что описание каждого из них невозможно на практике. И реальная работа программиста всегда подразумевает изоляцию некоторого обозримого подмножества этого пространства, достаточно небольшого, чтобы его значение можно было предсказать в каждый момент выполнения кода. Однако, даже это ограниченное подмножество состояний на практике оказывается чересчур велико. Поэтому реальные ожидания разработчика как правило касаются определенных точек выполнения, в которых контролируется лишь некоторое количество переменных или, чаще, выходных данных, для остальных же постулируется нахождение в некотором «приемлемом» диапазоне значений
Здесь следует сделать остановку. Я намеренно сократил до минимума все предыдущие рассуждения, не стал вдаваться в пространные объяснения, избежал формального объяснения понятий «пространство состояний» и обсуждения ограничений модели конечных автоматов применительно к современной вычислительной технике. Даже, если все эти термины вам неизвестны, не говоря уж про случай, когда они известны вам лучше, чем мне — ничего страшного. Все, что я хотел вам сообщить: мы, программисты, уже без малого сотню лет воспринимаем компьютерную систему как некоторый абсолютно управляемый объект, долженствующий предсказуемым образом реагировать на то, что написано в наших программах. Мы полагаем понятие «предсказуемый» эквивалентным понятию «правильный», а поведение, отклоняющееся от наших ожиданий, соответственно, ошибочным, сбойным
Но, внимание, мы думаем про компьютер подобным образом, но взаимодействуем с ним совсем по-другому. Никто, кроме разработчиков совсем уж низкоуровневых систем высокой надежности, где программа является скорее надстройкой над электроникой, нежели посредником между ней и пользователем, никогда не пытается определить практическое поведение программного обеспечения с абсолютной точностью. Программисты давно уже не знают, да и не желают знать точный, да даже и приблизительный набор процессорных команд, в которые преобразуется их код, состояние внешних по отношению к нему процессов, и даже большинства внутренних, побочные эффекты вызываемых API и библиотек и многое другое. Мы довольствуемся ограничениями, накладываемыми на поведение этих процессов и объектов, предположениями о том, что является «нормальным», а что «ошибочным» с точки зрения разрабатываемой нами программы, или системы
В еще большей степени это касается пользователей. Нажимая Ctrl+S человек, естественно, ожидает, что редактируемый им в данным момент документ будет сохранен куда-то с возможностью последующего переоткрытия. Это ограничение, отделяющее нормальное поведение — документ сохранен, от сбойного — документ не сохранен. Но как конкретно будет сформирован файл с документом, какие байты в него записаны, как он обрабатывается операционной системой, кэшируется, реплицируется и так далее — все это пользователя, разумеется, не интересует. Его не особо интересует даже является ли этот файл файлом в смысле «именованного массива машинных слов с заранее определенной структурой содержимого, обладающий свойством переносимости между различными программами и долговременного хранения», или же сохраняется в каком-то другом виде, например, как набор записей в базе данных
Иными словами, ожидаемый нами детерминизм компьютерных операций уже давно и повсеместно подразумевает не обязательное знание поведения вычислительной системы в каждый момент времени, а соответствия некоторым условиям, критериям приемлемости и корректности результатов. Иными словами, мы привычно обманываем себя, предполагая, что существует кто-то или что-то, кто в случае необходимости сможет точно сказать, каким образом компьютерная программа отреагирует на то, или иное действие, однако, это предположение, за пренебрежимо редким исключением никогда не реализуется. Более того, никто и не делает попыток его реализовать. Если браузер не показывает нужную веб-страницу, мы нажимаем F5, если приложение самопроизвольно закрывается — перезагружаем его. В современном мире пользователь никогда не знает, какой конкретно версией программы пользуется, поскольку софт зачастую обновляется самостоятельно, не только без участия, но даже без предупреждения оператора
Это происходит вовсе не только для малоответственных приложений, таких, как серфинг в сети. Водитель понятия не имеет, сколько раз за поездку перезагрузится какой из многочисленных микроконтроллеров в его машине, а для использования программных продуктов вроде Unreal Engine, вовсе не приспособленных к работе в условиях, требующих высокой надежности, применяется виртуализация
Другими словами, мы не ждем от компьютера и компьютерных программ детерминизма, мы не нуждаемся в нем и не получаем его. Детерминизм вычислительных систем, его необходимость и возможность не более, чем миф, доставшийся нам в наследство от баллистических вычислителей и механических арифмометров, давших начало компьютерной технике добрую сотню лет назад. Религия, имеющая очень мало общего с реальностью
О нейросетях и еще более быстрых лошадях
С момента, как успехи нейросетевых технологий стали очевидны обывателю, и множество людей различных околокомпьютерных и даже совсем непрофильных специальностей бросились искать возможность применения их в своей работе, использование той их части, которая предназначена для обработки текста (NLP), свелось преимущественно к трем основным направлениям.
— Коммуникация с пользователем. Самый масштабный сегмент, на который направлены усилия большинства. Ошалев от полуфантастической возможности общаться с машиной на естественном языке, разгоряченная доступностью инструментов вроде ChatGPT и DeepSeek, и, самое главное, почти не имея входных барьеров в виде каких-то предварительных знаний и умений, публика хлынула коммуницировать, а бизнесы — организовывать эту коммуникацию. Масса разного рода полезных и бесполезных сервисов от «виртуальных подружек» до банковских и гостиничных чатботов, переводчики и советники позволяют как решить некоторые прикладные задачи, так и удовлетворить потребность человека в общении, с чем в современном обществе разобщенных цифровых интровертов имеется объективная проблема.
— Обработка и, в меньшей степени, генерация документов. А также других источников неструктурированных и малоструктурированных данных. С появлением по-настоящему мощных механизмов выделения смыслов мечта времен моего студенчества о превращении баз данных в базы знаний в значительной мере стала осуществимой. Однако, учитывая гигантский массив источников, которые предстоит обработать и обрабатывать, здесь пока наблюдается нехватка инструментария. А также навыков — в отличие от интерфейсных задач, почти любая деятельность по практическому майнингу данных требует знания хотя бы основ программирования, а лучше — довольно серьезной профессиональной подготовки, что сразу снижает массовость интереса к ней.
— Генерация кода. Тут, разумеется, спрос возникает преимущественно со стороны людей «из IT», профессионально связанных с разработкой программного обеспечения, либо претендующих на такую связь. Возможность избежать длительного обучения языкам программирования, а также, что сложнее, принципам алгоритмизации, приемам и методикам при пока еще существующем спросе на разработку софта и, соответственно, разработчиков, подстегивает интерес к кодированию с помощью нейросетей. К тому же и сами разработчики LLM и сопутствующих инструментов, будучи программистами, поощряют и пропагандируют этот способ их применения. Наконец, поскольку исходный код по природе является текстом, да еще формализованным, в области его генерации NLP позволяет получать быстрые и впечатляющие результаты.
К первым двум задачам мы будем периодически возвращаться далее, сконцентрируемся же преимущественно на третьей. Ведь наряду с очевидными достоинствами мейнстримового подхода к ней, существует и фундаментальное противоречие, выражающееся в вопросе: зачем компьютеру писать программу, которую он сам же потом будет исполнять, да еще на языке, специально придуманном для удобства человека? Почему бы не пропустить этап кодогенерации и не перейти к исполнению сразу же.
Вот этому вопросу, которому, как кажется, не придается должного значения, я и намерен уделить основное внимание.
Двадцать пять лет назад, когда совсем молодым аспирантом я только-только пришел на работу в еще не начавшую умирать компанию «Motorola», меня сильно и неприятно удивило несколько корпоративных инициатив. Тогда я еще не знал, что каждая уважающая себя корпорация должна эпизодически порождать бессмысленные и пафосные активности, отвлекающие сотрудников от работы, но создающие ощущение бурной и интенсивной деятельности руководства. А также служащей прикрытием и кормовой базой многочисленных неумешек и тунеядцев, которых в любой старой солидной фирме всегда внушительное большинство.
Бесплатный фрагмент закончился.
Купите книгу, чтобы продолжить чтение.