paint-brush
Вичерпний навчальний посібник зі створення програми RAG за допомогою LangChainза@bexgboost
1,112 показання
1,112 показання

Вичерпний навчальний посібник зі створення програми RAG за допомогою LangChain

за Bex19m2024/09/03
Read on Terminal Reader

Надто довго; Читати

Дізнайтеся, як використовувати LangChain, дуже популярну структуру для створення систем RAG. Наприкінці підручника ми матимемо чат-бота (з інтерфейсом Streamlit і всім іншим), який пробиратиметься через деякі особисті дані, щоб дати відповіді на запитання.
featured image - Вичерпний навчальний посібник зі створення програми RAG за допомогою LangChain
Bex HackerNoon profile picture

Сучасні великі мовні моделі мають доступ до постійно зростаючої кількості інформації. Однак залишається величезна кількість приватних даних, які ці моделі не використовують. Ось чому одним із найпопулярніших застосувань LLM у корпоративних налаштуваннях є пошуково-доповнена генерація (скорочено RAG). на Візли , нашої платформи аналізу даних на базі ШІ, ми отримали цінну інформацію про створення ефективних систем RAG. У цьому підручнику ми поділимося деякими з наших знань і покажемо вам, як створити власну систему RAG.


Ви дізнаєтеся, як використовувати LangChain, дуже популярну структуру для побудови систем RAG, щоб створити просту систему RAG. Наприкінці навчального посібника ми матимемо чат-бота (з інтерфейсом Streamlit і всім іншим), який пробиратиметься через деякі особисті дані, щоб дати відповіді на запитання.

Що таке RAG?

Щоб зрозуміти, що таке RAG, розглянемо простий приклад.


Студент першого курсу коледжу, Чендлер, розглядає можливість пропустити кілька уроків, але хоче переконатися, що він не порушує правила відвідування університету. Як і будь-що в наші дні, він задає питання ChatGPT .


Звичайно, ChatGPT не може на нього відповісти. Чат-бот не тупий — він просто не має доступу до університетських документів Чендлера. Тож Чендлер сам знаходить документ про політику та виявляє, що це довге технічне читання, яке він не хоче пробиратися. Замість цього він передає весь документ ChatGPT і знову ставить запитання. Цього разу він отримує відповідь.


Це окремий випадок генерації з доповненим пошуком. Відповідь (генерація) мовної моделі доповнюється (збагачується) контекстом, отриманим із джерела, яке не є частиною її початкового навчання.


Масштабована версія системи RAG зможе відповісти на будь-яке запитання студента, самостійно шукаючи університетські документи, знаходячи відповідні та витягуючи фрагменти тексту, які, швидше за все, містять відповідь.


Загалом кажучи, у системі RAG ви отримуєте інформацію з приватного джерела даних і передаєте її в мовну модель, дозволяючи моделі давати релевантну контексту відповідь.

Компоненти програми RAG

Така система, незважаючи на те, що звучить просто, мала б багато рухомих компонентів. Перш ніж створити його самостійно, нам потрібно переглянути, що це таке та як вони грають разом.

Документи

Перша складова — документ або сукупність документів. Залежно від типу RAG-системи, яку ми створюємо, документами можуть бути текстові файли, PDF-файли, веб-сторінки (RAG поверх неструктурованих даних) або бази даних графіків, SQL або NoSQL (RAG поверх структурованих даних). Вони використовуються для введення різних типів даних у систему.

Завантажувачі документів

LangChain реалізує сотні класів, які називаються завантажувачами документів , для читання даних із різних джерел документів, таких як PDF-файли, Slack, Notion, Google Drive тощо.


Кожен клас завантажувача документів є унікальним, але всі вони мають однаковий метод .load() . Наприклад, ось як можна завантажити PDF-документ і веб-сторінку в LangChain:

 from langchain_community.document_loaders import PyPDFLoader, WebBaseLoader # pip install langchain-community pdf_loader = PyPDFLoader("framework_docs.pdf") web_loader = WebBaseLoader( "https://python.langchain.com/v0.2/docs/concepts/#document-loaders" ) pdf_docs = pdf_loader.load() web_docs = web_loader.load()


