RAG система на базе streamlit.
Есть техническая документация относительно которой llm должна давать ответы на запросы технического специалиста. Модель должна быть установлена локально — данные не должны поступать за пределы локальной системы. Документация условно поделена на разделы посвященные обслуживанию отдельных узлов и агрегатов , также есть текст с общей информацией. Если нарезать текст на мелкие чанки, модель не дает развернутых ответов, а некоторые действия в документации расписаны на десятки шагов. Если мы увеличиваем чанки до 2000-2500 символов — уже лучше, система дает ответы но думает очень долго.
Ситуация с RAG-системой на Streamlit с локальной LLM довольно типичная: баланс между качеством ответов (развёрнутость, полнота) и скоростью. Маленькие чанки (например, 200-500 символов) часто приводят к потере контекста, особенно для длинных процедур (десяти шагов), потому что модель не видит всей последовательности. Большие чанки (2000-2500 символов) улучшают контекст, но замедляют систему из-за большего объёма данных для эмбеддингов, retrieval и генерации. Данные остаются локальными, так что решения должны быть on-device.
Я опишу способы ускорения, основанные на лучших практиках для локальных RAG. Они включают оптимизацию чанкинга, retrieval, модели и инфраструктуры. Рекомендации шаг за шагом, с объяснением почему это работает.
1. Оптимизация размера и стратегии чанкинга
- Баланс размера чанков: Цельтесь на 1000-1500 символов (примерно 250-400 токенов, в зависимости от языка). Это золотая середина для технической документации: достаточно для захвата шагов процедуры, но не слишком много для замедления. Добавьте overlap (перекрытие) 10-20% (200-300 символов) между чанками — это сохранит контекст для последовательных действий.
- Почему ускоряет: Меньше чанков в целом, быстрее индексация и поиск. Для длинных процедур (десятки шагов) это лучше, чем мелкие чанки, но без излишней нагрузки.
- Семантический чанкинг вместо фиксированного: Используйте библиотеки вроде LangChain или SentenceTransformers для разбиения по смыслу (по абзацам, заголовкам или темам), а не по символам. Для вашей документации (разделы по узлам/агрегатам + общая info) это идеально: чанки будут следовать структуре документа.
- Пример в коде (с LangChain):
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(chunk_size=1500, chunk_overlap=200, separators=[«\n\n», «\n», «.», » «])
chunks = splitter.split_text(your_document_text)Почему ускоряет: Меньше «мусорных» чанков, retrieval точнее, модель обрабатывает меньше иррелевантного текста.
- Метаданные и иерархический чанкинг: Добавьте метаданные (раздел, узел, тип info) к каждому чанку. Для длинных документов используйте hybrid: большие чанки для общих разделов, мелкие для шагов процедур.
- Пример в коде (с LangChain):
2. Улучшение retrieval (поиска релевантных чанков)
- Иерархический RAG (Hierarchical Retrieval): Это ключевой апгрейд для вашей документации с разделами и длинными процедурами. Создайте многоуровневую структуру:
- Уровень 1: Summaries (краткие обзоры) для каждого раздела/узла (генерируйте их локальной LLM один раз заранее).
- Уровень 2: Детальные чанки внутри раздела.
- Retrieval: Сначала ищите по summaries (быстро, мало данных), потом углубляйтесь в топ-разделы.
- Почему ускоряет: Сужает поиск (сначала 10-20 summaries, потом 5-10 чанков), снижает шум и время на embedding/search. Для длинных шагов это сохраняет последовательность.
- Реализация: В LangChain используйте HierarchicalNodeParser или custom tree structure. Пример: TreeRAG-подход (библиотеки как LlamaIndex поддерживают).
- Эффективная векторная БД: Перейдите на FAISS (из facebookresearch) или ChromaDB вместо простого cosine similarity. Они оптимизированы для локального использования и ускоряют поиск в 5-10 раз на CPU/GPU.
- Установка: pip install faiss-cpu (или faiss-gpu если есть GPU).
- Почему: Индексация с HNSW (Hierarchical Navigable Small World) делает поиск approximate, но точным и быстрым.
- Multi-query или reranking: Генерируйте 2-3 варианта запроса (локальной LLM), ищите по ним, потом rerank топ-результаты (библиотека как rerankers). Это улучшит точность без роста времени.
- Почему ускоряет: Меньше ложных чанков в финальном промпте.
3. Оптимизация LLM и inference
- Выберите более быструю локальную модель: Если сейчас большая модель (типа GPT-4-like), перейдите на меньшую, но эффективную: Llama 3.1 (8B), Mistral 7B или Phi-3. Они дают хорошие ответы на техдокументацию, но inference в 2-3 раза быстрее.
- Установка: Через Ollama (ollama.ai) — оно оптимизировано для локального запуска, поддерживает quantization (снижение точности для скорости).
- Пример: ollama run llama3.1:8b (quantized версия).
- Почему: Меньше параметров = меньше вычислений. Для embeddings используйте mxbai-embed-large (быстрый на CPU).
- Ускорение inference:
- vLLM (vllm.ai) или llama.cpp для batching и GPU acceleration. Если есть GPU (даже старый), скорость вырастет в 5-10 раз.
- Quantization: 4-bit или 8-bit модели (в Ollama или HuggingFace).
- Почему: Локальный inference — bottleneck, это сократит время генерации с секунд до миллисекунд на токен.
- Кэширование: В Streamlit используйте @st.cache для эмбеддингов, индекса и частых запросов. Один раз проиндексируйте документацию, храните в памяти/файле.
4. Общие оптимизации системы
- Параллелизм: В retrieval обрабатывайте чанки параллельно (библиотека concurrent.futures в Python).
- Лимит на k (top-k чанков): Установите 3-5 релевантных чанков в промпт, не больше — модель не нуждается в избытке.
- Эксперименты и метрики: Тестируйте на сэмпле запросов. Измеряйте время (timeit), точность (ROUGE/BLEU для ответов). Начните с baseline (текущий setup), меняйте один параметр за раз.
- Hardware: Если CPU bottleneck, добавьте RAM (минимум 16GB) или GPU (NVIDIA с CUDA). Для чисто CPU — модели вроде mdbr-leaf-ir (быстрые embeddings).
- Библиотеки: LangChain + Streamlit + Ollama/llama.cpp — стандартный стек для локального RAG. Избегайте облачных API.
Начните с иерархического RAG + FAISS: это напрямую решит проблему длинных процедур (сохранит контекст) и ускорит (меньше данных на шаг). Затем оптимизируйте модель на Ollama с quantization. Ожидаемый эффект: время ответа сократится в 2-5 раз, без потери качества. Если документация огромная, препроцессинг (summaries) сделайте оффлайн один раз.