paint-brush
Учебное пособие о том, как создать свой собственный RAG и запустить его локально: Langchain + Ollama + Streamlitк@vndee
6,983 чтения
6,983 чтения

Учебное пособие о том, как создать свой собственный RAG и запустить его локально: Langchain + Ollama + Streamlit

к Duy Huynh8m2023/12/15
Read on Terminal Reader

Слишком долго; Читать

Для знакомства с RAG рекомендую просмотреть эти статьи. Однако в этом посте мы пропустим основы и покажем вам, как создать собственное приложение RAG, которое можно будет запускать локально на вашем ноутбуке, не беспокоясь о конфиденциальности данных и стоимости токенов. Мы создадим приложение, похожее на ChatPDF, но более простое. Где пользователи могут загружать PDF-документы и задавать вопросы через простой пользовательский интерфейс. Наш технологический стек очень прост: Langchain, Ollama и Streamlit.
featured image - Учебное пособие о том, как создать свой собственный RAG и запустить его локально: Langchain + Ollama + Streamlit
Duy Huynh HackerNoon profile picture

С появлением моделей больших языков и их впечатляющими возможностями на базе таких гигантских поставщиков LLM, как OpenAI и Anthropic, создается множество необычных приложений. Мифом, лежащим в основе таких приложений, является фреймворк RAG, подробно описанный в следующих статьях:


Для знакомства с RAG рекомендую просмотреть эти статьи. Однако в этом посте мы пропустим основы и покажем вам, как создать собственное приложение RAG, которое можно будет запускать локально на вашем ноутбуке, не беспокоясь о конфиденциальности данных и стоимости токенов.


Мы создадим приложение, похожее на ChatPD F, но более простое. Где пользователи могут загружать PDF-документы и задавать вопросы через простой пользовательский интерфейс. Наш технологический стек очень прост: Langchain, Ollama и Streamlit.

  • LLM-сервер : наиболее важным компонентом этого приложения является LLM-сервер. Благодаря Оллама , у нас есть надежный LLM-сервер, который можно настроить локально, даже на ноутбуке. Пока лама.cpp вариант, я считаю, что Ollama, написанная на Go, проще в настройке и запуске.


  • РАГ : Несомненно, две ведущие библиотеки в области LLM — это Лангчейн и ЛламИндекс . В этом проекте я буду использовать Langchain, поскольку знаком с ним по профессиональному опыту. Важным компонентом любой среды RAG является векторное хранилище. Мы будем использовать цветность здесь, поскольку он хорошо интегрируется с Langchain.


  • Пользовательский интерфейс чата : Пользовательский интерфейс также является важным компонентом. Хотя существует множество доступных технологий, я предпочитаю использовать Стримлит , библиотека Python, для вашего спокойствия.


Хорошо, приступим к настройке.

Настройка Олламы

Как упоминалось выше, настройка и запуск Ollama просты. Сначала посетите оллама.ай и загрузите приложение, подходящее для вашей операционной системы.


Затем откройте терминал и выполните следующую команду, чтобы получить последнюю версию Мистраль-7Б . Хотя есть много других Доступны модели LLM , я выбираю Мистраль-7Б за его компактность и конкурентоспособное качество.


 ollama pull mistral


После этого запустите ollama list , чтобы проверить, правильно ли вытянута модель. Вывод терминала должен выглядеть следующим образом:

Теперь, если сервер LLM еще не запущен, запустите его с помощью ollama serve . Если вы столкнулись с сообщением об ошибке типа "Error: listen tcp 127.0.0.1:11434: bind: address already in use" , это означает, что сервер уже запущен по умолчанию, и вы можете перейти к следующему шагу.

Постройте трубопровод RAG

Вторым шагом в нашем процессе является создание конвейера RAG. Учитывая простоту нашего приложения, нам в первую очередь нужны два метода: ingest и ask .


Метод ingest принимает путь к файлу и загружает его в векторное хранилище в два этапа: во-первых, он разбивает документ на более мелкие фрагменты, чтобы соответствовать лимиту токенов LLM; во-вторых, он векторизует эти фрагменты с помощью Qdrant FastEmbeddings и сохраняет их в Chroma.


Метод ask обрабатывает запросы пользователей. Пользователи могут задать вопрос, а затем RetrivalQAChain извлекает соответствующие контексты (фрагменты документов), используя методы поиска по векторному сходству.


Используя вопрос пользователя и полученные контексты, мы можем составить подсказку и запросить прогноз от сервера LLM.

 from langchain.vectorstores import Chroma from langchain.chat_models import ChatOllama from langchain.embeddings import FastEmbedEmbeddings from langchain.schema.output_parser import StrOutputParser from langchain.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.schema.runnable import RunnablePassthrough from langchain.prompts import PromptTemplate from langchain.vectorstores.utils import filter_complex_metadata class ChatPDF: vector_store = None retriever = None chain = None def __init__(self): self.model = ChatOllama(model="mistral") self.text_splitter = RecursiveCharacterTextSplitter(chunk_size=1024, chunk_overlap=100) self.prompt = PromptTemplate.from_template( """ <s> [INST] You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise. [/INST] </s> [INST] Question: {question} Context: {context} Answer: [/INST] """ ) def ingest(self, pdf_file_path: str): docs = PyPDFLoader(file_path=pdf_file_path).load() chunks = self.text_splitter.split_documents(docs) chunks = filter_complex_metadata(chunks) vector_store = Chroma.from_documents(documents=chunks, embedding=FastEmbedEmbeddings()) self.retriever = vector_store.as_retriever( search_type="similarity_score_threshold", search_kwargs={ "k": 3, "score_threshold": 0.5, }, ) self.chain = ({"context": self.retriever, "question": RunnablePassthrough()} | self.prompt | self.model | StrOutputParser()) def ask(self, query: str): if not self.chain: return "Please, add a PDF document first." return self.chain.invoke(query) def clear(self): self.vector_store = None self.retriever = None self.chain = None

