Последние полтора года наша ML-команда делает крайне интересные штуки, например строит ИИ-агентов поверх PostgreSQL, при этом инфраструктура меняется, индустрияПоследние полтора года наша ML-команда делает крайне интересные штуки, например строит ИИ-агентов поверх PostgreSQL, при этом инфраструктура меняется, индустрия

Выбор LLM и фреймворка для ИИ-агентов

defccd9ce27ae8c484d6b8cacf944921.png

Последние полтора года наша ML-команда делает крайне интересные штуки, например строит ИИ-агентов поверх PostgreSQL, при этом инфраструктура меняется, индустрия созревает, а ожидания и требования к качеству систем на базе ИИ только растут. Начинали мы с одной A100 в VK Cloud и довольно скромных задач, по типу «давайте прикрутим RAG», а сейчас одновременно поддерживаем прод AskPostgres, строим агентов-аналитиков, проводим эксперименты, разворачиваем собственные бенчмарки для агентов и готовимся к переезду на сервер с 8×H200, где уже можно запускать Qwen3-235B и разворачивать серьёзные работы по дообучению небольших моделей.

В статье о том, какие задачи мы решаем, как эволюционировало железо, модели и фреймворки, и почему в итоге мы гораздо меньше волнуемся какая модель лучше, и гораздо больше — о контекст-менеджменте и архитектуре агентов. Всё описанное актуально на конец 2025 — начало 2026 года.

Задачи, под которые мы строили стек

Вокруг единой LLM-инфраструктуры у нас постепенно вырос целый набор приложений. Чтобы было понятно, о чём речь, перечислю основные направления.

  1. Классический RAG Fusion над документацией и прочими источниками.
    Мы индексируем документацию Postgres Pro, статьи, вопросно-ответные пары, SQL-примеры, книги и прочий текст в pgvector. В качестве эмбеддера используем BGE-M3 и работаем не с BM25, а со sparse-векторами: строим разреженные представления текстов, считаем dense-векторы и комбинируем всё это через перемножение, ранжирование, дисконтирование и дополнительные эвристики. Обработка некоторых неструктурированных источников частично делегирована LLM.

  2. Развитие RAG в ИИ-агента на MCP с веб-поиском и SQL-executor.
    Классический чат с документацией быстро перестал устраивать: пользователям нужен полноценный ассистент с чёткой ролевой моделью и множеством разных инструментов. Поэтому вокруг RAG вырос ReAct-агент, который через Model Context Protocol (MCP) умеет ходить в PostgreSQL, обращаться к веб-поиску и комбинировать эти источники в одной цепочке рассуждений.

  3. ИИ-агент для аналитики.
    Это интерфейс поверх аналитических данных: агент понимает вопросы в духе «покажи выручку по регионам за последний год», генерирует SQL, объясняет результат, умеет возвращаться к прошлым шагам, строить графики и постепенно наращивать сложность запросов.

  4. Graph-RAG-агент над большой кодовой базой на C (ИИ-Copilot).
    Ядро PostgreSQL и сопутствующие проекты — это миллионы строк C-кода. Мы строим граф знаний в Apache AGE: вершины — директории, файлы, функции, структуры, макросы, переменные; рёбра — вложенные зависимости и вызовы. Агент поверх этого графа отвечает на вопросы о том, где реализовано вот это поведение, чем чревато изменение такого-то участка и помогает с навигацией по коду как по базе знаний, а не как по сплошному тексту с поиском.

  5. SQL-генератор.
    Развёрнутый пайплайн text-to-SQL, который мы тренируем и оцениваем на основе EX/EM-метрик и бенчмарков типа Spider/BIRD плюс наши схемы. Для обучения использовали Qwen-0.6B и на ней отрабатывали GRPO/SFT; отдельно экспериментировали с QLoRA-дообучением моделей порядка Qwen2.5-14B на чистом SFT.

  6. Генератор hint-сетов для PostgreSQL.
    Здесь в центре всего расширение pg_hint_plan. Модель видит запрос, статистику, индексы и предлагает подсказки в формате hint-сетов. Обучаем это дело при помощи GRPO, параллельно зажимаем формат подсказок формальной грамматикой, чтобы pg_hint_plan мог их распарсить и применить.

  7. Генератор схем БД и бизнес-логики из DSL.
    Мы используем DSL (domain specific language), который описывает не только сущности, но и схему транзакций для мутации схемы БД. Сама схема представляется как набор агрегатов с иерархической структурой данных в формате JTD (JSON Typedef). Агент по этому описанию генерирует таблицы, связи, транзакционную обвязку и фрагменты бизнес-логики, придерживаясь JTD-спецификации.

  8. Генератор тестовых данных.
    Под капотом это, казалось бы, «простой» генератор INSERT, но с нюансами. Агент умеет подцеплять правдоподобные списки значений (города, имена, адреса), учитывать связи между таблицами. Всё выходное описание генерации зажато в формальной грамматике, чтобы потом легко было валидировать и воспроизводить сценарии.

  9. Суммаризация и структурирование тикетов техподдержки.
    Цель здесь — не просто пересказать переписку, а разложить её в понятный отчёт: кто что делал, какие гипотезы проверялись, какие команды выполнялись, к какому итогу пришли. Параллельно агент классифицирует тикет по существующим меткам.

  10. Просмотр больших объёмов кода в поисках подозрительных фрагментов.
    По сути, LLM просеивает большие массивы кода и помечает фрагменты, которые выглядят подозрительно по заданным критериям. Это инструмент ускорения ручного аудита, а не его замена.

  11. Собственные бенчмарки для агентов.
    Мы пришли к схеме «тестируемый агент + тестирующий агент + валидатор». Первый решает задачу так, как будет делать это в проде, взаимодействуя с инструментами. Второй играет роль пользователя: отвечает, уточняет, направляет, опираясь только на ограниченное подмножество контекстных знаний. Третий, валидатор, анализирует весь диалог и решает, достигнута ли цель и соблюдены ли условия тестового кейса. Так мы тестируем не IQ модели, а поведение системы целиком.

  12. Исследования памяти и формальных ограничений.
    Параллельно мы играемся с тем, как устроить краткосрочную и долгосрочную память агентов, как управлять контекстом (от простого окна до суммарзации, маскирования и графов) и как формальные грамматики и строгий structured output влияют на качество, скорость и устойчивость поведения.

