Инференциальные двигатели с улучшенным поиском и генерацией (RAG) с использованием LangChain на процессорах.

Улучшенные инференциальные двигатели с поиском и генерацией (RAG) на процессорах, использующие LangChain.

Создано с помощью Nightcafe - Собственность автора

Исследование масштаба, полноты и задержки в приложениях искусственного интеллекта с помощью RAG

В то время как Retrieval Augmented Generation (RAG) широко освещается, особенно в его применении к чат-основанным LLM, в этой статье мы собираемся рассмотреть его с другой точки зрения и проанализировать его мощь как мощного операционного инструмента. Мы также предоставим полезный практический пример, чтобы приобрести практический опыт в применении RAG. К концу статьи вы получите уникальный взгляд на RAG – понимание его роли и потенциала в масштабируемом выводе в рамках развертывания LLM на производственном уровне.

Но сначала давайте обновим наше понимание вывода

Вывод – это процесс преобразования данных в прогнозы. Этот компонент жизненного цикла ML часто обеспечивается конвейерами данных, которые управляют предварительной обработкой и последующей обработкой задач. Рассмотрим практический пример, рассмотрим систему рекомендаций музыкального стриминга, показанную на рисунке 1. Когда пользователь посещает платформу стриминга, в интерфейсе приложения представляется интеллектуально подобранный список из 10 лучших песен. Система рекомендации, отвечающая за этот список, полагается на обученную модель и надежные конвейеры данных, чтобы обеспечить высококачественный результат.

Рис. 1. Простая диаграмма, иллюстрирующая систему рекомендаций, поддерживающую функциональность «список из 10 рекомендуемых песен» - изображение автора

Предварительная обработка, представленная желтыми блоками на нашей диаграмме, является важной для того, чтобы прогноз модели тесно соответствовал уникальным предпочтениям пользователя. Начиная с последних 250 прослушанных пользователем песен, конвейер обрабатывает данные и генерирует набор контекстных характеристик, прежде чем передать их обученной модели для вывода. Шаг вывода предсказывает, что может понравиться этому пользователю, и выдает выходные данные, которые проходят на постобработку (иллюстрируется оранжевым цветом). На этом последнем этапе лучшие рекомендации модели дополняются дополнительными метаданными – обложками альбомов, названиями песен, именами исполнителей и их рейтингом. Затем эта информация отображается в интерфейсе пользователя для потребления.

В описанном выше рабочем процессе ясно, насколько близок шаг вывода к пользователю в топологии приложения. В отличие от других компонентов жизненного цикла ИИ, таких как сбор данных и оптимизация модели, которые обычно работают в фоновом режиме, движок вывода находится на переднем плане, тесно взаимодействуя с пользовательским интерфейсом (UI) и пользовательским опытом (UX).

Рис. 2. Иллюстрация различных компонентов системы ИИ и их близость к пользовательскому опыту. — Изображение автора

Мы можем использовать приведенную выше диаграмму (рисунок 2) для иллюстрации близости различных компонентов жизненного цикла ИИ к пользователю. В то время как многие компоненты, такие как сбор данных и аннотация, находятся “за кулисами”, движок вывода стоит как важный мост между внутренними процессами ИИ и тем, с чем пользователи сталкиваются. Это не просто еще один механизм фоновой обработки, это ядро пользовательского осязаемого опыта с приложением.

Учитывая эту важную роль в формировании пользовательского опыта, важно, чтобы движок вывода – охватывающий процесс вывода и его периферийные компоненты, такие как предварительная / пост-обработка, управление API и управление вычислениями – работал безупречно. Для определения границ качества движка вывода, я представляю “Треугольник качества вывода (IQ)”, изображенный на рисунке 3. Эта качественная фигура выделяет три ключевых аспекта, на которые следует обратить внимание при повышении производительности нагрузки вывода:

  • Задержка: если движок вывода занимает меньше времени для предоставления ответа, это уменьшает накладные расходы для приложения и приводит к лучшему пользовательскому опыту.
  • Полнота: вывод должен предоставлять ответы, на которые пользователи могут положиться и относиться с уверенностью. Это включает, но не ограничивается, обеспечение высокой точности ответов и снижение галлюцинаций.
  • Масштабируемость: как нагрузка на систему ИИ колеблется, способность масштабировать инфраструктуру является ключевым моментом для оптимизации затрат и обеспечения подбора вычислительных ресурсов.
