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

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

Почему новые языки могут сработать

Будет ли агент заметно лучше работать с языком, который представлен в его весах? Очевидно, да. Но есть и менее очевидные факторы, влияющие на то, насколько хорошо агент программирует на конкретном языке: насколько хорош окружающий его инструментарий и как часто сам язык меняется.

Zig, похоже, слабо представлен в весах моделей, по крайней мере в тех, которыми пользовался я, и при этом быстро меняется. Это не оптимальное сочетание, но с ним все еще можно жить: писать код можно даже на будущей версии Zig, если указать агенту на правильную документацию. Но идеальной эту ситуацию не назовешь.

С другой стороны, некоторые языки хорошо представлены в весах моделей, но агенты все равно не так успешны в работе с ними из-за решений, связанных с инструментами. Хороший пример — Swift: по моему опыту, инструментарий для сборки приложений под Mac или iOS может быть настолько болезненным, что агентам трудно в нем ориентироваться. Тоже не лучший вариант.

Так что сам факт существования языка еще не означает, что агент справится с ним успешно, а новизна языка не обязательно означает, что агент будет с ним мучиться. Я убежден: можно постепенно прийти к новому языку, если не пытаться менять все и сразу.

Главная причина, по которой новые языки могут сработать, состоит в том, что стоимость написания кода резко снижается. В результате широта экосистемы становится менее важной. Сейчас я регулярно выбираю JavaScript там, где раньше использовал бы Python. Не потому, что я его люблю или считаю его экосистему лучше, а потому что агент гораздо лучше справляется с TypeScript.

Логика здесь такая: если в выбранном мной языке не хватает важной функциональности, я просто показываю агенту библиотеку из другого языка и прошу его сделать перенос. Конкретный пример: недавно я написал Ethernet-драйвер на JavaScript, чтобы реализовать хост-контроллер для нашей песочницы. Реализации уже существуют на Rust, C и Go, но мне нужно было что-то подключаемое и настраиваемое именно на JavaScript. Оказалось проще попросить агента реализовать это заново, чем подгонять систему сборки и распространение под привязку к нативному коду.

Новые языки смогут прижиться, если их ценностное предложение будет достаточно сильным и если они будут развиваться с учетом того, как обучаются большие языковые модели. Люди будут пользоваться ими, несмотря на слабую представленность в весах моделей. А если такие языки изначально проектировать так, чтобы с ними было удобно работать агентам, то они, вероятно, будут опираться на знакомый синтаксис, который уже доказал свою пригодность.

Зачем вообще нужен новый язык?

Так зачем нам вообще может понадобиться новый язык? Об этом интересно подумать потому, что многие современные языки проектировались исходя из предположения: нажимать клавиши трудоемко, поэтому ради краткости мы пошли на определенные компромиссы. Например, многие языки, особенно современные, активно опираются на вывод типов, чтобы разработчику не приходилось выписывать типы явно.

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

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

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

Так что аргумент в пользу нового языка сводится к следующему: с учетом фундаментальных изменений в том, кто программирует и какова стоимость кода, нам стоит как минимум рассмотреть такую возможность.

Чего хотят агенты

Сложно сказать, чего хочет агент, потому что агенты будут вам врать, а еще на них влияет весь код, который они видели. Но один из способов оценить, как у них идут дела, — посмотреть, сколько изменений им приходится вносить в файлы и сколько итераций им нужно для типичных задач.

Есть несколько вещей, которые я заметил и которые, думаю, еще какое-то время будут оставаться актуальными.

Контекст без LSP

Протокол языкового сервера (Language Server Protocol, LSP) позволяет среде разработки на основе семантического понимания кодовой базы выводить информацию о том, что находится под курсором, или о том, что нужно предложить для автодополнения. Это отличная система, но у нее есть одна конкретная цена, неудобная для агентов: LSP должен быть запущен.

Бывают ситуации, когда агент просто не станет запускать LSP — не из-за технических ограничений, а потому что он тоже ленив и пропустит этот шаг, если без него можно обойтись. Если дать ему пример из документации, запустить LSP нормальным способом не получится: это фрагмент кода, который может быть даже не полным. Если указать ему на репозиторий GitHub и он скачает отдельные файлы, он просто посмотрит на код. Он не будет настраивать LSP, чтобы получить информацию о типах.

Язык, который не распадается на два разных опыта работы — с LSP и без LSP, — будет полезен для агентов, потому что даст им единый способ работы в гораздо большем числе ситуаций.

Фигурные, квадратные и круглые скобки

Мне, как Python-разработчику, больно это говорить, но отступы на основе пробельных символов — проблема. С точки зрения эффективности токенизации правильно обрабатывать пробелы непросто, а язык со значимыми пробельными символами сложнее для LLM. Особенно хорошо это заметно, если попытаться заставить LLM вносить точечные изменения без вспомогательного инструмента. Довольно часто модель намеренно игнорирует пробелы, добавляет маркеры для включения или отключения кода, а затем рассчитывает, что форматтер кода позже приведет отступы в порядок.

