
Построение системы генерации с поддержкой извлечения (RAG) с использованием FAISS и открытых языковых моделей
Система генерации с поддержкой извлечения (RAG) представляет собой мощный подход, который сочетает в себе креативные возможности больших языковых моделей (LLMs) с фактической точностью систем извлечения. Это решение помогает преодолеть одну из основных проблем LLM — галлюцинацию.
Практические бизнес-решения
В этом руководстве мы создадим полную систему RAG, используя:
- FAISS (Facebook AI Similarity Search) в качестве векторной базы данных
- Sentence Transformers для создания высококачественных эмбеддингов
- Открытую языковую модель от Hugging Face (мы используем легкую модель, совместимую с CPU)
- Пользовательскую базу знаний, которую мы создадим
К концу этого руководства у вас будет работающая система RAG, способная отвечать на вопросы на основе ваших документов с улучшенной точностью и актуальностью. Этот подход полезен для создания специализированных помощников, систем поддержки клиентов или любых приложений, где важно обосновывать ответы LLM конкретными документами.
Шаг 1: Настройка окружения
Сначала необходимо установить все необходимые библиотеки. Для этого руководства мы будем использовать Google Colab.
# Установите необходимые пакеты !pip install -q transformers==4.34.0 !pip install -q sentence-transformers==2.2.2 !pip install -q faiss-cpu==1.7.4 !pip install -q accelerate==0.23.0 !pip install -q einops==0.7.0 !pip install -q langchain==0.0.312 !pip install -q langchain_community !pip install -q pypdf==3.15.1
Шаг 2: Создание базы знаний
Мы создадим простую базу знаний о концепциях ИИ. В реальных сценариях можно использовать для импорта PDF-документов, веб-страниц или баз данных.
import os import tempfile # Создаем временный каталог для наших документов docs_dir = tempfile.mkdtemp() print(f"Создан временный каталог по адресу: {docs_dir}") # Создаем образцы документов о концепциях ИИ documents = { "vector_databases.txt": "Описание векторных баз данных...", "embeddings.txt": "Описание эмбеддингов...", "rag_systems.txt": "Описание систем RAG..." } # Записываем документы в файлы for filename, content in documents.items(): with open(os.path.join(docs_dir, filename), 'w') as f: f.write(content) print(f"Создано {len(documents)} документов в {docs_dir}")
Шаг 3: Загрузка и обработка документов
Теперь загрузим эти документы и обработаем их для нашей системы RAG.
from langchain_community.document_loaders import TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter # Инициализируем список для хранения наших документов all_documents = [] # Загружаем каждый текстовый файл for filename in documents.keys(): file_path = os.path.join(docs_dir, filename) loader = TextLoader(file_path) loaded_docs = loader.load() all_documents.extend(loaded_docs) print(f"Загружено {len(all_documents)} документов") # Разбиваем документы на части text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50, separators=["nn", "n", ".", " ", ""] ) document_chunks = text_splitter.split_documents(all_documents) print(f"Создано {len(document_chunks)} частей документов")
Шаг 4: Создание эмбеддингов
Теперь преобразуем наши части документов в векторные эмбеддинги.
from sentence_transformers import SentenceTransformer import numpy as np # Инициализируем модель эмбеддингов model_name = "sentence-transformers/all-MiniLM-L6-v2" embedding_model = SentenceTransformer(model_name) # Создаем эмбеддинги для всех частей документов texts = [doc.page_content for doc in document_chunks] embeddings = embedding_model.encode(texts) print(f"Создано {len(embeddings)} эмбеддингов с формой {embeddings.shape}")
Шаг 5: Создание индекса FAISS
Теперь создадим наш индекс FAISS с этими эмбеддингами.
import faiss # Получаем размерность наших эмбеддингов dimension = embeddings.shape[1] # Создаем индекс FAISS index = faiss.IndexFlatL2(dimension) # Добавляем наши векторы в индекс index.add(embeddings.astype(np.float32)) print(f"Создан индекс FAISS с {index.ntotal} векторами")
Шаг 6: Загрузка языковой модели
Теперь загрузим открытую языковую модель от Hugging Face.
from transformers import AutoTokenizer, AutoModelForCausalLM model_id = "TinyLlama/TinyLlama-1.1B-Chat-v1.0" tokenizer = AutoTokenizer.from_pretrained(model_id) model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.float32) print(f"Успешно загружена модель {model_id}")
Шаг 7: Создание нашего RAG-пайплайна
Создадим функцию, которая объединяет извлечение и генерацию.
def rag_response(query, index, embedding_model, llm_model, llm_tokenizer, index_to_doc_map, top_k=3): # Шаг 1: Преобразуем запрос в эмбеддинг query_embedding = embedding_model.encode([query]) query_embedding = query_embedding.astype(np.float32) # Шаг 2: Поиск похожих документов distances, indices = index.search(query_embedding, top_k) # Шаг 3: Извлечение фактических частей документов retrieved_docs = [index_to_doc_map[idx] for idx in indices[0]] # Создаем контекст из извлеченных документов context = "nn".join([doc.page_content for doc in retrieved_docs]) # Шаг 4: Создаем запрос для LLM prompt = f"""<|system|> Вы полезный ИИ-помощник. Ответьте на вопрос, основываясь только на предоставленном контексте. Если вы не знаете ответа на основе контекста, скажите "У меня недостаточно информации, чтобы ответить на этот вопрос." Контекст: {context} <|user|> {query} <|assistant|>""" # Шаг 5: Генерация ответа от LLM input_ids = llm_tokenizer(prompt, return_tensors="pt").input_ids.to(model.device) generation_config = { "max_new_tokens": 256, "temperature": 0.7, "top_p": 0.95, "do_sample": True } with torch.no_grad(): output = llm_model.generate(input_ids=input_ids, **generation_config) generated_text = llm_tokenizer.decode(output[0], skip_special_tokens=True) response = generated_text.split("<|assistant|>")[-1].strip() return response
Шаг 8: Тестирование нашей системы RAG
Давайте протестируем нашу систему с несколькими вопросами.
test_questions = [ "Что такое FAISS и для чего он используется?", "Как эмбеддинги захватывают семантическое значение?", "Каковы преимущества систем RAG?" ] for question in test_questions: response = rag_response(query=question, index=index, embedding_model=embedding_model, llm_model=model, llm_tokenizer=tokenizer, index_to_doc_map=index_to_doc_chunk) print(f"Вопрос: {question}\nОтвет: {response}\n")
Заключение
В этом руководстве мы построили полную систему RAG с использованием FAISS в качестве векторной базы данных и открытой языковой модели. Мы реализовали обработку документов, генерацию эмбеддингов и индексацию векторов, а также интегрировали эти компоненты с техниками расширения запросов для улучшения качества извлечения.
Рекомендуем рассмотреть возможность:
- Реализации повторной оценки запросов с использованием кросс-кодеров
- Создания веб-интерфейса с использованием Gradio или Streamlit
- Добавления возможностей фильтрации метаданных
Если вам нужна помощь в управлении ИИ в бизнесе, свяжитесь с нами по адресу hello@itinai.ru.