Дальше в статье я буду постоянно отталкиваться от этих задач: именно под них мы подбирали железо, модели и фреймворки.

Первая итерация стека: 1×A100, RAG, LangChain и Ollama → vLLM

История с ресурсами у нас довольно классическая. Сначала была одна A100 80 GB в VK Cloud, на которой нужно было и экспериментировать, и что-то показывать по продукту. Этого хватало, чтобы поднимать 30–70-миллиардные модели в квантизации Q6_K_M через Ollama, крутить простые RAG-кейсы и собирать первые прототипы SQL-генератора.

Потом появился внутренний сервер с двумя A100. Это сильно облегчило жизнь: на нём сейчас живёт прод AskPostgres, существует несколько сред, там же мы держим стабильные пайплайны и параллельно гоняем эксперименты. В этот момент стало понятно, что Ollama — отличная штука для быстрого старта, но для прода нам нужен более контролируемый и эффективный движок инференса. Так мы пришли к vLLM.

Но почему именно vLLM, а не TensorRT-LLM или SGLang, у которых пиковая производительность как будто бы выше?

Не факт, что выше именно на вашем кейсе. В интернете можно найти кучу разных графиков и таблиц, которые будут либо противоречить друг другу (поскольку построены на разном железе, разных моделях в разные промежутки времени), либо демонстрировать относительный паритет в усреднённом случае:

