itstnd@yandex.ru

Консультации

Разработка и поддержка сайтов

RAG система на базе streamlit — оптимизация поиска

 Ai    

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: большие чанки для общих разделов, мелкие для шагов процедур.

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) сделайте оффлайн один раз.