Инструменты
Ассистент не обращается к базе данных или внешним системам напрямую. Вместо этого он работает через серверные инструменты. Дополнение включает набор предопределенных инструментов, а также позволяет добавлять собственные и переопределять существующие.
Предопределенные инструменты
В дополнение входят предопределенные инструменты, которые ассистент может вызывать от имени пользователя. Они сгруппированы по назначению, и каждая группа описана в отдельном разделе ниже. На данный момент дополнение предоставляет одну группу: инструменты Data Load.
Инструменты Data Load
Инструменты Data Load позволяют ассистенту отвечать на вопросы о данных приложения.
Процесс загрузки данных
Инструменты Data Load реализуют процесс загрузки данных по запросу на естественном языке. Когда пользователь запрашивает данные, ассистент обычно проходит следующие шаги:
-
Discover — получить список сущностей, доступных пользователю, и проанализировать нужные из них, включая атрибуты, связи и перечисления.
-
Generate — сформировать JPQL-запрос только для чтения с именованными параметрами.
-
Validate — проверить запрос по доменной модели и набору правил, включая режим только для чтения, синтаксис, известные сущности и атрибуты, поддерживаемые конструкции даты и времени и пагинацию.
-
Repair — если валидация не прошла, попросить модель исправить запрос и повторно его провалидировать, не более заданного числа попыток.
-
Execute — выполнить запрос через
DataManager, применить права доступа к сущностям и атрибутам и вернуть страницу строк.
Все шаги выполняются на сервере. Запрос всегда представляет собой SELECT только для чтения. Операции записи и обходы через native SQL отклоняются на этапе валидации, а при выполнении дополнительно применяются права текущего пользователя на чтение. Запрос к сущности, которую пользователь не может читать, будет отклонен, а атрибуты, недоступные для чтения, будут исключены из возвращаемых строк, так же как dataGrid скрывает колонки, привязанные к нечитаемым атрибутам. В обоих случаях пользователь не получает данные, к которым у него нет доступа.
Доступные инструменты
Этот процесс предоставляется модели в виде трех инструментов. Имя инструмента — это идентификатор, который модель использует для его вызова. Это же имя используется при переопределении инструмента.
| Имя инструмента | Назначение |
|---|---|
Возвращает краткие метаданные для каждой сущности, доступной пользователю в текущий момент: имя сущности, локализованные названия и имена свойств. Сущности, скрытые фильтрацией приложения или подсистемой безопасности, не возвращаются. Ассистент использует этот инструмент для анализа модели данных и получения корректных имен сущностей для последующих вызовов. |
|
Возвращает подробные метаданные для запрошенных сущностей: точные имена атрибутов, связи для |
|
Валидирует, при необходимости исправляет и выполняет JPQL-запрос только для чтения, возвращая результирующие строки. Параметры передаются как структурированный запрос, содержащий текст запроса, именованные параметры, имена результирующих колонок и информацию о пагинации. Результат содержит строки, признак наличия дополнительных строк, а также ошибки валидации или выполнения. |
Эти три инструмента объединены маркерным интерфейсом DataLoadAiTool, поэтому реестр может собирать их как одну группу. См. AiToolRegistry.
Управление доступной моделью данных
По умолчанию ассистент видит все JPA-сущности приложения, кроме сущностей фреймворка, так как пакеты io.jmix исключены, и сущностей системного уровня. Этот набор можно сузить или расширить с помощью свойств jmix.aitools.dataload.*.
Например, чтобы скрыть определенную сущность от ассистента и ограничить число строк по умолчанию для одного запроса:
# Hide the User entity from the AI
jmix.aitools.dataload.exclude-entities[0]=User
# Default number of rows returned when a generated query does not specify one
jmix.aitools.dataload.jpql-execution-max-result=50
Правила включения и исключения оцениваются для каждой сущности отдельно. Свойства exclude- скрывают сущности. Свойства include- включают сущности в набор по умолчанию, в том числе сущности, скрытые по умолчанию, например сущности фреймворка или системного уровня. При этом exclude-entities по-прежнему имеет приоритет над любым включением. Полный список параметров, включая ограничение числа строк, возвращаемых одним запросом, см. в свойствах Data Load.
| Фильтрация через конфигурацию меняет только набор сущностей, предоставляемых модели. Независимо от конфигурации каждый запрос все равно выполняется с учетом прав текущего пользователя на data access. Запрос к сущности, которую пользователь не может читать, будет отклонен, а атрибуты, недоступные для чтения, будут удалены из результата. Пользователь никогда не сможет прочитать данные, к которым у него нет доступа. |
Кастомизация доступности
Набор сущностей, предоставляемых модели, определяется через бин AvailableEntityFilter. Реализация по умолчанию скрывает сущности, на чтение которых у текущего пользователя нет прав. Чтобы изменить это поведение, например применить собственные правила видимости, зарегистрируйте свой бин, реализующий io.jmix.aitools.dataload.introspection.AvailableEntityFilter.
Настроенные сущности и их метаданные предоставляет бин AvailableEntityService, который можно использовать и в собственных инструментах. См. пример переопределения.
Пользовательские инструменты и реестр
Помимо предопределенных инструментов, можно добавлять ассистенту собственные инструменты и переопределять инструменты, поставляемые дополнением.
Создание инструмента
Инструмент — это Spring-бин, который:
-
реализует маркерный интерфейс
io.jmix.aitools.tool.JmixAiTool -
объявляет один или несколько методов с аннотацией Spring AI
@Tool
При запуске дополнение находит все такие бины, собирает их методы @Tool и делает их доступными ассистенту. Следующий бин добавляет инструмент, который возвращает каталог этапов онбординга:
@Component
public class OnboardingTools implements JmixAiTool { (1)
@Autowired
private DataManager dataManager;
@Autowired
private AiToolStatusPublisher statusPublisher;
@Tool(name = "getStepCatalog", (2)
description = "Returns the catalog of onboarding steps with their duration in days.")
public String getStepCatalog(ToolContext toolContext) { (3)
String message = "Loading the onboarding step catalog";
statusPublisher.update(message, toolContext); (4)
List<Step> steps = dataManager.load(Step.class).all().list(); (5)
statusPublisher.complete(message, steps.size() + " steps", toolContext);
return steps.stream()
.sorted(Comparator.comparing(Step::getSortValue))
.map(step -> step.getName() + " — " + step.getDuration() + " day(s)")
.collect(Collectors.joining("\n"));
}
}
| 1 | Реализация JmixAiTool помечает бин как источник инструментов. |
| 2 | Атрибуты name и description аннотации @Tool — это то, что видит модель. Описание должно объяснять, когда и как использовать инструмент. |
| 3 | Параметр ToolContext предоставляется фреймворком и не раскрывается модели. Он нужен только для публикации обновлений статуса. См. Публикация обновлений статуса. |
| 4 | Публикует обновление статуса о начале выполнения перед запуском длительной операции. |
| 5 | Загружает сущности Step через DataManager с учетом прав текущего пользователя на доступ к данным. |
Параметры метода становятся входной схемой инструмента. Чтобы добавить описания, аннотируйте их @ToolParam. Возвращаемое значение отправляется модели как результат работы инструмента.
Для объявления методов @Tool в classpath приложения должен присутствовать Model API из Spring AI. Стартер модели Spring AI, который вы добавляете в разделе Подключение модели, уже его предоставляет.
|
AiToolRegistry
io.jmix.aitools.tool.AiToolRegistry — центральный реестр всех инструментов, доступных в приложении. Он создается один раз при запуске на основе всех бинов JmixAiTool, после применения разрешения переопределений. Его методы:
| Метод | Описание |
|---|---|
|
Возвращает все итоговые инструменты в порядке регистрации. |
|
Возвращает инструмент, зарегистрированный под заданным именем, либо пустой результат. |
|
Возвращает инструменты, исходный бин которых реализует указанный маркерный подинтерфейс |
|
Возвращает объекты Spring AI |
Ассистент передает модели getAllCallbacks(), поэтому любой добавленный вами инструмент становится доступным автоматически. Больше ничего регистрировать не нужно.
Переопределение существующего инструмента
Чтобы заменить существующий инструмент, включая предопределенный, аннотируйте метод @Tool аннотацией @ToolOverride и передайте имя инструмента, который нужно заменить. Метод по-прежнему должен быть аннотирован @Tool и объявлен в бине JmixAiTool.
Следующий бин переопределяет aitls_getAvailableEntities и возвращает доступные сущности, отсортированные по их локализованному имени:
@Component
public class SortedEntitiesTool implements DataLoadAiTool { (1)
@Autowired
private AvailableEntityService availableEntityService;
@Tool(description = "Returns entities available to the user, ordered by localized name.")
@ToolOverride("aitls_getAvailableEntities") (2)
public List<EntitySummary> getAvailableEntities() {
return availableEntityService.getEntitySummaries().stream() (3)
.sorted(Comparator.comparing(this::firstLocalizedName))
.toList();
}
private String firstLocalizedName(EntitySummary summary) {
return summary.getLocalizedNames().isEmpty()
? summary.getEntityName()
: summary.getLocalizedNames().get(0);
}
}
| 1 | Реализация DataLoadAiTool оставляет переопределение в группе инструментов Data Load. Для инструмента, не связанного с загрузкой данных, реализуйте JmixAiTool напрямую. |
| 2 | @ToolOverride указывает имя заменяемого инструмента. Переопределение публикуется под этим именем, поэтому собственное имя @Tool у метода не имеет значения. |
| 3 | Повторно используется стандартный AvailableEntityService, поэтому переопределение по-прежнему учитывает фильтрацию сущностей и безопасность, меняя только порядок сортировки. |
Как работает разрешение переопределений:
-
Если несколько методов
@Toolсоздают инструмент с одним и тем же именем, выигрывает метод, помеченный@ToolOverride, а исходный инструмент исключается из реестра. -
Переопределение наследует маркерные интерфейсы заменяемого инструмента, поэтому поиск в реестре по маркеру продолжает работать.
-
Если указанного инструмента не существует, в лог пишется предупреждение, а переопределение регистрируется как обычный новый инструмент под собственным именем
@Tool. Если это имя уже используется другим инструментом, будет выброшено исключение, чтобы избежать неявной замены несвязанного инструмента.
Публикация обновлений статуса
Длительно выполняющиеся инструменты могут передавать прогресс в UI через бин io.jmix.aitools.tool.AiToolStatusPublisher, показанный в примере выше. Он реализует двухфазный контракт:
-
update(message, toolContext)— шаг начался, и UI показывает индикатор выполнения. -
complete(message, snippet, toolContext)— шаг завершился, и UI добавляет фрагмент результата в ту же запись. Значениеmessageдолжно совпадать с тем, которое было передано вupdate.
Оба метода принимают ToolContext метода инструмента. Когда инструмент вызывается вне UI чата, например через программный API, callback статуса отсутствует, и методы просто ничего не делают, поэтому вызывать их всегда безопасно.