https://www.clarifai.com/blog/comparing-sglang-vllm-and-tensorrt-llm-with-gpt-oss-120b)
https://www.clarifai.com/blog/comparing-sglang-vllm-and-tensorrt-llm-with-gpt-oss-120b)
LLM inference engines performance testing: SGLang VS. vLLM | by Chirawat  Chitpakdee | Medium
https://medium.com/@occlubssk/llm-inference-engines-performance-testing-sglang-vs-vllm-cfd2a597852a
Изображение
https://x.com/vllm_project/status/1913513173342392596/photo/1

Короче, типичная война исследователей, использующих бенчмарки, как оружие. Таким образом, на выбор будет влиять не циферка или столбик в каком-то графике, а применимость фреймворка в нашем конкретном кейсе.

Что нам нужно? Нужна поддержка структурированного аутпута и контекстно-свободных грамматик — здесь все три движка подходят. Также нужна поддержка абсолютно разных моделей с Hugginf Face, потому что хочется пробовать много разных вариантов для подбора лучшей базы для агентов — здесь TensorRT-LLM начинает проигрывать, поскольку поддерживает ограниченный набор линеек и архитектур, а также требует процесса компиляции модели при её переключении, что тормозит и усложняет R&D. Ещё хочется поддержку инференса на CPU, что есть и в vLLM, и в SGLang, но нет в TensorRT-LLM. По итогу, финальный выбор между vLLM и SGLang был основан на объективной величине активного комьюнити — vLLM победил.

Сейчас мы ожидаем сервер с 8×H200, который уже можно считать полноценной площадкой для самых тяжёлых моделей. Там вполне реалистично запускать Qwen3-235B и соседей по размеру, а заодно развернуть систематическую активность по обучению маленьких моделей под специфичные задачи: свои SQL/Cypher/DSL-генераторы, семантические классификаторы, векторизаторы, реранкеры, суммаризаторы, анализаторы логов и так далее. На A100 этого тоже можно было добиться, но ценой довольно агрессивных компромиссов по квантизации, размерам модели и времени обучения.

Что касается фреймворков, начинали мы с максимально простого набора: LangChain, LangGraph, LangFuse, RAGAS и несколько моделей семейства Qwen2.5. Нас интересовали русский и английский, поэтому мы быстро отмели части LLaMA- и Gemma-линеек: по нашим задачам и корпусам они заметно проигрывали Qwen именно на русском языке, а промптинг с инструктированием под них шёл сложнее. В тот момент нас устраивала схема: LangChain для RAG, LangGraph для первых агентных графов на базе Qwen. На этом стекe мы подняли ChatPPG (прототип AskPostgres), обкатали базовый RAG, SQL-генератор и первые экспериментальные пайплайны «генератор + критик + валидатор». RAGAS соответственно использовали для оценки итеративных изменений в нашем RAG: как с точки зрения изменения пайплайна/промптов/источников данных, так и с точки зрения изменения базовой модели. Целевыми метриками выступали answer_relevancy и answer_corectness — ориентируясь на них, мы и принимали решения о том, повлияло изменения на работу системы, стало лучше или хуже:

f087599e067eceeeb8c8f3300ced65e8.jpg

Параллельно оформился подход к retrieval: вместо привычного тандема BM25 + dense-вектора мы сделали ставку на BGE-M3 с его dense + sparse-представлениями и начали работать со sparse-векторами как с полнотекстовой частью поиска. Для наших текстов это оказалось удобнее и проще в эксплуатации.

SQL-генератор и hint-сеты: где дообучение действительно оправдано

«Мы сделали Fine-tuning модели» — звучит гордо. Однако легко забыть, что для большинства прикладных задач дообучение больших моделей — скорее роскошь, чем необходимость. Наш практический опыт здесь довольно приземлённый.

Для 80-миллиардного класса (и тем более для моделей уровня Qwen3-235B) типичный набор задач: RAG, SQL, код, инструменты — уже решается «из коробки». 90% проблем устраняет:

  • нормальный контекст-менеджмент;

  • адекватный RAG (BGE-M3, хорошая индексация, грамотный парсинг);

  • архитектурой пайплайн (генератор, критик, валидатор, SGR);

  • жёсткий structured output.

