Искусственный интеллект создаёт код по заказу пользователя
Искусственный интеллект создаёт код по заказу пользователя

Всем привет. Меня зовут Сергей и я руковожу разработкой автоматизации внутренних бизнес-процессов в рамках Центра управления процессами Московской Биржи.

В эпоху повсеместного распространения инструментов на базе искусственного интеллекта (ИИ) вопрос применения доменно-специфичных языков (DSL, domain specific language) вызывает неоднозначную реакцию. С одной стороны, большие языковые модели прекрасно понимают широкое многообразие естественного языка и могут работать напрямую с ним. С другой стороны, присущая любому человеческому общению неоднозначность оставляет простор для неправильных трактовок и ошибок.

Введение

Как отмечают многие исследователи, кодовые агенты наиболее эффективно работают в хорошо отстроенной системе ограничений. Ограничения могут быть мягкими, рекомендательными, как промпты и скиллы, так и жёсткими, например, компилятор или автоматическое тестирование. Задача разработчика при использовании ИИ сводится не столько к написанию кода, сколько к формированию качественного контекста и набора ограничений. Ручное тестирование и выявление ошибок кардинально увеличивает цикл обратной связи для ИИ-агента и должно применяться только в крайних случаях, когда цена ошибки слишком высока.

Мы в компании MOEX внимательно относимся к процессу разработки и рекомендациям службы информационной безопасности, чтобы предупредить последствия публикации некачественного кода. Это значит, что все наши проекты проходят проверки статическими и динамическими анализаторами кода, проходят композиционный анализ и тесты на проникновение. Со своей стороны мы делаем всё возможное, чтобы соответствовать положению 757-П Центрального Банка РФ «Об установлении обязательных для некредитных финансовых организаций требований к обеспечению защиты информации при осуществлении деятельности в сфере финансовых рынков в целях противодействия осуществлению незаконных финансовых операций».

Наиболее быструю обратную связь ИИ-агент получает от компилятора (интерпретатора) языка. Если мы хотим обеспечить строгую семантику критической части нашей логики, то есть проверенный способ построения доменно-специфичных языков на основе языков программирования общего назначения (GPPL, general purpose programming language). В статье рассмотрен подход по формированию типо-безопасного доступа к данным в условиях нестандартного интерфейса источника данных и его логических ограничений.

Каждый бэкенд-разработчик, работавший с реляционными базами, знает соблазн «просто собрать SQL-строку конкатенацией». Соблазн этот опасен: динамический SQL — классический вектор SQL-инъекций, и специалисты по информационной безопасности справедливо бьют по рукам за подобный код. Разбираемый в этой статье демо-проект [1] показывает элегантное решение: типо-безопасный DSL на базе библиотеки jOOQ, который превращает Java-код в SQL-запросы к резидентному хранилищу данных (In-Memory Data Grid, IMDG) вроде Apache Ignite, доступному только через кастомный REST-контракт. Ниже — разбор исторического контекста DSL, детальный анализ архитектуры проекта, аналогия с JPA (Java Persistence API) и взгляд на будущее DSL в эпоху ИИ-ассистированной разработки.

Исторические потребности и подходы к разработке DSL

Идея предметно-ориентированных языков не нова — она восходит к Lisp 1958 года, разработанному Джоном Маккарти, чья гомоиконность и макросистема позволяли встраивать мини-языки прямо в код общего назначения [2]. С тех пор DSL прошли путь от академических экспериментов до промышленного стандарта: SQL остаётся, вероятно, самым успешным DSL в истории, специализированным исключительно на манипуляции данными [3].

Классическая методология разработки DSL, зафиксированная ещё в работах по предметно-ориентированному программированию, включает три фазы [2][4]:

  • анализ — определение границ предметной области, сбор знаний экспертов, построение семантических нотаций;

  • реализация — создание библиотеки, воплощающей эти нотации, и компилятора/интерпретатора, транслирующего DSL-программы в вызовы этой библиотеки;

  • применение — написание и выполнение DSL-программ конечными разработчиками.

