用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/lebiraja/skills4agents --skill agent-module-rag-system-standard命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | agent-module-rag-system-standard |
| description | Module: Production-Grade RAG System Architecture and Implementation Standard |
agent.module.rag-system-standard1.0.0productionUse this module to architect and deploy RAG systems that augment LLM responses with domain knowledge, documents, or proprietary data.
Apply when:
Do not apply directly when:
Chunked retrieval + semantic ranking + LLM augmentationCore RAG Flow:
User Query
↓
[Embedding Model] (embed query)
↓
[Vector DB] (semantic search)
↓
[Re-ranker] (rank & filter results)
↓
[Context Assembly] (format retrieved docs + metadata)
↓
[LLM Prompt] (augment with context)
↓
[LLM Output] (generate response with attribution)
Exit criteria:
Embedding Model Decision Matrix:
| Criteria | Local (Ollama) | Cloud (AWS/OpenAI/Cohere) | Enterprise (Proprietary) |
|---|---|---|---|
| Latency (single embed) | 50–200ms | 100–500ms | <100ms |
| Throughput (batch) | 1K/sec | 10K–100K/sec | 100K+/sec |
| Cost | ~$0 (hardware) | $0.02–1.00 per 1K embeds | Custom |
| Privacy | ✅ Full | ❌ Cloud-stored | ✅ Full |
| Dimensionality | 768–4096 | 1536–3072 | 1024–10000 |
| Quality (MTEB) | 65–75 | 75–85 | 80–95 |
Best for: Privacy-first, cost-sensitive, offline capability.
BAAI/bge-small-en-v1.5 (384 dims)
ollama pull bge-small-enBAAI/bge-base-en-v1.5 (768 dims)
ollama pull bge-base-enBAAI/bge-large-en-v1.5 (1024 dims)
ollama pull bge-large-enSentence-Transformers/all-mpnet-base-v2 (768 dims)
Best for: Scalability, managed infrastructure, multi-tenant systems.
OpenAI text-embedding-3-small (1536 dims)
OpenAI text-embedding-3-large (3072 dims)
AWS Bedrock Amazon Titan Embeddings (1536 dims)
Cohere Embed API (1024 dims)
Anthropic Claude Embeddings (TBD dims)
Proprietary Fine-Tuned Models
Decision Rule:
IF latency < 50ms AND offline required:
→ BAAI bge-large-en-v1.5 (local GPU)
ELIF latency < 100ms AND cost < $0.05:
→ BAAI bge-base-en-v1.5 (local CPU)
ELIF quality > cost (MTEB > 75):
→ OpenAI text-embedding-3-small
ELIF multi-cloud required:
→ AWS Bedrock Titan
ELIF domain-specific (medical/legal):
→ Fine-tuned proprietary model
ELSE:
→ BAAI bge-base-en-v1.5 (default)
Exit criteria:
Vector DB Decision Matrix:
| Database | Deployment | Latency (search) | Scalability | Cost | Best For |
|---|---|---|---|---|---|
| Pinecone | Cloud | 50–100ms | Auto-scale (100M+) | $0.25/unit | Managed, multi-tenant |
| Weaviate | Self-hosted | 10–50ms | Up to 1B vectors | Self-hosted | Privacy, control |
| Milvus | Self-hosted | 10–50ms | Distributed (100M+) | Self-hosted | High-volume, on-prem |
| Qdrant | Self-hosted | 10–50ms | Up to 1B vectors | Self-hosted | Fast, minimal deps |
| Chroma | Local/Docker | 20–100ms | Up to 10M | Open-source | Development, small RAG |
| FAISS | Local library | 5–20ms | Batch-only (no live update) | Open-source | Offline, batch retrieval |
| Elasticsearch | Self-hosted | 50–200ms | 1B+ (with tuning) | Self-hosted | Full-text + vector hybrid |
Qdrant (Recommended for most RAG systems)
docker run -p 6333:6333 qdrant/qdrant:latest
curl -L https://github.com/qdrant/qdrant/releases/download/v1.x.x/qdrant-x86_64-unknown-linux-gnu \
-o qdrant && chmod +x qdrant && ./qdrant
from qdrant_client import QdrantClient
client = QdrantClient("http://localhost:6333")
Milvus (Enterprise-scale self-hosted)
helm repo add milvus https://milvus-io.github.io/milvus-helm/
helm install milvus milvus/milvus
from pymilvus import Collection, connections
connections.connect("default", host="localhost", port=19530)
Weaviate (GraphQL + Vector hybrid)
docker run -p 8080:8080 semitechnologies/weaviate:latest
Pinecone (Zero-ops vector DB)
pip install pinecone-client
import pinecone
pinecone.init(api_key="YOUR_KEY", environment="us-west1-gcp")
index = pinecone.Index("my-index")
index.upsert(vectors=[...])
AWS OpenSearch with Vector Support
Azure Cognitive Search + Vector Search
Chroma (Development-focused)
pip install chromadbimport chromadb
chroma_client = chromadb.Client()
collection = chroma_client.create_collection(name="my_collection")
collection.add(ids=[...], embeddings=[...], documents=[...])
FAISS (Facebook AI Similarity Search - batch only)
pip install faiss-cpuDecision Rule:
IF self-hosted AND < 100M vectors:
→ Qdrant (simplest, fastest)
ELIF self-hosted AND > 100M vectors:
→ Milvus (distributed)
ELIF managed service AND cost not critical:
→ Pinecone (zero-ops)
ELIF AWS ecosystem:
→ OpenSearch Vector
ELIF development/prototyping:
→ Chroma (local)
ELIF batch-only use case:
→ FAISS (fastest)
ELSE:
→ Qdrant (default)
Exit criteria:
Document Ingestion:
Chunking:
Embedding:
Indexing:
Metadata Storage:
Example Indexing Pipeline (Python):
from sentence_transformers import SentenceTransformer
from qdrant_client import QdrantClient
from qdrant_client.models import PointStruct
import hashlib
import time
# Load embedding model
model = SentenceTransformer("BAAI/bge-base-en-v1.5")
# Connect to vector DB
client = QdrantClient("http://localhost:6333")
# Create collection
client.recreate_collection(
collection_name="documents",
vectors_config={"size": 768, "distance": "Cosine"},
)
# Index documents
def index_documents(documents: list[dict]):
"""
Args:
documents: [{"id": "doc1", "content": "...", "source": "..."}, ...]
"""
for doc_id, doc in enumerate(documents):
# Chunk document
chunks = chunk_text(doc["content"], chunk_size=512, overlap=100)
# Embed chunks
embeddings = model.encode(chunks, batch_size=32)
# Prepare points for vector DB
points = []
for chunk_idx, (chunk_text, embedding) in enumerate(zip(chunks, embeddings)):
point_id = int(hashlib.md5(f"{doc['source']}_{chunk_idx}".encode()).hexdigest(), 16) % (10**8)
points.append(PointStruct(
id=point_id,
vector=embedding.tolist(),
payload={
"source": doc["source"],
"chunk_index": chunk_idx,
"chunk_text": chunk_text,
"timestamp": int(time.time()),
}
))
# Upsert to vector DB
client.upsert(collection_name="documents", points=points)
print(f"Indexed {len(points)} chunks from {doc['source']}")
def chunk_text(text: str, chunk_size: int = 512, overlap: int = 100) -> list[str]:
"""Simple chunking by tokens (approximate)."""
words = text.split()
chunks = []
for i in range(0, len(words), chunk_size - overlap):
chunk = " ".join(words[i:i + chunk_size])
if chunk.strip():
chunks.append(chunk)
return chunks
Exit criteria:
Query Embedding:
Vector Search:
Re-ranking:
Context Assembly:
Example Retrieval (Python):
from sentence_transformers import CrossEncoder
# Load re-ranker
reranker = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-12-v2")
def retrieve_context(query: str, top_k: int = 20, rerank_k: int = 3):
"""Retrieve and re-rank documents."""
# Embed query
query_embedding = model.encode(query)
# Vector search
results = client.search(
collection_name="documents",
query_vector=query_embedding.tolist(),
limit=top_k,
)
# Extract documents and scores
documents = []
scores = []
for hit in results:
documents.append(hit.payload["chunk_text"])
scores.append(hit.score)
# Re-rank using cross-encoder
pairs = [[query, doc] for doc in documents]
rerank_scores = reranker.predict(pairs)
# Sort by re-rank scores
ranked = sorted(zip(documents, rerank_scores, scores), key=lambda x: x[1], reverse=True)
# Return top reranked results
return [
{
"content": doc,
"semantic_score": semantic_score,
"rerank_score": rerank_score,
}
for doc, rerank_score, semantic_score in ranked[:rerank_k]
]
def assemble_context(retrieved: list[dict], max_tokens: int = 4000) -> str:
"""Format retrieved context for LLM."""
context_parts = []
token_count = 0
for i, item in enumerate(retrieved):
# Estimate tokens
tokens = len(item["content"].split()) * 1.3
if token_count + tokens > max_tokens:
break
context_parts.append(
f"[Source {i+1}] {item['content']}\n"
f"(Confidence: {item['rerank_score']:.2f})\n"
)
token_count += tokens
return "".join(context_parts)
Exit criteria:
Prompt Engineering:
Generation:
Attribution:
Example RAG Prompt:
def build_rag_prompt(query: str, context: str) -> str:
return f"""You are a helpful assistant answering questions based on provided documents.
Retrieved Context:
{context}
Instructions:
1. Answer the user's question using ONLY the provided context.
2. If the context doesn't contain enough information to answer, say "I don't have enough information."
3. Always cite your sources inline: [Source 1], [Source 2], etc.
4. Be accurate and concise.
User Question: {query}
Answer:"""
def generate_response(query: str, llm_client):
"""Generate RAG response."""
# Retrieve context
retrieved = retrieve_context(query)
context = assemble_context(retrieved)
# Build prompt
prompt = build_rag_prompt(query, context)
# Generate response
response = llm_client.generate(prompt, stream=True)
# Append sources
sources = [f"- {r['content'][:100]}..." for r in retrieved]
full_response = f"{response}\n\nSources:\n" + "\n".join(sources)
return full_response
Exit criteria:
Metrics to Track:
Alerting:
Optimization:
Exit criteria:
| Decision Area | Preferred Option | Alternative | Selection Rule |
|---|---|---|---|
| Embedding Model | BAAI bge-base-en-v1.5 (local) | OpenAI text-embedding-3-small (cloud) | Use local for privacy/cost; cloud for scalability/quality |
| Vector Database | Qdrant (< 100M vectors) | Milvus (> 100M) or Pinecone (managed) | Scale and ops tolerance determine choice |
| Chunking Strategy | 256–512 tokens with 50–100 overlap | Fixed 1K token chunks | Semantic boundaries outperform fixed sizes |
| Re-ranking | Cross-encoder (slow, accurate) | BM25 hybrid (fast) | Accuracy vs latency tradeoff |
| Context Assembly | Semantic + business rules ranking | Random sampling | Deterministic ranking ensures reproducibility |
| Caching Strategy | Query embedding cache (24h) | No cache | Cache layer reduces load 60–80% |
Example Evaluation:
from sklearn.metrics import ndcg_score
import numpy as np
def evaluate_retrieval(queries, ground_truth_docs, retrieved_results):
"""Evaluate retrieval quality using NDCG."""
scores = []
for query, true_docs, retrieved in zip(queries, ground_truth_docs, retrieved_results):
# Binary relevance (0 = not relevant, 1 = relevant)
y_true = [1 if doc in true_docs else 0 for doc in retrieved]
y_score = list(range(len(retrieved), 0, -1)) # Rank positions
ndcg = ndcg_score([y_true], [y_score], k=5)
scores.append(ndcg)
avg_ndcg = np.mean(scores)
print(f"NDCG@5: {avg_ndcg:.3f}")
return avg_ndcg >= 0.7
| Metric | Target | Notes |
|---|---|---|
| Retrieval Latency (p95) | <= 500ms | Includes embedding + search |
| Generation Latency (p95) | <= 1.5s | LLM streaming to first token |
| Total RAG Latency (p95) | <= 2.0s | End-to-end user experience |
| Embedding Model Throughput | >= 1K/sec (batched) | Indexing throughput |
| Vector Search QPS | >= 100 queries/sec | Per instance |
| Retrieval NDCG@5 | >= 0.7 | Relevance metric |
| Hallucination Rate | <= 5% | Manual review sample |
| Citation Accuracy | >= 95% | Source attribution correctness |
| Index Freshness | <= 1 day | Document update latency |
| Availability | >= 99.5% | Vector DB + embedding service |
| Vector DB Storage Efficiency | 10–15 bytes per vector | Compression + metadata |
Risk: Embedding model hallucination (poor retrieval quality).
Risk: Vector DB scale (> 1B vectors, latency degradation).
Risk: Stale documents (outdated information indexed).
Risk: Embedding drift (model updates break similarity scores).
Risk: Privacy leakage (sensitive data in context).
Risk: Cost explosion (large indexing, frequent searches).
Risk: Latency SLA violation (search > 500ms).
This module is reusable across any RAG system. Adapt only:
A RAG system is production-ready only if all are true:
# docker-compose.yml
version: '3.8'
services:
qdrant:
image: qdrant/qdrant:latest
ports:
- "6333:6333"
volumes:
- ./qdrant_storage:/qdrant/storage
# main.py
from sentence_transformers import SentenceTransformer
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams
# Initialize
model = SentenceTransformer("BAAI/bge-base-en-v1.5")
client = QdrantClient("http://localhost:6333")
# Create collection
client.recreate_collection(
collection_name="my_docs",
vectors_config=VectorParams(size=768, distance=Distance.COSINE),
)
# Index documents
documents = ["Machine learning is...", "LLMs can..."]
embeddings = model.encode(documents)
client.upsert(
collection_name="my_docs",
points=[...], # PointStruct with embeddings
)
# Search
query_embedding = model.encode("What is machine learning?")
results = client.search(
collection_name="my_docs",
query_vector=query_embedding,
limit=5,
)
import pinecone
from openai import OpenAI
# Initialize
pinecone.init(api_key="YOUR_KEY", environment="us-west1-gcp")
index = pinecone.Index("my-index")
client = OpenAI()
# Create index
pinecone.create_index(
name="my-index",
dimension=1536,
metric="cosine",
)
# Index documents
documents = ["Machine learning is...", "LLMs can..."]
response = client.embeddings.create(
input=documents,
model="text-embedding-3-small",
)
embeddings = [emb.embedding for emb in response.data]
# Upsert to Pinecone
index.upsert(vectors=[(f"doc-{i}", emb, {}) for i, emb in enumerate(embeddings)])
# Search
query_embedding = client.embeddings.create(
input="What is machine learning?",
model="text-embedding-3-small",
).data[0].embedding
results = index.query(vector=query_embedding, top_k=5)
from sentence_transformers import CrossEncoder
# Re-ranker
reranker = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-12-v2")
# Retrieve candidates
candidates = [...] # From vector DB
# Re-rank
pairs = [[query, doc] for doc in candidates]
scores = reranker.predict(pairs)
ranked = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True)
# Return top-k
return [doc for doc, _ in ranked[:3]]
client.get_collection_info()search_start = time.time()client.get_collection_info()docker logs qdrantdocker-compose restart qdrantCost Comparison (1M queries/month):
# Metadata-based filtering
results = client.search(
collection_name="documents",
query_vector=query_embedding,
query_filter=Filter(
must=[FieldCondition(key="tenant_id", match=MatchValue(value=user_tenant_id))]
),
limit=5,
)
# Elasticsearch with vector support
es = Elasticsearch(["http://localhost:9200"])
# Vector + BM25 hybrid
results = es.search(
index="documents",
body={
"query": {
"bool": {
"must": [
{"knn": {"embedding": {"vector": query_embedding}}},
{"match": {"content": query_text}},
]
}
},
},
)
# Fine-tune embedding model on domain corpus
from sentence_transformers import SentenceTransformer, losses
from torch.utils.data import DataLoader
model = SentenceTransformer("BAAI/bge-base-en-v1.5")
train_examples = [InputExample(texts=[query, pos], label=1)]
train_dataloader = DataLoader(train_examples, shuffle=True, batch_size=32)
train_loss = losses.CosineSimilarityLoss(model)
model.fit(
train_objectives=[(train_dataloader, train_loss)],
epochs=1,
warmup_steps=100,
)
import weaviate
client = weaviate.Client("http://localhost:8080")