📝 Development Notes
Documents bugs, design decisions, and agent flow for a chatbot backend using Gemini, Pinecone, and a plugin system.
What this file does
Documents bugs, design decisions, and agent flow for a chatbot backend using Gemini, Pinecone, and a plugin system.
When to use it
- Debugging a multi-model AI backend with fallback logic
- Designing a RAG pipeline with vector database and session memory
- Planning a plugin architecture for external API integrations
- Reviewing production readiness of a chatbot service
Assumes this stack
📝 Development Notes
🤖 AI-Generated vs Manual Code
AI-Generat### 5. Memory Management
Problem: Risk of memory leaks with unlimited message storage Solution: Implemented automatic message cleanup:
// Keep only last 10 messages per session
if (session.messages.length > 10) {
session.messages = session.messages.slice(-10);
}
6. Pinecone Integration Issues
Problem: Dimension mismatch between Google GenAI embeddings and Pinecone index
// ❌ This failed - wrong dimensions
await index.upsert([{ id, values: embedding }]); // 768 dimensions
// ✅ Fixed with proper embedding model
const embedding = await genAI.getGenerativeModel({ model: 'text-embedding-004' })
.embedContent(text); // 3072 dimensions
Solution: Used text-embedding-004 model and properly configured Pinecone index with 3072 dimensions.
7. Gemini API Overload Handling
Problem: Models returning 503 errors during high usage periods, fallback responses were confusing
// ❌ Generated fallback responses when APIs failed
return "I apologize, but I'm experiencing technical difficulties...";
// ✅ Return proper HTTP error codes
return res.status(503).json({
error: "Service temporarily unavailable",
message: "All AI models are currently overloaded. Please try again later.",
code: 503
});
Solution: Implemented multi-model retry with exponential backoff and clean HTTP error responses.ents (with GitHub Copilot assistance):
- Initial project structure - Used Copilot for boilerplate Express setup
- TypeScript interfaces (
src/types/index.ts) - AI suggested comprehensive type definitions - Plugin templates - Basic plugin structure and math evaluation logic
- README sections - Parts of documentation and example curl commands
- Error handling patterns - Standard Express error handling structures
Manual Implementation (Human-written):
- Core architecture design - System design and component interaction patterns
- Vector store algorithm - Custom cosine similarity implementation
- Memory management strategy - Session-based conversation memory logic
- Prompt engineering - All system prompts and context injection logic
- Plugin intent detection - Custom keyword matching and query analysis
- Agent orchestration flow - Complete integration of RAG + Memory + Plugins
- Business logic - All controllers and service coordination
Mixed Approach:
- Vector search implementation - Started with AI template, heavily customized for our needs
- Plugin execution system - AI structure, manual business logic
- API responses - AI suggested JSON structure, manual error handling and metadata
🐛 Bugs Faced and Solutions
1. Google GenAI API Issues
Problem: getGenerativeModel method not found, incorrect API initialization
// ❌ This didn't work
const genAI = new GoogleGenAI(apiKey);
// ✅ Fixed with proper options object
const genAI = new GoogleGenAI({ apiKey });
Solution: Read the official Google GenAI documentation and corrected the initialization pattern.
2. TypeScript Strict Mode Conflicts
Problem: exactOptionalPropertyTypes causing issues with conditional properties
// ❌ This failed type checking
pluginsUsed: pluginsUsed.length > 0 ? pluginsUsed : undefined
// ✅ Fixed with object spread
...(pluginsUsed.length > 0 && { pluginsUsed })
Solution: Used object spread syntax to conditionally include optional properties.
3. Vector Embedding Complexity
Problem: Initially tried to use ml-distance package but it had TypeScript issues
Solution: Implemented custom cosine similarity function with proper null checks:
function cosineSimilarity(a: number[], b: number[]): number {
// Custom implementation with safety checks
for (let i = 0; i < a.length; i++) {
const aVal = a[i] || 0; // Handle undefined values
const bVal = b[i] || 0;
}
}
4. File System Access Issues
Problem: Array indexing with potential undefined values in file reading
// ❌ Potential undefined access
const chunk = chunks[i];
await this.addDocument(chunks[i], metadata);
// ✅ Added safety check
const chunk = chunks[i];
if (chunk) {
await this.addDocument(chunk, metadata);
}
Solution: Added explicit undefined checks before processing chunks.
5. Memory Management
Problem: Risk of memory leaks with unlimited message storage Solution: Implemented automatic message cleanup:
// Keep only last 10 messages per session
if (session.messages.length > 10) {
session.messages = session.messages.slice(-10);
}
🔄 Agent Flow: RAG + Memory + Plugins
Complete Request Processing Flow:
-
Input Validation
- Check required fields (message, session_id)
- Validate API key availability
-
Memory Retrieval
// Add current message to session memoryManager.addMessage(session_id, message, 'user'); // Get conversation context const sessionSummary = memoryManager.getSessionSummary(session_id); -
RAG Context Retrieval
// Vector search for relevant documents const relevantContext = await vectorStore.search(message, 3); // Truncate contexts to fit prompt limits const contextDocs = relevantContext.map(doc => ({ ...doc, content: truncateContext(doc.content, 300) })); -
Plugin Execution
// Check which plugins can handle the query const pluginResults = await pluginManager.executePlugins(message); // Filter successful results const pluginsUsed = pluginResults .filter(result => result.success) .map(result => result.pluginName); -
Prompt Engineering
// Build comprehensive prompt with all context const prompt = PromptEngine.buildPrompt( message, // Current user message sessionSummary, // Conversation history contextDocs, // RAG retrieved documents pluginResults // Plugin execution results ); -
LLM Generation
// Generate response using Google Gemini const result = await model.generateContent(prompt); const aiResponse = result.response.text(); // Clean and format response const formattedResponse = PromptEngine.formatResponse(aiResponse); -
Memory Storage
// Store AI response for future context memoryManager.addMessage(session_id, formattedResponse, 'assistant'); -
Response Assembly
// Include metadata about what was used const response = { response: formattedResponse, sessionId: session_id, ...(pluginsUsed.length > 0 && { pluginsUsed }), ...(contextUsed.length > 0 && { contextUsed }) };
🎯 Key Design Decisions
1. Pinecone Vector Database over Custom Implementation
- Decision: Use Pinecone cloud vector database with Google GenAI embeddings
- Reason: Production-ready scaling, 3072-dimensional embeddings, better similarity search
- Trade-off: External dependency, requires API key, but much more robust than in-memory
2. Multi-Model Fallback Strategy
- Decision: Implement fallback chain: gemini-1.5-flash → gemini-pro → gemini-1.5-pro
- Reason: Reliability when models are overloaded, different quota limits
- Implementation: Exponential backoff retry with clean HTTP error codes
3. Plugin Architecture with Real APIs
- Decision: Interface-based plugin system with real API integrations
- Reason: Extensible, testable, production-ready data sources
- Implementation: OpenWeather API for weather, mathjs for calculations, realistic fallbacks
4. Prompt Engineering Approach
- Decision: Custom prompt builder with structured context injection
- Reason: Full control over how context, memory, and plugins are presented to the LLM
- Structure: System prompt + Memory + Context + Plugins + Current message
5. Clean Error Handling over Fallback Responses
- Decision: Return proper HTTP status codes (503, 500) instead of generated fallback content
- Reason: Professional API behavior, clear error communication, better debugging
- Implementation: 503 for overloaded models, 500 for configuration errors
⚡ Performance Considerations
Current Optimizations:
- Pinecone vector database for efficient similarity search
- Google GenAI embeddings (3072 dimensions) for better semantic understanding
- Session-based memory with automatic cleanup (10 messages max)
- Multi-model retry logic with exponential backoff
- Proper HTTP status codes for better client handling
Production Features:
- Real OpenWeather API integration with realistic fallbacks
- Comprehensive logging and error tracking
- Clean separation of concerns with proper TypeScript interfaces
- Environment-based configuration with validation
🚀 Recent Improvements & Production Readiness
Latest Updates (August 2025):
1. Pinecone Vector Database Integration
- Migrated from in-memory vector storage to production Pinecone
- Auto-index creation with 3072-dimensional Google GenAI embeddings
- Successfully loaded 26 documents with proper chunking
- Eliminated O(n) search limitations with proper vector database
2. Multi-Model Fallback System
- Implemented robust retry logic: gemini-1.5-flash → gemini-pro → gemini-1.5-pro
- Exponential backoff with 2s, 4s delays between retries
- Comprehensive error handling for 503 (overloaded), 429 (quota), 404 (not found)
- Detailed logging with emoji indicators for better debugging
3. OpenWeather API Integration
- Real weather data integration with proper API key handling
- Realistic city-based fallback simulation when API key missing
- Professional error handling with graceful degradation
- Comprehensive weather data including temperature, humidity, wind speed
4. Clean Error Handling
- Removed fallback response generation in favor of proper HTTP codes
- 503 "Service temporarily unavailable" when all models overloaded
- 500 "Internal server error" for missing API keys
- Professional API behavior suitable for production clients
5. Enhanced Logging & Monitoring
- Detailed request tracing with emoji indicators
- Plugin execution tracking with success/failure states
- Model retry attempts with clear failure reasons
- Session and memory usage statistics
System Status:
- ✅ Production Ready: Clean error codes, proper fallbacks, comprehensive logging
- ✅ Scalable: Pinecone integration handles large document sets efficiently
- ✅ Reliable: Multi-model fallback ensures high availability
- ✅ Extensible: Plugin system ready for additional integrations
- ✅ Maintainable: Clear separation of concerns, comprehensive TypeScript types
🧪 Testing Strategy
Manual Testing Approach:
- Basic Agent: Test simple Q&A without context
- Memory: Multiple messages in same session
- RAG: Questions about dataset content
- Weather Plugin: Various weather queries
- Math Plugin: Different mathematical expressions
- Combined: Complex queries triggering multiple systems
Example Test Scenarios:
# Memory persistence test
curl -X POST http://localhost:3001/agent/message -d '{"message":"My name is John","session_id":"test1"}'
curl -X POST http://localhost:3001/agent/message -d '{"message":"What is my name?","session_id":"test1"}'
# Multi-plugin execution test
curl -X POST http://localhost:3001/agent/message -d '{"message":"Weather in Mumbai and calculate 5*7","session_id":"test2"}'
# RAG context test
curl -X POST http://localhost:3001/agent/message -d '{"message":"Tell me about markdown blogging","session_id":"test3"}'
# Error handling test (missing message)
curl -X POST http://localhost:3001/agent/message -d '{"session_id":"test4"}'
🚀 Deployment Readiness
Environment Variables Required:
GEMINI_API- Essential - Google Gemini AI API key for LLM functionalityPINECONE_API- Essential - Pinecone vector database API key for RAGOPEN_WEATHER_API- Optional - OpenWeather API for real weather dataPORT- For platform deployment (Render, Railway, etc.)
Production Considerations:
- ✅ Rate limiting - Handled by Gemini API and Pinecone quotas
- ✅ Proper logging - Comprehensive emoji-based logging implemented
- ✅ Health checks -
/statusendpoint with detailed system information - ✅ Error handling - Clean HTTP status codes and proper error messages
- ✅ API authentication - Individual API key management per service
- Database persistence - Currently using session-based memory (consider Redis)
- Error monitoring - Consider Sentry for production deployments
The system is production-ready with proper error handling, multi-model fallback, and comprehensive logging. All major functionality is implemented and tested successfully.
Total Development Time: ~8-10 hours (including architecture, implementation, debugging, API integrations, and comprehensive documentation) Current Status: Production-ready with 26 vectorized documents, multi-model AI fallback, real weather API integration, and professional error handling
What's inside
7 sections covering bugs, agent flow, design decisions, performance, improvements, testing, and deployment
Change this for your project
- Replace
GEMINI_APIwith your own Google Gemini API key environment variable name - Replace
PINECONE_APIwith your own Pinecone API key environment variable name - Replace
OPEN_WEATHER_APIwith your own OpenWeather API key environment variable name - Replace
gemini-1.5-flashwith your preferred Gemini model ID
Where it goes
Keep it in your repository where the agent or team that needs it will read it.
Worth borrowing
- Multi-model fallback chain with exponential backoff for API overload
- Session memory cleanup to keep only last N messages
- Conditional object spread for optional properties in TypeScript
Related Documents
Building SupportX AI Assist: A Multi-Agent IT Support System
Describes building a multi-agent IT support system with AutoGen, Azure AI Search, and Gemini embeddings for instant issue resolution and automatic escalation.
An Introduction to Transformers
Presents a slide deck introducing transformer architecture, attention mechanisms, and a PyTorch implementation from scratch.
SMART-CAM (Smart AI Camera) — Full Documentation
Documents an edge AI surveillance pipeline that detects people, extracts ReID embeddings, and tracks identities locally on a Raspberry Pi with optional Hailo NPU acceleration.
Building an AI Travel Assistant with Micronaut and LangChain4j
Builds a Micronaut travel advisor that embeds user queries, runs vector similarity search in Oracle AI Database, and returns semantically matched destinations via a chat endpoint.