![Search icon](https://hackernoon.imgix.net/search-new.png?w=19&h=19)
Les grands modèles linguistiques d'aujourd'hui ont accès à une quantité toujours croissante d'informations. Cependant, il reste une vaste réserve de données privées que ces modèles n'exploitent pas. C'est pourquoi l'une des applications les plus populaires des LLM dans les environnements d'entreprise est la génération augmentée de récupération (RAG en abrégé).
Vous apprendrez à utiliser LangChain, le framework très populaire pour la création de systèmes RAG, pour créer un système RAG simple. À la fin du tutoriel, nous aurons un chatbot (avec une interface Streamlit et tout) qui se frayera un chemin à travers des données privées pour donner des réponses à des questions.
Pour clarifier ce qu’est RAG, considérons un exemple simple.
Chandler, un étudiant de première année à l'université, envisage de sécher quelques cours mais veut s'assurer qu'il ne viole pas la politique d'assiduité de l'université. Comme pour tout de nos jours, il pose la question à ChatGPT .
Bien sûr, ChatGPT ne peut pas répondre à cette question. Le chatbot n'est pas idiot, il n'a simplement pas accès aux documents universitaires de Chandler. Chandler trouve donc lui-même le document de politique et découvre qu'il s'agit d'une lecture longue et technique qu'il ne veut pas parcourir. Au lieu de cela, il donne l'intégralité du document à ChatGPT et repose la question. Cette fois, il obtient sa réponse.
Il s'agit d'un cas particulier de génération augmentée par récupération. La réponse (génération) du modèle de langage est augmentée (enrichie) par le contexte récupéré à partir d'une source ne faisant pas partie de son apprentissage d'origine.
Une version évolutive d’un système RAG serait capable de répondre à n’importe quelle question d’un étudiant en recherchant lui-même les documents universitaires, en trouvant ceux qui sont pertinents et en récupérant les morceaux de texte qui contiennent très probablement la réponse.
D'une manière générale, dans un système RAG, vous récupérez des informations à partir d'une source de données privée et les alimentez à un modèle de langage, permettant au modèle de donner une réponse contextuellement pertinente.
Un tel système, même s'il semble simple, comporterait de nombreux composants mobiles. Avant d'en construire un nous-mêmes, nous devons examiner ce qu'ils sont et comment ils fonctionnent ensemble.
Le premier composant est un document ou un ensemble de documents. Selon le type de système RAG que nous construisons, les documents peuvent être des fichiers texte, des PDF, des pages Web (RAG sur données non structurées) ou des bases de données graphiques, SQL ou NoSQL (RAG sur données structurées). Ils sont utilisés pour ingérer différents types de données dans le système.
LangChain implémente des centaines de classes appelées chargeurs de documents pour lire des données à partir de diverses sources de documents telles que les PDF, Slack, Notion, Google Drive, etc.
Chaque classe de chargeur de documents est unique, mais elles partagent toutes la même méthode .load()
. Par exemple, voici comment charger un document PDF et une page Web dans 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()
La classe PyPDFLoader gère les fichiers PDF à l'aide du package PyPDF2 sous le capot, tandis que WebBaseLoader récupère le contenu de la page Web donnée.
pdf_docs
contient quatre objets de document, un pour chaque page :
>>> len(pdf_docs) 4
Alors que web_docs
n'en contiennent qu'un :
>>> 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
Ces objets de document sont ensuite transmis à des modèles d'intégration pour comprendre la signification sémantique derrière leur texte.
Pour plus de détails sur d'autres types de chargeurs de documents, LangChain propose un
Une fois vos documents chargés, il est essentiel de les décomposer en morceaux de texte plus petits et plus faciles à gérer. Voici les principales raisons :
LangChain propose de nombreux types de séparateurs de texte dans son package langchain_text_splitters, et ils diffèrent en fonction du type de document.
Voici comment utiliser RecursiveCharacterTextSplitter
pour diviser du texte brut en fonction d'une liste de séparateurs et de la taille des blocs :
!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}")
Sortir:
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.
Ce séparateur est polyvalent et fonctionne bien pour de nombreux cas d'utilisation. Il crée chaque bloc avec un nombre de caractères aussi proche que possible chunk_size
. Il peut basculer de manière récursive entre les séparateurs à diviser pour conserver le nombre de caractères.
Dans l'exemple ci-dessus, notre séparateur essaie d'abord de se diviser sur les nouvelles lignes, puis sur les espaces simples, et enfin entre les caractères pour atteindre la taille de bloc souhaitée.
Il existe de nombreux autres séparateurs dans le package langchain_text_splitters
. En voici quelques-uns :
HTMLSectionSplitter
PythonCodeTexSplitter
RecursiveJsonSplitter
et ainsi de suite. Certains séparateurs créent des morceaux sémantiquement significatifs en utilisant un modèle de transformateur sous le capot.
Le bon séparateur de texte a un impact significatif sur les performances d'un système RAG.
Pour plus de détails sur l'utilisation des séparateurs de texte, consultez les
Une fois les documents divisés en texte, ils doivent être codés dans leur représentation numérique, ce qui est une exigence pour tous les modèles de calcul travaillant avec des données textuelles.
Dans le contexte de RAG, ce codage est appelé incorporation et est réalisé par des modèles d'incorporation . Ils créent une représentation vectorielle d'un morceau de texte qui capture sa signification sémantique. En présentant le texte de cette manière, vous pouvez effectuer des opérations mathématiques sur celui-ci, comme rechercher dans notre base de données de documents le texte le plus similaire en termes de signification ou trouver une réponse à une requête utilisateur.
LangChain prend en charge tous les principaux fournisseurs de modèles d'intégration, tels que OpenAI, Cohere, HuggingFace, etc. Ils sont implémentés en tant que classes Embedding
et fournissent deux méthodes : une pour l'intégration de documents et une pour l'intégration de requêtes (invites).
Voici un exemple de code qui intègre les morceaux de texte que nous avons créés dans la section précédente à l'aide d'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]}")
Sortir:
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]
La sortie ci-dessus montre que le modèle d’intégration crée un vecteur de 1536 dimensions pour tous les blocs de nos documents.
Pour intégrer une seule requête, vous pouvez utiliser la méthode 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]}")
Sortir:
Shape of the query embedding: 1536 First few values of the query embedding: [-0.012426204979419708, -0.016619959846138954, 0.007880032062530518, -0.0170428603887558, 0.011404196731746197]
Dans les applications RAG à grande échelle, où vous pouvez avoir des gigaoctets de documents, vous vous retrouverez avec des milliards de morceaux de texte et donc de vecteurs. Ils ne servent à rien si vous ne pouvez pas les stocker de manière fiable.
C'est pourquoi les bases de données ou magasins de vecteurs sont à la mode aujourd'hui. En plus de stocker vos intégrations, les bases de données vectorielles se chargent d'effectuer la recherche de vecteurs pour vous. Ces bases de données sont optimisées pour trouver rapidement les vecteurs les plus similaires lorsqu'on leur donne un vecteur de requête, ce qui est essentiel pour récupérer des informations pertinentes dans les systèmes RAG.
Voici un extrait de code qui intègre le contenu d'une page Web et stocke les vecteurs dans une base de données vectorielles Chroma ( Chroma est une solution de base de données vectorielle open source qui s'exécute entièrement sur votre machine) :
!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)
Tout d'abord, nous chargeons la page avec WebBaseLoader
et créons nos blocs. Ensuite, nous pouvons directement transmettre les blocs à la méthode from_documents
de Chroma
avec notre modèle d'intégration choisi :
from langchain_openai import OpenAIEmbeddings from langchain_chroma import Chroma db = Chroma.from_documents(chunks, OpenAIEmbeddings())
Tous les objets de base de données vectorielles dans LangChain exposent une méthode similarity_search
qui accepte une chaîne de requête :
query = "What is indexing in the context of RAG?" docs = db.similarity_search(query) print(docs[1].page_content)
Sortir:
If you are interested for RAG over structured data, check out our tutorial on doing question/answering over SQL data.ConceptsA 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:IndexingLoad: 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
Le résultat de similarity_search
est une liste de documents qui contiennent très probablement les informations que nous demandons dans la requête.
Pour plus de détails sur la façon d'utiliser les magasins vectoriels, consultez les
Bien que tous les magasins de vecteurs prennent en charge la récupération sous forme de recherche de similarité, LangChain implémente une interface Retriever
dédiée qui renvoie les documents à partir d'une requête non structurée. Un récupérateur n'a besoin que de renvoyer ou de récupérer des documents, et non de les stocker.
Voici comment vous pouvez convertir n'importe quel magasin de vecteurs en récupérateur dans 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
Il est possible de limiter le nombre de documents pertinents au top k en utilisant 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
Vous pouvez transmettre d'autres paramètres liés à la recherche à search_kwargs. Pour en savoir plus sur l'utilisation des récupérateurs, consultez
Maintenant que nous avons couvert les composants clés d'un système RAG, nous allons en construire un nous-mêmes. Je vais vous guider pas à pas dans la mise en œuvre d'un chatbot RAG conçu spécifiquement pour la documentation de code et les tutoriels. Vous le trouverez particulièrement utile lorsque vous aurez besoin d'une assistance au codage de l'IA pour de nouveaux frameworks ou de nouvelles fonctionnalités de frameworks existants qui ne font pas encore partie de la base de connaissances des LLM d'aujourd'hui.
Tout d’abord, remplissez votre répertoire de travail avec la structure de projet suivante :
rag-chatbot/ ├── .gitignore ├── requirements.txt ├── README.md ├── app.py ├── src/ │ ├── __init__.py │ ├── document_processor.py │ └── rag_chain.py └── .streamlit/ └── config.toml
Voici les commandes :
$ 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}
Dans cette étape, vous créez d’abord un nouvel environnement Conda et l’activez :
$ conda create -n rag_tutorial python=3.9 -y $ conda activate rag_tutorial
Ensuite, ouvrez le fichier requirements.txt
et collez les dépendances suivantes :
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
et installez-les :
$ pip install -r requirements.txt
Créez également un fichier .gitignore
pour masquer les fichiers de l'indexation git :
# .gitignore venv/ __pycache__/ .env *.pdf *.png *.jpg *.jpeg *.gif *.svg
Ensuite, ouvrez le fichier src/document_processor.py
et collez les extraits de code suivants.
Les importations nécessaires :
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
Explication des importations :
RecursiveCharacterTextSplitter
: divise le texte en morceaux plus petits de manière récursive.Language
: Énumération permettant de spécifier les langages de programmation dans le fractionnement de texte.PyPDFLoader
: Charge et extrait du texte à partir de fichiers PDF.extract_from_images_with_rapidocr
: fonction OCR pour extraire du texte à partir d'images.Document
: représente un document avec du contenu et des métadonnées.logging
: fournit une fonctionnalité de journalisation pour le débogage et les informations.
Ensuite, une fonction pour traiter les 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)
Voici comment cela fonctionne :
PyPDFLoader
. La fonction gère les cas où un PDF peut contenir un mélange de texte et de pages numérisées, garantissant que seules les pages textuelles sont traitées ultérieurement. Ceci est crucial pour les tâches d'analyse de texte où les pages numérisées sans OCR seraient inutilisables. Nous définirons la fonction split_documents
plus tard.
Ensuite, nous écrivons une fonction pour récupérer des informations à partir d’images (captures d’écran d’extraits de code et/ou de pages Web) :
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)
Cette fonction traite un fichier image en extrayant du texte à l'aide de la reconnaissance optique de caractères (OCR). Elle lit le fichier image, le convertit en octets, puis utilise la bibliothèque RapidOCR pour extraire le texte de l'image. Le texte extrait est ensuite enveloppé dans un objet Document avec des métadonnées contenant le chemin du fichier source. Enfin, la fonction divise le document en morceaux plus petits à l'aide de la fonction split_documents
, que nous définissons ensuite :
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)
La fonction utilise la classe RecursiveCharacterTextSplitter avec la syntaxe Python pour diviser le texte en morceaux de 1000 caractères et 200 caractères se chevauchant.
Notre fonction finale combine les fonctions d'analyse PDF et d'image en une seule :
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}")
Cette fonction finale sera utilisée par l'interface utilisateur Streamlit pour créer, intégrer et stocker des morceaux de documents fournis et les transmettre au composant RAG de notre système.
Maintenant, ouvrez le fichier src/rag_chain.py
et collez les extraits de code suivants.
Tout d’abord, importez les modules nécessaires :
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")
Voici une explication des importations :
• os
: interactions avec le système d'exploitation • dotenv
: charger les variables d'environnement • composants langchain
:
PromptTemplate
: création d'invite personnaliséeFAISS
: Un magasin vectoriel léger pour les documentsStrOutputParser
: Conversion d'objets de message LLM en sorties de chaîneRunnablePassthrough
: Créer des chaînes composablesChatOpenAI
, OpenAIEmbeddings
: interactions du modèle OpenAI
Ensuite, nous créons notre invite pour le système 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)
L'invite du système RAG est l'un des facteurs critiques de son succès. Notre version est simple mais fera l'affaire la plupart du temps. En pratique, vous passerez beaucoup de temps à itérer et à améliorer l'invite.
Si vous le remarquez, nous utilisons une classe PromptTemplate
pour construire l'invite. Cette construction nous permet d'ingérer dynamiquement le contexte récupéré à partir des documents et de la requête de l'utilisateur dans une invite finale.
En parlant de documents, nous avons besoin d'une fonction pour les formater avant qu'ils ne soient transmis comme contexte dans l'invite du système :
def format_docs(docs): return "\n\n".join(doc.page_content for doc in docs)
Il s'agit d'une fonction simple qui concatène le contenu de la page des documents récupérés.
Enfin, nous créons une fonction qui va développer notre chaîne 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
La fonction accepte des morceaux de documents, qui seront fournis par la fonction process_document
dans le script document_processor.py
.
La fonction commence par définir le modèle d'intégration et par stocker les documents dans un magasin de vecteurs FAISS. Elle est ensuite convertie en interface de récupération avec recherche de similarité qui renvoie les cinq premiers documents correspondant à la requête de l'utilisateur.
Pour le modèle de langage, nous utiliserons gpt-4o-mini
mais vous pouvez utiliser d'autres modèles comme GPT-4o en fonction de votre budget et de vos besoins.
Ensuite, nous allons rassembler tous ces composants à l'aide du LangChain Expression Language (LCEL). Le premier composant de la chaîne est un dictionnaire avec context
et question
comme clés. Les valeurs de ces clés sont fournies par le récupérateur formaté par notre fonction de formatage et par RunnablePassthrough()
, respectivement. Cette dernière classe agit comme un espace réservé pour la requête de l'utilisateur.
Le dictionnaire est ensuite transmis à notre invite système ; l'invite est transmise au LLM, qui génère une classe de message de sortie. La classe de message est transmise à un analyseur de sortie de chaîne qui renvoie une réponse en texte brut.
Dans cette section, nous allons créer l'interface utilisateur ci-dessous pour notre application :
Il s'agit d'une interface épurée et minimaliste avec deux champs de saisie : l'un pour le document, l'autre pour poser des questions sur le document. Dans la barre latérale gauche, l'utilisateur est invité à saisir sa clé API.
Pour créer l'interface, ouvrez le script app.py
au niveau le plus élevé de votre répertoire de travail et collez le code suivant :
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.")
Bien qu'il ne fasse que 65 lignes, il implémente les fonctionnalités suivantes :
Il ne reste plus qu'une étape : déployer notre application Streamlit. Il existe de nombreuses options, mais la plus simple est d'utiliser Streamlit Cloud, qui est gratuit et facile à configurer.
Tout d’abord, ouvrez le script .streamlit/config.toml
et collez les configurations suivantes :
[theme] primaryColor = "#F63366" backgroundColor = "#FFFFFF" secondaryBackgroundColor = "#F0F2F6" textColor = "#262730" font = "sans serif"
Voici quelques ajustements de thème qui découlent de préférences personnelles. Ensuite, rédigez le fichier README.md (vous pouvez copier son contenu à partir de ce fichier hébergé sur GitHub ).
Enfin, allez sur GitHub.com et créez un nouveau dépôt. Copiez son lien et revenez à votre répertoire de travail :
$ 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
Les commandes ci-dessus initialisent Git, créent un commit initial et poussent le tout vers le référentiel (n'oubliez pas de remplacer le lien du référentiel par le vôtre).
Vous devez maintenant créer un compte gratuit sur Streamlit Cloud . Connectez votre compte GitHub et sélectionnez le référentiel contenant votre application.
Ensuite, configurez les paramètres de l’application :
app.py
OPENAI_API_KEY
) dans les paramètres de l'application
Enfin, cliquez sur « Déployer » !
L'application devrait être opérationnelle en quelques minutes. L'application que j'ai créée pour ce tutoriel est disponible sur ce lien . Essayez-la !
Ce didacticiel présente le puissant mélange de génération augmentée de récupération (RAG) et de Streamlit qui forme un système interactif de questions-réponses basé sur des documents. Il guide le lecteur tout au long du processus, de la configuration d'un environnement et du traitement des documents à la création d'une chaîne RAG et au déploiement d'une application Web conviviale.
Les points importants incluent :
Ce projet constitue la base d'applications plus avancées. Il peut être étendu de manière significative, par exemple en intégrant plusieurs types de documents, en améliorant la précision de la recherche et en proposant des fonctionnalités telles que la synthèse de documents. Et pourtant, il sert en réalité à démontrer la puissance potentielle de ces technologies, individuellement ou combinées.