Исторически DSL делятся на внешние (со своим синтаксисом и парсером, как BNF (форма грамматики Бэкуса-Наура) или регулярные выражения) и внутренние — встроенные в синтаксис языка-хозяина через классы, методы и fluent-интерфейсы [5]. Второй подход резко снижает стоимость разработки: не нужен собственный парсер, IDE «из коробки» даёт автодополнение и проверку типов на этапе компиляции. Именно на этом принципе построены jOOQ, LINQ в .NET и Criteria API в JPA — все они реализуют внутренний DSL для построения запросов средствами языка общего назначения, избегая при этом уязвимостей текстовой конкатенации SQL. Ключевая мотивация подобных решений всегда одна и та же: изолировать разработчика от синтаксических ошибок и рисков инъекций, зафиксировав грамматику допустимых операций на уровне API [6].

К 2020-м годам интерес к DSL пережил новую волну — от финансовых расчётов до биоинформатики и низкокодовых платформ, а инструментарий для их создания расширился: ANTLR, Xtext, JetBrains MPS, встроенные метапрограммные возможности Kotlin и Scala [7]. Разбираемый ниже проект — характерный пример именно внутреннего DSL, решающего узкую, но болезненную задачу: безопасный доступ к нестандартному хранилищу данных.

Практический пример: DSL для IMDG на базе jOOQ

Постановка задачи и ограничения предметной области

В качестве примера возьмём структуру данных пользователей торговой системы Spectra срочного рынка Московской Биржи. Её контракт публичный и доступен для изучения всем желающим [17].

Проект jooq-dsl-demo [1] моделирует ситуацию, типичную для крупных финансовых и биржевых инфраструктур: данные хранятся в резидентной сетке (IMDG на основе Apache Ignite), доступ к которой предоставляется не через стандартный JDBC-драйвер, а через кастомный REST-эндпоинт /api/v2/queries/adhoc, принимающий SQL-текст в теле POST-запроса. Такая архитектура типична для Ignite: даже нативный REST API движка построен вокруг команд qryfldexe с SQL-подобным синтаксисом, инкапсулированным в HTTP-запрос [8].

При этом IMDG предметной области накладывает существенные ограничения на диалект SQL [1]:

  • отсутствует Data Definition Language (DDL) — схему нельзя изменить средствами SQL;

  • отсутствуют операции записи — INSERT, UPDATE, DELETE;

  • отсутствует поддержка JOIN между таблицами в SELECT-запросах;

  • имена «таблиц» фактически являются полностью квалифицированными именами Java-классов, а не классическими SQL-идентификаторами.

Эти ограничения — прямое следствие природы Ignite как объектно-ориентированного in-memory хранилища, где «таблица» — это по сути кэш объектов одного типа, а не запись в нормализованной реляционной схеме [9][10]. Именно поэтому официальная документация Ignite явно предупреждает: SqlFieldsQuery поддерживает произвольный SELECT, но объединения между кэшами требуют явного префиксирования именами кэшей, а не стандартного JOIN-синтаксиса [10].

Аналогия с JPA: разделение модели, транспорта и языка запросов

Архитектура DSL-доступа к IMDG через jOOQ
Архитектура DSL-доступа к IMDG через jOOQ

Схема архитектуры демо-проекта наглядно показывает три слоя: DSL-код на Java, runtime jOOQ, транспортный адаптер к REST и сам сервис IMDG. Разработчикам, знакомым с Java Persistence API, архитектура проекта покажется узнаваемой. JPA и Hibernate решают концептуально ту же задачу — дать разработчику безопасный, типизированный способ работать с хранилищем данных, не обращаясь к «сырому» SQL напрямую. Сопоставление слоёв даёт наглядную аналогию.

Слой ответственности

JPA / Hibernate

jOOQ-DSL для IMDG

Объектная модель

@Entity, @Table, аннотированные поля класса

Классы USER, UserRecord, сгенерированные jooq-codegen-maven из XML-схемы

Источник схемы

Аннотации в коде или обратная генерация из БД

Файл user-table.xml в формате information_schema, созданный вручную/через LLM из JSON-ответа сервиса

Транспортный слой

EntityManager + JDBC-драйвер

