Гайд · TNWS AI
Как разделить состояние пользователей RAG-демо через gr.State
Проверяем независимость пользовательских списков документов, сброс при новой вкладке и ограничения состояния сессии.
Задача и применимость
Русскоязычный вопрос: «как хранить отдельные документы в сессиях gradio state». Подходит для приложения на Gradio Blocks, когда набор фрагментов временно сохраняют только на время одной пользовательской сессии. Не заменяет базу знаний и не даёт доступа между устройствами. Страница gr.State и руководство Gradio проверены 20 сентября 2026 года.
Что подтверждено производителем
gr.State хранит произвольное значение для состояния сессии и передаётся как вход и выход обработчика события; стартовое значение копируется. Документация предупреждает об удалении после закрытия или обновления вкладки, а time_to_live задаёт дополнительное ограничение времени. Для общего глобального состояния переменная Python на уровне модуля не отделяет пользователей.
Порядок действий
- Создайте gr.State с начальным пустым списком.
- В обработчике берите старые фрагменты и возвращайте новый список как выход State.
- Вместе с State выведите видимое число фрагментов для отладки.
- Откройте вторую независимую вкладку и проверьте, что она начинается с пустого списка.
- Если нужна долгоживущая база, перенесите данные в хранилище с проверкой прав доступа.
Готовый шаблон
Сохраните пример в отдельном файле Python. В коде нет реального секрета или скрытого вызова модели: если подключён внешний API, его адрес и параметры указаны явно. Установите gradio в отдельном окружении; дополнительные пакеты требуются только там, где они импортированы в примере.
import gradio as gr
def add(text, docs):
text = text.strip()
if not text:
raise gr.Error("Введите непустой фрагмент")
next_docs = docs + [text]
return next_docs, f"В этой сессии {len(next_docs)} фрагментов"
with gr.Blocks() as demo:
fragment = gr.Textbox(label="Фрагмент для RAG")
status = gr.Textbox(label="Статус")
docs = gr.State(value=[], time_to_live=1800)
gr.Button("Добавить").click(add, inputs=[fragment, docs],
outputs=[docs, status])
demo.launch(server_name="127.0.0.1")
Вход и ожидаемый результат
Вкладка А вводит «Возврат 14 дней» и получает «1 фрагментов» (строка в коде ради прозрачности числа; для продукта поправьте склонение). Вкладка Б, начатая независимо, добавляет «Доставка по будням» и тоже получает 1, а не 2. Этот результат проверяет сессионное разделение, но пока не осуществляет vector search или генерацию.
Проверка контракта
Частая ошибка — объявить docs=[] глобально и изменять его функцией append. Тогда разные люди начинают записывать текст в один общий список, из которого RAG-бот может процитировать чужой документ. Возвращение нового списка из callback и gr.State как выход делает жизненный цикл явным. Даже так не загружайте конфиденциальные файлы в непроверенный публичный интерфейс: отдельная сессия UI не является полноценным механизмом авторизации или изоляцией всех данных в инфраструктуре.
Работа с данными пользователя
Важна и семантика времени хранения. Параметр time_to_live в примере — учебное локальное значение 1800 секунд, не дефолт Gradio. По истечении либо при закрытии вкладки состояние может исчезнуть, поэтому нельзя обещать восстановление корпуса после обновления браузера. Для настоящего рабочего пространства назначьте идентификатор пользователя сервером, настройте БД, права чтения и удаления, срок хранения и резервирование. Любой такой ID должен проверяться сервером, а не просто приниматься из поля браузера.
Что проверить перед развёртыванием
Когда вместо строк в State лежат объекты моделей, дескрипторы файлов и крупные массивы, копирование и жизненный цикл становятся существенными. Документация требует, чтобы передаваемое значение было совместимо с копированием; тяжёлую модель держите отдельно в управляемом сервисе, не дублируйте её на пользователя. Фрагменты RAG могут содержать персональные данные: журналируйте только метрики, если разрешения на хранение текста нет. Проверьте повторные запросы, две вкладки и обновление страницы как разные тесты.
Шаблон запроса для будущего сессионного ответа: «Отвечай только по фрагментам этой сессии. Для каждого утверждения назови номер фрагмента; если подходящего текста нет, скажи НЕИЗВЕСТНО». Тест намеренно включает два несовпадающих фрагмента в разных вкладках: вопрос во вкладке А о доставке не должен получать текст вкладки Б. Отрицательный тест на пересечение пользователей важнее красивой демонстрации одного запроса.
Независимость двух вкладок проверяйте также на отрицательном вопросе: во вкладке А спросите о факте, существующем только во вкладке Б. Правильный ответ будущей RAG-системы — отсутствие данных, даже если оба человека используют один модельный сервер. Если ответ содержит чужой документ, выясняйте источник смешения: глобальный список, общий векторный индекс без фильтра владельца или кэш вне сессии. Не пытайтесь замаскировать утечку изменением формулировки промпта; изоляцию обеспечивают серверные ограничения доступа к данным.
Критерии приёмки
- Два браузерных контекста не видят фрагменты друг друга.
- Пустой текст отклоняется до обновления State.
- После перезагрузки нет обещания долговременного сохранения.
Типичные ошибки и чего не делать
- Не хранить пользовательские документы в глобальном списке.
- Не путать gr.State с защищённой БД.
- Не задавать большой TTL без политики хранения.
FAQ
Общий ли State для всех?
Нет, это состояние сессии.
Сохраняется ли после закрытия вкладки?
На это нельзя полагаться.
Где хранить постоянный корпус?
В отдельной БД с проверкой доступа.
Официальные источники
Частые вопросы
Общий ли State для всех?
Нет, это состояние сессии.
Сохраняется ли после закрытия вкладки?
На это нельзя полагаться.
Где хранить постоянный корпус?
В отдельной БД с проверкой доступа.
Читайте также
Как добавить ползунок temperature к AI-чату через additional_inputs в Gradio
Связываем Slider и функцию чат-бота без ошибки порядка аргументов; проверяем значение до вызова нейросети.
Как добавить примеры вопросов в Gradio, не вызывая нейросеть по клику
Настраиваем examples и run_examples_on_click=False, чтобы пользователь отредактировал вопрос перед дорогим вызовом модели.
Как группировать запросы к ML-модели через batch=True в Gradio Interface
Сверяем сигнатуру пакетной функции, tuple of lists и max_batch_size на детерминированном тесте.
Комментарии
Пока тихо. Скажите первое слово