Stop letting LLMs lie to your face with RAG
RecursiveCharacterTextSplitter is too aggressive, your retrieval quality is going to tank and you're just throwing money at a broken system.from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS
from langchain.document_loaders import PDFLoaderloader = PDFLoader("company_docs.pdf")
docs = loader.load()
embeddings = OpenAIEmbeddings()
vector_store = FAISS.from_documents(docs, embeddings)
I've learned the hard way that a basic similarity search is amateur hour if you're moving toward actual production. You need a hybrid search—mixing semantic search with BM25 keyword search—to actually hit specific queries, and you absolutely need a reranking stage so you aren't feeding a mountain of noise into the prompt. You want to retrieve a bunch of docs but only pass the top-tier stuff to the LLM to keep token costs from spiraling.
# Retrieve many, rank few
retrieved = retriever.get_relevant_documents(query) # Get 100
ranked = rerank(retrieved, query, top_k=5) # Keep 5 best
context = "\n".join([d.page_content for d in ranked])from langchain.chains import RetrievalQA
from langchain.llms import OpenAIqa = RetrievalQA.from_chain_type(
llm=OpenAI(),
chain_type="stuff",
retriever=retriever
)
result = qa.run("What's our Q3 revenue?")
print(result) # Now grounded in real data!
If you're looking for a place to host embeddings without overcomplicating your stack, check out:
Pinecone
Weaviate
FAISS
MilvusIt’s a lot of moving parts and high architectural complexity, but it's the only way to build an agent that actually provides value instead of just being a glorified, expensive chatbot. Check out promptcube3.com if you want to see how this scales.