← Назад к статьям
Плагин · Capacitor Labs
@capacitor/local-llm

On-device LLM для Capacitor

Запускайте большие языковые модели прямо на устройстве — через Apple Intelligence на iOS и Gemini Nano на Android. Никаких сетевых запросов, API-ключей и утечки данных.

🔗 GitHub · 📦 npm: @capacitor/local-llm · ⚡ v1.0.0
⚠️

Capacitor Labs — проект экспериментальный. Официальная поддержка не предоставляется. Баги и идеи — через GitHub Issues.

@capacitor/local-llm — нативный плагин Capacitor для запуска LLM на устройстве использует Apple Intelligence (Foundation Models) на iOS и Gemini Nano на Android. Никаких сетевых запросов, никаких API-ключей, никаких данных, покидающих устройство.

Примечание: On-device LLM требуют физического железа. Android-эмуляторы не поддерживаются. iOS-симуляторы поддерживаются, если хост-устройство совместимо с Apple Intelligence и оно включено.

1. Установка

npm install @capacitor/local-llm
npx cap sync

2. Требования к платформам

Платформа Мин. ОС Примечания
iOS 15 Генерация изображений требует iOS 18.4+. Text LLM (Foundation Models / Apple Intelligence) — iOS 26+.
Android 9 (API 28) Gemini Nano через ML Kit требует устройство с поддержкой on-device AI (например, Pixel 9+).

3. Настройка iOS

Никакой дополнительной конфигурации не требуется. Foundation Models и Image Playground — системные фреймворки, доступные автоматически на поддерживаемых устройствах с включённым Apple Intelligence.

Вызывайте systemAvailability() в рантайме, чтобы проверить, готова ли модель к работе, прежде чем отправлять промпты.

На iOS 18 и ниже systemAvailability() вернёт 'unavailable' для text LLM. Если вызвать prompt() или warmup() в любом случае — промис упадёт с ошибкой. Генерация изображений через generateImage() полностью работает на iOS 18.4+.

4. Настройка Android

Минимальный Android SDK плагина — 28, выше текущего минимума Capacitor (24). Нужно изменить android/variables.gradle:

ext {
    minSdkVersion = 28
}

Gemini Nano распространяется через Google Play Services и должен быть загружен на устройство отдельно — модель не входит в комплект приложения.

Проверка и загрузка

Вызовите systemAvailability() чтобы узнать статус. Если статус downloadable — запустите загрузку через download() и опрашивайте systemAvailability() пока статус не станет available.

import { LocalLLM } from '@capacitor/local-llm';

const { status } = await LocalLLM.systemAvailability();

if (status === 'downloadable') {
  await LocalLLM.download();
  // Опрашиваем systemAvailability() пока status !== 'available'
  // Или используем addListener('systemAvailabilityChange', {})
}

5. Ограничения платформ

🍎 iOS

  • Text LLM требует iOS 26 и Apple Intelligence. На iOS 18 и ниже systemAvailability() вернёт 'unavailable'. Только iPhone 15 Pro и новее.
  • download() недоступен на iOS. Моделью управляет ОС — проверяйте готовность через systemAvailability().
  • Лимит контекста: 4096 токенов. Суммарно: системные инструкции + история диалога + текущий промпт.

🤖 Android

  • maximumOutputTokens зажат в 1–256 API ML Kit — значения вне диапазона будут срезаны.
  • Контекст multi-turn управляется в памяти ручной сборкой истории в каждый промпт. Не нативная сессия, не сохраняется между перезапусками.
  • warmup() игнорирует sessionId и promptPrefix на Android — прогревает модель глобально.
  • Не все Android 9+ поддерживают Gemini Nano. Нужен совместимый AI-чип (Pixel 9 и новее).
  • Фоновая работа запрещена. Инференс в бэкграунде упадёт с ошибкой.
  • AICore устанавливает квоту: слишком частые запросы — ошибка BUSY, превышение дневного лимита — PER_APP_BATTERY_USE_QUOTA_EXCEEDED. Используйте exponential backoff.

6. Использование

Базовый промпт

import { LocalLLM } from '@capacitor/local-llm';

const { text } = await LocalLLM.prompt({
  prompt: 'Объясни теорию относительности в одном абзаце.',
});

console.log(text);

Многошаговый диалог

Используйте sessionId для сохранения контекста между промптами.

import { LocalLLM } from '@capacitor/local-llm';

const sessionId = 'my-chat-session';

await LocalLLM.prompt({
  sessionId,
  instructions: 'Ты полезный ассистент.',
  prompt: 'Какая столица Франции?',
});

