Генерация с дополненным извлечением на документах Notion через LangChain
Эта статья была изначально опубликована в The Sequence и перепечатана здесь с разрешения.
У вас есть документы Notion, по которым вы хотите попросить языковую модель выполнить запрос? Давайте создадим базовое приложение типа retrieval augmented generation (RAG) с использованием LangChain и Milvus. Мы используем LangChain в качестве операционного фреймворка, а Milvus — как движок поиска по сходству. Ноутбук для этого блога можно найти на colab.
В этом руководстве мы рассмотрим следующее:
Обзор Self Querying в LangChain
Работа с документами Notion в LangChain
Загрузка ваших документов Notion
Хранение ваших документов Notion
Выполнение запросов к вашим документам Notion
Краткое изложение выполнения запросов к документам Notion с LangChain и Milvus
Обзор self querying в LangChain
Недавно мы рассмотрели как использовать LangChain для выполнения запросов к векторной базе данных, введение в то, что LangChain называет «self-querying». За кулисами функциональность self-querying в LangChain строит базовую архитектуру RAG, подобную показанной ниже.
Работа с документами Notion в LangChain
Я разделю это на три шага: загрузка, хранение и выполнение запросов. Загрузка охватывает получение ваших документов Notion и загрузку их содержимого в память. Хранение охватывает запуск векторной базы данных (Milvus), векторизацию документов, помещение их в векторную базу данных, а выполнение запросов охватывает постановку вопроса о ваших документах Notion.
Загрузка ваших документов Notion
Мы используем NotionDirectoryLoader из LangChain, чтобы загрузить документы в память. Мы указываем путь к нашим документам и вызываем функцию load, чтобы получить их. После того как документы загружены в память, мы берем markdown-файл, в данном случае всего один.
Затем мы используем разделитель текста по заголовкам markdown из LangChain. Мы передаем ему список разделителей, по которым нужно разбивать, а затем передаем ранее названный md_file, чтобы получить наши фрагменты. Когда вы определяете свой список headers_to_split_on, убедитесь, что используете заголовки, которые есть в вашем документе Notion, а не только примеры, которые я привел.
# Load Notion page as a markdownfile file
from langchain.document_loaders import NotionDirectoryLoader
path='./notion_docs'
loader = NotionDirectoryLoader(path)
docs = loader.load()
md_file=docs[0].page_content
# Let's create groups based on the section headers in our page
from langchain.text_splitter import MarkdownHeaderTextSplitter
headers_to_split_on = [
("##", "Section"),
]
markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
md_header_splits = markdown_splitter.split_text(md_file)
В коде ниже мы выполняем и изучаем наши разбиения. Мы используем RecursiveCharacterTextSplitter из LangChain, который проверяет несколько разных символов для разбиения. Четыре символа по умолчанию для проверки — это новая строка, двойная новая строка, пробел или отсутствие пробела. Вы также можете передать свои собственные с помощью параметра separators, который в этот раз мы не использовали.
Два ключевых гиперпараметра, которые нужно определить при разбиении вашего документа Notion на фрагменты, — это размер фрагмента и перекрытие фрагментов. В этом примере мы используем размер фрагмента 64 и перекрытие 8. В будущем мы рассмотрим тестирование этих значений и поиск хороших значений. После того как мы определим разделитель текста, мы вызываем его функции split_documents, чтобы получить все наши разбиения Document.
# Define our text splitter
from langchain.text_splitter import RecursiveCharacterTextSplitter
chunk_size = 64
chunk_overlap = 8
text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
all_splits = text_splitter.split_documents(md_header_splits)
all_splits
На изображении ниже показаны некоторые объекты Document из приведенного выше разбиения. Обратите внимание, что оно включает содержимое страницы и метаданные, которые включают раздел, из которого взято содержимое.
Хранение ваших документов Notion
Когда все документы загружены и разбиты, пришло время сохранить эти фрагменты. Сначала мы запускаем нашу векторную базу данных прямо в нашем notebook с помощью Milvus Lite. Нам также нужно получить необходимые модули LangChain — Milvus и OpenAIEmbeddings.
После импортов и запуска векторной базы данных мы используем модуль Milvus в LangChain, чтобы создать коллекцию из наших документов. Нам нужно передать ему список документов, используемые embeddings, параметры подключения и (необязательно) имя коллекции.
from milvus import default_server
default_server.start()
from langchain.vectorstores import Milvus
from langchain.embeddings import OpenAIEmbeddings
vectordb = Milvus.from_documents(documents=all_splits,
embedding=OpenAIEmbeddings(),
connection_args={"host": "127.0.0.1", "port": default_server.listen_port},
collection_name="EngineeringNotionDoc")
Запросы к вашим документам Notion
Все настроено и готово для запросов. Для этого раздела нам нужны еще три импорта из LangChain — OpenAI для доступа к GPT, SelfQueryRetriever для создания нашего базового RAG и объект “Attribute info” для передачи метаданных. Чтобы начать, мы определяем некоторые метаданные. Для этого примера — только разделы, которые мы использовали до сих пор.
Мы также даем self-query retriever описание документов. В данном случае просто “основные разделы документа”. Непосредственно перед тем, как создать экземпляр нашего self-query retriever, мы задаем версию GPT с температурой 0 в переменную llm. Когда LLM, векторная база данных, описание документа и поля метаданных готовы, мы определяем self-query retriever.
from langchain.llms import OpenAI
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo
metadata_fields_info = [
AttributeInfo(
name="Section",
description="Part of the document that the text comes from",
type="string or list[string]"
),
]
document_content_description = "Major sections of the document"
llm = OpenAI(temperature=0)
retriever = SelfQueryRetriever.from_llm(llm, vectordb, document_content_description, metadata_fields_info, verbose=True)
retriever.get_relevant_documents("What makes a distinguished engineer?")
Выбранный мной пример — “Что делает инженера выдающимся?” Из ответа на изображении ниже мы можем увидеть возвращенные наиболее семантически похожие фрагменты. Как мы видим, то, что они являются наиболее семантически похожими ответами, не означает, что они правильные. В будущих материалах мы рассмотрим, как экспериментировать с chunking и другими техниками для улучшения наших ответов.
Краткое изложение запросов к документам Notion в LangChain
В этом руководстве мы рассмотрели, как загрузить и разобрать документ Notion на разделы для запросов в базовой архитектуре RAG. Мы использовали LangChain как фреймворк оркестрации и Milvus как нашу векторную базу данных. LangChain соединяет компоненты вместе, а Milvus выполняет поиск по сходству.
Чтобы развить это руководство дальше, есть много вещей, которые мы можем протестировать. Примеры двух гиперпараметров для проверки — размер фрагмента и размер перекрытия между фрагментами. Мы можем использовать их для настройки наших ответов и того, как они выглядят. Помимо настройки, нам также нужно оценивать ответы.
В будущих руководствах мы рассмотрим различные стратегии разбиения на фрагменты. Более того, мы также глубже изучим эмбеддинги, стратегии разделения и оценку.
Читать далее

Introducing Zilliz Cloud Global Cluster: Region-Level Resilience for Mission-Critical AI
Zilliz Cloud Global Cluster delivers multi-region resilience, automatic failover, and fast global AI search with built-in security and compliance.

Introducing Zilliz MCP Server: Natural Language Access to Your Vector Database
Developers can easily manage and query vector databases with natural language via Zilliz MCP Server in AI-native environments.

1 Table = 1000 Words? Foundation Models for Tabular Data
TableGPT2 automates tabular data insights, overcoming schema variability, while Milvus accelerates vector search for efficient, scalable decision-making.