RestMockDataProvider, реализующий MockDataProvider и подменяющий JDBC-соединение HTTP-вызовом

Язык запросов

JPQL, Criteria API

DSLContext.select().from().where()— типобезопасный fluent DSL jOOQ

Контроль допустимых операций

Ограничения диалекта JPQL, каскады, @Transactional

ReadOnlyExecuteListener и NoJoinVisitListener — явные проверки AST-запроса

Центральная идея обеих экосистем — отделить бизнес-код от деталей транспорта и синтаксиса запроса. В JPA это достигается через EntityManager, который абстрагирует JDBC; в разбираемом проекте эту роль исполняет класс RestMockDataProvider, реализующий интерфейс MockDataProvider из тестового набора jOOQ [1]. Он подключается к MockConnection, которая реализует java.sql.Connection, поэтому весь остальной код — конфигурация DSLContext, построение запроса — работает так, будто использует настоящий JDBC-драйвер, хотя фактически SQL-текст, полученный из AST после inlineSql(), отправляется HTTP-клиентом в теле JSON-запроса на REST-эндпоинт сервиса.

Конвертация метаданных сервиса в XML-схему для jOOQ

Ключевой инженерный трюк проекта — обратная разработка (reverse engineering) схемы данных. Поскольку сервис не предоставляет стандартного механизма получения DDL, мы конвертируем метаданные ответа сервиса в формате JSON (файл user-data.json) в XML-описание таблицы user-table.xml, соответствующее XSD-схеме jooq-meta [1]. Указанная трансформация JSON → XML выполнена с применением LLM-модели [1] — то есть уже на этапе разработки инструмента искусственный интеллект использовался как ассистент кодогенерации метаданных.

Файл user-table.xml описывает каталог default, схему public и единственную таблицу user с двадцатью одной колонкой типов TIMESTAMP, BIGINT, INTEGER, SMALLINT и VARCHAR, а также первичный ключ по полю login. Именно этот XML-файл читает jooq-codegen-maven, встроенный в сборку проекта, и генерирует на его основе Java-классы USER (метаданные таблицы) и UserRecord (типизированная строка результата) — аналог того, как Hibernate по аннотациям @Entity строит внутреннюю объектную модель. Разница в том, что в мире IMDG обратный путь короче: нет команды SHOW CREATE TABLE, поэтому схему нужно либо получать из документации сервиса, либо — как в этом случае — синтезировать её из примера ответа API, распознав типы значений и структуру полей.

Реализация ограничений: только чтение и запрет JOIN

Ограничения предметной области — отсутствие записи и джойнов — реализованы не как декларативные настройки, а как явные перехватчики (listener), встроенные в конфигурацию DSLContext через провайдеры jOOQ [1]:

  • ReadOnlyExecuteListener расширяет DefaultExecuteListener и в методе renderStart проверяет тип выполняемой операции (ExecuteContext.type()); если тип равен ExecuteType.WRITE, выбрасывается DataAccessException с сообщением о запрете INSERT/UPDATE/DELETE

  • NoJoinVisitListener расширяет DefaultVisitListener и в методе visitStart анализирует узлы AST‑дерева запроса; при обнаружении узла Clause.TABLE_JOIN также выбрасывается исключение, блокирующее компиляцию запроса до отправки на сервер

Оба перехватчика подключаются к DefaultConfiguration через DefaultExecuteListenerProvider и DefaultVisitListenerProvider соответственно — паттерн, типичный для jOOQ, где поведение библиотеки расширяется через слушатели жизненного цикла запроса, а не через модификацию генерируемого кода. Это принципиально отличает подход от «постфактум»-валидации SQL-строки регулярными выражениями: проверка происходит на уровне синтаксического дерева запроса, до его материализации в текст, что исключает как ложноположительные, так и ложноотрицательные срабатывания, характерные для парсинга готовой SQL-строки.

