Ответы 2.4
Теория
- Назначение эмбеддингов: Преобразование текста в числовые векторы, которые сохраняют смысловое значение, позволяя компьютерам «понимать» текст.
- Семантическая близость: Отражается в схожести векторов слов/предложений с похожим значением в многомерном пространстве.
- Обучение эмбеддингов: Происходит на корпусах текстов, где векторы слов зависят от контекста их употребления (дистрибутивная семантика).
- Эмбеддинги в семантическом поиске: Позволяют находить релевантные документы по смыслу, даже без точных совпадений ключевых слов.
- Сопоставление документов и запросов: Эмбеддинги документа описывают его общий смысл, а эмбеддинг запроса — намерение пользователя; их сравнение выявляет релевантные соответствия.
- Векторное хранилище: База данных для эмбеддингов, оптимизированная для быстрого поиска ближайших соседей.
- Выбор хранилища: Зависит от объема данных, требований к персистентности и назначения (исследование, прототип, продакшен).
- Chroma для прототипирования: Удобна для прототипов и небольших наборов данных (работает в памяти, быстро), но имеет ограничения по персистентности и масштабированию.
- Типовой конвейер: Разделение текста → генерация эмбеддингов → индексация в векторном хранилище → обработка запроса → генерация ответа.
- Разделение текста: Улучшает гранулярность; сопоставление происходит на уровне смысловых фрагментов (чанков), а не целых документов.
- Генерация эмбеддингов: Преобразует текст в векторы, пригодные для вычислительного сравнения.
- Индексация в хранилище: Обеспечивает быстрый поиск наиболее схожих по смыслу фрагментов.
- Обработка запроса: Создание эмбеддинга запроса и поиск похожих фрагментов с использованием метрик (косинусное сходство, евклидово расстояние и др.).
- Генерация ответа: Использует найденные фрагменты и исходный запрос для формирования связного ответа.
- Настройка окружения: Установка необходимых библиотек, ключей API и конфигурация для работы с эмбеддингами и векторным хранилищем.
- Загрузка и разделение документов: Критически важны для эффективного управления текстом и повышения качества поиска.
- Иллюстрация схожести: Может быть показана с помощью скалярного произведения или косинусного сходства.
- Особенности Chroma: Важно учитывать директорию персистентности, очистку старых данных и правильную инициализацию коллекции.
- Поиск по схожести: Находит наиболее релевантные фрагменты по отношению к запросу.
- Типичные сбои и их устранение: Дубликаты и нерелевантные результаты могут быть исправлены путем фильтрации и тонкой настройки конвейера.
Практические задания
-
def generate_embeddings(sentences): """ Генерирует простой заглушечный эмбеддинг для каждого предложения на основе его длины. Параметры: - sentences (list of str): Список предложений для генерации эмбеддингов. Возвращает: - list of int: Список эмбеддингов, где каждый эмбеддинг - это длина соответствующего предложения. """ return [len(sentence) for sentence in sentences] def cosine_similarity(vector_a, vector_b): """ Вычисляет косинусное сходство между двумя векторами. Параметры: - vector_a (list of float): Первый вектор. - vector_b (list of float): Второй вектор. Возвращает: - float: Косинусное сходство между `vector_a` и `vector_b`. """ dot_product = sum(a*b for a, b in zip(vector_a, vector_b)) magnitude_a = sum(a**2 for a in vector_a) ** 0.5 magnitude_b = sum(b**2 for b in vector_b) ** 0.5 return dot_product / (magnitude_a * magnitude_b) # Пример использования: sentences = ["Hello, world!", "This is a longer sentence.", "Short"] embeddings = generate_embeddings(sentences) print("Эмбеддинги:", embeddings) vector_a = [1, 2, 3] vector_b = [2, 3, 4] similarity = cosine_similarity(vector_a, vector_b) print("Косинусная близость:", similarity)
-
def cosine_similarity(vector_a, vector_b): """Вычисляет косинусное сходство между двумя векторами.""" dot_product = sum(a*b for a, b in zip(vector_a, vector_b)) magnitude_a = sum(a**2 for a in vector_a) ** 0.5 magnitude_b = sum(b**2 for b in vector_b) ** 0.5 if magnitude_a == 0 or magnitude_b == 0: return 0 # Избегаем деления на ноль для предотвращения ошибок return dot_product / (magnitude_a * magnitude_b)
-
class SimpleVectorStore: def __init__(self): self.vectors = [] # Инициализируем пустой список для хранения векторов def add_vector(self, vector): """Добавляет вектор в хранилище.""" self.vectors.append(vector) def find_most_similar(self, query_vector): """Находит и возвращает вектор, наиболее похожий на `query_vector`.""" if not self.vectors: return None # Возвращаем None, если хранилище пусто similarities = [cosine_similarity(query_vector, vector) for vector in self.vectors] max_index = similarities.index(max(similarities)) return self.vectors[max_index]
-
import sys def split_text_into_chunks(text, chunk_size): """Разбивает заданный текст на чанки указанного размера.""" return [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)] def load_and_print_chunks(file_path, chunk_size): """Загружает текст из файла, разбивает его на чанки и выводит каждый чанк.""" try: with open(file_path, 'r') as file: text = file.read() chunks = split_text_into_chunks(text, chunk_size) for i, chunk in enumerate(chunks, 1): print(f"Чанк {i}:\n{chunk}\n{'-'*50}") except FileNotFoundError: print(f"Ошибка: Файл '{file_path}' не найден.") except Exception as e: print(f"Произошла непредвиденная ошибка: {e}") if __name__ == "__main__": if len(sys.argv) != 3: print("Использование: python script.py <путь_к_файлу> <размер_чанка>") sys.exit(1) file_path = sys.argv[1] chunk_size = int(sys.argv[2]) load_and_print_chunks(file_path, chunk_size)
-
# Предполагаем, что SimpleVectorStore и функция cosine_similarity определены ранее. def generate_query_embedding(query): """ Генерирует простой заглушечный эмбеддинг для запроса на основе его длины. В реальном сценарии для генерации эмбеддингов использовалась бы модель. """ return [len(query)] def query_processing(store, query): """ Обрабатывает запрос: генерирует эмбеддинг, ищет наиболее похожий фрагмент в векторном хранилище и выводит его. """ query_embedding = generate_query_embedding(query) most_similar = store.find_most_similar(query_embedding) if most_similar is not None: print("Наиболее похожий фрагмент документа:", most_similar) else: print("Фрагменты документов не найдены.")
-
def remove_duplicates(document_chunks): """Удаляет дублирующиеся фрагменты документов на основе точного совпадения их содержимого.""" unique_chunks = [] for chunk in document_chunks: if chunk not in unique_chunks: unique_chunks.append(chunk) return unique_chunks
-
# Инициализация SimpleVectorStore для демонстрации store = SimpleVectorStore() # Заглушка для фрагментов документов и их эмбеддингов для примера document_chunks = ["Document chunk 1", "Document chunk 2", "Document chunk 3"] # Симулируем эмбеддинги для этих фрагментов, например, на основе их длины document_embeddings = [[len(chunk)] for chunk in document_chunks] # Добавляем сгенерированные эмбеддинги документов в хранилище for embedding in document_embeddings: store.add_vector(embedding) # Проводим поиск по сходству с использованием примера запроса query = "Document" query_embedding = generate_query_embedding(query) # Находим наиболее похожие фрагменты документов на основе косинусного сходства similarities = [(cosine_similarity(query_embedding, doc_embedding), idx) for idx, doc_embedding in enumerate(document_embeddings)] similarities.sort(reverse=True) # Сортируем по сходству в порядке убывания top_n_indices = [idx for _, idx in similarities[:3]] # Получаем индексы топ-3 наиболее похожих фрагментов # Выводим ID или содержимое топ-3 наиболее похожих фрагментов документов print("Топ-3 наиболее похожих фрагмента документов:") for idx in top_n_indices: print(f"{idx + 1}: {document_chunks[idx]}")
-
def embed_and_store_documents(document_chunks): """ Генерирует эмбеддинги для каждого фрагмента документа и сохраняет их в `SimpleVectorStore`. Параметры: - document_chunks (list of str): Список фрагментов документов в виде строк. Возвращает: - SimpleVectorStore: Векторное хранилище, инициализированное эмбеддингами документов. """ store = SimpleVectorStore() for chunk in document_chunks: # Заглушка для генерации эмбеддинга на основе длины фрагмента embedding = [len(chunk)] store.add_vector(embedding) return store
-
import json def save_vector_store(store, filepath): """ Сохраняет состояние объекта `SimpleVectorStore` в указанный файл. Параметры: - store (SimpleVectorStore): Векторное хранилище для сохранения. - filepath (str): Путь к файлу, где будет сохранено хранилище. """ with open(filepath, 'w') as file: json.dump(store.vectors, file) def load_vector_store(filepath): """ Загружает состояние объекта `SimpleVectorStore` из указанного файла. Параметры: - filepath (str): Путь к файлу, из которого нужно загрузить хранилище. Возвращает: - SimpleVectorStore: Загруженное векторное хранилище. """ store = SimpleVectorStore() with open(filepath, 'r') as file: store.vectors = json.load(file) return store def vector_store_persistence(): """Демонстрирует сохранение и загрузку состояния `SimpleVectorStore`.""" store = SimpleVectorStore() # Предполагаем, что хранилище уже заполнено данными filepath = 'vector_store.json' # Пример сохранения и загрузки данных save_vector_store(store, filepath) loaded_store = load_vector_store(filepath) print("Векторное хранилище загружено с векторами:", loaded_store.vectors)
-
def evaluate_search_accuracy(queries, expected_chunks): """ Оценивает точность поиска по сходству для списка запросов и их ожидаемых результатов. Параметры: - queries (list of str): Список запросов в виде строк. - expected_chunks (list of str): Список ожидаемых наиболее похожих фрагментов документов, соответствующих каждому запросу. Возвращает: - float: Точность результатов поиска (доля правильно найденных фрагментов). """ correct = 0 # Эмбеддинг и сохранение документов плюс некоторые дополнительные для обеспечения уникальности store = embed_and_store_documents(expected_chunks + list(set(expected_chunks) - set(queries))) for query, expected in zip(queries, expected_chunks): query_embedding = generate_query_embedding(query) most_similar = store.find_most_similar(query_embedding) # Предполагаем, что expected_chunks — это эмбеддинги документов, сохраненные в том же порядке. if most_similar and most_similar == [len(expected)]: correct += 1 accuracy = correct / len(queries) return accuracy # Предполагаем, что embed_and_store_documents, generate_query_embedding и SimpleVectorStore # реализованы, как описано выше.