Рисунок 3. Простая модель выравнивания трех ключевых элементов высококачественных систем вывода. Сильное внимание уделяется оперативному совершенству, где ИИ-системы должны масштабироваться, сохраняя при этом низкую задержку и обеспечивая высокую точность результатов. - Изображение автора

В процессе продвижения по статье мы будем ссылаться на треугольник IQ, чтобы более глубоко исследовать, как эти три компонента – задержка, точность и масштаб – хорошо соответствуют нагрузке RAG.

Краткое введение в оздание с поддержкой выборки

Оздание с увеличением выборки, также известное как RAG, – это техника, впервые представленная Piktus et al. (2021) в “Оздание с увеличением выборки для задач NLP, требующих обширных знаний”, и с тех пор была адаптирована в разные фреймворки и приложения. RAG относится к категории техник контекстного обучения, которые сосредоточены на предоставлении дополнительных знаний предварительно обученным моделям в целях улучшения качества их ответов.

Основополагающим принципом RAG является интеллектуальное извлечение дополнительной информации из соответствующих источников данных, обычно векторных баз данных, с использованием алгоритмов, таких как поиск похожести. Извлеченные данные комбинируются с запросом пользователя, обогащая входные данные, предоставляемые генеративной модели. Стандартный рабочий процесс RAG показан на рисунке 4.

Рисунок 4. Простая схема рабочего процесса RAG - Изображение автора

Чтобы понять реальную ценность RAG, рассмотрим практический сценарий: финансовый аналитик крупной корпорации (рисунок 5) занимается задачей составления ежеквартального отчета о прибылях. Ее выполнение в традиционном стиле было бы затратным по времени. Приложения на основе LLM’ов предлагают значительные улучшения в эффективности, но есть одно “но” – необходимость в актуальной закрытой информации, к которой нельзя получить доступ на этапе обучения основных моделей с открытым исходным кодом. Это можно частично решить с помощью настройки, однако быстрый темп бизнес-операций означает, что для поддержания актуальности моделей этот процесс потребует постоянной настройки.

Рисунок 5. Адаптированная версия рисунка 6. В этом примере показан сценарий использования RAG финансовым аналитиком для иллюстрации допустимости рабочего процесса построения RAG-систем на основе закрытых данных. - Изображение автора

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

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

В данном практическом примере вы можете переключать RAG вкл/выкл, чтобы увидеть влияние качества ответов предобученной модели при наличии или отсутствии контекста, предоставляемого интеллектуальными методами поиска информации. См. Рисунок 10.

Рабочие системы RAG в поддержку систем вывода высокого качества

Теперь, когда у нас есть базовое понимание RAG и его роли в приложениях на основе LLM’ов, мы сосредоточимся на реализации практических и эксплуатационных аспектов этих систем.

Как было обещано, давайте вернемся к треугольнику IQ (рисунок 3), который подчеркивает три важных аспекта операционных систем вывода высокого качества. Мы проанализируем возможность решения всех трех этих аспектов – масштабируемость, время отклика и точность – с помощью приведенного ниже стека (рисунок 6), который фокусируется на системе вывода, состоящей из RAG-пайплайнов и сильно оптимизированных моделей, работающих на ЦП.

Рисунок 6. Предложенная структура системы вывода — изображение моим автором

Преимущества архитектуры RAG

Приложения, основанные на RAG, обладают значительными архитектурными преимуществами. С точки зрения масштабируемости, все компоненты конвейера, связанные с данными, сходятся на одной (или нескольких) векторных базах данных (рисунок 7), что позволяет системе RAG хорошо масштабироваться с возрастанием/уменьшением запросов пользователей. Такой объединенный подход может значительно улучшить точность ответов на специфические задачи в конкретной области, упрощая при этом управление данными.

Рисунок 7. Простая диаграмма потока данных, показывающая поток данных в системе искусственного интеллекта на основе RAG — изображение моим автором