Клас PyPDFLoader обробляє PDF-файли за допомогою пакета PyPDF2 під капотом, тоді як WebBaseLoader сканує вміст заданої веб-сторінки.


pdf_docs містить чотири об’єкти документа, по одному для кожної сторінки:


 >>> len(pdf_docs) 4


Хоча web_docs містять лише один:

 >>> print(web_docs[0].page_content[125:300].strip()) You can view the v0.1 docs here.IntegrationsAPI referenceLatestLegacyMorePeopleContributingCookbooks3rd party tutorialsYouTubearXivv0.2v0.2v0.1🦜️🔗LangSmithLangSmith DocsLangCh


Пізніше ці об’єкти документа передаються моделям вбудовування, щоб зрозуміти семантичне значення їхнього тексту.


Щоб дізнатися більше про інші типи завантажувачів документів, LangChain пропонує a присвячена сторінка з інструкціями .

Розділювачі тексту

Після того, як ви завантажили свої документи, дуже важливо розбити їх на менші та зручніші фрагменти тексту. Ось основні причини:

  1. Багато моделей вбудовування (більше про них пізніше) мають максимальний ліміт маркерів.
  2. Отримання точніше, якщо у вас є менші фрагменти.
  3. Мовна модель подається в точний контекст.


LangChain пропонує багато типів текстових роздільників у своєму пакеті langchain_text_splitters, і вони відрізняються залежно від типу документа.

Ось як використовувати RecursiveCharacterTextSplitter для розділення звичайного тексту на основі списку роздільників і розміру блоку:

 !pip install langchain_text_splitters from langchain_text_splitters import RecursiveCharacterTextSplitter # Example text text = """ RAG systems combine the power of large language models with external knowledge sources. This allows them to provide up-to-date and context-specific information. The process involves several steps including document loading, text splitting, and embedding. """ # Create a text splitter text_splitter = RecursiveCharacterTextSplitter( chunk_size=50, chunk_overlap=10, length_function=len, separators=["\n\n", "\n", " ", ""], ) # Split the text chunks = text_splitter.split_text(text) # Print the chunks for i, chunk in enumerate(chunks): print(f"Chunk {i + 1}: {chunk}")

Вихід:

 Chunk 1: RAG systems combine the power of large language Chunk 2: language models with external knowledge sources. Chunk 3: This allows them to provide up-to-date and Chunk 4: and context-specific information. Chunk 5: The process involves several steps including Chunk 6: including document loading, text splitting, and Chunk 7: and embedding.

Цей розгалужувач є універсальним і добре працює в багатьох випадках використання. Він створює кожен блок із кількістю символів, максимально наближеною до chunk_size . Він може рекурсивно перемикатися між роздільниками, на які потрібно розділити, щоб зберегти кількість символів.


У наведеному вище прикладі наш роздільник намагається спочатку розділити на символи нового рядка, потім на пробіли, а нарешті між будь-якими символами, щоб досягти бажаного розміру фрагмента.


У пакеті langchain_text_splitters є багато інших роздільників. Ось деякі з них:

  • HTMLSectionSplitter
  • PythonCodeTexSplitter
  • RecursiveJsonSplitter

і так далі. Деякі з розгалужувачів створюють семантично значущі фрагменти за допомогою моделі трансформатора під капотом.


Правильний роздільник тексту значно впливає на продуктивність системи RAG.


Докладніше про те, як використовувати роздільники тексту, див інструкції тут .

Вбудовування моделей

Коли документи розділені на текст, їх потрібно закодувати в числове представлення, що є вимогою для всіх моделей обчислень, що працюють з текстовими даними.


У контексті RAG таке кодування називається вбудовуванням і виконується моделями вбудовування . Вони створюють векторне представлення фрагмента тексту, яке фіксує їх семантичне значення. Представляючи текст таким чином, ви можете виконувати з ним математичні операції, наприклад шукати в нашій базі даних документів текст, найбільш схожий за значенням, або знаходити відповідь на запит користувача.


