只看单个 agent,记忆好像只是“把用户说过的话保存下来,下一次搜出来”。一旦进入真实产品,边界会迅速变厚: 数据可能来自聊天、文件、网页、企业云盘、代码仓库;处理可能要排队、抽取、切块、建索引;检索结果要按用户、项目、租户隔离; 过期和删除也要能被解释。Cognee 和 Supermemory 的价值,正在于它们把这些工程责任放到了显式平台层。

场景:你要给一个团队知识助手接长期记忆

输入不再只有聊天:
  会议记录、设计文档、网页、Google Drive、GitHub issue、客服历史

调用方也不止一个:
  聊天 agent、搜索页、工单助手、代码助手、后台同步任务

平台层必须回答:
  这份内容属于谁?
  处理到哪一步了?
  查询时返回画像、证据片段,还是图关系?
  用户撤回数据时删到哪里才算删干净?

这就是 Cognee 和 Supermemory 不应只被当成“大一点的 RAG”的原因。它们真正暴露出来的是记忆平台的合约: 数据怎样进入、怎样被加工、怎样按边界召回、怎样让多个调用方安全地复用。

阅读契约。 读完这一篇,应该能回答三件事:Cognee 的 remember() 为什么还能落回 add()cognify()improve() 这条知识图谱管线; Supermemory 的 addprofilesearch 和 connectors 为什么更像产品化 context API; 以及在自己的系统里,什么时候该选“知识层”,什么时候该选“上下文平台”。

这篇可以用同一份资料来读:一份“客服升级策略”文档。放进 Cognee 时,问题是怎样把资料加工成可复用知识; 放进 Supermemory 时,问题是怎样让产品通过 API 拿到画像、搜索结果和连接器上下文。下面这张表先把两个生命周期对齐。

边界 Cognee 路线 Supermemory 路线
写入入口 add / remember 接收文件、文本或 URL。 add 用 content、URL、metadata、containerTag 建立记忆对象。
处理状态 cognify 把 dataset 加工成 graph / vector 可检索层。 API 暴露 queued、processing、done 等状态,托管管线负责抽取与索引。
召回输出 search 更像面向知识层的查询结果。 profile 给稳定画像,search 给当前问题证据。
删除边界 重点是自托管数据集和知识加工产物如何治理。 重点是产品对象、连接器和 containerTag 范围内的数据如何撤回。

证据边界。 本文使用 topoteretes/cogneesupermemoryai/supermemory 的公开 README、文档和源码。 Cognee 本地 SDK 与开源服务端代码可直接追踪;Supermemory 的托管服务内部抽取策略不可见,本文只按公开文档、SDK 示例和 API schema 描述合约。

一、为什么平台化是最后一站

1.1 前面几层的问题,到平台层会同时出现

把 Cognee 和 Supermemory 放在最后,是因为它们需要前面几层作为铺垫。先看过 Mem0 的写入取舍、Letta 的 agent state、 Graphiti 的时间图、LangMem 的执行路径、TencentDB-Agent-Memory 的上下文卸载,再读这两个项目,才容易看见它们合并了哪些责任: 长期记忆最终要被谁拥有,怎样被处理,又通过什么 API 进入这一轮模型上下文。

到平台层以后,记忆不再只是单个 agent 的能力。一个产品可能同时接入聊天记录、文档、网页、邮件、代码仓库和第三方应用; 同一条资料可能属于用户、团队、项目、数据集或租户;一次查询可能要拿用户画像、相似片段、相关文件、图关系和权限过滤后的结果。 所以 Cognee / Supermemory 的问题不是“有没有长期记忆”,而是“长期记忆怎样成为多人、多源、多调用方都能依赖的基础设施”。

1.2 平台化以后,最难的是边界而不是召回

平台化以后,记忆至少要承担四类公共责任。第一是 scope:同一套服务要区分用户、项目、数据集、租户; 第二是 process:原始内容进入以后,要经历抽取、切块、嵌入、建图或建索引; 第三是 retrieve:调用方不只要文本相似结果,还可能要图关系、用户画像、相关文档和当前可用上下文; 第四是 delete:当用户、项目或数据源撤回内容时,平台要给出可操作的删除边界。

这四类责任正好对应平台常见故障。scope 不清,会把 A 用户的材料带进 B 用户的上下文;process 不清, 调用方不知道内容是待处理、已切块、已嵌入,还是已经进入图;retrieve 不清,搜索结果会混合画像、证据和文档片段; delete 不清,连接器断开以后旧内容还可能继续影响模型。平台化的价值,是把这些责任从应用 prompt 里搬出来。

Cognee 和 Supermemory 平台记忆图,右侧列出 scope、process、retrieve、delete 四个平台责任
这张图只抓一个主线:Cognee 更偏“先把资料变成知识层”,Supermemory 更偏“把上下文能力包装成 API 和连接器”。

