Содержание
  1. Официальный архивный статус и что он меняет
  2. Механизм чата и его пределы
  3. Учебный вход: чат «Справка мастерской»
  4. Структурная корректность и фактическая правильность
  5. Внешние примеры: NVIDIA и Mistral
  6. Случай, где подход не решает задачу
  7. Как разобрать существующее приложение
  8. Частые вопросы
Обзоры

Обзор Chainlit: архивный проект для ИИ-чатов

11 ноября 2026 · 9 минут чтения

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

Официальный архивный статус и что он меняет

Страница overview на docs.chainlit.io прямо фиксирует: «Chainlit is archived and no longer actively maintained». Дальше там же сказано, что авторы больше не предоставляют bug fixes, security updates и support, а сама документация доступна для справки. Это заявление владельца проекта на его собственном домене.

Практические последствия для решения читателя выстраиваются в короткую цепочку. Первое: команда не может рассчитывать на новые исправления безопасности от сопровождающих Chainlit; состояние зависимостей и способы обновления придётся проверять самостоятельно. Второе: официальная поддержка прекращена, поэтому для разбора поведения понадобятся исходники и сохранённая документация. Третье: интеграции со сторонними библиотеками, которые упоминает overview, описывают состояние на момент архивации.

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

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

Механизм чата и его пределы

Основной механизм описан в разделе pure-python на docs.chainlit.io. Приложение импортирует пакет Chainlit и объявляет функцию-обработчик входящих сообщений, помеченную декоратором. Эта функция вызывается каждый раз, когда пользователь отправляет сообщение в интерфейсе чата, и внутри неё размещается собственная логика: разбор текста, вызов API, вычисление результата. Ответ пользователю отправляет отдельный класс, отвечающий за отправку сообщения обратно.

Пределы этой модели видны сразу. Chainlit берёт на себя слой интерфейса и маршрутизацию сообщений к вашему коду. Всё, что происходит внутри обработчика, остаётся вашей ответственностью: выбор модели, обращение к внешним сервисам, проверка входных данных, обработка ошибок. Фреймворк не решает, что считать правильным ответом, и не проверяет фактическую достоверность того, что вернула модель.

Второй предел связан с состоянием. Документация по user session описывает ловушку прямо: код, который на первый взгляд работает, содержит серьёзный изъян, и при одновременном общении двух пользователей оба будут увеличивать одно и то же значение. Причина в том, что сессия пользователя и общее состояние процесса — разные вещи, и хранить пользовательские данные в модульной переменной опасно.

Третий предел — граница между интерфейсом и хранением. Сессия живёт в рамках взаимодействия и не равна постоянному хранилищу. Раздел data persistence на docs.chainlit.io описывает, что по умолчанию чаты и элементы не сохраняются, а для записи нужен Data Layer: официальный, из сообщества или собственный. Пока Data Layer и аутентификация не настроены, перезагрузка страницы не доказывает, что история где-то осталась.

Учебный вход: чат «Справка мастерской»

Ниже — учебный пример, собранный для этой статьи. Модель заменена проектируемой заглушкой, внешний API не вызывался, значения условные и служат входом для разбора.

PYTHON20 строк
import chainlit as cl

POLICY = "Для замены замка нужен бланк R-2."

@cl.on_chat_start
async def start():
    cl.user_session.set("question_count", 0)
    await cl.Message(content="Спросите о часах или бланках.").send()

@cl.step(name="read_policy")
async def read_policy(question: str) -> str:
    return POLICY

@cl.on_message
async def handle(message: cl.Message):
    count = cl.user_session.get("question_count") or 0
    cl.user_session.set("question_count", count + 1)
    source = await read_policy(message.content)
    answer = f"Нужен бланк R-2 [POLICY]"
    await cl.Message(content=answer).send()

Что здесь происходит по шагам. При старте сессии обработчик on_chat_start кладёт в user session счётчик и отправляет приветствие «Спросите о часах или бланках». Пользователь пишет «Какой бланк для замены?». Обработчик on_message увеличивает счётчик, вызывает шаг read_policy, который читает полный источник «Для замены замка нужен R-2», и отправляет итог «Нужен бланк R-2 [POLICY]».

Эталон проверки — матрица из четырёх условий. Новая сессия А видит приветствие. Сообщение в сессии А получает подтверждённый ответ R-2. Новая сессия Б не получает внутреннюю историю сессии А. Перезагрузка сессии А сама по себе не доказывает сохранение истории, пока не настроены Data Layer и аутентификация. В учебном состоянии сессии лежит {"question_count": 1}, постоянной записи нет.

Структурная корректность и фактическая правильность

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

Четыре пункта выше задают ожидаемое поведение; фактического прогона не было. В коде read_policy возвращает источник, но переменная source дальше не используется: финальный ответ задан отдельной строкой. Поэтому совпадение R-2 с POLICY — ручной эталон этой заглушки. При изменении POLICY зашитый ответ сам не обновится. При добавлении модели нужно отдельно проверять и механику обработчика, и соответствие ответа актуальному источнику.

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

