Files
portainer-core/plans/completed/phase2-memory-system-complete.md
T
jpmschweitzer 0c2c838766 feat(ai): complete Phase 2/3 documentation and memory system improvements
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
2025-11-26 08:41:44 +01:00

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:

Files:

  • src/memory/tier1_buffer.py - Fully functional
  • src/memory/qdrant_memory.py - Fully functional
  • src/memory/manager.py - Orchestration ready

2. Qdrant Vector Database Selection

Status: Excellent choice

Industry Support:

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:

  1. Stored BEFORE agent returns (user message)
  2. Stored AFTER agent completes (assistant response)
  3. 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:

  1. Check if conversation_id exists in memory
  2. Retrieve recent turns from memory manager
  3. Include in conversation_history passed to LLM
  4. 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]]

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/dev
  • langgraph-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:

  1. Store user message BEFORE agent.chat() call
  2. Store assistant response AFTER agent returns
  3. Handle both streaming and non-streaming modes
  4. 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:

  1. Add langgraph-checkpoint-postgres to requirements
  2. Configure checkpointer in agent initialization
  3. Replace custom memory calls with checkpoint API
  4. 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

LangGraph Persistence

RAG vs Memory

Embedding Models

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.