Оптимизация моделей: эффективность и производительность

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

Рисунок 8 — изображение моим автором

ЦП в поддержку RAG

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

Современные ЦП также оснащены низкоуровневыми оптимизациями — например, Advanced Matrix Extensions от Intel в их процессорах Xeon четвертого поколения — которые улучшают управление памятью и операции над матрицами в процессе обучения и вывода глубокого обучения. Их поддержка низкоточных типов данных (например, bf16 и int8) делает их идеально подходящими для достижения низкого времени отклика в процессе вывода.

Кроме того, совместимость ЦП с несколькими компонентами конвейера RAG (рисунок 9), включая векторные базы данных и интеллектуальный поиск (например, поиск похожести), упрощает управление инфраструктурой, делая масштабирование деплоя более простым и эффективным.

Рисунок 9. Адаптация рисунка 7. Демонстрирует возможность ЦП поддерживать различные части системы RAG — изображение моим автором

Прежде чем продолжить, я должен раскрыть свою принадлежность к Intel и используемый ниже продукт. Как старший инженер по искусственному интеллекту в Intel, следующий практический пример выполняется на Intel Developer Cloud (IDC). Мы будем использовать IDC как бесплатный и удобный способ доступа к вычислениям для получения практического опыта с описанными в этой статье концепциями.

Практический пример: Внедрение RAG с использованием LangChain в Intel Developer Cloud (IDC)

Для выполнения следующего практического примера создайте бесплатную учетную запись на Intel Developer Cloud и перейдите на страницу “Обучение и семинары”. В разделе Gen AI Essentials выберите опцию Генерация на основе извлечения информации (RAG) с использованием LangChain. Следуйте инструкциям на веб-странице, чтобы запустить окно JupyterLab и автоматически загрузить записную книжку со всем примерным кодом.

В записной книжке приведены подробные строки документации и описания кода. В этой статье будет рассмотрены общие механизмы, а также предоставлен контекст для конкретных функций.

Настройка зависимостей

Начнем с установки всех необходимых пакетов в базовую среду. Вы можете создать свою среду conda, но это быстрый и простой способ начать.

import sysimport os!{sys.executable} -m pip install langchain==0.0.335 --no-warn-script-location > /dev/null!{sys.executable} -m pip install pygpt4all==1.1.0 --no-warn-script-location > /dev/null!{sys.executable} -m pip install gpt4all==1.0.12 --no-warn-script-location > /dev/null!{sys.executable} -m pip install transformers==4.35.1 --no-warn-script-location > /dev/null!{sys.executable} -m pip install datasets==2.14.6 --no-warn-script-location > /dev/null!{sys.executable} -m pip install tiktoken==0.4.0 --no-warn-script-location > /dev/null!{sys.executable} -m pip install chromadb==0.4.15 --no-warn-script-location > /dev/null!{sys.executable} -m pip install sentence_transformers==2.2.2 --no-warn-script-location > /dev/null

Эти команды установят все необходимые пакеты в вашу базовую среду.

Данные и модель

Мы будем использовать квантованную версию Falcon 7B (gpt4all-falcon-q4_0) из проекта GPT4All. Вы можете узнать больше о этой модели на странице GPT4ALL в разделе “Исследователь модели”. Модель была сохранена на диске, чтобы упростить процесс доступа к модели.

Следующая логика загружает доступные наборы данных из проекта Hugging Face с названием FunDialogues. Выбранные данные будут пропущены через модель embedding и помещены в базу данных векторов на следующем шаге.

def download_dataset(self, dataset):        """        Загружает указанный набор данных и сохраняет его в путь к данным.        Parameters        ----------        dataset : str            Название загружаемого набора данных.        """        self.data_path = dataset + '_dialogues.txt'        if not os.path.isfile(self.data_path):            datasets = {"robot maintenance": "FunDialogues/customer-service-robot-support",                         "basketball coach": "FunDialogues/sports-basketball-coach",                         "physics professor": "FunDialogues/academia-physics-office-hours",                        "grocery cashier" : "FunDialogues/customer-service-grocery-cashier"}                        # Загружаем диалог с помощью Hugging Face            dataset = load_dataset(f"{datasets[dataset]}")            # Преобразуем набор данных в pandas dataframe            dialogues = dataset['train']            df = pd.DataFrame(dialogues, columns=['id', 'description', 'dialogue'])            # Выводим первые 5 строк dataframe            df.head()            # Оставляем только столбец с диалогом            dialog_df = df['dialogue']                        # Сохраняем данные в txt-файл            dialog_df.to_csv(self.data_path, sep=' ', index=False)        else:            print('data already exists in path.')