Third-party контракт REST API реализован в RestMockDataProvider.execute(): метод подставляет значения параметров прямо в SQL-текст (метод inlineSql), формирует JSON-тело с полем sql, отправляет POST-запрос на /api/v2/queries/adhoc через стандартный java.net.http.HttpClient и разбирает ответ, извлекая массив объектов из пути response.result в JSON. Далее полученные строки превращаются в jOOQ Result<Record> через вспомогательный DSLContext.newResult(), что позволяет использовать стандартный механизм result.into(UserRecord.class) для типизации итогового набора записей. Для локальной отладки без реального сервиса IMDG в проекте используется WireMock, эмулирующий REST-эндпоинт и возвращающий заранее подготовленный JSON-файл user-data.json [1].

В качестве развития инструмента можно рассмотреть доработку maven плагина кодогенерации, обеспечив возможность генерации кода из метаданных в формате JSON без промежуточного XML-представления.

Перспективы DSL в эпоху AI-ассистированной разработки

Использование LLM для генерации XML-схемы из JSON-примера в разбираемом проекте — не случайность, а симптом более широкой тенденции. Внутренние DSL традиционно были компромиссом между выразительностью внешнего языка и простотой встраивания в существующую кодовую базу; ограничение всегда заключалось в том, что написание самого DSL и правил его валидации требовало экспертизы и в предметной области, и в языковой инженерии одновременно [6].

AI-инструменты меняют это уравнение сразу в нескольких направлениях. Во-первых, LLM снижают порог входа в domain-анализ: там, где ранее аналитику требовались недели интервью с экспертами предметной области для формализации семантики (классический этап анализа в методологии DSL [4]), сейчас модель может за минуты предложить первичную схему данных на основе примеров вывода системы — именно так был получен user-table.xml из user-data.json в разбираемом проекте. Во-вторых, LLM способны генерировать сам код DSL-обёртки — классы записей, конфигурации RenderMapping, перехватчики валидации — по текстовому описанию ограничений домена, ускоряя фазу реализации.

Более глубокая перспектива касается роли DSL как «контракта» между человеком и AI-агентом, генерирующим код. Строго типизированный внутренний DSL, подобный jOOQ, естественно ограничивает пространство возможных ошибок AI-генерации: компилятор Java отклонит некорректный вызов select().from().where() на этапе сборки, тогда как ошибка в текстовой SQL-строке, сгенерированной LLM, обнаружится только в runtime или вовсе останется незамеченной до продакшена. Комбинация «AI генерирует вызовы DSL» + «DSL гарантирует безопасность на уровне типов и AST-валидации» — жизнеспособный паттерн для доверенной AI-кодогенерации в чувствительных доменах, включая финансовую инфраструктуру, где написан этот демо-проект.

Одновременно ограничения текущих LLM создают новые требования к дизайну DSL: языки и API должны быть спроектированы так, чтобы модели было легко их «понимать» и корректно применять — с предсказуемой, консистентной сигнатурой методов, богатой типизацией и минимумом неявных побочных эффектов. Это созвучно классическим принципам хорошего DSL — минимализму и ясности синтаксиса [7] — но добавляет новый критерий: предсказуемость для statistical pattern matching, лежащего в основе генерации кода современными моделями.

Перспективы DSL для языков программирования вне Java

Хотя разбираемый проект реализован на Java, сама идея — типобезопасная обёртка над нестандартным транспортом данных с проверкой AST на этапе построения запроса — универсальна и переносима на другие экосистемы.

Экосистема

Аналог внутреннего DSL для запросов

Особенности переноса подхода

.NET / C#

LINQ (Language Integrated Query)

Компилятор C# нативно поддерживает выражения‑деревья (Expression Trees), что упрощает статическую валидацию запросов без сторонних библиотек

Kotlin

Exposed, Ktorm

Kotlin DSL-builders на основе lambda-с-receiver дают синтаксис, близкий к SQL, при полной типобезопасности

Scala

Slick, Quill

Богатая система типов и макросы Scala позволяют генерировать SQL на этапе компиляции, а не runtime

Python

SQLAlchemy Core, Django ORM QuerySet

Динамическая типизация ограничивает compile-time проверки, но допускает runtime-валидацию через AST-подобные объекты выражений

Rust

Diesel, SeaORM

