Generazione aumentata dal recupero su documenti Notion tramite LangChain
Questo articolo è stato originariamente pubblicato su The Sequence ed è ripubblicato qui con autorizzazione.
Hai documenti Notion che vuoi chiedere a un modello linguistico di interrogare per te? Costruiamo un’app di base di tipo retrieval augmented generation (RAG) usando LangChain e Milvus. Usiamo LangChain come framework operativo e Milvus come motore di similarità. Puoi trovare il notebook per questo blog su colab.
In questo tutorial esaminiamo quanto segue:
Ripasso del self querying di LangChain
Lavorare con i documenti Notion in LangChain
Acquisizione dei tuoi documenti Notion
Archiviazione dei tuoi documenti Notion
Interrogazione dei tuoi documenti Notion
Riepilogo dell’interrogazione dei documenti Notion con LangChain e Milvus
Ripasso del self querying di LangChain
Di recente abbiamo trattato come usare LangChain per interrogare un database vettoriale, un’introduzione a ciò che LangChain definisce “self-querying”. Dietro le quinte, la funzionalità di self-querying in LangChain sta costruendo un’architettura RAG di base come quella mostrata di seguito.
Lavorare con i documenti Notion in LangChain
Dividerò questa parte in tre passaggi: acquisizione, archiviazione e interrogazione. L’acquisizione riguarda il recupero dei tuoi documenti Notion e il caricamento dei contenuti in memoria. L’archiviazione riguarda l’avvio di un database vettoriale (Milvus), la vettorializzazione dei documenti, il loro inserimento nel database vettoriale, mentre l’interrogazione riguarda il porre una domanda sui tuoi documenti Notion.
Acquisizione dei tuoi documenti Notion
Usiamo NotionDirectoryLoader di LangChain per caricare i documenti in memoria. Forniamo il percorso ai nostri documenti e chiamiamo la funzione load per ottenerli. Una volta caricati i documenti in memoria, prendiamo il file markdown, in questo caso solo uno.
Successivamente, usiamo lo splitter di testo per intestazioni markdown di LangChain. Gli forniamo una lista di separatori su cui suddividere e poi passiamo il md_file nominato in precedenza per ottenere le nostre suddivisioni. Quando definisci la tua lista headers_to_split_on, assicurati di usare le intestazioni che utilizzi nel tuo documento Notion, non solo gli esempi che ho fornito.
# 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)
Nel codice qui sotto, eseguiamo ed esaminiamo le nostre suddivisioni. Usiamo RecursiveCharacterTextSplitter di LangChain, che testa alcuni caratteri diversi su cui suddividere. I quattro caratteri predefiniti da controllare sono una nuova riga, una doppia nuova riga, uno spazio o nessuno spazio. Puoi anche scegliere di passarne di tuoi con un parametro separators, che questa volta non abbiamo usato.
I due iperparametri essenziali da definire quando suddividi in blocchi il tuo documento Notion sono la dimensione del blocco e la sovrapposizione tra blocchi. Per questo esempio, usiamo una dimensione del blocco di 64 e una sovrapposizione di 8. In futuro tratteremo il test di questi valori e come trovare buoni valori. Una volta definito lo splitter di testo, chiamiamo le sue funzioni split_documents per ottenere tutte le nostre suddivisioni di 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
L’immagine qui sotto mostra alcuni oggetti Document dalla suddivisione precedente. Nota che include il contenuto della pagina e i metadati che includono la sezione da cui il contenuto viene estratto.
Archiviare i tuoi documenti Notion
Con tutti i documenti caricati e suddivisi, è il momento di archiviare quelle suddivisioni. Per prima cosa, avviamo il nostro database vettoriale direttamente nel nostro notebook usando Milvus Lite. Dobbiamo anche ottenere i moduli LangChain necessari: Milvus e OpenAIEmbeddings.
Dopo gli import e l’avvio del database vettoriale, usiamo il modulo Milvus di LangChain per creare una collection dai nostri documenti. Dobbiamo passargli l’elenco dei documenti, gli embeddings da usare, i parametri di connessione e (facoltativamente) un nome di collection.
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")
Interrogare i tuoi documenti Notion
Tutto è configurato e pronto per le query. Per questa sezione, abbiamo bisogno di altri tre import da LangChain: OpenAI per accedere a GPT, il SelfQueryRetriever per creare il nostro RAG di base, e l’oggetto “Attribute info” per passare i metadati. Per iniziare, definiamo alcuni metadati. Per questo esempio, solo le sezioni che abbiamo usato finora.
Forniamo anche al self-query retriever una descrizione dei documenti. In questo caso, semplicemente “sezioni principali del documento”. Subito prima di istanziare il nostro self-query retriever, impostiamo una versione di GPT con temperatura 0 in una variabile llm. Con l’LLM, il database vettoriale, la descrizione del documento e i campi dei metadati pronti, definiamo il 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?")
Il mio esempio scelto è “Cosa rende un ingegnere distinguished?” Dalla risposta nell’immagine qui sotto, possiamo vedere i chunk più semanticamente simili restituiti. Come possiamo vedere, il fatto che siano le risposte più semanticamente simili non significa che siano quelle giuste. In articoli futuri, tratteremo come sperimentare con il chunking e altre tecniche per migliorare le nostre risposte.
Riepilogo dell’interrogazione dei documenti Notion in LangChain
In questo tutorial, abbiamo trattato come caricare e analizzare un documento Notion in sezioni da interrogare in un’architettura RAG di base. Abbiamo usato LangChain come framework di orchestrazione e Milvus come nostro database vettoriale. LangChain mette insieme i pezzi e Milvus guida la ricerca di similarità.
Per portare questo tutorial oltre, ci sono molte cose che possiamo testare. Esempi di due iperparametri da controllare sono la dimensione dei chunk e la dimensione della sovrapposizione tra chunk. Possiamo usarli per ottimizzare le nostre risposte e il loro aspetto. Oltre all’ottimizzazione, dobbiamo anche valutare le risposte.
Nei tutorial futuri, esamineremo diverse strategie di chunking. Non solo, ma approfondiremo anche embedding, strategie di suddivisione e valutazione.
Continua a leggere

Why Context Engineering Is Becoming the Full Stack of AI Agents
Discover how context engineering unifies prompts, RAG, and tools to build smarter, production-ready AI agents powered by Milvus.

Vector Databases vs. Time Series Databases
Use a vector database for similarity search and semantic relationships; use a time series database for tracking value changes over time.

Why Deepseek is Waking up AI Giants Like OpenAI And Why You Should Care
Discover how DeepSeek R1's open-source AI model with superior reasoning capabilities and lower costs is disrupting the AI landscape and challenging tech giants like OpenAI.



