Я собрал RAG с нуля на Python, чтобы понять, как он работает

Я использовал LangChain в продакшене в течение шести месяцев. Я не мог объяснить, как он работает. Я не знал, почему выбирал те или иные метрики и как текст превращался в векторы. Библиотека скрывала логику.

Чтобы это исправить, я удалил фреймворк. Я написал RAG-пайплайн с нуля, используя 500 строк чистого Python.

Вот чему я научился, собирая стек вручную.

Проблема «черных ящиков»

Когда вы используете высокоуровневые библиотеки, вы теряете контроль. Я видел, как модели галлюцинируют фактами или приводят неверные цитаты. Я не мог понять, где именно кроется ошибка: в чанкере, модели эмбеддингов или в промпте.

Когда вы строите систему сами, каждый слой можно проверить. Вы можете вывести в консоль именно те чанки, которые отправляются в LLM. Вы можете точно увидеть, где разрывается предложение.

Пять уровней RAG

RAG — это не один алгоритм. Это пять различных процессов, работающих в связке:

  • Chunking: решение о том, как разбивать текст.
  • Embedding: превращение текста в математические значения.
  • Retrieval: поиск нужных фрагментов.
  • Prompt Construction: инструкции модели о том, как себя вести.
  • Generation: получение финального ответа.

Уроки разработки

  1. Chunking — самый важный этап В большинстве туториалов это пропускают. Если не использовать перекрытие (overlap), вы потеряете контекст на границах фрагментов. Я использовал метод скользящего окна с посимвольным перекрытием. Это гарантирует, что модель увидит связь между двумя чанками.

  2. Метрики расстояния имеют значение Я потратил часы на отладку плохих результатов поиска. Проблема была не в данных, а в метрике. ChromaDB по умолчанию использует L2-расстояние. Для семантического поиска вам нужна косинусная близость (Cosine similarity). Одна строка кода изменила всё.

  3. Промптам нужны ограничения LLM — это инструмент для дополнения текста, а не оракул. Если задать расплывчатый вопрос, модель выдумает ответ. Я научился использовать строгий шаблон отказа. Я сказал модели: «Если в контексте нет ответа, скажи, что ты не знаешь». Это снизило уровень галлюцинаций с 40% до 5%.

  4. Группируйте запросы Отправка одного HTTP-запроса на каждый чанк — это медленно. Отправка их пачками (batches) происходит гораздо быстрее. Это позволяет локальной модели выстраивать конвейер обработки.

  5. Тестируйте снизу вверх Не пишите тесты в самом конце. Сначала протестируйте чанкер. Затем — эмбеддер. Затем — хранилище. Если тестировать в последнюю очередь, вы будете тестировать баги вместо логики.

Если вы чувствуете, что не до конца понимаете свой AI-стек, соберите его сами. Код — это не цель. Цель — это понимание.

Source: https://dev.to/avinash_zala_1c6f5e7c4af9/i-built-rag-from-scratch-in-python-to-understand-it-heres-what-i-learned-33kf

Optional learning community: https://t.me/GyaanSetuAi