В последние месяцы OpenAI Chat GPT вызвал много шума, породив новые библиотеки на основе ИИ, предприятия и даже совершенно новые сектора. У него есть много отличных примеров использования, но также есть несколько неприятных откатов, связанных с уверенным утверждением неверной информации. Сегодня я собираюсь пройти обучение по созданию автоматического бота SparkNotes, который будет отвечать на наши вопросы, используя только предоставленный текст, и не будет придумывать то, чего нет в тексте. Мы будем использовать OpenAI и очень крутую библиотеку Python под названием Langchain. Langchain позволяет вам использовать возможности LLM, которые предоставляет OpenAI, с дополнительными преимуществами агентов для выполнения таких задач, как поиск в Интернете или расчет математических уравнений, сложная и расширенная предварительная обработка документов, шаблоны для включения более целенаправленных запросов и цепочки, которые позволяют нам создать конвейер между различными задачами и LLM.

В этом уроке мы создадим автоматического бота SparkNotes на основе Алисы в стране чудес Льюиса Кэрролла. Наш бот сначала прочитает книгу. Затем мы зададим ему вопросы конкретно о книге, на которые он ответит, используя только информацию из текста.

Настраивать

Во-первых, давайте настроим весь наш импорт и установим переменную среды, чтобы она содержала наш ключ OpenAI.

import os
from langchain.llms import OpenAI
from langchain.chains.question_answering import load_qa_chain
from langchain.document_loaders import UnstructuredPDFLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma

os.environ["OPENAI_API_KEY"] = "<YOUR KEY HERE>"

Загрузка данных

Теперь мы будем использовать Langchain PDFLoader для предварительной обработки и загрузки нашего PDF в текст. У Langchain есть куча загрузчиков, чтобы превратить форматированные файлы, такие как PPT и Word, в пригодный для использования текст. (Примечание: загрузка занимает некоторое время, и вам может потребоваться установить несколько библиотек, если вы получите какие-либо ошибки).

loader = UnstructuredPDFLoader("./Alice_in_Wonderland.pdf")
documents = loader.load()

print(f'Loaded {len(documents)} documents')
print(f'Document has {len(documents[0].page_content)} characters')

Как только это запустится, вы должны увидеть, что мы загрузили 1 документ, содержащий около 150 тыс. символов.

Разделите данные

Теперь мы собираемся разбить данные на более мелкие «страницы» по 1000 символов. Причина, по которой мы это делаем, заключается в том, что нам нужно дать OpenAI некоторый контекст, когда мы задаем наш вопрос. Гораздо эффективнее с точки зрения затрат и времени дать OpenAI для чтения 1–2 страницы соответствующей информации, чем заставлять его читать всю книгу каждый раз, когда мы задаем вопрос.

text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)

print(f'You now have {len(texts)} texts')

"Читать"

На этом этапе наш бот получает и индексирует данные. Мы векторизируем каждую страницу, используя эмбеддинги из OpenAI. Векторизация текста преобразует его из строки типа «Привет, как дела» в [0,4, 0, 0,9, …, 0,04]. Мы хотим векторизовать текст в виде массива чисел, потому что это значительно упрощает проверку сходства между текстом нашего запроса и текстом на наших страницах.

embeddings = OpenAIEmbeddings()

db = Chroma.from_documents(texts, embeddings)

Найдите соответствующие страницы

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

query = "what is the rabbit late for?"
docs = db.similarity_search(query)

Ответить на вопросы

Теперь мы можем попросить OpenAI ответить на наш вопрос. Мы используем qa_chain от LangChain (который настроен с помощью шаблона для интерфейса вопросов и ответов). chain_type — это «stuff», что означает, что мы помещаем все документы в контекст. Запускаем цепочку с нашим вопросом и соответствующими страницами.

llm = OpenAI()
chain = load_qa_chain(llm, chain_type="stuff")

chain.run(input_documents=docs, question=query)

Затем мы получаем ответ вроде «Кролик опаздывает к чаю».

Если бы мы спросили что-то не по тексту, например «Кто президент?» бот ответит «я не знаю», потому что шаблон говорит ему отвечать на вопросы только на основе заданного текста.

Следующие шаги

Некоторые интересные следующие шаги могут состоять в том, чтобы хранить эти векторы в Интернете в векторном хранилище, таком как pinecone, чтобы вы могли добавлять больше книг в свой корпус и не приходилось каждый раз перечитывать PDF-файлы. Затем вы можете добавить быстрый пользовательский интерфейс и разместить его на веб-странице для использования людьми. Помимо SparkNotes, возможность читать PDF-документы книг была бы отличной для проверки характера содержания книги. Например, спрашивать, есть ли в книге какие-либо явные описания, прежде чем дать ребенку прочитать ее.