ИИ-аналитик с личным ревизором: Qwen пишет SQL, Jev проверяет

ИИ-аналитик с личным ревизором: Qwen пишет SQL, Jev проверяет

Большинство ИИ-агентов устроены одинаково: одна LLM генерирует ответ, сама же его оценивает, сама решает, что всё в порядке, и идёт дальше. Модель, которая ошиблась при генерации, с той же уверенностью пропустит свою ошибку при проверке. Sumanth, автор репозитория Hands-On AI Engineering, собрал ИИ-аналитика данных, где генерация, проверка и контроль доступа разнесены по разным слоям, и подробно описал, как это работает.

Из чего собран агент

Агентный цикл крутится на Vercel eve. Рантайм отвечает за сам цикл, вызов инструментов и сценарий подтверждения человеком. Основную работу делает Qwen (alibaba/qwen3.8-omni-flash), подключённый через Vercel AI Gateway. Данные лежат в локальной SQLite с тестовой базой продаж за 2025 год: клиенты, товары, заказы. Интерфейс написан на Gradio. Ревьюером выступает Jev от TypeSafe AI, отдельная модель, которая занимается только суждениями о качестве работы агента.

Модели доступны ровно два инструмента. inspect_schema показывает таблицы и колонки, run_sql выполняет запрос после того, как он прошёл все проверки. Прямого доступа к базе у Qwen нет.

Как проходит вопрос

Допустим, пользователь спрашивает, какая выручка была по категориям товаров. Qwen запрашивает схему, пишет один SELECT, run_sql возвращает строки, Qwen объясняет результат. Агент явно проговаривает, что считает выручкой: quantity * unit_price по заказам со статусом completed. Без такого уточнения запрос может быть синтаксически безупречным и при этом отвечать на какой-то соседний вопрос.

Безопасность проверяет код

Qwen только предлагает SQL. Решение о запуске принимает детерминированный код внутри run_sql: допускается ровно один SELECT, SQLite открыта в режиме read-only и query-only, любая попытка записи или второй инструкции отклоняется. Запросы, которые возвращают больше 200 строк, уходят обратно агенту с просьбой агрегировать данные или добавить LIMIT. Если в запросе нет WHERE, выполнение встаёт на паузу до подтверждения человеком. Ни Qwen, ни Jev в этих проверках не участвуют: всё, что можно проверить правилом, проверяется правилом.

Где нужен второй взгляд

Детерминированные проверки говорят, безопасно ли выполнять запрос. Понять, отвечает ли он на вопрос пользователя, они не могут. Безопасный запрос легко берёт не ту метрику, не тот период или группирует по не тому полю. Даже правильный SQL может закончиться объяснением, которое не следует из данных. Поэтому Jev включается в трёх местах.

Сначала он оценивает, можно ли вообще ответить на вопрос по имеющейся схеме. На вопрос «Кто наш лучший клиент?» Jev вернул вердикт clarify с уверенностью 93%: непонятно, лучший по выручке, по числу покупок, по среднему чеку или по последней активности. Агент не выбирает метрику молча и просит пользователя уточнить.

Затем Jev получает вопрос, схему и сгенерированный SQL и решает, соответствует ли запрос намерению пользователя. Регулярка увидит, что это SELECT, но не заметит, что считается выручка за всё время вместо прошлого месяца. При уверенном несоответствии агент получает причину и одну попытку переписать запрос до выполнения.

Наконец, Jev сверяет готовый ответ Qwen со строками, которые реально вернула база. Если в ответе есть утверждения без опоры на данные, он показывается как непроверенный черновик, а SQL и результат остаются на экране.

Ревьюер без права руля

Вердикт Jev ничего не разрешает. Он не может пропустить небезопасный SQL, снять лимит строк, обойти read-only, ответить на запрос подтверждения вместо человека или изменить базу. Jev высказывает мнение, рантайм решает, на что это мнение влияет. Слой ревью работает по принципу fail open: если Jev тормозит или недоступен, ответ всё равно приходит, но с пометкой, что проверка не проводилась.

Ограничения

Агента гоняли на учебной SQLite, нагрузку никто не мерил. Проверка SQL сейчас идёт через хелпер evaluate из eve, который не всегда отдаёт уверенность, поэтому этот шаг может пропустить запрос без блокировки. Jev не гарантирует корректность, безопасность доступа к базе держится на read-only, лимите строк и подтверждении человеком.

Правило, которое стоит забрать в свои проекты

Если условие можно проверить кодом, проверяйте кодом. Read-only ли запрос, вернул ли он больше 200 строк, нужно ли подтверждение, на всё это отвечает код. Двусмысленен ли вопрос, отражает ли SQL намерение пользователя, следует ли объяснение из строк, это уже семантика, и здесь нужна модель-судья.

Подробный разбор архитектуры читайте на Uproger. Код с тестовой базой и Gradio-приложением лежит на GitHub.