Представьте: ваш ИИ-агент в Flutter с GenUI собирает экраны на лету. Круто, да? Но вот тут ловушка: если вы заставите LLM считать налоги, конвертировать валюты или умножать цены, вы просто сожжете токены и добавите лишнюю сетевую задержку. Результат при этом может оказаться непредсказуемым. 🤯
Решение? Клиентские функции A2UI.
Это механизм, который позволяет зарегистрировать обычную Dart-функцию, описать её параметры и тип результата. Агент видит это описание, решает, что нужно вычислить, и отправляет вызов. А приложение спокойно выполняет код локально на устройстве. Мгновенно и без лишних запросов в сеть! ⚡️
Разделение труда становится таким:
🔹 Flutter-клиент объявляет доступные функции в каталоге GenUI.
🔹 Агент решает, где и когда показать компонент, и шлёт A2UI-выражение с аргументами.
🔹 Клиент выполняет вычисление локально и сразу рендерит результат.
Давайте посмотрим, как это выглядит в коде. Синхронные функции наследуются от
SynchronousClientFunction. Вот пример функции для расчёта стоимости ингредиента:class CalculateCostFunction extends SynchronousClientFunction {
const CalculateCostFunction();
@override
String get name => calculateCost;
@override
String get description =>
Calculates the cost for a certain quantity of an ingredient.
Returns a formatted dollar string (for example, \$4.50).;
@override
ClientFunctionReturnType get returnType => ClientFunctionReturnType.string;
@override
Schema get argumentSchema => S.object(
properties: {
ingredient_id: S.string(description: The ID of the ingredient.),
quantity: S.number(description: The quantity of the ingredient.),
},
required: [ingredient_id, quantity],
);
@override
Object? executeSync(JsonMap args, ExecutionContext context) {
final ingredientId = args[ingredient_id].toString();
final quantity = num.tryParse(args[quantity].toString())?.toDouble();
if (quantity == null || quantity < 1) {
return \$0.00;
}
final cost = CostService().fetchPrice(ingredientId, quantity);
return \$${cost.toStringAsFixed(2)};
}
}Ключевые моменты, на которые стоит обратить внимание:
🔹 name: уникальный идентификатор, по которому агент находит функцию.
🔹 description: критически важно! Это подсказка для LLM, чтобы она понимала, когда вызывать функцию и какой формат ответа ждать.
🔹 returnType: тип возвращаемого значения (в примере — строка).
🔹 argumentSchema: схема, которая говорит LLM, какие параметры обязательны.
🔹 executeSync: сам метод, который выполняется на устройстве. Парсит аргументы, вызывает локальный сервис и возвращает результат.
Этот паттерн очень похож на работу с UI-компонентами в каталоге. И там, и там вы даёте агенту метаданные для рассуждений, а Dart-код делает реальную работу: создаёт виджеты или считает числа.
Чтобы агент вообще узнал о функции, её нужно зарегистрировать в каталоге GenUI:
final commisCatalog = Catalog(
[
cateringJobItem,
recipeLineCatalogItem,
ingredientLineCatalogItem,
navigationCardCatalogItem,
simpleCardCatalogItem,
],
functions: [
CalculateCostFunction(),
],
catalogId: commis_catalog,
);
При инициализации сессии
PromptBuilder из genui автоматически инспектирует каталог, извлекает объявления функций и добавляет их в системный промпт для Gemini. Всё прозрачно и автоматизировано. 🤖Итог:
Клиентские функции A2UI — это способ вынести логику из головы ИИ в надёжный Dart-код. Меньше задержек, экономия токенов и предсказуемый результат. Обязательно попробуйте, если работаете с GenUI! 💡
Полную новость читайте здесь.
FlutterPulse — канал о мире Flutter!
#flutter #dart #FlutterPulse #FlutterPulseNews #hardworkerFlutter #AI #GenUI