Skip to content
CrewAI 文档版本 跟随上游 源快照 5c4c8ac4 更新于 2026-10-18

记忆

利用 CrewAI 中的统一记忆系统增强智能体能力。

概述

CrewAI 提供统一记忆系统 -- 一个单一的 Memory 类,用一个智能 API 取代了独立的短期记忆、长期记忆、实体记忆和外部记忆类型。记忆在保存时使用 LLM 分析内容(推断作用域、类别和重要性),并支持自适应深度召回,使用融合语义相似度、新近度和重要性的复合评分。

你可以通过四种方式使用记忆:独立使用(脚本、notebooks)、与团队一起使用、与智能体一起使用,或在流程内部使用。

快速开始

python
from crewai import Memory

memory = Memory()

# Store -- the LLM infers scope, categories, and importance
memory.remember("We decided to use PostgreSQL for the user database.")

# Retrieve -- results ranked by composite score (semantic + recency + importance)
matches = memory.recall("What database did we choose?")
for m in matches:
    print(f"[{m.score:.2f}] {m.record.content}")

# Tune scoring for a fast-moving project
memory = Memory(recency_weight=0.5, recency_half_life_days=7)

# Forget
memory.forget(scope="/project/old")

# Explore the self-organized scope tree
print(memory.tree())
print(memory.info("/"))

使用记忆的四种方式

独立使用

在脚本、notebook、CLI 工具中使用记忆,或将其作为独立知识库 -- 无需智能体或团队。

python
from crewai import Memory

memory = Memory()

# Build up knowledge
memory.remember("The API rate limit is 1000 requests per minute.")
memory.remember("Our staging environment uses port 8080.")
memory.remember("The team agreed to use feature flags for all new releases.")

# Later, recall what you need
matches = memory.recall("What are our API limits?", limit=5)
for m in matches:
    print(f"[{m.score:.2f}] {m.record.content}")

# Extract atomic facts from a longer text
raw = """Meeting notes: We decided to migrate from MySQL to PostgreSQL
next quarter. The budget is $50k. Sarah will lead the migration."""

facts = memory.extract_memories(raw)
# ["Migration from MySQL to PostgreSQL planned for next quarter",
#  "Database migration budget is $50k",
#  "Sarah will lead the database migration"]

for fact in facts:
    memory.remember(fact)

与团队一起使用

传入 memory=True 以使用默认设置,或传入已配置的 Memory 实例以实现自定义行为。

python
from crewai import Crew, Agent, Task, Process, Memory

# Option 1: Default memory
crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, writing_task],
    process=Process.sequential,
    memory=True,
    verbose=True,
)

# Option 2: Custom memory with tuned scoring
memory = Memory(
    recency_weight=0.4,
    semantic_weight=0.4,
    importance_weight=0.2,
    recency_half_life_days=14,
)
crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, writing_task],
    memory=memory,
)

当 memory=True 时,团队会创建一个默认的 Memory(),并自动传入团队的 embedder 配置。团队中的所有智能体共享团队记忆,除非某个智能体拥有自己的记忆。在没有自定义 embedder 的情况下,记忆使用 OpenAI text-embedding-3-large 嵌入。

每个任务完成后,团队会自动从任务输出中提取离散事实并存储。每个任务开始前,智能体会从记忆中召回相关上下文,并将其注入任务提示词。

与智能体一起使用

智能体可以使用团队的共享记忆(默认),或接收一个限定作用域的视图以获取私有上下文。

python
from crewai import Agent, Memory

memory = Memory()

# Researcher gets a private scope -- only sees /agent/researcher
researcher = Agent(
    role="Researcher",
    goal="Find and analyze information",
    backstory="Expert researcher with attention to detail",
    memory=memory.scope("/agent/researcher"),
)

# Writer uses crew shared memory (no agent-level memory set)
writer = Agent(
    role="Writer",
    goal="Produce clear, well-structured content",
    backstory="Experienced technical writer",
    # memory not set -- uses crew._memory when crew has memory enabled
)

这种模式让研究员获得私有的发现,而写作者从团队的共享记忆中读取。

与流程一起使用

每个 Flow 都内置记忆。在任何流程方法中,使用 self.remember()、self.recall() 和 self.extract_memories()。

python
from crewai.flow.flow import Flow, listen, start

