
Привет, Хабр! На связи Лиза Плюснина — лингвист-разработчик чат-ботов. Я работаю с платформой JAICP — одним из продуктов Just AI для создания голосовых и текстовых ботов. Мы с командой регулярно сталкиваемся с необходимостью написания и тестирования паттернов на специфичном языке JAICP DSL — процесс регулярный, довольно монотонный и отнимает много времени.
Когда в компании проходило обучение по AI-агентам, мы воспользовались моментом и решили: хватит это терпеть, пора автоматизировать!
Так родилась идея создать AI-агента, который бы взял на себя написание паттернов и автотестов к ним. Рассказываем, как мы это сделали, с какими трудностями столкнулись и что из этого вышло.
Идея и задачи: зачем нам свой агент
Для начала поясним, лингвист-разработчик — это специалист на стыке лингвистики и программирования, который проектирует и создает диалоговые системы. Если обычный разработчик пишет код, то лингвист-разработчик «учит» бота понимать человека и поддерживать осмысленный разговор, используя специальные инструменты и языки.
При разработке диалоговых сценариев для чат-ботов мы отвечаем за то, чтобы бот корректно понимал пользовательские реплики. Мы описываем возможные формулировки реплик и связываем их с нужными сценариями диалога. Для этого используются паттерны — конструкции, которые позволяют формализовать разные варианты фраз пользователя: от простых «да» или «привет» до более сложных формулировок.
В платформе JAICP паттерны описываются на собственном DSL — специальном языке, отличном от привычных инструментов вроде регулярных выражений. В JAICP уже доступен системный проект zb-common, который содержит в себе ряд универсальных и часто используемых паттернов, например именованный паттерн $agree состоит из стандартных фраз согласия.
Однако на практике часто возникают ситуации, когда возможностей стандартного системного файла zb-common недостаточно. Это может быть связано либо с отсутствием в нем терминологии заказчика, либо с необходимостью использовать уникальные фразы и сленг, характерные для конкретного бизнеса, которые не входят в общий набор шаблонов. В таких ситуациях разработчикам приходится самостоятельно писать фразы, а иногда и целые предложения, на DSL.
Написание паттернов — задача нетривиальная даже при хорошем владении языком.
На реальном проекте с турецким и немецким мы это прочувствовали: без помощника точно не справиться. Это не сложно, но монотонно и долго.
Например, для обработки стандартных реплик пользователя, таких как «да», «нет», «привет», «пока», принято писать паттерны. В реальной жизни пользователи не ограничиваются одним словом. Они могут написать и «добрый день», и «добрейшего дня» — сленговые фразы или диалектные выражения, о существовании которых разработчик может даже не догадываться. И все это — на разных языках. С такой проблемой мы и столкнулись на упомянутом выше проекте, языков у нас было 4, а формулировок еще больше. Вот пример некоторых из них:
Русский | Турецкий | Немецкий | Английский |
Мимо кассы | Tam hedefi vurmadı. | Daneben. | Missed the mark. |
Не в тему | Konu dışı. | Nicht zum Thema. | Off-topic. |
Вообще не то | Tamamen yanlış. | Überhaupt nicht. | Not at all. |
Промах | Iska geçti. | Fehlgriff. | Miss. |
Не то пальто | Hiç uymuyor. | Passt überhaupt nicht. | Not even close. |
Это фиаско | Bu tam bir fiyasko. | Das ist ein Fiasko. | This is a fiasco. |
Очевидно, что выражения вроде «не то пальто» нельзя переводить дословно на другие языки. В таких случаях подбираются смысловые аналоги — например, в английском это “Not even close”.
Однако, найти человека который будет владеть этими языками на достаточном уровне, чтобы переводить такие фразы — задача практически невыполнимая. Поэтому приходится самостоятельно разбираться: проявлять терпение, тратить время на анализ контекста и изучать особенности целевых языков.
Написание паттернов даже для простой группы фраз занимает время. Например, на описание приветствий для 20 фраз на русском языке у разработчика может уйти до часа.
Автотесты к таким паттернам теоретически можно сгенерировать скриптом — достаточно подставлять фразы в шаблон теста. Но и здесь полностью избавиться от ручной работы не получится. Сам скрипт нужно написать, отладить и поддерживать.
Кроме того, клиент обычно предоставляет лишь базовый набор фраз. Чтобы тесты действительно покрывали реальные пользовательские сценарии, разработчику приходится самостоятельно придумывать дополнительные вариации нестандартных формулировок — сленг, разговорные формы, опечатки. И каждую такую фразу нужно пропустить через скрипт еще раз.
Получается, что даже с частичной автоматизацией разработчик тратит время на механическую работу, а мог бы заниматься действительно сложными задачами.
Конечно, можно было бы просто обучить нейросеть писать паттерны и переводить их на другие языки, а не создавать целого агента. Но у такого подхода есть очевидные минусы:
Ограниченный контекст: каждый раз вводить LLM в курс дела — неэффективно.
Специфика DSL: языковые модели не знают наш внутренний язык для паттернов.
Отсутствие вариативности: модели склонны к шаблонным ответам.
Это просто неудобно для разработчиков: приходится переходить на сторонние сервисы, которые сейчас ограниченно доступны в России.
Поэтому мы решили пойти другим путем и создать собственного AI-агента, который понимает специфику нашего DSL, умеет генерировать паттерны и сразу писать автотесты к ним.
Архитектура и стек технологий
В качестве основной LLM-модели мы выбрали Claude Sonnet 4.5, так как на тот момент она лучше всего справлялась с генерацией кода на языке DSL, четко следовала промпту и писала код «без воды».
Нашему агенту были даны три инструмента:
Тул retrieveChunks — подтягивал релевантные фрагменты документации из базы знаний (Jay Knowledge Hub), чтобы агент мог опираться на готовые примеры и описания.
Тул generateAnswer — генерировал ответ на вопрос на стороне Jay Knowledge Hub, используя ту же базу знаний.
Тул Llm.sendRequest — обращался к LLM (GPT-4o-mini) для дополнительной самопроверки ответа модели и исправления ошибок.

