Merge pull request #128 from sirius0xdev/backend/t_438b663e-pgvector-rag-kb
feat(customer1): add pgvector RAG knowledge base with embedding service
This commit is contained in:
commit
9f9bdba2b7
16 changed files with 486 additions and 1 deletions
18
apps/base/customer1/embedding-service/Dockerfile.embedding
Normal file
18
apps/base/customer1/embedding-service/Dockerfile.embedding
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install sentence-transformers and deps
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# Copy application
|
||||||
|
COPY app.py .
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
|
||||||
|
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" || exit 1
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"]
|
||||||
150
apps/base/customer1/embedding-service/app.py
Normal file
150
apps/base/customer1/embedding-service/app.py
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
"""
|
||||||
|
Lightweight embedding service wrapping nomic-embed-text-v1.5
|
||||||
|
OpenAI-compatible /v1/embeddings endpoint.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import uuid
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
from fastapi import FastAPI, HTTPException
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
|
# Model globals (loaded at startup)
|
||||||
|
_model = None
|
||||||
|
_tokenizer = None
|
||||||
|
_dimensions = 768 # nomic-embed-text-v1.5 output dimensions
|
||||||
|
_model_name = "nomic-embed-text-v1.5"
|
||||||
|
|
||||||
|
|
||||||
|
def load_model():
|
||||||
|
"""Load the embedding model at startup."""
|
||||||
|
global _model, _tokenizer
|
||||||
|
from sentence_transformers import SentenceTransformer
|
||||||
|
|
||||||
|
model_path = os.getenv("MODEL_PATH", _model_name)
|
||||||
|
print(f"Loading model: {model_path}")
|
||||||
|
_model = SentenceTransformer(model_path, device="cpu")
|
||||||
|
_model.max_seq_length = 8192 # nomic supports long contexts
|
||||||
|
print(f"Model loaded. Dimensions: {_model.get_sentence_embedding_dimension()}")
|
||||||
|
_dimensions = _model.get_sentence_embedding_dimension()
|
||||||
|
|
||||||
|
|
||||||
|
@asynccontextmanager
|
||||||
|
async def lifespan(app: FastAPI):
|
||||||
|
"""Startup: load model."""
|
||||||
|
load_model()
|
||||||
|
yield
|
||||||
|
# Shutdown: no cleanup needed for CPU model
|
||||||
|
|
||||||
|
|
||||||
|
app = FastAPI(
|
||||||
|
title="Embedding Service",
|
||||||
|
description="OpenAI-compatible embedding service using nomic-embed-text-v1.5",
|
||||||
|
version="1.0.0",
|
||||||
|
lifespan=lifespan,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# --- Request/Response Models ---
|
||||||
|
|
||||||
|
class EmbeddingInput(BaseModel):
|
||||||
|
input: str | list[str] = Field(..., description="Text to embed. Can be a string or list of strings.")
|
||||||
|
model: str = Field(default=_model_name, description="Model name. Only nomic-embed-text-v1.5 is supported.")
|
||||||
|
encoding_format: str = Field(default="float", description="Output format. Only 'float' is supported.")
|
||||||
|
|
||||||
|
|
||||||
|
class EmbeddingObject(BaseModel):
|
||||||
|
object: str = "embedding"
|
||||||
|
embedding: list[float]
|
||||||
|
index: int
|
||||||
|
|
||||||
|
|
||||||
|
class UsageInfo(BaseModel):
|
||||||
|
prompt_tokens: int
|
||||||
|
total_tokens: int
|
||||||
|
|
||||||
|
|
||||||
|
class EmbeddingResponse(BaseModel):
|
||||||
|
object: str = "list"
|
||||||
|
data: list[EmbeddingObject]
|
||||||
|
model: str
|
||||||
|
usage: UsageInfo
|
||||||
|
|
||||||
|
|
||||||
|
# --- Endpoints ---
|
||||||
|
|
||||||
|
@app.post("/v1/embeddings")
|
||||||
|
def create_embeddings(req: EmbeddingInput) -> EmbeddingResponse:
|
||||||
|
"""Create embeddings for input text(s). OpenAI-compatible."""
|
||||||
|
# Normalize input to list
|
||||||
|
if isinstance(req.input, str):
|
||||||
|
texts = [req.input]
|
||||||
|
else:
|
||||||
|
texts = req.input
|
||||||
|
|
||||||
|
if not texts:
|
||||||
|
raise HTTPException(status_code=400, detail="Input must not be empty.")
|
||||||
|
|
||||||
|
if len(texts) > 2048:
|
||||||
|
raise HTTPException(status_code=400, detail="Input must have at most 2048 elements.")
|
||||||
|
|
||||||
|
# Generate embeddings
|
||||||
|
start = time.time()
|
||||||
|
embeddings = _model.encode(
|
||||||
|
texts,
|
||||||
|
normalize_embeddings=True, # cosine similarity ready
|
||||||
|
show_progress_bar=False,
|
||||||
|
).tolist()
|
||||||
|
|
||||||
|
elapsed = time.time() - start
|
||||||
|
|
||||||
|
# Build response
|
||||||
|
data = []
|
||||||
|
total_tokens = 0
|
||||||
|
for i, (text, emb) in enumerate(zip(texts, embeddings)):
|
||||||
|
tokens = len(text.split()) # rough token count
|
||||||
|
total_tokens += tokens
|
||||||
|
data.append(EmbeddingObject(
|
||||||
|
object="embedding",
|
||||||
|
embedding=emb,
|
||||||
|
index=i,
|
||||||
|
))
|
||||||
|
|
||||||
|
return EmbeddingResponse(
|
||||||
|
object="list",
|
||||||
|
data=data,
|
||||||
|
model=req.model,
|
||||||
|
usage=UsageInfo(
|
||||||
|
prompt_tokens=total_tokens,
|
||||||
|
total_tokens=total_tokens,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/v1/models")
|
||||||
|
def list_models():
|
||||||
|
"""List available models. OpenAI-compatible."""
|
||||||
|
return {
|
||||||
|
"object": "list",
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": _model_name,
|
||||||
|
"object": "model",
|
||||||
|
"created": int(time.time()),
|
||||||
|
"owned_by": "self",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
def health():
|
||||||
|
"""Health check."""
|
||||||
|
return {
|
||||||
|
"status": "healthy",
|
||||||
|
"model": _model_name,
|
||||||
|
"dimensions": _dimensions,
|
||||||
|
"ready": _model is not None,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: embedding-service
|
||||||
|
namespace: customer1
|
||||||
|
labels:
|
||||||
|
app: embedding-service
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: embedding-service
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: embedding-service
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: embedding-service
|
||||||
|
image: gcr.io/devops-lab-cluster/embedding-service:1.0.0
|
||||||
|
ports:
|
||||||
|
- containerPort: 8000
|
||||||
|
name: http
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: MODEL_NAME
|
||||||
|
value: "nomic-embed-text-v1.5"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "500m"
|
||||||
|
memory: "2Gi"
|
||||||
|
limits:
|
||||||
|
cpu: "2000m"
|
||||||
|
memory: "4Gi"
|
||||||
|
startupProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 8000
|
||||||
|
initialDelaySeconds: 60
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 12
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 8000
|
||||||
|
initialDelaySeconds: 180
|
||||||
|
periodSeconds: 30
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 8000
|
||||||
|
initialDelaySeconds: 60
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
16
apps/base/customer1/embedding-service/embedding-service.yaml
Normal file
16
apps/base/customer1/embedding-service/embedding-service.yaml
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: embedding-service
|
||||||
|
namespace: customer1
|
||||||
|
labels:
|
||||||
|
app: embedding-service
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app: embedding-service
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 8000
|
||||||
|
targetPort: 8000
|
||||||
|
protocol: TCP
|
||||||
6
apps/base/customer1/embedding-service/kustomization.yaml
Normal file
6
apps/base/customer1/embedding-service/kustomization.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- embedding-deployment.yaml
|
||||||
|
- embedding-service.yaml
|
||||||
7
apps/base/customer1/embedding-service/requirements.txt
Normal file
7
apps/base/customer1/embedding-service/requirements.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
fastapi==0.115.0
|
||||||
|
uvicorn[standard]==0.32.0
|
||||||
|
sentence-transformers==3.3.0
|
||||||
|
torch==2.5.1
|
||||||
|
transformers==4.46.0
|
||||||
|
numpy==2.1.0
|
||||||
|
pydantic==2.10.0
|
||||||
5
apps/base/customer1/hermes-db/.dockerignore
Normal file
5
apps/base/customer1/hermes-db/.dockerignore
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# .dockerignore for pgvector image builds
|
||||||
|
.git
|
||||||
|
*.md
|
||||||
|
*.yaml
|
||||||
|
*.yml
|
||||||
29
apps/base/customer1/hermes-db/Dockerfile.postgres-pgvector
Normal file
29
apps/base/customer1/hermes-db/Dockerfile.postgres-pgvector
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Custom PostgreSQL 15 image with pgvector extension
|
||||||
|
# Based on CNPG's official image - must preserve OS user, entrypoint, and PGDATA
|
||||||
|
FROM ghcr.io/cloudnative-pg/postgresql:15.2
|
||||||
|
|
||||||
|
# pgvector version (latest stable as of 2026-05)
|
||||||
|
ARG PGVECTOR_VERSION=0.8.0
|
||||||
|
|
||||||
|
# Install build dependencies for compiling pgvector from source
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
git \
|
||||||
|
&& \
|
||||||
|
cd /tmp && \
|
||||||
|
git clone --branch "v${PGVECTOR_VERSION}" --depth 1 https://github.com/pgvector/pgvector.git && \
|
||||||
|
cd pgvector && \
|
||||||
|
make && \
|
||||||
|
make install && \
|
||||||
|
apt-get remove -y build-essential git && \
|
||||||
|
apt-get autoremove -y && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm -rf /var/lib/apt/lists/* /tmp/pgvector
|
||||||
|
|
||||||
|
# Verify pgvector is installed
|
||||||
|
RUN pg_config --version && \
|
||||||
|
ls -la /usr/lib/postgresql/*/lib/vector.so
|
||||||
|
|
||||||
|
# CNPG requirements: same OS user (1000), same entrypoint, same PGDATA
|
||||||
|
# The base image already sets these correctly, so no changes needed.
|
||||||
12
apps/base/customer1/hermes-db/agent-memory-rag-db.yaml
Normal file
12
apps/base/customer1/hermes-db/agent-memory-rag-db.yaml
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: Database
|
||||||
|
metadata:
|
||||||
|
name: agent-memory-rag
|
||||||
|
namespace: customer1
|
||||||
|
spec:
|
||||||
|
cluster:
|
||||||
|
name: hermes-pgdb
|
||||||
|
name: agent_memory
|
||||||
|
owner: memory
|
||||||
|
sql:
|
||||||
|
- "@rag-db-init.sql"
|
||||||
|
|
@ -8,6 +8,9 @@ resources:
|
||||||
- memory-db-credentials.yaml
|
- memory-db-credentials.yaml
|
||||||
- trading-data-db.yaml
|
- trading-data-db.yaml
|
||||||
- agent-memory-db.yaml
|
- agent-memory-db.yaml
|
||||||
|
- agent-memory-rag-db.yaml
|
||||||
- hermes-scheduled-backup.yaml
|
- hermes-scheduled-backup.yaml
|
||||||
- kafka-broker.yaml
|
- kafka-broker.yaml
|
||||||
- redis-cluster.yaml
|
- redis-cluster.yaml
|
||||||
|
- rag-init-sql-configmap.yaml
|
||||||
|
- rag-init-job.yaml
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,20 @@ metadata:
|
||||||
|
|
||||||
spec:
|
spec:
|
||||||
instances: 1
|
instances: 1
|
||||||
imageName: ghcr.io/cloudnative-pg/postgresql:15.2
|
# Custom image with pgvector extension
|
||||||
|
imageName: "gcr.io/devops-lab-cluster/postgres-pgvector:15.2-0.8.0"
|
||||||
storage:
|
storage:
|
||||||
size: 20Gi
|
size: 20Gi
|
||||||
|
|
||||||
|
# pgvector extension configuration
|
||||||
|
sharedPreloadLibraries:
|
||||||
|
- pgvector
|
||||||
|
|
||||||
|
postgresql:
|
||||||
|
parameters:
|
||||||
|
# pgvector HNSW index memory settings
|
||||||
|
maintenance_work_mem: "256MB"
|
||||||
|
|
||||||
managed:
|
managed:
|
||||||
roles:
|
roles:
|
||||||
- name: hermes
|
- name: hermes
|
||||||
|
|
|
||||||
35
apps/base/customer1/hermes-db/rag-db-init.sql
Normal file
35
apps/base/customer1/hermes-db/rag-db-init.sql
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
-- RAG knowledge base initialization SQL
|
||||||
|
-- Applied to agent_memory database via CNPG Database resource
|
||||||
|
|
||||||
|
CREATE EXTENSION IF NOT EXISTS vector;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS documents (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
metadata JSONB DEFAULT '{}'::jsonb,
|
||||||
|
embedding vector(768),
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_documents_embedding_hnsw
|
||||||
|
ON documents USING hnsw (embedding vector_cosine_ops);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_documents_content
|
||||||
|
ON documents USING gin (to_tsvector('english', content));
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_documents_metadata
|
||||||
|
ON documents USING gin (metadata);
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION update_documents_updated_at()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
NEW.updated_at = now();
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_documents_updated_at
|
||||||
|
BEFORE UPDATE ON documents
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE FUNCTION update_documents_updated_at();
|
||||||
41
apps/base/customer1/hermes-db/rag-init-job.yaml
Normal file
41
apps/base/customer1/hermes-db/rag-init-job.yaml
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Job to initialize RAG schema in agent_memory database
|
||||||
|
# Runs once after the cluster is available with pgvector
|
||||||
|
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: init-rag-schema
|
||||||
|
namespace: customer1
|
||||||
|
annotations:
|
||||||
|
"helm.sh/hook": post-install,post-upgrade
|
||||||
|
"helm.sh/hook-delete-policy": hook-succeeded
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
containers:
|
||||||
|
- name: psql
|
||||||
|
image: ghcr.io/cloudnative-pg/postgresql:15.2
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
PGPASSWORD=$(cat /run/secrets/postgresql/password) psql \
|
||||||
|
-h hermes-pgdb-rpostgres.customer1.svc.cluster.local \
|
||||||
|
-p 5432 \
|
||||||
|
-U memory \
|
||||||
|
-d agent_memory \
|
||||||
|
-f /sql/rag-db-init.sql
|
||||||
|
env:
|
||||||
|
- name: PGPASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: memory-db-credentials
|
||||||
|
key: password
|
||||||
|
volumeMounts:
|
||||||
|
- name: rag-sql
|
||||||
|
mountPath: /sql
|
||||||
|
volumes:
|
||||||
|
- name: rag-sql
|
||||||
|
configMap:
|
||||||
|
name: rag-init-sql
|
||||||
45
apps/base/customer1/hermes-db/rag-init-sql-configmap.yaml
Normal file
45
apps/base/customer1/hermes-db/rag-init-sql-configmap.yaml
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: rag-init-sql
|
||||||
|
namespace: customer1
|
||||||
|
data:
|
||||||
|
rag-db-init.sql: |
|
||||||
|
-- Enable pgvector extension
|
||||||
|
CREATE EXTENSION IF NOT EXISTS vector;
|
||||||
|
|
||||||
|
-- Documents table for RAG knowledge base
|
||||||
|
CREATE TABLE IF NOT EXISTS documents (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
metadata JSONB DEFAULT '{}'::jsonb,
|
||||||
|
embedding vector(768),
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- HNSW index for vector similarity search (cosine distance)
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_documents_embedding_hnsw
|
||||||
|
ON documents USING hnsw (embedding vector_cosine_ops);
|
||||||
|
|
||||||
|
-- Full-text search index
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_documents_content
|
||||||
|
ON documents USING gin (to_tsvector('english', content));
|
||||||
|
|
||||||
|
-- Metadata filter index
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_documents_metadata
|
||||||
|
ON documents USING gin (metadata);
|
||||||
|
|
||||||
|
-- Auto-update updated_at timestamp
|
||||||
|
CREATE OR REPLACE FUNCTION update_documents_updated_at()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
NEW.updated_at = now();
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_documents_updated_at
|
||||||
|
BEFORE UPDATE ON documents
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE FUNCTION update_documents_updated_at();
|
||||||
52
apps/base/customer1/hermes-db/rag-schema.sql
Normal file
52
apps/base/customer1/hermes-db/rag-schema.sql
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
-- ============================================================
|
||||||
|
-- RAG Knowledge Base Schema for agent_memory database
|
||||||
|
-- Embedding dimensions: 768 (nomic-embed-text-v1.5)
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
-- Enable pgvector extension
|
||||||
|
CREATE EXTENSION IF NOT EXISTS vector;
|
||||||
|
|
||||||
|
-- Documents table for RAG knowledge base
|
||||||
|
CREATE TABLE IF NOT EXISTS documents (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
metadata JSONB DEFAULT '{}'::jsonb,
|
||||||
|
embedding vector(768),
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Index on content for full-text search
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_documents_content ON documents USING gin (to_tsvector('english', content));
|
||||||
|
|
||||||
|
-- HNSW index for vector similarity search (cosine distance)
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_documents_embedding_hnsw ON documents USING hnsw (embedding vector_cosine_ops);
|
||||||
|
|
||||||
|
-- Index on metadata for filtering
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_documents_metadata ON documents USING gin (metadata);
|
||||||
|
|
||||||
|
-- Updated_at trigger
|
||||||
|
CREATE OR REPLACE FUNCTION update_documents_updated_at()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
NEW.updated_at = now();
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_documents_updated_at
|
||||||
|
BEFORE UPDATE ON documents
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE FUNCTION update_documents_updated_at();
|
||||||
|
|
||||||
|
-- Comments for documentation
|
||||||
|
COMMENT ON TABLE documents IS 'RAG knowledge base documents with vector embeddings';
|
||||||
|
COMMENT ON COLUMN documents.content IS 'Full text content of the document';
|
||||||
|
COMMENT ON COLUMN documents.metadata IS 'JSON metadata: source, chunk_id, title, tags, etc.';
|
||||||
|
COMMENT ON COLUMN documents.embedding IS '768-dim vector embedding (nomic-embed-text-v1.5)';
|
||||||
|
|
||||||
|
-- Example query for similarity search:
|
||||||
|
-- SELECT id, content, metadata, 1 - (embedding <=> 'your_embedding_here'::vector) AS similarity
|
||||||
|
-- FROM documents
|
||||||
|
-- ORDER BY embedding <=> 'your_embedding_here'::vector
|
||||||
|
-- LIMIT 5;
|
||||||
|
|
@ -9,6 +9,7 @@ resources:
|
||||||
- ../../base/customer1/paaas-landing/
|
- ../../base/customer1/paaas-landing/
|
||||||
- ../../base/customer1/hermes-agent/
|
- ../../base/customer1/hermes-agent/
|
||||||
- ../../base/customer1/hermes-db/
|
- ../../base/customer1/hermes-db/
|
||||||
|
- ../../base/customer1/embedding-service/
|
||||||
- ../../base/customer1/trade-dashboard/
|
- ../../base/customer1/trade-dashboard/
|
||||||
- ../../base/customer1/siriusdevops-db/
|
- ../../base/customer1/siriusdevops-db/
|
||||||
- ../../base/customer1/trading-platform/
|
- ../../base/customer1/trading-platform/
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue