Как вы обрабатываете real-time фичи для LLM (например, текущий сток товара)?

Краткий тезис

Real-time фичи — это динамические данные (текущий сток, цена, баланс пользователя), которые LLM должна учитывать при генерации ответа. Прямой запрос к БД на каждый call|вызов LLM слишком медленный. Решение — feature store (например, Redis) с low-latency доступом, tool calling для получения фичей по требованию, кэширование с TTL и event-driven обновление через Kafka. Это позволяет LLM получать актуальные данные за <10ms без перегрузки основных систем.


1. Термин: Real-time фичи для LLM

Real-time фичи — это признаки, которые быстро меняются во времени и влияют на релевантность ответа LLM. Примеры:

  • current_stock — остаток товара на складе
  • price — текущая цена (может меняться из-за акций)
  • user_balance — баланс пользователя
  • promotion_active — активна ли скидка

Без real-time фичей LLM может предложить товар, которого нет в наличии, или назвать устаревшую цену. В RAG|agentic RAG LLM действует как агент, вызывая инструменты для получения таких данных.

Проблема LLM не имеет встроенного доступа к базам данных. Каждый запрос к БД (PostgreSQL, MongoDB) занимает 10–100ms, что неприемлемо для интерактивного диалога. Нужна специализированная инфраструктура.


2. Feature store как центральное хранилище фичей

Feature store — это система для хранения, обслуживания и доставки признаков (features) в реальном времени. Популярные реализации: Redis, Feast, Tecton, Aerospike.

СвойствоОписание
LatencyЧтение из памяти (Redis) — <1ms, из SSD — <5ms
СогласованностьEventual consistency (допускается небольшая задержка обновления)
APIПростой get/set по ключу (например, stock:product_123)
TTLАвтоматическое удаление устаревших записей

В контексте LLM feature store выступает как источник истины для динамических данных. LLM не обращается напрямую к БД заказов, а читает предварительно агрегированные фичи из Redis.


3. Tool calling для получения фичей

Tool calling (function calling) — механизм, позволяющий LLM вызывать внешние функции. В нашем случае LLM может вызвать функцию get_current_stock(product_id), которая:

  1. Проверяет наличие ключа stock:{product_id} в Redis.
  2. Если есть — возвращает значение.
  3. Если нет — возвращает fallback (например, unknown или запрашивает из БД и кэширует).

Пример реализации на Python (с использованием библиотеки redis):

import redis

r = redis.Redis(host='localhost', port=6379, decode_responses=True)

def get_current_stock(product_id: str) -> int:
    """Возвращает текущий остаток товара."""
    key = f"stock:{product_id}"
    value = r.get(key)
    if value is not None:
        return int(value)
    # fallback: запрос к основной БД (медленно)
    stock = query_db(f"SELECT stock FROM products WHERE id = {product_id}")
    r.setex(key, 60, stock)  # кэшируем на 1 минуту
    return stock

LLM получает описание функции в системном промпте и решает, когда её вызвать. Например, пользователь спрашивает: «Есть ли iPhone 15 в наличии?» — LLM вызывает get_current_stock("iphone15") и получает ответ 42.


4. Кэширование с TTL для снижения нагрузки

Кэширование — временное хранение результатов для повторного использования. TTL (Time-To-Live) — время жизни записи в кэше.

ПараметрЗначение
TTL для стока1 минута
TTL для цены5 минут (меняется реже)
TTL для баланса30 секунд (чувствительные данные)

Выбор TTL — компромисс между актуальностью и нагрузкой. Слишком короткий TTL (например, 1 секунда) — частые запросы к БД. Слишком длинный (1 час) — риск устаревших данных.

Почему не запрашивать БД каждый раз? Даже если БД быстрая (10ms), при 1000 RPS это 10 секунд процессорного времени только на чтение. Кэш снижает нагрузку в 10–100 раз.


5. Event-driven обновление через Kafka

Event-driven архитектура — система реагирует на события (изменения данных) и обновляет кэш немедленно. Apache Kafka — популярная платформа для потоковой обработки событий.