Отдельно про Steps. Документация по step описывает их как способ показать этапы обработки сообщения. Декоратор @cl.step в примере выше помечает функцию read_policy, и в интерфейсе появляется отдельный этап с именем. Это этапы приложения: чтение политики, вызов инструмента, обращение к хранилищу. Скрытую цепочку рассуждений модели Steps не показывают, и выдавать их за неё нельзя.

Внешние примеры: NVIDIA и Mistral

Два первоисточника показывают, как Chainlit применяли на практике. Технический блог NVIDIA описывает архитектуру routing и multi-source RAG, которая объединяет поиск по документам, веб-поиск через Perplexity и обработку задач вне RAG, чтобы отвечать на широкий круг вопросов. В том же материале сказано, что Chainlit даёт интерфейс с индикаторами прогресса, автоматической трассировкой через LlamaIndexCallbackHandler и корпоративной аутентификацией с хранением в PostgreSQL.

Полезная деталь из блога NVIDIA — структура референсной реализации: код разделён на workflow.py для маршрутизации и поиска, ingest.py для загрузки документов в Milvus Lite, chainlit_app.py для фронтенда и config.py для выбора модели. Такое разделение помогает читать чужой проект: интерфейсная часть отделена от логики поиска.

Второй источник — cookbook Mistral AI. Он показывает приложение на API Mistral, где самопроверяющийся агент решает, хватает ли собранной информации для ответа на вложенный вопрос, и приводит пример с погодой в родном городе Наполеона: сначала нужно получить город, затем погоду для него. Там же описаны декораторы @chainlit.step для трассировки функций и автоматическая инструментовка Mistral API через chainlit.instrument_mistralai(), а также файл .env со строкой MISTRAL_API_KEY=.

Сравнение двух примеров по явным критериям:

Критерий Пример NVIDIA Пример Mistral
Задача Маршрутизация и multi-source RAG Вложенные вопросы и самопроверка агента
Трассировка LlamaIndexCallbackHandler @chainlit.step, instrument_mistralai()
Дополнительные службы в примере Аутентификация и сохранение данных с PostgreSQL Literal AI для трассировки; сопоставимый способ хранения истории здесь не указан
Структура Четыре модуля по ролям Один app.py целиком

Случай, где подход не решает задачу

Возьмём сценарий, где пользователю нужен ответ по внутреннему регламенту с юридической силой. Учебный чат отправляет отдельную зашитую строку «Нужен бланк R-2 [POLICY]». Она совпадает с POLICY в этом учебном входе; изменение источника потребует отдельного изменения или проверки ответа.

Ситуация ломается, когда регламент обновляется, а в приложении остаётся зашитая строка. Chainlit не отслеживает актуальность источника: он вызывает ваш обработчик и показывает то, что обработчик вернул. Ответ останется структурно корректным и фактически устаревшим.

Второй случай — несколько источников с противоречиями. Если обработчик передаёт оба противоречащих фрагмента дальше без проверки приоритета, пользователь может получить ответ по отменённому документу. Логику приоритета источников пишет разработчик.

Третий случай — вопрос вне покрытия. Пользователь спрашивает про бланк, которого нет в политике. Обработчик из примера вернёт R-2, потому что другого пути в коде нет. Отказ «в источнике нет ответа» требует отдельной ветки, и Chainlit её не добавляет.

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

Как разобрать существующее приложение

Начните с обработчиков старта и входящего сообщения. Проследите, какой источник получает обработчик и откуда берётся финальная строка ответа. В учебной заглушке источник прочитан, но ответ зашит отдельно — это место, которое потребует изменения при обновлении политики.

Затем найдите пользовательское состояние и настройку Data Layer. Проверьте, какие данные существуют только в памяти сессии и какие действительно записываются. Отдельно выпишите внешние вызовы и назначение Steps: эта карта покажет границы интерфейса, логики и хранения.

Решение о дальнейшем использовании требует оценки безопасности, зависимости от API Chainlit и ресурса команды на сопровождение архивного проекта. Приведённая схема помогает читать код; план миграции составляют по зависимостям конкретного приложения.

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

Chainlit ещё поддерживается?

Официальная документация проекта сообщает, что Chainlit архивирован и активно не поддерживается. Исправления ошибок, обновления безопасности и поддержка прекращены. Документация оставлена для справки. Для нового рабочего приложения это существенное ограничение.

Что такое chainlit python и как устроен обработчик?

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

Чем user session отличается от постоянного хранения?

Сессия живёт в рамках взаимодействия пользователя с приложением. Постоянное хранение требует Data Layer, который бывает официальным, из сообщества или собственным. Документация по data persistence указывает, что по умолчанию чаты и элементы не сохраняются. Перезагрузка страницы сама по себе сохранение не доказывает.

Steps показывают рассуждения модели?

Steps показывают этапы обработки сообщения в приложении: чтение источника, вызов инструмента, обращение к хранилищу. Декоратор @cl.step помечает функцию, и этап появляется в интерфейсе. Скрытую цепочку рассуждений модели они не отображают.

Можно ли использовать примеры chainlit cookbook?

Cookbook Mistral AI показывает приложение на API Mistral с самопроверяющимся агентом и декораторами трассировки. Технический блог NVIDIA описывает архитектуру routing и multi-source RAG с LlamaIndex и NIM. Оба примера относятся к своим продуктам и своим версиям, поэтому переносить настройки между ними не стоит.

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

3 материала