Документация
AI Telegram bot
Что делает: пользователь пишет Telegram-боту → SUMMING gets update → LLM отвечает на основе вашей knowledge-базы (через RAG) → бот отправляет ответ. Помнит контек
Что делает: пользователь пишет Telegram-боту → SUMMING gets update → LLM отвечает на основе вашей knowledge-базы (через RAG) → бот отправляет ответ. Помнит контекст разговора per-чат.
Типовой use-case: FAQ-бот магазина, бот технической поддержки, «спроси нашу документацию» ассистент.
Prerequisites
- Telegram-бот + webhook setup (getting-started/telegram.md)
- SUMMING knowledge-база — это data-table с текстовыми чанками,
которые
ai.embedнода предварительно проиндексировала - LLM API key настроен
Secrets
telegram-bot-token
telegram-webhook-secret
Подготовка knowledge-базы (один раз)
1. Создайте data-table kb-chunks
Data Tables → + New → name: kb-chunks → schema:
| Column | Type | Description |
|---|---|---|
| chunk_text | text | Raw текст чанка |
| source | text | Откуда (URL / имя файла) |
| embedding | vector(1536) | Вектор (заполняется при загрузке) |
2. Загрузите документы
Через CSV-импорт или через ad-hoc workflow. Пример workflow'а для bulk-import'а:
cron.trigger (once, manual)
↓
external.http
url: "https://your-cms.example/api/articles"
(или load'ите из файла через data.fetch)
↓
data.array.foreach (on: articles)
ai.embed
input: "{{item.title}}\n\n{{item.body}}"
↓
data_table.rows.insert
table: kb-chunks
data:
chunk_text: "{{item.title}}\n\n{{item.body}}"
source: "{{item.url}}"
embedding: "{{embed.output}}"
Это одноразовый workflow — запускаете его, когда обновляете knowledge-базу.
Bot workflow
┌──────────────────┐
│ telegram.webhook │
│ .trigger │
└────────┬─────────┘
│ {message: {text, chat.id, from.id}}
↓
┌──────────────────┐
│ ai.rag.answer │ semantic search + LLM answer
│ │ memory_key: "tg:{{chat.id}}"
└────────┬─────────┘
│ {answer: "...", sources: [...]}
↓
┌──────────────────┐
│ telegram.message │ reply_to original message
│ .send │
└──────────────────┘
Node-by-node
1. telegram.webhook.trigger
secretTokenRef: telegram-webhook-secret
filter:
# Игнорируем все updates кроме text-messages в приватном чате.
# edited_message / callback_query / group-chats пусть идут мимо.
expression: |
trigger.message && trigger.message.text && !trigger.edited_message
2. ai.rag.answer
query: "{{trigger.message.text}}"
knowledgeBase:
table: kb-chunks
embeddingColumn: embedding
textColumn: chunk_text
topK: 5
minSimilarity: 0.7 # чтобы не отвечать на вопросы, где KB пуста
systemPrompt: |
Ты помощник магазина Acme. Отвечай только на основе приведённого
контекста. Если контекста недостаточно — скажи «Не нашёл в
документации, переключаю на менеджера» и ничего не выдумывай.
memory:
key: "tg:{{trigger.message.chat.id}}"
ttlSeconds: 3600 # история чата — 1 час
model: gpt-4o-mini
maxTokens: 500
ai.rag.answer объединяет три операции: embedding запроса (ai. embed внутри), vector-search по kb-chunks (ai.vector.search) +
LLM-call с context'ом (ai.generate). Это shortcut-нода — если
вам нужен custom-поведение, разбейте на три отдельные.
3. telegram.message.send
chat_id: "{{trigger.message.chat.id}}"
text: "{{rag.answer.answer}}"
reply_to_message_id: "{{trigger.message.message_id}}"
parse_mode: Markdown
Runtime behavior
Первое сообщение:
/runs— новый run- Timeline:
webhook.trigger(5ms) →ai.rag.answer(800-1500ms, embedding + search + LLM) →telegram.message.send(200ms) - Ответ в Telegram приходит в течение 1-2 секунд
Второе сообщение в том же чате:
ai.rag.answerвидитmemory[tg:<chat_id>]содержащий prev-turn, feed'ит в prompt → ответ контекстный
Memory очищается через 1 час inactivity (TTL).
Cost
ai.embedper-query — ~0.001 копейка (1 запрос, ~20 токенов)ai.vector.search— 0 (local Postgres vector search)ai.generateс gpt-4o-mini — ~1-2 копейки per ответ (context + output)- Итого: ~2 коп / вопрос. 1000 вопросов / день — 20 руб / день.
Variations
Двухуровневый fallback: сначала KB, потом general chat
ai.rag.answer
minSimilarity: 0.7
↓
control.switch on rag.answer.sources.length
> 0 → telegram.message.send (text = rag.answer.answer)
== 0 → ai.chat (general, без RAG)
↓
telegram.message.send (text = chat.output)
Escalate к менеджеру на «не знаю»
Если LLM отвечает «переключаю на менеджера» — отправьте параллельно уведомление в чат-команды:
ai.rag.answer
↓
control.switch on rag.answer.answer.includes('переключаю на менеджера')
yes → telegram.message.send (chat_id = support_team, ...)
no → terminal
Inline-кнопки «Подробнее» на sources
telegram.message.send
reply_markup:
inline_keyboard:
- - text: "📄 Источник 1"
url: "{{rag.answer.sources.0.url}}"
Голосовые сообщения
Добавьте ai.transcribe перед rag.answer:
telegram.webhook.trigger
↓
control.switch on trigger.message.voice
yes → telegram.get_file (file_id = voice.file_id)
↓
ai.transcribe (audio = get_file.output)
↓ trigger_text = transcribe.output
no → trigger_text = trigger.message.text
↓
ai.rag.answer (query = trigger_text)
↓
...
ai.transcribe + telegram.get_file — в backlog'е, ETA Q2-2026.
Troubleshooting
Бот отвечает «ничего не нашёл» на очевидные вопросы
KB пустая или embedding-column пустой. Data Tables → kb-chunks → Rows проверьте что embedding'и заполнены (не null). Если пусто —
ре-запустите bulk-import workflow.
Memory не помнит контекст
ai.rag.answer не получает memory.key. Проверьте что template
resolve'ится правильно (в /runs/<id>/traces видно resolved-value
в step-input'е).
LLM выдумывает ответы не из KB
- Прописанный system prompt не достаточно жёсткий. Добавьте явное «Если в контексте нет ответа — не отвечай, не выдумывай».
- Model — gpt-4o-mini иногда халатничает. Попробуйте gpt-4o для critical-вопросов.
Дубли ответов
Webhook retry от Telegram → SUMMING дедуп'ит по update_id, должно
работать из коробки. Если всё равно дубли — проверьте что trigger-
нода настроена с idempotency (default включена).