class ResearchFlow(Flow):
    @start()
    def gather_data(self):
        findings = "PostgreSQL handles 10k concurrent connections. MySQL caps at 5k."
        self.remember(findings, scope="/research/databases")
        return findings

    @listen(gather_data)
    def write_report(self, findings):
        # Recall past research to provide context
        past = self.recall("database performance benchmarks")
        context = "\n".join(f"- {m.record.content}" for m in past)
        return f"Report:\nNew findings: {findings}\nPrevious context:\n{context}"

有关流程中记忆的更多信息,请参阅 流程文档。

分层作用域

什么是作用域

记忆被组织成作用域的分层树,类似于文件系统。每个作用域都是一个路径,例如 /、/project/alpha 或 /agent/researcher/findings。

/
  /company
    /company/engineering
    /company/product
  /project
    /project/alpha
    /project/beta
  /agent
    /agent/researcher
    /agent/writer

作用域提供上下文相关记忆 -- 当你在某个作用域内召回时,只会搜索树的该分支,从而同时提高精度和性能。

作用域推断如何工作

当你调用 remember() 而未指定作用域时,LLM 会分析内容和现有作用域树,然后建议最佳放置位置。如果没有现有作用域适合,它会创建一个新的作用域。随着时间推移,作用域树会从内容本身有机地生长出来 -- 你不需要预先设计 schema。

python
memory = Memory()

# LLM infers scope from content
memory.remember("We chose PostgreSQL for the user database.")
# -> might be placed under /project/decisions or /engineering/database

# You can also specify scope explicitly
memory.remember("Sprint velocity is 42 points", scope="/team/metrics")

可视化作用域树

python
print(memory.tree())
# / (15 records)
#   /project (8 records)
#     /project/alpha (5 records)
#     /project/beta (3 records)
#   /agent (7 records)
#     /agent/researcher (4 records)
#     /agent/writer (3 records)

print(memory.info("/project/alpha"))
# ScopeInfo(path='/project/alpha', record_count=5,
#           categories=['architecture', 'database'],
#           oldest_record=datetime(...), newest_record=datetime(...),
#           child_scopes=[])

MemoryScope:子树视图

MemoryScope 将所有操作限制到树的某个分支。使用它的智能体或代码只能在该子树内查看和写入。

python
memory = Memory()

# Create a scope for a specific agent
agent_memory = memory.scope("/agent/researcher")

# Everything is relative to /agent/researcher
agent_memory.remember("Found three relevant papers on LLM memory.")
# -> stored under /agent/researcher

agent_memory.recall("relevant papers")
# -> searches only under /agent/researcher

# Narrow further with subscope
project_memory = agent_memory.subscope("project-alpha")
# -> /agent/researcher/project-alpha

作用域设计最佳实践

  • 从扁平开始,让 LLM 组织。 不要预先过度设计作用域层级。从 memory.remember(content) 开始,让 LLM 的作用域推断在内容积累时创建结构。

  • 使用 /{entity_type}/{identifier} 模式。 自然层级会从 /project/alpha、/agent/researcher、/company/engineering、/customer/acme-corp 等模式中浮现。

  • 按关注点划分作用域,而不是按数据类型。 使用 /project/alpha/decisions,而不是 /decisions/project/alpha。这会让相关内容保持在一起。

  • 保持较浅的深度(2-3 层)。 嵌套过深的作用域会变得过于稀疏。/project/alpha/architecture 很好;/project/alpha/architecture/decisions/databases/postgresql 则太深。

  • 知道时使用显式作用域,不知道时让 LLM 推断。 如果你要存储已知的项目决策,传入 scope="/project/alpha/decisions"。如果你要存储自由形式的智能体输出,省略作用域,让 LLM 自行判断。

用例示例

多项目团队:

python
memory = Memory()
# Each project gets its own branch
memory.remember("Using microservices architecture", scope="/project/alpha/architecture")
memory.remember("GraphQL API for client apps", scope="/project/beta/api")

# Recall across all projects
memory.recall("API design decisions")

# Or within a specific project
memory.recall("API design", scope="/project/beta")

每个智能体的私有上下文与共享知识:

python
memory = Memory()

# Researcher has private findings
researcher_memory = memory.scope("/agent/researcher")