С другой стороны, фигурные скобки, которые не отделены пробелами, тоже могут создавать проблемы. В зависимости от токенизатора, цепочки закрывающих скобок могут разбиваться на токены неожиданным образом, примерно как в задаче с подсчетом букв в слове «strawberry». Поэтому LLM легко ошибиться в Lisp или Scheme: модель теряет счет тому, сколько закрывающих скобок уже вывела или сколько сейчас видит. Можно ли это исправить в будущих LLM? Конечно. Но и людям без инструментов с этим тоже было непросто.

Сквозной контекст, но явный

Я большой сторонник асинхронных локальных переменных и сквозного контекста выполнения — по сути, возможности переносить данные через каждый вызов, даже если эти данные могут понадобиться только много уровней ниже по цепочке вызовов. Работа в компании, занимающейся observability, особенно ясно показала мне, насколько это важно.

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

Один из подходов, с которым я экспериментировал, — это маркеры эффектов у функций, которые добавляются на этапе форматирования кода. Функция может объявить, что ей нужно текущее время или база данных, но если она не помечает это явно, по сути возникает предупреждение линтера, которое автоформатирование исправляет. LLM может начать использовать в функции что-то вроде текущего времени, и любой существующий вызывающий код получит предупреждение; форматирование распространит аннотацию.

Это удобно, потому что, когда LLM строит тест, она может точно замокать эти побочные эффекты: по сообщениям об ошибках модель понимает, что именно должна предоставить.

Например:

fn issue(sub: UserId, scopes: []Scope) -> Token
    needs { time, rng }
{
    return Token{
        sub,
        exp: time.now().add(24h),
        scopes,
    }
}

test "issue creates exp in the future" {
    using time = time.fixed("2026-02-06T23:00:00Z");
    using rng  = rng.deterministic(seed: 1);

    let t = issue(user("u1"), ["read"]);
    assert(t.exp > time.now());
}

Результаты вместо исключений

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

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

И, как в случае с предложенным автоматическим распространением контекстных данных, это может оказаться не тем решением.

Возможно, правильнее сильнее опереться на типизированные результаты, но с их компонуемостью все еще непросто, если в языке нет системы типов и объектов, которая это поддерживает.

Минимальные диффы и построчное чтение

Обычно агенты сегодня читают файлы в память построчно. Поэтому они часто выбирают фрагменты, которые пересекают границы многострочных строк. Есть простой способ увидеть, как это ломается: заставить агента работать с файлом на 2000 строк, в котором есть длинные встроенные строки с кодом — по сути, генератор кода. Агент иногда начинает редактировать внутри многострочной строки, принимая ее за настоящий код, хотя на деле это просто код, встроенный в строковый литерал.

Насколько я знаю, из языков с хорошим решением для многострочных строк можно назвать только Zig, но его синтаксис на основе префиксов для большинства людей выглядит довольно непривычно.

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

Сделайте код пригодным для поиска через grep

Что действительно хорошо в Go: в большинстве случаев нельзя импортировать символы из другого пакета в область видимости так, чтобы при каждом использовании они не были предварены именем пакета. Например, context.Context вместо просто Context. Есть обходные пути — псевдонимы импортов и импорты с точкой, — но они встречаются сравнительно редко и обычно считаются плохой практикой.

Это очень помогает агенту понимать, на что он смотрит. В целом, если код легко искать самыми базовыми инструментами, это отлично: такой подход работает с внешними файлами, которые не проиндексированы, и дает меньше ложных срабатываний при крупномасштабной автоматизации на основе кода, сгенерированного на лету, например при вызовах sed или perl.

Локальное рассуждение

Большая часть сказанного мной сводится к тому, что агентам очень нравится локальное рассуждение. Им нужно, чтобы работа раскладывалась на части, потому что часто в контекст у них загружено всего несколько файлов и они плохо представляют пространственную структуру кодовой базы. Чтобы что-то находить, они опираются на внешние инструменты вроде grep, поэтому все, что плохо ищется через grep или прячет информацию где-то еще, создает сложности.

Сборка с учетом зависимостей

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

Что агенты ненавидят

Макросы

Агенты часто испытывают трудности с макросами. Уже и так было довольно очевидно, что людям макросы тоже даются нелегко, но главный аргумент в их пользу обычно заключался в том, что генерация кода позволяет писать меньше кода вручную. Теперь это уже не так важно, поэтому нам стоит стремиться к языкам, которые меньше зависят от макросов.

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

Повторные экспорты и файлы-агрегаторы экспортов

Связано с пригодностью к поиску через grep: агентам часто трудно разобраться в файлах-агрегаторах экспортов (barrel files), и они их не любят. Если нельзя быстро понять, откуда берется класс или функция, это приводит к импортам из неправильного места, к полностью пропущенным сущностям или к пустой трате контекста из-за чтения слишком большого числа файлов. Прямое соответствие между тем, где что-то объявлено, и тем, откуда это импортируется, — это отлично.

