RAG система на Python: пошаговый гайд за 15 минут | AiManual
AiManual Logo Ai / Manual.
28 Дек 2025 Гайд

RAG за 15 минут: создаем свою систему на Python с нуля (пошаговый гайд)

Создайте свою Retrieval-Augmented Generation систему на Python с нуля. Полный гайд с кодом, объяснением архитектуры и практическими примерами.

Проблема: почему обычные LLM "галлюцинируют" и как это исправить

Вы наверняка сталкивались с ситуацией, когда ChatGPT или другая языковая модель уверенно отвечает на вопрос, но при этом выдумывает факты. Это явление называется "галлюцинацией" (hallucination) и является фундаментальной проблемой современных LLM. Модели обучены на огромных объемах данных, но у них нет доступа к актуальной или специфической информации.

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

Именно эту проблему решает Retrieval-Augmented Generation (RAG) — архитектурный подход, который дополняет языковые модели внешними источниками знаний. Вместо того чтобы полагаться только на внутренние знания модели, RAG:

  • Извлекает релевантные документы из вашей базы знаний
  • Добавляет их в контекст запроса
  • Генерирует ответ на основе как внутренних знаний модели, так и внешних источников

Решение: архитектура RAG — как это работает под капотом

RAG система состоит из трех основных компонентов, которые мы сегодня реализуем:

Компонент Назначение Что используем
Векторная база Хранение и поиск документов по семантическому сходству FAISS (Facebook AI Similarity Search)
Эмбеддинг-модель Преобразование текста в числовые векторы Sentence Transformers
Языковая модель Генерация ответов на основе контекста OpenAI GPT или локальная модель
💡
Если вам интересны другие практические применения ИИ, рекомендую посмотреть статью "40 лайфхаков Google AI 2025", где собраны полезные приемы для работы с современными инструментами.

Пошаговый план: создаем RAG систему за 15 минут

Теперь перейдем к практической части. Мы создадим полноценную RAG систему, которая сможет отвечать на вопросы по вашим документам.

1 Подготовка окружения и установка зависимостей

Создайте новую директорию и виртуальное окружение:

mkdir rag-system && cd rag-system
python -m venv venv
source venv/bin/activate  # На Windows: venv\Scripts\activate

Установите необходимые библиотеки:

pip install langchain langchain-openai faiss-cpu sentence-transformers python-dotenv

Создайте файл .env для хранения API ключей:

echo "OPENAI_API_KEY=your_api_key_here" > .env

2 Подготовка документов и создание векторной базы

Создайте файл documents.txt с вашими документами. Для примера:

Компания TechCorp была основана в 2015 году.
Основной продукт — облачная платформа для аналитики данных.
Штаб-квартира находится в Сан-Франциско.
Количество сотрудников: 250 человек.
Годовой доход: 50 миллионов долларов.

Теперь создайте скрипт create_vectorstore.py:

import os
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import HuggingFaceEmbeddings
from dotenv import load_dotenv

load_dotenv()

# Загружаем документы
def create_vector_store():
    # Загрузка документов
    loader = TextLoader("documents.txt", encoding="utf-8")
    documents = loader.load()
    
    # Разделение на чанки
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=500,
        chunk_overlap=50,
        length_function=len,
    )
    chunks = text_splitter.split_documents(documents)
    
    # Создание эмбеддингов и векторного хранилища
    embeddings = HuggingFaceEmbeddings(
        model_name="sentence-transformers/all-MiniLM-L6-v2"
    )
    
    vectorstore = FAISS.from_documents(chunks, embeddings)
    vectorstore.save_local("faiss_index")
    
    print(f"Создано {len(chunks)} чанков")
    print("Векторное хранилище сохранено в 'faiss_index'")
    
    return vectorstore

if __name__ == "__main__":
    create_vector_store()

Важно: Размер чанка (chunk_size) — критический параметр. Слишком маленькие чанки теряют контекст, слишком большие — содержат лишнюю информацию. Начните с 500-1000 символов и экспериментируйте.

3 Создание RAG цепи с LangChain

Создайте основной файл rag_system.py:

import os
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
from dotenv import load_dotenv

load_dotenv()

class RAGSystem:
    def __init__(self):
        # Загрузка векторного хранилища
        self.embeddings = HuggingFaceEmbeddings(
            model_name="sentence-transformers/all-MiniLM-L6-v2"
        )
        
        self.vectorstore = FAISS.load_local(
            "faiss_index", 
            self.embeddings, 
            allow_dangerous_deserialization=True
        )
        
        # Инициализация LLM
        self.llm = ChatOpenAI(
            model="gpt-3.5-turbo",
            temperature=0.3,  # Низкая температура для более точных ответов
            api_key=os.getenv("OPENAI_API_KEY")
        )
        
        # Создание кастомного промпта
        prompt_template = """Используй следующие фрагменты контекста, чтобы ответить на вопрос.
        Если ты не знаешь ответа, просто скажи, что не знаешь, не пытайся выдумывать.
        
        Контекст: {context}
        
        Вопрос: {question}
        
        Точный и подробный ответ:"""
        
        PROMPT = PromptTemplate(
            template=prompt_template,
            input_variables=["context", "question"]
        )
        
        # Создание RAG цепи
        self.qa_chain = RetrievalQA.from_chain_type(
            llm=self.llm,
            chain_type="stuff",
            retriever=self.vectorstore.as_retriever(
                search_kwargs={"k": 3}  # Берем 3 наиболее релевантных документа
            ),
            chain_type_kwargs={"prompt": PROMPT},
            return_source_documents=True
        )
    
    def query(self, question: str):
        """Запрос к RAG системе"""
        result = self.qa_chain.invoke({"query": question})
        
        return {
            "answer": result["result"],
            "sources": result["source_documents"]
        }