Дообучение у нас оправдано в двух случаях. Первый — когда нужна небольшая модель под конкретный сценарий, например, on-prem у клиента, где нет мощных GPU. Второй — когда требуется очень специфичный формат вывода, который трудно стабильно выжать из модели одними промптами.

Технически мы используем классический набор: пробовали PEFT/LoRA/QLoRA, LLaMA-Factory и LMPO, но пришли де-факто к стандарту — TRL для экспериментов с SFT и RL-подходами (GRPO, GSPO и тому подобное). При этом для сложных вещей вроде SQL-генератора мы предпочитаем обкатывать методологию на маленьких моделях (например, на Qwen-0.6B), а уже потом переносить отобранные траектории и данные на более крупные.

Главный фильтр, который мы проходим, очень простой: если у нас нет мощностей, адекватного бенчмарка с метриками или данных для задачи, мы не дообучаем модель под эту задачу. Сначала тюнинг через контекст, а потом fine-tuning.

SQL-генератор стал первым местом, где мы подумали: «Ладно, здесь без дообучения будет больно». Нам хотелось, чтобы модель не просто выдавала валидный SQL, но и вела себя предсказуемо, понимала особенности диалекта PostgreSQL и делала какой-никакой schema-linking в процессе ризонинга на типичных запросах пользователей.

В качестве теста мы взяли Qwen-0.6B: на нём запускали SFT и GRPO с LoRA и учились конструировать reward. Это повысило качество при сложных запросах и показало, что подобного рода пайплайны оправданы на маленьких моделях. Также учили и Qwen2.5-14B с QLoRA на чистом SFT. В результате получили улучшение формата, но знаний новых модели это не добавило, что явно отображалось на бенчмарках.

Генератор hint-сетов вырос из этой же логики, но с более жёсткими ограничениями. Здесь в центре внимания pg_hint_plan, и любая ошибка в формате подсказки может привести к тому, что планировщик не поймёт, чего от него хотят, и просто проигнорирует план. Поэтому мы сразу зажали выход модели формальной грамматикой и тренировали её с помощью GRPO, максимально аккуратно подбирая наборы подсказок, которые реально ускоряют запросы.

Стоит отметить, что алгоритмов RL море и у каждого свои плюсы и минусы. Так, например, мы пробовали относительно новый GSPO и поняли, что он больше подходит для MoE-архитектур, в то время как GRPO на маленьких dense-моделях сходился быстрее.

DSL, JTD и генерация тестовых данных

Отдельная ветка — работа с DSL. Нам нужен был язык описания, в котором не только схема данных задаётся декларативно, но и схема транзакций для её мутации: какие операции возможны, какие инварианты должны сохраняться, какие агрегаты существуют. Для этого мы описали структуру в терминах JTD (JSON Typedef): так получилось связать иерархические агрегаты, бизнес-инварианты и транзакционную логику. Агент, который работает с этим DSL, по сути, выступает переводчиком с языка бизнеса на формальный язык, может задать уточняющие вопросы и создать необходимую мутацию в случае необходимости. Подробнее про сам DSL можно почитать здесь.

Ещё один более приземлённый пайплайн — генератор тестовых данных. Он получает схему и набор требований, а на выходе выдаёт набор INSERT. При необходимости агент подтягивает правдоподобные значения (списки городов, имён, доменов и тому подобное), следит за связями и edge-кейсами. Всё, что он выдаёт, тоже ограничено формальной грамматикой, так что генерацию можно всегда считать синтаксически корректной и валидной для дальнейших этапов работы с тестовой БД.

От «зоопарка» пайплайнов к агентам на MCP

Пока все эти компоненты жили каждый сам по себе, жизнь была непростой. Для RAG — свой пайплайн, для SQL — свой, для Graph-RAG по коду — ещё какой-то. Каждый держит собственные подключения к базе, свои форматы логов и свои представления о том, что такое контекст.