При этом правило не обязательно должно быть чрезмерно строгим. Go отчасти идет в этом направлении, но без крайностей. Любой файл внутри каталога может определить функцию, что не идеально, но ее достаточно быстро найти, и искать приходится недалеко. Это работает потому, что пакеты вынужденно остаются достаточно маленькими, чтобы в них можно было все найти через grep.

Худший случай — свободные повторные экспорты повсюду, которые полностью отвязывают реализацию от любого места на диске, восстанавливаемого тривиальным образом. Или еще хуже — использование псевдонимов.

Использование псевдонимов

Агенты часто ненавидят ситуации, где задействованы псевдонимы (aliases). Более того, можно добиться того, что они даже начнут жаловаться на это в блоках рассуждений, если дать им рефакторить код с большим количеством псевдонимов. В идеале язык должен поощрять хорошие имена и, как следствие, не поощрять создание псевдонимов при импорте.

Нестабильные тесты и расхождение сред разработки

Никто не любит flaky-тесты, но агенты — особенно. Что иронично, учитывая, что сами агенты сейчас особенно хорошо умеют создавать нестабильные тесты. Причина в том, что агенты в нынешнем виде любят подменять зависимости через моки, а большинство языков плохо поддерживает такую подмену. Поэтому многие тесты в итоге случайно оказываются небезопасными при параллельном выполнении или зависят от состояния среды разработки, которое затем расходится со средой непрерывной интеграции (CI) или продакшеном.

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

Несколько условий отказа

В идеальном мире у агента есть одна команда, которая запускает линтинг, компиляцию и сообщает агенту, всё ли прошло успешно. Возможно, еще одна команда — чтобы запустить все тесты, которые действительно нужно запустить. На практике большинство сред устроены иначе. Например, в TypeScript код часто можно запустить, даже если он не проходит проверку типов. Это может сбивать агента с толку. Аналогично разные настройки сборщика могут привести к тому, что в одной конфигурации все успешно соберется, а в чуть другой конфигурации в CI позже упадет. Чем единообразнее инструментарий, тем лучше.

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

Увидим ли мы новые языки?

Думаю, увидим. Сейчас мы пишем больше программного обеспечения, чем когда-либо: больше сайтов, больше open source-проектов, больше всего. Даже если доля новых языков останется прежней, их абсолютное количество вырастет. Но я также искренне верю, что гораздо больше людей будет готово переосмыслить основы разработки ПО и языки, с которыми мы работаем. Дело в том, что еще несколько лет назад казалось: чтобы язык взлетел, нужно построить вокруг него большую инфраструктуру. Теперь же можно нацелиться на довольно узкий сценарий: сделать так, чтобы агенту было удобно, а уже оттуда расширяться к человеку.

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

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

Теперь же мы постепенно приходим к точке, где факты становятся важнее, потому что можно действительно измерять, что работает, наблюдая, насколько хорошо с этим справляются агенты. Ни один человек не хочет становиться объектом опросов, а агентам все равно. Мы можем видеть, насколько они успешны и где именно испытывают трудности.

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

  • 27 мая, 20:00. «Мифы про ИИ-агентов: что реально работает в 2026 году». Записаться

  • 15 июня, 20:00. «Интеграция ИИ-агентов в рабочую разработку: обвязка агента навыками и MCP». Записаться

  • 16 июня, 20:00. «Вайб-кодинг работает — но не всегда и не у всех». Записаться

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

Комментарии (6)


  1. schekinfs
    20.05.2026 18:14

    кажется новые языки уже не нужны, можно конечно это настругать из забавы, но для ИИ никакой разницы нету считай вообще, дело теперь не в языках, теперь в моделях :)


    1. forthuse
      20.05.2026 18:14

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

      P.S. У меня на роль такого языка по описанным критериям только “один” кандидат - проверенный временем язык из конкатенативной (цепочечной) группы https://concatenative.org - Форт (Forth) или возможно Factor, 8th …, в целом кто эволюционно покажет свою состоятельность, как когда то Фортран язык “закрыл” тему математических вычислений и породил своих последователей, хотя раньше был Алгол. т.е. время и решаемые технологические задачи могут вывести вчерашних “аутсайдеров” вновь в лидеры из их ниши в широкое “поле” … ИИ от гугла, к примеру, уже “затачивается”, как подозреваю на “это” без афиширования проводимых исследованний (сужу по выданной “сентенции” диалога им, при вопросе показать направление “своих” “фантазий” - это было сильно!)


      1. forthuse
        20.05.2026 18:14

        P.P.S. Проверьте такое суждение на правильность своими ИИ, и отпишитесь по выводам, что так или не так в нём, если не лень. :)


  1. st---v
    20.05.2026 18:14

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


    1. Yevgeny_VS
      20.05.2026 18:14

      Это всё прекрасно, только не забывайте, что чтобы освоить язык, LLM должна поглотить огромное количество написанного на нём кода. Откуда он возьмётся?


  1. Dhwtj
    20.05.2026 18:14

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

    Вайбкодьте на раст!