ຮູບແບບພາສາຂະຫນາດໃຫຍ່ຂອງມື້ນີ້ສາມາດເຂົ້າເຖິງຂໍ້ມູນທີ່ມີການຂະຫຍາຍຕົວຢ່າງຕໍ່ເນື່ອງ. ຢ່າງໃດກໍຕາມ, ຍັງມີຂໍ້ມູນສ່ວນຕົວອັນໃຫຍ່ຫຼວງທີ່ຕົວແບບເຫຼົ່ານີ້ບໍ່ໄດ້ແຕະໃສ່. ນີ້ແມ່ນເຫດຜົນທີ່ວ່າຫນຶ່ງໃນຄໍາຮ້ອງສະຫມັກທີ່ນິຍົມຫຼາຍທີ່ສຸດຂອງ LLMs ໃນການຕັ້ງຄ່າວິສາຫະກິດແມ່ນການຜະລິດທີ່ເພີ່ມຂຶ້ນ - RAG ສໍາລັບສັ້ນ. ທີ່
ທ່ານຈະໄດ້ຮຽນຮູ້ວິທີການນໍາໃຊ້ LangChain, ກອບທີ່ນິຍົມຢ່າງຫຼວງຫຼາຍສໍາລັບການກໍ່ສ້າງລະບົບ RAG, ເພື່ອສ້າງລະບົບ RAG ງ່າຍດາຍ. ໃນຕອນທ້າຍຂອງການສອນ, ພວກເຮົາຈະມີ chatbot (ມີການໂຕ້ຕອບ Streamlit ແລະທັງຫມົດ) ທີ່ຈະ RAG ວິທີການຂອງຕົນໂດຍຜ່ານຂໍ້ມູນສ່ວນຕົວບາງຢ່າງເພື່ອໃຫ້ຄໍາຕອບຕໍ່ຄໍາຖາມ.
ເພື່ອຊີ້ແຈງວ່າ RAG ແມ່ນຫຍັງ, ໃຫ້ພິຈາລະນາຕົວຢ່າງງ່າຍໆ.
ນັກສຶກສາວິທະຍາໄລປີທໍາອິດ, Chandler, ກໍາລັງພິຈາລະນາຂ້າມຫ້ອງຮຽນຈໍານວນຫນ້ອຍຫນຶ່ງແຕ່ຕ້ອງການໃຫ້ແນ່ໃຈວ່າລາວບໍ່ໄດ້ລະເມີດນະໂຍບາຍການເຂົ້າມະຫາວິທະຍາໄລ. ເຊັ່ນດຽວກັນກັບທຸກມື້ນີ້, ລາວຖາມ ChatGPT ຄໍາຖາມ.
ແນ່ນອນ, ChatGPT ບໍ່ສາມາດຕອບມັນໄດ້. chatbot ບໍ່ແມ່ນຄົນໂງ່ - ມັນພຽງແຕ່ບໍ່ມີການເຂົ້າເຖິງເອກະສານວິທະຍາໄລຂອງ Chandler. ດັ່ງນັ້ນ, Chandler ຊອກຫາເອກະສານນະໂຍບາຍຕົນເອງແລະຄົ້ນພົບວ່າມັນເປັນການອ່ານທາງວິຊາການທີ່ຍາວນານ, ລາວບໍ່ຕ້ອງການທີ່ຈະຍ່າງຜ່ານ. ແທນທີ່ຈະ, ລາວໃຫ້ເອກະສານທັງຫມົດໃຫ້ກັບ ChatGPT ແລະຖາມຄໍາຖາມອີກເທື່ອຫນຶ່ງ. ເວລານີ້, ລາວໄດ້ຮັບຄໍາຕອບຂອງລາວ.
ນີ້ແມ່ນກໍລະນີສ່ວນບຸກຄົນຂອງການຜະລິດທີ່ເພີ່ມຂຶ້ນ. ຄໍາຕອບຂອງຕົວແບບພາສາ (ຮຸ່ນ) ແມ່ນການເພີ່ມ (ເສີມ) ໂດຍບໍລິບົດທີ່ດຶງມາຈາກແຫຼ່ງທີ່ບໍ່ແມ່ນສ່ວນຫນຶ່ງຂອງການຝຶກອົບຮົມຕົ້ນສະບັບຂອງມັນ.
ຮຸ່ນທີ່ສາມາດຂະຫຍາຍໄດ້ຂອງລະບົບ RAG ຈະສາມາດຕອບຄໍາຖາມຂອງນັກຮຽນໄດ້ໂດຍການຄົ້ນຫາເອກະສານມະຫາວິທະຍາໄລຕົວເອງ, ຊອກຫາສິ່ງທີ່ກ່ຽວຂ້ອງ, ແລະການດຶງເອົາຂໍ້ຄວາມທີ່ມັກຈະມີຄໍາຕອບ.
ໂດຍທົ່ວໄປແລ້ວ, ໃນລະບົບ RAG, ທ່ານເອົາຂໍ້ມູນຈາກແຫຼ່ງຂໍ້ມູນສ່ວນຕົວແລະໃຫ້ມັນເຂົ້າໄປໃນຕົວແບບພາສາ, ເຮັດໃຫ້ຕົວແບບເພື່ອໃຫ້ຄໍາຕອບທີ່ກ່ຽວຂ້ອງໃນສະພາບການ.
ລະບົບດັ່ງກ່າວ, ເຖິງວ່າຈະມີສຽງກົງໄປກົງມາ, ຈະມີອົງປະກອບເຄື່ອນທີ່ຫຼາຍ. ກ່ອນທີ່ຈະສ້າງຕົວເຮົາເອງ, ພວກເຮົາຈໍາເປັນຕ້ອງໄດ້ທົບທວນຄືນສິ່ງທີ່ພວກເຂົາເປັນແລະວິທີການທີ່ເຂົາເຈົ້າຫຼິ້ນຮ່ວມກັນ.
ອົງປະກອບທໍາອິດແມ່ນເອກະສານຫຼືການເກັບກໍາເອກະສານ. ອີງຕາມປະເພດຂອງລະບົບ RAG ທີ່ພວກເຮົາກໍາລັງສ້າງ, ເອກະສານສາມາດເປັນໄຟລ໌ຂໍ້ຄວາມ, PDFs, ຫນ້າເວັບ (RAG over unstructured data) ຫຼື graph, SQL, ຫຼື NoSQL databases (RAG over structured data). ພວກມັນຖືກນໍາໃຊ້ເພື່ອເອົາຂໍ້ມູນປະເພດຕ່າງໆເຂົ້າໄປໃນລະບົບ.
LangChain ປະຕິບັດຫຼາຍຮ້ອຍຊັ້ນຮຽນທີ່ເອີ້ນວ່າ ຕົວໂຫລດເອກະສານ ເພື່ອອ່ານຂໍ້ມູນຈາກແຫຼ່ງເອກະສານຕ່າງໆເຊັ່ນ PDFs, Slack, Notion, Google Drive, ແລະອື່ນໆ.
ແຕ່ລະຫ້ອງຮຽນ loader ເອກະສານແມ່ນເປັນເອກະລັກ, ແຕ່ພວກເຂົາທັງຫມົດແບ່ງປັນວິທີການ .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
ຕໍ່ມາວັດຖຸເອກະສານເຫຼົ່ານີ້ຖືກມອບໃຫ້ກັບຕົວແບບຝັງຕົວເພື່ອເຂົ້າໃຈຄວາມໝາຍທາງຄວາມໝາຍທີ່ຢູ່ເບື້ອງຫຼັງຂໍ້ຄວາມ.
ສໍາລັບການສະເພາະກ່ຽວກັບປະເພດອື່ນໆຂອງ loaders ເອກະສານ, LangChain ສະເຫນີ a
ເມື່ອທ່ານໂຫລດເອກະສານຂອງທ່ານແລ້ວ, ມັນເປັນສິ່ງ ສຳ ຄັນທີ່ຈະແຍກພວກມັນອອກເປັນຕ່ອນນ້ອຍໆແລະສາມາດຈັດການໄດ້ຫຼາຍຂຶ້ນ. ນີ້ແມ່ນເຫດຜົນຕົ້ນຕໍ:
LangChain ສະຫນອງຕົວແຍກຂໍ້ຄວາມຫຼາຍປະເພດພາຍໃຕ້ຊຸດ langchain_text_splitters ຂອງມັນ, ແລະພວກມັນແຕກຕ່າງກັນໂດຍອີງໃສ່ປະເພດເອກະສານ.
ນີ້ແມ່ນວິທີການໃຊ້ RecursiveCharacterTextSplitter
ເພື່ອແບ່ງຂໍ້ຄວາມທໍາມະດາໂດຍອີງໃສ່ບັນຊີລາຍຊື່ຂອງຕົວແຍກແລະຂະຫນາດ chunk:
!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 ດ້ວຍການນັບຕົວອັກສອນໃກ້ຄຽງກັບ chunk_size
ເທົ່າທີ່ເປັນໄປໄດ້. ມັນສາມາດສະຫຼັບຄືນໃຫມ່ລະຫວ່າງຕົວແຍກທີ່ຈະແບ່ງອອກເພື່ອຮັກສາການນັບຕົວອັກສອນ.
ໃນຕົວຢ່າງຂ້າງເທິງ, ຕົວແຍກຂອງພວກເຮົາພະຍາຍາມແບ່ງເສັ້ນໃຫມ່ກ່ອນ, ຫຼັງຈາກນັ້ນຊ່ອງຫວ່າງດຽວ, ແລະສຸດທ້າຍລະຫວ່າງຕົວອັກສອນໃດນຶ່ງເພື່ອບັນລຸຂະຫນາດ chunk ທີ່ຕ້ອງການ.
ມີຕົວແຍກອື່ນໆຈໍານວນຫຼາຍຢູ່ໃນຊຸດ langchain_text_splitters
. ນີ້ແມ່ນບາງອັນ:
HTMLSectionSplitter
PythonCodeTexSplitter
RecursiveJsonSplitter
ແລະອື່ນໆ. ບາງຕົວແຍກສ້າງສ່ວນທີ່ມີຄວາມຫມາຍໂດຍການນໍາໃຊ້ຕົວແບບການຫັນປ່ຽນພາຍໃຕ້ຝາປິດ.
ຕົວແຍກຂໍ້ຄວາມທີ່ຖືກຕ້ອງມີຜົນກະທົບຢ່າງຫຼວງຫຼາຍຕໍ່ການປະຕິບັດຂອງລະບົບ RAG.
ສໍາລັບສະເພາະກ່ຽວກັບວິທີການນໍາໃຊ້ຕົວແຍກຂໍ້ຄວາມ, ເບິ່ງທີ່ກ່ຽວຂ້ອງ
ເມື່ອເອກະສານຖືກແບ່ງອອກເປັນຂໍ້ຄວາມ, ພວກມັນຈໍາເປັນຕ້ອງຖືກເຂົ້າລະຫັດເຂົ້າໃນການສະແດງຕົວເລກຂອງພວກເຂົາ, ເຊິ່ງເປັນຂໍ້ກໍານົດສໍາລັບຮູບແບບການຄິດໄລ່ທັງຫມົດທີ່ເຮັດວຽກກັບຂໍ້ມູນຂໍ້ຄວາມ.
ໃນສະພາບການຂອງ RAG, ການເຂົ້າລະຫັດນີ້ເອີ້ນວ່າ ການຝັງ ແລະເຮັດໂດຍ ການຝັງຕົວແບບ . ພວກເຂົາສ້າງຕົວສະແດງ vector ຂອງຂໍ້ຄວາມທີ່ເກັບກໍາຄວາມຫມາຍ semantic ຂອງເຂົາເຈົ້າ. ໂດຍການນໍາສະເຫນີຂໍ້ຄວາມດ້ວຍວິທີນີ້, ທ່ານສາມາດດໍາເນີນການທາງຄະນິດສາດກ່ຽວກັບພວກມັນໄດ້, ເຊັ່ນການຄົ້ນຫາຖານຂໍ້ມູນເອກະສານຂອງພວກເຮົາສໍາລັບຂໍ້ຄວາມທີ່ຄ້າຍຄືກັນທີ່ສຸດໃນຄວາມຫມາຍຫຼືຊອກຫາຄໍາຕອບສໍາລັບຄໍາຖາມຂອງຜູ້ໃຊ້.
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]
ຜົນໄດ້ຮັບຂ້າງເທິງສະແດງໃຫ້ເຫັນວ່າຮູບແບບການຝັງແມ່ນການສ້າງ vector 1536-dimensional ສໍາລັບ chunks ທັງຫມົດໃນເອກະສານຂອງພວກເຮົາ.
ເພື່ອຝັງຄິວຣີດຽວ, ທ່ານສາມາດໃຊ້ວິທີ 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 ຂະຫນາດໃຫຍ່ທີ່ທ່ານອາດຈະມີເອກະສານ gigabytes, ທ່ານຈະສິ້ນສຸດດ້ວຍຂໍ້ຄວາມ gazillion ແລະດັ່ງນັ້ນ, vectors. ມັນບໍ່ມີປະໂຫຍດຫຍັງກັບພວກມັນຖ້າທ່ານບໍ່ສາມາດເກັບຮັກສາພວກມັນໄວ້ຢ່າງເຊື່ອຖືໄດ້.
ນີ້ແມ່ນເຫດຜົນທີ່ ຮ້ານຄ້າ vector ຫຼືຖານຂໍ້ມູນ ທັງຫມົດແມ່ນ rage ໃນປັດຈຸບັນ. ນອກເຫນືອຈາກການເກັບຮັກສາການຝັງຂອງທ່ານ, ຖານຂໍ້ມູນ vector ເບິ່ງແຍງການປະຕິບັດການຊອກຫາ vector ສໍາລັບທ່ານ. ຖານຂໍ້ມູນເຫຼົ່ານີ້ຖືກປັບປຸງໃຫ້ດີທີ່ສຸດເພື່ອຊອກຫາ vectors ທີ່ຄ້າຍຄືກັນທີ່ສຸດໃນເວລາທີ່ໃຫ້ vector ສອບຖາມ, ເຊິ່ງເປັນສິ່ງຈໍາເປັນສໍາລັບການດຶງຂໍ້ມູນທີ່ກ່ຽວຂ້ອງໃນລະບົບ RAG.
ນີ້ແມ່ນຕົວຢ່າງຂອງລະຫັດທີ່ຝັງເນື້ອໃນຂອງຫນ້າເວັບແລະເກັບຮັກສາ vectors ເຂົ້າໄປໃນຖານຂໍ້ມູນ vector Chroma ( Chroma ແມ່ນການແກ້ໄຂຖານຂໍ້ມູນ vector open-source ທີ່ເຮັດວຽກທັງຫມົດໃນເຄື່ອງຂອງທ່ານ):
!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
ແລະສ້າງ chunks ຂອງພວກເຮົາ. ຫຼັງຈາກນັ້ນ, ພວກເຮົາສາມາດສົ່ງ chunks ໂດຍກົງໄປຫາວິທີການ from_documents
ຂອງ Chroma
ພ້ອມກັບຕົວແບບການຝັງຂອງພວກເຮົາທາງເລືອກ:
from langchain_openai import OpenAIEmbeddings from langchain_chroma import Chroma db = Chroma.from_documents(chunks, OpenAIEmbeddings())
ວັດຖຸຖານຂໍ້ມູນ vector ທັງຫມົດໃນ 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.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
ຜົນໄດ້ຮັບຂອງ similarity_search
ແມ່ນບັນຊີລາຍຊື່ຂອງເອກະສານທີ່ມັກຈະມີຂໍ້ມູນທີ່ພວກເຮົາກໍາລັງຖາມຢູ່ໃນຄໍາຖາມ.
ສໍາລັບສະເພາະກ່ຽວກັບວິທີການນໍາໃຊ້ຮ້ານຄ້າ vector, ເບິ່ງທີ່ກ່ຽວຂ້ອງ
ເຖິງແມ່ນວ່າຮ້ານຄ້າ vector ທັງຫມົດສະຫນັບສະຫນູນການດຶງຂໍ້ມູນໃນຮູບແບບຂອງການຄົ້ນຫາທີ່ຄ້າຍຄືກັນ, LangChain ປະຕິບັດການໂຕ້ຕອບ Retriever
ທີ່ອຸທິດຕົນທີ່ສົ່ງຄືນເອກະສານທີ່ມີການສອບຖາມທີ່ບໍ່ມີໂຄງສ້າງ. Retriever ພຽງແຕ່ຕ້ອງການກັບຄືນຫຼືດຶງເອກະສານ, ບໍ່ແມ່ນເກັບຮັກສາໄວ້.
ນີ້ແມ່ນວິທີທີ່ທ່ານສາມາດປ່ຽນຮ້ານ vector ໃດເປັນ 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
ມັນເປັນໄປໄດ້ທີ່ຈະຈໍາກັດຈໍານວນເອກະສານທີ່ກ່ຽວຂ້ອງຢູ່ເທິງ 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. ສຶກສາເພີ່ມເຕີມກ່ຽວກັບການໃຊ້ retrievers ຈາກ
ໃນປັດຈຸບັນທີ່ພວກເຮົາໄດ້ກວມເອົາອົງປະກອບທີ່ສໍາຄັນຂອງລະບົບ RAG, ພວກເຮົາຈະສ້າງຕົວເອງ. ຂ້າພະເຈົ້າຈະແນະນໍາທ່ານຜ່ານການປະຕິບັດຂັ້ນຕອນຂອງ RAG chatbot ທີ່ຖືກອອກແບບໂດຍສະເພາະສໍາລັບເອກະສານລະຫັດແລະການສອນ. ທ່ານຈະເຫັນວ່າມັນເປັນປະໂຫຍດໂດຍສະເພາະໃນເວລາທີ່ທ່ານຕ້ອງການການຊ່ວຍເຫຼືອການຂຽນລະຫັດ AI ສໍາລັບກອບໃຫມ່ຫຼືລັກສະນະໃຫມ່ຂອງກອບທີ່ມີຢູ່ແລ້ວທີ່ຍັງບໍ່ທັນເປັນສ່ວນຫນຶ່ງຂອງພື້ນຖານຄວາມຮູ້ຂອງ LLMs ໃນມື້ນີ້.
ທໍາອິດ, ຕື່ມຂໍ້ມູນໃສ່ໄດເລກະທໍລີເຮັດວຽກຂອງທ່ານດ້ວຍໂຄງສ້າງໂຄງການຕໍ່ໄປນີ້:
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}
ໃນຂັ້ນຕອນນີ້, ທ່ານທໍາອິດສ້າງສະພາບແວດລ້ອມ 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
ຕໍ່ໄປ, ເປີດໄຟລ໌ src/document_processor.py
ແລະວາງ snippets ຂອງລະຫັດທີ່ຈະມາເຖິງ.
ການນໍາເຂົ້າທີ່ຈໍາເປັນ:
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
: ເປັນຕົວແທນຂອງເອກະສານທີ່ມີເນື້ອໃນ ແລະ metadata.logging
: ສະຫນອງການທໍາງານຂອງການບັນທຶກສໍາລັບການ debugging ແລະຂໍ້ມູນຂ່າວສານ.
ຫຼັງຈາກນັ້ນ, ຫນ້າທີ່ສໍາລັບການປຸງແຕ່ງ PDFs:
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)
ນີ້ແມ່ນວິທີທີ່ມັນເຮັດວຽກ:
PyPDFLoader
. ຟັງຊັນຈັດການກໍລະນີທີ່ 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 (Optical Character Recognition). ມັນອ່ານໄຟລ໌ຮູບພາບ, ປ່ຽນເປັນໄບຕ໌, ແລະຫຼັງຈາກນັ້ນໃຊ້ຫ້ອງສະຫມຸດ RapidOCR ເພື່ອສະກັດຂໍ້ຄວາມຈາກຮູບພາບ. ຂໍ້ຄວາມທີ່ສະກັດຈາກນັ້ນຖືກຫໍ່ຢູ່ໃນວັດຖຸເອກະສານທີ່ມີ metadata ທີ່ມີເສັ້ນທາງໄຟລ໌ແຫຼ່ງ. ສຸດທ້າຍ, ຟັງຊັນແບ່ງເອກະສານອອກເປັນຕ່ອນນ້ອຍໆໂດຍໃຊ້ຟັງຊັນ 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 ກັບ syntax ຂອງ Python ເພື່ອແຍກຂໍ້ຄວາມອອກເປັນ chunks ຂອງ 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 UI ລົງແຖວເພື່ອສ້າງ, ຝັງ ແລະເກັບຮັກສາ chunks ຈາກເອກະສານທີ່ສະຫນອງໃຫ້ແລະສົ່ງໃຫ້ເຂົາເຈົ້າລົງໄປອົງປະກອບ RAG ຂອງລະບົບຂອງພວກເຮົາ.
ດຽວນີ້, ເປີດໄຟລ໌ src/rag_chain.py
ແລະວາງ snippets ຂອງລະຫັດທີ່ຈະມາເຖິງ.
ທໍາອິດ, ນໍາເຂົ້າໂມດູນທີ່ຈໍາເປັນ:
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
: Load environment variables • langchain
components:
PromptTemplate
: ການສ້າງ prompt ແບບກຳນົດເອງFAISS
: ເກັບຮັກສາ vector ທີ່ມີນ້ໍາຫນັກເບົາສໍາລັບເອກະສານStrOutputParser
: ການແປງວັດຖຸຂໍ້ຄວາມ LLM ໃຫ້ເປັນ String outputsRunnablePassthrough
: ສ້າງຕ່ອງໂສ້ທີ່ສາມາດປະກອບໄດ້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 ແມ່ນປັດໃຈສໍາຄັນໃນຄວາມສໍາເລັດຂອງມັນ. ສະບັບຂອງພວກເຮົາແມ່ນເປັນຫນຶ່ງທີ່ງ່າຍດາຍແຕ່ຈະໄດ້ຮັບການເຮັດວຽກຫຼາຍທີ່ສຸດຂອງເວລາ. ໃນການປະຕິບັດ, ທ່ານຈະໃຊ້ເວລາຫຼາຍ iterating ແລະປັບປຸງທັນທີ.
ຖ້າທ່ານສັງເກດເຫັນ, ພວກເຮົາໃຊ້ຫ້ອງຮຽນ PromptTemplate
ສໍາລັບການກໍ່ສ້າງການເຕືອນ. ໂຄງສ້າງນີ້ຊ່ວຍໃຫ້ພວກເຮົາສາມາດເອົາບໍລິບົດທີ່ດຶງມາຈາກເອກະສານແລະການສອບຖາມຂອງຜູ້ໃຊ້ເຂົ້າໃນການກະຕຸ້ນເຕືອນສຸດທ້າຍ.
ເວົ້າກ່ຽວກັບເອກະສານ, ພວກເຮົາຕ້ອງການຟັງຊັນເພື່ອຈັດຮູບແບບພວກມັນກ່ອນທີ່ພວກມັນຈະຖືກສົ່ງຜ່ານສະພາບການເຂົ້າໄປໃນລະບົບເຕືອນ:
def format_docs(docs): return "\n\n".join(doc.page_content for doc in docs)
ມັນເປັນຫນ້າທີ່ງ່າຍດາຍທີ່ concatenates ເນື້ອໃນຫນ້າຂອງເອກະສານທີ່ດຶງມາ.
ສຸດທ້າຍ, ພວກເຮົາສ້າງຫນ້າທີ່ທີ່ຈະພັດທະນາລະບົບຕ່ອງໂສ້ 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
.
ຟັງຊັນເລີ່ມຕົ້ນໂດຍການກໍານົດຮູບແບບການຝັງແລະການເກັບຮັກສາເອກະສານເຂົ້າໄປໃນຮ້ານ vector FAISS. ຫຼັງຈາກນັ້ນ, ມັນຖືກປ່ຽນເປັນການໂຕ້ຕອບ retriever ກັບການຄົ້ນຫາທີ່ຄ້າຍຄືກັນທີ່ສົ່ງຄືນເອກະສານຫ້າອັນທີ່ກົງກັບຄໍາຖາມຂອງຜູ້ໃຊ້.
ສໍາລັບຮູບແບບພາສາ, ພວກເຮົາຈະໃຊ້ gpt-4o-mini
ແຕ່ທ່ານສາມາດນໍາໃຊ້ແບບຈໍາລອງອື່ນໆເຊັ່ນ GPT-4o ຂຶ້ນກັບງົບປະມານແລະຄວາມຕ້ອງການຂອງທ່ານ.
ຫຼັງຈາກນັ້ນ, ພວກເຮົາຈະເອົາອົງປະກອບເຫຼົ່ານີ້ທັງຫມົດຮ່ວມກັນໂດຍໃຊ້ LangChain Expression Language (LCEL). ອົງປະກອບທໍາອິດຂອງລະບົບຕ່ອງໂສ້ແມ່ນວັດຈະນານຸກົມທີ່ມີ context
ແລະ question
ເປັນກະແຈ. ຄ່າຂອງກະແຈເຫຼົ່ານີ້ແມ່ນສະໜອງໃຫ້ໂດຍ retriever ທີ່ຈັດຮູບແບບໂດຍຟັງຊັນການຈັດຮູບແບບຂອງພວກເຮົາ ແລະ RunnablePassthrough()
ຕາມລໍາດັບ. ຫ້ອງຮຽນສຸດທ້າຍເຮັດຫນ້າທີ່ເປັນຕົວຍຶດສໍາລັບການສອບຖາມຂອງຜູ້ໃຊ້.
ວັດຈະນານຸກົມໄດ້ຖືກຖ່າຍທອດເຂົ້າໄປໃນລະບົບຂອງພວກເຮົາທັນທີ; ການກະຕຸ້ນເຕືອນແມ່ນປ້ອນໃຫ້ LLM, ເຊິ່ງສ້າງຊັ້ນຂໍ້ຄວາມຜົນຜະລິດ. ຫ້ອງຮຽນຂໍ້ຄວາມຖືກມອບໃຫ້ກັບຕົວແຍກສະຕຣິງຜົນຜະລິດທີ່ສົ່ງຜົນຕອບແທນຂໍ້ຄວາມທຳມະດາ.
ໃນພາກນີ້, ພວກເຮົາຈະສ້າງ UI ຂ້າງລຸ່ມນີ້ສໍາລັບ app ຂອງພວກເຮົາ:
ມັນເປັນການໂຕ້ຕອບທີ່ສະອາດ, ຫນ້ອຍທີ່ມີສອງຊ່ອງໃສ່ຂໍ້ມູນ - ຫນຶ່ງສໍາລັບເອກະສານ, ອື່ນສໍາລັບການຖາມຄໍາຖາມກ່ຽວກັບເອກະສານ. ໃນແຖບດ້ານຊ້າຍ, ຜູ້ໃຊ້ຖືກຮ້ອງຂໍໃຫ້ໃສ່ລະຫັດ 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 ເສັ້ນ, ມັນປະຕິບັດຫນ້າທີ່ດັ່ງຕໍ່ໄປນີ້:
ເຫຼືອພຽງຂັ້ນຕອນດຽວເທົ່ານັ້ນ - ການນຳໃຊ້ແອັບ Streamlit ຂອງພວກເຮົາ. ມີຫຼາຍທາງເລືອກຢູ່ທີ່ນີ້, ແຕ່ວິທີທີ່ງ່າຍທີ່ສຸດແມ່ນໂດຍໃຊ້ Streamlit Cloud, ເຊິ່ງບໍ່ເສຍຄ່າ ແລະງ່າຍຕໍ່ການຕັ້ງຄ່າ.
ກ່ອນອື່ນ, ເປີດສະຄຣິບ .streamlit/config.toml
ແລະວາງການຕັ້ງຄ່າຕໍ່ໄປນີ້:
[theme] primaryColor = "#F63366" backgroundColor = "#FFFFFF" secondaryBackgroundColor = "#F0F2F6" textColor = "#262730" font = "sans serif"
ນີ້ແມ່ນການປັບປ່ຽນຫົວຂໍ້ບາງຢ່າງທີ່ມາຈາກຄວາມມັກສ່ວນຕົວ. ຫຼັງຈາກນັ້ນ, ຂຽນໄຟລ໌ README.md (ທ່ານສາມາດຄັດລອກເນື້ອຫາຂອງມັນຈາກ ໄຟລ໌ທີ່ໂຮດຢູ່ໃນ GitHub ).
ສຸດທ້າຍ, ໄປ GitHub.com ແລະສ້າງ repository ໃຫມ່. ຄັດລອກລິ້ງຂອງມັນແລະກັບຄືນໄປຫາໄດເລກະທໍລີທີ່ເຮັດວຽກຂອງທ່ານ:
$ 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, ສ້າງຄໍາຫມັ້ນສັນຍາເບື້ອງຕົ້ນແລະຍູ້ທຸກສິ່ງທຸກຢ່າງໄປຫາບ່ອນເກັບມ້ຽນ (ຢ່າລືມປ່ຽນການເຊື່ອມຕໍ່ repo ດ້ວຍຕົວເອງ).
ດຽວນີ້, ທ່ານຕ້ອງລົງທະບຽນບັນຊີຟຣີຢູ່ Streamlit Cloud . ເຊື່ອມຕໍ່ບັນຊີ GitHub ຂອງທ່ານແລະເລືອກບ່ອນເກັບມ້ຽນທີ່ມີແອັບຯຂອງທ່ານ.
ຈາກນັ້ນ, ຕັ້ງຄ່າການຕັ້ງຄ່າແອັບ:
app.py
OPENAI_API_KEY
) ໃນການຕັ້ງຄ່າແອັບຯ
ສຸດທ້າຍ, ໃຫ້ຄລິກໃສ່ "Deploy"!
ແອັບຯຕ້ອງເຮັດວຽກພາຍໃນນາທີ. ແອັບທີ່ຂ້ອຍສ້າງຂຶ້ນສຳລັບບົດສອນນີ້ສາມາດພົບໄດ້ທີ່ ລິ້ງນີ້ . ລອງໃຊ້ເບິ່ງ!
ການສອນນີ້ເບິ່ງການປະສົມທີ່ມີທ່າແຮງຂອງ Retrieval-Augmented Generation (RAG) ແລະ Streamlit ທີ່ປະກອບເປັນລະບົບການຕອບຄໍາຖາມແບບໂຕ້ຕອບໂດຍອີງໃສ່ເອກະສານ. ມັນໃຊ້ເວລາຜູ້ອ່ານໂດຍຜ່ານຂະບວນການທັງຫມົດ, ຈາກການຕັ້ງຄ່າສະພາບແວດລ້ອມແລະການປຸງແຕ່ງເອກະສານເພື່ອສ້າງລະບົບຕ່ອງໂສ້ RAG ແລະນໍາໃຊ້ແອັບຯເວັບທີ່ເປັນມິດ.
ຈຸດສໍາຄັນປະກອບມີ:
ໂຄງການນີ້ເປັນພື້ນຖານສໍາລັບຄໍາຮ້ອງສະຫມັກທີ່ກ້າວຫນ້າຫຼາຍ. ມັນສາມາດຂະຫຍາຍອອກໄດ້ໃນຫຼາຍວິທີເຊັ່ນ: ການລວມເອົາເອກະສານຫຼາຍປະເພດ, ປັບປຸງຄວາມຖືກຕ້ອງຂອງການດຶງຂໍ້ມູນ, ແລະຄຸນສົມບັດເຊັ່ນ: ການສະຫຼຸບເອກະສານ. ແລະທັນ, ສິ່ງທີ່ມັນຮັບໃຊ້ຢ່າງແທ້ຈິງແມ່ນເປັນການສະແດງໃຫ້ເຫັນເຖິງພະລັງງານທີ່ມີທ່າແຮງຂອງເຕັກໂນໂລຢີເຫຼົ່ານີ້, ສ່ວນບຸກຄົນແລະປະສົມປະສານ.