LangChain підтримує всіх основних постачальників моделей вбудовування, таких як OpenAI, Cohere, HuggingFace тощо. Вони реалізовані як класи Embedding та надають два методи: один для вбудовування документів і один для вбудовування запитів (підказок).


Ось приклад коду, який вбудовує фрагменти тексту, які ми створили в попередньому розділі за допомогою OpenAI:

 from langchain_openai import OpenAIEmbeddings # Initialize the OpenAI embeddings embeddings = OpenAIEmbeddings() # Embed the chunks embedded_chunks = embeddings.embed_documents(chunks) # Print the first embedded chunk to see its structure print(f"Shape of the first embedded chunk: {len(embedded_chunks[0])}") print(f"First few values of the first embedded chunk: {embedded_chunks[0][:5]}")


Вихід:

 Shape of the first embedded chunk: 1536 First few values of the first embedded chunk: [-0.020282309502363205, -0.0015041005099192262, 0.004193042870610952, 0.00229285703971982, 0.007068077567964792]

Вихідні дані вище показують, що модель вбудовування створює 1536-вимірний вектор для всіх блоків у наших документах.


Щоб вставити один запит, ви можете використати метод embed_query() :

 query = "What is RAG?" query_embedding = embeddings.embed_query(query) print(f"Shape of the query embedding: {len(query_embedding)}") print(f"First few values of the query embedding: {query_embedding[:5]}")


Вихід:

 Shape of the query embedding: 1536 First few values of the query embedding: [-0.012426204979419708, -0.016619959846138954, 0.007880032062530518, -0.0170428603887558, 0.011404196731746197]

Векторні магазини

У великомасштабних додатках RAG, де у вас можуть бути гігабайти документів, ви отримаєте величезну кількість текстових блоків і, отже, векторів. Від них немає користі, якщо ви не можете їх надійно зберігати.


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


Ось фрагмент коду, який вбудовує вміст веб-сторінки та зберігає вектори в векторній базі даних Chroma ( Chroma — це рішення векторної бази даних із відкритим кодом , яке повністю працює на вашому комп’ютері):

 !pip install chromadb langchain_chroma from langchain_community.document_loaders import WebBaseLoader from langchain_text_splitters import RecursiveCharacterTextSplitter # Load the web page loader = WebBaseLoader("https://python.langchain.com/v0.2/docs/tutorials/rag/") docs = loader.load() # Split the documents into chunks text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200) chunks = text_splitter.split_documents(docs)


Спочатку ми завантажуємо сторінку за допомогою WebBaseLoader і створюємо фрагменти. Потім ми можемо безпосередньо передати фрагменти в метод from_documents Chroma разом із обраною моделлю вбудовування:

 from langchain_openai import OpenAIEmbeddings from langchain_chroma import Chroma db = Chroma.from_documents(chunks, OpenAIEmbeddings())


Усі об’єкти векторної бази даних у LangChain надають метод similarity_search , який приймає рядок запиту:

 query = "What is indexing in the context of RAG?" docs = db.similarity_search(query) print(docs[1].page_content)


Вихід:

 If you are interested for RAG over structured data, check out our tutorial on doing question/answering over SQL data.Concepts​A typical RAG application has two main components:Indexing: a pipeline for ingesting data from a source and indexing it. This usually happens offline.Retrieval and generation: the actual RAG chain, which takes the user query at run time and retrieves the relevant data from the index, then passes that to the model.The most common full sequence from raw data to answer looks like:Indexing​Load: First we need to load our data. This is done with Document Loaders.Split: Text splitters break large Documents into smaller chunks. This is useful both for indexing data and for passing it in to a model, since large chunks are harder to search over and won't fit in a model's finite context window.Store: We need somewhere to store and index our splits, so that they can later be searched over. This is often done using a VectorStore and Embeddings model.Retrieval and

Результатом similarity_search є список документів, які, швидше за все, містять інформацію, яку ми запитуємо в запиті.


Докладніше про використання векторних сховищ див інструкції тут .

Ретривери

Хоча всі векторні сховища підтримують пошук у формі пошуку подібності, LangChain реалізує спеціальний інтерфейс Retriever , який повертає документи за неструктурованим запитом. Ретриверу потрібно лише повертати або витягувати документи, а не зберігати їх.


