소스 정보
- 저장소
- tools-only/X-Skills
- 최근 소스 활동
- 2026년 2월 9일 04:32
- 감지된 SKILL.md 언어
- 영어
- 스타
- 7
- 포크
- 1
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/tools-only/X-Skills --skill rag-pipeline-gen명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
SOC 직업 분류 기준
| name | rag-pipeline-gen |
| type | command |
| description | Generate complete RAG pipeline with embeddings, vector DB, and retrieval |
| category | ai |
| version | 1.0.0 |
| author | Jeremy Longshore |
| shortcut | rpg |
| estimated_time | 5-10 minutes |
Generate a complete, production-ready RAG (Retrieval-Augmented Generation) pipeline with document ingestion, embedding, vector storage, retrieval, and LLM integration.
When you run this command, you'll receive:
/rag-pipeline-gen <vector_db> [options]
Vector Databases: pinecone, qdrant, chromadb, weaviate
Examples:
/rpg pinecone - Generate RAG pipeline with Pinecone/rpg qdrant - Generate RAG pipeline with Qdrant Cloud/rpg chromadb - Generate RAG pipeline with ChromaDB (local development)Input:
/rpg pinecone
Output:
rag-pipeline/
├── src/
│ ├── ingestion/
│ │ ├── __init__.py
│ │ ├── document_loader.py # Load PDFs, text, web pages
│ │ ├── chunker.py # Text chunking strategies
│ │ └── embedder.py # Generate embeddings
│ ├── retrieval/
│ │ ├── __init__.py
│ │ ├── vector_store.py # Vector DB operations
│ │ ├── retriever.py # Query and retrieval
│ │ └── reranker.py # Reranking results
│ ├── generation/
│ │ ├── __init__.py
│ │ ├── llm_client.py # LLM integration
│ │ └── prompt_templates.py # Prompt engineering
│ ├── api/
│ │ ├── __init__.py
│ │ ├── main.py # FastAPI server
│ │ └── models.py # Pydantic models
│ └── config/
│ ├── __init__.py
│ └── settings.py # Configuration
├── tests/
│ ├── __init__.py
│ ├── test_ingestion.py
│ ├── test_retrieval.py
│ └── test_integration.py
├── notebooks/
│ └── evaluation.ipynb # RAG evaluation
├── docker/
│ ├── Dockerfile
│ └── docker-compose.yml
├── requirements.txt
├── .env.example
└── README.md
from pathlib import Path
from typing import List, Dict
import PyPDF2
from langchain.text_splitter import RecursiveCharacterTextSplitter
class DocumentLoader:
"""Load and process documents from various sources."""
def __init__(self, chunk_size: int = 1000, chunk_overlap: int = 200):
self.chunker = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
separators=["\n\n", "\n", ". ", " ", ""]
)
def load_pdf(self, file_path: Path) -> List[Dict]:
"""Load and chunk PDF file."""
with open(file_path, 'rb') as file:
pdf_reader = PyPDF2.PdfReader(file)
text = ""
for page_num, page in enumerate(pdf_reader.pages):
text += page.extract_text()
# Chunk text
chunks = self.chunker.split_text(text)
# Create document objects
documents = [
{
"text": chunk,
"metadata": {
"source": (file_path),
: i // ((chunks) // (pdf_reader.pages) + ),
: i
}
}
i, chunk (chunks)
]
documents
() -> []:
(file_path, , encoding=) file:
text = file.read()
chunks = .chunker.split_text(text)
[
{
: chunk,
: {
: (file_path),
: i
}
}
i, chunk (chunks)
]
() -> []:
documents = []
file_path directory.glob():
file_path.suffix == :
documents.extend(.load_pdf(file_path))
file_path.suffix [, ]:
documents.extend(.load_text(file_path))
documents
from typing import List
import openai
from tenacity import retry, stop_after_attempt, wait_exponential
class Embedder:
"""Generate embeddings for text chunks."""
def __init__(
self,
model: str = "text-embedding-3-small",
api_key: str = None
):
self.model = model
self.client = openai.OpenAI(api_key=api_key)
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10)
)
async def embed(self, text: str) -> List[float]:
"""Generate embedding for single text."""
response = await self.client.embeddings.create(
model=self.model,
input=text
)
return response.data[0].embedding
async def embed_batch(
self,
texts: List[str],
batch_size: int =
) -> [[]]:
embeddings = []
i (, (texts), batch_size):
batch = texts[i:i + batch_size]
response = .client.embeddings.create(
model=.model,
=batch
)
batch_embeddings = [item.embedding item response.data]
embeddings.extend(batch_embeddings)
embeddings
from typing import List, Dict, Optional
from pinecone import Pinecone, ServerlessSpec
import hashlib
class PineconeVectorStore:
"""Pinecone vector database operations."""
def __init__(
self,
api_key: str,
index_name: str,
dimension: int = 1536,
metric: str = "cosine"
):
self.pc = Pinecone(api_key=api_key)
self.index_name = index_name
# Create index if doesn't exist
if index_name not in self.pc.list_indexes().names():
self.pc.create_index(
name=index_name,
dimension=dimension,
metric=metric,
spec=ServerlessSpec(cloud="aws", region="us-east-1")
)
self.index = self.pc.Index(index_name)
async def upsert_documents(
self,
documents: List[Dict],
embeddings: List[List[float]],
namespace: str = "default"
):
"""Insert documents with embeddings into vector store."""
vectors = []
doc, embedding (documents, embeddings):
doc_id = ._generate_id(doc)
vectors.append({
: doc_id,
: embedding,
: {
: doc[],
**doc[]
}
})
batch_size =
i (, (vectors), batch_size):
batch = vectors[i:i + batch_size]
.index.upsert(vectors=batch, namespace=namespace)
(vectors)
() -> []:
results = .index.query(
vector=query_embedding,
top_k=top_k,
namespace=namespace,
=,
include_metadata=
)
[
{
: [],
: [],
: [][],
: {
k: v k, v [].items()
k !=
}
}
results[]
]
() -> :
content =
hashlib.md5(content.encode()).hexdigest()
():
.index.delete(namespace=namespace, delete_all=)
from typing import List, Dict
import cohere
from src.ingestion.embedder import Embedder
from src.retrieval.vector_store import PineconeVectorStore
class RAGRetriever:
"""Retrieve and rerank documents for RAG."""
def __init__(
self,
embedder: Embedder,
vector_store: PineconeVectorStore,
cohere_api_key: Optional[str] = None
):
self.embedder = embedder
self.vector_store = vector_store
self.cohere = cohere.Client(cohere_api_key) if cohere_api_key else None
async def retrieve(
self,
query: str,
top_k: int = 5,
initial_k: int = 20,
rerank: bool = True,
namespace: str = "default",
filter: Optional[Dict] = None
) -> List[Dict]:
"""Retrieve relevant documents with optional reranking."""
# 1. Embed query
query_embedding = await self.embedder.embed(query)
k = initial_k rerank top_k
results = .vector_store.search(
query_embedding=query_embedding,
top_k=k,
namespace=namespace,
=
)
rerank .cohere (results) > top_k:
documents = [r[] r results]
reranked = .cohere.rerank(
query=query,
documents=documents,
top_n=top_k,
model=
)
results = [results[r.index] r reranked.results]
results[:top_k]
() -> []:
results_standard = .retrieve(
query=query,
top_k=top_k,
rerank=,
namespace=namespace
)
query_variants = ._generate_query_variants(query)
results_variants = []
variant query_variants[:]:
variant_results = .retrieve(
query=variant,
top_k=top_k,
rerank=,
namespace=namespace
)
results_variants.extend(variant_results)
seen_ids = ()
combined_results = []
result results_standard + results_variants:
result[] seen_ids:
seen_ids.add(result[])
combined_results.append(result)
combined_results.sort(key= x: x[], reverse=)
combined_results[:top_k]
() -> []:
[query]
from typing import List, Dict
from anthropic import AsyncAnthropic
class LLMClient:
"""Generate answers using LLM."""
def __init__(self, api_key: str, model: str = "claude-3-haiku-20240307"):
self.client = AsyncAnthropic(api_key=api_key)
self.model = model
async def generate_answer(
self,
question: str,
context: List[Dict],
max_tokens: int = 1024
) -> Dict:
"""Generate answer using retrieved context."""
# Format context
context_text = "\n\n".join([
f"Source {i+1} ({ctx['metadata'].get('source', 'Unknown')}):\n{ctx['text']}"
for i, ctx in enumerate(context)
])
# Build prompt
prompt = f"""Answer the question using ONLY the provided context. If the answer cannot be found in the context, say "I don't have enough information to answer this question."
Context:
{context_text}
Question: {question}
Answer:"""
# Generate response
message = .client.messages.create(
model=.model,
max_tokens=max_tokens,
messages=[{: , : prompt}]
)
{
: message.content[].text,
: [
{
: ctx[].get(, ),
: ctx[]
}
ctx context
],
: {
: message.usage.input_tokens,
: message.usage.output_tokens
}
}
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional
import asyncio
from src.ingestion.document_loader import DocumentLoader
from src.ingestion.embedder import Embedder
from src.retrieval.vector_store import PineconeVectorStore
from src.retrieval.retriever import RAGRetriever
from src.generation.llm_client import LLMClient
from src.config.settings import Settings
app = FastAPI(title="RAG API", version="1.0.0")
settings = Settings()
# Initialize components
embedder = Embedder(api_key=settings.openai_api_key)
vector_store = PineconeVectorStore(
api_key=settings.pinecone_api_key,
index_name=settings.pinecone_index_name
)
retriever = RAGRetriever(
embedder=embedder,
vector_store=vector_store,
cohere_api_key=settings.cohere_api_key
)
llm = LLMClient(api_key=settings.anthropic_api_key)
class QueryRequest(BaseModel):
question: str
top_k: int = 5
rerank: bool = True
namespace: str = "default"
class QueryResponse(BaseModel):
answer: str
sources: List[Dict]
usage: Dict
@app.post(, response_model=QueryResponse)
():
:
context = retriever.retrieve(
query=request.question,
top_k=request.top_k,
rerank=request.rerank,
namespace=request.namespace
)
result = llm.generate_answer(
question=request.question,
context=context
)
QueryResponse(**result)
Exception e:
HTTPException(status_code=, detail=(e))
():
directory:
namespace: =
():
:
loader = DocumentLoader()
documents = loader.load_directory(Path(request.directory))
texts = [doc[] doc documents]
embeddings = embedder.embed_batch(texts)
num_uploaded = vector_store.upsert_documents(
documents=documents,
embeddings=embeddings,
namespace=request.namespace
)
{
: ,
: num_uploaded
}
Exception e:
HTTPException(status_code=, detail=(e))
():
{: }
__name__ == :
uvicorn
uvicorn.run(app, host=, port=)
FROM python:3.11-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY src/ ./src/
# Environment variables
ENV OPENAI_API_KEY=""
ENV PINECONE_API_KEY=""
ENV ANTHROPIC_API_KEY=""
ENV COHERE_API_KEY=""
# Expose port
EXPOSE 8000
# Run application
CMD ["uvicorn", "src.api.main:app", "--host", "0.0.0.0", "--port", "8000"]
version: '3.8'
services:
rag-api:
build:
context: .
dockerfile: docker/Dockerfile
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- PINECONE_API_KEY=${PINECONE_API_KEY}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- COHERE_API_KEY=${COHERE_API_KEY}
- PINECONE_INDEX_NAME=rag-index
ports:
- "8000:8000"
volumes:
- ./data:/app/data # Mount for document ingestion
fastapi==0.109.0
uvicorn[standard]==0.27.0
anthropic==0.18.1
openai==1.12.0
pinecone-client==3.0.0
cohere==4.47
PyPDF2==3.0.1
langchain==0.1.6
pydantic==2.6.0
pydantic-settings==2.1.0
tenacity==8.2.3
python-multipart==0.0.9
import requests
# Query RAG system
response = requests.post(
"http://localhost:8000/query",
json={
"question": "What is quantum computing?",
"top_k": 5,
"rerank": True
}
)
result = response.json()
print(f"Answer: {result['answer']}")
print(f"Sources: {result['sources']}")
print(f"Tokens: {result['usage']}")
Response:
{
"answer": "Quantum computing is a type of computing that uses quantum-mechanical phenomena...",
"sources": [
{"source": "quantum_physics.pdf", "score": 0.92},
{"source": "computing_basics.pdf", "score": 0.87}
],
"usage": {
"input_tokens": 450,
"output_tokens": 120
}
}
Production-Ready:
Advanced Features:
Manual implementation: 16-24 hours
With this command: 5-10 minutes
ROI: 96-144x time multiplier
Next Steps:
/rpg pinecone or /rpg qdrant or /rpg chromadbpip install -r requirements.txt.env filePOST /ingestPOST /querydocker-compose up -dProduction checklist:
Estimated monthly cost: $50-$200 depending on document volume and query rate.