mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-09 16:18:30 +00:00
fix: cache agent knowledge to avoid reloading on every kickoff
- Add caching mechanism in Agent.set_knowledge to track loaded state - Skip knowledge reloading when sources and embedder haven't changed - Add reset_knowledge_cache method for explicit cache clearing - Add comprehensive tests for caching behavior and edge cases - Fixes issue #3076 performance overhead on repeated kickoffs Co-Authored-By: João <joao@crewai.com>
This commit is contained in:
@@ -194,6 +194,14 @@ class Agent(BaseAgent):
|
||||
|
||||
def set_knowledge(self, crew_embedder: Optional[Dict[str, Any]] = None):
|
||||
try:
|
||||
current_embedder = crew_embedder or self.embedder
|
||||
if (hasattr(self, '_knowledge_loaded') and
|
||||
self._knowledge_loaded and
|
||||
self.knowledge is not None and
|
||||
getattr(self, '_last_embedder', None) == current_embedder and
|
||||
getattr(self, '_last_knowledge_sources', None) == self.knowledge_sources):
|
||||
return
|
||||
|
||||
if self.embedder is None and crew_embedder:
|
||||
self.embedder = crew_embedder
|
||||
|
||||
@@ -208,6 +216,10 @@ class Agent(BaseAgent):
|
||||
storage=self.knowledge_storage or None,
|
||||
)
|
||||
self.knowledge.add_sources()
|
||||
|
||||
self._knowledge_loaded = True
|
||||
self._last_embedder = current_embedder
|
||||
self._last_knowledge_sources = self.knowledge_sources.copy() if self.knowledge_sources else None
|
||||
except (TypeError, ValueError) as e:
|
||||
raise ValueError(f"Invalid Knowledge Configuration: {str(e)}")
|
||||
|
||||
@@ -228,6 +240,13 @@ class Agent(BaseAgent):
|
||||
|
||||
return any(getattr(self.crew, attr) for attr in memory_attributes)
|
||||
|
||||
def reset_knowledge_cache(self):
|
||||
"""Reset the knowledge cache to force reloading on next set_knowledge call."""
|
||||
self._knowledge_loaded = False
|
||||
self._last_embedder = None
|
||||
self._last_knowledge_sources = None
|
||||
self.knowledge = None
|
||||
|
||||
def execute_task(
|
||||
self,
|
||||
task: Task,
|
||||
|
||||
@@ -2276,3 +2276,119 @@ def test_agent_from_repository_without_org_set(
|
||||
"No organization currently set. We recommend setting one before using: `crewai org switch <org_id>` command.",
|
||||
style="yellow",
|
||||
)
|
||||
|
||||
|
||||
def test_agent_knowledge_caching_on_multiple_kickoffs():
|
||||
"""Test that agent knowledge is only loaded once when kickoff is called multiple times."""
|
||||
content = "Brandon's favorite color is blue and he likes Mexican food."
|
||||
string_source = StringKnowledgeSource(content=content)
|
||||
|
||||
agent = Agent(
|
||||
role="Researcher",
|
||||
goal="Research about Brandon",
|
||||
backstory="You are a researcher.",
|
||||
knowledge_sources=[string_source]
|
||||
)
|
||||
|
||||
task = Task(
|
||||
description="What is Brandon's favorite color?",
|
||||
expected_output="Brandon's favorite color",
|
||||
agent=agent
|
||||
)
|
||||
|
||||
crew = Crew(agents=[agent], tasks=[task])
|
||||
|
||||
with patch.object(Knowledge, 'add_sources') as mock_add_sources:
|
||||
crew.kickoff()
|
||||
assert mock_add_sources.call_count == 1
|
||||
|
||||
crew.kickoff()
|
||||
assert mock_add_sources.call_count == 1
|
||||
|
||||
crew.kickoff()
|
||||
assert mock_add_sources.call_count == 1
|
||||
|
||||
|
||||
def test_agent_knowledge_reloads_when_sources_change():
|
||||
"""Test that agent knowledge is reloaded when knowledge sources change."""
|
||||
content1 = "Brandon's favorite color is blue."
|
||||
content2 = "Brandon's favorite food is tacos."
|
||||
string_source1 = StringKnowledgeSource(content=content1)
|
||||
string_source2 = StringKnowledgeSource(content=content2)
|
||||
|
||||
agent = Agent(
|
||||
role="Researcher",
|
||||
goal="Research about Brandon",
|
||||
backstory="You are a researcher.",
|
||||
knowledge_sources=[string_source1]
|
||||
)
|
||||
|
||||
task = Task(
|
||||
description="What do you know about Brandon?",
|
||||
expected_output="Information about Brandon",
|
||||
agent=agent
|
||||
)
|
||||
|
||||
crew = Crew(agents=[agent], tasks=[task])
|
||||
|
||||
with patch.object(Knowledge, 'add_sources') as mock_add_sources:
|
||||
crew.kickoff()
|
||||
assert mock_add_sources.call_count == 1
|
||||
|
||||
agent.knowledge_sources = [string_source2]
|
||||
|
||||
crew.kickoff()
|
||||
assert mock_add_sources.call_count == 2
|
||||
|
||||
|
||||
def test_agent_knowledge_reloads_when_embedder_changes():
|
||||
"""Test that agent knowledge is reloaded when embedder changes."""
|
||||
content = "Brandon's favorite color is blue."
|
||||
string_source = StringKnowledgeSource(content=content)
|
||||
|
||||
agent = Agent(
|
||||
role="Researcher",
|
||||
goal="Research about Brandon",
|
||||
backstory="You are a researcher.",
|
||||
knowledge_sources=[string_source]
|
||||
)
|
||||
|
||||
task = Task(
|
||||
description="What is Brandon's favorite color?",
|
||||
expected_output="Brandon's favorite color",
|
||||
agent=agent
|
||||
)
|
||||
|
||||
crew1 = Crew(agents=[agent], tasks=[task], embedder={"model": "text-embedding-ada-002"})
|
||||
crew2 = Crew(agents=[agent], tasks=[task], embedder={"model": "text-embedding-3-small"})
|
||||
|
||||
with patch.object(Knowledge, 'add_sources') as mock_add_sources:
|
||||
crew1.kickoff()
|
||||
assert mock_add_sources.call_count == 1
|
||||
|
||||
crew2.kickoff()
|
||||
assert mock_add_sources.call_count == 2
|
||||
|
||||
|
||||
def test_agent_reset_knowledge_cache():
|
||||
"""Test that reset_knowledge_cache forces knowledge reloading."""
|
||||
content = "Brandon's favorite color is blue."
|
||||
string_source = StringKnowledgeSource(content=content)
|
||||
|
||||
agent = Agent(
|
||||
role="Researcher",
|
||||
goal="Research about Brandon",
|
||||
backstory="You are a researcher.",
|
||||
knowledge_sources=[string_source]
|
||||
)
|
||||
|
||||
agent._knowledge_loaded = True
|
||||
agent._last_embedder = {"model": "test"}
|
||||
agent._last_knowledge_sources = [string_source]
|
||||
|
||||
agent.reset_knowledge_cache()
|
||||
|
||||
assert not getattr(agent, '_knowledge_loaded', True)
|
||||
assert agent._last_embedder is None
|
||||
assert agent._last_knowledge_sources is None
|
||||
assert agent.knowledge is None
|
||||
|
||||
Reference in New Issue
Block a user