Пользователь хочет увидеть расходы за прошлый месяц по категориям, но API отдаёт сырой JSON — это неудобно. Мы решаем эту задачу с помощью AI-агента, который преобразует естественный язык в SQL и возвращает готовый отформатированный ответ. Наш опыт показывает: правильно настроенный Text-to-SQL сокращает время разработки аналитических экранов в 2–3 раза, при этом безопасность данных остаётся на первом месте. За 8 лет работы мы реализовали более 15 проектов с интеграцией LLM в мобильные приложения — на SwiftUI, Kotlin и Flutter. Такое решение экономит до 40% бюджета на интеграцию и ускоряет вывод фич.
Почему Text-to-SQL на мобильном — отдельная задача
Прямой доступ мобильного приложения к продуктовой БД — плохая идея, даже read-only. Правильная архитектура, которую мы применяем: мобильный клиент → бэкенд API с агентом → БД. Бэкенд валидирует сгенерированный SQL, ограничивает набор доступных таблиц и контролирует права пользователя. На клиенте используется либо локальная БД (SQLite через Room на Android, Core Data / GRDB на iOS) для офлайн-данных, либо агент работает на сервере и возвращает готовые данные. Гарантируем, что без нашей архитектуры вы рискуете получить утечку данных. Альтернативные подходы (прямой SQL из клиента) увеличивают риски в 3–5 раз.
Как научить модели вашей схеме БД
Модель не знает вашу схему. Нужно передавать её в системном промпте или через инструмент get_schema. Однако вываливать весь DDL на 200 таблиц — ошибка: мы отбираем только релевантные таблицы. Для приложения с личными финансами достаточно 5–8 таблиц.
Пример схемы для промпта
-- Пример схемы для промпта (упрощённая)
CREATE TABLE transactions (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
amount DECIMAL(10,2) NOT NULL,
category VARCHAR(50),
description TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
В системный промпт добавляем: «Ты генерируешь SQL-запросы ТОЛЬКО для SELECT. Никогда не используй INSERT, UPDATE, DELETE, DROP. Все запросы должны содержать WHERE user_id = :user_id.» Ограничение через промпт — первый слой защиты. Второй слой — валидация на сервере: парсим AST сгенерированного SQL (библиотека sql-parser или pg_query для PostgreSQL), проверяем тип запроса и список таблиц.
Как защитить данные при генерации запросов?
Помимо промпта, мы внедряем обязательные меры: параметризованные подзапросы, whitelist таблиц и колонок, лимит результатов LIMIT 1000, таймаут SET statement_timeout = '5s' и полное логирование. Все запросы перед выполнением проходят через AST-валидатор, который гарантирует, что модель не нарушила контракт. Этот сертифицированный подход используется во всех проектах. Таким образом, безопасность SQL достигается без потери гибкости.
Room и агент: локальная БД на Android
Если агент работает с локальными данными приложения через Room, адаптируем SQL-интерфейс. Согласно официальной документации Google, Room позволяет выполнять сырые SQL-запросы через SupportSQLiteDatabase. Вот пример:
class DatabaseTool(private val db: AppDatabase) {
suspend fun executeQuery(sql: String): String {
return try {
val cursor = db.openHelper.readableDatabase.query(sql)
cursor.toJsonArray().toString()
} catch (e: Exception) {
"""{"error": "${e.message}"}"""
}
}
}
SupportSQLiteDatabase.query() принимает сырой SQL — удобно для агента. Room DAO здесь не подходит: он требует фиксированных запросов на этапе компиляции. Важный момент: Room не разрешает raw queries в основном потоке — всё выполняется в suspend fun или withContext(Dispatchers.IO). Это увеличивает надёжность и предотвращает блокировки UI.
Форматирование результата
Агент получил строки из БД — нужно вернуть их пользователю в читаемом виде, а не как JSON-массив. Передаём результат обратно модели с инструкцией отформатировать:
Tool result: [{"category":"food","total":"-15420"},{"category":"transport","total":"-8300"}]
→ Модель форматирует: "За прошлый месяц вы потратили 154.20 BYN на еду и 83.00 BYN на транспорт"
Для числовых данных хорошо работает запрос к модели на создание Markdown-таблицы — её легко отрендерить на мобильном через Markwon (Android), AttributedString (iOS) или flutter_markdown (Flutter).
Сравнение: локальный агент против серверного
| Характеристика | Локальный агент (Room) | Серверный агент (PostgreSQL) |
|---|---|---|
| Задержка | <50 мс | 200–500 мс (сеть) |
| Безопасность | Ограничена песочницей ОС | AST-валидация + промпт |
| Сложность схемы | До 10 таблиц | Без ограничений |
| Офлайн-режим | Да | Нет |
| Стоимость внедрения | Ниже | Выше, но масштабируется |
| Количество пользователей | 1 | Неограниченно |
Серверный агент лучше подходит для сложных схем и многопользовательских систем, локальный — для простых офлайн-сценариев. Выбор зависит от ваших задач. Закажите консультацию — мы подберём оптимальное решение под ваш бюджет и сроки.
Этапы и сроки
| Этап | Описание | Длительность |
|---|---|---|
| Анализ | Изучение схемы, выделение релевантных таблиц | 2–3 дня |
| Проектирование | Системный промпт, валидатор, архитектура | 3–5 дней |
| Реализация | Интеграция агента на бэкенде или клиенте | 7–14 дней |
| Тестирование | Покрытие всех типов запросов, исправление ошибок | 5–7 дней |
| Деплой и мониторинг | Запуск, логирование, настройка алертов | 2–3 дня |
Полный цикл занимает от 2 до 6 недель в зависимости от сложности схемы и выбранного архитектурного подхода. Закажите консультацию — мы подберём оптимальное решение под ваш бюджет и сроки.
Что входит в работу
- Анализ схемы БД и определение доступных таблиц
- Разработка системного промпта с описанием схемы
- Реализация SQL-валидатора на бэкенде
- Интеграция агентного цикла (вызов LLM, выполнение, форматирование)
- Тестирование на 50+ пользовательских запросах
- Мониторинг качества генерации и доработка
Дополнительно предоставляем документацию по архитектуре, обучение команды и гарантию на 6 месяцев поддержки. Свяжитесь с нами, чтобы обсудить ваш проект — оценим его за 1 рабочий день.







