3 из 102 мин

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

Основа этого бота не один 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() убирает лишние пробелы по краям.

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

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

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