二、Cognee:先把资料变成可检索、可推理的知识层

Cognee README 给自己的定位是 open-source AI memory platform:接收任意格式数据,构建 self-hosted knowledge graph, 让 agents 跨会话 recall、connect、act with context。README 的介绍还明确提到 vector embeddings、graph reasoning、 ontology generation,说明它的目标超过向量索引:原始资料要被加工成可连接的知识层。 这些定位可以看 README 的 About Cognee

2.1 用户看到的是 remember / recall,底下仍是管线

Cognee 的 quickstart 现在把 API 简化成四个动作:rememberrecallforgetimprove。示例里 remember() 既能永久写入知识图谱, 也能带 session_id 写入 session memory;recall() 则按 query 自动路由。 这一层接口看起来很轻,见 README quickstart

源码把这个轻接口展开了。remember() 的 docstring 明确区分两条路径:没有 session_id 时是 permanent memory,会跑 add()cognify();有 session_id 时先写 session cache,再在默认 self_improvement=True 时把 session 数据桥接到永久图。永久路径实际执行时,内部的 _run()add(...),再 cognify(...),最后按配置调用 improve(...)

async def remember(data, dataset_name="main_dataset", session_id=None, self_improvement=True):
    if session_id:
        # session memory: fast cache, then optional bridge into permanent graph
        ...

    async def _run():
        await add(data=data, dataset_name=dataset_name, ...)
        cognify_result = await cognify(datasets=[dataset_name], ...)

        if self_improvement:
            await improve(dataset=dataset_name, user=user)

这段调用链让 Cognee 的产品接口变得容易理解:remember() 是门面,add() 负责接入, cognify() 负责把资料转成图和向量可检索结构,improve() 负责继续增强。 调用方看到的是一个动词,平台内部保留了明确阶段。

用户动作 平台内部责任 为什么要拆开
remember(data) add 接入原始数据,cognify 生成知识图谱,improve 做后续增强。 调用方只关心“记住”,平台负责数据进入后的多阶段处理。
remember(data, session_id) 先写 session cache,再把可沉淀内容桥接到永久图。 当前会话要快,长期知识层可以异步变好。
recall(query) 按 scope、query type 和 session 信息路由到 session、graph 或 graph context。 同一个问题可能先查短期会话,也可能直接查永久图。

2.2 addcognify 把“资料”变成“知识图”

add() 是第一步,负责接收文本、文件、URL、binary streams 等输入,并把它们放进 dataset,供后续处理。 它的 docstring 也把 workflow 写成 data resolution、content extraction、dataset storage、metadata tracking、 permission assignment。所以 Cognee 的边界从 query 之前就开始:平台先拥有一个明确的数据接入层。

第二步是 cognify()。 这个函数把已接入数据转成 structured knowledge graph:文档分类、文本切块、实体抽取、关系检测、图构建和内容摘要都在它的说明里。 这里的价值在于中间层:平台先把原始材料加工成更稳定的结构,后面不同 agent、不同查询策略都可以复用它。

检索端也延续这个思路。search() 的参数里有 query_type、datasets、top_knode_name、 neighborhood、references 等控制项;它的说明列出 GRAPH_COMPLETIONRAG_COMPLETIONCHUNKSCYPHERCHUNKS_LEXICAL 等搜索类型。 对调用方来说,请求已经从“给我最相似的 10 段文本”变成了“在这个知识层里选一种回答方式”。

await add(data, dataset_name="company_docs")

await cognify(
    datasets=["company_docs"],
    graph_model=KnowledgeGraph,
    chunker=TextChunker,
)

results = await search(
    query_text="How should we handle customer escalation?",
    query_type=SearchType.GRAPH_COMPLETION,
    datasets=["company_docs"],
    include_references=True,
)
形状示例:同一份文档在 Cognee 里的生命周期

add / remember:
  source = "客服升级策略..."
  dataset = "company_docs"

cognify:
  dataset 被切分、抽取实体和关系,并生成图 / 向量可检索层

search:
  query = "客户投诉升级到谁?"
  结果来自处理后的知识层,并可带回 reference

用这条链看 Cognee,就不会把它误读成单纯“上传文件后向量搜索”。add 只是把资料放入 dataset; cognify 才开始文档分类、切块、实体关系抽取和图构建;search 则让调用方选择图回答、 RAG 回答、chunk 检索或 Cypher 查询等不同视角。

2.3 Cognee 的优势,是把公司知识变成可治理的中间层

Cognee 最适合的场景,是你有一批资料、业务文档、代码、客户历史或专家经验,希望它们经过处理后成为 可重复使用、可追踪、可自托管的知识层。README 的 use cases 也偏向 customer support agent、 SQL copilot、company brain 这类“领域知识要被多个任务复用”的问题。