# Writer can read from both its own scope and shared company knowledge
writer_view = memory.slice(
    scopes=["/agent/writer", "/company/knowledge"],
    read_only=True,
)

客户支持(按客户划分上下文):

python
memory = Memory()

# Each customer gets isolated context
memory.remember("Prefers email communication", scope="/customer/acme-corp")
memory.remember("On enterprise plan, 50 seats", scope="/customer/acme-corp")

# Shared product docs are accessible to all agents
memory.remember("Rate limit is 1000 req/min on enterprise plan", scope="/product/docs")

记忆切片

什么是切片

MemorySlice 是跨多个(可能不相交的)作用域的视图。与作用域(限制到一个子树)不同,切片允许你同时从多个分支召回。

何时使用切片与作用域

  • 作用域:当智能体或代码块应限制到单个子树时使用。示例:一个只能看到 /agent/researcher 的智能体。
  • 切片:当你需要组合多个分支的上下文时使用。示例:一个从自身作用域以及共享公司知识中读取的智能体。

只读切片

最常见的模式:授予智能体对多个分支的读取权限,同时不允许其写入共享区域。

python
memory = Memory()

# Agent can recall from its own scope AND company knowledge,
# but cannot write to company knowledge
agent_view = memory.slice(
    scopes=["/agent/researcher", "/company/knowledge"],
    read_only=True,
)

matches = agent_view.recall("company security policies", limit=5)
# Searches both /agent/researcher and /company/knowledge, merges and ranks results

agent_view.remember("new finding")  # Raises PermissionError (read-only)

读写切片

当禁用只读时,你可以写入任何包含的作用域,但必须显式指定是哪个作用域。

python
view = memory.slice(scopes=["/team/alpha", "/team/beta"], read_only=False)

# Must specify scope when writing
view.remember("Cross-team decision", scope="/team/alpha", categories=["decisions"])

复合评分

召回结果按三个信号的加权组合排序:

composite = semantic_weight * similarity + recency_weight * decay + importance_weight * importance

其中:

  • 相似度 = 来自向量索引的 1 / (1 + distance)(0 到 1)
  • 衰减 = 0.5^(age_days / half_life_days) -- 指数衰减(今天为 1.0,半衰期时为 0.5)
  • 重要性 = 记录的重要性分数(0 到 1),在编码时设置

在 Memory 构造函数上直接配置这些参数:

python
# Sprint retrospective: favor recent memories, short half-life
memory = Memory(
    recency_weight=0.5,
    semantic_weight=0.3,
    importance_weight=0.2,
    recency_half_life_days=7,
)

# Architecture knowledge base: favor important memories, long half-life
memory = Memory(
    recency_weight=0.1,
    semantic_weight=0.5,
    importance_weight=0.4,
    recency_half_life_days=180,
)

每个 MemoryMatch 都包含一个 match_reasons 列表,因此你可以看到某个结果为何排名如此(例如 ["semantic", "recency", "importance"])。

LLM 分析层

记忆以三种方式使用 LLM:

  1. 保存时 -- 当你省略作用域、类别或重要性时,LLM 会分析内容并建议作用域、类别、重要性及元数据(实体、日期、主题)。
  2. 召回时 -- 对于深度/自动召回,LLM 会分析查询(关键词、时间提示、建议作用域、复杂度)以引导检索。
  3. 提取记忆 -- extract_memories(content) 将原始文本(例如任务输出)拆分为离散的记忆陈述。智能体在对每条陈述调用 remember() 之前会使用它,以便存储原子事实,而不是一个大块。

所有分析在 LLM 失败时都会优雅降级 -- 参见 失败行为。

记忆整合

保存新内容时,编码流水线会自动检查存储中是否存在相似的现有记录。如果相似度高于 consolidation_threshold(默认 0.85),LLM 会决定如何处理:

  • keep -- 现有记录仍然准确且不冗余。
  • update -- 应使用新信息更新现有记录(LLM 提供合并后的内容)。
  • delete -- 现有记录已过时、被取代或与事实矛盾。
  • insert_new -- 新内容是否也应作为单独记录插入。

这可以防止重复内容积累。例如,如果你三次保存“CrewAI 确保可靠运行”,整合会识别出重复项,并且只保留一条记录。

批内去重

