Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Build Retrieval-Augmented Generation (RAG) systems for LLM applications with vector databases and semantic search. Use when implementing knowledge-grounded AI, building document Q&A systems, or integrating LLMs with external knowledge bases.
.claude/skills/microck-rag-implementation/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-17 | ✗→✓ | ▲ Improved | 152% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 143% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 233% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 110% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 99% | 0% |
Master Retrieval-Augmented Generation (RAG) to build LLM applications that provide accurate, grounded responses using external knowledge sources.
Purpose: Store and retrieve document embeddings efficiently
Options:
Purpose: Convert text to numerical vectors for similarity search
Models:
Approaches:
Purpose: Improve retrieval quality by reordering results
Methods:
pythonfrom langchain.document_loaders import DirectoryLoader from langchain.text_splitters import RecursiveCharacterTextSplitter from langchain.embeddings import OpenAIEmbeddings from langchain.vectorstores import Chroma from langchain.chains import RetrievalQA from langchain.llms import OpenAI # 1. Load documents loader = DirectoryLoader('./docs', glob="**/*.txt") documents = loader.load() # 2. Split into chunks text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=200, length_function=len ) chunks = text_splitter.split_documents(documents) # 3. Create embeddings and vector store embeddings = OpenAIEmbeddings() vectorstore = Chroma.from_documents(chunks, embeddings) # 4. Create retrieval chain qa_chain = RetrievalQA.from_chain_type( llm=OpenAI(), chain_type="stuff", retriever=vectorstore.as_retriever(search_kwargs={"k": 4}), return_source_documents=True ) # 5. Query result = qa_chain({"query": "What are the main features?"}) print(result['result']) print(result['source_documents'])
pythonfrom langchain.retrievers import BM25Retriever, EnsembleRetriever # Sparse retriever (BM25) bm25_retriever = BM25Retriever.from_documents(chunks) bm25_retriever.k = 5 # Dense retriever (embeddings) embedding_retriever = vectorstore.as_retriever(search_kwargs={"k": 5}) # Combine with weights ensemble_retriever = EnsembleRetriever( retrievers=[bm25_retriever, embedding_retriever], weights=[0.3, 0.7] )
pythonfrom langchain.retrievers.multi_query import MultiQueryRetriever # Generate multiple query perspectives retriever = MultiQueryRetriever.from_llm( retriever=vectorstore.as_retriever(), llm=OpenAI() ) # Single query → multiple variations → combined results results = retriever.get_relevant_documents("What is the main topic?")
pythonfrom langchain.retrievers import ContextualCompressionRetriever from langchain.retrievers.document_compressors import LLMChainExtractor compressor = LLMChainExtractor.from_llm(llm) compression_retriever = ContextualCompressionRetriever( base_compressor=compressor, base_retriever=vectorstore.as_retriever() ) # Returns only relevant parts of documents compressed_docs = compression_retriever.get_relevant_documents("query")
pythonfrom langchain.retrievers import ParentDocumentRetriever from langchain.storage import InMemoryStore # Store for parent documents store = InMemoryStore() # Small chunks for retrieval, large chunks for context child_splitter = RecursiveCharacterTextSplitter(chunk_size=400) parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000) retriever = ParentDocumentRetriever( vectorstore=vectorstore, docstore=store, child_splitter=child_splitter, parent_splitter=parent_splitter )
pythonfrom langchain.text_splitters import RecursiveCharacterTextSplitter splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=200, length_function=len, separators=["\n\n", "\n", " ", ""] # Try these in order )
pythonfrom langchain.text_splitters import TokenTextSplitter splitter = TokenTextSplitter( chunk_size=512, chunk_overlap=50 )
pythonfrom langchain.text_splitters import SemanticChunker splitter = SemanticChunker( embeddings=OpenAIEmbeddings(), breakpoint_threshold_type="percentile" )
pythonfrom langchain.text_splitters import MarkdownHeaderTextSplitter headers_to_split_on = [ ("#", "Header 1"), ("##", "Header 2"), ("###", "Header 3"), ] splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
pythonimport pinecone from langchain.vectorstores import Pinecone pinecone.init(api_key="your-api-key", environment="us-west1-gcp") index = pinecone.Index("your-index-name") vectorstore = Pinecone(index, embeddings.embed_query, "text")
pythonimport weaviate from langchain.vectorstores import Weaviate client = weaviate.Client("http://localhost:8080") vectorstore = Weaviate(client, "Document", "content", embeddings)
pythonfrom langchain.vectorstores import Chroma vectorstore = Chroma( collection_name="my_collection", embedding_function=embeddings, persist_directory="./chroma_db" )
python# Add metadata during indexing chunks_with_metadata = [] for i, chunk in enumerate(chunks): chunk.metadata = { "source": chunk.metadata.get("source"), "page": i, "category": determine_category(chunk.page_content) } chunks_with_metadata.append(chunk) # Filter during retrieval results = vectorstore.similarity_search( "query", filter={"category": "technical"}, k=5 )
python# Balance relevance with diversity results = vectorstore.max_marginal_relevance_search( "query", k=5, fetch_k=20, # Fetch 20, return top 5 diverse lambda_mult=0.5 # 0=max diversity, 1=max relevance )
pythonfrom sentence_transformers import CrossEncoder reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2') # Get initial results candidates = vectorstore.similarity_search("query", k=20) # Rerank pairs = [[query, doc.page_content] for doc in candidates] scores = reranker.predict(pairs) # Sort by score and take top k reranked = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True)[:5]
pythonprompt_template = """Use the following context to answer the question. If you cannot answer based on the context, say "I don't have enough information." Context: {context} Question: {question} Answer:"""
pythonprompt_template = """Answer the question based on the context below. Include citations using [1], [2], etc. Context: {context} Question: {question} Answer (with citations):"""
pythonprompt_template = """Answer the question using the context. Provide a confidence score (0-100%) for your answer. Context: {context} Question: {question} Answer: Confidence:"""
pythondef evaluate_rag_system(qa_chain, test_cases): metrics = { 'accuracy': [], 'retrieval_quality': [], 'groundedness': [] } for test in test_cases: result = qa_chain({"query": test['question']}) # Check if answer matches expected accuracy = calculate_accuracy(result['result'], test['expected']) metrics['accuracy'].append(accuracy) # Check if relevant docs were retrieved retrieval_quality = evaluate_retrieved_docs( result['source_documents'], test['relevant_docs'] ) metrics['retrieval_quality'].append(retrieval_quality) # Check if answer is grounded in context groundedness = check_groundedness( result['result'], result['source_documents'] ) metrics['groundedness'].append(groundedness) return {k: sum(v)/len(v) for k, v in metrics.items()}
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 6,090 | 4,030 | -34% | 1 | 1 | 0% | 1,067 | 3,554 | +233% | 0 | 0 | — |
case-02 | pass→pass | 13,063 | 12,026 | -8% | 1 | 1 | 0% | 2,438 | 5,113 | +110% | 0 | 0 | — |
case-03 | pass→pass | 14,618 | 13,399 | -8% | 1 | 1 | 0% | 2,586 | 5,137 | +99% | 0 | 0 | — |
case-04 | pass→pass | 10,157 | 11,005 | +8% | 1 | 1 | 0% | 1,520 | 4,616 | +204% | 0 | 0 | — |
case-05 | pass→pass | 14,431 | 13,627 | -6% | 1 | 1 | 0% | 2,853 | 5,305 | +86% | 0 | 0 | — |
case-06 | pass→pass | 11,847 | 14,270 | +20% | 1 | 1 | 0% | 2,259 | 5,132 | +127% | 0 | 0 | — |
case-07 | pass→pass | 14,358 | 13,085 | -9% | 1 | 1 | 0% | 2,989 | 5,205 | +74% | 0 | 0 | — |
case-08 | pass→pass | 14,614 | 12,492 | -15% | 1 | 1 | 0% | 2,481 | 5,595 | +126% | 0 | 0 | — |
case-09 | pass→pass | 11,918 | 3,976 | -67% | 1 | 1 | 0% | 2,047 | 3,615 | +77% | 0 | 0 | — |
case-10 | pass→pass | 10,049 | 8,073 | -20% | 1 | 1 | 0% | 1,841 | 4,284 | +133% | 0 | 0 | — |
case-11 | pass→pass | 8,957 | 7,429 | -17% | 1 | 1 | 0% | 1,701 | 4,073 | +139% | 0 | 0 | — |
case-12 | pass→pass | 11,822 | 8,442 | -29% | 1 | 1 | 0% | 2,151 | 4,402 | +105% | 0 | 0 | — |
case-13 | pass→pass | 13,933 | 11,310 | -19% | 1 | 1 | 0% | 2,272 | 4,962 | +118% | 0 | 0 | — |
case-14 | fail→fail | 9,531 | 8,112 | -15% | 1 | 1 | 0% | 1,611 | 4,265 | +165% | 0 | 0 | — |
case-15 | pass→pass | 9,504 | 7,832 | -18% | 1 | 1 | 0% | 1,758 | 4,480 | +155% | 0 | 0 | — |
case-16 | pass→pass | 14,376 | 13,214 | -8% | 1 | 1 | 0% | 2,380 | 4,986 | +109% | 0 | 0 | — |
case-17 | fail→pass | 8,211 | 5,221 | -36% | 1 | 1 | 0% | 1,506 | 3,797 | +152% | 0 | 0 | — |
case-18 | pass→pass | 10,118 | 7,589 | -25% | 1 | 1 | 0% | 2,085 | 4,366 | +109% | 0 | 0 | — |
case-19 | fail→fail | 9,629 | 6,548 | -32% | 1 | 1 | 0% | 1,812 | 4,058 | +124% | 0 | 0 | — |
case-20 | fail→pass | 12,513 | 12,436 | -1% | 1 | 1 | 0% | 2,078 | 5,041 | +143% | 0 | 0 | — |
case-21 | pass→pass | 20,127 | 17,408 | -14% | 1 | 1 | 0% | 4,194 | 6,447 | +54% | 0 | 0 | — |
case-22 | pass→pass | 14,639 | 13,917 | -5% | 1 | 1 | 0% | 2,805 | 5,662 | +102% | 0 | 0 | — |
case-23 | pass→pass | 11,439 | 9,742 | -15% | 1 | 1 | 0% | 2,133 | 4,659 | +118% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +9 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.