项目:topoteretes/cognee
Stars:27.1k | 语言:Python 85% | 许可:Apache-2.0
Cognee是面向智能体的开源AI记忆平台。它用一套可本地部署的知识图谱引擎,为AI智能体提供跨会话的持久长期记忆。项目实现路径本质还是基于RAG的那套体系。
记忆数据分两层摄入:
知识记忆把文档、PDF、代码库等领域的知识,通过cognee.add()+cognify()构建成知识图谱
会话记忆把对话片段、用户偏好、交互模式等会话内容通过cognee.remember()存入系统,并且支持session_id维度的缓存
项目自身提供的Claude Code插件是典型的应用场景:记录prompts、工具调用轨迹和助手回复,在会话结束时自动同步到知识图谱。

* *
部署使用
Cognee的部署门槛很低:只要接入一个LLM的API key就能跑,因为它所有的默认数据库都是类似SQLite这种单文件数据库。
最小依赖
uv pip install cognee
只需要一个环境变量:
LLMAPIKEY="youropenaiapi_key"
默认的嵌入式存储,不需要额外服务:
| 数据库 | 职责 | 存储内容 |
| — | — | — |
| SQLite | 关系数据 | 元数据、用户、数据集、权限 |
| LanceDB | 向量存储 | embedding向量 |
| Ladybug(兼容旧Kuzu路径) | 图数据库 | 知识图谱(实体、关系、三元组) |
补充一个细节:项目文档里仍然把本地图库入口写成Kuzudb,但源码配置里的默认GRAPHDATABASEPROVIDER已经是ladybug,只是继续兼容旧的kuzu命名和历史数据路径。
Ladybug是Kuzu的直接继承者和活跃的开源分支。Kuzu原开发团队的核心成员被苹果公司收购后,原项目被归档停止维护,开源社区接管并启动了Ladybug,负责修复安全漏洞并持续推进。社区称它为“图数据库界的DuckDB”
生产环境
生产环境部署建议直接切到PostgreSQL,而且也是一个数据库搞定图、向量、会话、元数据存储,部署也很方便:
pip install "cognee[postgres]"# .envDBPROVIDER=postgresVECTORDBPROVIDER=pgvectorGRAPHDATABASEPROVIDER=postgresCACHEBACKEND=postgresDBHOST=localhostDBPORT=5432DBUSERNAME=cogneeDBPASSWORD=cogneeDBNAME=cogneedb
项目的CI benchmark说明是:同样跑在PostgreSQL上时,搜索速度比“图+向量分离”的方案快约10%,但是没说召回准确率相关的数据。
可换后端数据库
图数据库:可以切到postgres、neo4j、neptune
向量数据库:可以切到pgvector、chromadb、qdrant、weaviate、milvus
会话缓存:支持sqlite、postgres、redis、fs、tapes,默认是sqlite
支持 Docker 部署
基础 API 服务docker compose up# 加前端 UIdocker compose –profile ui up# 加 MCP 服务docker compose –profile mcp up# 全套docker compose –profile ui –profile mcp –profile postgres up
资源参考:API服务建议4 CPU / 8GB内存,MCP服务建议2 CPU / 4GB内存。
LLM 兼容性
Cognee基于litellm接主流模型提供商。切换时改provider和key就够:
LLMPROVIDER="anthropic"LLMAPIKEY="youranthropic_key"
litellm是一个Python SDK,以OpenAI兼容格式接入100多个LLM API,内置成本追踪和负载均衡。
* *
怎么接入使用
Cognee的接入方式:
Python API:精确管控使用add → cognify → search。直接走Agent记忆层,用remember → recall
import cognee# graph pipelineawait cognee.add("document.pdf")await cognee.cognify()results = await cognee.search("What is…")# memory APIawait cognee.remember("User prefers detailed explanations.", sessionid="chat1")results = await cognee.recall("What does the user prefer?", sessionid="chat1")
CLI命令行:适合快速验证和脚本集成
cognee-cli remember "Cognee turns documents into AI memory."cognee-cli recall "What does Cognee do?"cognee-cli forget –all
项目自带本地Web UI:cognee-cli -ui。另外这个命令背后的MCP server是跑在Docker容器里的,所以本机要能跑的起来Docker。
Claude Code插件:直接给Claude Code加持久记忆
claude plugin marketplace add topoteretes/cognee-integrationsclaude plugin install cognee-memory@cognee
插件会监听Claude Code的生命周期:SessionStart→UserPromptSubmit→PostToolUse→Stop→PreCompact→SessionEnd,自动注入上下文并在session结束时回刷知识图谱。
运行模式分本地和远端:本地模式默认会在http://localhost:8011自举本地Cognee API;远端/云端模式则改用COGNEEBASEURL+COGNEEAPIKEY直连远端实例。
MCP Server:标准MCP协议接入,支持HTTP / SSE / stdio三种传输模式。
docker run -e TRANSPORT_MODE=http –env-file ./.env -p 8000:8000 cognee/cognee-mcp:main
多语言客户端:除Python外,官方还提供了Rust (cargo add cognee)和TypeScript (npm install @cognee/cognee-ts)客户端。
OpenClaw插件:npm install @cognee/cognee-openclaw
Docker容器:两种方式
方式一:从源码构建docker compose up # API 服务docker compose –profile ui up # + 前端界面(localhost:3000)docker compose –profile mcp up # + MCP 服务(localhost:8001)docker compose –profile postgres up # + PostgreSQLdocker compose –profile neo4j up # + Neo4j# 方式二:拉取预构建镜像docker run –env-file ./.env -p 8000:8000 cognee/cognee:main
Cognee Cloud:官方提供的全托管服务,通过SDK直连
import cogneeawait cognee.serve(url="https://your-instance.cognee.ai", apikey="ck…")
其他云平台:Modal(Serverless)、Railway(PaaS)、Fly.io(边缘部署)、Render(托管Postgres),每个都有对应的部署脚本或一键部署方式。
* *
以上是安装部署使用的介绍,下面是主要实现部分的技术拆解,目录:
数据摄入
分片策略
检索/召回
核心算法:Brute Force Triplet Search(暴力三元组搜索)
GraphCompletionRetriever:默认检索器
存储架构
与传统RAG的差异
基准测试Benchmark
* *
数据摄入
Cognee的数据处理有两层API:
memory APIremember()、recall()、forget()、improve(), Agent记忆链路主路径
graph pipeline APIadd()、cognify()、search(),精确控制数据摄入、抽取、检索链路
如果只是Agent记忆系统,从官方quickstart看其实主要走remember/recall方法
如果看具体技术实现路径,就要看add/cognify/search这些方法实现。remember()内部实现(如果不带会话ID参数)也是走add()+cognify()。
执行主链是这样:
await cognee.add("document.pdf") # 添加数据await cognee.cognify() # 构建知识图谱results = await cognee.search("What is…")
add()负责接收、处理数据:
默认loader加载器覆盖PDF、CSV、JSON和普通文本,代码文件也是按文本导入
docx/pptx/xlsx这类Office文档,通常要额外装cognee[docling]或cognee[docs]可选依赖。
cognify()是核心处理步骤,把原始数据构建成知识图谱:
classify_documents把原始Data item归类成Document
extractchunksfrom_documents切chunk
extractgraphand_summarize并行做chunk级图抽取和摘要
adddatapoints把节点、边和embedding落到图/向量库
extractdltfk_edges如果是DLT数据,再补外键边
如果启用temporal_cognify=True,这条链会换成事件/时间戳抽取的时间线流水线(temporal pipeline)。
remember() 先决定走哪条摄入路径
remember()是统一的记忆注入入口,根据参数走不同的模式:
无sessionid(永久记忆):自动运行add()+cognify();如果不手动关闭selfimprovement,还会继续跑一次improve()做enrichment增强
有sessionid(会话记忆):先写会话缓存(session cache);只要selfimprovement=True,后台就会异步improve(dataset=…, sessionids=[sessionid]),把session的Q&A和trace桥接回永久图,同时把feedback作用到图元素权重上
这里的self_improvement不是一个抽象的“自动优化”开关,而是remember()默认附带的第二段处理:对永久记忆路径,它会在cognify()之后继续跑improve(),给图补三元组嵌入(triplet embedding)和索引;对会话记忆路径,它会把session里的内容异步桥接回永久知识图谱,让后续检索不只停留在临时cache。
会话内容是有时效性的,系统对此的处理方式如下:
会话缓存本身有独立生命周期,默认TTL是7天;但improve(sessionids=…)把会话桥接到永久图时,当前实现主要是把整段Q&A序列化后写进usersessionsfromcache这个node set,并不会把cache的TTL语义原样带到图里。
这意味着,Cognee现在对“这是不是时效性记忆”的区分,更多还是靠来源分层和上层策略,也就是需要外部业务系统处理,项目不包含永久图内建的过期治理:
usersessionsfrom_cache把原始会话回灌进图,适合保留可复用问答、偏好、反馈线索,也方便后续追溯
session_learnings先经过会话上下文的置信度和有害内容门控(harmful gating),再提炼成经验(lesson),更适合长期沉淀的“提炼后记忆”
所以“哪些值得永久化、哪些只是临时上下文、是否要在session end时同步、是否要过滤路径/任务状态/一次性噪音”这些,更多还是你在外层决定。
remember()示例
永久记忆:进入知识图谱await cognee.remember("Einstein was born in Ulm.")# 会话记忆:先写缓存,后台同步到图await cognee.remember("User prefers detailed explanations.", sessionid="chat1")