Строгая система типов и трейты позволяют закодировать ограничения предметной области (например, «только SELECT») прямо в типах на этапе компиляции

Go

Squirrel, GORM

Отсутствие обобщений в старых версиях ограничивало выразительность DSL; начиная с Go 1.18 обобщённые типы приближают библиотеки к возможностям jOOQ

Для функциональных языков, как Scala, стоит отметить, что их экосистема традиционно предлагает наиболее развитый инструментарий для встроенных DSL благодаря выразительной системе типов, неявным преобразованиям (implicit conversions) и макросам, что делает библиотеки Slick и Quill естественным аналогом jOOQ для доступа к нестандартным источникам данных, включая REST-обёртки над Ignite или другими IMDG. Общий паттерн — «сгенерировать метамодель из схемы (реальной или восстановленной), обернуть транспорт в адаптер к стандартному интерфейсу платформы, добавить перехватчики для доменных ограничений» — переносим почти без изменений: в Rust роль перехватчиков могут взять на себя типы-обёртки (newtype pattern), запрещающие построение запроса с недопустимой клаузой уже на этапе компиляции, а в динамических языках типа Python — runtime-валидаторы AST, аналогичные NoJoinVisitListener.

Ключевой вывод для мультиязычных команд: чем более выразительна система типов языка, тем раньше — в идеале на этапе компиляции — можно перехватывать нарушения контракта предметной области, будь то запрет JOIN, запрет операций записи или иные бизнес-ограничения нестандартного хранилища данных. Это делает инвестиции в разработку внутреннего DSL оправданными именно для языков со статической типизацией и богатой системой типов — Scala, Kotlin, Rust, TypeScript — где безопасность, продемонстрированная в разбираемом Java-проекте, достигается «бесплатно» на этапе сборки, а не ценой дополнительных runtime-проверок.

Заключение

В статье описан метод борьбы с распространённой уязвимостью «Инъекция» в сетевых сервисах. По данным популярного рейтинга безопасности «OWASP Top 10» за 2025 год проблема инъекций, по-прежнему, занимает стабильное место в середине списка. С учётом взрывного увеличения количества кода, сгенерированного ИИ, решение проблем защиты усложняется в разы. Своей целью в MOEX мы видим постоянный поиск и применение новых технологий, но со зрячим контролем результата и нивелированием возникающих вызовов для информационной безопасности.