Ось як ви можете перетворити будь-який векторний магазин на ретривер у LangChain:

 # Convert the vector store to a retriever chroma_retriever = db.as_retriever() docs = chroma_retriever.invoke("What is indexing in the context of RAG?") >>> len(docs) 4


Можна обмежити кількість релевантних документів до top k за допомогою search_kwargs :

 chroma_retriever = db.as_retriever(search_kwargs={"k": 1}) docs = chroma_retriever.invoke("What is indexing in the context of RAG?") >>> len(docs) 1

Ви можете передати інші параметри, пов’язані з пошуком, у search_kwargs. Дізнайтеся більше про використання ретриверів з конкретні інструкції .

Покроковий робочий процес для створення програми RAG у LangChain

Тепер, коли ми розглянули ключові компоненти системи RAG, ми створимо її самостійно. Я проведу вас через крок за кроком впровадження чат-бота RAG, розробленого спеціально для документації коду та навчальних посібників. Ви знайдете це особливо корисним, коли вам потрібна допомога в кодуванні ШІ для нових фреймворків або нових функцій існуючих фреймворків, які ще не є частиною бази знань сучасних LLM.

0. Створення структури проекту

Спочатку заповніть свій робочий каталог такою структурою проекту:

 rag-chatbot/ ├── .gitignore ├── requirements.txt ├── README.md ├── app.py ├── src/ │ ├── __init__.py │ ├── document_processor.py │ └── rag_chain.py └── .streamlit/ └── config.toml


Ось команди:

 $ touch .gitignore requirements.txt README.md app.py $ mkdir src .streamlit $ touch src/{.env,__init__.py,document_processor.py,rag_chain.py} $ touch .streamlit/{.env,config.toml}

1. Налаштування середовища

На цьому кроці ви спочатку створюєте нове середовище Conda та активуєте його:

 $ conda create -n rag_tutorial python=3.9 -y $ conda activate rag_tutorial


Далі відкрийте файл requirements.txt і вставте такі залежності:

 langchain==0.2.14 langchain_community==0.2.12 langchain_core==0.2.35 langchain_openai==0.1.22 python-dotenv==1.0.1 streamlit==1.37.1 faiss-cpu pypdf

і встановити їх:

 $ pip install -r requirements.txt


Також створіть файл .gitignore , щоб приховати файли від індексування git:

 # .gitignore venv/ __pycache__/ .env *.pdf *.png *.jpg *.jpeg *.gif *.svg

2. Налаштування завантажувачів документів

Далі відкрийте файл src/document_processor.py і вставте наступні фрагменти коду.


Необхідний імпорт:

 import logging from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.text_splitter import Language from langchain_community.document_loaders import PyPDFLoader from langchain_community.document_loaders.parsers.pdf import ( extract_from_images_with_rapidocr, ) from langchain.schema import Document


Пояснення щодо імпорту:

  • RecursiveCharacterTextSplitter : рекурсивно розділяє текст на менші фрагменти.
  • Language : Enum для визначення мов програмування в розділенні тексту.
  • PyPDFLoader : завантажує та витягує текст із файлів PDF.
  • extract_from_images_with_rapidocr : функція OCR для вилучення тексту із зображень.
  • Document : представляє документ із вмістом і метаданими.
  • logging : надає функцію журналювання для налагодження та інформації.


Потім функція для обробки PDF-файлів:

 def process_pdf(source): loader = PyPDFLoader(source) documents = loader.load() # Filter out scanned pages unscanned_documents = [doc for doc in documents if doc.page_content.strip() != ""] scanned_pages = len(documents) - len(unscanned_documents) if scanned_pages > 0: logging.info(f"Omitted {scanned_pages} scanned page(s) from the PDF.") if not unscanned_documents: raise ValueError( "All pages in the PDF appear to be scanned. Please use a PDF with text content." ) return split_documents(unscanned_documents)


