mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-08 07:38:29 +00:00
fix: Remove OpenAI dependency for memory reset when using alternative LLMs
- Add environment variables for default embedding provider - Support Ollama as default embedding provider - Add tests for memory reset with different providers - Update documentation Fixes #2023 Co-Authored-By: Joe Moura <joao@crewai.com>
This commit is contained in:
@@ -34,3 +34,43 @@ crewai reset-memories -a
|
||||
```
|
||||
|
||||
The memory system will use the configured embedding provider for all operations, including memory reset.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. OpenAI API Key Missing
|
||||
```bash
|
||||
# Error: EmbeddingConfigurationError: Invalid configuration for OpenAI provider
|
||||
# Solution: Set your OpenAI API key
|
||||
export OPENAI_API_KEY=your_key
|
||||
```
|
||||
|
||||
2. Ollama Connection Issues
|
||||
```bash
|
||||
# Error: Failed to connect to Ollama server
|
||||
# Solution: Ensure Ollama is running and accessible
|
||||
curl http://localhost:11434/api/embeddings
|
||||
```
|
||||
|
||||
3. Memory Reset Permission Issues
|
||||
```bash
|
||||
# Error: Failed to reset memory (readonly database)
|
||||
# Solution: Check file permissions or use custom path
|
||||
export CREWAI_MEMORY_PATH=/path/with/write/access
|
||||
```
|
||||
|
||||
### Custom Storage Path
|
||||
|
||||
You can configure a custom storage path for memory files:
|
||||
|
||||
```python
|
||||
from crewai.memory import ShortTermMemory
|
||||
|
||||
memory = ShortTermMemory(path="/custom/storage/path")
|
||||
```
|
||||
|
||||
This is useful when:
|
||||
- Default storage location has permission issues
|
||||
- You want to isolate memory storage for different crews
|
||||
- You need to manage memory persistence manually
|
||||
|
||||
@@ -85,11 +85,10 @@ class RAGStorage(BaseRAGStorage):
|
||||
|
||||
self._set_embedder_config()
|
||||
try:
|
||||
chroma_client = chromadb.PersistentClient(
|
||||
self.app = chromadb.PersistentClient(
|
||||
path=self.path if self.path else self.storage_file_name,
|
||||
settings=Settings(allow_reset=self.allow_reset),
|
||||
)
|
||||
self.app = chroma_client
|
||||
if not self.app:
|
||||
raise RuntimeError("Failed to initialize ChromaDB client")
|
||||
|
||||
@@ -104,19 +103,6 @@ class RAGStorage(BaseRAGStorage):
|
||||
except Exception as e:
|
||||
raise RuntimeError(f"Failed to initialize ChromaDB: {str(e)}")
|
||||
|
||||
self.app = chroma_client
|
||||
if not self.app:
|
||||
raise RuntimeError("Failed to initialize ChromaDB client")
|
||||
|
||||
try:
|
||||
self.collection = self.app.get_collection(
|
||||
name=self.type, embedding_function=self.embedder_config
|
||||
)
|
||||
except Exception:
|
||||
self.collection = self.app.create_collection(
|
||||
name=self.type, embedding_function=self.embedder_config
|
||||
)
|
||||
|
||||
def _sanitize_role(self, role: str) -> str:
|
||||
"""
|
||||
Sanitizes agent roles to ensure valid directory names.
|
||||
@@ -138,12 +124,21 @@ class RAGStorage(BaseRAGStorage):
|
||||
return f"{base_path}/{file_name}"
|
||||
|
||||
def save(self, value: Any, metadata: Dict[str, Any]) -> None:
|
||||
"""Save a value with metadata to the memory storage.
|
||||
|
||||
Args:
|
||||
value: The text content to store
|
||||
metadata: Additional metadata for the stored content
|
||||
|
||||
Raises:
|
||||
EmbeddingInitializationError: If embedding generation fails
|
||||
"""
|
||||
if not hasattr(self, "app") or not hasattr(self, "collection"):
|
||||
self._initialize_app()
|
||||
try:
|
||||
self._generate_embedding(value, metadata)
|
||||
except Exception as e:
|
||||
logging.error(f"Error during {self.type} save: {str(e)}")
|
||||
raise EmbeddingInitializationError(self.type, str(e))
|
||||
|
||||
def search(
|
||||
self,
|
||||
@@ -151,7 +146,18 @@ class RAGStorage(BaseRAGStorage):
|
||||
limit: int = 3,
|
||||
filter: Optional[dict] = None,
|
||||
score_threshold: float = 0.35,
|
||||
) -> List[Any]:
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Search for similar content in memory.
|
||||
|
||||
Args:
|
||||
query: The search query text
|
||||
limit: Maximum number of results to return
|
||||
filter: Optional filter criteria
|
||||
score_threshold: Minimum similarity score threshold
|
||||
|
||||
Returns:
|
||||
List of matching results with metadata and scores
|
||||
"""
|
||||
if not hasattr(self, "app"):
|
||||
self._initialize_app()
|
||||
|
||||
@@ -175,15 +181,24 @@ class RAGStorage(BaseRAGStorage):
|
||||
logging.error(f"Error during {self.type} search: {str(e)}")
|
||||
return []
|
||||
|
||||
def _generate_embedding(self, text: str, metadata: Dict[str, Any]) -> None: # type: ignore
|
||||
def _generate_embedding(self, text: str, metadata: Dict[str, Any]) -> None:
|
||||
"""Generate and store embeddings for the given text.
|
||||
|
||||
Args:
|
||||
text: The text to generate embeddings for
|
||||
metadata: Additional metadata to store with the embeddings
|
||||
"""
|
||||
if not hasattr(self, "app") or not hasattr(self, "collection"):
|
||||
self._initialize_app()
|
||||
|
||||
self.collection.add(
|
||||
documents=[text],
|
||||
metadatas=[metadata or {}],
|
||||
ids=[str(uuid.uuid4())],
|
||||
)
|
||||
try:
|
||||
self.collection.add(
|
||||
documents=[text],
|
||||
metadatas=[metadata or {}],
|
||||
ids=[str(uuid.uuid4())],
|
||||
)
|
||||
except Exception as e:
|
||||
raise EmbeddingInitializationError(self.type, f"Failed to generate embedding: {str(e)}")
|
||||
|
||||
def reset(self) -> None:
|
||||
"""Reset the memory storage by clearing the database and removing files.
|
||||
|
||||
@@ -71,8 +71,11 @@ class EmbeddingConfigurator:
|
||||
model = os.getenv("CREWAI_EMBEDDING_MODEL", DEFAULT_EMBEDDING_MODEL)
|
||||
|
||||
if provider == "openai":
|
||||
api_key = os.getenv("OPENAI_API_KEY")
|
||||
if not api_key:
|
||||
raise EmbeddingConfigurationError("OpenAI API key is required but not provided")
|
||||
from chromadb.utils.embedding_functions.openai_embedding_function import OpenAIEmbeddingFunction
|
||||
return OpenAIEmbeddingFunction(api_key=os.getenv("OPENAI_API_KEY"), model_name=model)
|
||||
return OpenAIEmbeddingFunction(api_key=api_key, model_name=model)
|
||||
elif provider == "ollama":
|
||||
from chromadb.utils.embedding_functions.ollama_embedding_function import OllamaEmbeddingFunction
|
||||
url = os.getenv("CREWAI_OLLAMA_URL", "http://localhost:11434/api/embeddings")
|
||||
|
||||
@@ -48,6 +48,19 @@ def test_memory_reset_with_invalid_provider(temp_db_dir):
|
||||
for memory in memories:
|
||||
memory.reset()
|
||||
|
||||
def test_memory_reset_with_invalid_configuration(temp_db_dir):
|
||||
os.environ["CREWAI_EMBEDDING_PROVIDER"] = "openai"
|
||||
os.environ.pop("OPENAI_API_KEY", None)
|
||||
|
||||
with pytest.raises(EmbeddingConfigurationError):
|
||||
memories = [
|
||||
ShortTermMemory(path=temp_db_dir),
|
||||
LongTermMemory(path=temp_db_dir),
|
||||
EntityMemory(path=temp_db_dir)
|
||||
]
|
||||
for memory in memories:
|
||||
memory.reset()
|
||||
|
||||
def test_memory_reset_with_missing_ollama_url(temp_db_dir):
|
||||
os.environ["CREWAI_EMBEDDING_PROVIDER"] = "ollama"
|
||||
os.environ.pop("CREWAI_OLLAMA_URL", None)
|
||||
@@ -59,3 +72,20 @@ def test_memory_reset_with_missing_ollama_url(temp_db_dir):
|
||||
]
|
||||
for memory in memories:
|
||||
memory.reset()
|
||||
|
||||
def test_memory_reset_with_custom_path(temp_db_dir):
|
||||
os.environ["CREWAI_EMBEDDING_PROVIDER"] = "ollama"
|
||||
custom_path = os.path.join(temp_db_dir, "custom")
|
||||
os.makedirs(custom_path, exist_ok=True)
|
||||
|
||||
memories = [
|
||||
ShortTermMemory(path=custom_path),
|
||||
LongTermMemory(path=custom_path),
|
||||
EntityMemory(path=custom_path)
|
||||
]
|
||||
for memory in memories:
|
||||
memory.reset()
|
||||
|
||||
assert not os.path.exists(os.path.join(custom_path, "short_term"))
|
||||
assert not os.path.exists(os.path.join(custom_path, "long_term"))
|
||||
assert not os.path.exists(os.path.join(custom_path, "entity"))
|
||||
|
||||
Reference in New Issue
Block a user