Гайд · TNWS AI

Как показывать локальную генерацию потоком через TextIteratorStreamer

5 мин—

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

Задача и применимость

Запрос читателя: «как показывать генерацию потоком transformers TextIteratorStreamer». Ниже разобрана одна воспроизводимая задача на Python и Transformers 4.57.1. Действия относятся к checkpoint HuggingFaceTB/SmolLM2-135M-Instruct, а не ко всем нейросетям с похожим названием. Код не отправляет запросы к админ-панели и не меняет чужие данные. Для первого запуска требуется загрузить модель из Hugging Face Hub; модель может требовать памяти и иметь собственные лицензионные условия. Проверяйте карточку checkpoint до применения к пользовательскому контенту. Демонстрационные предсказания не выдаются здесь за фактически выполненный инференс: в доступной проверке сверены документация и синтаксис Python, но веса модели не запускались.

Факт из документации, на который опирается инструкция: TextIteratorStreamer принимает tokenizer, в примерах — skip_prompt=True и skip_special_tokens=True, а generate запускается в отдельном Thread, чтобы можно было итерировать готовые текстовые фрагменты. Streamer может буферизовать части слова, поэтому границы yield не равны границам токенов. API streamer в документации отмечен как потенциально изменяемый. Если версия вашей библиотеки или конфигурация checkpoint отличается, повторите короткий тест перед массовым использованием. Код показывает механизм, а не результат промышленной оценки качества на вашем корпусе.

Порядок действий

  1. Форматируйте messages шаблоном модели и создайте input_ids.
  2. Создайте TextIteratorStreamer с пропуском промпта и служебных токенов.
  3. Передайте streamer в generate, запустив генерацию в отдельном потоке.
  4. Итерируйте фрагменты и одновременно собирайте полную строку.
  5. После окончания потока дождитесь потока исполнения и проверьте окончательную форму ответа.

Для установки в отдельном окружении используйте совместимую версию пакета и backend PyTorch: pip install "transformers==4.57.1" torch. Наличие команды не означает, что все веса доступны именно вашей системе или что GPU настроен. Секреты и персональные данные не помещайте в демонстрационные входы. Для быстрой диагностики перед первым большим прогоном проверьте import transformers; print(transformers.__version__).

Готовый шаблон Python

from threading import Thread
from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer

name = "HuggingFaceTB/SmolLM2-135M-Instruct"
tok = AutoTokenizer.from_pretrained(name)
model = AutoModelForCausalLM.from_pretrained(name)
ids = tok.apply_chat_template([{"role":"user","content":"Name two colors."}],
                              tokenize=True, add_generation_prompt=True,
                              return_tensors="pt")
streamer = TextIteratorStreamer(tok, skip_prompt=True,
                                skip_special_tokens=True, timeout=30)
worker = Thread(target=model.generate,
                kwargs={"input_ids":ids, "max_new_tokens":32, "streamer":streamer})
worker.start()
parts = []
for piece in streamer:
    parts.append(piece)
    print(piece, end="", flush=True)
worker.join()
print("\ncomplete:", "".join(parts))

Этот шаблон можно перенести в отдельный файл и заменить демонстрационные тексты на обезличенную выборку. Зафиксируйте checkpoint и входные строки, чтобы отличать ошибки подготовки от поведения модели. В серверном сценарии загрузку модели выполняйте один раз при старте службы, а не заново при каждом обращении. Если пример возвращает словарь, используйте проверку наличия ключа перед сохранением его в долговременное хранилище. Сначала воспроизведите малый тест, лишь затем подключайте массовый поток.

Пример входных данных и ожидаемой проверки

Вход: запрос «Name two colors». Ожидается последовательность текстовых фрагментов и затем строка complete из их конкатенации; конкретное разбиение слов на куски не фиксировано. Если соединение с браузером оборвалось, приложение не должно сохранять полученные первые символы как полноценный ответ.

Важно различать ожидаемую структуру ответа и непроверенное заранее содержимое нейросетевого предсказания. Если устройство или модель вернули иное значение, не «подгоняйте» скрипт под рассказ статьи. Сохраните фактический вывод, сопоставьте его с контрольным примером и запишите, какой слой дал отличие: вход, токенизация, checkpoint или постобработка. Так тест остается полезным после обновления окружения.

Как принимать решение по реальным данным

Потоковая выдача сокращает время до первых видимых символов, но не означает, что вся задача вычисляется быстрее. Streamer выдаёт декодируемые текстовые части: если фронтенд считает каждый piece отдельным словом или токеном, метрики и UI будут неверными. Сборка parts нужна для аудита и для финальной проверки ответа. Особенно важно отличать «полный ответ» от «вкладка закрылась после двух слов». При исключении в worker основной поток может ждать следующие части; timeout позволяет не ждать бесконечно, но потребуются обработка исключения и журнал состояния задания. В примере демонстрируется успешный путь на локальной модели; промышленный сервер должен дополнительно передавать ошибки фонового потока в основной обработчик и иметь правила отмены работы. Не подключайте автоматическую отправку письма к каждому частичному фрагменту.

Дополнительный тест перед внедрением

Проверьте три сценария приёмки: нормальное завершение с полной строкой, остановку клиентского соединения и ошибку генерации после первых слов. В первом концевая строка должна равняться сумме показанных фрагментов. Во втором запись в базе помечается прерванной, даже если пользователь уже увидел красивое начало. В третьем нельзя возвращать HTTP-успех как будто модель закончила ответ. Если LLM обязана выдать JSON, поток служит только предварительным отображением: парсинг и принятие результата выполняйте по завершении. Длительный пользовательский ввод тоже задержит первый символ, поэтому отдельно измеряйте время подготовки, загрузки модели и генерации. При смене версии Transformers проверяйте streamer API заново, поскольку производитель прямо предупреждает об изменяемости реализации.

Критерии готовности

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

Записывайте тестовый результат вместе с ID входа и конфигурацией, но не публикуйте приватные запросы в открытых логах. Ручная разметка небольшой выборки нужна даже тогда, когда код возвращает ответ без ошибок: технически правильная форма не подтверждает полезность предсказания. После изменения модели или библиотеки прогоните тот же набор повторно. Если одно из условий не пройдено, сначала исправляйте причину, затем расширяйте применение.

Типичные ошибки и что не делать

  • Не считать каждый piece отдельным токеном.
  • Не сохранять частичный ответ как проверенный результат.
  • Не игнорировать исключения фонового worker.

Не путайте демонстрационный вывод с обещанием точности и не подменяйте источники сведений ответом модели. Для автоматического действия с последствиями для человека добавляйте независимую проверку. Изменения языка, объёма текста и домена применения требуют новой оценки качества. В документации производителя описан интерфейс инструмента, но показатели вашей задачи можно узнать только на вашей контрольной выборке.

FAQ

Нужен ли отдельный поток?

В примере да: генерация выполняется параллельно с чтением streamer.

Равен ли кусок одному токену?

Нет, куски формируются после декодирования.

Можно ли валидировать JSON на каждом куске?

Финальную валидацию делайте после завершения потока.

Официальные источники

Частые вопросы

Нужен ли отдельный поток?

В примере да: генерация выполняется параллельно с чтением streamer.

Равен ли кусок одному токену?

Нет, куски формируются после декодирования.

Можно ли валидировать JSON на каждом куске?

Финальную валидацию делайте после завершения потока.

Читайте также

Комментарии

Пока тихо. Скажите первое слово