代价也来自同一个设计。知识层越重,就越要关心处理延迟、数据集权限、图模型、ontology、搜索类型和运维部署。 如果你的需求只是“这个用户喜欢深色模式,下次回答时记得”,直接上完整知识图谱可能过重; 如果你的需求是“多个 agent 要长期复用一组企业知识,并且要解释关系和来源”,Cognee 这条路线就更自然。

2.4 它更像知识加工层,不是轻量偏好存储

用 Cognee 时最好先问一个问题:这份资料是否值得被加工成中间层。值得的情况通常有三个信号: 第一,资料会被多个 agent 或多个流程复用;第二,关系和来源比单段文本更重要;第三,系统需要自托管和可治理的数据处理链。 如果这三个信号都不强,Cognee 的 dataset、cognify、graph search 可能会显得笨重。

反过来说,一旦这些信号成立,Cognee 的优势就不是“多一种搜索方式”,而是让资料先离开临时 prompt,进入可重复加工的知识层。 这层可以后续继续 improve、重新 search、按 dataset 管理,也能让不同 agent 面向同一组公司知识工作。

三、Supermemory:把记忆、画像、搜索和连接器包装成 context API

Supermemory README 的定位更产品化:memory and context layer for AI。它把 memory、user profiles、hybrid search、 connectors、multi-modal extractors 放在同一张功能表里,还明确说可以给 AI products 提供 single API。 这条线的重心从手写图谱管线转向可接入的 API 面:内容进入、上下文生成、用户画像、搜索和同步,都由平台包装出来。 这些材料见 README 开头Build with Supermemory

3.1 add 会触发记忆抽取

Supermemory 文档把入口说得很直接:把 conversations、documents、files、URLs 发给 Supermemory,系统自动抽取 memories。 Add context 文档 还建议使用 customId 标识 conversation ID 或 document ID,以便更新和去重。 同一页的参数表把 contentcustomIdcontainerTag、metadata、 entityContextdreaming 都列出来;containerTag 用来按用户或项目分组, 也是 user profiles 的必要边界。

公开 API schema 也能看到这一层边界。 MemorySchema 包含 content、metadata、source、status、summary、title、type、url、containerTagschunkCount 等字段。这些字段让一份内容在平台里的生命周期变得可见: 它来自哪里、处理到什么状态、属于哪些容器、被切成多少 chunks。

const MemorySchema = z.object({
  customId: z.string().nullable().optional(),
  content: z.string().nullable().optional(),
  metadata: MetadataSchema.nullable().optional(),
  source: z.string().nullable().optional(),
  status: DocumentSchema.shape.status,
  summary: z.string().nullable().optional(),
  containerTags: z.array(z.string()).optional(),
  chunkCount: z.number().default(0),
});

这个 schema 说明 add 的结果不只是“存了一段文本”。customId 负责和业务系统里的文档或会话对齐; containerTags 负责用户、项目或空间隔离;statuschunkCount 让调用方知道后台处理是否完成。

文档里的 processing pipeline 进一步把这件事展开:添加内容后,Supermemory 会 validate request、store and queue、 extract content、chunk into searchable memories、embed、index。这个顺序见 Processing Pipeline。 对产品开发者来说,这意味着“记忆”已经变成后台处理队列和 API 状态机,离开了 prompt 模板里的临时数组。

Supermemory add pipeline:
  validate request
  -> store document and queue processing
  -> extract content (OCR / transcription / web scraping)
  -> chunk into searchable memories
  -> embed
  -> index

Progress:
  GET /v3/documents/{id} -> queued | processing | done
形状示例:同一份文档在 Supermemory 里的状态变化

add:
  content = "客服升级策略..."
  containerTag = "support-team"
  status = "queued"

worker:
  status = "processing"
  派生的可检索产物正在生成

later search:
  status = "done"
  profile / search 可返回当前问题需要的背景和证据

3.2 profile 给模型一个稳定底座,search 负责具体问题

Supermemory 的一个清晰产品判断,是把 user profile 从普通搜索里拆出来。 User Profiles 文档 把 profile 分成 static 和 dynamic:static 是长期稳定事实,比如职业、偏好、专长;dynamic 是最近上下文和临时状态。 这样做的好处很实际:模型每轮不用靠三五次搜索拼出用户是谁,先拿到一个宽背景,再用 search 补具体细节。

README 里的 API 示例也是这个形状:client.add({ content, containerTag }) 写入对话, client.profile({ containerTag, q }) 一次返回 profile.staticprofile.dynamic 和相关 searchResults。 它把“用户是谁”和“这次问题需要什么证据”分开交给调用方,而不是混成一个结果列表。

