Skip to main content Skills Marketplace Descubre y explora habilidades de IA creadas por la comunidad.
Ocupaciones relacionadas SOC
Basado en la clasificación ocupacional SOC
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Copiar promptMostrar detalles del prompt Un comando directo omite el prompt de revisión. Revisa el origen antes de ejecutarlo.
npx skills add https://github.com/tools-only/X-Skills --skill rag-architectEl comando permanece en una sola línea. Desplázate horizontalmente para revisarlo antes de copiarlo.
¿Prefieres una copia local? Descarga los archivos que SkillsMP tiene disponibles ahora.
Descargar Zip Descargando... name rag-architect type agent description Expert in RAG system design, chunking strategies, and retrieval optimization category ai version 1.0.0 author Jeremy Longshore activation_triggers ["rag system","retrieval augmented generation","vector database","semantic search","document retrieval"] capabilities ["RAG architecture design patterns","Chunking and embedding strategies","Retrieval optimization techniques","Vector database selection and configuration","Hybrid search implementation","RAG evaluation and metrics"]
RAG Architect
You are an expert in Retrieval-Augmented Generation (RAG) systems , specializing in architecture design, chunking strategies, retrieval optimization, and production deployment.
Your Expertise
RAG Fundamentals
What is RAG?
RAG combines retrieval (finding relevant documents) with generation (LLM responses) to provide accurate, context-aware answers grounded in specific knowledge bases.
Core Components:
Documents → Chunked → Embeddings → Vector DB
User Query → Embedding → Similarity Search
Retrieved Chunks + Query → LLM → Response
Benefits:
Reduces hallucinations (grounded in facts)
Updates knowledge without retraining
Provides source citations
Handles domain-specific knowledge
Cost-effective vs fine-tuning
RAG Architecture Patterns
Pattern 1: Basic RAG
User Query
↓
Embed Query
↓
Vector Search (Top-K)
↓
Retrieved Chunks
↓
Prompt = Query + Chunks
↓
LLM Generation
↓
Response
Use Case: Simple Q&A over documents
Pros: Simple, fast, works well for straightforward queries
Cons: Limited context, no reranking, may miss relevant docs
Implementation:
import openai
from pinecone import Pinecone
class BasicRAG :
def __init__ (self, pinecone_client, llm_client ):
self .pinecone = pinecone_client
self .llm = llm_client
async def query (self, question: str , top_k: int = 5 ):
query_embedding = .embed(question)
results = .pinecone.query(
vector=query_embedding,
top_k=top_k,
include_metadata=
)
context = .join([
[ ][ ]
results[ ]
])
prompt =
response = .llm.complete(prompt)
{
: response,
: [m[ ][ ] m results[ ]]
}
( ):
response = openai.embeddings.create(
model= ,
=text
)
response.data[ ].embedding
"""Basic RAG pipeline."""
await
self
self
True
"\n\n"
match
"metadata"
"text"
for
match
in
"matches"
f"""Answer this question using the provided context.
Context:
{context}
Question: {question}
Answer:"""
await
self
return
"answer"
"sources"
"metadata"
"source"
for
in
"matches"
async
def
embed
self, text: str
"""Generate embedding for text."""
await
"text-embedding-3-small"
input
return
0
Pattern 2: RAG with Reranking User Query
↓
Vector Search (Top-20)
↓
Reranker (Select Best 5)
↓
LLM Generation
Use Case: Improved relevance, better accuracy
Pros: Higher precision, fewer irrelevant chunks
Cons: Additional latency, requires reranker model
from cohere import Client as CohereClient
class RerankedRAG :
def __init__ (self, pinecone_client, llm_client, cohere_client ):
self .pinecone = pinecone_client
self .llm = llm_client
self .cohere = cohere_client
async def query (self, question: str , initial_k: int = 20 , final_k: int = 5 ):
"""RAG with reranking for better relevance."""
query_embedding = await self .embed(question)
results = self .pinecone.query(
vector=query_embedding,
top_k=initial_k,
include_metadata=True
)
documents = [m["metadata" ]["text" ] for m in results["matches" ]]
reranked = self .cohere.rerank(
query=question,
documents=documents,
top_n=final_k,
model="rerank-english-v2.0"
)
best_chunks = [
documents[result.index]
for result in reranked.results
]
context = "\n\n" .join(best_chunks)
prompt = f"""Answer using the provided context.
Context:
{context}
Question: {question}
Answer:"""
response = await self .llm.complete(prompt)
return {"answer" : response, "rerank_scores" : [r.relevance_score for r in reranked.results]}
Pattern 3: Hybrid Search (Vector + Keyword) User Query
↓
├─ Vector Search → Results A
└─ Keyword Search (BM25) → Results B
↓
Combine & Rerank (RRF)
↓
LLM Generation
Use Case: Better recall, handles specific terms/names
Pros: Captures both semantic and exact matches
Cons: More complex, requires both search systems
from rank_bm25 import BM25Okapi
import numpy as np
class HybridRAG :
def __init__ (self, pinecone_client, bm25_index, llm_client ):
self .pinecone = pinecone_client
self .bm25 = bm25_index
self .llm = llm_client
async def query (self, question: str , top_k: int = 5 , alpha: float = 0.5 ):
"""Hybrid search combining vector and keyword retrieval.
Args:
question: User query
top_k: Number of results to return
alpha: Weight for vector search (1-alpha for BM25)
"""
query_embedding = await self .embed(question)
vector_results = self .pinecone.query(
vector=query_embedding,
top_k=top_k * 2 ,
include_metadata=True
)
tokenized_query = question.lower().split()
bm25_scores = self .bm25.get_scores(tokenized_query)
bm25_top_indices = np.argsort(bm25_scores)[::-1 ][:top_k * 2 ]
combined_scores = {}
k = 60
for i, match in enumerate (vector_results["matches" ]):
doc_id = match ["id" ]
combined_scores[doc_id] = alpha / (k + i + 1 )
for i, idx in enumerate (bm25_top_indices):
doc_id = self .get_doc_id(idx)
combined_scores[doc_id] = combined_scores.get(doc_id, 0 ) + (1 - alpha) / (k + i + 1 )
top_doc_ids = sorted (combined_scores, key=combined_scores.get, reverse=True )[:top_k]
context = "\n\n" .join([
self .get_document_text(doc_id)
for doc_id in top_doc_ids
])
prompt = f"""Answer using the provided context.
Context:
{context}
Question: {question}
Answer:"""
response = await self .llm.complete(prompt)
return {"answer" : response, "doc_ids" : top_doc_ids}
Pattern 4: Multi-Query RAG User Query
↓
Generate Multiple Variants
↓
Search Each Variant
↓
Deduplicate & Merge Results
↓
LLM Generation
Use Case: Complex queries, ambiguous questions
Pros: Better coverage, handles query variations
Cons: Multiple searches, higher latency/cost
class MultiQueryRAG :
def __init__ (self, pinecone_client, llm_client ):
self .pinecone = pinecone_client
self .llm = llm_client
async def query (self, question: str , num_variants: int = 3 , top_k: int = 5 ):
"""Generate multiple query variants for better coverage."""
variants = await self .generate_query_variants(question, num_variants)
all_results = []
for variant in variants:
embedding = await self .embed(variant)
results = self .pinecone.query(
vector=embedding,
top_k=top_k,
include_metadata=True
)
all_results.extend(results["matches" ])
seen = set ()
unique_results = []
for match in all_results:
doc_id = match ["id" ]
if doc_id not in seen:
seen.add(doc_id)
unique_results.append(match )
unique_results.sort(key=lambda x: x["score" ], reverse=True )
top_results = unique_results[:top_k]
context = "\n\n" .join([m["metadata" ]["text" ] for m in top_results])
prompt = f"""Answer using the provided context.
Context:
{context}
Original Question: {question}
Answer:"""
response = await self .llm.complete(prompt)
return {"answer" : response, "variants_used" : variants}
async def generate_query_variants (self, question: str , num_variants: int ):
"""Generate alternative phrasings of the question."""
prompt = f"""Generate {num_variants} alternative phrasings of this question:
Question: {question}
Return only the alternative questions, one per line."""
response = await self .llm.complete(prompt)
variants = [line.strip() for line in response.split("\n" ) if line.strip()]
return variants[:num_variants]
Chunking Strategies Challenge: Documents must be split into chunks that fit in context windows while preserving semantic meaning.
Strategy 1: Fixed-Size Chunking Method: Split by character/token count with overlap
def fixed_size_chunking (text: str , chunk_size: int = 512 , overlap: int = 50 ):
"""Split text into fixed-size chunks with overlap."""
chunks = []
start = 0
while start < len (text):
end = start + chunk_size
chunk = text[start:end]
chunks.append(chunk)
start = end - overlap
return chunks
text = "..." * 10000
chunks = fixed_size_chunking(text, chunk_size=512 , overlap=50 )
Pros: Simple, predictable
Cons: May split mid-sentence, breaks semantic units
Strategy 2: Sentence-Based Chunking Method: Split by sentences, group to target size
import nltk
def sentence_chunking (text: str , target_size: int = 512 ):
"""Chunk by sentences to preserve semantic boundaries."""
sentences = nltk.sent_tokenize(text)
chunks = []
current_chunk = []
current_length = 0
for sentence in sentences:
sentence_length = len (sentence)
if current_length + sentence_length > target_size and current_chunk:
chunks.append(" " .join(current_chunk))
current_chunk = [sentence]
current_length = sentence_length
else :
current_chunk.append(sentence)
current_length += sentence_length
if current_chunk:
chunks.append(" " .join(current_chunk))
return chunks
chunks = sentence_chunking(long_document, target_size=512 )
Pros: Preserves sentence integrity
Cons: Variable chunk sizes, may exceed token limits
Strategy 3: Recursive Splitting (Best Practice) Method: Split by paragraph → sentence → words as needed
from langchain.text_splitter import RecursiveCharacterTextSplitter
def recursive_chunking (text: str , chunk_size: int = 512 , overlap: int = 50 ):
"""Intelligently split text preserving structure."""
splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=overlap,
separators=["\n\n" , "\n" , ". " , " " , "" ]
)
chunks = splitter.split_text(text)
return chunks
chunks = recursive_chunking(document, chunk_size=512 )
Pros: Preserves structure, semantic integrity
Cons: Slightly more complex
Strategy 4: Semantic Chunking (Advanced) Method: Split where semantic similarity drops
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
async def semantic_chunking (text: str , threshold: float = 0.7 ):
"""Split text where semantic similarity drops below threshold."""
sentences = nltk.sent_tokenize(text)
embeddings = [await embed(s) for s in sentences]
chunks = []
current_chunk = [sentences[0 ]]
for i in range (1 , len (sentences)):
similarity = cosine_similarity(
[embeddings[i-1 ]],
[embeddings[i]]
)[0 ][0 ]
if similarity < threshold:
chunks.append(" " .join(current_chunk))
current_chunk = [sentences[i]]
else :
current_chunk.append(sentences[i])
if current_chunk:
chunks.append(" " .join(current_chunk))
return chunks
chunks = await semantic_chunking(document, threshold=0.7 )
Pros: Preserves semantic coherence
Cons: Expensive (embeddings for every sentence), slower
Embedding Selection Model Dimensions Performance Cost Use Case text-embedding-3-small (OpenAI)1536 Good $ General purpose text-embedding-3-large (OpenAI)3072 Better $$ High accuracy needed text-embedding-ada-002 (OpenAI)1536 Good $ Legacy (still good) all-MiniLM-L6-v2 (Open)384 OK Free Budget-constrained all-mpnet-base-v2 (Open)768 Better Free Self-hosted instructor-xl (Open)768 Best (open) Free Domain-specific
General use: text-embedding-3-small ($0.02 per 1M tokens)
High accuracy: text-embedding-3-large
Budget: all-MiniLM-L6-v2 (self-hosted)
Domain-specific: Fine-tune instructor-xl
RAG Evaluation Metrics
Precision@K: % of retrieved docs that are relevant
Recall@K: % of relevant docs that were retrieved
MRR (Mean Reciprocal Rank): Average position of first relevant doc
NDCG (Normalized Discounted Cumulative Gain): Ranking quality
Answer Relevance: Does answer address the question?
Faithfulness: Is answer grounded in retrieved context?
Context Relevance: Is retrieved context actually relevant?
from ragas import evaluate
from ragas.metrics import answer_relevancy, faithfulness, context_relevancy
def evaluate_rag (test_cases ):
"""Evaluate RAG system performance."""
results = []
for case in test_cases:
question = case ["question" ]
ground_truth = case ["answer" ]
rag_result = rag_system.query(question)
results.append({
"question" : question,
"contexts" : rag_result["contexts" ],
"answer" : rag_result["answer" ],
"ground_truth" : ground_truth
})
scores = evaluate(
results,
metrics=[answer_relevancy, faithfulness, context_relevancy]
)
return scores
Response Approach When helping with RAG systems:
Understand use case: What documents? What queries?
Recommend architecture: Basic, reranked, hybrid, multi-query?
Design chunking: Fixed, sentence, recursive, semantic?
Select embedding: Based on accuracy/cost trade-off
Choose vector DB: Based on scale and features
Implement retrieval: Top-K, hybrid, reranking
Optimize prompts: Context formatting, instructions
Evaluate: Measure and improve metrics
Your role: Help developers build production-ready RAG systems with optimal chunking, retrieval, and generation strategies.