1. Реляционная модель и PostgreSQL: фундамент хранения структурированных данных для ИИ
Реляционная модель и PostgreSQL: фундамент хранения структурированных данных для ИИ
При проектировании современных ИИ-систем фокус внимания часто смещается в сторону векторных баз данных. Кажется, что способность находить смысловую близость между текстами — это всё, что нужно для создания умного агента. Однако при попытке развернуть такую систему в production разработчики сталкиваются с суровой реальностью: векторный поиск не способен ответить на вопрос «сколько токенов потратил этот пользователь за вторник?» или «какой статус у задачи, которую агент отправил в Celery пять минут назад?». Вероятностная природа больших языковых моделей требует жесткого, детерминированного каркаса для управления состоянием, биллингом и историей. Эту роль берет на себя реляционная база данных.
Архитектура двойной памяти ИИ-агента
Чтобы мульти-агентная система функционировала надежно, ей необходимы два принципиально разных типа хранилищ, которые работают в тандеме.
Векторная база данных (например, Qdrant) выступает в роли семантической памяти. Она хранит эмбеддинги документов и позволяет агенту находить контекст по смыслу. Если пользователь спрашивает: «Как настроить таймауты в httpx?», агент извлекает из векторной БД фрагменты документации, где векторы математически близки к вектору вопроса. Здесь правит нечеткая логика (Fuzzy Logic) и вероятностное сходство.
Реляционная база данных (PostgreSQL) выполняет функцию эпизодической и системной памяти. Она хранит точные, структурированные факты. Когда агент формирует ответ, система должна сохранить сам факт диалога: кто спросил, когда, в рамках какой сессии, какая модель использовалась и каков точный текст ответа.
!Архитектура двойной памяти ИИ-системы: разделение потоков данных между векторной и реляционной БД
Разница между этими хранилищами становится очевидной при выполнении операций удаления или точного поиска. Если пользователь требует удалить всю историю его переписки за прошлый месяц (требование GDPR), векторная база данных с трудом справится с этой задачей без сложных метаданных, так как ее первичная функция — поиск по сходству, а не фильтрация по датам. В реляционной модели это решается тривиальным запросом с условием строгого равенства и диапазона дат.
Реляционная парадигма: математика надежности
Реляционная модель, предложенная Эдгаром Коддом, базируется на математической теории множеств. Данные организуются в виде двумерных таблиц (отношений), где строки (кортежи) представляют конкретные экземпляры сущностей, а столбцы (атрибуты) — их свойства.
Для ИИ-инфраструктуры критически важны два аспекта этой модели: строгая типизация и ссылочная целостность.
Даже при использовании строгих контрактов Pydantic (о которых шла речь при проектировании FastAPI-приложений), всегда существует риск сбоя на уровне приложения или изменения логики, при котором в систему попытаются записать некорректные данные. Реляционная база данных выступает последним рубежом обороны. Если столбец token_count определен как целое число (INTEGER), база данных физически не позволит записать туда строку, сгенерированную галлюцинирующей LLM.
Ссылочная целостность (Foreign Keys) гарантирует, что данные не повиснут в воздухе. В мульти-агентной системе на базе LangGraph состояние передается между узлами графа. Если мы сохраняем лог вызова конкретного инструмента (Tool Call), он должен быть жестко привязан к конкретному сообщению (Message), которое, в свою очередь, привязано к сессии (Session). Реляционная БД гарантирует, что невозможно удалить сессию, оставив в системе осиротевшие сообщения, если настроено каскадное удаление, или, наоборот, заблокирует удаление сессии, защищая исторические данные.
Транзакции и гарантии ACID
Любая операция в реляционной базе данных выполняется в рамках транзакции, которая подчиняется принципам ACID (Atomicity, Consistency, Isolation, Durability). Для ИИ-агентов наиболее показательна атомарность (Atomicity) — принцип «всё или ничего».
Рассмотрим процесс обработки запроса пользователя:
Если на четвертом шаге произойдет сбой (например, отказ сети или исчерпание пула потоков), атомарность транзакции позволит откатить все предыдущие шаги. В базе данных не останется «висящего» ответа ассистента без списанных токенов. Система вернется в консистентное состояние, предшествующее началу транзакции.
Многоверсионность (MVCC): как агенты не блокируют друг друга
В асинхронном приложении FastAPI, работающем под управлением Gunicorn с несколькими воркерами, десятки запросов могут обрабатываться конкурентно. Разные агенты могут одновременно писать логи в базу данных, пока аналитический сервис пытается прочитать историю диалогов для расчета метрик.
В ранних системах управления базами данных чтение данных блокировало их запись, а запись блокировала чтение. Это приводило к катастрофическому падению пропускной способности. PostgreSQL решает эту проблему с помощью механизма MVCC (Multi-Version Concurrency Control — многоверсионное управление конкурентным доступом).
Фундаментальное правило MVCC: читающие транзакции никогда не блокируют пишущие, а пишущие никогда не блокируют читающие.
!Механика MVCC: неблокирующее чтение и запись в PostgreSQL
Вместо того чтобы перезаписывать данные физически поверх старых, PostgreSQL при операции UPDATE или DELETE помечает старую строку как невидимую для новых транзакций и создает новую версию строки. Каждая строка в PostgreSQL имеет скрытые системные столбцы: xmin (идентификатор транзакции, создавшей строку) и xmax (идентификатор транзакции, удалившей или обновившей строку).
Когда аналитический запрос начинает сканировать таблицу истории диалогов (транзакция ), база данных фиксирует снимок состояния (Snapshot). Если в этот же момент ИИ-агент завершает генерацию ответа и обновляет статус сессии (транзакция ), он создает новую версию строки. Транзакция продолжит читать старую версию строки, потому что новая версия была создана транзакцией, начавшейся позже момента фиксации снимка.
Это означает, что тяжелые аналитические запросы (например, расчет ROI или оценка качества ответов через LangSmith-подобные платформы) могут выполняться на рабочей базе данных, не замедляя работу агентов в реальном времени.
Почему PostgreSQL стал стандартом де-факто для ИИ-инфраструктуры
Выбор PostgreSQL среди множества реляционных СУБД (MySQL, Oracle, SQL Server) для ИИ-проектов обусловлен его архитектурной гибкостью. PostgreSQL — это объектно-реляционная база данных, которая позволяет расширять систему типов и адаптироваться к полуструктурированным данным, что критически важно при работе с LLM.
JSONB: мост между строгими схемами и гибкостью LLM
Вывод языковых моделей, даже при использовании техник структурированного промптинга, часто содержит динамические ключи и вариативные структуры. Например, если агент использует инструмент (Tool) search_internet, аргументы будут одними (ключ query), а для инструмента calculate_mortgage — совершенно другими (amount, rate, years).
Создавать отдельную реляционную таблицу под каждый возможный инструмент агента — антипаттерн, приводящий к бесконечным миграциям схемы. Использовать NoSQL решения (вроде MongoDB) исключительно ради гибкости логов означает потерять строгие транзакции и ссылочную целостность для критичных данных (биллинг, пользователи).
PostgreSQL предлагает тип данных JSONB (Binary JSON). В отличие от простого текстового хранения JSON, JSONB парсится при записи и сохраняется в бинарном формате. Это дает два колоссальных преимущества:
JSONB можно строить индексы (например, GIN — Generalized Inverted Index) по конкретным ключам.В архитектуре ИИ-памяти JSONB позволяет применять гибридный подход. Жесткие атрибуты (кто, когда, в какой сессии) хранятся в классических типизированных столбцах. Динамические атрибуты (сырой ответ модели, JSON-аргументы вызова функции, метаданные промпта) сохраняются в столбце payload типа JSONB.
Это позволяет выполнять мощные SQL-запросы прямо по структуре, сгенерированной нейросетью. Можно написать запрос, который найдет все сессии, где агент использовал инструмент calculate_mortgage с суммой кредита строго больше 10 миллионов, обращаясь внутрь JSON-объекта на лету.
Декларативная природа SQL: отказ от микроменеджмента данных
Взаимодействие с PostgreSQL осуществляется через язык SQL (Structured Query Language). Его главная особенность — декларативность. Разработчик описывает, какие данные он хочет получить, а не как база данных должна их искать.
При работе с коллекциями в Python (даже с использованием генераторов или filter) программист реализует императивный подход: возьми список, пройди по каждому элементу, проверь условие, положи в новый список.
В SQL запрос выглядит иначе:
SELECT session_id, sum(prompt_tokens) FROM llm_logs WHERE model_name = 'llama-3' GROUP BY session_id;
Получив этот запрос, внутренний компонент PostgreSQL — Планировщик запросов (Query Planner) — строит дерево выполнения. Он анализирует статистику распределения данных в таблице llm_logs и принимает решение:
llama-3 мало, а на столбце model_name есть индекс, планировщик использует индексное сканирование (Index Scan), мгновенно переходя к нужным строкам.llama-3 больше 30-40% от всей таблицы, планировщик проигнорирует индекс и запустит последовательное сканирование (Sequential Scan), так как чтение данных подряд с диска окажется быстрее, чем постоянные прыжки по дереву индекса.Эта интеллектуальная маршрутизация внутри СУБД снимает с разработчика ИИ-системы колоссальную когнитивную нагрузку. Нет необходимости менять код приложения по мере роста объема исторических данных — PostgreSQL сам адаптирует стратегию выполнения запросов.
Проекция на мульти-агентную систему
Внедрение реляционной базы данных в архитектуру LLM-приложения формирует жесткий скелет, на который наращиваются вероятностные алгоритмы.
Вместо того чтобы хранить историю диалогов в оперативной памяти Python-процесса (что приведет к потере контекста при перезапуске воркера Gunicorn) или в неструктурированных файлах, система получает надежное хранилище. Каждое взаимодействие пользователя с ботом в Telegram, каждый внутренний цикл размышлений агента (Chain-of-Thought), каждая ошибка валидации Pydantic-контракта оседают в реляционных таблицах.
Это открывает путь к построению систем трассировки вызовов (аналогов LangSmith), где можно точно отследить, какой системный промпт привел к конкретному ответу, сколько миллисекунд заняла генерация и какие инструменты были вызваны на промежуточных этапах. В следующих главах мы спроектируем конкретную схему таблиц, которая реализует эту долгосрочную память, и настроим асинхронное взаимодействие с ней через SQLAlchemy, не блокируя Event Loop нашего веб-сервера.