Advanced RAG Example
This example demonstrates advanced features of MongoDB-RAG, including custom preprocessing, metadata filtering, and integration with an LLM for question answering.
Prerequisites
Install additional dependencies:
npm install mongodb-rag dotenv openai
Advanced Configuration Example
import { MongoRAG } from 'mongodb-rag';
import { OpenAI } from 'openai';
import dotenv from 'dotenv';
dotenv.config();
// Initialize OpenAI client
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY
});
async function createAdvancedRAGSystem() {
// Custom document preprocessor
const documentPreprocessor = (doc) => {
return {
...doc,
content: doc.content.trim(),
metadata: {
...doc.metadata,
processedDate: new Date(),
wordCount: doc.content.split(' ').length
}
};
};
// Initialize MongoRAG with advanced configuration
const rag = new MongoRAG({
mongoUrl: process.env.MONGODB_URI,
database: 'ragAdvanced',
collection: 'documents',
embedding: {
provider: 'openai',
apiKey: process.env.OPENAI_API_KEY,
model: 'text-embedding-ada-002',
batchSize: 100 // Custom batch size for embeddings
},
preprocessing: {
documentPreprocessor,
chunkSize: 500, // Split documents into 500-token chunks
chunkOverlap: 50 // 50-token overlap between chunks
},
search: {
maxResults: 5, // Return top 5 matches
minScore: 0.7 // Minimum similarity score threshold
}
});
return rag;
}
// Advanced QA function using RAG results
async function answerQuestion(rag, question, metadata = {}) {
// Search with metadata filters
const searchResults = await rag.search(question, {
filter: metadata,
maxResults: 3
});
// Format context from search results
const context = searchResults
.map(result => result.content)
.join('\n\n');
// Generate answer using OpenAI
const completion = await openai.chat.completions.create({
model: 'gpt-4',
messages: [
{
role: 'system',
content: 'You are a helpful assistant. Use the provided context to answer questions accurately.'
},
{
role: 'user',
content: `Context: ${context}\n\nQuestion: ${question}`
}
],
temperature: 0.7,
max_tokens: 500
});
return {
answer: completion.choices[0].message.content,
sources: searchResults.map(result => ({
content: result.content,
score: result.score,
metadata: result.metadata
}))
};
}
// Example usage
async function main() {
const rag = await createAdvancedRAGSystem();
await rag.connect();
// Example documents with metadata
const documents = [
{
title: 'Vector Search Setup',
content: 'Setting up Vector Search in MongoDB Atlas requires selecting the proper index type...',
metadata: {
category: 'setup',
difficulty: 'intermediate'
}
},
{
title: 'Performance Optimization',
content: 'To optimize vector search performance, consider index size and dimension reduction...',
metadata: {
category: 'optimization',
difficulty: 'advanced'
}
}
];
// Ingest documents
await rag.ingestBatch(documents);
// Answer a question with metadata filtering
const response = await answerQuestion(
rag,
'How do I optimize vector search performance?',
{ difficulty: 'advanced' }
);
console.log('Answer:', response.answer);
console.log('Sources:', response.sources);
}
main().catch(console.error);
Advanced Features Explained
1. Custom Document Preprocessing
- Document enhancement with metadata
- Custom chunking strategy
- Batch processing optimization
2. Metadata Filtering
- Filter search results by metadata fields
- Combine semantic search with metadata constraints
- Flexible query conditions
3. Advanced Search Configuration
- Customizable similarity thresholds
- Result count control
- Score-based filtering
4. LLM Integration
- Context formatting
- Prompt engineering
- Source attribution
5. Error Handling and Monitoring
// Error handling example
async function robustSearch(rag, question, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await rag.search(question);
} catch (error) {
console.error(`Attempt ${i + 1} failed:`, error);
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
}
// Monitoring example
const searchWithMetrics = async (rag, question) => {
const startTime = Date.now();
const results = await rag.search(question);
const duration = Date.now() - startTime;
console.log(`Search metrics:
- Duration: ${duration}ms
- Results found: ${results.length}
- Average score: ${results.reduce((acc, r) => acc + r.score, 0) / results.length}
`);
return results;
};
Best Practices
-
Document Processing
- Implement robust text cleaning
- Consider domain-specific preprocessing
- Optimize chunk sizes for your use case
-
Search Optimization
- Balance precision vs. recall
- Use appropriate similarity thresholds
- Implement caching for frequent queries
-
Performance
- Monitor memory usage
- Implement connection pooling
- Use appropriate batch sizes
-
Security
- Implement proper API key management
- Validate and sanitize input
- Monitor usage and implement rate limiting