remember()还支持结构化记忆条目:
QAEntry问答对(问题、上下文、答案、反馈)
TraceEntryAgent追踪步骤(函数调用、状态、输入输出)
FeedbackEntry用户反馈(关联到某个QA)
SkillRunEntry技能运行记录
这些条目类型让Agent记住的不只是文本,还有问答、工具调用轨迹、反馈和技能运行结果。
分片策略
分片链路执行是在永久记忆路径进入cognify()之后,如果参数带sessionid,首次写入不会走分片逻辑,但是如果selfimprovement开启,需要把会话写入永久图,这时候也可能发生分片(把会话内容序列化后分片)。
Cognee默认的分片处理器是TextChunker。它的执行顺序是一条四层流水线:
async def TextChunker.read(document): buffer = [] buffersize = 0 for textblock in document.gettext(): for chunkdata in chunkbyparagraph( textblock, maxchunksize=maxchunksize, batchparagraphs=True, ): if buffersize + chunkdata["chunksize"] buffer.append(chunkdata) buffersize += chunkdata["chunksize"] elif not buffer: # 单个 chunk 本身就够大,直接产出 yield DocumentChunk(text=chunkdata["text"], …) else: # 把前面攒下来的段落块拼成一个正式 DocumentChunk yield DocumentChunk(text=" ".join(chunk["text"] for chunk in buffer), …) buffer = [chunkdata] buffersize = chunkdata["chunksize"]def chunkbyparagraph(text, maxchunksize): # 按 sentence 流累积,超上限时切一块 for paragraphid, sentence, sentencesize, endtype in chunkbysentence( text, maximumsize=maxchunksize, ): accumulatesentencesuntillimit()def chunkbysentence(text, maximumsize): # 用 embedding tokenizer 计 token;句子超上限就切成 sentencecut for word, wordtype in chunkbyword(text): accumulatewordsuntilsentenceendorsizelimit()def chunkbyword(text): # 先切最底层 token:单词 / 空格 / 句末符 / 段落换行 yield wordorsentenceboundary
它尽量保住词边界,再保句子边界,再拼成段落块,最后由TextChunker聚合成真正写入图谱的DocumentChunk。
DocumentChunk字段包含:text、chunksize、chunkindex、documentid、documentname和contains。
其中contains初始是空列表,后面extractgraphfrom_data()方法会把抽出来的chunk图谱和实体回填进去(基于LLM提取),于是形成一条chunk → contains → 节点/边的映射链,后面的检索召回也是可以通过这个字段回查DocumentChunk。
Cognee还另外提供了TextChunkerWithOverlap(带重叠)、LangchainChunker(递归字符分割)、CsvChunker(CSV专用)等分片器,但分片不是Cognee的核心,用默认的就差不多了。
检索/召回
Cognee的检索层支持17种模式,但主要检索路径有三条:
CHUNKS最轻,纯向量检索,直接返回文档块
RAG_COMPLETION中间态,用文档块做传统RAG,再交给LLM生成答案
GRAPH_COMPLETION最重,也是Cognee的主要能力,先从图里找相关三元组,再让LLM组织回答
如果显式设置GRAPH_COMPLETION模式,走的是知识图谱三元组,不是完整的文档块,而且这条路径的前提是数据摄入的时候跑过cognify()。