使用 remember_many() 时,同一批次内的项会在写入存储前相互比较。如果两个项的余弦相似度 >= batch_dedup_threshold(默认 0.98),后一项会被静默丢弃。这可以在单批次内捕获精确或几乎精确的重复项,而无需任何 LLM 调用(纯向量数学)。

python
# Only 2 records are stored (the third is a near-duplicate of the first)
memory.remember_many([
    "CrewAI supports complex workflows.",
    "Python is a great language.",
    "CrewAI supports complex workflows.",  # dropped by intra-batch dedup
])

非阻塞保存

remember_many() 是非阻塞的 -- 它将编码流水线提交到后台线程并立即返回。这意味着智能体可以在保存记忆的同时继续执行下一个任务。

python
# Returns immediately -- save happens in background
memory.remember_many(["Fact A.", "Fact B.", "Fact C."])

# recall() automatically waits for pending saves before searching
matches = memory.recall("facts")  # sees all 3 records

读屏障

每次 recall() 调用都会在搜索前自动调用 drain_writes(),确保查询始终能看到最新持久化的记录。这是透明的 -- 你永远不需要考虑它。

团队关闭

当团队完成时,kickoff() 会在其 finally 块中排空所有待处理的记忆保存,因此即使团队在后台保存仍在进行时完成,也不会丢失任何保存。

独立使用

对于没有团队生命周期的脚本或 notebook,请显式调用 drain_writes() 或 close():

python
memory = Memory()
memory.remember_many(["Fact A.", "Fact B."])

# Option 1: Wait for pending saves
memory.drain_writes()

# Option 2: Drain and shut down the background pool
memory.close()

来源与隐私

每条记忆记录都可以携带用于来源追踪的 source 标签,以及用于访问控制的 private 标志。

来源追踪

source 参数标识记忆的来源:

python
# Tag memories with their origin
memory.remember("User prefers dark mode", source="user:alice")
memory.remember("System config updated", source="admin")
memory.remember("Agent found a bug", source="agent:debugger")

# Recall only memories from a specific source
matches = memory.recall("user preferences", source="user:alice")

私有记忆

仅当 source 匹配时,私有记忆才会对召回可见:

python
# Store a private memory
memory.remember("Alice's API key is sk-...", source="user:alice", private=True)

# This recall sees the private memory (source matches)
matches = memory.recall("API key", source="user:alice")

# This recall does NOT see it (different source)
matches = memory.recall("API key", source="user:bob")

# Admin access: see all private records regardless of source
matches = memory.recall("API key", include_private=True)

这在多用户或企业版部署中特别有用,因为不同用户的记忆应当相互隔离。

RecallFlow(深度召回)

recall() 支持两种深度:

  • depth="shallow" -- 使用复合评分的直接向量搜索。快速(~200ms),无 LLM 调用。
  • depth="deep"(默认) -- 运行多步 RecallFlow:查询分析、作用域选择、并行向量搜索、基于置信度的路由,以及置信度较低时的可选递归探索。

智能 LLM 跳过:短于 query_analysis_threshold(默认 200 个字符)的查询会完全跳过 LLM 查询分析,即使在深度模式下也是如此。诸如“我们使用什么数据库?”这样的短查询本身就是不错的搜索短语——LLM 分析带来的价值很小。对于典型的短查询,这每次回忆可节省 ~1-3s。只有较长的查询(例如完整任务描述)才会经过 LLM 提炼为有针对性的子查询。

python
# Shallow: pure vector search, no LLM
matches = memory.recall("What did we decide?", limit=10, depth="shallow")

# Deep (default): intelligent retrieval with LLM analysis for long queries
matches = memory.recall(
    "Summarize all architecture decisions from this quarter",
    limit=10,
    depth="deep",
)

控制 RecallFlow 路由的置信度阈值是可配置的:

python
memory = Memory(
    confidence_threshold_high=0.9,   # Only synthesize when very confident
    confidence_threshold_low=0.4,    # Explore deeper more aggressively
    exploration_budget=2,            # Allow up to 2 exploration rounds
    query_analysis_threshold=200,    # Skip LLM for queries shorter than this
)

嵌入器配置

记忆需要一个嵌入模型来将文本转换为向量以进行语义搜索。默认情况下,Memory() 使用 OpenAI text-embedding-3-large 嵌入,生成 3072 维向量。为默认路径设置 OPENAI_API_KEY,或通过以下三种方式之一配置自定义嵌入器。

