Бессмысленность и скоротечность

Философия, встроенная в память, разговор и код

10 заметок · 17 мин

«Бессмысленность и скоротечность» как философия, встроенная в память, разговор и рециркуляцию.: иллюстрация 1
Мы встречаемся на пороге между условной нормой и хаосом Бессмысленность и скоротечность 👆

Оглавление

  1. Как из идеи книги родилось пространство для памяти, разговора и рециркуляции2 мин
  2. Из чего на самом деле состоит этот проект1 мин
  3. Память, профиль и контекст: на чем держится бот2 мин
  4. По какой логике бот отвечает людям2 мин
  5. Как я сделал систему, которая не даёт контенту исчезатьфото2 мин
  6. Как философия проекта вшита в кодфото2 мин
  7. Почему этот проект живёт не только в тексте3 мин
  8. Как бот собирает и обновляет профили людейфото1 мин
  9. Как я защищаю проект от хаоса, дублей и случайностифото1 мин
  10. Почему я писал этот код не ради автоматизации1 мин

Как из идеи книги родилось пространство для памяти, разговора и рециркуляции

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

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

Вместо неё постепенно возникла другая форма.

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

Отчасти поэтому и появился чат «Бессмысленность и скоротечность» вместе с ботом ann: не только как отдельное пространство для этого материала, но и как способ косвенно раскрывать философию, из которой этот материал возникает.

Со временем этот чат стал медиатекой и средой, в которой контент не исчезает после публикации, а возвращается, рециркулируется и продолжает жить.

Социальные сети устроены так, что почти любая вещь быстро тонет в потоке. Мне этот принцип всегда казался слишком бедным. Некоторые вещи раскрываются не сразу. Иногда им нужен не день и не месяц, а годы.

Поэтому внутри этого пространства появился бот ann. Не как украшение и не как функция ради функции. Его задача другая: в разговоре, вскользь, не в лоб, показывать философию, которая лежит под тем, что я делаю. Объяснять не отдельные посты, а тот угол зрения, из которого они возникают.

Для меня «Бессмысленность и скоротечность» это не просто чат и не просто архив. Это попытка создать среду, в которой вещи не растворяются в потоке сразу после появления, а сохраняют право быть увиденными и понятыми позже.

К оглавлению

Из чего на самом деле состоит этот проект

Со стороны это выглядит просто: чат, бот, ответы. Но на деле этот проект устроен как система из нескольких слоев.

Первый слой это Telegram-интерфейс: сообщения, команды, медиа, точки входа и само взаимодействие с людьми.

Второй слой это база данных SQLite. В ней хранятся сообщения, пользователи, профили, evidence, медиа и служебное состояние. Иначе бот оставался бы существом с памятью длиной в одно окно чата.

Третий слой это контекстная логика. Бот опирается не только на последнее сообщение, а на историю общения, профиль человека, предыдущие реакции, внутренние правила и уже накопленный материал.

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

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

И, наконец, есть фоновые процессы: обновление профилей, ротация контента, служебные состояния, отдельные циклы для поддержания всей системы в живом состоянии.

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

К оглавлению

Память, профиль и контекст: на чем держится бот

Основа этого бота не один prompt, а собственная память в SQLite.

Вот один из базовых фрагментов:

c.execute("""
CREATE TABLE IF NOT EXISTS ann_messages(
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  chat_id INTEGER, msg_id INTEGER,
  user_id INTEGER, date TEXT, text TEXT,
  reply_to_msg_id INTEGER, entities_json TEXT
)
""")

— CREATE TABLE IF NOT EXISTS ann_messages
Создаёт таблицу ann_messages, если её ещё нет.
Именно здесь бот хранит историю диалога.

— id INTEGER PRIMARY KEY AUTOINCREMENT
Внутренний порядковый номер строки.
Нужен самой базе, чтобы у каждой записи был свой уникальный ID.

— chat_id INTEGER
ID чата, откуда пришло сообщение.
Это нужно, чтобы не смешивать сообщения из разных чатов.