Переход к MCP дал долгожданный порядок как в инфраструктуре, так и в головах. Стало гораздо легче объяснять, как агенты работают с инструментами, какие существуют уровни абстракции и какие возможности расширения существуют. Мы стали описывать доступ к данным и инструментам в терминах MCP-серверов, а поверх них строить ReAct-агентов. В результате у нас появился единый слой, где:

  • PostgreSQL, файловая система, web-поиск, graph-store и внутренние API выглядят одинаково — как набор инструментов с чёткими контрактами;

  • разные агенты могут использовать один и тот же набор MCP-серверов без копипаста и «зоопарка» интеграций.

9a98ffd1102aa8c3870a1be24c9dfb42.png

На этом фоне особенно важным стало поведение модели именно как агента: насколько аккуратно она вызывает инструменты, как реагирует на ошибки, умеет ли честно признать, что нужных данных нет. Для начала можно воспользоваться лидербордами, по типу этого, но нужно же оценивать качество и на своих задачах. Это и подтолкнуло нас к созданию собственного бенчмарка с тройкой «тестируемый агент — тестирующий агент — валидатор». Нам оказалось мало просто «хорошей модели», нужна была система, которая ведёт себя предсказуемо в длинной траектории решения.

Текущий стек: vLLM, Qwen3-Next-80B и свой агентный слой

К настоящему моменту стек выглядит примерно так.

Внизу лежит vLLM как основной движок для инференса open-source-моделей. Далее идёт OpenAI-совместимый MCP-клиент, который занимается стримингом, подключением к MCP-серверам, управляет циклом агента и отвечает за то, чтобы все нужные инструменты были вызваны и весь контекст корректно передался в LLM, как мы хотим. Тут мы сознательно ушли от попыток строить сложные сценарии целиком внутри LangChain/LangGraph, оставив их для быстрого прототипирования. Причина есть: сырость и наличие большого количества багов в продовых сценариях. Логирование и аналитику мы тоже сделали свою на PostgreSQL. Ранее использовали LangFuse, но до тех пор, пока не обнаружили утечку памяти, что благополучно клало нам прод несколько раз в неделю.

5fa7284ddad6a0c8cc894c6479dcce34.png

Стоит отметить, что ресурсы между командами мы делим через LiteLLM: это удобный gateway с OpenAI-совместимым API, который умеет маршрутизировать запросы на разные модели - как локальные, так и внешние закрытые модели при необходимости.

Инструменты и источники данных живут в отдельном слое MCP-серверов. Это даёт возможность подключать и отключать серверы без переписывания логики агентов и делиться ими между разными продуктами/командами.

В описанной конфигурации по цифрам нагрузочного тестирования в многопользовательском режиме получаем в среднем 18 секунд на ответ с использование инструмента поиска по документации, а p95 при этом около 60 секунд, что более чем хорошо для нашего контекста.

Квантизация и её характер

Если говорить о квантизации, то на практике всё свелось к весьма простой картине.

Пока мы жили на A100, AWQ-4bit стал рабочей нормой для больших моделей. В таком виде Qwen3-Next-80B-A3B помещается на карту, показывает достойное качество на наших задачах и позволяет ещё строить поверх неё многоступенчатых агентов, не раздувая латентность до неприличия.

В более агрессивные режимы мы иногда заходили, но быстро убедились, что стоимость ошибок возрастает: модель чаще уводит вывод на неправильный язык, зацикливается на шаблонных фразах и чаще ломает формат вызова инструментов (сейчас иногда это тоже происходит). Часть этого лечится промптами и настройкой параметров семплирования (температура, top-p, top-k), но по-настоящему надёжной становится связка только тогда, когда вы сверху накрываете модель формальными грамматиками и жёсткими спецификациями выходных форматов.