WARNING

使用 1536 维嵌入(例如 text-embedding-3-small 或 text-embedding-ada-002)创建的现有本地记忆存储,可能与 text-embedding-3-large 默认值不兼容。这同时适用于 OpenAI 和 Azure OpenAI 服务商——Azure 的默认嵌入模型也已从 text-embedding-ada-002 改为 text-embedding-3-large。如果本地测试因嵌入维度不匹配而失败,请使用 crewai reset-memories -m 重置记忆、删除本地记忆存储目录,或在迁移之前显式配置较旧的嵌入器模型。

直接传递给 Memory

python
from crewai import Memory

# As a config dict
memory = Memory(embedder={"provider": "openai", "config": {"model_name": "text-embedding-3-large"}})

# As a pre-built callable
from crewai.rag.embeddings.factory import build_embedder
embedder = build_embedder({"provider": "ollama", "config": {"model_name": "mxbai-embed-large"}})
memory = Memory(embedder=embedder)

通过 Crew 嵌入器配置

使用 memory=True 时,团队的 embedder 配置会被透传:

python
from crewai import Crew

crew = Crew(
    agents=[...],
    tasks=[...],
    memory=True,
    embedder={"provider": "openai", "config": {"model_name": "text-embedding-3-large"}},
)

服务商示例

OpenAI(默认)
python
memory = Memory(embedder={
    "provider": "openai",
    "config": {
        "model_name": "text-embedding-3-large",
        # "api_key": "sk-...",  # or set OPENAI_API_KEY env var
    },
})
Ollama(本地、私有)
python
memory = Memory(embedder={
    "provider": "ollama",
    "config": {
        "model_name": "mxbai-embed-large",
        "url": "http://localhost:11434/api/embeddings",
    },
})
Azure OpenAI
python
memory = Memory(embedder={
    "provider": "azure",
    "config": {
        "deployment_id": "your-embedding-deployment",
        "api_key": "your-azure-api-key",
        "api_base": "https://your-resource.openai.azure.com",
        "api_version": "2024-02-01",
    },
})
Google AI
python
memory = Memory(embedder={
    "provider": "google-generativeai",
    "config": {
        "model_name": "gemini-embedding-001",
        # "api_key": "...",  # or set GOOGLE_API_KEY env var
    },
})
Google Vertex AI
python
memory = Memory(embedder={
    "provider": "google-vertex",
    "config": {
        "model_name": "gemini-embedding-001",
        "project_id": "your-gcp-project-id",
        "location": "us-central1",
    },
})
Cohere
python
memory = Memory(embedder={
    "provider": "cohere",
    "config": {
        "model_name": "embed-english-v3.0",
        # "api_key": "...",  # or set COHERE_API_KEY env var
    },
})
VoyageAI
python
memory = Memory(embedder={
    "provider": "voyageai",
    "config": {
        "model": "voyage-3",
        # "api_key": "...",  # or set VOYAGE_API_KEY env var
    },
})
AWS Bedrock
python
memory = Memory(embedder={
    "provider": "amazon-bedrock",
    "config": {
        "model_name": "amazon.titan-embed-text-v1",
        # Uses default AWS credentials (boto3 session)
    },
})
Hugging Face
python
memory = Memory(embedder={
    "provider": "huggingface",
    "config": {
        "model_name": "sentence-transformers/all-MiniLM-L6-v2",
    },
})
Jina
python
memory = Memory(embedder={
    "provider": "jina",
    "config": {
        "model_name": "jina-embeddings-v2-base-en",
        # "api_key": "...",  # or set JINA_API_KEY env var
    },
})
IBM WatsonX
python
memory = Memory(embedder={
    "provider": "watsonx",
    "config": {
        "model_id": "ibm/slate-30m-english-rtrvr",
        "api_key": "your-watsonx-api-key",
        "project_id": "your-project-id",
        "url": "https://us-south.ml.cloud.ibm.com",
    },
})
自定义嵌入器
python
# Pass any callable that takes a list of strings and returns a list of vectors
def my_embedder(texts: list[str]) -> list[list[float]]:
    # Your embedding logic here
    return [[0.1, 0.2, ...] for _ in texts]

memory = Memory(embedder=my_embedder)

服务商参考