В указанном фрагменте кода вы можете выбрать из 4 разных синтетических наборов данных:

  • Обслуживание робота: разговоры между техником и агентом службы поддержки клиентов при устранении неполадок роботизированной руки.
  • Тренер по баскетболу: разговоры между тренерами по баскетболу и игроками во время игры.
  • Профессор физики: разговоры между студентами и профессором физики во время консультаций.
  • Кассир в продуктовом магазине: разговоры между кассиром в продуктовом магазине и клиентами

Настройка модели

Расширение GPT4ALL в API LangChain заботится о загрузке модели в память и настройке различных параметров, таких как:

  • model_path: Эта строка указывает путь к файлу предварительно обученной модели.
  • n_threads: Устанавливает количество потоков, которые будут использоваться, что может влиять на параллельную обработку или скорость вывода. Это особенно важно для многоядерных систем.
  • max_tokens: Ограничивает количество токенов (слов или подслов) для входных или выходных последовательностей, гарантируя, что данные, подаваемые на вход модели или получаемые от нее, не превышают эту длину.
  • repeat_penalty: Этот параметр возможно штрафует повторяющийся контент в выходных данных модели. Значение больше 1.0 предотвращает генерацию повторяющихся последовательностей.
  • n_batch: Указывает размер пакета для обработки данных. Это может помочь оптимизировать скорость обработки и использование памяти.
  • top_k: Определяет стратегию выбора “лучших k” при генерации модели. При генерации текста модель будет учитывать только k наиболее вероятных следующих токенов.
def load_model(self, n_threads, max_tokens, repeat_penalty, n_batch, top_k, temp):        """        Загружает модель с указанными параметрами для параллельной обработки.        Параметры        ----------        n_threads : int            Количество потоков для параллельной обработки.        max_tokens : int            Максимальное количество токенов для предсказания модели.        repeat_penalty : float            Штраф за повторяющиеся токены при генерации.        n_batch : int            Количество пакетов для обработки.        top_k : int            Количество лучших k токенов, учитываемых при выборке.        """        # Поддержка обратных вызовов с потоковой передачей        callbacks = [StreamingStdOutCallbackHandler()]        # Требуется параметр вывода для передачи менеджеру обратных вызовов        self.llm = GPT4All(model=self.model_path, callbacks=callbacks, verbose=False,                           n_threads=n_threads, n_predict=max_tokens, repeat_penalty=repeat_penalty,                            n_batch=n_batch, top_k=top_k, temp=temp)

Построение векторной базы данных с помощью ChromaDB

Векторная база данных Chroma является неотъемлемой частью нашей конфигурации RAG, где мы эффективно храним и управляем нашими данными. Вот как мы ее строим:

def build_vectordb(self, chunk_size, overlap):        """        Создает векторную базу данных из набора данных для целей поиска.        Параметры        ----------        chunk_size : int            Размер фрагментов текста для векторизации.        overlap : int            Размер перекрытия между фрагментами.        """        loader = TextLoader(self.data_path)        # Разделитель текста        text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=overlap)        # Встроить документ и сохранить в Chroma DB        self.index = VectorstoreIndexCreator(embedding=HuggingFaceEmbeddings(), text_splitter=text_splitter).from_loaders([loader])

Выполнение механизма извлечения

При получении запроса пользователя мы используем поиск похожести для поиска в нашей векторной базе данных подходящих данных. Как только найдено k совпадающих результатов, они извлекаются и используются для добавления контекста к запросу пользователя. Мы используем функцию PromptTemplate, чтобы создать шаблон и вставить запрос пользователя вместе с извлеченным контекстом. После заполнения шаблона мы переходим к компоненту вывода.

