Self-hosted · Один docker-compose

AI-агент, который читает каждый твой TG-чат

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

SQLite · Claude Haiku 4.5 · grammy long-polling · базa знаний — knowledge_base.md

📥 message classifier decision responder CRM update 📤 reply / notify
10
классов
сообщений
0.7
порог уверенности
→ draft владельцу
5
статусов лида
new → buyer
1
SQLite-файл
= весь бэкап
Классификация

Каждое сообщение —
один из 10 классов

Claude Haiku 4.5 с tool-use выдаёт класс + confidence. Decision engine превращает это в действие. При уверенности ниже 0.7 действие downgrade'ится до DRAFT_FOR_OWNER — ты увидишь черновик в DM и решишь сам.

QUESTION
REPLY
Вопрос по теме — отвечает по базе знаний.
PRODUCT_INTEREST
REPLY
«Расскажи подробнее» — даёт оффер, тянет к следующему шагу.
PRICE_REQUEST
REPLY + NOTIFY
«Сколько стоит?» — отвечает + дёргает тебя в DM.
BUYING_INTENT
REPLY + NOTIFY
«Готов купить» — горячий лид → ✅ в личку.
OBJECTION
REPLY_SOFT
«Дорого / уже есть» — мягкий ответ без давления.
SUPPORT_REQUEST
NOTIFY
«Не работает X» — тихий пинг владельцу, бот не отвечает.
OWNER_REQUEST
DRAFT_FOR_OWNER
«Хочу с Ильёй / лично» — черновик в DM, ты пишешь сам.
NEGATIVE
IGNORE
Хейт / троллинг — игнор. Статус negative залипает.
SPAM
IGNORE
Реклама / флуд — молча.
GENERAL_CHAT
IGNORE
Болтовня не по делу — не лезет.
Деплой

Три шага —
и бот в твоих чатах

Никаких внешних админок, ни Supabase, ни OpenAI. Один процесс, одна SQLite-БД, один docker-compose на твоём сервере.

01 · BOT
🤖

Сделай бота у BotFather

Один диалог с @BotFather: /newbot → токен. Обязательно /setprivacy → Disable, иначе бот в группе будет видеть только команды и упоминания, а нам нужны все сообщения.

⏱ 2 минуты
02 · KB
📚

Положи базу знаний

Один markdown-файл knowledge_base.md с секциями Продукты и цены, FAQ, Возражения, Кейсы, Правила. Бот не имеет права выходить за пределы — если факта нет, честно говорит «уточню».

⏱ 10–20 минут
03 · UP
🚀

docker compose up

Заполни .env (токен, Anthropic-ключ, owner id, ALLOWED_CHAT_IDS, пароль админки) → docker compose up -d. Добавь бота в группы из whitelist — он сразу в работе.

⏱ 5 минут
.env env
# обязательное TELEGRAM_BOT_TOKEN=от @BotFather ANTHROPIC_API_KEY=sk-ant-... # Haiku 4.5 для classifier + responder OWNER_TELEGRAM_ID=1280515130 # твой numeric id, узнать у @userinfobot ALLOWED_CHAT_IDS=-100123,-100456 # whitelist групп, остальное игнор ADMIN_USERNAME=admin ADMIN_PASSWORD=<basic-auth для :8080> CONFIDENCE_THRESHOLD=0.7 # при меньшей — DRAFT_FOR_OWNER
Что внутри

Конвейер из 7 узлов,
под капотом — никакой магии

Каждый файл — отдельный слой, всё читаемо за вечер. Никаких vendor-локов: захочешь — поменяешь responder на свой LLM или классификатор на правила.

🧠

Classifier

Claude Haiku 4.5 + tool-use. На выходе строгий JSON: class + confidence 0–1. 10 классов, никакой свободной формы — никаких сюрпризов в downstream.

Claude Haiku 4.5 tool-use
⚖️

Decision engine

Чистая функция: класс + confidence → одно из IGNORE / REPLY / REPLY_SOFT / REPLY_AND_NOTIFY / NOTIFY_ONLY / DRAFT_FOR_OWNER. Никакого LLM в этом слое — детерминизм.

детерминированный
💬

Responder в твоём стиле

Claude + tone-of-voice + база знаний. У каждого класса своя стратегия ответа. Не вылезает за пределы базы — если факта нет, говорит «уточню», а не выдумывает.

TOV-locked no hallucinations
📁

Кабинет с папками чатов

Админка на :8080: список чатов, у каждого — последние сообщения, юзеры, статусы. По клику открывается полная переписка. auto_reply переключается тоггером.

Hono + Tailwind basic-auth
📈

CRM-лестница

Статус на (chat_id, user_id): new → cold → warm → hot → buyer. Односторонняя — назад не падает. negative залипает, SUPPORT_REQUESTsupport.

state-machine
🔔

Notifier в личку

На REPLY_AND_NOTIFY / NOTIFY_ONLY / DRAFT_FOR_OWNER — DM владельцу с триаж-блоком: кто, в каком чате, что сказал, какое действие. Чтобы DM работал — один раз /start у бота.

triage в DM
🛑

Kill switch per-chat

Один тоггл в админке: auto_reply: OFF. Бот всё ещё классифицирует и пишет в БД, но молчит и не дёргает владельца. Полезно когда сам ведёшь диалог и не хочешь, чтобы бот лез.

мгновенный
🗄️

Один SQLite-файл

Никакого Postgres, Redis или внешних сервисов. Весь state — tg-agent.db в docker volume. Бэкап = sqlite3 .backup в крон. Схема накатывается при старте, миграций руками нет.

better-sqlite3 zero-ops
🔐

Whitelist чатов

ALLOWED_CHAT_IDS в .env — единственный источник того, где бот работает. Добавили в чужой чат? Бот молча проигнорирует. Без whitelist'а вообще не стартует.

safe-by-default
CRM

Лестница лида —
сама поднимается по поведению

Бот не просит вас выбирать статус. Он смотрит на класс сообщения и продвигает (chat, user) вверх по лестнице. Назад не падает — раз стал buyer, остался buyer.

new cold warm hot buyer ✓
QUESTION → cold · PRODUCT_INTEREST → warm · PRICE_REQUEST → hot · BUYING_INTENT → buyer
Стек

Boring tech,
читается за вечер

Ничего нового или экзотического. TypeScript + grammy + Hono + better-sqlite3 + Anthropic SDK. Один Docker-образ, multi-stage build, native-deps собраны заранее.

grammy
Transport для Telegram. Long-polling, single replica.
Claude Haiku 4.5
Classifier + responder. Tool-use для structured output.
Hono
Admin HTTP-сервер на :8080. Basic auth + JSON API.
better-sqlite3
Sync API, native. Один файл, нулевые операции.
TypeScript ESM
tsx для dev, tsc для build. Strict, no any.
Docker
Multi-stage, native-deps в builder. Volume на data.
Caddy / Cloudflare
TLS перед :8080. В compose порт биндится только на 127.0.0.1.
JSON-логи
stdout. Парсятся любым log-агрегатором, grafana / loki — опционально.
FAQ

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

Только если в @BotFather выключить privacy mode: /setprivacy → выбрать бота → Disable. В дефолтном privacy mode боты в группах видят только команды (/...) и упоминания (@bot). Без Disable вся идея не работает — classifier не получит сообщения для разметки.
ALLOWED_CHAT_IDS в .env — whitelist. Сообщения из чатов вне списка проходят через handler, но decision engine принудительно ставит IGNORE. Никакого ответа, никакого классификатора, никакого расхода токенов на чужие чаты.
При confidence < CONFIDENCE_THRESHOLD (0.7 по умолчанию) любое не-IGNORE действие downgrade'ится до DRAFT_FOR_OWNER. Ты получаешь в DM: класс, confidence, оригинал сообщения, предлагаемый ответ. Решаешь — отправить, отредактировать или просто посмотреть.
В админке на tg.46-62-215-11.nip.io у каждого чата есть тоггл auto_reply. OFF — бот всё ещё классифицирует и пишет в БД, но молчит и не дёргает тебя. ON — снова в бою. Изменение мгновенное, рестарт не нужен.
Один SQLite-файл в docker volume tg-agent-data. Три таблицы: tg_chats (чат + auto_reply), tg_users (лестница лида), tg_messages (полный лог). Бэкап — sqlite3 .backup в крон, ничего больше. Никаких облачных БД.
Да. classifier.ts и responder.ts изолированы за функциями classify() и respond(). Меняй внутренности — остальное не заметит. Decision engine, CRM и админка — pure logic, без LLM.
Не делает backfill истории чата — видит только новые сообщения с момента старта. Не одобряет DRAFT_FOR_OWNER кнопками в DM — пока ты просто видишь черновик и пишешь сам. Не работает в личных чатах с клиентами (DM) — заточен под групповые. И базовая авторизация админки — только HTTP basic, поэтому перед публикой обязателен TLS-терминатор (Caddy / Cloudflare).

Бот, который не пропускает горячих лидов

Один docker-compose, твой сервер, твоя база знаний. Никакой облачной БД, никаких API-ключей, кроме твоих собственных.

Открыть админку → Что внутри

Сейчас живёт на одной машине · admin under tg.46-62-215-11.nip.io