服务商键典型模型说明
OpenAIopenaitext-embedding-3-large默认。设置 OPENAI_API_KEY。
Ollamaollamamxbai-embed-large本地,无需 API key。
Azure OpenAIazuretext-embedding-3-large默认模型。需要 deployment_id。
Google AIgoogle-generativeaigemini-embedding-001设置 GOOGLE_API_KEY。
Google Vertexgoogle-vertexgemini-embedding-001需要 project_id。
Coherecohereembed-english-v3.0强大的多语言支持。
VoyageAIvoyageaivoyage-3针对检索优化。
AWS Bedrockamazon-bedrockamazon.titan-embed-text-v1使用 boto3 凭证。
Hugging Facehuggingfaceall-MiniLM-L6-v2本地 sentence-transformers。
Jinajinajina-embeddings-v2-base-en设置 JINA_API_KEY。
IBM WatsonXwatsonxibm/slate-30m-english-rtrvr需要 project_id。
Sentence Transformersentence-transformerall-MiniLM-L6-v2本地,无需 API key。
自定义custom--需要 embedding_callable。

LLM 配置

记忆使用 LLM 进行保存分析(作用域、类别、重要性推断)、整合决策以及深度回忆查询分析。你可以配置使用哪个模型。

python
from crewai import Memory, LLM

# Default: gpt-4o-mini
memory = Memory()

# Use a different OpenAI model
memory = Memory(llm="gpt-4o")

# Use Anthropic
memory = Memory(llm="anthropic/claude-3-haiku-20240307")

# Use Ollama for fully local/private analysis
memory = Memory(llm="ollama/llama3.2")

# Use Google Gemini
memory = Memory(llm="gemini/gemini-3.7-flash")

# Pass a pre-configured LLM instance with custom settings
llm = LLM(model="gpt-4o", temperature=0)
memory = Memory(llm=llm)

LLM 是惰性初始化的——只有在首次需要时才会创建。这意味着即使没有设置 API key,Memory() 在构造时也绝不会失败。错误只会在实际调用 LLM 时才会暴露(例如在未显式指定作用域/类别时保存,或在深度回忆期间)。

如需完全离线/私有运行,可同时为 LLM 和嵌入器使用本地模型:

python
memory = Memory(
    llm="ollama/llama3.2",
    embedder={"provider": "ollama", "config": {"model_name": "mxbai-embed-large"}},
)

存储后端

  • 默认:LanceDB,存储在 ./.crewai/memory 下(如果设置了环境变量,则为 $CREWAI_STORAGE_DIR/memory,或你通过 storage="path/to/dir" 传入的路径)。
  • 自定义后端:实现 StorageBackend 协议(参见 crewai.memory.storage.backend),并将实例传给 Memory(storage=your_backend)。对于生产部署,你可以使用 crewai-mongodb-memory 包中的 MongoDBStorageBackend。了解更多,请参阅 MongoDB 实现教程。

探索

查看作用域层级、类别和记录:

python
memory.tree()                        # Formatted tree of scopes and record counts
memory.tree("/project", max_depth=2) # Subtree view
memory.info("/project")              # ScopeInfo: record_count, categories, oldest/newest
memory.list_scopes("/")              # Immediate child scopes
memory.list_categories()             # Category names and counts
memory.list_records(scope="/project/alpha", limit=20)  # Records in a scope, newest first

故障行为

如果 LLM 在分析期间失败(网络错误、限流、无效响应),记忆会优雅降级:

  • 保存分析——记录一条警告,记忆仍会以默认作用域 /、空类别和重要性 0.5 存储。
  • 提取记忆——完整内容会作为单条记忆存储,因此不会丢失任何内容。
  • 查询分析——回忆会回退到简单的作用域选择和向量搜索,因此你仍能获得结果。

这些分析失败不会抛出异常;只有存储或嵌入器失败才会抛出异常。

隐私说明

记忆内容会被发送到配置的 LLM 进行分析(保存时的作用域/类别/重要性,查询分析以及可选的深度回忆)。对于敏感数据,请使用本地 LLM(例如 Ollama),或确保你的服务商满足你的合规要求。

记忆事件

所有记忆操作都会发出带有 source_type="unified_memory" 的事件。你可以监听耗时、错误和内容。

