PGVector-Template
A flexible, production-ready template library for building Retrieval-Augmented Generation (RAG) applications using PostgreSQL with PGVector extensions.
Overview
PGVector-Template provides a robust foundation for implementing vector-based document storage and retrieval systems. It offers a clean abstraction layer over PostgreSQL's PGVector extension, making it easy to build scalable RAG applications with proper document management, metadata handling, and efficient vector search capabilities.
Quick Start
from pgvector_template import DocumentDatabaseManager
from pgvector_template.core.document import BaseDocument
from pgvector_template.models.search import SearchQuery
from pgvector_template.service.document_service import DocumentService, DocumentServiceConfig
# 1. Define your document model
class MyDocument(BaseDocument):
__tablename__ = "my_documents"
# 2. Set up the database: connects, enables pgvector, creates the schema and tables
db = DocumentDatabaseManager(
database_url="postgresql://user:pass@localhost/mydb",
schema_suffix="my_kb",
document_classes=[MyDocument],
)
db.setup()
# 3. Create a service. `my_embedding_provider` is your `BaseEmbeddingProvider` subclass
config = DocumentServiceConfig(document_cls=MyDocument, embedding_provider=my_embedding_provider)
with db.get_session() as session:
service = DocumentService(session, config)
# 4. Insert a corpus: it is split into chunks, embedded and stored
service.corpus_manager.insert_corpus("Your document content here", {}, corpus_id="doc-1")
# 5. Search
results = service.search_client.search(SearchQuery(text="your query", limit=5))
Key Concepts
Corpus vs Document: Understanding the hierarchy is essential:
- Corpus: A complete source document (e.g., a full PDF, article, or book)
- Document: A chunk or segment of a corpus that fits within embedding limits
- Collection: A logical grouping of related corpora (e.g., "legal_docs", "user_manuals")
Example: A 50-page PDF (corpus) might be split into 200 documents (chunks), all sharing the same corpus_id but with different chunk_index values.
Key Features
- Flexible Document Model: Abstract base classes for customizable document schemas
- Vector Search: Optimized HNSW indexing for fast similarity search
- Metadata Management: JSON-based flexible metadata with GIN indexing
- Collection Support: Organize documents into logical collections
- Chunk Management: Handle long content by chunking into retrievable documents
- Smart Upserts: Re-inserting a corpus only re-embeds chunks whose content changed, and skips the write entirely if nothing did
- Database Abstraction: Clean SQLAlchemy-based database layer with schema creation API
- Type Safety: Full Pydantic validation and type hints
- Production Ready: Comprehensive testing and error handling
Architecture
The library is organized into several key components:
- Core: Document models, embedders, search functionality
- Database: Connection management and document database operations
- Service: High-level document service layer
- Types: Shared type definitions and schemas
Installation
Basic Installation
pip install pgvector-template
With Database Driver
For production use, you'll also need a PostgreSQL driver:
# For binary driver (recommended)
pip install pgvector-template psycopg[binary]
# Or for source driver
pip install pgvector-template psycopg
Prerequisites
- Python 3.11+
- PostgreSQL 12+ with PGVector extension
- For development: Additional test dependencies
Configuration
Database Setup
- Install PostgreSQL with PGVector extension
- Create your database and enable the vector extension:
CREATE EXTENSION IF NOT EXISTS vector;
- Set up your connection:
from pgvector_template import DatabaseManager
db_manager = DatabaseManager("postgresql://user:password@localhost:5432/mydb")
db_manager.initialize() # connects and enables the vector extension
create_tables also adds nullable model columns that are missing from existing tables (for example content_hash).
Only the column name and type are applied: indexes, foreign keys, unique constraints and server defaults are not. This is a stopgap until proper migrations are added.
Environment Variables
# Development
DATABASE_URL=postgresql://user:password@localhost:5432/dev_db
Usage Examples
1. Define Your Document Model
from pgvector_template.core.document import BaseDocument, BaseDocumentMetadata
from pydantic import Field
class MyDocumentMetadata(BaseDocumentMetadata):
source_type: str = Field(..., description="Type of source document")
author: str = Field(default="unknown", description="Document author")
class MyDocument(BaseDocument):
__tablename__ = "my_documents"
2. Insert a Corpus
from pgvector_template.core.document import BaseDocumentOptionalProps
optional_props = BaseDocumentOptionalProps(
title="Chapter 1: Introduction",
collection="textbooks",
language="en",
)
with db.get_session() as session:
service = DocumentService(session, config)
result = service.corpus_manager.insert_corpus(
"This is the document content...",
{"source_type": "pdf", "author": "John Doe"}, # corpus metadata
optional_props,
corpus_id="intro-chapter",
)
To insert chunks you have already split and embedded, use insert_documents().
Calling insert_corpus() again with the same corpus_id replaces the corpus. Unchanged chunks reuse their stored vector, and the write is skipped if nothing changed:
result = corpus_manager.insert_corpus(text, {"source": "pdf"}, corpus_id="handbook")
# UpsertResult(corpus_hash=..., skipped=False, embedded=12, reused=0, total=12)
result = corpus_manager.insert_corpus(edited_text, {"source": "pdf"}, corpus_id="handbook")
# UpsertResult(corpus_hash=..., skipped=False, embedded=1, reused=11, total=12)
Rows written before content_hash existed have no hash, so their first upsert re-embeds them.
3. Search Documents
from pgvector_template.models.search import MetadataFilter, SearchQuery
# Semantic search
results = service.search_client.search(SearchQuery(text="how do I reset my password", limit=10))
# Keyword search combined with a metadata filter
results = service.search_client.search(
SearchQuery(
keywords=["password", "reset"],
metadata_filters=[MetadataFilter(field_name="source_type", condition="eq", value="pdf")],
limit=10,
)
)
for r in results:
print(r.score, r.document.content)
4. Read a Corpus Back
corpus = service.corpus_manager.get_full_corpus("intro-chapter")
print(corpus.content, corpus.metadata, len(corpus.documents))
Concept Reference
Core Classes
BaseDocument: Abstract SQLAlchemy model for documents with vector embeddingsBaseDocumentOptionalProps: Pydantic model for optional document propertiesBaseDocumentMetadata: Base schema for structured document metadataBaseEmbeddingProvider: Interface to implement for your embedding modelBaseCorpusManager: Splits, embeds and upserts corpora (insert_corpus,get_full_corpus)BaseSearchClient: Semantic, keyword and metadata search (search)DocumentService: Bundles a corpus manager and a search client over one sessionDatabaseManager/DocumentDatabaseManager: Connection, schema and table setup
Testing
Install dependencies (preferably in a virtualenv) before running tests:
pip install -e .[test]
Unit Tests
python -m unittest
Integration Tests
Integration tests require a PostgreSQL database with PGVector extension. Set up your test database and configure the connection in integ-tests/.env:
python -m unittest discover -s integ-tests
Contributing
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Run the test suite
- Submit a pull request
Development Setup
pip install -e .[dev,test]
ruff check . && ruff format .
ty check .
License
MIT License - see LICENSE file for details.
Links
Metadata
Release files for pgvector-template 0.6.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pgvector_template-0.6.1.tar.gz | 24.7 kB | Without provenance | Details for pgvector_template-0.6.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pgvector_template-0.6.1-py3-none-any.whl | Python 3 | none | any | Details for pgvector_template-0.6.1-py3-none-any.whl |
Total release size: 51.1 kB
Release files / pgvector_template-0.6.1.tar.gz
| Download URL | pgvector_template-0.6.1.tar.gz |
|---|---|
| Size | 24.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7618cd3bd57c0aca0a99b67c8a3a73169f571452eedc6c3d958caa8b8f0c2880
|
|
BLAKE2b-256 checksum How to use checksums |
dbbef5c35540c5b0a743faa4ef5f056c53687e9949b6eb4afc32840c091a6c3a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / pgvector_template-0.6.1-py3-none-any.whl
| Download URL | pgvector_template-0.6.1-py3-none-any.whl |
|---|---|
| Size | 26.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9350144782e63a3c1ad55eea111152985e8943770c25a2ecb3e84f5bf08fa652
|
|
BLAKE2b-256 checksum How to use checksums |
00a8cd6e6d7d885fc054d0fa80bb08c2be049c5358d5b4f48f2ec1bcdc519de4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for pgvector-template 0.6.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.