— msg_id INTEGER
ID самого сообщения в Telegram.
По нему можно понять, о каком именно сообщении идёт речь.

— user_id INTEGER
ID пользователя, который отправил сообщение.
То есть бот запоминает не только текст, но и автора.

— date TEXT
Дата и время сообщения.
Нужно для хронологии: кто, что и когда сказал.

— text TEXT
Сам текст сообщения.

— reply_to_msg_id INTEGER
Если сообщение было ответом на другое сообщение, здесь хранится ID этого исходного сообщения.
Это уже не просто память о тексте, а память о структуре разговора.

— entities_json TEXT
Служебные данные Telegram: упоминания, ссылки, форматирование и другие сущности.
То есть бот при желании может помнить не только текст, но и его форму.

Теперь момент записи сообщения в базу:

def ann_touch_message(user_id: int, chat_id: int, msg_id: int|None, text: str|None, dt_iso: str|None,
                      reply_to_msg_id: int|None, entities_json: str|None):
    c.execute("""
      INSERT INTO ann_messages(chat_id, msg_id, user_id, date, text, reply_to_msg_id, entities_json)
      VALUES(?,?,?,?,?,?,?)
    """, (int(chat_id), int(msg_id or 0), int(user_id), dt_iso or _utc_now_iso(), (text or "").strip(), reply_to_msg_id, entities_json))

— def ann_touch_message(…)
Функция, которая сохраняет новое сообщение в память бота.

— INSERT INTO ann_messages(…)
Команда вставляет новую строку в таблицу ann_messages.

— VALUES(?,?,?,?,?,?,?)
Сюда подставляются реальные значения: чат, сообщение, пользователь, дата, текст, reply и entities.

— int(chat_id)
Приводит chat_id к числу.
Это защита от кривых типов.

— int(msg_id or 0)
Если msg_id нет, ставится 0.
То есть функция всё равно сможет сохранить запись.

— dt_iso or _utc_now_iso()
Если дата не передана, берётся текущее время.

— (text or “”).strip()
Если текста нет, подставляется пустая строка.
strip() убирает лишние пробелы по краям.

Именно в этом месте бот перестаёт быть обычным чат-ботом.
Он не просто отвечает на последнее сообщение, а складывает разговор в собственную память: кто написал, когда написал, что написал и на что отвечал.

Дальше уже поверх этой памяти строятся профиль и контекст. Но фундамент начинается именно здесь.

К оглавлению

По какой логике бот отвечает людям

Бот отвечает не по принципу “увидел сообщение → сразу сгенерировал текст”.

Сначала он решает, нужно ли вообще отвечать. Потом собирает контекст, подтягивает профиль и только после этого строит ответ.

Один из ключевых узлов выглядит так:

ctx = ann_build_context_from_db(chat_id, limit=ANN_CONTEXT_MSG_LIMIT, max_chars=ANN_CONTEXT_MAX_CHARS)
profile_block = _build_profile_prompt_block(last_user_text, base_max_tokens, mention_max_tokens)

messages = [
    {"role": "system", "content": system_prompt},
    {"role": "system", "content": profile_block},
    {"role": "user", "content": ctx},
]

Что здесь важно:

• ann_build_context_from_db(…)
Функция собирает контекст из базы данных.
То есть бот берет не только последнее сообщение, а историю разговора перед ответом.

• chat_id
Контекст собирается для конкретного чата.
Это защита от смешивания разных диалогов.

• limit=ANN_CONTEXT_MSG_LIMIT
Ограничивает, сколько сообщений брать в контекст.
Иначе prompt раздуется и станет шумным.

• max_chars=ANN_CONTEXT_MAX_CHARS
Дополнительно ограничивает размер контекста в символах.
Это нужно, чтобы не перегружать модель.

• _build_profile_prompt_block(…)
Отдельно строит блок профиля пользователя.
То есть бот подмешивает не только историю чата, но и накопленные наблюдения о человеке.

