Большие языковые модели (LLM) стали важным инструментом в обработке естественного языка, генерируя тексты так, что кажется, будто их пишет человек. Они анализируют огромные объёмы данных и генерируют точные ответы.
Ограничения LLM в генеративном ИИ
Но, как и у любого инструмента, у LLM есть свои ограничения. Главная проблема в том, что LLM обучаются на фиксированных данных и после этого работают только с тем, что уже заложено в них во время обучения. Никаких «посмотрел новости» или «узнал последние данные» — всё это им недоступно. Они не получают новые знания и не используют их.
Мы уже так привыкли к LLM, что здесь нужно вспомнить, что мы имеем в виду под «работают»?
LLM генерируют ответы на основе статистики, подбирая слова с учётом вероятностей. Кажется, что они действительно понимают, о чём говорят, но на самом деле — нет, они просто статистически определяют, что должно следовать за чем.
Поэтому LLM иногда выдаёт точные ответы, а иногда — случайные факты из своего обучающего набора данных, которые могут быть устаревшими или вовсе не релевантными. Эти так называемые галлюцинации могут вводить в заблуждение, когда модель «придумывает» факты или пересказывает что-то устаревшее. Такая непоследовательность — следствие отсутствия доступа к актуальной информации и понимания контекста.
С учётом этой особенности LLM полезны для обобщённого предоставления информации, но сталкиваются с проблемами при работе с узкоспециализированной информацией или актуальными данными, которые появились уже после завершения обучения модели.
Эта проблема особенно заметна в случаях, когда требуются актуальные или специализированные данные. Например, в поддержке клиентов, где вопросы часто касаются уникальных особенностей продуктов или услуг, либо в технической или нормативной документации, которая часто обновляется.
Представьте LLM, обученную на наборе данных, содержащем информацию о продуктах компании на момент 2022 года. В 2024 году компания выпускает новую линейку продуктов с обновлёнными характеристиками. Однако LLM, обученная в 2022 году, не сможет предоставить информацию о новых продуктах. Это делает её менее полезной в ответах на запросы клиентов.
Решение: Retrieval-Augmented Generation (RAG)
Генерация, дополненная поиском (Retrieval-Augmented Generation, RAG) — это технология, которая улучшает качество ответов, генерируемых большими языковыми моделями (LLM), путём предоставления доступа к внешним источникам данных. RAG позволяет LLM получать актуальные данные прямо во время анализа запроса пользователя и генерации ответа.
В отличие от стандартных LLM, которые полагаются исключительно на данные, использованные во время их обучения, RAG даёт возможность интегрировать актуальные и проверяемые факты из внешних баз знаний, что делает ответы LLM более достоверными.
В нашем примере с обновлённой продуктовой линейкой RAG может обратиться к актуальной документации или базе данных прямо в процессе ответа. Если в 2024 году появились новые характеристики, RAG сразу сообщит о них, не дожидаясь повторного обучения модели.
Основные преимущества внедрения RAG в систему ответов на вопросы заключаются в следующем:
- Актуальность и контекст. Модель получает доступ к «свежим» фактам, что делает её ответы более точными.
- Возможность проверки. Пользователи могут сопоставить ответ модели с исходными источниками, что позволяет проверить сгенерированные ответы и убедиться в их достоверности.
- Снижение вероятности «галлюцинаций» за счёт использования внешних данных.
Одно из ключевых преимуществ RAG — снижение потребности в дообучении (fine-tuning) LLM для работы с новыми данными. Это экономит вычислительные ресурсы и снижает стоимость, что особенно важно для компаний, использующих чат-боты и другие AI-решениями на основе LLM. Таким компаниям приходится часто обновлять информацию, чтобы их сервисы оставались актуальными, и это не должно быть дорого.
Таким образом, RAG предлагает экономичное и надёжное решение для обработки данных и повышения эффективности работы LLM.
Теперь давайте посмотрим, как можно применить RAG на практике. В качестве примера возьмём руководство пользователя в формате PDF, содержащее неструктурированные данные, и интегрируем его в LLM. PDF-документ будет преобразован для работы с моделью.
Мы увидим, что это улучшит способность LLM обрабатывать сложные и подробные вопросы.
Извлечение PDF-текста для RAG с помощью LangChain и NLTK
PDF-документ слишком объёмный, чтобы его можно было просто передать модели целиком, поэтому мы разобьём его на небольшие части, или, как их ещё называют, «чанки» (chunks).
Начнём с того, как извлечь текст из PDF с помощью Python. Для этого я буду использовать файл «GitReferenceMaterial.pdf» (это просто пример, для этого подойдёт любой другой документ).
Прежде чем модель сможет работать с текстом, нужно извлечь его из PDF-файла. Для этого используем библиотеку LangChain — она отлично справляется с задачей обработки больших текстов и легко интегрируется с языковыми моделями.
from langchain_community.document_loaders import PyPDFLoader pages = PyPDFLoader("GitReferenceMaterial.pdf").load_and_split() print("Прочитано {0} страниц".format(len(pages))) alltext = " ".join(p.page_content.replace("\n", " ") for p in pages)
Далее я использую инструментарий для обработки естественного языка, чтобы разбить текст на предложения.
Не весь текст полезен, так как в PDF-файле могут быть ненужные фрагменты, например, оглавление или указатели.
Чтобы очистить текст, я удалю предложения длиной 1 символ (как правило, это остатки от форматирования) и слишком длинные предложения — скорее всего, с ними что-то не так, если их длина превышает 2000 символов.
Вот пример кода для этого:
import nltk lengths=[] cleantext = "" for s in nltk.sent_tokenize(alltext): if(len(s) > 1 and len(s) < 2000): lengths.append(len(s)) cleantext = cleantext + s + " " print("Количество предложений: {0}".format(len(lengths))) print("Длинна текста %d" % len(cleantext))
Теперь, когда мы очистили текст и оставили только полезную информацию, он всё равно ещё остаётся неструктурированным.
Следующий шаг — разбить его на более удобные для модели «куски», чтобы искусственный интеллект мог эффективно использовать этот текст.
Разделение текста на фрагменты
При обработке текста важно учитывать, что предложения часто зависят друг от друга. Если разделить их слишком жёстко, можно потерять контекст, который необходим для правильного понимания. Давайте рассмотрим пример:
«Разработка данных включает проектирование и создание систем сбора, хранения и анализа данных. Она играет ключевую роль в оптимизации потоков данных. Это гарантирует безопасный доступ к данным и их эффективное обслуживание.»
Если мы возьмём второе предложение отдельно — «Она играет ключевую роль…» — оно теряет смысл без первого. Здесь «она» относится к «разработке данных», что показывает важность сохранения контекста.
Поэтому для обработки текста лучше использовать более крупные «куски» с перекрытием, чтобы модель могла учитывать взаимосвязи между предложениями.
Определяем длину фрагментов и перекрытий
Прежде чем разделить текст, полезно проанализировать его структуру. Например, можно рассчитать среднюю длину предложений:
import statistics m = statistics.mean(lengths) sd = statistics.stdev(lengths) print("Mean %d" % m) print("SD %d" % sd)
Это не жёсткое правило, а скорее рекомендация по выбору оптимальной длины фрагментов.
После нескольких экспериментов я заметила, что фрагменты длиной от 1 до 2 стандартных отклонений от средней длины предложения дают хорошие результаты.
Поэтому в примере с «GitReferenceMaterial.pdf» я использовала длину фрагмента в 380 символов и перекрытие в 80 символов.
Разбиваем текст на фрагменты оптимальной длины с LangChain
Теперь давайте посмотрим, как можно разбить текст на такие фрагменты с использованием библиотеки LangChain.
from langchain_text_splitters import RecursiveCharacterTextSplitter text_splitter = RecursiveCharacterTextSplitter( chunk_size=380, chunk_overlap=80, length_function=len, is_separator_regex=False, ) docs = text_splitter.create_documents([cleantext]) chunks = [d.page_content for d in docs]
Этот код разбивает текст на фрагменты оптимальной длины.
Теперь у нас есть список всех фрагментов (chunks) руководства пользователя, готовых для использования моделью LLM. Далее преобразуем их в векторы и добавим в векторную базу данных.
Преобразование фрагментов текста в векторы и сохранение в векторной базе данных
Когда текст разбит на фрагменты, следующим шагом является преобразование этих фрагментов в векторы. Векторы — это числовые представления текста, которые отражают его содержание. Чем ближе векторы друг к другу, тем больше текстовые фрагменты похожи.
Для сравнения векторов чаще всего используется косинусное расстояние. Оно показыает угол между векторами: если угол равен 0 (косинус равен 1), значит, тексты практически идентичны. Это удобный способ быстро находить наиболее релевантные фрагменты текста.
Векторные базы данных (на примере FAISS)
Чтобы хранить и искать по векторным представлениям текста, используются векторные базы данных, такие как FAISS. FAISS позволяет быстро искать похожие фрагменты среди миллионов векторов. FAISS также поддерживает различные индексы, что даёт возможность выбирать между точным и быстрым поиском.
Для преобразования текста в векторы используется технология встраиваний (embeddings).
Практическая реализация
Теперь давайте посмотрим, как это сделать на практике. В этом примере мы используем FAISS для хранения векторов и модель встраиваний от YandexGPT.
Вот пример кода:
from langchain_community.vectorstores import FAISS from langchain_community.embeddings.yandex import YandexGPTEmbeddings embeddings = YandexGPTEmbeddings(api_key='YANDEXGPT-IP-KEY', folder_id='FOLDER_ID', sleep_interval=0.1) vectorstore = FAISS.from_texts(chunks, embedding=embeddings) vectorstore.save_local("GitDB.faiss")
Этот код преобразует фрагменты текста в векторы с помощью модели YandexGPT и сохраняет их в базе данных FAISS. Это позволит быстро находить похожие фрагменты текста в будущем.
Процесс может занять некоторое время, так как система обрабатывает тысячи фрагментов текста и создаёт для каждого из них вектор. Однако после создания базы данных её можно будет использовать многократно, что ускорит будущие поиски.
Теперь, когда вы понимаете теорию, давайте проверим, будет ли это работать на практике!
Как протестировать векторную базу данных
RAG работает так: выборочно добавляет подходящие фрагменты текста (chunks) в промпты для LLM.
Важно оценить то, как быстро векторная база данных сможет находить наиболее релевантные чанки для добавления в промпт.
Давайте на примере посмотрим, как это можно проверить.
vectorstore = FAISS.load_local("GitDB.faiss", embeddings,allow_dangerous_deserialization=True) res = vectorstore.search("Что такое сокращение расходов?", search_type="similarity") for d in res: print(d.page_content)
Этот фрагмент загружает базу данных FAISS из дискового кэша и выполняет поиск по строке. Важно, чтобы для создания базы данных и для поиска использовалась одна и та же модель встраивания.
Попробуем выполнить этот код, чтобы проверить работу поиска. Ожидается, что в ответ на запрос мы получим несколько подходящих фрагментов текста. Иногда один и тот же текст может появляться несколько раз — это нормально. Это помогает LLM лучше понять контекст и дать более точный ответ.
При выполнении запроса вы можете выбрать, сколько фрагментов текста вернуть в запросе к LLM. Часто используется пять фрагментов, но можно поэкспериментировать.
- Если установить слишком мало «чанков», LLM может не получить всю нужную информацию.
- Если задать значение «ноль», это будет равносильно обычному запросу без RAG.
- Если выбрать слишком много фрагментов, запрос может стать слишком длинным и перегруженным неактуальной информацией, что может ухудшить качество ответа.
Простой пример использования RAG с LangChain, FAISS и встраиваниями (embeddings) в AI
В этом примере мы рассмотрим, как объединить векторную базу данных с моделью встраиваний (embeddings) и YandexGPT, чтобы создать систему с использованием Retrieval-Augmented Generation (RAG). Этот подход позволяет модели находить и использовать конкретные фрагменты текста из векторной базы данных.
from langchain_community.vectorstores import FAISS from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import RunnableLambda, RunnablePassthrough from langchain_community.embeddings.yandex import YandexGPTEmbeddings from langchain_community.llms import YandexGPT embeddings = YandexGPTEmbeddings(api_key='YOUR-IP-KEY', folder_id='FOLDER-ID', sleep_interval=0.1) vectorstore = FAISS.load_local("GitDB.faiss", embeddings, allow_dangerous_deserialization=True) vscontext = vectorstore.as_retriever() model = YandexGPT(modelUri="gpt://FOLDER-ID/yandexgpt-lite", temperature=1, api_key='YOUR-IP-KEY', folder_id='FOLDER-ID') template = """Ваша задача - ответить на вопрос по инструкции Git. Используйте следующий контекст, чтобы помочь ответить на вопрос. {context} {question} """ prompt = ChatPromptTemplate.from_template(template) print(prompt) chain = ( {"context": vscontext, "question": RunnablePassthrough()} | prompt | model | StrOutputParser() ) print(chain.invoke("Каков минимальный размер частичного хэша, который Git может использовать для ссылки на коммит?"))
Шаг 1: Загрузка векторной базы данных с векторами
Первый шаг — загрузить векторную базу данных, в которой содержатся заранее обработанные фрагменты текста, представленные в виде векторов. Важно, что для создания этой базы данных использовалась модель встраиваний YandexGPT Embeddings. В дальнейшем она же будет использоваться для поиска.
Здесь мы используем модель встраиваний YandexGPT Embeddings для того, чтобы текстовые фрагменты преобразовать в векторы.
Шаг 2: Настройка GPT и шаблона промпта, где контекст (релевантные фрагменты текста) и вопрос пользователя подставляются автоматически.
Далее подключаем YandexGPT, который будет отвечать на вопросы. Для того чтобы LLM могла использовать информацию из базы данных, мы создаём шаблон запроса, который включает:
- Контекст, полученный из векторной базы данных (релевантные фрагменты текста, найденные с помощью встраиваний),
- Вопрос, на который нужно ответить.
Здесь шаблон запроса соединяет контекст, который был найден с помощью эмбеддингов в векторной базе данных, и вопрос пользователя.
Шаг 3: Выполнение RAG-запроса с использованием встраиваний. Модель YandexGPT использует как текстовые фрагменты из векторной базы данных, так и сам вопрос пользователя для того, чтобы сформулировать более точный ответ
Теперь мы можем выполнить запрос, используя контекст из векторной базы данных и вопрос, который передаём LLM.
Векторная база данных находит релевантные фрагменты текста, которые помогают модели лучше понять контекст и дать точный ответ.
Пример результата
Когда вы запустите этот код, вы получите ответ от YandexGPT, который будет усилен данными из векторной базы данных. Вот пример ответа:
Минимальный размер частичного хэша, который Git может использовать для ссылки на коммит, составляет четыре символа.
RAG с Epsilon Workflow: как использовать LLM для ИИ без строчки кода
Epsilon Workflow позволяет вам встроить большие языковые модели (LLM) в процессы, не написав при этом ни строчки кода. Важная характеристика — поддержка Retrieval-Augmented Generation (RAG). Это значит, что LLM получает доступ к данным из векторных баз данных. Этот подход ускоряет внедрение RAG в любые проекты — как новые, так и существующие.
Как это работает?
Epsilon Workflow интегрируется с векторными базами данных и автоматически извлекает нужные фрагменты текста для LLM. Это позволяет вашему LLM работать с актуальными данными, а вам — быстро получить точные ответы без программирования и сложной настройки.
Ещё одна функция — обратный ETL. Этот инструмент отправляет данные, сгенерированные LLM, напрямую в бизнес-процессы. Например, обработанная ИИ стенограмма совещания может сразу попасть в вашу CRM.
Что это даёт?
- No-code. Настройка и поддержка LLM и RAG без необходимости программирования.
- Работа с векторными базами данных. Поддержка различных векторных баз данных позволяет улучшать ответы LLM.
- Автоматизация бизнес-процессов с помощью обратного ETL. Простая интеграция результатов LLM в системы.
- Прозрачность процессов. Контроль и объяснение каждого шага работы модели.
Как это поможет вашему бизнесу?
Представьте, что у вас есть система, которая автоматически обрабатывает данные, извлекает нужную информацию и помогает вашей LLM отвечать на запросы клиентов или сотрудников. И всё это без необходимости в программировании. Epsilon Workflow позволяет внедрить такие решения быстро и просто.
Если вам интересно, как это работает на практике, Epsilon Workflow предлагает библиотеку с видеоуроками и демонстрациями. В одном из таких видео рассказываем, как с помощью RAG автоматизировать ответы на вопросы клиентов.
С Epsilon Workflow вы получаете возможность легко интегрировать LLM и RAG в свои рабочие процессы без строчки кода. Это мощный инструмент для бизнеса, который помогает ускорить работу с ИИ, автоматизировать задачи и сделать процесс управления данными лёгким и понятным.
Epsilon Workflow может стать ключевым инструментом для включения ИИ в ваши процессы. Начните с нами уже сегодня.