RAG-бот в Telegram, помогающий студентам с методологиями разработки ПО: Agile, Scrum, Kanban, DevOps, планирование задач, документация.
┌─────────────┐ ┌──────────────┐ ┌─────────────────┐
│ Telegram │────▶│ Bot (Python)│────▶│ llama.cpp │
│ пользователь│◀────│ + RAG │◀────│ server (LLM) │
└─────────────┘ │ + ChromaDB │ └─────────────────┘
│ + SQLite │
└──────────────┘
Компоненты:
- llama.cpp server — обслуживает LLM через OpenAI-совместимый API
- ChromaDB — векторная БД для хранения базы знаний (embedded, внутри контейнера бота)
- SQLite — хранение истории диалогов, summary, обратной связи
- aiogram 3 — Telegram-бот с асинхронной обработкой
cp .env.example .env
# Отредактируйте .env: укажите TELEGRAM_TOKEN и модельdocker compose up -dЭто запустит:
llama-server— скачает модель через-hfфлаг и запустит серверbot— Telegram-бот с RAG-пайплайном
# Терминал 1: запустите llama-server
llama-server -hf unsloth/Qwen3.5-9B-GGUF:UD-Q4_K_XL -c 128000 --host 0.0.0.0 --port 8765
# Терминал 2: запустите бота
pip install -r requirements.txt
python -m app.mainРаскомментируйте секцию deploy в docker-compose.yml для llama-server:
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]Используйте образ ghcr.io/ggml-org/llama.cpp:server-cuda вместо ghcr.io/ggml-org/llama.cpp:server.
| Переменная | По умолчанию | Описание |
|---|---|---|
MODEL_HF |
unsloth/Qwen3.5-9B-GGUF:UD-Q4_K_XL |
Модель для -hf флага llama.cpp |
CONTEXT_SIZE |
128000 |
Размер контекстного окна (-c флаг) |
LLM_HOST |
llama-server |
Хост llama.cpp сервера |
LLM_PORT |
8765 |
Порт llama.cpp сервера |
IS_MULTIMODAL |
true |
Поддерживает ли модель изображения |
IS_REASONING_MODEL |
true |
Является ли модель рассуждающей (thinking) |
TELEGRAM_TOKEN |
— | Токен Telegram-бота |
MAX_QUEUE_SIZE |
3 |
Макс. размер очереди сообщений на пользователя |
RAW_MESSAGES_SIZE |
10 |
Минимум сырых сообщений в контексте |
MESSAGES_SUMMARY_SIZE |
5 |
Дополнительный буфер сырых сообщений |
SUMMARY_TOKENS_SIZE |
12000 |
Макс. размер summary в токенах |
SUMMARY_MODEL_HF |
(= MODEL_HF) |
Отдельная модель для сжатия |
SUMMARY_LLM_HOST |
(= LLM_HOST) |
Хост для summary-модели |
SUMMARY_LLM_PORT |
(= LLM_PORT) |
Порт для summary-модели |
RAG_TOP_K |
5 |
Количество фрагментов из векторной БД |
RAG_SCORE_THRESHOLD |
0.35 |
Порог релевантности для RAG |
EMBEDDING_MODEL |
sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 |
Модель эмбеддингов |
RAG (Retrieval-Augmented Generation) используется автоматически на основе релевантности вопроса:
- Каждый вопрос пользователя отправляется в векторную БД (ChromaDB)
- Извлекаются
RAG_TOP_Kнаиболее похожих фрагментов - Если хотя бы один фрагмент имеет
score >= RAG_SCORE_THRESHOLD— он включается в контекст - Если ни один фрагмент не достаточно релевантен — RAG-контекст не добавляется
RAG используется для:
- Вопросов о методологиях (Agile, Scrum, Kanban, DevOps)
- Вопросов о планировании, документации, ролях в команде
- Любых тем, по которым есть материалы в базе знаний
RAG НЕ используется для:
- Приветствий и общих вопросов
- Тем, по которым нет релевантных документов в базе
- В этих случаях ассистент использует общие знания LLM, предупреждая об этом
RAG_SCORE_THRESHOLD=0.35 — косинусное сходство. Значения:
>0.7— высокая релевантность, точное совпадение темы0.5–0.7— средняя релевантность, смежная тема0.35–0.5— низкая релевантность, может быть полезно<0.35— нерелевантно, не включается в контекст
Каждый пользователь Telegram имеет полностью изолированный контекст:
- SQLite хранит историю сообщений с привязкой к
user_id - Summary (сжатие старых сообщений) хранится отдельно для каждого пользователя
- Очередь обработки — отдельная для каждого пользователя
- Контексты никогда не пересекаются: запросы и данные одного пользователя недоступны другому
Контекст не теряется при перезапуске или сбое:
- Все сообщения сохраняются в SQLite сразу при получении
- Summary хранится в SQLite с отметкой времени
- При перезапуске бот загружает историю из БД
- SQLite-файл хранится на Docker volume (
sqlite_data)
┌──────────────────────────────────────┐
│ 1. Системный промпт (инструкция) │
│ 2. Summary (если есть) │
│ 3. Последние N сырых сообщений │
│ 4. RAG-фрагменты (если релевантны) │
│ 5. Текущий вопрос пользователя │
└──────────────────────────────────────┘
- Если сообщений
<= RAW_MESSAGES_SIZE + MESSAGES_SUMMARY_SIZE - 1(по умолчанию 14) — все в сыром виде - Если больше — последние
RAW_MESSAGES_SIZE(10) остаются сырыми, остальные сжимаются в summary - Новый summary объединяется с существующим
- Если summary >
SUMMARY_TOKENS_SIZE(12000 токенов) — пересжимается - Для сжатия можно использовать отдельную модель (
SUMMARY_MODEL_HF)
IS_MULTIMODAL=true— бот принимает изображения и отправляет их в LLMIS_MULTIMODAL=false— при отправке изображения бот отвечает: "Простите, я понимаю только текст"- Модели unsloth с UD-квантизацией (TurboQuant) поддерживают мультимодальность
Для моделей вроде Qwen3.5, которые генерируют <think>...</think> блоки:
IS_REASONING_MODEL=true— включает фильтрацию- Пользователю сначала отправляется: "Рассуждаю, подождите..."
- После получения ответа
<think>блоки вырезаются - Пользователь видит только финальный ответ без рассуждений
- Каждый пользователь имеет очередь размером
MAX_QUEUE_SIZE(по умолчанию 3) - Если пользователь отправляет сообщение, пока предыдущее обрабатывается — оно встаёт в очередь
- Если очередь полна — новые сообщения игнорируются с уведомлением
- Обработка строго последовательная для каждого пользователя
Модели unsloth с префиксом UD- используют TurboQuant — оптимизированную квантизацию, обеспечивающую:
- Более быстрый инференс
- Меньший размер модели
- Минимальную потерю качества
Пример: unsloth/Qwen3.5-9B-GGUF:UD-Q4_K_XL — модель 9B параметров с квантизацией Q4_K_XL в формате TurboQuant.
- Создайте файл
.mdвdata/knowledge_base/:
# Пример: data/knowledge_base/testing_practices.md- Формат файла — обычный Markdown:
# Тестирование ПО
## Виды тестирования
### Unit-тесты
Unit-тесты проверяют отдельные модули...
### Интеграционные тесты
Проверяют взаимодействие компонентов...- Перезапустите бота — новые документы автоматически индексируются:
docker compose restart bot- Документы разбиваются на чанки по ~800 символов с перекрытием 150 символов
- Каждый чанк получает эмбеддинг через
paraphrase-multilingual-MiniLM-L12-v2 - Чанки сохраняются в ChromaDB с метаданными (source, chunk_index)
- При повторном запуске уже существующие чанки пропускаются (дедупликация по ID)
- Используйте заголовки
#,##,###для структуры - Разделяйте темы двойным переносом строки
- Пишите на русском (модель эмбеддингов мультиязычная)
- Оптимальный размер документа: 1000–5000 символов
- Темы: Agile, Scrum, Kanban, DevOps, CI/CD, ГОСТы, управление проектами
Каждый запрос генерирует структурированный JSON-лог в logs/bot.log:
{
"trace_id": "uuid",
"chat_id": 123,
"inbound": {
"telegram_message_id": 456,
"text": "Привет, продолжим?",
"received_at": "2026-03-30T12:00:00Z"
},
"context_window": {
"messages": [
{"id": "m0", "role": "system", "tokens": 150},
{"id": "m1", "role": "user", "tokens": 20}
],
"total_tokens": 500
},
"compression": {
"strategy": "summary+state",
"input_chars": 8000,
"output_chars": 900,
"summary_text": "...",
"created_at": "2026-03-30T12:00:01Z"
},
"rag": {
"query": "Что такое Scrum?",
"num_results": 3,
"used": true,
"top_score": 0.82
},
"llm_call": {
"model": "unsloth/Qwen3.5-9B-GGUF:UD-Q4_K_XL",
"prompt": "...",
"response": "...",
"prompt_tokens": 600,
"completion_tokens": 200,
"latency_ms": 950
},
"completed_at": "2026-03-30T12:00:02Z"
}# Запуск тестов
python -m pytest tests/ -v
# С покрытием
python -m pytest tests/ --cov=app --cov-report=term-missing
# Текущее покрытие: 63%| Команда | Описание |
|---|---|
/start |
Приветствие + сбор обратной связи |
/reset |
Сбросить контекст диалога |
/feedback |
Оставить отзыв (оценка 1–5 + комментарий) |
/help |
Список команд |
RAG/
├── docker-compose.yml # Оркестрация сервисов
├── Dockerfile # Образ бота
├── .env # Переменные окружения
├── .env.example # Пример для пользователей
├── requirements.txt # Python-зависимости
├── app/
│ ├── main.py # Точка входа
│ ├── config.py # Настройки (из .env)
│ ├── logger.py # Структурированное логирование
│ ├── bot/
│ │ ├── handlers.py # Обработчики Telegram
│ │ └── queue_manager.py # Очередь сообщений
│ ├── llm/
│ │ ├── client.py # Клиент llama.cpp API
│ │ └── thinking.py # Фильтр рассуждений
│ ├── rag/
│ │ ├── vectordb.py # ChromaDB обёртка
│ │ └── pipeline.py # RAG-пайплайн + промпт
│ ├── memory/
│ │ ├── context.py # Формирование контекста
│ │ └── summary.py # Сжатие в summary
│ └── storage/
│ └── persistence.py # SQLite (сообщения, summary, feedback)
├── data/
│ └── knowledge_base/ # Markdown-документы базы знаний
├── tests/ # Unit-тесты (79 тестов, 63% покрытие)
├── chroma_data/ # ChromaDB (Docker volume)
├── sqlite_data/ # SQLite (Docker volume)
└── logs/ # Логи