• last_user_text
В профильный блок передаётся последнее сообщение пользователя.
Это помогает выбрать более релевантный тон и факт из профиля.

• messages = […]
Это уже финальная сборка prompt-пакета перед генерацией.

• {“role”: “system”, “content”: system_prompt}
Главный системный слой.
Здесь лежит общий характер бота, его рамка и поведение.

• {“role”: “system”, “content”: profile_block}
Второй системный слой.
Здесь лежит персонализация: тон, факты, особенности конкретного человека.

• {“role”: “user”, “content”: ctx}
А здесь лежит уже сам собранный контекст разговора.

То есть логика такая:

  1. бот не отвечает “вслепую”
  2. сначала собирает историю диалога
  3. потом добавляет профиль человека
  4. потом соединяет это с общей философией и системными правилами
  5. и только после этого генерирует ответ

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

К оглавлению

Как я сделал систему, которая не даёт контенту исчезать

Одна из главных задач этого проекта не только отвечать людям, но и возвращать материал обратно в жизнь.

Для этого у бота есть отдельная база контента. В ней хранятся не только сами материалы, но и их описания. Именно по этим описаниям система понимает, что и когда может снова появиться в разговоре.

Один из ключевых фрагментов выглядит так:

def load_content_index(path: str = CONTENT_JSON_PATH):
    global _content_loaded, content_index, content_embeddings
    if _content_loaded:
        return

    with open(path, "r", encoding="utf-8") as f:
        raw = json.load(f)

    content_index = raw.get("items", []) or []
    content_embeddings = [_extract_embedding(item) for item in content_index]
    _content_loaded = True

Что здесь важно:

• load_content_index(…)
Функция загружает контентную базу из content.json.

• global _content_loaded, content_index, content_embeddings
Здесь объявляются общие переменные, в которых потом живёт загруженный контент.

• if _content_loaded: return
Если база уже загружена, повторно читать файл не нужно.
Это экономит время и не делает лишнюю работу.

• json.load(f)
Читает JSON-файл целиком.

• content_index = raw.get(“items”, []) or []
Достаёт список материалов. То есть бот работает с отдельным индексом контента.
Если ключа items нет, подставляется пустой список.

• content_embeddings = [_extract_embedding(item) for item in content_index]
Для каждого элемента отдельно вытаскивается embedding.
То есть контент хранится не только как текст или ссылка, но и как вектор для смыслового поиска.

• _content_loaded = True
Пометка, что база уже в памяти.

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

Ещё один важный узел:

picked = pick_relevant_content(query_text, top_k=CONTENT_TOP_K)
if picked:
    send_content_to_chat(chat_id, picked)

Что происходит здесь:

• pick_relevant_content(query_text, top_k=CONTENT_TOP_K)
Система получает текущий текст или тему разговора и ищет среди контента наиболее подходящие элементы.

• query_text
Это то, от чего идёт поиск: сообщение, тема или собранный контекст.

• top_k=CONTENT_TOP_K
Ограничивает количество кандидатов.
Бот не тащит всё подряд, а выбирает только верхние совпадения.

• if picked:
Если подходящий материал найден, бот идёт дальше.

• send_content_to_chat(chat_id, picked)
Отправляет найденный материал обратно в чат.

Именно здесь начинается рециркуляция.
Материал не лежит мёртвым архивом. Он может снова появиться в разговоре, если система понимает, что сейчас для него есть место.

То есть логика здесь такая:

  1. контент хранится отдельно
  2. для него есть embeddings
  3. бот умеет искать по смыслу
  4. найденный материал возвращается в чат
  5. старые вещи не исчезают, а получают новую точку входа

Поэтому этот проект для меня не просто бот.
Это система, в которой память работает не только на ответы, но и на возвращение материала в жизнь.