Приглашение получено из хаба Langchain: Langchain RAG подсказывает Мистраль . Эта подсказка была протестирована и загружена тысячи раз и служит надежным ресурсом для изучения методов подсказок LLM.


Вы можете узнать больше о методах подсказок LLM. здесь .


Подробнее о реализации:


  • ingest : мы используем PyPDFLoader для загрузки PDF-файла, загруженного пользователем. RecursiveCharacterSplitter, предоставленный Langchain, затем разбивает этот PDF-файл на более мелкие фрагменты. Важно отфильтровывать сложные метаданные, не поддерживаемые ChromaDB, с помощью функции filter_complex_metadata из Langchain.


    Для векторного хранения используется Chroma в сочетании с Qdrant FastEmbed в качестве нашей модели встраивания. Эта облегченная модель затем преобразуется в ретривер с порогом оценки 0,5 и k=3, что означает, что она возвращает 3 верхних фрагмента с наивысшими оценками выше 0,5. Наконец, мы строим простую цепочку разговоров, используя ЛЕКЛ .


  • ask : этот метод просто передает вопрос пользователя в нашу предопределенную цепочку, а затем возвращает результат.


  • clear : этот метод используется для очистки предыдущего сеанса чата и хранилища при загрузке нового PDF-файла.

Проект простого пользовательского интерфейса

Для простого пользовательского интерфейса мы будем использовать Стримлит , инфраструктура пользовательского интерфейса, предназначенная для быстрого создания прототипов приложений AI/ML.

 import os import tempfile import streamlit as st from streamlit_chat import message from rag import ChatPDF st.set_page_config(page_title="ChatPDF") def display_messages(): st.subheader("Chat") for i, (msg, is_user) in enumerate(st.session_state["messages"]): message(msg, is_user=is_user, key=str(i)) st.session_state["thinking_spinner"] = st.empty() def process_input(): if st.session_state["user_input"] and len(st.session_state["user_input"].strip()) > 0: user_text = st.session_state["user_input"].strip() with st.session_state["thinking_spinner"], st.spinner(f"Thinking"): agent_text = st.session_state["assistant"].ask(user_text) st.session_state["messages"].append((user_text, True)) st.session_state["messages"].append((agent_text, False)) def read_and_save_file(): st.session_state["assistant"].clear() st.session_state["messages"] = [] st.session_state["user_input"] = "" for file in st.session_state["file_uploader"]: with tempfile.NamedTemporaryFile(delete=False) as tf: tf.write(file.getbuffer()) file_path = tf.name with st.session_state["ingestion_spinner"], st.spinner(f"Ingesting {file.name}"): st.session_state["assistant"].ingest(file_path) os.remove(file_path) def page(): if len(st.session_state) == 0: st.session_state["messages"] = [] st.session_state["assistant"] = ChatPDF() st.header("ChatPDF") st.subheader("Upload a document") st.file_uploader( "Upload document", type=["pdf"], key="file_uploader", on_change=read_and_save_file, label_visibility="collapsed", accept_multiple_files=True, ) st.session_state["ingestion_spinner"] = st.empty() display_messages() st.text_input("Message", key="user_input", on_change=process_input) if __name__ == "__main__": page()


Запустите этот код с помощью streamlit run app.py , чтобы увидеть, как он выглядит.

Хорошо, вот и все! Теперь у нас есть приложение ChatPDF, которое полностью работает на вашем ноутбуке. Поскольку этот пост в основном посвящен общему обзору того, как создать собственное приложение RAG, есть несколько аспектов, которые требуют тонкой настройки. Вы можете рассмотреть следующие предложения, чтобы улучшить свое приложение и развить свои навыки:


  • Добавить память в цепочку разговора : в настоящее время он не запоминает ход разговора. Добавление временной памяти поможет вашему помощнику осознавать контекст.


  • Разрешить загрузку нескольких файлов : можно обсуждать один документ одновременно. Но представьте, если бы мы могли обсуждать несколько документов — вы могли бы поместить туда всю свою книжную полку. Это было бы супер круто!


  • Используйте другие модели LLM : хотя Mistral эффективен, существует множество других альтернатив. Возможно, вы найдете модель, которая лучше соответствует вашим потребностям, например LlamaCode для разработчиков. Однако помните, что выбор модели зависит от вашего оборудования, особенно от объема оперативной памяти 💵


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


Наконец, спасибо за чтение. Если вы найдете эту информацию полезной, пожалуйста, рассмотрите возможность подписки на мою рассылку. Подстек или мое личное блог . Я планирую написать больше о приложениях RAG и LLM, и вы можете предлагать темы, оставив комментарий ниже. Ваше здоровье!


Полный исходный код: https://github.com/vndee/local-rag-example