Схема работы

  1. Внешняя система (например, сервис заказов) публикует событие stock_changed в топик Kafka.
  2. Consumer (сервис фичей) читает событие и обновляет Redis: SET stock:product_123 10.
  3. LLM при следующем вызове get_current_stock получает актуальное значение.

Преимущества

  • Минимальная задержка обновления (секунды).
  • Отсутствие polling (периодических запросов к БД).
  • Масштабируемость: Kafka выдерживает миллионы событий в секунду.

Недостатки

  • Сложность инфраструктуры (нужен Kafka-кластер).
  • Возможна потеря событий (нужна настройка гарантий доставки).

6. Обработка race conditions и согласованность

Race condition — ситуация, когда два процесса одновременно читают и пишут одни и те же данные, приводя к некорректному состоянию. Пример: LLM получила сток = 5, но через 1 мс пришло событие об уменьшении до 3. Если LLM уже начала формировать ответ, он может быть неверным.

Стратегии

  • Optimistic locking — использовать версионирование (например, Redis CAS).
  • Read-after-write consistency — для критичных фичей (баланс) можно читать напрямую из БД, игнорируя кэш.
  • Eventual consistency — допустить, что данные могут быть устаревшими на несколько секунд. Для стока товара это приемлемо (пользователь не заметит задержку в 2 секунды).

Рекомендация Для большинства фичей использовать eventual consistency. Для финансовых транзакций — строгую согласованность через БД.


7. Мониторинг и метрики

Чтобы убедиться, что real-time фичи работают корректно, нужно отслеживать:

МетрикаОписаниеЦелевое значение
P99 latencyВремя получения фичи из feature store<10ms
Cache hit rateДоля запросов, найденных в кэше>95%
StalenessСредняя задержка между изменением данных и обновлением кэша<5 секунд
Error rateДоля неудачных вызовов (Redis недоступен)<0.1%

Инструменты: Prometheus + Grafana, Datadog, New Relic.


8. Альтернативные подходы

ПодходОписаниеКогда использовать
In-memory cache (local)Хранить фичи в памяти самого LLM-сервиса (например, Python dict)Для прототипов, малой нагрузки
CDN для статических фичейИспользовать CDN (Cloudflare, Akamai) для фичей, которые меняются раз в часДля цен каталога, описаний
Precomputed featuresЗаранее рассчитать фичи для всех возможных запросов и сохранить в векторной БДДля рекомендательных систем
GraphQL subscriptionsПодписка на изменения через WebSocketДля интерактивных чатов

В production обычно комбинируют Redis (для горячих данных) и Kafka (для обновлений).


9. Пример архитектуры (текстовая диаграмма)

[Пользователь] → [LLM Agent]
                   ↓
            [Tool: get_current_stock]
                   ↓
            [Redis (Feature Store)]
                   ↑
            [Kafka Consumer]
                   ↑
            [Kafka Topic: stock_changes]
                   ↑
            [Сервис заказов] (публикует события)

LLM вызывает tool, tool читает из Redis. Redis обновляется асинхронно через Kafka при каждом изменении стока.


Пет-проект для закрепления

Задача Реализовать микросервис для получения real-time фичей стока товаров, который используется LLM-агентом.

Инструменты Python, Redis (через redis-py), Kafka (через confluent-kafka), FastAPI (для демонстрации).

Шаги:

  1. Запустите Redis и Kafka локально (через Docker Compose).
  2. Напишите consumer, который слушает топик stock_changes и обновляет Redis.
  3. Напишите FastAPI-эндпоинт /stock/{product_id}, который возвращает значение из Redis (имитация tool calling).
  4. Напишите скрипт, который публикует тестовые события в Kafka.
  5. Подключите LLM (например, через OpenAI API) и передайте описание функции get_current_stock. Проверьте, что LLM вызывает её при запросе «Сколько iPhone в наличии?».

Ожидаемый результат Работающий сервис, где LLM получает актуальный сток с задержкой <10ms, а обновления происходят через Kafka.


Связь с другими вопросами

ВопросТема
530Как проектировать tool calling для LLM?
531Как кэшировать результаты вызовов инструментов?
532Как обрабатывать ошибки при вызове внешних API?
534Как обеспечить согласованность данных в agentic RAG?
535Как мониторить производительность агентов?
536Как тестировать агентные системы?

Навигация