const { text } = await LocalLLM.prompt({
  sessionId,
  prompt: 'Какое население у этого города?',
});

// Очистка после завершения
await LocalLLM.endSession({ sessionId });

Warmup — снижаем задержку первого ответа

import { LocalLLM } from '@capacitor/local-llm';

// Пре-инициализация модели до того, как пользователь начал печатать
await LocalLLM.warmup({
  sessionId: 'my-session',
  promptPrefix: 'Ты — агент поддержки компании Acme Corp.',
});

Генерация изображений (только iOS)

import { LocalLLM } from '@capacitor/local-llm';

const { pngBase64Images } = await LocalLLM.generateImage({
  prompt: 'Горное озеро на рассвете, фотореализм',
  count: 2,
});

// Используем прямо в <img>
const src = `data:image/png;base64,${pngBase64Images[0]}`;

7. Обработка ошибок

Все методы плагина выбрасывают LocalLLMException при ошибке. Он расширяет Error и добавляет машиночитаемый код LocalLLMErrorCode.

import { LocalLLM, LocalLLMException } from '@capacitor/local-llm';

try {
  await LocalLLM.prompt({ prompt: 'Привет' });
} catch (err) {
  if (err instanceof LocalLLMException) {
    console.log(err.code);    // напр. 'LOCAL_LLM_NOT_ENABLED'
    console.log(err.message); // человекочитаемое описание
  }
}

Коды ошибок

Код Описание
LOCAL_LLM_UNSUPPORTED_PLATFORM Текущая версия ОС или железо не поддерживает on-device LLM.
LOCAL_LLM_NOT_ENABLED On-device AI доступен, но не включён пользователем (например, Apple Intelligence).
LOCAL_LLM_NOT_READY Модель есть на устройстве, но ещё загружается или инициализируется.
LOCAL_LLM_UNAVAILABLE Модель недоступна по неклассифицированной причине.
LOCAL_LLM_RESPONSE_IN_PROGRESS Промпт отправлен в сессию, которая уже генерирует ответ.
LOCAL_LLM_NOT_INITIALIZED Плагин не инициализирован. При нормальных условиях возникать не должно.
LOCAL_LLM_MISSING_PARAMETER Обязательный параметр не передан (например, sessionId или prompt).
LOCAL_LLM_WEB_NOT_SUPPORTED Метод вызван на веб-платформе — не поддерживается.
LOCAL_LLM_IMAGE_GENERATION_FAILED Генерация изображения не удалась (например, нет доступного стиля генерации).
LOCAL_LLM_UNKNOWN_ERROR Неожиданная ошибка от SDK платформы. Проверьте err.message.

8. Справочник API

systemAvailability()

Проверяет доступность on-device LLM. Определяет, готова ли модель, нужно ли её загрузить, или она недоступна на данном устройстве.

Возвращает: Promise<SystemAvailabilityResponse> со статусом status: LLMAvailability

download()

Загружает on-device LLM модель. Только на Android.

Возвращает: Promise<void>

prompt(options)

Отправляет промпт on-device LLM и получает ответ. Можно указать sessionId для поддержания контекста беседы.

Параметры: PromptOptions — текст промпта и опциональные настройки (температура, макс. токены и т.д.)

Возвращает: Promise<PromptResponse>

endSession(options)

Завершает активную сессию LLM. Важно для освобождения памяти и предотвращения утечек ресурсов.

Параметры: EndSessionOptions — идентификатор сессии

Возвращает: Promise<void>

generateImage(options)

Генерирует изображения из текстового описания. Возвращает массив PNG в base64. Доступно только на iOS 18.4+.

Параметры: GenerateImageOptions — промпт, количество, опциональные референсные изображения

Возвращает: Promise<GenerateImageResponse> — { pngBase64Images: string[] }

warmup(options)

Прогревает on-device LLM для более быстрых первых ответов. Пре-инициализирует модель с промпт-профиксом, снижая задержку первого запроса.

Возвращает: Promise<void>

addListener('systemAvailabilityChange', callback)

Подписывается на изменения статуса доступности on-device LLM. Опрос начинается с добавлением первого слушателя и останавливается после removeAllListeners().

removeAllListeners()

Удаляет все подписки и останавливает опрос статуса.

📦 Интерфейсы

SystemAvailabilityResponse{ status: LLMAvailability }

PromptResponse{ text: string }

GenerateImageResponse{ pngBase64Images: string[] }

LLMAvailability'available' | 'downloadable' | 'unavailable'