05
RAG Knowledge Base
Telegram-бот, который превращает загруженные PDF в поисковую базу знаний. Задавай вопросы обычным текстом - бот находит релевантные фрагменты и генерирует обоснованные ответы с указанием источников.
PythonLangChainChromaDBOpenAIDocker
"Загрузи PDF. Задай вопрос. Получи ответ с указанием страниц."
1000
символов на чанк, перекрытие 200
top 4
чанка извлекается на вопрос
1536-мерный
вектор эмбеддинга
локально
ChromaDB - без внешней векторной БД
Как это работает
Загрузка PDF→
Извлечение PyMuPDF→
Чанкинг + перекрытие→
text-embedding-3-small→
ChromaDB→
GPT-4o-mini→
Ответ + источники
Структура проекта
rag/ingest.pyPDF → PyMuPDF → чанки → эмбеддинги → ChromaDBrag/retriever.pyвопрос → similarity search → GPT-4o-mini → ответ + источникиbot/handlers.pyTelegram хэндлеры: /start /list /clear, загрузка PDF, вопросыdata/chroma/персистентное хранилище ChromaDB - монтируется как Docker volumeВажная деталь
Модель явно инструктируется отвечать только по извлечённому контексту - не по обучающим данным. Это привязывает каждый ответ к твоим документам и делает галлюцинации структурно невозможными для вопросов вне контекста.
Код
# retriever.py - полный RAG-пайплайн в одной функции
def ask(question: str) -> str:
# 1. Эмбеддинг вопроса в том же векторном пространстве что и чанки
docs = vectorstore.similarity_search(question, k=TOP_K)
if not docs:
return "Релевантные документы не найдены."
# 2. Контекст из топ-4 извлечённых чанков
context = "\n\n".join(d.page_content for d in docs)
# 3. GPT-4o-mini отвечает ТОЛЬКО по контексту - не по обучающим данным
response = openai.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content":
"Отвечай только на основе контекста ниже. "
"Если ответа нет в контексте, так и скажи."},
{"role": "user", "content":
f"Контекст:\n{context}\n\nВопрос: {question}"}
]
)
# 4. Дедупликация источников и добавление к ответу
sources = list({
f"{d.metadata['source']} (стр. {d.metadata['page']})"
for d in docs
})
return response.choices[0].message.content + "\n\n📎 Источники:\n" + "\n".join(f" • {s}" for s in sources)Скриншоты

Функции
- •Загрузка любого текстового PDF прямо в Telegram - без веб-интерфейса
- •Умный чанкинг с перекрытием - контекст сохраняется на границах чанков
- •Семантический поиск по всем проиндексированным документам одновременно
- •GPT-4o-mini отвечает строго по извлечённому контексту - без галлюцинаций из обучающих данных
- •Каждый ответ содержит имя файла-источника и номер страницы
- •Поддержка нескольких документов - вопросы охватывают все PDF сразу
- •Определение дубликатов - один и тот же файл не индексируется дважды
- •Защита от сканов, файлов 500+ страниц и не-PDF загрузок
- •Команды /list и /clear для управления базой знаний
- •ChromaDB сохраняется через Docker volume - данные не теряются при перезапуске