Ось як це працює:

  1. Він завантажує PDF за допомогою PyPDFLoader .
  2. Він фільтрує відскановані сторінки, видаляючи документи з порожнім вмістом.
  3. Він реєструє кількість пропущених відсканованих сторінок, якщо такі є.
  4. Якщо скануються всі сторінки (тобто немає текстового вмісту), виникає помилка ValueError.
  5. Нарешті, він розбиває решту несканованих документів на менші частини за допомогою функції split_documents.

Ця функція обробляє випадки, коли PDF-файл може містити суміш тексту та відсканованих сторінок, забезпечуючи подальшу обробку лише текстових сторінок. Це має вирішальне значення для завдань аналізу тексту, коли відскановані сторінки без OCR були б непридатними. Ми визначимо функцію split_documents пізніше.


Далі ми пишемо функцію для отримання інформації із зображень (скріншотів фрагментів коду та/або веб-сторінок):


 def process_image(source): # Extract text from image using OCR with open(source, "rb") as image_file: image_bytes = image_file.read() extracted_text = extract_from_images_with_rapidocr([image_bytes]) documents = [Document(page_content=extracted_text, metadata={"source": source})] return split_documents(documents)


Ця функція обробляє файл зображення шляхом вилучення тексту за допомогою OCR (оптичне розпізнавання символів). Він зчитує файл зображення, перетворює його на байти, а потім використовує бібліотеку RapidOCR для вилучення тексту із зображення. Потім витягнутий текст загортається в об’єкт Document із метаданими, що містять шлях до вихідного файлу. Нарешті, функція розбиває документ на менші фрагменти за допомогою функції split_documents , яку ми визначаємо далі:


 def split_documents(documents): # Split documents into smaller chunks for processing text_splitter = RecursiveCharacterTextSplitter.from_language( language=Language.PYTHON, chunk_size=1000, chunk_overlap=200 ) return text_splitter.split_documents(documents)


Функція використовує клас RecursiveCharacterTextSplitter із синтаксисом Python, щоб розділити текст на фрагменти по 1000 символів із перекриттям 200 символів.


Наша остання функція об’єднує функції аналізатора PDF і зображень в одну:


 def process_document(source): # Determine file type and process accordingly if source.lower().endswith(".pdf"): return process_pdf(source) elif source.lower().endswith((".png", ".jpg", ".jpeg")): return process_image(source) else: raise ValueError(f"Unsupported file type: {source}")


Ця остання функція використовуватиметься інтерфейсом користувача Streamlit для створення, вбудовування та зберігання фрагментів із наданих документів і передачі їх у компонент RAG нашої системи.

3. Налаштування RAG

Тепер відкрийте файл src/rag_chain.py і вставте наступні фрагменти коду.


Спочатку імпортуйте необхідні модулі:


 import os from dotenv import load_dotenv from langchain.prompts import PromptTemplate from langchain_community.vectorstores import FAISS from langchain_core.output_parsers import StrOutputParser from langchain_core.runnables import RunnablePassthrough from langchain_openai import ChatOpenAI, OpenAIEmbeddings # Load the API key from env variables load_dotenv() api_key = os.getenv("OPENAI_API_KEY")


Ось пояснення щодо імпорту:

os : взаємодія операційної системи • dotenv : завантаження змінних середовища • компоненти langchain :

  • PromptTemplate : створення спеціального підказки
  • FAISS : легке векторне сховище документів
  • StrOutputParser : Перетворення об’єктів повідомлень LLM у вихідні рядки
  • RunnablePassthrough : створюйте складні ланцюжки
  • ChatOpenAI , OpenAIEmbeddings : взаємодія моделі OpenAI


Далі ми створюємо наш запит для системи RAG:


 RAG_PROMPT_TEMPLATE = """ You are a helpful coding assistant that can answer questions about the provided context. The context is usually a PDF document or an image (screenshot) of a code file. Augment your answers with code snippets from the context if necessary. If you don't know the answer, say you don't know. Context: {context} Question: {question} """ PROMPT = PromptTemplate.from_template(RAG_PROMPT_TEMPLATE)


Підказка системи RAG є одним з найважливіших факторів її успіху. Наша версія проста, але більшу частину часу виконає роботу. На практиці ви витратите багато часу на ітерацію та вдосконалення підказки.


