在此為確保程式碼的可執行性,使用了免費的模型,若要求性能,可以使用替代方案。
Basic Moves
1. 載入文件
loader = WebBaseLoader(urls_list)
documents = loader.load()
- 使用
WebBaseLoader
從給定的 URL 列表中載入文件。在這裡可以根據需求替換其它 Loader。PyPDFLoader
用於 PDF 文件。TextLoader
用於純文本文件。
2. 分割文件
pythonCopytext_splitter = CharacterTextSplitter.from_tiktoken_encoder(chunk_size=7500, chunk_overlap=100)
doc_splits = text_splitter.split_documents(documents)
- 文件分割是一個關鍵步驟。這裡使用
CharacterTextSplitter
並基於tiktoken
編碼器進行分割。 - 參數說明:
chunk_size
: 定義每個 chunk 的最大 token 數。較大的 chunk 可能包含更多上下文,但可能降低檢索精度。chunk_overlap
: 定義相鄰塊之間的重疊 token 數。增加重疊可以幫助保持上下文連續性,但會增加記憶體需求。
- 替代方案:
RecursiveCharacterTextSplitter
: 可以更智能地處理文檔結構。TokenTextSplitter
: 直接基於標記進行分割,可能更準確但速度較慢。
3. 選擇 embedding 模型
pythonCopyembeddings = OllamaEmbeddings(model="mistral")
- 這裡使用
Ollama
的Mistral
模型生成嵌入。 - 替代方案:
OpenAI
HuggingFace
Gemini
4. 創建向量資料庫
pythonCopyvector_store = Chroma.from_documents(
documents = doc_splits,
embedding = embeddings,
collection_name = "rag-chroma",
)
- 替代方案:
FAISS
(Meta 的)Milvus
Pinecone
5. 建立 Retriever Interface
retriever = vector_store.as_retriever()
- 可以通過設置參數
search_type
與search_kwargs
來調整檢索行為。
6. 執行 RAG
rag_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
- 定義 RAG 鏈。可以通過修改 prompt 或使用不同的 LLM 來優化性能。
7. 查詢
return rag_chain.invoke(question)
- 調用 RAG 鏈針對輸入的問題返回答案。
Advanced Moves
加入 metadata 並進行篩選:
loader = WebBaseLoader(urls_list)
loader.requests_kwargs = {'verify':False}
docs = loader.load()
docs = [Document(page_content=doc.page_content, metadata={"source": doc.metadata['source']}) for doc in docs]
# 在檢索時使用 metadata 篩選
retriever = vector_store.as_retriever(search_kwargs={"filter": {"source": "特定URL"}})
加入 pre/post retrieval 處理:
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor
compressor = LLMChainExtractor.from_llm(llm)
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=retriever
)
加入 rerank 提升回答的加權:
from langchain.retrievers import EnsembleRetriever
bm25_retriever = BM25Retriever.from_documents(documents)
ensemble_retriever = EnsembleRetriever(
retrievers=[retriever, bm25_retriever],
weights=[0.5, 0.5]
)
改變 naive RAG 為 graph RAG:
from langchain.graphs import NetworkxEntityGraph
from langchain.indexes import GraphIndexCreator
graph_creator = GraphIndexCreator(
graph_type=NetworkxEntityGraph,
include_embeddings=True
)
graph = graph_creator.from_documents(documents)
# 使用 graph RAG
retrieved_nodes = graph.get_relevant_nodes(query)