问题背景
在使用 CrewAI 1.8.0 构建多智能体系统时,如果为 Agent 配置了知识源(Knowledge Sources),会遇到一个性能问题:每次调用 crew.kickoff() 时,所有知识源都会被重新嵌入到向量数据库中。
问题表现
# 典型的 Agent 配置
@agent
def my_agent(self) -> Agent:
return Agent(
config=self.agents_config["my_agent"],
llm=self.llm,
knowledge_sources=[
JSONKnowledgeSource(file_paths=["data.json"])
]
)
# 每次 kickoff 都会重新嵌入
crew = MyCrew().crew()
result = crew.kickoff(inputs={...})
性能影响:
- 每次启动延迟增加 10-30 秒(取决于知识源大小)
- 重复调用 Embedding API,产生额外费用
- 浪费计算资源,特别是批处理场景
日志表现
即使第二次、第三次运行相同任务,日志中仍会反复出现:
INFO: 将 88 条数据逐条嵌入
INFO: 嵌入进度: 10/88
INFO: 嵌入进度: 20/88
...
INFO: 所有 88 条数据嵌入完成
问题根源分析
1. CrewAI 的知识源初始化机制
查看 CrewAI 源码可以发现,在 crew.kickoff() 执行时,会调用以下逻辑:
# crewai/crew.py (简化版)
class Crew:
def kickoff(self, inputs):
# 在 kickoff 时重新设置知识源
for agent in self.agents:
agent.set_knowledge(crew_embedder=self.embedder)
在 Agent.set_knowledge() 方法中:
# crewai/agent.py (简化版)
class Agent:
def set_knowledge(self, crew_embedder):
if self.knowledge_sources:
# 重新创建 Knowledge 对象,触发重新嵌入
self.knowledge = Knowledge(
sources=self.knowledge_sources,
embedder=crew_embedder,
# 没有使用持久化的 collection_name
)
关键问题:
knowledge_sources参数传递的KnowledgeSource对象在每次kickoff()时都会被重新包装成新的Knowledge对象- 新的
Knowledge对象会生成随机的collection_name(如knowledge_Agent_Name_12345) - ChromaDB 找不到已有的 collection,认为是新数据,触发重新嵌入
2. ChromaDB 存储结构
CrewAI 选用 ChromaDB 来充当向量数据库,它的存储结构如下:
knowledge_sources/
├── chroma.sqlite3 # 元数据数据库
├── 00dce6e3-281b-4450-8f65-b3d8.../ # UUID 目录(实际向量数据)
├── 85d93e0c-3b79-4200-90ab-360b.../
└── ...
Collection 名称是存储在 chroma.sqlite3 里面的,而向量数据则存储在以 UUID 命名的目录中。要是 collection_name 每次都不一样,那就会去创建新的 collection。
------存储在 chroma.sqlite3 中,向量数据存储在 UUID 命名的目录中。如果 collection_name 每次都不同,就会
解决方案:使用 knowledge 参数替代 knowledge_sources
CrewAI 官方文档中提到:
“With the typical file structure provided by CrewAI, knowledge sources are embedded every time the kickoff is triggered… To resolve this, directly initialize the knowledge parameter instead of the knowledge_sources parameter.”
核心思路
直接创建 Knowledge 对象并指定固定的 collection_name,让 ChromaDB 能够找到已有的 collection,避免重复嵌入。
实现步骤
第 1 步:创建知识管理器模块
创建一个单例模块来管理 Knowledge 对象:
# tools/knowledge_manager.py
from crewai import Knowledge
from crewai.knowledge.source.json_knowledge_source import JSONKnowledgeSource
from crewai.knowledge.storage.knowledge_storage import KnowledgeStorage
from pathlib import Path
import os
_KNOWLEDGE_OBJECTS = {}
_INITIALIZED = False
def _initialize_knowledge_objects():
"""初始化 Knowledge 对象(仅执行一次)"""
global _KNOWLEDGE_OBJECTS, _INITIALIZED
if _INITIALIZED:
return
# embedder 配置
embedder_config = {
"provider": "openai",
"config": {
"model": "text-embedding-3-small"
}
}
project_root = Path(__file__).parent.parent
original_cwd = Path.cwd()
os.chdir(project_root)
try:
# 创建知识源
data_source = JSONKnowledgeSource(
file_paths=["knowledge/data.json"]
)
data_storage = KnowledgeStorage(
embedder=embedder_config,
collection_name="data_persistent" # 固定名称
)
_KNOWLEDGE_OBJECTS['data'] = Knowledge(
collection_name="data_persistent",
sources=[data_source],
embedder=embedder_config,
storage=data_storage
)
_INITIALIZED = True
print("Knowledge 对象初始化完成")
finally:
os.chdir(original_cwd)
def get_knowledge(name: str):
"""获取预初始化的 Knowledge 对象"""
if not _INITIALIZED:
_initialize_knowledge_objects()
if name not in _KNOWLEDGE_OBJECTS:
raise ValueError(f"未知的知识源: {name}")
return _KNOWLEDGE_OBJECTS[name]
第 2 步:在 Crew 中使用 knowledge 参数
错误方式(会重复嵌入):
from crewai import Agent, Crew
from crewai.project import CrewBase, agent, crew
from crewai.knowledge.source.json_knowledge_source import JSONKnowledgeSource
@CrewBase
class MyCrew:
@agent
def my_agent(self) -> Agent:
return Agent(
config=self.agents_config["my_agent"],
llm=self.llm,
knowledge_sources=[JSONKnowledgeSource(file_paths=["data.json"])]
)
正确方式(使用持久化):
from crewai import Agent, Crew
from crewai.project import CrewBase, agent, crew
from tools.knowledge_manager import get_knowledge
@CrewBase
class MyCrew:
data_knowledge = get_knowledge('data')
@agent
def my_agent(self) -> Agent:
return Agent(
config=self.agents_config["my_agent"],
llm=self.llm,
knowledge=self.data_knowledge
)
参考文献:https://docs.crewai.com/en/concepts/knowledge

421

被折叠的 条评论
为什么被折叠?