最简:纯向量检索,不碰知识图谱await cognee.add("docs/")results = await cognee.recall("query", querytype=SearchType.CHUNKS)# 中等:传统 RAG,文档块 + LLMresults = await cognee.recall("query", querytype=SearchType.RAGCOMPLETION)# 完整:知识图谱推理await cognee.cognify()results = await cognee.recall("query", querytype=SearchType.GRAPH_COMPLETION)
这里的GRAPH_COMPLETION依赖的是图里沉淀后的语义信息,而不是默认回灌完整原始chunk;但如果节点或者边里本身带了chunk相关文本,它也会一起被序列化进LLM上下文。这让它更擅长回答关系、归因、跨文档连接类问题,但在原文细节保真上不如RAG路线。
项目的search()和recall()方法的默认行为并不一致:
search()的默认querytype是GRAPHCOMPLETION
Python SDK的recall()如果不显式传querytype,默认autoroute=True,会先走一层规则路由
HTTP/v1/recall仍使用GRAPHCOMPLETION默认值;只有显式传searchtype=null才会自动路由
这个“自动路由”本质上还是关键词/模式匹配 + 权重打分:
if querytype is not None: # 你显式指定了类型,就按你指定的跑 # autoroute 这时只做 override 记录,不改最终执行类型 use(querytype)elif autoroute: scores = {} for pattern, searchtype, weight in RULES: if pattern.matches(querytext) and not negatednearby(querytext): scores[searchtype] += weight if not scores or max(scores.values()) 2.0: use(GRAPHCOMPLETION) # 没命中明确规则,回退默认图检索 else: use(argmax(scores)) # 分数最高的 SearchType 胜出else: use(GRAPH_COMPLETION)
路由规则大致分这几类:
Cypher语法MATCH … RETURN …这类原生图查询,直接路由到CYPHER
代码规则问题coding rules、code review、lint、refactor,再加上def / async / import / .py这类编程语境,路由到CODING_RULES
精确短语检索整句被引号包起来,或者出现exact / verbatim / literal,路由到CHUNKS_LEXICAL
摘要类问题summarize、overview、tldr、key takeaways,路由到GRAPHSUMMARYCOMPLETION
解释/推理类问题why、explain、step by step、chain of thought,路由到GRAPHCOMPLETIONCOT
关系/连接类问题related to、connected to、path between、degree of separation,路由到GRAPHCOMPLETIONCONTEXT_EXTENSION
时间类问题when、timeline、between 1910 and 1920、1915这种带明显时间信号的查询,路由到TEMPORAL
一个小细节:规则命中前会看一下附近有没有not / no / never / without这种否定词,避免把“not related to”也误判成关系查询。
autoroute目前不会把普通问答自动分到RAGCOMPLETION、CHUNKS或HYBRIDCOMPLETION。大多数没有明确特征的自然语言问题,最后会回落到GRAPHCOMPLETION,它不是基于深层语义理解的检索策略选择器。
项目支持17种SearchType,但常使用的,还是“纯chunk检索”“传统RAG”“图谱推理”这三档,再加一个recall()的自动路由。
当前SearchType枚举一共17个:
| 类型 | 用途 | 是否用LLM |
| — | — | — |
| GRAPH_COMPLETION | 图推理 + LLM回答 | ✅ |
| RAG_COMPLETION | 传统RAG,纯文档块 | ✅ |
| CHUNKS | 纯向量相似度,返回文本块 | ❌ |
| CHUNKS_LEXICAL | BM25词法匹配 | ❌ |
| SUMMARIES | 预生成摘要 | ❌ |
| CYPHER | 直接写Cypher查询图数据库 | ❌ |
| FEELING_LUCKY | 自动选最佳策略 | ✅ |
| AGENTIC_COMPLETION | 带skill/tool的Agent检索 | ✅ |
| HYBRID_COMPLETION | 混合检索(图+向量) | ✅ |
| TRIPLET_COMPLETION | 三元组直接回答 | ✅ |
| GRAPHCOMPLETIONCOT | 图推理 + 链式思考 | ✅ |
| GRAPHCOMPLETIONDECOMPOSITION | 图推理 + 问题分解 | ✅ |
| GRAPHSUMMARYCOMPLETION | 图推理 + 摘要 | ✅ |
| GRAPHCOMPLETIONCONTEXT_EXTENSION | 图推理 + 上下文扩展 | ✅ |
| NATURAL_LANGUAGE | 自然语言转图查询 | ✅ |
| TEMPORAL | 时序数据检索 | ✅ |
| CODING_RULES | 编码规则检索 | ✅ |
recall()还有一层“从哪些记忆源取”的开关。它支持scope=graph/session/trace/graphcontext/sessioncontext/all/auto。默认其实就是auto:有session_id时先查session,没有时直接查graph;如果你显式扩scope参数,它还可以同时带上trace、session context和回刷到cache的graph context。
results = await cognee.recall( "What does the user prefer?", sessionid="chat1", scope=["session", "graph"],)
* *
核心算法:Brute Force Triplet Search(暴力三元组搜索)
系统默认的GRAPH_COMPLETION走的是一套多阶段流水线:查询 → 向量搜索 → 图投影 → 距离映射 → 三元组打分 → LLM生成。
向量搜索定位种子节点
查询文本先经过embedding,然后在多个collection中并行做相似度检索。这里也不是把5个collection硬编码死了:GraphCompletionRetriever会扫描所有DataPoint子类里metadata.index_fields指定的字段,动态拼出可检索集合。默认文档 / 记忆 场景里,最核心的通常是这几个:
collections = [ "Entityname", # 实体名称 "TextSummarytext", # 文本摘要 "EntityTypename", # 实体类型 "DocumentChunktext", # 文档块 "EdgeTyperelationshipname" # 关系类型]
这一步的作用是先做一轮宽搜:从多个collection里拿到相关节点候选,同时也拿到边类型相关的向量分数,供后面映射到图上。注意:真正拿来做图投影种子的主要是节点ID,不是边类型ID。单query默认会用widesearchtop_k=100截断这批候选,再做后面的子图投影,batch查询则直接走全图投影。
图投影——两种模式
拿到种子节点ID后,从图数据库中拉出相关子图。两种模式通过neighborhood_depth参数切换:
ID过滤投影(单query默认):先用种子节点ID过滤,从图数据库拉相关子图。如果图数据库支持getidfilteredgraphdata,会优先走ID过滤;如果adapter不支持,或者过滤结果为空,才回退到拉全图。
邻域投影:以种子节点为起点,沿边扩展k跳,只拉局部邻域。这种方式在大图上更高效,避免拉出不相关的远端节点。
上面这套“种子节点 -> 子图投影”的描述主要对应单query路径。batch查询时不会从宽搜结果里抽种子节点ID,而是直接投影全图,再分别按query计算triplet排名。
nodesdata, edgesdata = await adapter.getneighborhood( nodeids=seednodeids, depth=depth, # 跳数,如 1、2、3 edgetypes=edgetypes # 可选:只沿特定关系类型走)
邻域模式还有一个细节:对扩展发现的新节点,会补一轮ID过滤的向量搜索,让这些节点也有向量分数,参与后续排序。
距离映射
图投影完成后,图中的节点和边还没有"相关性分数"。距离映射就是把向量搜索的结果"写"到图元素上。
具体过程:
1.向量搜索返回一批结果,每个结果有id和score(cosine距离,范围0~2,越小越相关)
2.遍历这些结果,在图中找到对应的节点或边
3.把score写到该节点/边的vector_distance字段
节点距离映射for result in nodedistances: node = graph.getnode(result.id) # 在图中找到这个节点 node.vectordistance = result.score # 写入向量分数# 边距离映射for result in edgedistances: edges = graph.edgesbydistancekey[result.id] # 通过 edgetypeid 找到匹配的边 for edge in edges: edge.vectordistance = result.score
未命中的元素怎么办?
图中有些节点/边没有被向量搜索命中(不在topk结果里),它们的vectordistance会被设为默认惩罚值tripletdistancepenalty(默认6.5)。
这个惩罚值有讲究:正常的cosine距离范围是0~2,惩罚值6.5远大于这个范围。这意味着:
被向量命中的元素:距离0~2,排序靠前
未被命中的元素:距离6.5,排序靠后
这样就实现了"向量搜索快速缩小范围,图结构补充关系"的效果。
三元组打分
每个三元组(Node1 – Edge – Node2)的分数计算方式:
def score(edge): importances = [] for element in [node1, node2, edge]: distance = element.vectordistance[queryindex] importanceweight = element.importanceweight # 取不到时回退到 0.5 feedbackweight = element.feedbackweight # 用户反馈累积 # 核心公式:重要性权重调整距离 adjusteddistance = (2 – importanceweight) * distance # 混合反馈权重 final = blend(adjusteddistance, feedbackweight) importances.append(final) return sum(importances) # 三个元素的距离求和
排序逻辑:距离越小越相关。用heapq.nsmallest(k, edges, key=score)取top_k个三元组。
importanceweight的含义:权重越高,调整后的距离越小,该元素越容易被选中。不过这里也要说清楚:源码默认投影的importanceweight主要是节点属性;edge在很多场景下拿不到这个字段,会回退到默认值0.5。所以它更准确地说是“让重要节点更容易被选中”,而不是“所有关系边都会同等享受这个加权”。
反馈权重混合
Cognee的反馈机制类似点赞:用户使用中对回答答案给出1-5分评分,好答案的来源节点权重会提升,坏答案的来源节点权重会压低。
反馈来源:Session中的QAEntry记录了feedbackscore(1-5分)和usedgraphelementids(这次问答使用了哪些图节点/边)。
识别条件:
feedback_score必须是1-5的整数
usedgraphelementids必须包含nodeids或edge_ids(知道哪些节点/边被用过)
还没有被处理过(避免重复更新)
权重更新公式(指数移动平均):
def streamupdateweight(previousweight, feedbackscore, alpha): # feedbackscore 1-5 映射到 0-1 normalizedrating = (feedbackscore – 1) / 4 # EMA 更新:alpha 控制学习率 updated = previousweight + alpha * (normalizedrating – previousweight) return max(0.0, min(1.0, updated)) # 裁剪到 [0, 1]
检索时的影响:
默认情况下反馈权重不参与排序。feedbackinfluence默认值是0.0,也就是默认检索不混入反馈权重;只有你显式把feedbackinfluence调大,或者改了全局配置,下面这套blending才会参与排序。
feedback_influence(0~1)控制反馈对排序的影响程度:
def effectivedistance(distance, feedbackweight): # 只对有效距离(0~2范围内的 cosine 距离)做混合 if distance >= tripletdistancepenalty or distance 0 or distance > 2: return distance # 惩罚值不参与混合 normalizeddistance = distance / 2.0 blended = (1 – feedbackinfluence) * normalizeddistance + feedbackinfluence * (1 – feedbackweight) return blended * 2.0
feedback_weight越高(接近1),混合后的距离越小,该元素排名越靠前。
关键点:
反馈是显式的(用户主动给1-5分)
关联是精确的(只更新实际用到的节点/边)
更新是渐进的(EMA,不会剧烈波动)
默认是关闭混合影响的;要显式把feedback_influence打开,反馈才会进入召回排序
完整流程

* *
GraphCompletionRetriever:默认检索器
GraphCompletionRetriever位于cognee/modules/retrieval/graphcompletionretriever.py,是图检索的默认实现。
完整流水线
class GraphCompletionRetriever(BaseRetriever): async def getcompletion(self, query): # 1. 准备(含 session 上下文) turnpreparation = await self.preparesessionturnforretrieval(query) # 2. 检索三元组 retrievedobjects = await self.getretrievedobjects(query) # 3. 三元组 → 文本上下文 context = await self.getcontextfromobjects(query, retrievedobjects) # 4. LLM 生成回答 completion = await self.getcompletionfromcontext(query, context) return completion
关键特性
全局上下文索引:设置includeglobalcontext_index=True后,会在triplet context之前先拼一段全局前言。它由root summary和top summaries组成,本质上还是对TextSummary的向量检索。
参考文献:设置include_references=True后,Cognee不会直接把“这次命中的图元素”拿来当引用,而是会拿生成后的回答再反查chunk index,补一段证据块(Evidence block)。
批量查询:支持query_batch参数,一次处理多个查询,内部共享图投影,减少重复计算。
Session 缓存机制
Cognee的会话缓存是一整套session级结构化数据,也就是问答对(question/context/answer)记录:
await cognee.remember("User prefers detailed explanations.", sessionid="chat1")results = await cognee.recall("What does the user prefer?", sessionid="chat1")
这个缓存和Claude Code / Codex保存的会话transcript不是一类东西。后两者主要是为了恢复和继续agent会话;Cognee的session cache更像一个可检索的会话记忆层,会先把结构化会话内容缓存下来参与召回,并可在self_improvement开启时进一步同步到永久知识图。
这个“结构化会话内容”首先就是一轮QA。正常的session回答链路会把每一轮存成question / context / answer这样的结构化问答对,后续session recall取回的也是这些QA记录;但如果你是直接调用remember(…, sessionid="chat1")往会话里塞一段内容,首次写入的则不是完整问答,而更像一条question=""、context=""、answer=text的会话记忆记录。除了QA之外,session cache里还可以带agent trace、sessioncontext和graphcontext。
Session缓存的工作方式,用伪代码写大致是这样:
async def remember(data, *, sessionid=None, selfimprovement=True): if sessionid is None: # 永久记忆路径:add -> cognify -> improve return await addandcognify(data) # 会话记忆路径:先写 session cache await addtosessioncache( sessionid=sessionid, qa={ # 正常 session turn 通常是完整 question/context/answer # 直接 remember(sessionid=…) 注入时,往往更像 answer=text "question": "", "context": "", "answer": data, }, ) # 默认后台再跑 improve,把 session 内容桥接回永久图 if selfimprovement: spawnbackgroundtask( improve(dataset="maindataset", sessionids=[sessionid]) )async def recall(query, *, sessionid=None, datasets=None, querytype=None, scope="auto"): if scope == "auto": if sessionid and not datasets and querytype is None: # 默认会话模式:先查 session,再决定要不要掉回 graph sessionhits = await searchsessionqa(query, sessionid=sessionid) if sessionhits: return sessionhits # short-circuit return await searchgraph(query) if sessionid and (datasets or querytype is not None): # 显式带 dataset / querytype 时,session 和 graph 一起参与 return merge( await searchsessionqa(query, sessionid=sessionid), await searchgraph(query, datasets=datasets, querytype=querytype), ) return await searchgraph(query) # 显式 scope 时,还可以把 trace / graphcontext / sessioncontext 一起带上 return await recallfromexplicitsources( query, sessionid=session_id, scope=scope, )
remember(sessionid=…)负责把内容先放进会话缓存;recall(sessionid=…)则在默认模式下优先查session QA,只有没命中时才继续掉回图检索。只有你显式扩scope,或者同时给了datasets / query_type,它才不再是简单的“session first, graph fallback”。
* *
存储架构
Cognee 1.0的一个特点:把所有存储层统一到PostgreSQL。
传统方案 Cognee 方案─────────────────────────────────────────Neo4j (图) → Cognee 的 Postgres graph backendRedis (会话) → SQL session cache向量数据库 → pgvector关系数据库 → PostgreSQL
本地开发模式更轻量:SQLite + LanceDB + Ladybug/Kuzu兼容图库,零外部依赖,全部是单文件数据库,会话缓存默认也是SQLite。
* *
与传统 RAG 的差异
Cognee的整体架构本质上仍然在RAG范式里:文档摄入、分块、索引、召回、LLM生成,这些骨架都没变。它在传统chunk-RAG之外叠了一层图检索和会话记忆机制,重点增强的是Agent场景下的关系召回、会话连续性和知识沉淀。
下面这张对比表可以理解为“传统chunk-RAG”和“Cognee的完整memory + graph路线”的对比,因为实际上Cognee不是所有检索都会自动走图谱三元组:
| 维度 | 传统RAG | Cognee(记忆增强RAG) |
| — | — | — |
| 索引结构 | 文档块 + 向量 | 文档块 + 向量 + 知识图谱 + session cache |
| 主要检索单元 | 文档块(chunk) | 可切换:chunk、图三元组、session QA |
| 生成上下文 | 相似文档块拼接 | 取决于模式:文档块、图三元组文本化结果、会话上下文 |
| 多跳关系召回 | 通常靠多次检索或上层编排 | 图路径更容易显式表示关系链,但回答仍要靠LLM组织 |
| 会话记忆 | 通常靠外部对话层补 | 内建Session缓存,并可桥接到永久图 |
| 反馈机制 | 通常无内建反馈回路 | 有显式feedbackweight / feedbackinfluence,但默认不是强开启 |
| 知识持久化 | 多为一次性建索引后查询 | 支持追加摄入、session桥接和部分权重更新,但不等于默认在线持续学习 |
核心区别在于:
图结构让检索不只盯着chunk相似度,还能显式利用实体、边和关系路径
记忆层Session缓存、session → graph桥接、可选反馈权重,让系统多了一层“会话记忆”能力
多路检索既能当纯chunk-RAG用,也能切到图检索或混合检索,而不是只有一条图谱路径
* *
基准测试 Benchmark
Cognee当前公开了两组比较有代表性的benchmark结果:一组是长上下文记忆场景下的BEAM,另一组是多跳问答场景下的HotPotQA子集评测。
BEAM:长上下文记忆
BEAM测试系统在长对话中追踪信息变化的能力,比传统的needle-in-a-haystack更贴近Agent记忆场景。
| 设置 | Cognee | 前任SOTA | RAG基线 |
| — | — | — | — |
| 100K tokens | 0.79(按题路由可到 >0.8) | 0.735 | ~0.33 |
| 10M tokens | 0.67 | 0.641 | ~0.33 |
Cognee自称在100K设定下超过了前任SOTA,在10M设定下大致打平。而且提醒:这组数字更适合看趋势,不太适合脱离具体方法细节单独拿出来下结论。
HotPotQA:多跳问答
项目在一个24题的HotPotQA子集上做了repeated-run评估,并把整组实验概括成45个评估轮次(evaluation cycles)。
参与对比的系统包括:
Mem0基于OpenAI的记忆QA系统
GraphitiLangChain + Neo4j知识图谱QA
LightRAGFalkor的GraphRAG-SDK
评估指标包括DeepEval Correctness、EM、F1和Human-like Correctness。
Cognee在DeepEval Correctness(0.846)、EM(0.687)、F1(0.841)三项上领先;但Human-like Correctness最高的是LightRAG(0.955),Cognee是0.925,并不是所有指标都第一。
这也说明了Cognee的成绩和具体检索配置关系很大。单看benchmarksummarycognee.json,GRAPHCOMPLETIONCOT是表现最好的一档,其次是GRAPHCOMPLETIONCONTEXTEXTENSION,最后才是基础GRAPHCOMPLETION。如果换回默认基础配置,Cognee Graph Completion的分数会明显低一档:Correctness 0.743、EM 0.596、F1 0.724、Human-like Correctness 0.805。


* *
最后
如果你也在构建Agent记忆系统这样的项目,Cognee的很多实现细节是个很好的参考,甚至可以直接集成到项目中。
如果你在构建RAG知识库项目,Cognee也值得参考,它本身就是一个RAG系统。当成RAG知识库使用也是可以的,而且部署也很简单。
拆解LangChain刚开源的OpenWiki:如何落地个人Wiki知识库
RAG知识库的核心组件:PDF/OCR解析 看这些开源项目就够了