def retrieval_mechanism(self, user_input, top_k=1, context_verbosity=False, rag_off=False):        """        Извлекает соответствующие фрагменты документов на основе запроса пользователя.        Параметры        ----------        user_input : str            Ввод или запрос пользователя.        top_k : int, optional            Количество лучших результатов для возврата, по умолчанию 1.        context_verbosity : bool, optional            Если True, выводится дополнительная контекстная информация, по умолчанию False.        rag_off : bool, optional            Если True, отключает расширенное поколение с помощью поиска данных, по умолчанию False.        """        self.user_input = user_input        self.context_verbosity = context_verbosity                        # выполнить поиск похожести и извлечь контекст из наших документов        results = self.index.vectorstore.similarity_search(self.user_input, k=top_k)        # объединить всю контекстную информацию в одну строку         context = "\n".join([document.page_content for document in results])        if self.context_verbosity:            print(f"Извлечение информации, связанной с вашим вопросом...")            print(f"Найденный контент, наиболее схожий с вашим вопросом: {context}")        if rag_off:            template = """Вопрос: {question}            Ответ: Это ответ: """            self.prompt = PromptTemplate(template=template, input_variables=["question"])        else:                 template = """Не просто повторяйте следующий контекст, используйте его в сочетании с вашими знаниями для улучшения ответа на вопрос: {context}            Вопрос: {question}            """            self.prompt = PromptTemplate(template=template, input_variables=["context", "question"]).partial(context=context)

Инструмент LangChain LLMChain для выполнения инференса на основе запроса, переданного пользователем, и настроенного шаблона. Результат возвращается пользователю.

 def inference(self):        """        Выполняет инференс для генерации ответа на основе запроса пользователя.        Возвращает        -------        str            Сгенерированный ответ.        """        if self.context_verbosity:            print(f"Ваш запрос: {self.prompt}")                    llm_chain = LLMChain(prompt=self.prompt, llm=self.llm)        print("Обработка информации с помощью gpt4all...\n")        response = llm_chain.run(self.user_input)        return  response  

Интерактивная экспериментирование

Чтобы помочь вам быстро начать, в блокноте есть интегрированные компоненты ipywidget. Вы должны выполнить все ячейки в блокноте, чтобы включить эти компоненты. Мы призываем вас настраивать параметры и оценивать влияние на задержку и достоверность ответа системы. Помните, что это всего лишь отправная точка и базовая демонстрация возможностей RAG.

Figure 10. In this example, we get a quick taste of the power of RAG, clearly seeing the benefits of the additional context provided by RAG, which helps yield a helpful answer to the user’s question — “My robot is not turning on, Can you help me?” The RAG-enabled output provides valid recommendations, while the raw model without RAG simply provides a polite inquiry that is not very helpful to the user.

Резюме и дискуссия

Никто не хочет взаимодействовать с медленными и нестабильными чат-ботами, которые отвечают ложной информацией. Существует множество комбинаций технического стека, которые помогают разработчикам избежать создания систем, которые дают ужасный пользовательский опыт. В этой статье мы рассмотрели важность качества инференса движка для пользовательского опыта с точки зрения стека, который обеспечивает масштаб, достоверность и задержку. Сочетание RAG, CPU и техник оптимизации моделей охватывает все углы IQ-треугольника (рисунок 3) и хорошо соответствует потребностям операционных AI-приложений на основе LLM.

Несколько интересных вещей, которые можно попробовать:

  • Измените шаблон запроса, найденный в методе retrieval_mechanism, чтобы создавать более качественные запросы в сочетании с извлеченным контекстом.
  • Настройте различные параметры модели и RAG и оцените их влияние на задержку и качество ответа.
  • Добавьте новые наборы данных, имеющие значение для вашей области, и проверьте, насколько подходит использование RAG для создания ваших приложений на основе чат-ботов.
  • Модель в этом примере (gpt4all-falcon-q4_0) не оптимизирована для процессоров Xeon. Исследуйте возможность использования моделей, оптимизированных для CPU-платформ, и оцените преимущества задержки инференса.

Спасибо за внимание! Не забудьте подписаться на мой профиль для получения больше статей в таком же духе!