Как я сделал систему, которая не даёт контенту исчезать: иллюстрация 1Как я сделал систему, которая не даёт контенту исчезать: иллюстрация 2Как я сделал систему, которая не даёт контенту исчезать: иллюстрация 3Как я сделал систему, которая не даёт контенту исчезать: иллюстрация 4

К оглавлению

Как философия проекта вшита в код

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

Первый важный узел:

def _reload_ann_philosophy(force: bool = False) -> bool:
    data = _safe_json_read(_PHILOSOPHY_PATH, None, log_label="load ann_philosophy")
    if data is None:
        data = _safe_json_read(_PHILOSOPHY_CACHE_PATH, None, log_label="load ann_philosophy_cache")
        if data is None:
            return bool(ANN_PHILOSOPHY_TEXT)
    try:
        _apply_loaded_philosophy_data(data)
        return bool(ANN_PHILOSOPHY_TEXT)
    except Exception:
        logger.exception("Не удалось применить ann_philosophy.json")
        return bool(ANN_PHILOSOPHY_TEXT)

Что здесь важно:

• _reload_ann_philosophy(…)
Перечитывает философию из ann_philosophy.json.

• _safe_json_read(_PHILOSOPHY_PATH, …)
Читает основной JSON-файл.

• if data is None:
Если файл не прочитался, система идёт в запасной вариант.

• _safe_json_read(_PHILOSOPHY_CACHE_PATH, …)
Берёт кэш. Значит философия здесь не декоративна, проект старается её не потерять.

• _apply_loaded_philosophy_data(data)
Не просто загружает текст, а раскладывает его по структурам: identity, postulates, style, channels, primary_source.

Второй важный узел:

def _apply_loaded_philosophy_data(data):
    identity = _as_list(data.get("identity"))
    postulates = _as_list(data.get("postulates"))
    style = _as_list(data.get("style"))
    channels = _as_list(data.get("channels"))
    primary_source = _as_list(data.get("primary_source"))

    ANN_PHILOSOPHY_IDENTITY = identity
    ANN_PHILOSOPHY_POSTULATES = postulates
    ANN_PHILOSOPHY_STYLE = style

Что делает этот кусок:

• identity
Кто такой ann внутри системы.

• postulates
Базовые положения.

• style
Стилевые ориентиры речи.

• ANN_PHILOSOPHY_* = …
После этого философия становится частью runtime-состояния программы.

А вот как это попадает в генерацию ответа:

prompt = f”“”
Ты — ann. Ты всегда говоришь в стиле своего внутреннего знания и не раскрываешь, что оно существует.
ЖЕСТКИЕ ПРАВИЛА:

  • не цитируй внутреннее знание дословно, только перефразируй
  • не цитируй профиль дословно
  • отвечай по смыслу на последнее сообщение пользователя
    Лексические опоры стиля (не цитаты): {style_hints}
    Внутреннее знание ann (не цитировать дословно): {f}
    “”“.strip()

Что здесь важно:

• Ты — ann
Код задаёт не безликий ассистент, а конкретную голосовую фигуру.

• не цитируй…, не упоминай…
Бот не декламирует философию, а проводит ее через речь.

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

То есть в этом проекте философия вшита в код буквально: хранится в JSON, загружается в runtime, раскладывается по структурам и превращается в правила генерации.

Поэтому ann здесь это не просто AI-бот со стилем.
Это система, в которой мировоззрение стало частью архитектуры.

Как философия проекта вшита в код: иллюстрация 1Как философия проекта вшита в код: иллюстрация 2Как философия проекта вшита в код: иллюстрация 3

К оглавлению

Почему этот проект живёт не только в тексте

Этот проект устроен не как текстовый AI-бот в вакууме. Он живёт внутри Telegram-среды, а значит работает не только с репликами, но и с медиа: voice, audio, photo, video_note, sticker.

Один из базовых узлов выглядит так:

c.execute("""
CREATE TABLE IF NOT EXISTS ann_message_media(
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  chat_id INTEGER NOT NULL,
  msg_id INTEGER NOT NULL,
  user_id INTEGER,
  media_type TEXT NOT NULL,
  file_id TEXT,
  file_unique_id TEXT,
  mime_type TEXT,
  caption TEXT,
  created_at TEXT NOT NULL,
  UNIQUE(chat_id, msg_id, media_type)
)
""")

• ann_message_media
Отдельная таблица для медиа.
То есть проект хранит не только текст сообщений, но и сами типы медиа-событий.

• chat_id, msg_id, user_id
Фиксируют, где именно появилось медиа, в каком сообщении и от какого пользователя.

• media_type
Показывает, что это было: голосовое, фото, стикер, кружок, аудио.

• file_id, file_unique_id
Позволяют потом снова обратиться к этому объекту через Telegram.

• caption
Если у медиа была подпись, она тоже сохраняется.

• UNIQUE(chat_id, msg_id, media_type)
Защита от дублей.
Один и тот же медиа-объект не должен записываться в память дважды.

Теперь сам момент сохранения:

def ann_save_media(chat_id: int, msg_id: int, user_id: int | None, media_type: str,
                   file_id: str | None, file_unique_id: str | None,
                   mime_type: str | None = None, caption: str | None = None):
    c.execute("""
      INSERT OR IGNORE INTO ann_message_media
      (chat_id, msg_id, user_id, media_type, file_id, file_unique_id, mime_type, caption, created_at)
      VALUES(?,?,?,?,?,?,?,?,?)
    """, (...))

• ann_save_media(…)
Функция сохраняет медиа в память проекта.

• INSERT OR IGNORE
Если такая запись уже есть, база не создаёт дубль.
Это важно для стабильной работы в Telegram, где одно и то же событие иногда может прийти повторно.

• media_type, file_id, caption
Проект запоминает не просто “было какое-то медиа”, а его тип, идентификатор и контекст.

То есть бот хранит не только разговор в словах, но и разговор в формах.

А дальше у проекта есть ещё один слой, уже публикационный:

c.execute("""
CREATE TABLE IF NOT EXISTS ann_story_state(
  id INTEGER PRIMARY KEY CHECK (id=1),
  last_story_at TEXT,
  last_source_chat_id INTEGER,
  last_source_msg_id INTEGER,
  last_file_unique_id TEXT,
  cooldown_until TEXT,
  note TEXT
)
""")

• ann_story_state
Это таблица состояния Stories.

• last_story_at
Когда Story публиковалась в последний раз.

• last_source_chat_id, last_source_msg_id
Откуда был взят исходный материал.

• last_file_unique_id
Какой именно файл уже использовался.

• cooldown_until
Когда снова можно публиковать.

То есть проект работает с медиа не как с мёртвыми вложениями.
Он помнит их, различает, связывает с источником и управляет их повторным появлением.

Именно поэтому этот проект живет не только в тексте.
Он живет в материале: в голосе, изображении, стикере, кружке, подписи, публикации, повторном возвращении файла в поток.

И в этом смысле он устроен не как “чат с AI”, а как система, встроенная в реальную медиа-жизнь Telegram.

К оглавлению

Как бот собирает и обновляет профили людей

Один из самых редких механизмов в этом проекте связан не с ответами, а с тем, как система постепенно собирает профиль человека.

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

Ключевой узел выглядит так:

if n >= PROFILE_UPDATE_EVERY:
    c.execute("UPDATE ann_profile_counters SET since_last_update=0 WHERE user_id=?", (int(user_id),))
    queue_profile_update(int(user_id))

• PROFILE_UPDATE_EVERY
Задаёт порог обновления.
Профиль не дёргается после каждого нового сообщения.

• since_last_update
Счётчик показывает, сколько нового материала накопилось с прошлого обновления.

• queue_profile_update(int(user_id))
Пересборка профиля выносится отдельно.
Это значит, что система сначала накапливает наблюдения, а потом обновляет профиль как самостоятельную задачу.

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

Сам профиль хранится отдельно:

CREATE TABLE IF NOT EXISTS ann_profiles(...)

А основания для него ещё в одном слое:

CREATE TABLE IF NOT EXISTS ann_profile_evidence(...)

• ann_profiles
Хранит текущее описание человека внутри системы.

• ann_profile_evidence
Хранит, на чём это описание вообще основано.

Это важный момент.
Проект не просто “формирует впечатление” о пользователе. Он хранит ещё и следы, из которых это впечатление выросло.

Поэтому бот работает не с разовым образом собеседника, а с длительно уточняемым представлением о человеке.

Именно это делает профиль в проекте не декоративной персонализацией, а отдельным операционным слоем системы.

Как бот собирает и обновляет профили людей: иллюстрация 1

К оглавлению

Как я защищаю проект от хаоса, дублей и случайности

Самая неприятная вещь в таких проектах не ошибки, а тихий накапливающийся хаос.

Когда одно и то же событие приходит дважды.
Когда медиа сохраняется повторно.
Когда система постепенно начинает противоречить самой себе.

Снаружи это почти незаметно.
Но именно так проект и теряет форму.

Первое, что пришлось сделать, это остановить дубли на самом низком уровне:

UNIQUE(chat_id, msg_id, media_type)

База просто не даёт записать одно и то же дважды.
Без дополнительной логики и без надежды, что это потом кто-то разберёт вручную.

Следом идёт второй слой:

INSERT OR IGNORE INTO ann_message_media

Если событие уже было, оно просто не проходит дальше.
Лишнее состояние не создаётся.

Но дубли это только часть проблемы.

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

Здесь появляется:

cooldown_until

Система хранит момент, раньше которого она не должна ничего делать.
Это уже не про функциональность, а про дисциплину поведения.

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

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

И, наконец, сбои.

Если внешний слой падает, проект не должен превращаться ни в тишину, ни в мусор.
Поэтому здесь есть паузы, fallback-сценарии, восстановление состояния, а база работает через WAL, чтобы запись не блокировала систему целиком.

В итоге защита строится по слоям:

  • база не пускает дубли
  • код не усиливает повтор
  • cooldown сдерживает лишнюю активность
  • тяжёлая логика вынесена из диалога
  • сбой не разрушает весь поток работы

И только после этого вообще можно говорить о качестве ответов.

Как я защищаю проект от хаоса, дублей и случайности: иллюстрация 1Как я защищаю проект от хаоса, дублей и случайности: иллюстрация 2Как я защищаю проект от хаоса, дублей и случайности: иллюстрация 3Как я защищаю проект от хаоса, дублей и случайности: иллюстрация 4

К оглавлению

Почему я писал этот код не ради автоматизации

Такие проекты обычно описывают через удобство: бот отвечает, что-то сохраняет, что-то публикует, что-то ищет. Но в моём случае задача изначально была другой.

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

То же самое видно в логике ответа:

messages = [
    {"role": "system", "content": system_prompt},
    {"role": "system", "content": profile_block},
    {"role": "user", "content": ctx},
]

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

Но самый важный момент в том, что проект живёт не только в ответах.

queue_profile_update(int(user_id))
picked = pick_relevant_content(query_text, top_k=CONTENT_TOP_K)
ANN_PHILOSOPHY_STYLE = style

Что здесь важно:

• queue_profile_update(…)
Система продолжает работать и между сообщениями. Она обновляет представление о человеке не мгновенно, а по мере накопления материала.

• pick_relevant_content(…)
Материал не лежит мёртвым архивом. Он возвращается в разговор по смыслу.

• ANN_PHILOSOPHY_STYLE = style
Философия здесь не приложена рядом. Она встроена в поведение и влияет на сам принцип речи.

Поэтому это не просто бот, а среда.
Разговор здесь не обнуляется, материал не исчезает, а философия работает как часть поведения системы.
«Бессмысленность и скоротечность» — среда, где эта логика живёт в действии.

К оглавлению

Следующая серияWithout Streaming