From ceb310bcde4bd58b82a241cc8ce96453fb8a6c3f Mon Sep 17 00:00:00 2001 From: Lucas Gomide Date: Wed, 2 Jul 2025 12:10:45 -0300 Subject: [PATCH] docs: add docs about Memory Events (#3104) --- docs/en/concepts/event-listener.mdx | 11 ++ docs/en/concepts/memory.mdx | 224 ++++++++++++++++++++++++++-- 2 files changed, 220 insertions(+), 15 deletions(-) diff --git a/docs/en/concepts/event-listener.mdx b/docs/en/concepts/event-listener.mdx index 3b2330f65..6c3e391f2 100644 --- a/docs/en/concepts/event-listener.mdx +++ b/docs/en/concepts/event-listener.mdx @@ -255,6 +255,17 @@ CrewAI provides a wide range of events that you can listen for: - **LLMCallFailedEvent**: Emitted when an LLM call fails - **LLMStreamChunkEvent**: Emitted for each chunk received during streaming LLM responses +### Memory Events + +- **MemoryQueryStartedEvent**: Emitted when a memory query is started. Contains the query, limit, and optional score threshold. +- **MemoryQueryCompletedEvent**: Emitted when a memory query is completed successfully. Contains the query, results, limit, score threshold, and query execution time. +- **MemoryQueryFailedEvent**: Emitted when a memory query fails. Contains the query, limit, score threshold, and error message. +- **MemorySaveStartedEvent**: Emitted when a memory save operation is started. Contains the value to be saved, metadata, and optional agent role. +- **MemorySaveCompletedEvent**: Emitted when a memory save operation is completed successfully. Contains the saved value, metadata, agent role, and save execution time. +- **MemorySaveFailedEvent**: Emitted when a memory save operation fails. Contains the value, metadata, agent role, and error message. +- **MemoryRetrievalStartedEvent**: Emitted when memory retrieval for a task prompt starts. Contains the optional task ID. +- **MemoryRetrievalCompletedEvent**: Emitted when memory retrieval for a task prompt completes successfully. Contains the task ID, memory content, and retrieval execution time. + ## Event Handler Structure Each event handler receives two parameters: diff --git a/docs/en/concepts/memory.mdx b/docs/en/concepts/memory.mdx index da228f4e9..0a731f6c6 100644 --- a/docs/en/concepts/memory.mdx +++ b/docs/en/concepts/memory.mdx @@ -9,7 +9,7 @@ icon: database The CrewAI framework provides a sophisticated memory system designed to significantly enhance AI agent capabilities. CrewAI offers **three distinct memory approaches** that serve different use cases: 1. **Basic Memory System** - Built-in short-term, long-term, and entity memory -2. **User Memory** - User-specific memory with Mem0 integration (legacy approach) +2. **User Memory** - User-specific memory with Mem0 integration (legacy approach) 3. **External Memory** - Standalone external memory providers (new approach) ## Memory System Components @@ -62,7 +62,7 @@ By default, CrewAI uses the `appdirs` library to determine storage locations fol ``` ~/Library/Application Support/CrewAI/{project_name}/ ├── knowledge/ # Knowledge base ChromaDB files -├── short_term_memory/ # Short-term memory ChromaDB files +├── short_term_memory/ # Short-term memory ChromaDB files ├── long_term_memory/ # Long-term memory ChromaDB files ├── entities/ # Entity memory ChromaDB files └── long_term_memory_storage.db # SQLite database @@ -252,7 +252,7 @@ chroma_path = os.path.join(storage_path, "knowledge") if os.path.exists(chroma_path): client = chromadb.PersistentClient(path=chroma_path) collections = client.list_collections() - + print("ChromaDB Collections:") for collection in collections: print(f" - {collection.name}: {collection.count()} documents") @@ -269,7 +269,7 @@ crew = Crew(agents=[...], tasks=[...], memory=True) # Reset specific memory types crew.reset_memories(command_type='short') # Short-term memory -crew.reset_memories(command_type='long') # Long-term memory +crew.reset_memories(command_type='long') # Long-term memory crew.reset_memories(command_type='entity') # Entity memory crew.reset_memories(command_type='knowledge') # Knowledge storage ``` @@ -596,7 +596,7 @@ providers_to_test = [ { "name": "Ollama", "config": { - "provider": "ollama", + "provider": "ollama", "config": {"model": "mxbai-embed-large"} } } @@ -604,7 +604,7 @@ providers_to_test = [ for provider in providers_to_test: print(f"\nTesting {provider['name']} embeddings...") - + # Create crew with specific embedder crew = Crew( agents=[...], @@ -612,7 +612,7 @@ for provider in providers_to_test: memory=True, embedder=provider['config'] ) - + # Run your test and measure performance result = crew.kickoff() print(f"{provider['name']} completed successfully") @@ -655,17 +655,17 @@ import time def test_embedding_performance(embedder_config, test_text="This is a test document"): start_time = time.time() - + crew = Crew( agents=[...], tasks=[...], memory=True, embedder=embedder_config ) - + # Simulate memory operation crew.kickoff() - + end_time = time.time() return end_time - start_time @@ -676,7 +676,7 @@ openai_time = test_embedding_performance({ }) ollama_time = test_embedding_performance({ - "provider": "ollama", + "provider": "ollama", "config": {"model": "mxbai-embed-large"} }) @@ -783,7 +783,7 @@ os.environ["MEM0_API_KEY"] = "your-api-key" # Create external memory instance external_memory = ExternalMemory( embedder_config={ - "provider": "mem0", + "provider": "mem0", "config": {"user_id": "U-123"} } ) @@ -808,8 +808,8 @@ class CustomStorage(Storage): def save(self, value, metadata=None, agent=None): self.memories.append({ - "value": value, - "metadata": metadata, + "value": value, + "metadata": metadata, "agent": agent }) @@ -986,7 +986,201 @@ crew = Crew( - 🫡 **Enhanced Personalization:** Memory enables agents to remember user preferences and historical interactions, leading to personalized experiences. - 🧠 **Improved Problem Solving:** Access to a rich memory store aids agents in making more informed decisions, drawing on past learnings and contextual insights. +## Memory Events + +CrewAI's event system provides powerful insights into memory operations. By leveraging memory events, you can monitor, debug, and optimize your memory system's performance and behavior. + +### Available Memory Events + +CrewAI emits the following memory-related events: + +| Event | Description | Key Properties | +| :---- | :---------- | :------------- | +| **MemoryQueryStartedEvent** | Emitted when a memory query begins | `query`, `limit`, `score_threshold` | +| **MemoryQueryCompletedEvent** | Emitted when a memory query completes successfully | `query`, `results`, `limit`, `score_threshold`, `query_time_ms` | +| **MemoryQueryFailedEvent** | Emitted when a memory query fails | `query`, `limit`, `score_threshold`, `error` | +| **MemorySaveStartedEvent** | Emitted when a memory save operation begins | `value`, `metadata`, `agent_role` | +| **MemorySaveCompletedEvent** | Emitted when a memory save operation completes successfully | `value`, `metadata`, `agent_role`, `save_time_ms` | +| **MemorySaveFailedEvent** | Emitted when a memory save operation fails | `value`, `metadata`, `agent_role`, `error` | +| **MemoryRetrievalStartedEvent** | Emitted when memory retrieval for a task prompt starts | `task_id` | +| **MemoryRetrievalCompletedEvent** | Emitted when memory retrieval completes successfully | `task_id`, `memory_content`, `retrieval_time_ms` | + +### Practical Applications + +#### 1. Memory Performance Monitoring + +Track memory operation timing to optimize your application: + +```python +from crewai.utilities.events.base_event_listener import BaseEventListener +from crewai.utilities.events import ( + MemoryQueryCompletedEvent, + MemorySaveCompletedEvent +) +import time + +class MemoryPerformanceMonitor(BaseEventListener): + def __init__(self): + super().__init__() + self.query_times = [] + self.save_times = [] + + def setup_listeners(self, crewai_event_bus): + @crewai_event_bus.on(MemoryQueryCompletedEvent) + def on_memory_query_completed(source, event: MemoryQueryCompletedEvent): + self.query_times.append(event.query_time_ms) + print(f"Memory query completed in {event.query_time_ms:.2f}ms. Query: '{event.query}'") + print(f"Average query time: {sum(self.query_times)/len(self.query_times):.2f}ms") + + @crewai_event_bus.on(MemorySaveCompletedEvent) + def on_memory_save_completed(source, event: MemorySaveCompletedEvent): + self.save_times.append(event.save_time_ms) + print(f"Memory save completed in {event.save_time_ms:.2f}ms") + print(f"Average save time: {sum(self.save_times)/len(self.save_times):.2f}ms") + +# Create an instance of your listener +memory_monitor = MemoryPerformanceMonitor() +``` + +#### 2. Memory Content Logging + +Log memory operations for debugging and insights: + +```python +from crewai.utilities.events.base_event_listener import BaseEventListener +from crewai.utilities.events import ( + MemorySaveStartedEvent, + MemoryQueryStartedEvent, + MemoryRetrievalCompletedEvent +) +import logging + +# Configure logging +logger = logging.getLogger('memory_events') + +class MemoryLogger(BaseEventListener): + def setup_listeners(self, crewai_event_bus): + @crewai_event_bus.on(MemorySaveStartedEvent) + def on_memory_save_started(source, event: MemorySaveStartedEvent): + if event.agent_role: + logger.info(f"Agent '{event.agent_role}' saving memory: {event.value[:50]}...") + else: + logger.info(f"Saving memory: {event.value[:50]}...") + + @crewai_event_bus.on(MemoryQueryStartedEvent) + def on_memory_query_started(source, event: MemoryQueryStartedEvent): + logger.info(f"Memory query started: '{event.query}' (limit: {event.limit})") + + @crewai_event_bus.on(MemoryRetrievalCompletedEvent) + def on_memory_retrieval_completed(source, event: MemoryRetrievalCompletedEvent): + if event.task_id: + logger.info(f"Memory retrieved for task {event.task_id} in {event.retrieval_time_ms:.2f}ms") + else: + logger.info(f"Memory retrieved in {event.retrieval_time_ms:.2f}ms") + logger.debug(f"Memory content: {event.memory_content}") + +# Create an instance of your listener +memory_logger = MemoryLogger() +``` + +#### 3. Error Tracking and Notifications + +Capture and respond to memory errors: + +```python +from crewai.utilities.events.base_event_listener import BaseEventListener +from crewai.utilities.events import ( + MemorySaveFailedEvent, + MemoryQueryFailedEvent +) +import logging +from typing import Optional + +# Configure logging +logger = logging.getLogger('memory_errors') + +class MemoryErrorTracker(BaseEventListener): + def __init__(self, notify_email: Optional[str] = None): + super().__init__() + self.notify_email = notify_email + self.error_count = 0 + + def setup_listeners(self, crewai_event_bus): + @crewai_event_bus.on(MemorySaveFailedEvent) + def on_memory_save_failed(source, event: MemorySaveFailedEvent): + self.error_count += 1 + agent_info = f"Agent '{event.agent_role}'" if event.agent_role else "Unknown agent" + error_message = f"Memory save failed: {event.error}. {agent_info}" + logger.error(error_message) + + if self.notify_email and self.error_count % 5 == 0: + self._send_notification(error_message) + + @crewai_event_bus.on(MemoryQueryFailedEvent) + def on_memory_query_failed(source, event: MemoryQueryFailedEvent): + self.error_count += 1 + error_message = f"Memory query failed: {event.error}. Query: '{event.query}'" + logger.error(error_message) + + if self.notify_email and self.error_count % 5 == 0: + self._send_notification(error_message) + + def _send_notification(self, message): + # Implement your notification system (email, Slack, etc.) + print(f"[NOTIFICATION] Would send to {self.notify_email}: {message}") + +# Create an instance of your listener +error_tracker = MemoryErrorTracker(notify_email="admin@example.com") +``` + +### Integrating with Analytics Platforms + +Memory events can be forwarded to analytics and monitoring platforms to track performance metrics, detect anomalies, and visualize memory usage patterns: + +```python +from crewai.utilities.events.base_event_listener import BaseEventListener +from crewai.utilities.events import ( + MemoryQueryCompletedEvent, + MemorySaveCompletedEvent +) + +class MemoryAnalyticsForwarder(BaseEventListener): + def __init__(self, analytics_client): + super().__init__() + self.client = analytics_client + + def setup_listeners(self, crewai_event_bus): + @crewai_event_bus.on(MemoryQueryCompletedEvent) + def on_memory_query_completed(source, event: MemoryQueryCompletedEvent): + # Forward query metrics to analytics platform + self.client.track_metric({ + "event_type": "memory_query", + "query": event.query, + "duration_ms": event.query_time_ms, + "result_count": len(event.results) if hasattr(event.results, "__len__") else 0, + "timestamp": event.timestamp + }) + + @crewai_event_bus.on(MemorySaveCompletedEvent) + def on_memory_save_completed(source, event: MemorySaveCompletedEvent): + # Forward save metrics to analytics platform + self.client.track_metric({ + "event_type": "memory_save", + "agent_role": event.agent_role, + "duration_ms": event.save_time_ms, + "timestamp": event.timestamp + }) +``` + +### Best Practices for Memory Event Listeners + +1. **Keep handlers lightweight**: Avoid complex processing in event handlers to prevent performance impacts +2. **Use appropriate logging levels**: Use INFO for normal operations, DEBUG for details, ERROR for issues +3. **Batch metrics when possible**: Accumulate metrics before sending to external systems +4. **Handle exceptions gracefully**: Ensure your event handlers don't crash due to unexpected data +5. **Consider memory consumption**: Be mindful of storing large amounts of event data + ## Conclusion -Integrating CrewAI's memory system into your projects is straightforward. By leveraging the provided memory components and configurations, +Integrating CrewAI's memory system into your projects is straightforward. By leveraging the provided memory components and configurations, you can quickly empower your agents with the ability to remember, reason, and learn from their interactions, unlocking new levels of intelligence and capability.