事件描述关键属性
MemoryQueryStartedEvent查询开始query、limit
MemoryQueryCompletedEvent查询成功query、results、query_time_ms
MemoryQueryFailedEvent查询失败query、error
MemorySaveStartedEvent保存开始value、metadata
MemorySaveCompletedEvent保存成功value、save_time_ms
MemorySaveFailedEvent保存失败value、error
MemoryRetrievalStartedEvent智能体检索开始task_id
MemoryRetrievalCompletedEvent智能体检索完成task_id、memory_content、retrieval_time_ms

示例:监控查询耗时:

python
from crewai.events import BaseEventListener, MemoryQueryCompletedEvent

class MemoryMonitor(BaseEventListener):
    def setup_listeners(self, crewai_event_bus):
        @crewai_event_bus.on(MemoryQueryCompletedEvent)
        def on_done(source, event):
            if getattr(event, "source_type", None) == "unified_memory":
                print(f"Query '{event.query}' completed in {event.query_time_ms:.0f}ms")

故障排查

记忆没有持久化?

  • 确保存储路径可写(默认 ./.crewai/memory)。传入 storage="./your_path" 以使用其他目录,或设置 CREWAI_STORAGE_DIR 环境变量。
  • 使用团队时,确认已设置 memory=True 或 memory=Memory(...)。

回忆很慢?

  • 常规智能体上下文使用 depth="shallow"。将 depth="deep" 留给复杂查询。
  • 提高 query_analysis_threshold,让更多查询跳过 LLM 分析。

日志中出现 LLM 分析错误?

  • 记忆仍会以安全的默认值保存/回忆。如果你希望获得完整的 LLM 分析,请检查 API key、限流和模型可用性。

日志中出现后台保存错误?

  • 记忆保存运行在后台线程中。错误会以 MemorySaveFailedEvent 发出,但不会导致智能体崩溃。检查日志以找出根本原因(通常是 LLM 或嵌入器连接问题)。

嵌入维度不匹配?

  • 现有的本地记忆存储可能是用不同的嵌入模型创建的。默认的 OpenAI 记忆嵌入器现在是 text-embedding-3-large(3072 维),而较早的存储通常使用 1536 维嵌入。对于本地测试,请运行 crewai reset-memories -m、删除本地记忆存储目录,或显式配置之前的嵌入器模型。

并发写入冲突?

  • LanceDB 操作通过共享锁串行化,并在冲突时自动重试。这可以处理多个 Memory 实例指向同一数据库的情况(例如智能体记忆 + 团队记忆)。无需任何操作。

从终端浏览记忆:

bash
crewai memory                              # Opens the TUI browser
crewai memory --storage-path ./my_memory   # Point to a specific directory

重置记忆(例如用于测试):

python
crew.reset_memories(command_type="memory")  # Resets unified memory
# Or on a Memory instance:
memory.reset()                    # All scopes
memory.reset(scope="/project/old")  # Only that subtree

配置参考

所有配置都作为关键字参数传给 Memory(...)。每个参数都有合理的默认值。

参数默认值描述
llm"gpt-4o-mini"用于分析的 LLM(模型名称或 BaseLLM 实例)。
storage"lancedb"存储后端("lancedb"、路径字符串或 StorageBackend 实例)。
embedderNone(OpenAI text-embedding-3-large)嵌入器(配置字典、可调用对象,或 None 表示使用默认 OpenAI)。
recency_weight0.3综合评分中新近度的权重。
semantic_weight0.5综合评分中语义相似度的权重。
importance_weight0.2综合评分中重要性的权重。
recency_half_life_days30新近度分数减半所需的天数(指数衰减)。
consolidation_threshold0.85相似度高于该值时,在保存时触发合并。设为 1.0 可禁用。
consolidation_limit5合并过程中最多比较的已有记录数。
default_importance0.5未提供且跳过 LLM 分析时赋予的重要性。
batch_dedup_threshold0.98在 remember_many() 批次内丢弃近似重复项的余弦相似度阈值。
confidence_threshold_high0.8召回置信度高于该值时直接返回结果。
confidence_threshold_low0.5召回置信度低于该值时触发更深入的探索。
complex_query_threshold0.7对于复杂查询,置信度低于该值时进行更深入的探索。
exploration_budget1深度召回期间由 LLM 驱动的探索轮数。
query_analysis_threshold200短于该值(字符数)的查询在深度召回期间跳过 LLM 分析。

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。