Phase completion and enhancement updates: ## Documentation Added - Phase 2 completion: Memory system implementation details - Phase 3 completion: Research capabilities and tool integration - Session documentation: Model testing, VRAM optimization analysis - Test results: Comprehensive prompt testing (v1_verbose: 87/100) - Tool logging implementation guide ## System Prompts - Added prompts.py with 7 tested variants for A/B testing - v1_verbose, v2_concise, v3_imperative, v4_minimal, etc. - Comprehensive testing results for each variant - Production-ready prompt selection guidance ## Memory System Enhancements - Multi-tenancy support: Added user_id parameter throughout - System message filtering: Don't store system messages in history - Improved conversation turn tracking with user isolation - Enhanced memory manager for better multi-user support ## AI Controller Improvements - Better memory integration with user_id support - Enhanced error handling for memory operations - Improved token tracking for usage monitoring - Skip system message storage (part of agent state) ## Portainer Client - Comprehensive API client (148 lines) - Stack management and service monitoring - Container operations with full error handling - Async support for all operations ## Architecture Documentation - Updated agent flow diagrams for ADK architecture - Enhanced core-api README with current setup - Updated Docker compose stack configuration - Complete testing and validation documentation
21 KiB
Phase 2: Memory Systems - Implementation Status & Research Findings
Last Updated: 2025-11-23 Research Completed: 2025-11-23 Status: 85% Complete - Critical Fixes Needed
Executive Summary
Phase 2 memory infrastructure is architecturally sound and follows 2024/2025 industry best practices, but has critical implementation gaps preventing it from working in production.
Architecture Grade: 8.5/10 ⭐⭐⭐⭐ Implementation Status: 🔴 Non-functional (memory storage bypassed)
Current Implementation Review
✅ What's Working (Excellent Foundation)
1. Multi-Tier Memory Architecture
Implementation:
- Tier 1: In-memory buffer (ConversationBufferMemory) - last 10 turns
- Tier 2/3: Unified Qdrant storage (QdrantConversationMemory) - persistent + semantic
Industry Validation:
- ✅ Aligns with hybrid memory architecture recommendations
- ✅ Follows dual-retrieval patterns (episodic + semantic)
- ✅ Buffer size (10 turns) validated by ConvoMem research - shows long context viable up to 150 conversations
Files:
src/memory/tier1_buffer.py- ✅ Fully functionalsrc/memory/qdrant_memory.py- ✅ Fully functionalsrc/memory/manager.py- ✅ Orchestration ready
2. Qdrant Vector Database Selection
Status: ✅ Excellent choice
Industry Support:
- Recommended for agentic vector search
- Used in production long-term memory systems
- n8n workflow templates demonstrate production patterns
Performance Benefits:
- Token consumption reduction: 60-80% vs full conversation histories
- Fast semantic search: < 50ms
- Collection exists:
core_api_conversations
3. Dual-Mode Retrieval
Implementation:
- Tier 2 mode: Chronological retrieval (filter by conversation_id)
- Tier 3 mode: Semantic search (vector similarity)
Industry Alignment: Research shows this is current best practice:
"A customer support copilot pulls the last conversation turns (episodic) while also recalling policy knowledge (semantic), then merges and de-dupes"
4. Auto-Consolidation Logic
Implementation:
- Triggers every 10 messages
- Moves buffer → Qdrant
- Automatic pruning
Industry Alignment: ✅ Solid approach
🔴 Critical Issues (Blocking Production Use)
Issue #1: Memory Storage Bypassed in Agent Path
Problem: Memory storage code is unreachable when unified agent is active (which is 100% of requests).
Location: src/controllers/ai_controller.py:307-386
Root Cause:
# Line 308-372: Agent executes and RETURNS immediately
if AGENT_AVAILABLE:
# ... agent.chat() ...
return response # ← Returns here, never reaches line 377
# Line 377-386: Memory storage (NEVER EXECUTED)
if request.store_in_memory:
await store_conversation_turn(...)
Evidence:
# Qdrant collection stats:
curl http://qdrant:6333/collections/core_api_conversations
{
"points_count": 0, # ← No conversations stored!
"indexed_vectors_count": 0
}
# Logs show memory enabled but nothing stored:
store_in_memory=True # ← Flag is set
# But 0 points in Qdrant
Industry Pattern: Long-term agentic memory shows memory must be:
- Stored BEFORE agent returns (user message)
- Stored AFTER agent completes (assistant response)
- Integrated with agent lifecycle (not in fallback path)
Fix Required: Add memory storage calls inside agent code path (lines 307-372)
Issue #2: Embedding Dimension Mismatch
Problem: Configuration specifies one dimension, Qdrant collection uses another.
Current State:
- Config:
embedding_model = "nomic-embed-text"→ 768 dimensions - Qdrant Collection: 384 dimensions (wrong!)
Evidence:
// From curl http://qdrant:6333/collections/core_api_conversations
{
"config": {
"params": {
"vectors": {
"size": 384, // ← Wrong!
"distance": "Cosine"
}
}
}
}
Industry Guidance: From Ollama embedding models best practices:
- all-minilm: 384d - fastest (14.7ms/1K tokens), CPU-friendly
- nomic-embed-text: 768d - better accuracy (81.2% vs 80.04%), 2048 token context
- mxbai-embed-large: 1024d - highest quality
Performance Research: Nomic vs MiniLM comparison:
- nomic-embed: 81.2% accuracy, 2048 token context, 768d
- all-MiniLM-L6-v2: 80.04% accuracy, blazing fast, 384d
Fix Options:
Option A: Recreate collection for 768d (nomic-embed-text)
# Drop existing collection
curl -X DELETE http://qdrant:6333/collections/core_api_conversations
# Will auto-recreate with 768d on next memory operation
Option B: Switch to 384d model (all-minilm)
# config.py
embedding_model: str = "all-minilm"
embedding_dimension: int = 384
Recommendation:
- For homelab with GPU: Use nomic-embed-text (768d) - better accuracy, longer context
- For speed priority: Use all-minilm (384d) - 6x faster
Advanced Option: Matryoshka embeddings - nomic-embed v1.5 supports variable dimensions (64-768), can truncate 768→384 with minimal accuracy loss
Issue #3: Memory Retrieval Not Implemented
Problem: Agent doesn't load previous conversation context from memory.
Current Behavior:
# ai_controller.py:312-318
history = []
for msg in request.messages[:-1]: # Uses request messages only
history.append({"role": msg.role.value, "content": msg.content})
# ← Should load from memory manager here!
agent = get_unified_agent()
response = agent.chat(message=user_message, conversation_history=history)
Industry Pattern: Redis + LangGraph memory integration:
- Check if conversation_id exists in memory
- Retrieve recent turns from memory manager
- Include in conversation_history passed to LLM
- Fall back to request.messages if no memory
Fix Required:
# Load from memory if conversation exists
memory_manager = get_memory_manager()
if await memory_manager.buffer_memory.conversation_exists(conversation_id):
# Get recent turns from memory
memory_turns = await memory_manager.get_recent_turns(conversation_id, limit=10)
# Convert to history format
history = [{"role": t.role.value, "content": t.content} for t in memory_turns]
else:
# Fall back to request messages
history = [{"role": m.role.value, "content": m.content} for m in request.messages[:-1]]
🟡 Architecture Gaps (Recommended Improvements)
Gap #1: LangGraph Checkpointing Not Used
Current Approach: Custom memory management with manual storage/retrieval.
Industry Standard (2024): LangGraph native persistence via checkpointers:
langgraph-checkpoint-sqlite- For local/devlanggraph-checkpoint-postgres- For production (recommended)langgraph-checkpoint-redis- For high-performance
Benefits You're Missing:
- Thread-scoped state management
- Automatic error recovery at any step
- Human-in-the-loop intervention points
- Time travel debugging
- Cross-thread memory stores
Example from Research: Mastering Persistence in LangGraph:
- Checkpoints save graph state at every super-step
- Enables powerful capabilities: session memory, error recovery, fault tolerance
- Thread-based conversation management
Long-term Recommendation: Consider migrating to LangGraph checkpointers for production. Your current system works but doesn't leverage the framework's full capabilities.
Time Investment: 4-6 hours (bigger refactor)
Gap #2: Cross-Thread Memory Not Implemented
Current Limitation: Memory is conversation-scoped only. No learning across conversations.
Industry Trend (2024/2025): Cross-thread memory stores:
- Remember user preferences across all conversations
- Learn from historical interactions
- Extract and store user facts (name, preferences, context)
Examples:
- MongoDB Store for LangGraph (cross-thread memory)
- mem0 / Cognee (agentic memory systems)
- Redis cross-thread capabilities
Priority: Low (advanced feature for future)
📊 Comparison: Implementation vs Industry Standards
| Feature | Your Status | Industry Standard | Alignment | Priority |
|---|---|---|---|---|
| Multi-tier memory (buffer + vector) | ✅ Implemented | ✅ Recommended | ⭐⭐⭐⭐⭐ Perfect | - |
| Qdrant vector database | ✅ Configured | ✅ Recommended | ⭐⭐⭐⭐⭐ Perfect | - |
| Semantic + chronological search | ✅ Implemented | ✅ Recommended | ⭐⭐⭐⭐⭐ Perfect | - |
| Auto-consolidation (10 turns) | ✅ Implemented | ✅ Recommended | ⭐⭐⭐⭐⭐ Perfect | - |
| Memory storage in agent | ❌ Bypassed | ✅ Required | 🔴 Critical Gap | P1 |
| Embedding dimension match | ❌ Mismatch | ✅ Required | 🔴 Critical Bug | P1 |
| Memory retrieval in context | ❌ Not implemented | ✅ Required | 🔴 Critical Gap | P2 |
| LangGraph checkpointing | ❌ Not used | 🟡 Recommended | 🟡 Optional | P3 |
| Cross-thread memory | ❌ Not implemented | 🟡 Advanced | ⚪ Future | P4 |
| Human-in-the-loop | ❌ Not implemented | 🟡 Advanced | ⚪ Future | P4 |
🎯 Prioritized Action Plan
Priority 1: Critical Fixes 🔴 (MUST DO - 2-3 hours)
Task 1.1: Integrate Memory Storage with Agent Path
Problem: Memory storage unreachable
File: src/controllers/ai_controller.py:307-386
Changes Required:
- Store user message BEFORE agent.chat() call
- Store assistant response AFTER agent returns
- Handle both streaming and non-streaming modes
- Move storage inside try block (lines 309-375)
Code Pattern:
# Before agent call
if request.store_in_memory:
await store_conversation_turn(
conversation_id=conversation_id,
role="user",
content=user_message
)
# Agent executes
response_text = await agent.chat_completion(...)
# After agent returns
if request.store_in_memory:
await store_conversation_turn(
conversation_id=conversation_id,
role="assistant",
content=response_text,
tokens={"prompt": ..., "completion": ..., "total": ...}
)
Success Criteria:
- Qdrant collection
points_count> 0 after API calls - Both user and assistant messages stored
- No errors in logs
Task 1.2: Fix Embedding Dimension Mismatch
Problem: Collection (384d) ≠ Config (768d)
Decision Required: Choose embedding model strategy
Option A: Use nomic-embed-text (768d) - Recommended for GPU homelab
# 1. Drop existing collection
docker exec core-api curl -X DELETE http://qdrant:6333/collections/core_api_conversations
# 2. Collection will auto-recreate with 768d on next memory operation
# 3. Verify in config.py:
# embedding_model = "nomic-embed-text"
# embedding_dimension = 768
Option B: Use all-minilm (384d) - Faster, keep existing collection
# config.py changes:
embedding_model: str = "all-minilm" # Was: nomic-embed-text
embedding_dimension: int = 384 # Was: 768
Success Criteria:
- Collection dimension matches config dimension
- Embeddings generate successfully
- No errors during consolidation
Priority 2: Memory Retrieval 🟡 (SHOULD DO - 1-2 hours)
Task 2.1: Load Previous Conversation Context
Problem: Agent doesn't retrieve past conversations from memory
File: src/controllers/ai_controller.py:312-318
Changes Required:
# Check if conversation exists in memory
memory_manager = get_memory_manager()
conversation_exists = await memory_manager.buffer_memory.conversation_exists(conversation_id)
if conversation_exists:
# Load from memory
memory_turns = await memory_manager.get_recent_turns(conversation_id, limit=10)
history = [{"role": t.role.value, "content": t.content} for t in memory_turns]
else:
# Fall back to request messages
history = []
for msg in request.messages[:-1]:
history.append({"role": msg.role.value, "content": msg.content})
Success Criteria:
- Multi-turn conversations maintain context
- Agent recalls previous messages
- New conversations start fresh (no memory loaded)
Priority 3: Architecture Enhancement 🟡 (NICE TO HAVE - 4-6 hours)
Task 3.1: Migrate to LangGraph Checkpointers
Current: Custom memory management Industry Standard: LangGraph native persistence
Research Sources:
Implementation:
- Add
langgraph-checkpoint-postgresto requirements - Configure checkpointer in agent initialization
- Replace custom memory calls with checkpoint API
- Leverage thread-based conversation management
Benefits:
- Native framework support
- Error recovery at any step
- Human-in-the-loop capabilities
- Time travel debugging
- Easier maintenance
Decision: Defer until current implementation is proven and stable
Priority 4: Advanced Features ⚪ (FUTURE)
Task 4.1: Cross-Thread Memory
Purpose: Remember user preferences across all conversations
Research:
Defer: Until core memory system proven in production
Task 4.2: Memory Summarization
Purpose: Compress old conversations to reduce token usage
Pattern: Conversation Summary Buffer Memory (LangChain docs)
Defer: Until memory usage becomes a concern
Task 4.3: User Fact Extraction
Purpose: Automatically extract and store user preferences, context, facts
Tools: mem0, Cognee (agentic memory systems)
Defer: Advanced feature for future iterations
🧪 Testing Strategy
Phase 1: Unit Tests (After Fixes)
# Run existing test suite
docker exec core-api python /app/tests/test_memory_simple.py
# Expected: All 3 tests pass
# - Embedding Client: ✅
# - Qdrant Memory: ✅
# - Full Integration: ✅
Phase 2: Integration Tests (After P1)
# 1. Make API request
curl -X POST http://localhost:8083/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Tatlock",
"messages": [{"role": "user", "content": "Hello, remember my name is John"}],
"conversation_id": "test_123",
"store_in_memory": true
}'
# 2. Verify storage in Qdrant
docker exec core-api curl -s http://qdrant:6333/collections/core_api_conversations
# Expected: points_count > 0
# 3. Test recall (send follow-up)
curl -X POST http://localhost:8083/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Tatlock",
"messages": [{"role": "user", "content": "What is my name?"}],
"conversation_id": "test_123",
"store_in_memory": true
}'
# Expected: Agent recalls "John"
Phase 3: Persistence Tests (After P2)
# 1. Create conversation
# 2. Restart core-api container
docker restart core-api
# 3. Send follow-up message with same conversation_id
# Expected: Memory persists, agent recalls previous context
📚 Research Sources
Memory Architecture
- Long Term Memory for LLMs using Vector Store
- Build Persistent Chat Memory with Qdrant
- Beyond Vector Databases: True Long-Term AI Memory
- Memory in Agents: Episodic vs Semantic
LangGraph Persistence
- Mastering Persistence in LangGraph
- LangGraph Persistence Docs
- LangGraph v0.2 Checkpointer Libraries
- Long-Term Agentic Memory With LangGraph
- Redis + LangGraph Memory Integration
- MongoDB Cross-Thread Memory
RAG vs Memory
- RAG vs Memory for AI Agents
- The Evolution from RAG to Agent Memory
- Enhancing AI Conversations with LangChain Memory
- Memory and Hybrid Search in RAG
- ConvoMem Benchmark: First 150 Conversations
Embedding Models
- Nomic Embeddings Guide
- Best Open-Source Embedding Models Benchmarked
- Ollama Embedding Models Guide
- Best Ollama Embedding Models for RAG
- Nomic Embed Matryoshka (Variable Dimensions)
Qdrant Best Practices
Timeline Estimate
Priority 1 (Critical Fixes): 2-3 hours
- Task 1.1: Memory storage integration (1.5 hours)
- Task 1.2: Dimension fix (30 minutes)
- Testing (30 minutes)
Priority 2 (Memory Retrieval): 1-2 hours
- Task 2.1: Context loading (1 hour)
- Testing (30 minutes)
Priority 3 (LangGraph Migration): 4-6 hours
- Research and planning (1 hour)
- Implementation (3-4 hours)
- Testing (1 hour)
Total to production-ready: 3-5 hours (P1 + P2) Total with architecture upgrade: 7-11 hours (P1 + P2 + P3)
Success Metrics
Phase 1 Complete (P1 Fixed):
- ✅ Qdrant
points_count> 0 after conversations - ✅ Both user and assistant messages stored
- ✅ No memory-related errors in logs
- ✅ Embeddings match collection dimension
Phase 2 Complete (P2 Fixed):
- ✅ Agent recalls previous conversation context
- ✅ Multi-turn conversations work correctly
- ✅ Memory persists across container restarts
- ✅ New conversations start with empty context
Production Ready:
- ✅ All integration tests pass
- ✅ Memory consolidation triggers correctly
- ✅ Semantic search returns relevant results
- ✅ Performance meets targets (< 50ms retrieval)
Conclusion
Architecture: Excellent (8.5/10) ⭐⭐⭐⭐ Implementation: Incomplete (requires fixes) 🔴
Your design follows current industry best practices for 2024/2025:
- ✅ Multi-tier memory (buffer + vector)
- ✅ Hybrid search (episodic + semantic)
- ✅ Qdrant for production-grade vector storage
- ✅ Auto-consolidation and pruning
The issues are implementation bugs (storage bypassed, dimension mismatch) and missing integration (memory retrieval), NOT architectural flaws.
Recommendation: Complete Priority 1 and 2 fixes (3-5 hours total) to have a production-ready memory system that matches industry standards.
Next Steps: Review this document with stakeholders, then proceed with Priority 1 fixes.