241 lines
7.1 KiB
Markdown
241 lines
7.1 KiB
Markdown
# Embeddings And Semantic Search Setup
|
|
|
|
This guide explains how to set up and use the new vector-based semantic search for the Learning Hub.
|
|
|
|
## What This Enables
|
|
|
|
- **Semantic search** - Find content by meaning, not just keywords
|
|
- **3 search modes**:
|
|
- **Keyword** (`/api/learning/search`) - Traditional text matching
|
|
- **Semantic** (`/api/learning/search/semantic`) - AI-powered vector similarity
|
|
- **Hybrid** (`/api/learning/search/hybrid`) - Combines both for best results
|
|
- **Auto-embedding** - Content is automatically vectorized when created/updated
|
|
- **Gateway-routed** - Uses LiteLLM embeddings so provider policy stays in one place
|
|
|
|
## Prerequisites
|
|
|
|
### 1. Install pgvector Extension
|
|
|
|
The database needs the `pgvector` extension for vector operations:
|
|
|
|
```bash
|
|
# For PostgreSQL 16 on Ubuntu/Debian
|
|
sudo apt-get install postgresql-16-pgvector
|
|
|
|
# For PostgreSQL 15
|
|
sudo apt-get install postgresql-15-pgvector
|
|
|
|
# For Docker (add to Dockerfile or docker-compose)
|
|
# The postgres:16-alpine base image doesn't include pgvector by default
|
|
# You'll need to use a custom image or install at runtime
|
|
```
|
|
|
|
**For Docker deployments**, use this postgres image instead:
|
|
```yaml
|
|
postgres:
|
|
image: pgvector/pgvector:pg16
|
|
# ... rest of your config
|
|
```
|
|
|
|
### 2. Configure LiteLLM Embeddings
|
|
|
|
Add to your `.env` file:
|
|
|
|
```bash
|
|
LITELLM_API_BASE=http://localhost:4000
|
|
LITELLM_API_KEY=your-key
|
|
EMBEDDING_MODEL=openai-text-embedding-3-large
|
|
EMBEDDING_DIMENSIONS=3072
|
|
```
|
|
|
|
## Available Embedding Models
|
|
|
|
The Admin embedding search reads LiteLLM `/model/info` and only shows models with `model_info.mode = "embedding"`. Do not add app-side built-in Vertex/OpenAI embedding lists; configure those choices in LiteLLM.
|
|
|
|
The local LiteLLM instance currently exposes examples such as `openai-text-embedding-3-large`, `openai-text-embedding-3-small`, and Mistral embedding models. Dimensions are read from LiteLLM metadata when available.
|
|
|
|
## Setup Steps
|
|
|
|
### 1. Database Migration
|
|
|
|
The database will automatically:
|
|
- Enable the `pgvector` extension
|
|
- Add `embedding vector(768)` column to `learning_content`
|
|
- Create IVFFLAT index for fast similarity search (after 10+ embeddings)
|
|
|
|
Just restart your server after installing pgvector.
|
|
|
|
### 2. Generate Embeddings for Existing Content
|
|
|
|
Two options:
|
|
|
|
**Option A: Admin API (recommended)**
|
|
```bash
|
|
curl -X POST http://localhost:3000/api/admin/learning/embeddings/generate \
|
|
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"regenerateAll": false}'
|
|
```
|
|
|
|
**Option B: Via Admin Panel**
|
|
- Go to Admin → Learning Hub → Settings
|
|
- Click "Generate Embeddings" button
|
|
- Check status at `/api/admin/learning/embeddings/status`
|
|
|
|
### 3. Verify Setup
|
|
|
|
Check embedding status:
|
|
```bash
|
|
curl http://localhost:3000/api/admin/learning/embeddings/status \
|
|
-H "Authorization: Bearer YOUR_JWT_TOKEN"
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"enabled": true,
|
|
"total": 50,
|
|
"withEmbeddings": 50,
|
|
"missing": 0,
|
|
"model": "openai-text-embedding-3-large",
|
|
"dimensions": 3072
|
|
}
|
|
```
|
|
|
|
## Using Semantic Search
|
|
|
|
### Keyword Search (existing)
|
|
```bash
|
|
GET /api/learning/search?q=pneumonia
|
|
```
|
|
Returns exact text matches in title/subject/body.
|
|
|
|
### Semantic Search (new)
|
|
```bash
|
|
GET /api/learning/search/semantic?q=childhood breathing problems&limit=10&threshold=0.5
|
|
```
|
|
Returns content similar by **meaning** (e.g., finds "pediatric asthma" articles).
|
|
|
|
**Parameters:**
|
|
- `q` (required) - Search query
|
|
- `limit` (optional, default 10, max 50) - Max results
|
|
- `threshold` (optional, default 0.5) - Similarity threshold (0-1, higher = more similar)
|
|
- `contentType` (optional) - Filter by type: article, quiz, pearl, presentation
|
|
|
|
### Hybrid Search (recommended)
|
|
```bash
|
|
GET /api/learning/search/hybrid?q=fever management
|
|
```
|
|
Combines keyword + semantic for best results. Automatically deduplicates and ranks by relevance.
|
|
|
|
## How It Works
|
|
|
|
1. **Content Creation/Update**:
|
|
- Text is extracted from `title`, `subject`, and `body` (HTML stripped)
|
|
- Sent to the configured LiteLLM embedding model
|
|
- Returns an embedding vector
|
|
- Stored in `learning_content.embedding` column
|
|
|
|
2. **Semantic Search**:
|
|
- Query text → embedding vector
|
|
- PostgreSQL pgvector computes cosine similarity
|
|
- Returns top N most similar documents
|
|
- Similarity score 0-1 (1 = identical, 0 = unrelated)
|
|
|
|
3. **Hybrid Search**:
|
|
- Runs both keyword + semantic searches in parallel
|
|
- Merges results (semantic first for quality)
|
|
- Deduplicates by content ID
|
|
- Sorts by relevance score
|
|
|
|
## Cost Estimate
|
|
|
|
Embedding cost depends on the upstream configured in LiteLLM.
|
|
|
|
## Troubleshooting
|
|
|
|
### "pgvector extension not available"
|
|
- Install: `apt-get install postgresql-16-pgvector`
|
|
- For Docker: Use `pgvector/pgvector:pg16` image
|
|
|
|
### "Embeddings not configured"
|
|
- Verify `.env` has `LITELLM_API_BASE`
|
|
- Test: `curl http://localhost:3000/api/admin/learning/embeddings/status`
|
|
|
|
### "Embedding generation failed"
|
|
- Check logs for API errors
|
|
- Verify LiteLLM `/model/info` shows the selected model with `mode: embedding`
|
|
- Check content isn't empty (skips empty bodies)
|
|
|
|
### "No results from semantic search"
|
|
- Check if embeddings exist: `/api/admin/learning/embeddings/status`
|
|
- Lower threshold: `?threshold=0.3` (default 0.5)
|
|
- Verify pgvector index exists: `\di` in psql
|
|
|
|
## Performance
|
|
|
|
- **Embedding generation**: latency depends on the LiteLLM upstream
|
|
- **Search latency**:
|
|
- Keyword: 10-50ms
|
|
- Semantic: 20-100ms (with IVFFLAT index)
|
|
- Hybrid: 30-150ms
|
|
- **Index build time**: ~1-5 seconds per 1,000 articles
|
|
|
|
## Security And Compliance
|
|
|
|
- **Compliance**: controlled by the upstream provider configured in LiteLLM
|
|
- **Data retention**: Embeddings stored in your database only
|
|
- **No PHI**: Only article content (not patient data) is embedded
|
|
- **Encryption**: TLS in transit, at-rest encryption via PostgreSQL
|
|
|
|
## Example Queries
|
|
|
|
**Before (keyword):**
|
|
```
|
|
Query: "fever in babies"
|
|
Results: Only articles with exact words "fever" or "babies"
|
|
```
|
|
|
|
**After (semantic):**
|
|
```
|
|
Query: "fever in babies"
|
|
Results:
|
|
- Infant hyperthermia management (similarity: 0.89)
|
|
- Pediatric fever evaluation (similarity: 0.87)
|
|
- Febrile seizures in toddlers (similarity: 0.82)
|
|
- Neonatal temperature regulation (similarity: 0.78)
|
|
```
|
|
|
|
**Hybrid (best):**
|
|
```
|
|
Query: "asthma"
|
|
Results:
|
|
- Childhood asthma management (keyword + semantic: 1.0)
|
|
- Pediatric breathing difficulties (semantic: 0.91)
|
|
- Reactive airway disease (semantic: 0.86)
|
|
- Bronchiolitis vs asthma (keyword: 1.0)
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### Admin Endpoints
|
|
|
|
- `POST /api/admin/learning/embeddings/generate` - Backfill embeddings
|
|
- `GET /api/admin/learning/embeddings/status` - Check status
|
|
- `GET /api/admin/learning/stats` - Includes embedding count
|
|
|
|
### User Endpoints
|
|
|
|
- `GET /api/learning/search` - Keyword search
|
|
- `GET /api/learning/search/semantic` - Semantic search
|
|
- `GET /api/learning/search/hybrid` - Hybrid search (recommended)
|
|
|
|
All endpoints require authentication (JWT token).
|
|
|
|
---
|
|
|
|
**Questions?** Check logs for detailed error messages, or review the code in:
|
|
- `/src/utils/embeddings.js` - Core embedding logic
|
|
- `/src/routes/learningHub.js` - Search endpoints
|
|
- `/src/routes/learningAdmin.js` - Admin management
|