Якщо ви помітили, ми використовуємо клас PromptTemplate для створення підказки. Ця конструкція дозволяє нам динамічно вводити контекст, отриманий із документів і запиту користувача, у кінцеву підказку.


Говорячи про документи, нам потрібна функція для їх форматування перед тим, як вони будуть передані як контекст у системну підказку:


 def format_docs(docs): return "\n\n".join(doc.page_content for doc in docs)


Це проста функція, яка об’єднує вміст сторінки отриманих документів.


Нарешті, ми створюємо функцію, яка розвиватиме наш ланцюжок RAG:


 def create_rag_chain(chunks): embeddings = OpenAIEmbeddings(api_key=api_key) doc_search = FAISS.from_documents(chunks, embeddings) retriever = doc_search.as_retriever( search_type="similarity", search_kwargs={"k": 5} ) llm = ChatOpenAI(model_name="gpt-4o-mini", temperature=0) rag_chain = ( {"context": retriever | format_docs, "question": RunnablePassthrough()} | PROMPT | llm | StrOutputParser() ) return rag_chain


Функція приймає фрагменти документів, які надає функція process_document у сценарії document_processor.py .

Функція починається з визначення моделі вбудовування та збереження документів у векторному сховищі FAISS. Потім він перетворюється на інтерфейс пошуку за схожістю, який повертає перші п’ять документів, які відповідають запиту користувача.


Для мовної моделі ми будемо використовувати gpt-4o-mini але ви можете використовувати інші моделі, наприклад GPT-4o, залежно від вашого бюджету та потреб.

Потім ми об’єднаємо всі ці компоненти за допомогою мови виразів LangChain (LCEL). Першим компонентом ланцюжка є словник із context і question як ключі. Значення цих ключів надаються ретрівером, відформатованим нашою функцією форматування та RunnablePassthrough() відповідно. Останній клас діє як заповнювач для запиту користувача.


Потім словник передається в підказку нашої системи; підказка передається в LLM, який генерує вихідний клас повідомлення. Клас повідомлення надається синтаксичному аналізатору виведення рядка, який повертає відповідь у вигляді звичайного тексту.

4. Створення інтерфейсу Streamlit

У цьому розділі ми створимо наведений нижче інтерфейс користувача для нашої програми:


Знімок екрана нашого інтерфейсу користувача Streamlit.

Це чистий, мінімальний інтерфейс із двома полями введення: одне для документа, інше для постановки запитань щодо документа. На лівій бічній панелі користувачеві пропонується ввести свій ключ API.


Щоб створити інтерфейс, відкрийте сценарій app.py на найвищому рівні вашого робочого каталогу та вставте наступний код:


 import streamlit as st import os from dotenv import load_dotenv from src.document_processor import process_document from src.rag_chain import create_rag_chain # Load environment variables load_dotenv() st.set_page_config(page_title="RAG Chatbot", page_icon="🤖") st.title("RAG Chatbot") # Initialize session state if "rag_chain" not in st.session_state: st.session_state.rag_chain = None # Sidebar for API key input with st.sidebar: api_key = st.text_input("Enter your OpenAI API Key", type="password") if api_key: os.environ["OPENAI_API_KEY"] = api_key # File uploader uploaded_file = st.file_uploader("Choose a file", type=["pdf", "png", "jpg", "jpeg"]) if uploaded_file is not None: if st.button("Process File"): if api_key: with st.spinner("Processing file..."): # Save the uploaded file temporarily with open(uploaded_file.name, "wb") as f: f.write(uploaded_file.getbuffer()) try: # Process the document chunks = process_document(uploaded_file.name) # Create RAG chain st.session_state.rag_chain = create_rag_chain(chunks) st.success("File processed successfully!") except ValueError as e: st.error(str(e)) finally: # Remove the temporary file os.remove(uploaded_file.name) else: st.error("Please provide your OpenAI API key.") # Query input query = st.text_input("Ask a question about the uploaded document") if st.button("Ask"): if st.session_state.rag_chain and query: with st.spinner("Generating answer..."): result = st.session_state.rag_chain.invoke(query) st.subheader("Answer:") st.write(result) elif not st.session_state.rag_chain: st.error("Please upload and process a file first.") else: st.error("Please enter a question.")


Незважаючи на те, що він містить лише 65 рядків, він реалізує такі функції:

  1. Введення ключа API: дозволяє користувачам безпечно вводити ключ OpenAI API.
  2. Завантаження файлів: підтримує завантаження файлів PDF, PNG, JPG і JPEG.
  3. Обробка документів: обробляє завантажений файл і створює фрагменти тексту.
  4. Створення ланцюжка RAG: будує ланцюжок генерації з доповненим пошуком, використовуючи фрагменти обробленого документа.
  5. Обробка запитів: приймає запитання користувачів щодо завантаженого документа.
  6. Генерація відповідей: використовує ланцюжок RAG для створення відповідей на основі завантаженого документа та запиту користувача.
  7. Обробка помилок: надає відповідні повідомлення про помилки для відсутніх ключів API, необроблених файлів або порожніх запитів.
  8. Відгуки користувачів: відображаються лічильники під час обробки та повідомлення про успіх/помилку, щоб тримати користувача в курсі.
  9. Керування станом: використовує стан сеансу Streamlit для підтримки ланцюга RAG між взаємодіями.

5. Розгортання як чат-бота Streamlit

Залишився лише один крок — розгорнути наш додаток Streamlit. Тут є багато варіантів, але найпростішим є використання Streamlit Cloud, яке є безкоштовним і простим у налаштуванні.


Спочатку відкрийте сценарій .streamlit/config.toml і вставте такі конфігурації:


 [theme] primaryColor = "#F63366" backgroundColor = "#FFFFFF" secondaryBackgroundColor = "#F0F2F6" textColor = "#262730" font = "sans serif"


Це деякі коригування теми, які випливають з особистих уподобань. Потім запишіть файл README.md (ви можете скопіювати його вміст із цього розміщеного файлу на GitHub ).


Нарешті, перейдіть на GitHub.com і створіть нове сховище. Скопіюйте його посилання та поверніться до робочого каталогу:


 $ git init $ git add . $ git commit -m "Initial commit" $ git remote add origin https://github.com/YourUsername/YourRepo.git $ git push --set-upstream origin master


Наведені вище команди ініціалізують Git, створюють початковий комміт і надсилають усе до репозиторію (не забудьте замінити посилання репо своїм власним).


Тепер вам потрібно зареєструвати безкоштовний обліковий запис у Streamlit Cloud . Підключіть свій обліковий запис GitHub і виберіть репозиторій, що містить вашу програму.


Потім налаштуйте параметри програми:

  • Встановіть версію Python (наприклад, 3.9)
  • Встановіть основний шлях до файлу app.py
  • Додайте будь-які необхідні секрети (наприклад OPENAI_API_KEY ) у налаштуваннях програми


Нарешті натисніть «Розгорнути»!


Додаток має запрацювати протягом кількох хвилин. Програму, яку я створив для цього підручника, можна знайти за цим посиланням . Спробуйте!

Система RAG в дії

Висновок

У цьому підручнику розглядається потужне поєднання Retrieval-Augmented Generation (RAG) і Streamlit, яке формує інтерактивну систему відповідей на запитання на основі документів. Він проводить читача через увесь процес, від налаштування середовища й обробки документів до побудови ланцюжка RAG і розгортання зручної веб-програми.


Важливі моменти:

  • RAG для розумнішої (у сенсі зовнішніх знань) мовної моделі
  • Ланцюги RAG можна створювати за допомогою моделей LangChain, OpenAI та сторонніх інтеграцій спільноти.
  • Додаток можна зробити інтерактивним за допомогою Streamlit і розгорнути для загального використання.


Цей проект є основою для більш просунутих програм. Його можна розширити значною мірою, наприклад, об’єднати декілька типів документів, покращити точність пошуку та такі функції, як резюмування документів. І все-таки він насправді служить для демонстрації потенційної потужності цих технологій, як окремо, так і разом.