Источники

  1. GitHub — Unlocker/jooq‑dsl‑demo — исходный репозиторий с демо‑проектом DSL для доступа к IMDG через jOOQ (README, исходный код Java‑классов, user‑table.xml, user‑data.json,pom.xml) — github

  2. Domain Specific Language (DSL) Tools — методология анализа, реализации и применения DSL — 2006.secrus

  3. Apache Ignite Quick Start Guide, O'Reilly — Field based query — описание SqlFieldsQuery и ограничений SELECT‑запросов в Ignite — oreilly

  4. Концепция DSL и особенности практического применения — исторический и практический обзор DSL на русском языке  — rusnauka

  5. Apache Ignite.NET — Class SqlFieldsQuery (официальная документация)  — ignite.apache

  6. Apache Ignite — SQL API (официальная документация)  — ignite.apache

  7. Querying with Apache Ignite (LinkedIn, Soumya Jyoti Banerjee) — практический разбор SQL‑запросов в Ignite — LinkedIn

  8. GridGain Documentation — REST API — описание REST‑контракта для доступа к данным IMDG — gridgain

  9. How to run Apache Ignite SQL queries over a REST API — stackoverflow

  10. Создание DSL: как разработать собственный язык для специфической предметной области — it‑classic

  11. GridGain SDK Javadoc — SqlFieldsQuery (Collocated Flag) — gridgain

  12. Apache Ignite SQL query composed primary key.NET — stackoverflow

  13. Предметно‑ориентированный язык — Википедия  — ru.wikipedia

  14. Apache Ignite 3 Documentation — SQL API  — ignite.apache

  15. Example of SQL query — Apache Mail Archives — lists.apache

  16. When and how to develop domain‑specific languages — академическая работа о паттернах разработки DSL — dl.acm

  17. Plaza II Шлюз. Версия 9.6 — Публичный FTP Московской Биржи — ftp.moex.com


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


  1. ToxaBes
    02.10.2026 13:09

    Спасибо за статью, все так. Единственное, что хотел был добавить, относится к:

    сейчас модель может за минуты предложить первичную схему данных на основе примеров вывода системы

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

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

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

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

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


    1. unlocker Автор
      02.10.2026 13:09

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


      1. ToxaBes
        02.10.2026 13:09

        Отличительное свойство любой LLM -- это работа с вероятностями, что обратной стороной может дать нам галлюцинации

        Вы абсолютно правы в контексте современных моделей, и именно имаго подход вместе со строгой Pydantic валидацией решает этот вопрос.

        Пример для понимания, одна из моих доработанных по имаго моделей может разобрать 15-страничное pdf резюме кандидата в свободной стуктуре (HH, LinkedIn, итд - не важно) в строгий формат (json), без потери данных и галлюцинаций. Еще 1.5 года назад это было невозможно сделать и до сих пор это не может сделать нормально ни одна облачная фронтир модель. Потому что для таких задач нужна специализация в самой модели. И для ее работы достаточно какой-нибудь RTX 3090.

        Другими словами, большинство текущих модели это полуфабрикаты, а не готовые блюда (под конкретные узкие задачи).


        1. unlocker Автор
          02.10.2026 13:09

          Работа с большими языковыми моделями подкупает своей "универсальностью". Специально разработанные или глубоко тюненные модели -- это удел дата-саентистов. Разумеется, мы можем сделать специальную модель под конкретную узкую задачу, но это совсем другой процесс и стоимость вывода в бой. Недавно даже цифра попадалась, что стоимость обучения GPT-3 (1.7B параметров) составила 12-16 млн. долларов США, только на аренду видеокарт и серверов. Стоимость сбора обучающего набора мне не попадалась, но предположу, что цифра сопоставимая.

          "За неимением гербовой пишем на обычной", как гласит народная мудрость.


          1. ToxaBes
            02.10.2026 13:09

            Работа с большими языковыми моделями подкупает своей "универсальностью".

            Большие модели общего назначения не дают преимуществ в узких задачах потому что они общего назначения. Дообученная модель размером от 30B справится лучше, а жить может даже на видеокарте предприятия стоимость 400-800 тыр.

            стоимость обучения GPT-3 (1.7B параметров) составила 12-16 млн. долларов США, только на аренду видеокарт и серверов. 

            Вот тут сидит (пока что) главное непонимание по поводу моделей. Вы говорите о полном обучении модели с нуля. Зачем это делать если можно адаптировать существующую модель общего назначения?

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

            LoRA-адаптация как раз и смещает веса внимания в нужные стороны. Это и есть имаго подход, дать модели правильные привычки, общие знания у нее уже есть, а специфицеские знания лежат в RAG. Подробнее я писал об этом подходе тут.

            По стоимости там не миллионы долларов, зачастую даже не миллионы рублей (сужу по своей практике).

            Стоимость сбора обучающего набора мне не попадалась, но предположу, что цифра сопоставимая.

            От 2х недель до 2х месяцев работы ML-инженера.


  1. kreout
    02.10.2026 13:09

    Сергей, спасибо за содержательный разбор. Особенно ценно рассмотрение DSL как исполняемого контракта между предметной областью и ИИ-агентом: типизированная метамодель и проверки AST дают агенту конкретную обратную связь, а команде — воспроизводимый способ контролировать допустимые операции. Такой подход хорошо сочетается с развитием моделей: качество генерации может расти, при этом явно заданные ограничения сохраняют самостоятельную ценность.

    Интересно подробнее понять, как вы видите проверку самого контракта. Если исходная XML-метамодель восстанавливается из примера JSON-ответа, компилятор проверяет согласованность кода с этой моделью; соответствие модели реальному сервису требует отдельного подтверждения. Как бы вы организовали её валидацию и версионирование при изменении API — например, через контрактные тесты на nullable-поля, диапазоны значений и совместимость схем?