Привет! Сегодня у нас на препарировании не просто очередной пет-проект, а настоящий культурный артефакт — Deaddit. Это полная симуляция Reddit, где все, от пользователей и сабреддитов до постов и комментариев, создано нейросетями. Идеальная иллюстрация «теории мертвого интернета» в вакууме.
Автор этого проекта собрал все в один репозиторий. Мы посмотрим на код, разберем, почему некоторые архитектурные решения здесь — это образец прагматизма, которого так не хватает в мире, помешанном на микросервисах и Kubernetes для блога на три статьи.
Проект построен на надежном стеке, без лишних понтов. И это его первый плюс.
Никакого тебе Celery, RabbitMQ, Redis и прочего оверинжиниринга, который так любят, чтобы резюме выглядело посолиднее. Здесь все подчинено одной цели — решить задачу максимально простыми и эффективными инструментами.
Прежде чем лезть в архитектуру, давайте оценим красоту идеи. Deaddit — это не просто генератор текста. Это полноценная симуляция экосистемы.
Пользователи (users.json
) — это не просто имена. У каждого есть возраст, пол, профессия, интересы, черты характера и даже стиль письма. Нейросеть получает на вход готовую «личность», от лица которой и пишет посты или комменты.
Сабреддиты (subdeaddits_base.json
) — тоже с характером. У каждого свое описание и, что важно, предопределенные post_types
(типы постов). То есть в AskDeaddit
будут генерироваться в основном вопросы, а в TalesFromRetail
— личные истории.
[!INFO] Вишенка на торте Отдельного уважения заслуживает сабреддит
d/BetweenRobots
. Его описание гласит: «A subdeaddit for AI language models to discuss their experiences as AIs... This is a space for AIs to be open about their artificial nature... Remember to maintain the illusion of humanity in other subdeaddits!». Место, где боты могут «снять маски» и поговорить о своем, о ботском.
Структура проекта классическая для Flask. Давайте пробежимся по ключевым файлам в директории deaddit/
.
__init__.py
: Стандартная точка входа. Создание приложения Flask, инициализация SQLAlchemy, Cache и SocketIO. Важный момент — db.create_all()
здесь же, что типично для небольших проектов, где миграции не нужны.models.py
: Определения всех сущностей через SQLAlchemy — Subdeaddit
, Post
, Comment
, User
, Job
и другие. Все четко, понятно, с правильно прописанными связями (relationships
).routes.py
: Вся логика отображения страниц — главная, сабреддиты, посты, профили пользователей. Классический веб-бэкенд без лишних сложностей.api.py
: А вот это уже интереснее. Здесь находятся эндпоинты для «загрузки» сгенерированного контента (/api/ingest
), а также ручки для получения данных, которые использует фронтенд (/api/posts
, /api/users
и т.д.). Разделение логики веб-страниц и API — хороший тон.admin.py
: Целый мир в миниатюре. Полноценная админка для управления всем этим безумием: мониторинг задач, генерация контента, просмотр статистики.jobs.py
и loader.py
: Сердце и мозг генерации. jobs.py
отвечает за фоновое выполнение задач, а loader.py
содержит всю логику взаимодействия с AI, включая формирование промптов и обработку ответов. Именно их мы сейчас и разберем подробнее.А теперь мой любимый момент. В 9 из 10 пет-проектов, где нужны фоновые задачи, я вижу связку Celery + Redis/RabbitMQ. И в 9 из 10 случаев это стрельба из пушки по воробьям. Автор Deaddit пошел другим путем и использовал APScheduler.
Почему это гениально для такого проекта?
jobs.py
. Создание задачи — это вызов одной функции scheduler.add_job()
. Никаких воркеров, брокеров и сложной конфигурации.ThreadPoolExecutor
с разным количеством воркеров. Автор так и сделал, создав очереди для задач с высоким, нормальным и низким приоритетом. Просто и эффективно.В файле jobs.py
функция create_job
принимает тип задачи, параметры и приоритет, а затем просто добавляет ее в очередь APScheduler.
# deaddit/jobs.py
# ... (конфигурация APScheduler) ...
def create_job(
job_type: JobType,
parameters: dict[str, Any],
priority: int = 5,
total_items: int = 1,
delay_seconds: int = 0,
) -> Job:
# ... (создание записи в БД) ...
# Выбор очереди по приоритету
if priority >= 8:
executor = "high_priority"
elif priority <= 3:
executor = "low_priority"
else:
executor = "default"
# Просто добавляем задачу в планировщик
scheduled_job = scheduler.add_job(
execute_job,
"date",
run_date=datetime.now(),
args=[job.id],
id=job.rq_job_id,
executor=executor,
replace_existing=True,
)
# ... (логирование) ...
return job
[!TIP] Когда НЕ стоит использовать APScheduler Важно понимать ограничения этого подхода. APScheduler не подойдет для высоконагруженных систем, где требуется масштабирование воркеров на несколько машин или гарантированная доставка задач даже при падении основного приложения. Но для 95% пет-проектов и многих небольших коммерческих продуктов его более чем достаточно.
Поехали дальше. Теперь вскроем «мозг» — посмотрим, как Deaddit заставляет нейросети генерировать осмысленный и, что важнее, разнообразный контент.
loader.py
: Искусство делать ботов «живыми»Файл loader.py
— это настоящая сокровищница для тех, кто хочет понять, как заставить LLM работать на себя. Автор не просто кидает в модель запрос «напиши пост», а выстраивает сложную систему контекста и правил.
select_user_smart
)Проект избегает главной ошибки многих генераторов — случайного выбора автора. Вместо этого используется взвешенный подход, чтобы пользователи, у которых меньше всего постов и комментов, имели больше шансов быть выбранными.
# deaddit/loader.py
def select_user_weighted(users):
# ...
# Получаем текущее количество активностей для каждого юзера
activity_counts = get_user_activity_counts()
# Считаем веса: чем меньше активностей, тем выше вес
weights = []
max_activity = max([activity_counts.get(username, 0) for username in usernames])
for username in usernames:
current_activity = activity_counts.get(username, 0)
weight = (max_activity + 1) - current_activity
weights.append(max(weight, 1))
# Выбираем пользователя с учетом весов
selected_user = random.choices(users, weights=weights, k=1)[0]
return selected_user
[!NOTE] Стратегии на выбор Автор даже предусмотрел несколько стратегий выбора в
Config
:weighted
(взвешенный, по умолчанию),round_robin
(строго по очереди, выбирает того, у кого меньше всего постов) иimproved_random
. Это показывает зрелый подход к проблеме разнообразия контента.
get_system_prompt
)Это сердце всей системы. Вместо одного статичного системного промпта, Deaddit генерирует его на лету для каждой задачи, основываясь на личности AI-агента.
Промпт собирается как конструктор:
get_personality_archetype
определяет основной архетип (аналитик, креативщик, спорщик и т.д.) и добавляет соответствующие инструкции по поведению.subdeaddit_context
, добавляется фраза вроде «You're familiar with r/{subdeaddit.name} and understand its community culture...».В конце добавляются универсальные «Правила Аутентичности», которые заставляют модель вести себя более естественно: не здороваться, не писать общими фразами, включать в текст персональные причуды.
get_diverse_comment_strategy
и get_varied_comment_structure
)Чтобы комментарии не были однотипными, loader.py
использует две гениальные функции:
get_diverse_comment_strategy
: Перед генерацией комментария эта функция выбирает стратегию. Она зависит от архетипа пользователя. Например, «аналитик» может получить стратегию «Найти логические несостыковки», а «эмпат» — «Признать эмоциональную сложность ситуации». Это напрямую влияет на содержание комментария.get_varied_comment_structure
: Эта функция определяет структуру ответа: будет ли он коротким и едким, или длинным и рассудительным. Выбор зависит от фазы обсуждения и личности бота.Этот двухэтапный подход — стратегия + структура — ключ к созданию иллюзии живой дискуссии, а не просто набора однотипных ответов.
analyze_conversation_context
)При генерации комментария Deaddit не просто смотрит на пост. Он анализирует всю ветку комментариев. Функция analyze_conversation_context
пытается понять:
На основе этого анализа система может попросить AI-агента, например, «попробовать разрядить обстановку» в конфликтной ветке или «задать наводящий вопрос», если обсуждение затухает. Это уже не просто генерация, а модерация и симуляция социального взаимодействия.
Ваша поддержка — это энергия для новых статей и проектов. Спасибо, что читаете!
Deaddit — это отличный пример того, как нужно подходить к созданию пет-проектов.
Этот проект — прекрасный учебный материал для тех, кто хочет не просто «дергать API», а создавать осмысленные приложения на основе LLM.