На схеме показана общая архитектура агента. Но сами по себе инструменты еще не определяют его поведение — важно, как агент решает, когда и какой инструмент использовать.
Эту логику мы задали через промпт. Посмотрим, как он устроен.
Как работает агент: разбор промпта
Правильно составленный промпт — половина успеха. На Just AI Agent Platform удобный интерфейс написания промпта, разделенный на сегменты: роль, цель и инструкции.
Роль и цель мы описали в общих чертах, чтобы задать контекст. А вот инструкции мы описали подробнее, потому что именно они определяют, как агент будет действовать.

В текущую архитектуру можно было бы добавить дополнительные тулы/инструменты с прямыми обращениями к LLM: одно для генерации паттернов, а другое для генерации автотестов. Однако, качество промпта для агента позволило решить задачу силами одного лишь мозга агента — Claude Sonnet 4.5. Промпт был поделен на части:
Общая часть. Это своего рода предобработка запроса. Агент анализирует, что хочет пользователь, и решает, какой инструмент использовать.
Алгоритм работы:
Расскажи чем ты можешь помочь пользователю.
Проанализируй запрос пользователя и определи его тип.
В зависимости от типа, используй соответствующий тул.
Если тип неясен — уточни у пользователя.
Сегмент «Паттерны» — самый большой блок, который содержит:
Методологию: здесь мы описали этапы анализа текста (семантический, морфологический, синтаксический).
Инструменты: указали, какой тул вызывать, и дали базовые обозначения нашего DSL (например, [] — опциональные блоки).
Примеры: добавили несколько эталонных образцов, чтобы модель понимала, какой результат мы от нее ждем. Например: «не работает» → $not_working = (не работа* | сломал* | ошибк* | не функцион*).
В этот же сегмент мы включили набор правил, которые помогают модели строить оптимальные паттерны: объединять синонимы, использовать опциональные блоки, выстраивать иерархию паттернов и применять альтернативные конструкции DSL.
СТРАТЕГИЯ СОЗДАНИЯ ОПТИМАЛЬНЫХ ПАТТЕРНОВ: 1. СИНОНИМИЧЕСКИЕ ГРУППЫ: сразу группируй синонимы через
/- Вместо:(спасибо | благодарю | спасиб)- Используй:(спасиб*|благодар*)2. ОПЦИОНАЛЬНЫЕ БЛОКИ: выделяй необязательные части в[ ]- Вместо:(за помощь | помощь)- Используй:([за] помощ*)3. ИЕРАРХИЧЕСКАЯ СТРУКТУРА: строй логические уровни вложенности - Вместо плоского перечисления - Используй:((я|мне) (нужн*|необходим*))4. УМНЫЕ АЛЬТЕРНАТИВЫ: объединяй схожие семантические конструкции
В конце инструкции к этому блоку было добавлено задание «Теперь создай ОПТИМИЗИРОВАННЫЙ паттерн для фразы: текст пользователя». Слово оптимизированный выделено не просто так — на первых итерациях модель продолжала выдавать слишком буквальные паттерны (например, «спасибо|благодарю|спасиб»), вместо более гибких и коротких конструкций.
3. Сегмент «Автотесты». Этот блок значительно меньше: он содержит инструкцию по использованию нужного тула и пример готового автотеста.