# Пример использования
if __name__ == "__main__":
    rag = RAGSystem()
    
    # Тестовые вопросы
    questions = [
        "Когда была основана компания TechCorp?",
        "Сколько сотрудников в компании?",
        "Какой основной продукт у компании?"
    ]
    
    for question in questions:
        print(f"\nВопрос: {question}")
        response = rag.query(question)
        print(f"Ответ: {response['answer']}")
        print(f"Источники: {len(response['sources'])} документов")
💡
Для сложных сценариев с большими объемами данных иногда мультиагентные системы могут быть излишни. Узнайте, когда стоит использовать более простые подходы, в статье "Когда мультиагентные системы излишни".

4 Запуск и тестирование системы

Запустите систему командой:

python rag_system.py

Вы должны увидеть ответы на ваши вопросы, основанные на документах из documents.txt.

Нюансы и возможные ошибки

1. Качество эмбеддингов

Модель all-MiniLM-L6-v2 — хороший баланс между скоростью и качеством. Для production:

  • Для английского: all-mpnet-base-v2 (лучшее качество)
  • Для русского: sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2
  • Для скорости: all-MiniLM-L6-v2 (самый быстрый)

2. Стратегии поиска

Стратегия Описание Когда использовать
Similarity Search Поиск по косинусному сходству Большинство случаев
MMR (Maximal Marginal Relevance) Баланс релевантности и разнообразия Когда нужны разные аспекты темы
Self-Query Поиск с фильтрацией по метаданным Структурированные данные

3. Распространенные ошибки

Ошибка 1: Слишком большие чанки. Решение: уменьшите chunk_size до 500-1000 символов.

Ошибка 2: LLM игнорирует контекст. Решение: улучшите промпт, явно указав "Используй только предоставленный контекст".

Ошибка 3: Медленный поиск. Решение: используйте FAISS с индексом IVF для больших баз данных.

Продвинутые улучшения

После того как базовая система работает, рассмотрите эти улучшения:

1. Добавление метаданных

# При создании чанков добавляйте метаданные
from langchain.schema import Document

chunks_with_metadata = []
for i, chunk in enumerate(chunks):
    doc = Document(
        page_content=chunk.page_content,
        metadata={
            "source": "documents.txt",
            "chunk_id": i,
            "timestamp": "2024-01-01"
        }
    )
    chunks_with_metadata.append(doc)

2. Переписывание запросов (Query Rewriting)

# Улучшение запросов перед поиском
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate

rewrite_prompt = PromptTemplate(
    input_variables=["question"],
    template="""Перепиши этот вопрос для лучшего поиска в базе знаний:
    Оригинальный вопрос: {question}
    Переписанный вопрос:"""
)

rewrite_chain = LLMChain(llm=llm, prompt=rewrite_prompt)
improved_question = rewrite_chain.run(question=original_question)

3. Reranking результатов

Используйте модель для переранжирования найденных документов:

from sentence_transformers import CrossEncoder

# Инициализация модели для reranking
reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')

# Ранжирование пар запрос-документ
pairs = [[question, doc.page_content] for doc in retrieved_docs]
scores = reranker.predict(pairs)

# Сортировка по убыванию релевантности
ranked_docs = [doc for _, doc in sorted(zip(scores, retrieved_docs), reverse=True)]
💡
Для развертывания подобных систем в production может потребоваться инфраструктура. Если вам интересно, как построить ML-песочницу для экспериментов, рекомендую гайд по созданию ML-песочницы на k8s и Docker.

FAQ: ответы на частые вопросы

Можно ли использовать локальную LLM вместо OpenAI?

Да, абсолютно. Вместо ChatOpenAI можно использовать:

from langchain_community.llms import LlamaCpp

llm = LlamaCpp(
    model_path="./models/llama-7b.gguf",
    temperature=0.3,
    n_ctx=2048,
)

Как обрабатывать PDF, Word и другие форматы?

LangChain поддерживает множество загрузчиков:

from langchain_community.document_loaders import (
    PyPDFLoader,
    Docx2txtLoader,
    UnstructuredHTMLLoader,
    CSVLoader
)

# Для PDF
loader = PyPDFLoader("document.pdf")

# Для Word
loader = Docx2txtLoader("document.docx")

Как масштабировать на миллионы документов?

Для больших объемов данных:

  • Используйте Pinecone или Weaviate вместо FAISS
  • Реализуйте пагинацию и батчинг при индексации
  • Используйте GPU для вычисления эмбеддингов
  • Рассмотрите иерархическую индексацию

Заключение

Вы только что создали полноценную RAG систему с нуля! Теперь у вас есть основа, которую можно расширять и улучшать. Ключевые моменты для запоминания:

  1. Качество чанков важнее всего — правильно разделяйте документы
  2. Промпт-инжиниринг критически важен — явно указывайте LLM использовать контекст
  3. Метаданные упрощают фильтрацию и отладку
  4. Тестируйте с реальными вопросами пользователей

RAG — это не серебряная пуля, но мощный инструмент для создания интеллектуальных систем, которые действительно "знают" ваши данные. Начните с простой реализации, как в этом гайде, и постепенно добавляйте сложность по мере необходимости.

💡
Интересно, как ИИ решает фундаментальные научные проблемы? Узнайте о попытках применения ML к одной из величайших математических задач в статье "Нули Римана как статистический отпечаток пальца".

Весь код из этой статьи доступен для копирования и запуска. Экспериментируйте, меняйте параметры, адаптируйте под свои нужды. Удачи в создании умных систем!