await client.add({
  content: conversation,
  customId: "conv_123",
  containerTag: "user_123",
});

const { profile, searchResults } = await client.profile({
  containerTag: "user_123",
  q: "programming style",
});

// profile.static  -> 长期稳定事实
// profile.dynamic -> 最近上下文
// searchResults   -> 和本轮问题相关的证据

搜索端,Searchv4RequestSchema 暴露 containerTag、threshold、filters、include、limit、query、rerank、rewriteQuery 等参数; 返回端的 MemorySearchResult 则包含 memory、similarity、version、parents / children context、documents。这里的 context 不再只是一段文本, 而是带相似分、版本、关系和关联文档的结果对象。

const Searchv4RequestSchema = z.object({
  containerTag: z.string().optional(),
  threshold: z.number().default(0.6),
  filters: SearchFiltersSchema.optional(),
  include: z.object({
    documents: z.boolean().default(false),
    summaries: z.boolean().default(false),
    relatedMemories: z.boolean().default(false),
  }),
  limit: z.number().default(10),
  q: z.string().min(1),
  rerank: z.boolean().default(false),
  rewriteQuery: z.boolean().default(false),
});

const MemorySearchResult = z.object({
  memory: z.string(),
  similarity: z.number(),
  version: z.number().nullable().optional(),
  context: z.object({ parents: z.array(...), children: z.array(...) }).optional(),
  documents: z.array(MemorySearchDocumentSchema).optional(),
});

因此 Supermemory 的检索合约有两个层次:请求侧用 containerTag、filters 和 threshold 控制边界与召回宽度; 返回侧用 similarity、version、parents / children 和 documents 说明“为什么这条 memory 和问题有关”。 这比普通向量库的 top-k chunk 更接近产品 API。

连接器则把平台边界继续往外推。Supermemory connectors 文档列出 Google Drive、Gmail、Notion、OneDrive、GitHub、 Granola 和 Web Crawler,并说明它们会自动同步外部文档进入知识库。 How Connectors Work 把流程写成创建连接、用户授权、自动建立连接、通过 webhooks 或定时同步持续更新。 到这一步,记忆已经接近产品基础设施:它要面对 OAuth、webhook、文件版本、同步状态和用户空间。

3.4 它更像产品上下文 API,不是只给 agent 用的库

Supermemory 的强项,是把接入成本压到 API 和连接器层。产品可以先把对话、文档、URL 或文件交给平台, 再通过 profilesearch 得到可用上下文。这样做牺牲了一部分内部可见性: 公开材料能看到请求参数、返回 shape 和处理状态,但托管服务内部怎样抽取、怎样合并、怎样重排,并不都在开源代码里。

因此它适合“我要尽快把产品接上长期上下文”的团队,而不是“我要完全掌控知识图谱每一步加工”的团队。 前者看重 connector、containerTag、profile、search 和 hosted pipeline;后者可能更倾向 Cognee 这类自托管知识层。

四、怎么选:知识层、上下文 API,还是前面几条路线

4.1 先判断系统处在哪个阶段

Cognee 和 Supermemory 都把记忆做得更“平台”,但它们的入口问题不同。Cognee 先问:我怎样把一批资料加工成可复用的知识层? Supermemory 先问:我怎样让产品用一个 API 得到记忆、画像、搜索、连接器和文件处理?这两问都成立,只是面向的系统阶段不同。

系统压力 更自然的路线 判断方式
想在应用和模型之间加一层长期记忆,重点是写入、去重、时间、衰减和检索排序。 Mem0 先看 memory layer 的写入与检索算法。
记忆本身就是 agent state 的一部分,要和 persona、human profile、tools、messages 一起存在。 Letta 先看 agent state 谁拥有、怎样编译进上下文。
事实会随时间变化,旧事实不能直接删除,还要保留来源和有效期。 Graphiti 先看 temporal graph 和 episode provenance。
记忆写入会影响 agent 当前回答路径,需要决定同步工具还是后台整理。 LangMem / LangGraph 先看 hot path、background manager、store、checkpointer。
公司资料、文档、代码和专家经验要被加工成可复用知识层。 Cognee 先看 add、cognify、search、dataset、graph/vector 配置。
产品想快速接入记忆、画像、搜索、连接器和文件处理。 Supermemory 先看 add、profile、search、connectors、containerTag 边界。

如果把这个系列压成一句话,就是:不要先问“用哪个向量库”。先问这份历史属于谁,是证据、画像、关系、工作流状态、知识层, 还是当前模型上下文。Cognee 和 Supermemory 把问题推进到了平台层,也提醒我们:长期记忆做大以后,难点常常在数据来源、 处理责任、检索合约和删除边界,而不只是把内容搜出来。

参考资料