4. Самопроверка. В конце мы добавили требование проверять сгенерированный код через Llm.sendRequest и убирать лишнюю разметку.
Такой детально проработанный промпт позволил нам не добавлять дополнительные инструменты и не усложнять архитектуру.
Проблемы и решения
На пути к такому агенту мы набили немало шишек. Вот основные проблемы, с которыми столкнулись.
Модели «своевольничают» и игнорируют инструкции
Поначалу модели часто игнорировали часть инструкций или трактовали их по-своему, опираясь на свои внутренние знания. Это приводило к тому, что паттерны генерировались с ошибками или использовали устаревшие конструкции, не соответствующие нашей документации.
Решение 1: мы явно разделили источники знаний и правила генерации. В качестве источника примеров и справочной информации агент использует базу знаний (Jay Knowledge Hub), где хранится документация JAICP и готовые паттерны. При этом все правила, ограничения и требования к синтаксису DSL заданы непосредственно в промпте. Так мы снизили самодеятельность модели и сделали генерацию более предсказуемой.
Решение 2: мы попросили другую LLM — в этот раз выбор пал на DeepSeek — оптимизировать наш промпт, которому должны следовать другие модели. Она проанализировала исходные требования и составила более четкий и структурированный промпт, который помог отсечь лишнее и повысить стабильность генерации.
Отсутствие вариативности
Модель часто генерировала однотипные конструкции, просто переставляя слова местами.
Решение: Чтобы добиться действительно разнообразных формулировок, пришлось вручную прописывать в промпте примеры использования синонимов, сленга и альтернативных синтаксических конструкций.
Трудности с многоязычностью
Модель неплохо справлялась с английским и русским, но на турецком или немецком начинала ошибаться в морфологии и пропускать важные словоформы.
Решение: проблему решили, добавив в промпт простую инструкцию: «Сначала определи язык запроса, а затем применяй специфические для него правила построения паттернов».
Еще более надежным решением этой проблемы могло бы стать наполнение базы знаний большим количеством реальных примеров на разных языках — тогда модель просто брала бы готовые паттерны и тесты, а не пыталась генерировать их с нуля. Однако такие доработки требуют значительных ресурсов и времени на сбор и разметку данных. В рамках этого проекта мы пошли по более прагматичному пути и решили большинство проблем за счет тонкой настройки промпта.
Что получилось в итоге
Агентская платформа позволяет легко интегрировать бота в различные каналы связи. Для удобства тестирования и отладки мы подключили бота к Telegram.

В результате мы получили бота, который:
По запросу пользователя генерирует паттерны на языке DSL и поясняет их структуру. Пользователь может отправить одну фразу, например «привет, как дела», а в ответ получить не только готовый паттерн, но и учтенную вариативность — «привет», «здравствуйте», «добрый день» и другие формулировки. Это оказалось особенно полезно для онбординга новичков.
Демонстрирует примеры фраз. Бот сразу показывает, какие именно фразы покрывает сгенерированный паттерн, показывая вариативность.

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

Жестких ограничений по обработке нетематических сообщений у нас не было, но бот следует своей роли и не выходит за рамки задачи:

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

А что по цифрам
Практическая польза стала очевидна почти сразу. Задача, которая раньше занимала несколько часов, стала выполняться за секунды.
Мы, конечно, все посчитали. Например, есть 20 фраз от клиента. Их нужно превратить в паттерны на четырех языках (русский, турецкий, испанский, английский), добавить вариативность и написать автотесты.
Ручная работа:
1 час на паттерны на русском.
Не менее трех часов на три других языка.
1 час на автотесты.
~1 час на придумывание вариаций.
Итого: минимум 6 часов монотонной работы, и это без учета последующих правок и неизбежных при ручной работе ошибок.
Также агент: справляется за 1 минуту, ускорение в 360 раз!
Конечно, финальный результат все еще требует проверки и возможной корректировки со стороны разработчика. Но даже с учетом времени на ревью, экономия времени остается очень заметной. Если вы тоже экспериментируете с агентами или автоматизируете свои задачи с помощью ИИ-агентов — будет интересно обсудить опыт в комментариях.
А если хотите глубже погрузиться в тему архитектуры агентов, RAG-подхода и интеграций, присоединяйтесь к нашему Telegram-комьюнити для разработчиков.