С приходом H200 мы будем активнее смотреть в сторону FP8-квантов и более крупных моделей, но философия вряд ли изменится: квантизация — это trade-off между качеством и скоростью. Мы будем выбирать опираясь на бенчмаркинг и несколько измеряемых критериев, не исключая latency.

Что мы поняли про выбор моделей

Если попробовать выжать весь опыт в один тезис, он будет таким: модель важна, но контекст и архитектура ещё важнее.

Да, если взять gpt-5.2 или Gemini Pro 3.0, они объективно будут умнее любого открытого аналога. Но если агент не умеет управлять контекстом, если у него нет памяти и продуманной работы с инструментами, то никакая «мега-триллионная-модель» не спасёт ситуацию.

Мы прошли путь от Qwen2.5-14B/32B в Q6_K_M через Ollama до Qwen3-Next-80B-A3B AWQ-4bit на vLLM и сейчас смотрим в сторону Qwen3-235B на H200. На каждом шаге по пути можно было построить полезного агента, при условии что вокруг модели есть всё остальное: RAG, MCP, агентный слой, память, грамматики и бенчмарки.

Поэтому сейчас, выбирая LLM под новую задачу, мы в первую очередь спрашиваем себя, не о том, какая модель в прайме. Нас интересует:

  • какие данные и источники контекста нам нужны;

  • как мы будем управлять этим контекстом;

  • какие инструменты и в каком виде нужны агенту;

  • как мы будем измерять качество его поведения.

А модель — это просто компонент, который встраивается в эту систему. Пусть даже это будет gpt-5.2: без контекста и архитектуры ничего не поедет

Источник

Возможности рынка
Логотип Large Language Model
Large Language Model Курс (LLM)
$0.0003184
$0.0003184$0.0003184
-2.45%
USD
График цены Large Language Model (LLM) в реальном времени
Отказ от ответственности: Статьи, размещенные на этом веб-сайте, взяты из общедоступных источников и предоставляются исключительно в информационных целях. Они не обязательно отражают точку зрения MEXC. Все права принадлежат первоисточникам. Если вы считаете, что какой-либо контент нарушает права третьих лиц, пожалуйста, обратитесь по адресу service@support.mexc.com для его удаления. MEXC не дает никаких гарантий в отношении точности, полноты или своевременности контента и не несет ответственности за любые действия, предпринятые на основе предоставленной информации. Контент не является финансовой, юридической или иной профессиональной консультацией и не должен рассматриваться как рекомендация или одобрение со стороны MEXC.

Вам также может быть интересно

Metaplanet получила одобрение акционеров на расширение привилегированных акций

Metaplanet получила одобрение акционеров на расширение привилегированных акций

Metaplanet поделилась своим последним достижением — ей удалось убедить акционеров одобрить пять предложений на внеочередном собрании акционеров. Это новое
Поделиться
Tronweekly2025/12/24 03:00
Erebor достиг оценки в $4,3 млрд после одобрения регуляторами банковской лицензии

Erebor достиг оценки в $4,3 млрд после одобрения регуляторами банковской лицензии

Erebor достигает оценки в 4,3 млрд $ после привлечения 350 млн $, позиционируя себя как лидера в банковском обслуживании цифровых активов. Регуляторы США продвигают банковскую лицензию Erebor,
Поделиться
Coincentral2025/12/24 02:47
IntouchAI от IntouchCX признан важным конкурентом в оценке PEAK Matrix® Assessment 2025 от Everest Group по разговорному ИИ и ИИ-агентам в продуктах CXM

IntouchAI от IntouchCX признан важным конкурентом в оценке PEAK Matrix® Assessment 2025 от Everest Group по разговорному ИИ и ИИ-агентам в продуктах CXM

ВИННИПЕГ, Манитоба–(BUSINESS WIRE)–IntouchCX, мировой лидер в области управления клиентским опытом и автоматизации, объявил, что IntouchAI и его пакет решений
Поделиться
AI Journal2025/12/24 03:15