pgvector-hybrid-search
Skill4 starsChanged 3 months agoMITView on GitHub
Production PostgreSQL & pgvector Hybrid Vector Search RAG Architecture. Implements native vector embeddings with HNSW/IVFFlat indexes, full-text TSVECTOR search, in-database Reciprocal Rank Fusion (RRF), Supabase/Prisma ORM integration, and connection pooling.
In this repository19 other files it gives its agents.
- agent-introspection-debuggingSkill
- airops-programmatic-content-engineSkill
- api-designSkill
- code-review-and-qualitySkill
- enterprise-rag-knowledge-systemsSkill
- eval-harnessSkill
- geo-aeo-agent-optimizationSkill
- langchain-agent-patternsSkill
- mcp-server-patternsSkill
- multi-agent-crew-patternsSkill
- openai-agents-sdkSkill
- prd-criticSkill
- product-spec-generatorSkill
- prompt-engineerSkill
- security-and-hardeningSkill
- security-reviewSkill
- signal-based-ai-agentSkill
- tdd-workflowSkill
- ui-ux-pro-maxSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 125
HNSW vs IVFFlat: Use HNSW for highest query QPS and accuracy without requiring table warming.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
🐘 PostgreSQL + pgvector Hybrid Search & RAG Architecture
pgvector turns PostgreSQL into a high-performance vector database. Combining pgvector dense similarity search with PostgreSQL native Full-Text Search (tsvector) provides production-grade Hybrid RAG without requiring an external vector DB.
🏗️ Schema Setup (pgvector + tsvector)
-- 1. Enable pgvector extension
CREATE EXTENSION IF NOT EXISTS vector;
-- 2. Create Knowledge Base Table
CREATE TABLE document_chunks (
id BIGSERIAL PRIMARY KEY,
document_id UUID NOT NULL,
content TEXT NOT NULL,
metadata JSONB DEFAULT '{}'::jsonb,
-- Dense Vector Embedding (1536 dimensions for OpenAI / 1024 for Cohere)
embedding vector(1536),
-- Sparse Full-Text Search Vector
fts_tokens tsvector GENERATED ALWAYS AS (to_tsvector('english', content)) STORED,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 3. Create HNSW Vector Index for fast approximate nearest neighbor (ANN) search
CREATE INDEX idx_chunks_embedding_hnsw
ON document_chunks
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- 4. Create GIN Index for Fast Full-Text Search
CREATE INDEX idx_chunks_fts
ON document_chunks
USING gin (fts_tokens);2. In-Database Hybrid Search Query (RRF in SQL)
Perform dense vector search and full-text keyword search in a single SQL query, combining their ranks via Reciprocal Rank Fusion (RRF) ($k = 60$):
WITH vector_search AS (
SELECT id, content, metadata,
ROW_NUMBER() OVER (ORDER BY embedding <=> :query_embedding) AS rank
FROM document_chunks
ORDER BY embedding <=> :query_embedding
LIMIT 50
),
fts_search AS (
SELECT id, content, metadata,
ROW_NUMBER() OVER (ORDER BY ts_rank_cd(fts_tokens, websearch_to_tsquery('english', :query_text)) DESC) AS rank
FROM document_chunks
WHERE fts_tokens @@ websearch_to_tsquery('english', :query_text)
ORDER BY rank
LIMIT 50
)
SELECT
COALESCE(v.id, f.id) AS id,
COALESCE(v.content, f.content) AS content,
COALESCE(v.metadata, f.metadata) AS metadata,
(COALESCE(1.0 / (60 + v.rank), 0.0) + COALESCE(1.0 / (60 + f.rank), 0.0)) AS rrf_score
FROM vector_search v
FULL OUTER JOIN fts_search f ON v.id = f.id
ORDER BY rrf_score DESC
LIMIT 5;3. Python Integration (AsyncPG / SQLAlchemy)
import asyncpg
import numpy as np
async def query_hybrid_rag(pg_pool, query_text: str, query_embedding: list[float], limit: int = 5):
embedding_array = f"[{','.join(map(str, query_embedding))}]"
sql = """
WITH vector_search AS (
SELECT id, content, metadata,
ROW_NUMBER() OVER (ORDER BY embedding <=> $1::vector) AS rank
FROM document_chunks
ORDER BY embedding <=> $1::vector
LIMIT 50
),
fts_search AS (
SELECT id, content, metadata,
ROW_NUMBER() OVER (ORDER BY ts_rank_cd(fts_tokens, websearch_to_tsquery('english', $2)) DESC) AS rank
FROM document_chunks
WHERE fts_tokens @@ websearch_to_tsquery('english', $2)
ORDER BY rank
LIMIT 50
)
SELECT
COALESCE(v.id, f.id) AS id,
COALESCE(v.content, f.content) AS content,
(COALESCE(1.0 / (60 + v.rank), 0.0) + COALESCE(1.0 / (60 + f.rank), 0.0)) AS rrf_score
FROM vector_search v
FULL OUTER JOIN fts_search f ON v.id = f.id
ORDER BY rrf_score DESC
LIMIT $3;
"""
async with pg_pool.acquire() as conn:
rows = await conn.fetch(sql, embedding_array, query_text, limit)
return [dict(r) for r in rows]4. Index Tuning Guidelines
- HNSW vs IVFFlat: Use
HNSWfor highest query QPS and accuracy without requiring table warming. UseIVFFlatonly if memory is strictly constrained. - Distance Metrics:
<=>Cosine Distance (Normalized embeddings, recommended for text).<->L2 Euclidean Distance.<#>Negative Inner Product (Dot product).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

