RAG Setup Guide
This guide walks you through setting up Retrieval Augmented Generation (RAG) with Astreus, enabling your agents to search and reference document content in their responses.
Overview
RAG allows agents to:
- Search through document collections using semantic similarity
- Reference specific information from documents in responses
- Maintain up-to-date knowledge without retraining
- Provide citations and sources for their answers
- Automatically create required database tables when first used
Quick Start
Here's a complete example to get you started with RAG:
import { createAgent, createProvider, createMemory, createDatabase, createRAG } from '@astreus-ai/astreus';
async function setupRAGAgent() {
// 1. Initialize core components (no manual schema setup needed)
const db = await createDatabase();
const memory = await createMemory({ database: db }); // Creates memories table
const provider = createProvider({
type: 'openai',
model: 'gpt-4o-mini',
apiKey: process.env.OPENAI_API_KEY
});
// 2. Create Vector RAG system (automatically creates RAG tables)
const rag = await createRAG({
type: 'vector',
database: db,
provider: provider,
tableName: 'knowledge_base',
chunkSize: 1000,
chunkOverlap: 200
});
// 3. Create agent (creates agents table when needed)
const agent = await createAgent({
name: 'KnowledgeAgent',
provider: provider,
memory: memory,
systemPrompt: `You are a knowledgeable assistant with access to a document database.
When answering questions, search for relevant information and cite your sources.`
});
// 4. Add RAG tools to agent
const ragTools = rag.createRAGTools();
ragTools.forEach(tool => agent.addTool(tool));
return { agent, rag };
}
// Use the RAG-enabled agent
const { agent, rag } = await setupRAGAgent();
// Add some documents (RAG tables created automatically on first document)
await rag.addDocument({
title: "Company Handbook",
content: "Our company values include integrity, innovation, and customer focus. We believe in creating value for all stakeholders...",
metadata: {
type: "policy",
department: "HR",
lastUpdated: "2024-01-15"
}
});
// Agent can now search and reference documents
const response = await agent.chat({
stream: true,
message: "What are our company values?",
sessionId: "hr-inquiry",
onChunk: (chunk) => console.log(chunk)
});
Step-by-Step Setup
Step 1: Choose Your RAG Type
Astreus supports two RAG types with automatic table creation:
Vector RAG (Recommended for most use cases):
- Uses semantic similarity search
- Better for large document collections
- Supports document chunking
- Requires OpenAI API for embeddings
- Creates vector-optimized tables automatically
Document RAG (For simpler use cases):
- Uses keyword-based search
- Better for smaller document sets
- No embedding costs
- Faster setup
- Creates text-search optimized tables automatically
Step 2: Database Configuration
Single Database Setup (Recommended for getting started)
import { createDatabase } from '@astreus-ai/astreus';
// SQLite (for development) - no manual schema needed
const db = await createDatabase({
type: 'sqlite',
path: './knowledge.db'
});
// PostgreSQL (for production) - no manual schema needed
const db = await createDatabase({
type: 'postgresql',
host: 'localhost',
port: 5432,
database: 'knowledge_base',
username: 'user',
password: 'password'
});
Separate Vector Database (For production with high volume)
// Main database for application data
const mainDB = await createDatabase({
type: 'postgresql',
host: 'main-db-host',
database: 'main_app'
});
// Dedicated vector database for embeddings
const vectorDB = await createDatabase({
type: 'postgresql',
host: 'vector-db-host',
database: 'vector_store'
});
// RAG system with separate databases (creates tables in both automatically)
const rag = await createRAG({
type: 'vector',
database: mainDB, // Main database for metadata
vectorDatabase: vectorDB, // Separate vector database
provider: provider
});
Step 3: Create RAG System
Vector RAG Setup
// Creates vector-optimized tables automatically
const vectorRAG = await createRAG({
type: 'vector',
database: db,
provider: provider,
tableName: 'documents', // Custom table name
chunkSize: 1000, // Size of text chunks
chunkOverlap: 200, // Overlap between chunks
embeddingModel: 'text-embedding-3-small' // OpenAI embedding model
});
// Tables created automatically:
// - documents_documents (document metadata)
// - documents_chunks (text chunks)
// - documents_chunk_associations (for external vector DBs)
Document RAG Setup
// Creates text-search optimized tables automatically
const documentRAG = await createRAG({
type: 'document',
database: db,
tableName: 'documents',
chunkSize: 500,
searchFields: ['title', 'content', 'tags']
});
// Tables created automatically:
// - documents_documents (document metadata and content)
Step 4: Add Documents
The required tables are created automatically when you add your first document:
Adding Individual Documents
// Add a single document (creates tables if they don't exist)
const docId = await rag.addDocument({
title: "Product Manual",
content: "This manual covers installation, configuration, and troubleshooting...",
metadata: {
category: "documentation",
product: "widget-pro",
version: "2.1",
author: "Technical Team",
tags: ["manual", "installation", "troubleshooting"]
}
});
console.log(`Document added with ID: ${docId}`);
Batch Adding Documents
const documents = [
{
title: "Getting Started Guide",
content: "Welcome to our platform. This guide will help you...",
metadata: { category: "onboarding", difficulty: "beginner" }
},
{
title: "Advanced Features",
content: "For experienced users, we offer advanced features...",
metadata: { category: "advanced", difficulty: "expert" }
},
{
title: "API Reference",
content: "Our API provides endpoints for managing resources...",
metadata: { category: "technical", type: "reference" }
}
];
// Add documents in batch (tables created on first document)
for (const doc of documents) {
await rag.addDocument(doc);
}
// Or use Promise.all for parallel processing
await Promise.all(documents.map(doc => rag.addDocument(doc)));
Step 5: Create Agent with RAG
const agent = await createAgent({
name: 'DocumentAssistant',
provider: provider,
memory: memory,
systemPrompt: `You are a helpful assistant with access to company documentation.
When users ask questions, search the knowledge base for relevant information and provide accurate answers with citations.
Guidelines:
- Always search for relevant information before answering
- Cite your sources when referencing documents
- If you can't find relevant information, say so clearly
- Provide specific and actionable answers when possible`
});
// Add RAG tool to agent
const ragTool = rag.getTool();
agent.addTool(ragTool);
Database Table Creation
RAG systems automatically create their required tables when first used:
Vector RAG Tables
When using Vector RAG, these tables are created automatically:
-- Document metadata table (with tableName 'knowledge_base')
CREATE TABLE knowledge_base_documents (
id VARCHAR PRIMARY KEY,
content TEXT,
metadata JSON,
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Document chunks for processing
CREATE TABLE knowledge_base_chunks (
id VARCHAR PRIMARY KEY,
documentId VARCHAR,
content TEXT,
metadata JSON,
embedding JSON,
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (documentId) REFERENCES knowledge_base_documents(id)
);
-- For external vector databases, association tracking
CREATE TABLE knowledge_base_chunk_associations (
chunkId VARCHAR PRIMARY KEY,
documentId VARCHAR,
chunkIndex INTEGER,
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Performance indexes
CREATE INDEX idx_chunks_document ON knowledge_base_chunks(documentId);
Document RAG Tables
When using Document RAG, these tables are created automatically:
-- Document storage with full-text search (with tableName 'documents')
CREATE TABLE documents_documents (
id VARCHAR PRIMARY KEY,
content TEXT,
metadata JSON,
embedding JSON, -- if storeEmbeddings is enabled
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Full-text search indexes
CREATE INDEX idx_documents_content ON documents_documents USING gin(to_tsvector('english', content));
Advanced Configuration
Optimizing Chunk Size
Choose chunk sizes based on your content type:
// For technical documentation (larger chunks for context)
const technicalRAG = await createRAG({
type: 'vector',
database: db,
provider: provider,
tableName: 'technical_docs', // Custom table name
chunkSize: 1500,
chunkOverlap: 300
});
// For FAQ or short-form content (smaller chunks for precision)
const faqRAG = await createRAG({
type: 'vector',
database: db,
provider: provider,
tableName: 'faqs', // Custom table name
chunkSize: 500,
chunkOverlap: 100
});
// For conversational content (medium chunks)
const chatRAG = await createRAG({
type: 'vector',
database: db,
provider: provider,
tableName: 'conversations', // Custom table name
chunkSize: 800,
chunkOverlap: 150
});
Custom Search Parameters
// Search with custom parameters
const results = await rag.search("How to install the software?", 5);
results.forEach(result => {
console.log(`Score: ${result.similarity}`);
console.log(`Title: ${result.metadata.title}`);
console.log(`Content: ${result.content.substring(0, 200)}...`);
});
Multiple RAG Systems
You can use multiple RAG systems for different types of content:
// Create specialized RAG systems (each creates its own tables)
const policyRAG = await createRAG({
type: 'vector',
database: db,
provider: provider,
tableName: 'policies'
});
const technicalRAG = await createRAG({
type: 'vector',
database: db,
provider: provider,
tableName: 'technical_docs'
});
const faqRAG = await createRAG({
type: 'document',
database: db,
tableName: 'faqs'
});
// Add all RAG tools to agent
agent.addTool(policyRAG.getTool());
agent.addTool(technicalRAG.getTool());
agent.addTool(faqRAG.getTool());
// Agent can now search across all knowledge bases
Document Management
Updating Documents
// Get document by ID
const document = await rag.getDocument(docId);
// Update document content
await rag.updateDocument(docId, {
title: "Updated Product Manual",
content: "This updated manual covers new features...",
metadata: {
...document.metadata,
version: "2.2",
lastUpdated: new Date().toISOString()
}
});
Deleting Documents
// Delete a specific document
await rag.deleteDocument(docId);
// Delete documents by metadata
const oldDocs = await rag.listDocuments({
metadata: { version: "1.0" }
});
for (const doc of oldDocs) {
await rag.deleteDocument(doc.id);
}
Listing Documents
// List all documents
const allDocs = await rag.listDocuments({
limit: 50,
offset: 0
});
// List documents with filtering
const policyDocs = await rag.listDocuments({
metadata: { category: "policy" },
limit: 20
});
console.log(`Found ${policyDocs.length} policy documents`);
Production Considerations
Environment Variables
Set up your environment variables:
# .env file
OPENAI_API_KEY=your_openai_api_key
# Database configuration (no manual schema setup needed)
DATABASE_TYPE=postgresql
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=knowledge_base
DATABASE_USER=user
DATABASE_PASSWORD=password
# Vector database (if separate)
VECTOR_DB_HOST=vector-db-host
VECTOR_DB_NAME=vector_store
VECTOR_DB_USER=vector_user
VECTOR_DB_PASSWORD=vector_password
Performance Optimization
// Batch processing for large document sets
async function batchAddDocuments(rag: any, documents: any[], batchSize = 10) {
for (let i = 0; i < documents.length; i += batchSize) {
const batch = documents.slice(i, i + batchSize);
// Process batch in parallel (tables created on first document)
await Promise.all(batch.map(doc => rag.addDocument(doc)));
// Optional: Add delay between batches
if (i + batchSize < documents.length) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
console.log(`Processed ${Math.min(i + batchSize, documents.length)}/${documents.length} documents`);
}
}
// Use batch processing
await batchAddDocuments(rag, largeDocumentSet, 5);
Error Handling
async function robustDocumentAdd(rag: any, document: any, retries = 3) {
for (let attempt = 1; attempt <= retries; attempt++) {
try {
const docId = await rag.addDocument(document);
console.log(`Document added successfully: ${docId}`);
return docId;
} catch (error) {
console.error(`Attempt ${attempt} failed:`, error.message);
if (attempt === retries) {
console.error(`Failed to add document after ${retries} attempts`);
throw error;
}
// Wait before retry
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
}
}
Testing Your RAG Setup
Basic Functionality Test
async function testRAGSetup() {
console.log('Testing RAG setup...');
// Add a test document (creates tables if needed)
const testDocId = await rag.addDocument({
title: "Test Document",
content: "This is a test document for verifying RAG functionality. It contains information about testing procedures.",
metadata: { type: "test", category: "verification" }
});
console.log(`Test document added: ${testDocId}`);
// Test search functionality
const searchResults = await rag.search("testing procedures", 3);
console.log(`Search found ${searchResults.length} results`);
if (searchResults.length > 0) {
console.log('✅ RAG search is working');
console.log(`Top result score: ${searchResults[0].similarity}`);
} else {
console.log('❌ RAG search returned no results');
}
// Test agent integration
const response = await agent.chat({
message: "Tell me about testing procedures",
sessionId: "test-session"
});
console.log('Agent response:', response);
// Clean up test document
await rag.deleteDocument(testDocId);
console.log('Test document cleaned up');
}
// Run the test
await testRAGSetup();
Performance Benchmarking
async function benchmarkRAG() {
const queries = [
"How to install the software?",
"What are the system requirements?",
"How to troubleshoot connection issues?",
"What are the security best practices?",
"How to configure the database?"
];
console.log('Benchmarking RAG performance...');
const startTime = Date.now();
for (const query of queries) {
const queryStart = Date.now();
const results = await rag.search(query, 5);
const queryTime = Date.now() - queryStart;
console.log(`Query: "${query}"`);
console.log(`Time: ${queryTime}ms, Results: ${results.length}`);
}
const totalTime = Date.now() - startTime;
console.log(`Total benchmark time: ${totalTime}ms`);
console.log(`Average query time: ${totalTime / queries.length}ms`);
}
await benchmarkRAG();
Troubleshooting
Common Issues
Tables not created automatically?
- Check database connection and permissions
- Ensure you're calling
rag.addDocument()
to trigger table creation - Verify database type is supported (SQLite or PostgreSQL)
- Check that the database user has CREATE TABLE permissions
No search results returned:
- Check if documents were added successfully
- Verify embedding generation is working (for Vector RAG)
- Lower the similarity threshold
- Check for typos in search queries
Slow search performance:
- Consider using a separate vector database
- Optimize chunk sizes for your content
- Add database indexes (handled automatically)
- Use batch processing for large document sets
High embedding costs:
- Use smaller chunk sizes
- Consider Document RAG for keyword-only search
- Implement caching for repeated queries
- Monitor usage and set limits
Memory issues:
- Process documents in smaller batches
- Use streaming for large files
- Implement proper cleanup
- Monitor database size
Debug Mode
Enable debug logging to troubleshoot issues:
import { logger } from '@astreus-ai/astreus';
// Enable debug logging
logger.level = 'debug';
// Your RAG operations will now show detailed logs
const results = await rag.search("test query");
Next Steps
Once you have RAG working with automatic table creation:
- Expand your knowledge base with more documents
- Optimize chunk sizes based on your content
- Implement document versioning for updates
- Add metadata filtering for better search precision
- Monitor performance and costs in production
- Consider hybrid search combining multiple RAG types
- Trust the automatic table creation - no manual schema needed
For more advanced features, see the RAG Concepts documentation. For more advanced features, see the RAG Concepts documentation.
How is this guide?