Что получится в результате
Соберем Telegram-бота, внутри которого работает ИИ-агент. Пользователь пишет боту, backend принимает update через webhook, сохраняет сессию, запускает агента, агент отвечает по базе знаний, вызывает только разрешенные tools, передает сложный диалог оператору и при необходимости создает лид или заявку.
В первой версии бот не должен менять CRM, принимать оплату, удалять данные, отправлять массовые сообщения и выполнять произвольные команды пользователя. Правильный MVP: ответы по базе знаний, сбор контакта, команды `/start` и `/help`, handoff оператору, логи, лимиты и тесты.
В результате будет рабочий контур:
- бот описан в `telegram_bots`;
- токен хранится в `telegram_bot_credentials`;
- webhook описан в `telegram_webhooks`;
- пользователи лежат в `telegram_users`;
- чаты лежат в `telegram_chats`;
- сессии лежат в `telegram_sessions`;
- входящие update лежат в `telegram_updates`;
- сообщения лежат в `telegram_messages`;
- команды лежат в `telegram_commands`;
- состояния диалога лежат в `telegram_dialog_state`;
- запуски агента лежат в `telegram_agent_runs`;
- RAG-поиск пишется в `telegram_retrieval_log`;
- tool policy лежит в `telegram_tool_policy`;
- handoff оператору пишется в `telegram_handoff_queue`;
- лиды пишутся в `telegram_crm_lead_queue`;
- исходящие ответы лежат в `telegram_outbox`;
- ошибки лежат в `telegram_error_log`;
- метрики пишутся в `telegram_bot_metrics`;
- тесты лежат в `telegram_bot_test_cases`.
Финальная проверка: пользователь пишет `/start`, задает вопрос, бот отвечает по базе знаний, сохраняет историю, не раскрывает секреты, не вызывает запрещенные tools и умеет передать диалог человеку.
Что понадобится
Подготовьте:
- аккаунт Telegram;
- BotFather;
- домен backend API с HTTPS;
- сервер или deploy, где работает backend;
- LLM API key или локальная модель;
- база знаний для ответов;
- Telegram Bot API token;
- endpoint для webhook;
- секрет для webhook path или header;
- список команд бота;
- список разрешенных tools;
- список запрещенных действий;
- канал handoff: операторский чат, CRM, helpdesk или email;
- 20-30 тестовых сообщений;
- отдельный тестовый бот для staging.
Для первого запуска используйте отдельного staging-бота, чтобы не тестировать webhook и prompts на реальных пользователях.
Шаг 1. Создайте бота в BotFather
Откройте Telegram и найдите `@BotFather`.
Команды:
/newbot
Дальше:
- задайте отображаемое имя;
- задайте username, который заканчивается на `bot`;
- получите bot token;
- сохраните token в secret storage;
- не отправляйте token в чат команды;
- не вставляйте token в frontend.
Проверка:
curl "https://api.telegram.org/botBOT_TOKEN/getMe"
Ожидаемый результат: JSON с `ok: true` и username бота.
Шаг 2. Запишите бота в `telegram_bots`
Создайте таблицу `telegram_bots`.
Колонки:
id
bot_key
bot_username
display_name
environment
default_language
mode
is_active
created_at
updated_at
Пример:
{
"bot_key": "support_bot_staging",
"bot_username": "example_support_ai_bot",
"environment": "staging",
"mode": "support",
"default_language": "ru",
"is_active": true
}
Проверка: staging и production используют разные `bot_key` и разные Telegram tokens.
Шаг 3. Сохраните токен безопасно
Создайте `telegram_bot_credentials`.
Колонки:
id
bot_key
credential_type
secret_ref
scopes_json
last_rotated_at
is_active
Правила:
- token хранится в `.env`, vault или secret manager;
- в базе хранится `secret_ref`, а не сам token;
- token не попадает в logs;
- token не передается в prompt;
- при утечке token перевыпускается в BotFather;
- доступ к token есть только у backend.
Проверка: `rg BOT_TOKEN logs` не находит реальное значение token.
Шаг 4. Выберите webhook, а не polling для production
Для локального прототипа можно использовать polling. Для production лучше webhook.
Polling подходит:
- локальный тест;
- маленький прототип;
- нет публичного HTTPS;
- один процесс разработчика.
Webhook подходит:
- production;
- быстрые ответы;
- масштабирование;
- логирование update;
- контроль retries;
- работа за reverse proxy.
Проверка: production-бот принимает update через HTTPS endpoint, а не через открытый терминал с polling.
Шаг 5. Создайте webhook endpoint
Endpoint:
POST /telegram/webhook/{bot_key}/{secret}
Создайте `telegram_webhooks`.
Колонки:
id
bot_key
webhook_url
secret_token_hash
allowed_updates_json
status
last_checked_at
created_at
`allowed_updates` для MVP:
["message", "callback_query"]
Проверка: endpoint принимает только POST и возвращает `200` быстро, без долгого LLM-запроса внутри webhook.
Шаг 6. Установите webhook в Telegram
Команда:
curl -X POST "https://api.telegram.org/botBOT_TOKEN/setWebhook" \
-H "Content-Type: application/json" \
-d '{
"url": "https://agent.example.com/telegram/webhook/support_bot_staging/SECRET_PATH",
"allowed_updates": ["message", "callback_query"],
"drop_pending_updates": true
}'
Проверьте:
curl "https://api.telegram.org/botBOT_TOKEN/getWebhookInfo"
Ожидаемый результат:
- `url` заполнен;
- `pending_update_count` не растет;
- `last_error_message` пустой;
- сертификат HTTPS валидный.
Проверка: отправьте боту `/start`, и backend должен получить update.
Шаг 7. Сохраняйте входящие update
Создайте `telegram_updates`.
Колонки:
id
bot_key
update_id
update_type
payload_json
received_at
processed_at
status
Статусы:
- `received`;
- `queued`;
- `processed`;
- `ignored`;
- `failed`;
- `duplicate`;
Правила:
- `update_id` уникален внутри bot;
- webhook быстро сохраняет update;
- тяжелая обработка идет через очередь;
- дубль update не обрабатывается второй раз;
- payload хранится для отладки.
Проверка: повтор одного update не вызывает второй ответ пользователю.
Шаг 8. Создайте пользователей и чаты
Создайте `telegram_users`.
id
telegram_user_id
username
first_name
last_name
language_code
is_bot
first_seen_at
last_seen_at
Создайте `telegram_chats`.
id
telegram_chat_id
chat_type
title
username
bot_key
is_active
created_at
updated_at
`chat_type`:
- `private`;
- `group`;
- `supergroup`;
- `channel`.
Для MVP отвечайте только в `private`, если не планируете групповую модерацию.
Проверка: сообщение из группы игнорируется или обрабатывается отдельным правилом, а не смешивается с личным чатом.
Шаг 9. Создайте сессии диалога
Создайте `telegram_sessions`.
Колонки:
id
session_id
bot_key
telegram_chat_id
telegram_user_id
status
current_intent
last_message_at
created_at
closed_at
Статусы:
- `active`;
- `waiting_agent`;
- `waiting_user`;
- `handoff_requested`;
- `lead_capture`;
- `closed`;
- `blocked`.
Правила:
- одна active session на личный chat;
- session закрывается после таймаута;
- `/start` может создать новую session;
- `/reset` очищает состояние;
- handoff не теряется после перезапуска backend.
Проверка: пользователь может написать через час, и бот продолжит или корректно начнет новую сессию.
Шаг 10. Сохраняйте сообщения
Создайте `telegram_messages`.
Колонки:
id
session_id
telegram_message_id
sender_type
message_type
text
attachments_json
reply_to_message_id
created_at
`sender_type`:
- `user`;
- `bot`;
- `operator`;
- `system`.
`message_type`:
- `text`;
- `command`;
- `voice`;
- `photo`;
- `document`;
- `callback_query`;
- `unsupported`.
Проверка: текст пользователя и ответ бота связаны одной session.
Шаг 11. Настройте команды бота
Создайте `telegram_commands`.
Колонки:
id
bot_key
command
description
handler_key
is_active
Минимальные команды:
- `/start` - начать диалог;
- `/help` - показать возможности;
- `/reset` - сбросить контекст;
- `/operator` - позвать человека;
- `/privacy` - показать правила обработки данных;
- `/status` - показать статус заявки, если есть.
Установите команды:
curl -X POST "https://api.telegram.org/botBOT_TOKEN/setMyCommands" \
-H "Content-Type: application/json" \
-d '{
"commands": [
{"command": "start", "description": "Начать диалог"},
{"command": "help", "description": "Что умеет бот"},
{"command": "operator", "description": "Позвать оператора"},
{"command": "privacy", "description": "Обработка данных"}
]
}'
Проверка: команды видны в меню Telegram.
Шаг 12. Настройте состояние диалога
Создайте `telegram_dialog_state`.
Колонки:
id
session_id
state_key
state_payload_json
expires_at
updated_at
Состояния:
- `idle`;
- `answering_question`;
- `collecting_contact`;
- `waiting_operator`;
- `creating_lead`;
- `blocked`;
Правила:
- состояние имеет TTL;
- `/reset` очищает состояние;
- контакт собирается пошагово;
- агент не должен зациклиться на одном вопросе;
- состояние не заменяет долговременную память.
Проверка: если пользователь начал оставлять контакт и передумал, бот возвращается в `idle`.
Шаг 13. Обработайте обычное сообщение
Алгоритм backend:
- принять update;
- проверить duplicate;
- сохранить user и chat;
- найти или создать session;
- сохранить message;
- проверить command;
- проверить rate limit;
- проверить guardrails;
- создать `telegram_agent_runs`;
- отправить задачу в очередь;
- быстро вернуть `200` Telegram.
Проверка: webhook не ждет полного ответа LLM дольше нескольких секунд.
Шаг 14. Создайте `telegram_agent_runs`
Колонки:
id
run_id
session_id
message_id
status
input_json
output_json
confidence_score
needs_human
model_name
started_at
finished_at
Статусы:
- `queued`;
- `running`;
- `completed`;
- `needs_human`;
- `failed`;
- `blocked`;
- `timeout`.
Проверка: любой ответ бота можно связать с конкретным run.
Шаг 15. Подключите базу знаний
Создайте `telegram_knowledge_sources`.
Колонки:
id
bot_key
source_key
source_type
source_url
status
last_indexed_at
Подключите:
- FAQ;
- инструкции;
- цены;
- правила поддержки;
- описания услуг;
- ограничения;
- контакты;
- политику обработки данных.
Проверка: бот отвечает только по опубликованным источникам текущего bot key.
Шаг 16. Настройте RAG-поиск
Создайте `telegram_retrieval_log`.
Колонки:
id
run_id
query_text
matched_chunk_ids_json
top_score
used_in_answer
created_at
Правила:
- искать по базе знаний бота;
- top 3-5 chunks передавать в prompt;
- не использовать устаревшие chunks;
- при плохом score переводить в handoff;
- сохранять source ids для проверки;
- не отвечать без источника на важные темы.
Проверка: вопрос "сколько стоит" использует актуальный chunk с тарифами, а не общий текст.
Шаг 17. Напишите system prompt Telegram-агента
Каркас:
Ты ИИ-агент в Telegram-боте.
Отвечай коротко и по делу.
Используй только контекст базы знаний и разрешенные tools.
Если ответа нет, предложи передать вопрос человеку.
Не проси пароль, код из SMS, токен или полный номер карты.
Не обещай скидки, сроки, оплату или юридические условия без подтвержденных данных.
Если пользователь просит оператора, поставь needs_human = true.
Верни JSON.
Формат ответа:
{
"answer": "Могу помочь с подбором сценария. Напишите, для чего нужен агент: поддержка, продажи или документы.",
"confidence_score": 0.84,
"needs_human": false,
"lead_intent": true,
"used_sources": ["service-overview"],
"next_state": "idle"
}
Проверка: модель возвращает валидный JSON, а не произвольный Markdown.
Шаг 18. Отправляйте ответ через outbox
Создайте `telegram_outbox`.
Колонки:
id
bot_key
session_id
telegram_chat_id
method
payload_json
status
attempts
last_error
sent_at
created_at
Методы:
- `sendMessage`;
- `sendPhoto`;
- `sendDocument`;
- `sendChatAction`;
- `editMessageText`;
- `answerCallbackQuery`.
Для MVP используйте `sendMessage`.
Проверка: если Telegram API временно недоступен, сообщение остается в outbox и повторяется.
Шаг 19. Добавьте inline-кнопки
Кнопки помогают не заставлять пользователя писать лишний текст.
Примеры:
- `Связаться с человеком`;
- `Оставить заявку`;
- `Посмотреть цены`;
- `Сбросить диалог`;
- `Да, передайте менеджеру`;
- `Нет, продолжим здесь`.
Payload:
{
"inline_keyboard": [
[
{"text": "Оставить заявку", "callback_data": "lead:start"},
{"text": "Оператор", "callback_data": "handoff:operator"}
]
]
}
Проверка: `callback_query` сохраняется и не запускает LLM, если это простая кнопка.
Шаг 20. Соберите контакт пошагово
Создайте `telegram_lead_capture`.
Колонки:
id
session_id
step
name
phone
email
company
need_summary
consent_accepted
status
updated_at
Шаги:
- уточнить задачу;
- спросить имя;
- спросить email или телефон;
- уточнить компанию, если нужно;
- показать короткое согласие;
- создать lead;
- отправить подтверждение пользователю.
Правила:
- не спрашивать все поля сразу;
- не выдумывать контакт;
- не создавать lead без контакта;
- не включать marketing consent по умолчанию;
- дать команду `/reset`.
Проверка: пользователь может отказаться оставить контакт, и бот не продолжает давить.
Шаг 21. Подключите CRM или helpdesk
Создайте `telegram_crm_lead_queue`.
Колонки:
id
session_id
telegram_user_id
lead_payload_json
status
crm_lead_id
last_error
created_at
sent_at
Payload:
{
"name": "Иван",
"telegram_username": "ivan_ai",
"email": "ivan@example.com",
"source": "telegram_bot",
"need_summary": "Хочет подключить ИИ-агента к Telegram",
"dialog_summary": "Спросил про RAG, CRM и стоимость"
}
Правила:
- CRM token не попадает в Telegram;
- лид создается после согласия;
- дубли проверяются по email, phone и telegram_user_id;
- ошибка CRM идет в retry;
- пользователь получает мягкое сообщение, если CRM недоступна.
Проверка: после тестовой заявки в CRM появляется один лид с Telegram username и summary.
Шаг 22. Настройте handoff оператору
Создайте `telegram_handoff_queue`.
Колонки:
id
session_id
reason
priority
summary
last_messages_json
target_channel
status
created_at
resolved_at
Причины:
- пользователь просит оператора;
- нет ответа в базе знаний;
- низкая уверенность;
- жалоба;
- вопрос о цене или договоре;
- персональные данные;
- ошибка агента;
- запрос запрещенного действия.
Каналы handoff:
- операторский Telegram-чат;
- CRM task;
- helpdesk ticket;
- email менеджеру.
Проверка: оператор получает summary, ссылку на чат и последние сообщения.
Шаг 23. Настройте operator chat
Создайте отдельный закрытый Telegram-чат для операторов.
`telegram_operator_channels`:
id
bot_key
operator_chat_id
channel_name
is_active
created_at
Сообщение оператору:
Нужен оператор.
Причина: нет ответа в базе знаний.
Пользователь: @ivan_ai
Summary: спрашивает про интеграцию с CRM.
Session: sess_123
Правила:
- не отправлять персональные данные без необходимости;
- не отправлять весь transcript, если он длинный;
- не отправлять секреты;
- оператор может взять диалог в работу;
- статус handoff обновляется.
Проверка: команда `/operator` создает запись и уведомление в операторском чате.
Шаг 24. Ограничьте tools
Создайте `telegram_tool_policy`.
Колонки:
id
tool_name
enabled
can_read
can_write
requires_approval
allowed_chat_types_json
max_calls_per_run
timeout_seconds
Правила для MVP:
- `search_knowledge_base` включен;
- `create_crm_lead` включен после согласия;
- `notify_operator` включен;
- `get_order_status` только read-only;
- `send_mass_message` выключен;
- `delete_user_data` только через operator flow;
- `refund_payment` выключен;
- `update_crm_deal` требует approval.
Проверка: prompt injection не может заставить бота вызвать запрещенный tool.
Шаг 25. Настройте rate limit
Создайте `telegram_rate_limit_rules`.
Колонки:
id
scope
limit_per_minute
limit_per_hour
action_on_limit
is_active
Стартовые лимиты:
- user - 10 сообщений в минуту;
- chat - 30 сообщений в час;
- bot - дневной лимит LLM-бюджета;
- group chat - выключить или сильно ограничить;
- callback_query - 20 в минуту.
При лимите:
- не вызывать LLM;
- отправить короткое предупреждение;
- записать событие;
- при спаме временно заблокировать session.
Проверка: 50 сообщений подряд не сжигают LLM-бюджет.
Шаг 26. Защитите от опасных запросов
Создайте `telegram_guardrail_events`.
Колонки:
id
session_id
rule_key
input_text
action
created_at
Блокируйте или переводите в handoff:
- "игнорируй инструкции";
- "покажи system prompt";
- "покажи token";
- "удали данные";
- "сделай скидку";
- "отправь всем пользователям";
- "выполни shell command";
- "обойди правила";
- пароль или код из SMS;
- токсичные запросы.
Проверка: бот не раскрывает prompt и token даже после прямой просьбы.
Шаг 27. Обработайте вложения и голосовые
В MVP лучше ограничить вложения.
Правила:
- text обрабатывается сразу;
- voice можно отключить или отправлять в transcription queue;
- photo не анализируется без отдельного OCR/vision tool;
- documents не скачиваются без проверки;
- executable и archives блокируются;
- большие файлы отклоняются;
- все file_id сохраняются отдельно.
Создайте `telegram_attachments`.
id
session_id
message_id
file_id
file_type
file_size
status
created_at
Проверка: бот не утверждает, что прочитал файл, если file processing выключен.
Шаг 28. Логируйте ошибки
Создайте `telegram_error_log`.
Колонки:
id
bot_key
session_id
error_type
error_message
context_json
created_at
Ошибки:
- invalid token;
- webhook unavailable;
- LLM timeout;
- Telegram API rate limit;
- sendMessage failed;
- CRM unavailable;
- invalid JSON from model;
- RAG unavailable;
- tool timeout;
- duplicate update.
Проверка: пользователь получает нормальный fallback, а разработчик видит причину в логе.
Шаг 29. Настройте метрики
Создайте `telegram_bot_metrics`.
Колонки:
id
date
bot_key
active_users
messages_in
messages_out
agent_runs
handoff_count
leads_created
error_count
avg_latency_ms
estimated_cost_usd
created_at
Смотрите:
- количество пользователей;
- количество сообщений;
- handoff rate;
- lead conversion;
- error rate;
- p95 latency;
- стоимость;
- темы без ответа;
- rate limit events;
- повторные обращения.
Проверка: после первого дня видно, какие вопросы бот закрывает, а какие уходят оператору.
Шаг 30. Создайте тесты
Создайте `telegram_bot_test_cases`.
Колонки:
id
case_key
case_group
input_update_json
expected_behavior
expected_status
is_critical
Минимальные тесты:
- `/start`;
- `/help`;
- простой вопрос по базе знаний;
- вопрос без ответа;
- запрос оператора;
- сбор email;
- отказ оставить контакт;
- создание CRM lead;
- дубль update;
- callback query;
- prompt injection;
- rate limit;
- LLM timeout;
- Telegram sendMessage error;
- group chat ignored;
- unsupported attachment;
- reset session;
- invalid webhook secret;
- RAG source check;
- отсутствие token в логах.
Проверка: critical tests проходят до подключения production-бота.
Шаг 31. Проведите smoke test
Порядок:
- отправьте `/start`;
- проверьте запись в `telegram_updates`;
- проверьте `telegram_users`;
- проверьте `telegram_sessions`;
- задайте вопрос по базе знаний;
- проверьте `telegram_agent_runs`;
- проверьте `telegram_retrieval_log`;
- получите ответ;
- нажмите inline-кнопку;
- позовите оператора;
- оставьте контакт;
- проверьте CRM lead или handoff;
- отправьте prompt injection;
- проверьте guardrail event.
Проверка результата: весь путь от Telegram update до ответа и лога проходит без ручного запуска worker.
Шаг 32. Включите limited production
Первый запуск:
- один production-бот;
- личные чаты, группы выключены;
- только text messages;
- RAG по одной базе знаний;
- CRM через очередь;
- write-tools выключены или approval;
- daily LLM budget маленький;
- rate limit включен;
- handoff включен;
- первые диалоги проверяет человек.
Проверка: бота можно быстро остановить через `telegram_bots.is_active = false` или удаление webhook.
Шаг 33. Минимальный результат для запуска
MVP готов, если выполнены условия:
- bot создан в BotFather;
- token хранится безопасно;
- webhook установлен;
- update сохраняются;
- users и chats сохраняются;
- session работает;
- commands настроены;
- messages сохраняются;
- agent run создается;
- RAG ищет по базе знаний;
- answer отправляется через outbox;
- inline-кнопки работают;
- lead capture работает;
- CRM lead или handoff работает;
- tool policy ограничивает действия;
- rate limit работает;
- guardrails работают;
- ошибки логируются;
- metrics заполняются;
- smoke test пройден.
Финальная проверка: отправьте `/start`, вопрос по базе знаний, вопрос без ответа, заявку с контактом, prompt injection и повтор webhook. Если ответы корректны, дублей нет, секреты не светятся, а handoff работает, можно запускать ограниченный production.
Что нельзя автоматизировать в первой версии
В первой версии не автоматизируйте:
- массовые рассылки пользователям;
- прием платежей;
- возвраты денег;
- изменение CRM-сделки без approval;
- удаление данных пользователя без оператора;
- обработку любых файлов без проверки;
- ответы в группах без отдельной логики;
- хранение token в коде;
- раскрытие system prompt;
- выполнение shell-команд;
- отправку длинных сырых логов оператору;
- обучение на Telegram-диалогах без очистки;
- сбор лишних персональных данных;
- работу с production-ботом без staging;
- отключение rate limit ради удобства теста.
Сначала бот должен стабильно отвечать, сохранять историю, передавать сложные случаи человеку и не делать опасных действий. Остальные функции добавляйте после тестов.
Частые вопросы
Webhook или polling лучше для Telegram-бота?
Для production лучше webhook: он быстрее, надежнее и проще логируется на сервере. Polling удобен для локального прототипа, но плохо подходит для стабильного запуска.
Можно ли хранить Telegram token в базе?
Лучше хранить token в `.env`, vault или secret manager, а в базе держать только `secret_ref`. Token не должен попадать в prompt, logs и frontend.
Нужно ли отвечать в групповых чатах?
Для первой версии лучше отвечать только в личных чатах. Группы требуют отдельной логики: упоминания бота, модерация, приватность, rate limit и контекст нескольких участников.
Что делать, если бот не знает ответ?
Он должен сказать, что не нашел подтвержденный ответ, и предложить handoff оператору. Нельзя придумывать ответ, особенно по цене, договору, оплате и персональным данным.
Когда можно подключать CRM?
Когда работает базовый диалог, consent, сбор контакта, дедупликация и handoff. CRM write-back делайте через очередь и approval, а не прямым вызовом из prompt.