Graphiti 源码架构与实现教程
项目:
getzep/graphiti目标:从 架构 → 数据模型 → 写入流程 → 检索流程 → Driver → LLM/Embedding → 服务层 → 每个代码模块 ,逐层拆解 Graphiti。
分析基线:GitHub
main分支,检查时间 2026-08-19 ;根目录pyproject.toml中graphiti-core版本为 0.29.3 。说明:本文以"源码阅读教程"的方式组织,不逐行复制源码,而是解释源码职责、关键函数、调用关系与设计意图。这样既便于理解,也不受行号频繁变化影响。
目录
- [先建立全局认知:Graphiti 到底是什么](#先建立全局认知:Graphiti 到底是什么)
- [总体架构:六层理解 Graphiti](#总体架构:六层理解 Graphiti)
- 仓库目录总览
- 核心图数据模型:Episode、Entity、Fact、Community、Saga
- [时间模型:Graphiti 为什么适合"记忆"](#时间模型:Graphiti 为什么适合“记忆”)
- [
Graphiti类:整个系统的总编排器](#Graphiti 类:整个系统的总编排器) add_episode():一次记忆写入的完整源码流程- 节点抽取与实体去重
- 关系抽取、事实去重与时间失效
- [Episode、MENTIONS 与事实溯源](#Episode、MENTIONS 与事实溯源)
- Saga:连续会话/事件链如何组织
- [批量写入
add_episode_bulk()](#批量写入 add_episode_bulk()) - 搜索系统总览:不是单纯向量检索
- BM25、Cosine、BFS、RRF、MMR、Cross-Encoder
- [SearchConfig 与搜索配方](#SearchConfig 与搜索配方)
- [Node / Edge Namespace:新一代数据访问 API](#Node / Edge Namespace:新一代数据访问 API)
- [Driver 层:Neo4j / FalkorDB / Neptune / Kuzu](#Driver 层:Neo4j / FalkorDB / Neptune / Kuzu)
- [LLM Client 层](#LLM Client 层)
- [Prompt 系统:Graphiti 的"认知逻辑"放在哪里](#Prompt 系统:Graphiti 的“认知逻辑”放在哪里)
- [Embedder 与 Cross-Encoder](#Embedder 与 Cross-Encoder)
- Community:图社区与摘要
- 维护、去重、属性抽取工具链
- [FastAPI Server](#FastAPI Server)
- [MCP Server](#MCP Server)
- Tracing、Telemetry、并发与容错
- [
graphiti_core每个模块源码地图](#graphiti_core 每个模块源码地图) - 服务、示例、测试与工程目录逐项说明
- 完整函数调用关系总图
- [如何扩展 Graphiti](#如何扩展 Graphiti)
- 源码阅读顺序与调试建议
- 术语与缩写字典
- [最终总结:把 Graphiti 看成什么最准确](#最终总结:把 Graphiti 看成什么最准确)
第1章 先建立全局认知:Graphiti 到底是什么
Graphiti 的定位不是"一个图数据库 SDK",也不是"一个向量数据库包装器"。
更准确地说:
Graphiti 是一套把连续事件转换成可更新、可追溯、带时间语义的知识图,并提供混合检索能力的 Agent Context / Memory Engine。
它试图解决的是:
- Agent 每天不断接收新的对话、事件、业务数据;
- 新信息可能补充旧信息,也可能推翻旧信息;
- 不能只保留"最新值",因为过去事实仍可能有价值;
- 检索时不仅要按"语义像不像"找,还要考虑:
- 关键词;
- 图结构邻近性;
- 信息来源;
- 时间;
- 实体关系;
- 候选结果的精排。
因此 Graphiti 的基本思想可以概括为:
#mermaid-svg-smls9hdAKNSVu57r{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-smls9hdAKNSVu57r .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-smls9hdAKNSVu57r .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-smls9hdAKNSVu57r .error-icon{fill:#552222;}#mermaid-svg-smls9hdAKNSVu57r .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-smls9hdAKNSVu57r .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-smls9hdAKNSVu57r .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-smls9hdAKNSVu57r .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-smls9hdAKNSVu57r .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-smls9hdAKNSVu57r .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-smls9hdAKNSVu57r .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-smls9hdAKNSVu57r .marker{fill:#333333;stroke:#333333;}#mermaid-svg-smls9hdAKNSVu57r .marker.cross{stroke:#333333;}#mermaid-svg-smls9hdAKNSVu57r svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-smls9hdAKNSVu57r p{margin:0;}#mermaid-svg-smls9hdAKNSVu57r .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-smls9hdAKNSVu57r .cluster-label text{fill:#333;}#mermaid-svg-smls9hdAKNSVu57r .cluster-label span{color:#333;}#mermaid-svg-smls9hdAKNSVu57r .cluster-label span p{background-color:transparent;}#mermaid-svg-smls9hdAKNSVu57r .label text,#mermaid-svg-smls9hdAKNSVu57r span{fill:#333;color:#333;}#mermaid-svg-smls9hdAKNSVu57r .node rect,#mermaid-svg-smls9hdAKNSVu57r .node circle,#mermaid-svg-smls9hdAKNSVu57r .node ellipse,#mermaid-svg-smls9hdAKNSVu57r .node polygon,#mermaid-svg-smls9hdAKNSVu57r .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-smls9hdAKNSVu57r .rough-node .label text,#mermaid-svg-smls9hdAKNSVu57r .node .label text,#mermaid-svg-smls9hdAKNSVu57r .image-shape .label,#mermaid-svg-smls9hdAKNSVu57r .icon-shape .label{text-anchor:middle;}#mermaid-svg-smls9hdAKNSVu57r .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-smls9hdAKNSVu57r .rough-node .label,#mermaid-svg-smls9hdAKNSVu57r .node .label,#mermaid-svg-smls9hdAKNSVu57r .image-shape .label,#mermaid-svg-smls9hdAKNSVu57r .icon-shape .label{text-align:center;}#mermaid-svg-smls9hdAKNSVu57r .node.clickable{cursor:pointer;}#mermaid-svg-smls9hdAKNSVu57r .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-smls9hdAKNSVu57r .arrowheadPath{fill:#333333;}#mermaid-svg-smls9hdAKNSVu57r .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-smls9hdAKNSVu57r .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-smls9hdAKNSVu57r .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-smls9hdAKNSVu57r .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-smls9hdAKNSVu57r .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-smls9hdAKNSVu57r .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-smls9hdAKNSVu57r .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-smls9hdAKNSVu57r .cluster text{fill:#333;}#mermaid-svg-smls9hdAKNSVu57r .cluster span{color:#333;}#mermaid-svg-smls9hdAKNSVu57r div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-smls9hdAKNSVu57r .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-smls9hdAKNSVu57r rect.text{fill:none;stroke-width:0;}#mermaid-svg-smls9hdAKNSVu57r .icon-shape,#mermaid-svg-smls9hdAKNSVu57r .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-smls9hdAKNSVu57r .icon-shape p,#mermaid-svg-smls9hdAKNSVu57r .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-smls9hdAKNSVu57r .icon-shape .label rect,#mermaid-svg-smls9hdAKNSVu57r .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-smls9hdAKNSVu57r .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-smls9hdAKNSVu57r .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-smls9hdAKNSVu57r :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 连续输入
Message / Text / JSON / Fact Triple
Episode
原始事件
LLM 信息抽取
Entity
实体节点
Fact / Relationship
关系事实
去重 + 消歧 + 时间判断
Temporal Context Graph
时间上下文图
Hybrid Search
混合检索
Agent / RAG / Memory
1.1 Graphiti 与普通 RAG 的区别
典型 RAG:
text
文档
↓
切块
↓
Embedding
↓
向量数据库
↓
Query Embedding
↓
Top-K 相似文本
Graphiti:
text
事件
↓
Episode
↓
实体 / 关系 / 时间抽取
↓
实体消歧
↓
事实去重
↓
矛盾事实时间失效
↓
图数据库 + 向量 + 全文索引
↓
BM25 / Vector / BFS
↓
RRF / MMR / Cross-Encoder / 图距离
↓
结构化、可追溯的上下文
普通 RAG 主要回答
"有哪些文本跟这个 Query 相似?"
Graphiti 更希望回答
"与这个问题相关的实体、事实、事件有哪些?
这些事实什么时候成立?
哪些已经失效?
它们来自哪一次 Episode?
与某个中心实体在图上有什么关系?"
1.2 Graphiti 与静态知识图谱的区别
传统知识图谱通常倾向于得到:
text
Alice --WORKS_AT--> Company A
如果 Alice 后来去了 Company B,最简单的系统可能更新成:
text
Alice --WORKS_AT--> Company B
Graphiti 更强调保留事实生命周期:
text
Alice --WORKS_AT--> Company A
valid_at = 2024-01
invalid_at = 2026-03
Alice --WORKS_AT--> Company B
valid_at = 2026-03
invalid_at = null
也就是说:
"事实变化"不是删除历史,而是改变事实有效区间。
这正是 Graphiti 很适合 Agent 长期记忆的原因。
第2章 总体架构:六层理解 Graphiti
阅读 Graphiti 源码时,建议始终脑中保持下面六层。
#mermaid-svg-w58E8E1hV65pzqZS{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-w58E8E1hV65pzqZS .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-w58E8E1hV65pzqZS .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-w58E8E1hV65pzqZS .error-icon{fill:#552222;}#mermaid-svg-w58E8E1hV65pzqZS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-w58E8E1hV65pzqZS .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-w58E8E1hV65pzqZS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-w58E8E1hV65pzqZS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-w58E8E1hV65pzqZS .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-w58E8E1hV65pzqZS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-w58E8E1hV65pzqZS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-w58E8E1hV65pzqZS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-w58E8E1hV65pzqZS .marker.cross{stroke:#333333;}#mermaid-svg-w58E8E1hV65pzqZS svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-w58E8E1hV65pzqZS p{margin:0;}#mermaid-svg-w58E8E1hV65pzqZS .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-w58E8E1hV65pzqZS .cluster-label text{fill:#333;}#mermaid-svg-w58E8E1hV65pzqZS .cluster-label span{color:#333;}#mermaid-svg-w58E8E1hV65pzqZS .cluster-label span p{background-color:transparent;}#mermaid-svg-w58E8E1hV65pzqZS .label text,#mermaid-svg-w58E8E1hV65pzqZS span{fill:#333;color:#333;}#mermaid-svg-w58E8E1hV65pzqZS .node rect,#mermaid-svg-w58E8E1hV65pzqZS .node circle,#mermaid-svg-w58E8E1hV65pzqZS .node ellipse,#mermaid-svg-w58E8E1hV65pzqZS .node polygon,#mermaid-svg-w58E8E1hV65pzqZS .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-w58E8E1hV65pzqZS .rough-node .label text,#mermaid-svg-w58E8E1hV65pzqZS .node .label text,#mermaid-svg-w58E8E1hV65pzqZS .image-shape .label,#mermaid-svg-w58E8E1hV65pzqZS .icon-shape .label{text-anchor:middle;}#mermaid-svg-w58E8E1hV65pzqZS .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-w58E8E1hV65pzqZS .rough-node .label,#mermaid-svg-w58E8E1hV65pzqZS .node .label,#mermaid-svg-w58E8E1hV65pzqZS .image-shape .label,#mermaid-svg-w58E8E1hV65pzqZS .icon-shape .label{text-align:center;}#mermaid-svg-w58E8E1hV65pzqZS .node.clickable{cursor:pointer;}#mermaid-svg-w58E8E1hV65pzqZS .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-w58E8E1hV65pzqZS .arrowheadPath{fill:#333333;}#mermaid-svg-w58E8E1hV65pzqZS .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-w58E8E1hV65pzqZS .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-w58E8E1hV65pzqZS .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-w58E8E1hV65pzqZS .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-w58E8E1hV65pzqZS .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-w58E8E1hV65pzqZS .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-w58E8E1hV65pzqZS .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-w58E8E1hV65pzqZS .cluster text{fill:#333;}#mermaid-svg-w58E8E1hV65pzqZS .cluster span{color:#333;}#mermaid-svg-w58E8E1hV65pzqZS div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-w58E8E1hV65pzqZS .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-w58E8E1hV65pzqZS rect.text{fill:none;stroke-width:0;}#mermaid-svg-w58E8E1hV65pzqZS .icon-shape,#mermaid-svg-w58E8E1hV65pzqZS .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-w58E8E1hV65pzqZS .icon-shape p,#mermaid-svg-w58E8E1hV65pzqZS .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-w58E8E1hV65pzqZS .icon-shape .label rect,#mermaid-svg-w58E8E1hV65pzqZS .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-w58E8E1hV65pzqZS .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-w58E8E1hV65pzqZS .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-w58E8E1hV65pzqZS :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ⑥ 数据访问层
⑤ 检索层
④ AI 能力层
③ 记忆构建层
② 编排层
① 接入层
FastAPI Server
MCP Server
Python SDK / Graphiti
Graphiti
NodeNamespace
EdgeNamespace
Node Extraction
Node Resolution / Dedupe
Edge Extraction
Edge Resolution / Dedupe
Temporal Invalidation
Community
Saga
LLMClient
PromptLibrary
EmbedderClient
CrossEncoderClient
search() / search_()
BM25
Cosine Similarity
BFS
RRF / MMR / Cross-Encoder
Operations ABC
GraphDriver
Neo4j
FalkorDB
Neptune
Kuzu
2.1 六层分别负责什么
| 层 | 作用 | 典型源码 |
|---|---|---|
| 接入层 | 给应用暴露 HTTP、MCP、Python API | server/, mcp_server/, graphiti_core/graphiti.py |
| 编排层 | 把一次写入/搜索拆成多个阶段并调度 | graphiti.py, namespaces/ |
| 记忆构建层 | 抽实体、抽关系、去重、时间失效、社区、Saga | utils/maintenance/ |
| AI 能力层 | LLM、Embedding、Reranker、Prompt | llm_client/, embedder/, cross_encoder/, prompts/ |
| 检索层 | 混合召回 + 重排 | search/ |
| 数据访问层 | 屏蔽不同图数据库差异 | driver/, models/*_db_queries.py |
第3章 仓库目录总览
当前仓库顶层可按下面理解:
text
graphiti/
├─ graphiti_core/ # 核心 Python SDK,最重要
├─ server/ # FastAPI 图服务
├─ mcp_server/ # MCP Server
├─ examples/ # 示例
├─ tests/ # 核心测试
├─ spec/ # 架构设计文档
├─ signatures/version1/ # CLA 等签署资料
├─ images/ # README / 文档图片
├─ .github/ # CI、Issue、PR、脚本
├─ pyproject.toml # graphiti-core 包配置
├─ Dockerfile
├─ docker-compose.yml
├─ Makefile
└─ ...
3.1 顶层目录职责
| 目录 | 功能 |
|---|---|
graphiti_core/ |
Graphiti 真正的核心源码 |
server/ |
将 Graphiti 封装为 HTTP/FastAPI 服务 |
mcp_server/ |
将 Graphiti 封装成 MCP 工具,供 Agent/LLM Client 调用 |
examples/ |
OpenAI、Azure、LangGraph、GLiNER2、OpenTelemetry 等使用样例 |
tests/ |
单元测试、集成测试、Driver/LLM/Embedder 测试 |
spec/ |
设计演进文档,目前尤其重要的是 Driver Operations redesign |
signatures/version1/ |
贡献者协议相关数据 |
images/ |
项目文档中的 SVG/GIF/截图 |
.github/ |
GitHub Actions、Issue 模板、PR 模板、安全扫描等 |
第4章 核心图数据模型:Episode、Entity、Fact、Community、Saga
Graphiti 的"图"并不是只有 Entity。
核心节点大致有四类,边有五类。
4.1 图模型总图
#mermaid-svg-9rwUrplj1P2PNcrW{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9rwUrplj1P2PNcrW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9rwUrplj1P2PNcrW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9rwUrplj1P2PNcrW .error-icon{fill:#552222;}#mermaid-svg-9rwUrplj1P2PNcrW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9rwUrplj1P2PNcrW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9rwUrplj1P2PNcrW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9rwUrplj1P2PNcrW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9rwUrplj1P2PNcrW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9rwUrplj1P2PNcrW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9rwUrplj1P2PNcrW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9rwUrplj1P2PNcrW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9rwUrplj1P2PNcrW .marker.cross{stroke:#333333;}#mermaid-svg-9rwUrplj1P2PNcrW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9rwUrplj1P2PNcrW p{margin:0;}#mermaid-svg-9rwUrplj1P2PNcrW .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9rwUrplj1P2PNcrW .cluster-label text{fill:#333;}#mermaid-svg-9rwUrplj1P2PNcrW .cluster-label span{color:#333;}#mermaid-svg-9rwUrplj1P2PNcrW .cluster-label span p{background-color:transparent;}#mermaid-svg-9rwUrplj1P2PNcrW .label text,#mermaid-svg-9rwUrplj1P2PNcrW span{fill:#333;color:#333;}#mermaid-svg-9rwUrplj1P2PNcrW .node rect,#mermaid-svg-9rwUrplj1P2PNcrW .node circle,#mermaid-svg-9rwUrplj1P2PNcrW .node ellipse,#mermaid-svg-9rwUrplj1P2PNcrW .node polygon,#mermaid-svg-9rwUrplj1P2PNcrW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9rwUrplj1P2PNcrW .rough-node .label text,#mermaid-svg-9rwUrplj1P2PNcrW .node .label text,#mermaid-svg-9rwUrplj1P2PNcrW .image-shape .label,#mermaid-svg-9rwUrplj1P2PNcrW .icon-shape .label{text-anchor:middle;}#mermaid-svg-9rwUrplj1P2PNcrW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-9rwUrplj1P2PNcrW .rough-node .label,#mermaid-svg-9rwUrplj1P2PNcrW .node .label,#mermaid-svg-9rwUrplj1P2PNcrW .image-shape .label,#mermaid-svg-9rwUrplj1P2PNcrW .icon-shape .label{text-align:center;}#mermaid-svg-9rwUrplj1P2PNcrW .node.clickable{cursor:pointer;}#mermaid-svg-9rwUrplj1P2PNcrW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-9rwUrplj1P2PNcrW .arrowheadPath{fill:#333333;}#mermaid-svg-9rwUrplj1P2PNcrW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9rwUrplj1P2PNcrW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9rwUrplj1P2PNcrW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9rwUrplj1P2PNcrW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-9rwUrplj1P2PNcrW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9rwUrplj1P2PNcrW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-9rwUrplj1P2PNcrW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9rwUrplj1P2PNcrW .cluster text{fill:#333;}#mermaid-svg-9rwUrplj1P2PNcrW .cluster span{color:#333;}#mermaid-svg-9rwUrplj1P2PNcrW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9rwUrplj1P2PNcrW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9rwUrplj1P2PNcrW rect.text{fill:none;stroke-width:0;}#mermaid-svg-9rwUrplj1P2PNcrW .icon-shape,#mermaid-svg-9rwUrplj1P2PNcrW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9rwUrplj1P2PNcrW .icon-shape p,#mermaid-svg-9rwUrplj1P2PNcrW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-9rwUrplj1P2PNcrW .icon-shape .label rect,#mermaid-svg-9rwUrplj1P2PNcrW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9rwUrplj1P2PNcrW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9rwUrplj1P2PNcrW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9rwUrplj1P2PNcrW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} HAS_EPISODE
HAS_EPISODE
NEXT_EPISODE
MENTIONS
MENTIONS
MENTIONS
RELATES_TO
EntityEdge = Fact
HAS_MEMBER
HAS_MEMBER
SagaNode
一段连续事件/会话
EpisodicNode
Episode 1
EpisodicNode
Episode 2
EntityNode
User
EntityNode
Company
CommunityNode
实体社区
4.2 Node 基类
源码:
text
graphiti_core/nodes.py
基础字段可以理解为:
| 字段 | 含义 |
|---|---|
uuid |
全局唯一 ID |
name |
节点名字 |
group_id |
图分区 / 租户 / namespace 语义 |
labels |
图数据库标签 |
created_at |
Graphiti 创建该节点的系统时间 |
Node 是抽象基类,不负责具体业务语义。
4.3 EpisodicNode
它保存"原始发生过的一次输入"。
典型输入:
- 用户说了一句话;
- 一段 JSON;
- 一篇新文档;
- 一个业务事件;
- 一条事实三元组。
重要字段:
| 字段 | 解释 |
|---|---|
source |
Episode 输入类型 |
source_description |
来源说明 |
content |
原始事件内容 |
valid_at |
该事件在现实世界中的参考时间 |
entity_edges |
本 Episode 产生/关联的 EntityEdge UUID |
episode_metadata |
额外元数据 |
EpisodeType
常见值:
messagetextjsonfact_triple
注意:
EpisodicNode.valid_at不是"Graphiti 把它写进数据库的时间",而是源事件自己的参考时间。
这对历史回填非常重要。
4.4 EntityNode
实体就是知识图中的"对象"。
例如:
text
张三
OpenAI
上海
ESP32-P4
小搭
Graphiti
重要字段:
| 字段 | 作用 |
|---|---|
name |
实体名称 |
name_embedding |
名称的向量表示 |
summary |
实体周围事实的区域性摘要 |
attributes |
自定义 ontology 提取出的字段 |
labels |
实体类型 |
其中:
text
generate_name_embedding()
↓
EmbedderClient.create(name)
4.5 EntityEdge
这是 Graphiti 最重要的数据结构之一。
物理图上通常表现为:
text
(Entity)-[:RELATES_TO]->(Entity)
但真正的业务关系名存在 EntityEdge.name 中。
例如:
text
张三 --RELATES_TO--> OpenAI
name = "WORKS_AT"
fact = "张三在 OpenAI 工作"
重要字段:
| 字段 | 含义 |
|---|---|
name |
关系类型/名字 |
fact |
自然语言事实 |
fact_embedding |
fact 的向量 |
episodes |
支撑这个事实的 Episode UUID 列表 |
valid_at |
事实什么时候开始为真 |
invalid_at |
事实什么时候停止为真 |
expired_at |
Graphiti 什么时候发现并标记旧事实失效 |
reference_time |
产生该事实的 Episode 的参考时间 |
attributes |
自定义关系属性 |
为什么同时要 name 和 fact
name 更适合图结构:
text
WORKS_AT
LIVES_IN
OWNS
LIKES
fact 更适合:
- 人类阅读;
- Embedding;
- Cross-Encoder;
- LLM 去重;
- 时间判断。
4.6 EpisodicEdge
物理语义:
text
(Episodic)-[:MENTIONS]->(Entity)
表示:
某次 Episode 提到了某个实体。
它是 Provenance(溯源) 的重要组成部分。
4.7 CommunityNode / CommunityEdge
社区节点代表图中一组语义/结构上相关的实体。
关系:
text
(Community)-[:HAS_MEMBER]->(Entity)
Community 能保存:
- 名称;
- Summary;
- Embedding。
用途:
当单个 Entity/Fact 太细时,Community 提供更高层次的上下文摘要。
4.8 SagaNode
Saga 用来把一系列 Episode 组织成连续链。
#mermaid-svg-6ttSuVySs6PMFJog{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6ttSuVySs6PMFJog .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6ttSuVySs6PMFJog .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6ttSuVySs6PMFJog .error-icon{fill:#552222;}#mermaid-svg-6ttSuVySs6PMFJog .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6ttSuVySs6PMFJog .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6ttSuVySs6PMFJog .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6ttSuVySs6PMFJog .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6ttSuVySs6PMFJog .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6ttSuVySs6PMFJog .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6ttSuVySs6PMFJog .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6ttSuVySs6PMFJog .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6ttSuVySs6PMFJog .marker.cross{stroke:#333333;}#mermaid-svg-6ttSuVySs6PMFJog svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6ttSuVySs6PMFJog p{margin:0;}#mermaid-svg-6ttSuVySs6PMFJog .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6ttSuVySs6PMFJog .cluster-label text{fill:#333;}#mermaid-svg-6ttSuVySs6PMFJog .cluster-label span{color:#333;}#mermaid-svg-6ttSuVySs6PMFJog .cluster-label span p{background-color:transparent;}#mermaid-svg-6ttSuVySs6PMFJog .label text,#mermaid-svg-6ttSuVySs6PMFJog span{fill:#333;color:#333;}#mermaid-svg-6ttSuVySs6PMFJog .node rect,#mermaid-svg-6ttSuVySs6PMFJog .node circle,#mermaid-svg-6ttSuVySs6PMFJog .node ellipse,#mermaid-svg-6ttSuVySs6PMFJog .node polygon,#mermaid-svg-6ttSuVySs6PMFJog .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6ttSuVySs6PMFJog .rough-node .label text,#mermaid-svg-6ttSuVySs6PMFJog .node .label text,#mermaid-svg-6ttSuVySs6PMFJog .image-shape .label,#mermaid-svg-6ttSuVySs6PMFJog .icon-shape .label{text-anchor:middle;}#mermaid-svg-6ttSuVySs6PMFJog .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6ttSuVySs6PMFJog .rough-node .label,#mermaid-svg-6ttSuVySs6PMFJog .node .label,#mermaid-svg-6ttSuVySs6PMFJog .image-shape .label,#mermaid-svg-6ttSuVySs6PMFJog .icon-shape .label{text-align:center;}#mermaid-svg-6ttSuVySs6PMFJog .node.clickable{cursor:pointer;}#mermaid-svg-6ttSuVySs6PMFJog .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6ttSuVySs6PMFJog .arrowheadPath{fill:#333333;}#mermaid-svg-6ttSuVySs6PMFJog .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6ttSuVySs6PMFJog .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6ttSuVySs6PMFJog .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6ttSuVySs6PMFJog .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6ttSuVySs6PMFJog .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6ttSuVySs6PMFJog .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6ttSuVySs6PMFJog .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6ttSuVySs6PMFJog .cluster text{fill:#333;}#mermaid-svg-6ttSuVySs6PMFJog .cluster span{color:#333;}#mermaid-svg-6ttSuVySs6PMFJog div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6ttSuVySs6PMFJog .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6ttSuVySs6PMFJog rect.text{fill:none;stroke-width:0;}#mermaid-svg-6ttSuVySs6PMFJog .icon-shape,#mermaid-svg-6ttSuVySs6PMFJog .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6ttSuVySs6PMFJog .icon-shape p,#mermaid-svg-6ttSuVySs6PMFJog .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6ttSuVySs6PMFJog .icon-shape .label rect,#mermaid-svg-6ttSuVySs6PMFJog .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6ttSuVySs6PMFJog .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6ttSuVySs6PMFJog .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6ttSuVySs6PMFJog :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} HAS_EPISODE
HAS_EPISODE
HAS_EPISODE
NEXT_EPISODE
NEXT_EPISODE
Saga
Episode 1
Episode 2
Episode 3
Saga 保存:
summaryfirst_episode_uuidlast_episode_uuidlast_summarized_atlast_summarized_episode_valid_at
后两个字段非常值得区分:
last_summarized_at:系统真正执行摘要的墙钟时间;last_summarized_episode_valid_at:已经摘要到哪个 Episode 的业务时间。
这是为了正确处理"历史 Episode 回填"。
第5章 时间模型:Graphiti 为什么适合"记忆"
Graphiti 的核心不是简单"加时间戳",而是区分多种时间。
5.1 五个常见时间字段
#mermaid-svg-2NO4NsgkK6tUtpDY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2NO4NsgkK6tUtpDY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2NO4NsgkK6tUtpDY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2NO4NsgkK6tUtpDY .error-icon{fill:#552222;}#mermaid-svg-2NO4NsgkK6tUtpDY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2NO4NsgkK6tUtpDY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2NO4NsgkK6tUtpDY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2NO4NsgkK6tUtpDY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2NO4NsgkK6tUtpDY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2NO4NsgkK6tUtpDY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2NO4NsgkK6tUtpDY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2NO4NsgkK6tUtpDY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2NO4NsgkK6tUtpDY .marker.cross{stroke:#333333;}#mermaid-svg-2NO4NsgkK6tUtpDY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2NO4NsgkK6tUtpDY p{margin:0;}#mermaid-svg-2NO4NsgkK6tUtpDY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2NO4NsgkK6tUtpDY .cluster-label text{fill:#333;}#mermaid-svg-2NO4NsgkK6tUtpDY .cluster-label span{color:#333;}#mermaid-svg-2NO4NsgkK6tUtpDY .cluster-label span p{background-color:transparent;}#mermaid-svg-2NO4NsgkK6tUtpDY .label text,#mermaid-svg-2NO4NsgkK6tUtpDY span{fill:#333;color:#333;}#mermaid-svg-2NO4NsgkK6tUtpDY .node rect,#mermaid-svg-2NO4NsgkK6tUtpDY .node circle,#mermaid-svg-2NO4NsgkK6tUtpDY .node ellipse,#mermaid-svg-2NO4NsgkK6tUtpDY .node polygon,#mermaid-svg-2NO4NsgkK6tUtpDY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2NO4NsgkK6tUtpDY .rough-node .label text,#mermaid-svg-2NO4NsgkK6tUtpDY .node .label text,#mermaid-svg-2NO4NsgkK6tUtpDY .image-shape .label,#mermaid-svg-2NO4NsgkK6tUtpDY .icon-shape .label{text-anchor:middle;}#mermaid-svg-2NO4NsgkK6tUtpDY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2NO4NsgkK6tUtpDY .rough-node .label,#mermaid-svg-2NO4NsgkK6tUtpDY .node .label,#mermaid-svg-2NO4NsgkK6tUtpDY .image-shape .label,#mermaid-svg-2NO4NsgkK6tUtpDY .icon-shape .label{text-align:center;}#mermaid-svg-2NO4NsgkK6tUtpDY .node.clickable{cursor:pointer;}#mermaid-svg-2NO4NsgkK6tUtpDY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2NO4NsgkK6tUtpDY .arrowheadPath{fill:#333333;}#mermaid-svg-2NO4NsgkK6tUtpDY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2NO4NsgkK6tUtpDY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2NO4NsgkK6tUtpDY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2NO4NsgkK6tUtpDY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2NO4NsgkK6tUtpDY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2NO4NsgkK6tUtpDY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2NO4NsgkK6tUtpDY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2NO4NsgkK6tUtpDY .cluster text{fill:#333;}#mermaid-svg-2NO4NsgkK6tUtpDY .cluster span{color:#333;}#mermaid-svg-2NO4NsgkK6tUtpDY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2NO4NsgkK6tUtpDY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2NO4NsgkK6tUtpDY rect.text{fill:none;stroke-width:0;}#mermaid-svg-2NO4NsgkK6tUtpDY .icon-shape,#mermaid-svg-2NO4NsgkK6tUtpDY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2NO4NsgkK6tUtpDY .icon-shape p,#mermaid-svg-2NO4NsgkK6tUtpDY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2NO4NsgkK6tUtpDY .icon-shape .label rect,#mermaid-svg-2NO4NsgkK6tUtpDY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2NO4NsgkK6tUtpDY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2NO4NsgkK6tUtpDY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2NO4NsgkK6tUtpDY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} reference_time
来源 Episode 的参考时间
valid_at
事实开始为真
invalid_at
事实停止为真
created_at
Graphiti 写入时间
expired_at
Graphiti 发现旧事实被替代的时间
| 字段 | 时间轴 | 意义 |
|---|---|---|
created_at |
系统时间 | 记录何时创建 |
reference_time |
事件时间 | 本事实依据哪个时间点的 Episode |
valid_at |
业务有效时间 | 事实开始为真 |
invalid_at |
业务有效时间 | 事实停止为真 |
expired_at |
系统时间 | 系统何时判断旧事实已失效 |
5.2 一个例子
2025-01:
"小王住在北京。"
得到:
text
Fact A:
小王 --LIVES_IN--> 北京
valid_at = 2025-01
invalid_at = null
2026-06:
"小王已经搬到上海。"
得到:
text
Fact B:
小王 --LIVES_IN--> 上海
valid_at = 2026-06
invalid_at = null
同时旧事实可能被更新为:
text
Fact A:
valid_at = 2025-01
invalid_at = 2026-06
expired_at = Graphiti 处理第二个 Episode 的系统时间
5.3 事实失效流程
#mermaid-svg-e6xbVUKnx4lIwjjU{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-e6xbVUKnx4lIwjjU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-e6xbVUKnx4lIwjjU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-e6xbVUKnx4lIwjjU .error-icon{fill:#552222;}#mermaid-svg-e6xbVUKnx4lIwjjU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-e6xbVUKnx4lIwjjU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-e6xbVUKnx4lIwjjU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-e6xbVUKnx4lIwjjU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-e6xbVUKnx4lIwjjU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-e6xbVUKnx4lIwjjU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-e6xbVUKnx4lIwjjU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-e6xbVUKnx4lIwjjU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-e6xbVUKnx4lIwjjU .marker.cross{stroke:#333333;}#mermaid-svg-e6xbVUKnx4lIwjjU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-e6xbVUKnx4lIwjjU p{margin:0;}#mermaid-svg-e6xbVUKnx4lIwjjU .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-e6xbVUKnx4lIwjjU .cluster-label text{fill:#333;}#mermaid-svg-e6xbVUKnx4lIwjjU .cluster-label span{color:#333;}#mermaid-svg-e6xbVUKnx4lIwjjU .cluster-label span p{background-color:transparent;}#mermaid-svg-e6xbVUKnx4lIwjjU .label text,#mermaid-svg-e6xbVUKnx4lIwjjU span{fill:#333;color:#333;}#mermaid-svg-e6xbVUKnx4lIwjjU .node rect,#mermaid-svg-e6xbVUKnx4lIwjjU .node circle,#mermaid-svg-e6xbVUKnx4lIwjjU .node ellipse,#mermaid-svg-e6xbVUKnx4lIwjjU .node polygon,#mermaid-svg-e6xbVUKnx4lIwjjU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-e6xbVUKnx4lIwjjU .rough-node .label text,#mermaid-svg-e6xbVUKnx4lIwjjU .node .label text,#mermaid-svg-e6xbVUKnx4lIwjjU .image-shape .label,#mermaid-svg-e6xbVUKnx4lIwjjU .icon-shape .label{text-anchor:middle;}#mermaid-svg-e6xbVUKnx4lIwjjU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-e6xbVUKnx4lIwjjU .rough-node .label,#mermaid-svg-e6xbVUKnx4lIwjjU .node .label,#mermaid-svg-e6xbVUKnx4lIwjjU .image-shape .label,#mermaid-svg-e6xbVUKnx4lIwjjU .icon-shape .label{text-align:center;}#mermaid-svg-e6xbVUKnx4lIwjjU .node.clickable{cursor:pointer;}#mermaid-svg-e6xbVUKnx4lIwjjU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-e6xbVUKnx4lIwjjU .arrowheadPath{fill:#333333;}#mermaid-svg-e6xbVUKnx4lIwjjU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-e6xbVUKnx4lIwjjU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-e6xbVUKnx4lIwjjU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-e6xbVUKnx4lIwjjU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-e6xbVUKnx4lIwjjU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-e6xbVUKnx4lIwjjU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-e6xbVUKnx4lIwjjU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-e6xbVUKnx4lIwjjU .cluster text{fill:#333;}#mermaid-svg-e6xbVUKnx4lIwjjU .cluster span{color:#333;}#mermaid-svg-e6xbVUKnx4lIwjjU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-e6xbVUKnx4lIwjjU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-e6xbVUKnx4lIwjjU rect.text{fill:none;stroke-width:0;}#mermaid-svg-e6xbVUKnx4lIwjjU .icon-shape,#mermaid-svg-e6xbVUKnx4lIwjjU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-e6xbVUKnx4lIwjjU .icon-shape p,#mermaid-svg-e6xbVUKnx4lIwjjU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-e6xbVUKnx4lIwjjU .icon-shape .label rect,#mermaid-svg-e6xbVUKnx4lIwjjU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-e6xbVUKnx4lIwjjU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-e6xbVUKnx4lIwjjU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-e6xbVUKnx4lIwjjU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
否
是
是
否
新 Fact
找到相同实体对附近的 Existing Edges
语义是否重复?
合并到已有 Fact
是否与旧 Fact 矛盾?
时间区间是否重叠?
旧 Fact invalid_at = 新 Fact valid_at
旧 Fact expired_at = 当前系统时间
新 Fact 作为新 Edge 保存
并存
不错误地互相失效
这体现了一个很重要的原则:
"语义矛盾"并不必然意味着旧事实必须失效;还要看它们在时间上是否应该同时成立。
第6章 Graphiti 类:整个系统的总编排器
核心文件:
text
graphiti_core/graphiti.py
这是源码阅读最应该先看的文件。
6.1 构造函数依赖
Graphiti(...) 大致接收:
- DB URI / user / password;
llm_client;embedder;cross_encoder;graph_driver;store_raw_episode_content;- 并发限制;
- tracer。
默认情况下,会为未传入的组件创建默认实现。
6.2 GraphitiClients
Graphiti 将四个主要依赖打包:
text
GraphitiClients
├─ driver
├─ llm_client
├─ embedder
├─ cross_encoder
└─ tracer
可以把它理解成轻量的 Dependency Container。
6.3 Graphiti 的职责不是做算法,而是"编排"
#mermaid-svg-2L33i3tHk08WxxHe{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2L33i3tHk08WxxHe .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2L33i3tHk08WxxHe .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2L33i3tHk08WxxHe .error-icon{fill:#552222;}#mermaid-svg-2L33i3tHk08WxxHe .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2L33i3tHk08WxxHe .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2L33i3tHk08WxxHe .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2L33i3tHk08WxxHe .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2L33i3tHk08WxxHe .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2L33i3tHk08WxxHe .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2L33i3tHk08WxxHe .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2L33i3tHk08WxxHe .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2L33i3tHk08WxxHe .marker.cross{stroke:#333333;}#mermaid-svg-2L33i3tHk08WxxHe svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2L33i3tHk08WxxHe p{margin:0;}#mermaid-svg-2L33i3tHk08WxxHe .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2L33i3tHk08WxxHe .cluster-label text{fill:#333;}#mermaid-svg-2L33i3tHk08WxxHe .cluster-label span{color:#333;}#mermaid-svg-2L33i3tHk08WxxHe .cluster-label span p{background-color:transparent;}#mermaid-svg-2L33i3tHk08WxxHe .label text,#mermaid-svg-2L33i3tHk08WxxHe span{fill:#333;color:#333;}#mermaid-svg-2L33i3tHk08WxxHe .node rect,#mermaid-svg-2L33i3tHk08WxxHe .node circle,#mermaid-svg-2L33i3tHk08WxxHe .node ellipse,#mermaid-svg-2L33i3tHk08WxxHe .node polygon,#mermaid-svg-2L33i3tHk08WxxHe .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2L33i3tHk08WxxHe .rough-node .label text,#mermaid-svg-2L33i3tHk08WxxHe .node .label text,#mermaid-svg-2L33i3tHk08WxxHe .image-shape .label,#mermaid-svg-2L33i3tHk08WxxHe .icon-shape .label{text-anchor:middle;}#mermaid-svg-2L33i3tHk08WxxHe .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2L33i3tHk08WxxHe .rough-node .label,#mermaid-svg-2L33i3tHk08WxxHe .node .label,#mermaid-svg-2L33i3tHk08WxxHe .image-shape .label,#mermaid-svg-2L33i3tHk08WxxHe .icon-shape .label{text-align:center;}#mermaid-svg-2L33i3tHk08WxxHe .node.clickable{cursor:pointer;}#mermaid-svg-2L33i3tHk08WxxHe .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2L33i3tHk08WxxHe .arrowheadPath{fill:#333333;}#mermaid-svg-2L33i3tHk08WxxHe .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2L33i3tHk08WxxHe .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2L33i3tHk08WxxHe .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2L33i3tHk08WxxHe .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2L33i3tHk08WxxHe .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2L33i3tHk08WxxHe .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2L33i3tHk08WxxHe .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2L33i3tHk08WxxHe .cluster text{fill:#333;}#mermaid-svg-2L33i3tHk08WxxHe .cluster span{color:#333;}#mermaid-svg-2L33i3tHk08WxxHe div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2L33i3tHk08WxxHe .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2L33i3tHk08WxxHe rect.text{fill:none;stroke-width:0;}#mermaid-svg-2L33i3tHk08WxxHe .icon-shape,#mermaid-svg-2L33i3tHk08WxxHe .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2L33i3tHk08WxxHe .icon-shape p,#mermaid-svg-2L33i3tHk08WxxHe .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2L33i3tHk08WxxHe .icon-shape .label rect,#mermaid-svg-2L33i3tHk08WxxHe .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2L33i3tHk08WxxHe .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2L33i3tHk08WxxHe .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2L33i3tHk08WxxHe :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Graphiti
Ingestion
Retrieval
Maintenance
Namespaces
add_episode
add_episode_bulk
add_triplet
search
search_
get_nodes_and_edges_by_episode
build_communities
remove_episode
nodes
edges
它本身更多是:
- 建立上下文;
- 调用抽取;
- 调用去重;
- 调用时间解析;
- 调用持久化;
- 调用搜索;
- 管理 tracing。
第7章 add_episode():一次记忆写入的完整源码流程
这是整个项目最重要的一条调用链。
7.1 总体时序图
Community GraphDriver _process_episode_data extract_attributes_from_nodes resolve_extracted_edges extract_edges resolve_extracted_nodes extract_nodes retrieve_episodes Graphiti.add_episode 应用 Community GraphDriver _process_episode_data extract_attributes_from_nodes resolve_extracted_edges extract_edges resolve_extracted_nodes extract_nodes retrieve_episodes Graphiti.add_episode 应用 #mermaid-svg-sbLSDU9gNNrfmQCF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sbLSDU9gNNrfmQCF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sbLSDU9gNNrfmQCF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sbLSDU9gNNrfmQCF .error-icon{fill:#552222;}#mermaid-svg-sbLSDU9gNNrfmQCF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sbLSDU9gNNrfmQCF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sbLSDU9gNNrfmQCF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sbLSDU9gNNrfmQCF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sbLSDU9gNNrfmQCF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sbLSDU9gNNrfmQCF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sbLSDU9gNNrfmQCF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sbLSDU9gNNrfmQCF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sbLSDU9gNNrfmQCF .marker.cross{stroke:#333333;}#mermaid-svg-sbLSDU9gNNrfmQCF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sbLSDU9gNNrfmQCF p{margin:0;}#mermaid-svg-sbLSDU9gNNrfmQCF .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-sbLSDU9gNNrfmQCF text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-sbLSDU9gNNrfmQCF .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-sbLSDU9gNNrfmQCF .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-sbLSDU9gNNrfmQCF .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-sbLSDU9gNNrfmQCF .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-sbLSDU9gNNrfmQCF #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-sbLSDU9gNNrfmQCF .sequenceNumber{fill:white;}#mermaid-svg-sbLSDU9gNNrfmQCF #sequencenumber{fill:#333;}#mermaid-svg-sbLSDU9gNNrfmQCF #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-sbLSDU9gNNrfmQCF .messageText{fill:#333;stroke:none;}#mermaid-svg-sbLSDU9gNNrfmQCF .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-sbLSDU9gNNrfmQCF .labelText,#mermaid-svg-sbLSDU9gNNrfmQCF .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-sbLSDU9gNNrfmQCF .loopText,#mermaid-svg-sbLSDU9gNNrfmQCF .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-sbLSDU9gNNrfmQCF .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-sbLSDU9gNNrfmQCF .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-sbLSDU9gNNrfmQCF .noteText,#mermaid-svg-sbLSDU9gNNrfmQCF .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-sbLSDU9gNNrfmQCF .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-sbLSDU9gNNrfmQCF .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-sbLSDU9gNNrfmQCF .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-sbLSDU9gNNrfmQCF .actorPopupMenu{position:absolute;}#mermaid-svg-sbLSDU9gNNrfmQCF .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-sbLSDU9gNNrfmQCF .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-sbLSDU9gNNrfmQCF .actor-man circle,#mermaid-svg-sbLSDU9gNNrfmQCF line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-sbLSDU9gNNrfmQCF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} opt saga enabled opt update_communities name, episode_body, reference_time... validate entity_types / exclusions / group_id 获取前序 Episodes 作为上下文 query recent episodes episodes previous_episodes 构造 EpisodicNode 从 Episode 抽实体 extracted_nodes 实体消歧/去重 resolved_nodes + uuid_map 从 Episode 抽关系 extracted_edges resolve + dedupe + temporal invalidation resolved_edges + invalidated_edges + new_edges 更新实体属性/summary enriched_nodes Episode + Nodes + Edges bulk persist HAS_EPISODE / NEXT_EPISODE / Saga 更新 Community save community nodes/edges AddEpisodeResults
7.2 add_episode() 分 10 步看
Step 1:校验输入
包括:
entity_typesexcluded_entity_typesedge_typesedge_type_mapgroup_id
entity_types 决定 LLM 可抽取哪些自定义实体 schema。
edge_type_map 决定:
什么类型实体之间允许出现什么关系类型。
Step 2:处理 group_id
group_id 是非常重要的隔离维度。
可以理解为:
text
group_id = tenant / user / workspace / graph partition
对于 FalkorDB 等 Provider,它甚至可能映射为不同 Graph。
Step 3:查询 previous episodes
调用方向:
text
add_episode()
└─ retrieve_episodes()
└─ GraphOperations / Driver query
目的是给当前 Episode 抽取提供近期上下文。
为什么?
例如:
text
Episode 1: 小王现在在 OpenAI 工作。
Episode 2: 他下个月要搬去旧金山。
仅看 Episode 2,LLM 不知道"他"是谁。
加入历史 Episode 后才能把"他"解析为"小王"。
Step 4:构造 EpisodicNode
核心信息:
text
name
group_id
source
source_description
content
valid_at = reference_time
created_at = now
Graphiti 在这一刻先保留"原始事件"。
Step 5:抽取实体 extract_nodes()
text
Episode
↓
Prompt context
↓
LLM
↓
Extracted EntityNode[]
此时的节点还是"候选实体",并不意味着一定要新建。
Step 6:实体解析 resolve_extracted_nodes()
text
"Open AI"
"OpenAI"
"OpenAI Inc."
可能都是同一实体。
因此 Graphiti 会做:
- 名字向量;
- 相似候选搜索;
- 确定性/相似度判断;
- 必要时 LLM dedupe;
- 产生
uuid_map。
uuid_map 非常关键:
text
临时候选 UUID
↓
最终 canonical entity UUID
后面关系必须把 source / target pointer 改到 canonical UUID。
Step 7:边抽取 + 解析
调用:
text
_extract_and_resolve_edges()
├─ extract_edges()
├─ resolve_edge_pointers()
└─ resolve_extracted_edges()
输出三组:
text
resolved_edges
invalidated_edges
new_edges
这里是 Graphiti 时间记忆机制的核心。
Step 8:实体属性/摘要更新
调用大意:
text
extract_attributes_from_nodes(
nodes,
edges=new_edges,
...
)
注意它重点使用 new_edges,而不是把已经存在的重复事实反复灌入摘要。
Step 9:统一持久化
进入:
text
_process_episode_data()
内部完成:
- 生成
MENTIONS; - Episode 记录对应 fact edge UUID;
- 批量保存 Episode;
- 批量保存 Entity;
- 批量保存 EntityEdge;
- 保存 EpisodicEdge;
- 可选处理 Saga。
Step 10:可选更新 Community
如果配置更新社区,则:
text
Entity/Edge changes
↓
community maintenance
↓
CommunityNode / CommunityEdge
7.3 add_episode() 主调用树
#mermaid-svg-zZWJSMunKUakFvZI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zZWJSMunKUakFvZI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zZWJSMunKUakFvZI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zZWJSMunKUakFvZI .error-icon{fill:#552222;}#mermaid-svg-zZWJSMunKUakFvZI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zZWJSMunKUakFvZI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zZWJSMunKUakFvZI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zZWJSMunKUakFvZI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zZWJSMunKUakFvZI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zZWJSMunKUakFvZI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zZWJSMunKUakFvZI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zZWJSMunKUakFvZI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zZWJSMunKUakFvZI .marker.cross{stroke:#333333;}#mermaid-svg-zZWJSMunKUakFvZI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zZWJSMunKUakFvZI p{margin:0;}#mermaid-svg-zZWJSMunKUakFvZI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zZWJSMunKUakFvZI .cluster-label text{fill:#333;}#mermaid-svg-zZWJSMunKUakFvZI .cluster-label span{color:#333;}#mermaid-svg-zZWJSMunKUakFvZI .cluster-label span p{background-color:transparent;}#mermaid-svg-zZWJSMunKUakFvZI .label text,#mermaid-svg-zZWJSMunKUakFvZI span{fill:#333;color:#333;}#mermaid-svg-zZWJSMunKUakFvZI .node rect,#mermaid-svg-zZWJSMunKUakFvZI .node circle,#mermaid-svg-zZWJSMunKUakFvZI .node ellipse,#mermaid-svg-zZWJSMunKUakFvZI .node polygon,#mermaid-svg-zZWJSMunKUakFvZI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zZWJSMunKUakFvZI .rough-node .label text,#mermaid-svg-zZWJSMunKUakFvZI .node .label text,#mermaid-svg-zZWJSMunKUakFvZI .image-shape .label,#mermaid-svg-zZWJSMunKUakFvZI .icon-shape .label{text-anchor:middle;}#mermaid-svg-zZWJSMunKUakFvZI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zZWJSMunKUakFvZI .rough-node .label,#mermaid-svg-zZWJSMunKUakFvZI .node .label,#mermaid-svg-zZWJSMunKUakFvZI .image-shape .label,#mermaid-svg-zZWJSMunKUakFvZI .icon-shape .label{text-align:center;}#mermaid-svg-zZWJSMunKUakFvZI .node.clickable{cursor:pointer;}#mermaid-svg-zZWJSMunKUakFvZI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zZWJSMunKUakFvZI .arrowheadPath{fill:#333333;}#mermaid-svg-zZWJSMunKUakFvZI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zZWJSMunKUakFvZI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zZWJSMunKUakFvZI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zZWJSMunKUakFvZI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zZWJSMunKUakFvZI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zZWJSMunKUakFvZI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zZWJSMunKUakFvZI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zZWJSMunKUakFvZI .cluster text{fill:#333;}#mermaid-svg-zZWJSMunKUakFvZI .cluster span{color:#333;}#mermaid-svg-zZWJSMunKUakFvZI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zZWJSMunKUakFvZI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zZWJSMunKUakFvZI rect.text{fill:none;stroke-width:0;}#mermaid-svg-zZWJSMunKUakFvZI .icon-shape,#mermaid-svg-zZWJSMunKUakFvZI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zZWJSMunKUakFvZI .icon-shape p,#mermaid-svg-zZWJSMunKUakFvZI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zZWJSMunKUakFvZI .icon-shape .label rect,#mermaid-svg-zZWJSMunKUakFvZI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zZWJSMunKUakFvZI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zZWJSMunKUakFvZI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zZWJSMunKUakFvZI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Graphiti.add_episode
validate_entity_types
retrieve_episodes
EpisodicNode(...)
extract_nodes
resolve_extracted_nodes
_extract_and_resolve_edges
extract_edges
resolve_edge_pointers
resolve_extracted_edges
extract_attributes_from_nodes
_process_episode_data
build_episodic_edges
add_nodes_and_edges_bulk
Saga processing
Community update
第8章 节点抽取与实体去重
核心文件:
text
graphiti_core/utils/maintenance/node_operations.py
8.1 extract_nodes()
它不是只把当前一句话塞给 LLM。
构造的上下文大致包含:
- 当前 Episode 内容;
- Episode 类型;
- Episode reference time;
- 前序 Episodes;
- Entity Type schema;
- 自定义抽取 instructions;
- 多 Episode 时的 episode index 归属约束。
8.2 根据 Episode 类型选择 Prompt
概念上:
#mermaid-svg-0j8GdU9eJFXPr9ZB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0j8GdU9eJFXPr9ZB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0j8GdU9eJFXPr9ZB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0j8GdU9eJFXPr9ZB .error-icon{fill:#552222;}#mermaid-svg-0j8GdU9eJFXPr9ZB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0j8GdU9eJFXPr9ZB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0j8GdU9eJFXPr9ZB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0j8GdU9eJFXPr9ZB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0j8GdU9eJFXPr9ZB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0j8GdU9eJFXPr9ZB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0j8GdU9eJFXPr9ZB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0j8GdU9eJFXPr9ZB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0j8GdU9eJFXPr9ZB .marker.cross{stroke:#333333;}#mermaid-svg-0j8GdU9eJFXPr9ZB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0j8GdU9eJFXPr9ZB p{margin:0;}#mermaid-svg-0j8GdU9eJFXPr9ZB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0j8GdU9eJFXPr9ZB .cluster-label text{fill:#333;}#mermaid-svg-0j8GdU9eJFXPr9ZB .cluster-label span{color:#333;}#mermaid-svg-0j8GdU9eJFXPr9ZB .cluster-label span p{background-color:transparent;}#mermaid-svg-0j8GdU9eJFXPr9ZB .label text,#mermaid-svg-0j8GdU9eJFXPr9ZB span{fill:#333;color:#333;}#mermaid-svg-0j8GdU9eJFXPr9ZB .node rect,#mermaid-svg-0j8GdU9eJFXPr9ZB .node circle,#mermaid-svg-0j8GdU9eJFXPr9ZB .node ellipse,#mermaid-svg-0j8GdU9eJFXPr9ZB .node polygon,#mermaid-svg-0j8GdU9eJFXPr9ZB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0j8GdU9eJFXPr9ZB .rough-node .label text,#mermaid-svg-0j8GdU9eJFXPr9ZB .node .label text,#mermaid-svg-0j8GdU9eJFXPr9ZB .image-shape .label,#mermaid-svg-0j8GdU9eJFXPr9ZB .icon-shape .label{text-anchor:middle;}#mermaid-svg-0j8GdU9eJFXPr9ZB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0j8GdU9eJFXPr9ZB .rough-node .label,#mermaid-svg-0j8GdU9eJFXPr9ZB .node .label,#mermaid-svg-0j8GdU9eJFXPr9ZB .image-shape .label,#mermaid-svg-0j8GdU9eJFXPr9ZB .icon-shape .label{text-align:center;}#mermaid-svg-0j8GdU9eJFXPr9ZB .node.clickable{cursor:pointer;}#mermaid-svg-0j8GdU9eJFXPr9ZB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0j8GdU9eJFXPr9ZB .arrowheadPath{fill:#333333;}#mermaid-svg-0j8GdU9eJFXPr9ZB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0j8GdU9eJFXPr9ZB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0j8GdU9eJFXPr9ZB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0j8GdU9eJFXPr9ZB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0j8GdU9eJFXPr9ZB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0j8GdU9eJFXPr9ZB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0j8GdU9eJFXPr9ZB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0j8GdU9eJFXPr9ZB .cluster text{fill:#333;}#mermaid-svg-0j8GdU9eJFXPr9ZB .cluster span{color:#333;}#mermaid-svg-0j8GdU9eJFXPr9ZB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-0j8GdU9eJFXPr9ZB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0j8GdU9eJFXPr9ZB rect.text{fill:none;stroke-width:0;}#mermaid-svg-0j8GdU9eJFXPr9ZB .icon-shape,#mermaid-svg-0j8GdU9eJFXPr9ZB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0j8GdU9eJFXPr9ZB .icon-shape p,#mermaid-svg-0j8GdU9eJFXPr9ZB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0j8GdU9eJFXPr9ZB .icon-shape .label rect,#mermaid-svg-0j8GdU9eJFXPr9ZB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0j8GdU9eJFXPr9ZB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0j8GdU9eJFXPr9ZB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0j8GdU9eJFXPr9ZB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} message
text
json
fact_triple
Episode
source type
message prompt
text prompt
json prompt
fact_triple prompt
Prompt 定义集中在:
text
graphiti_core/prompts/extract_nodes.py
8.3 为什么不直接把所有抽出的 Entity 保存
因为这会产生大量重复节点:
text
OpenAI
Open AI
openai
OpenAI Inc
OpenAI 公司
所以必须做 Entity Resolution。
8.4 resolve_extracted_nodes() 的多阶段去重
#mermaid-svg-p2Ve1s1ZZAJirftc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-p2Ve1s1ZZAJirftc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-p2Ve1s1ZZAJirftc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-p2Ve1s1ZZAJirftc .error-icon{fill:#552222;}#mermaid-svg-p2Ve1s1ZZAJirftc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-p2Ve1s1ZZAJirftc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-p2Ve1s1ZZAJirftc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-p2Ve1s1ZZAJirftc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-p2Ve1s1ZZAJirftc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-p2Ve1s1ZZAJirftc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-p2Ve1s1ZZAJirftc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-p2Ve1s1ZZAJirftc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-p2Ve1s1ZZAJirftc .marker.cross{stroke:#333333;}#mermaid-svg-p2Ve1s1ZZAJirftc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-p2Ve1s1ZZAJirftc p{margin:0;}#mermaid-svg-p2Ve1s1ZZAJirftc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-p2Ve1s1ZZAJirftc .cluster-label text{fill:#333;}#mermaid-svg-p2Ve1s1ZZAJirftc .cluster-label span{color:#333;}#mermaid-svg-p2Ve1s1ZZAJirftc .cluster-label span p{background-color:transparent;}#mermaid-svg-p2Ve1s1ZZAJirftc .label text,#mermaid-svg-p2Ve1s1ZZAJirftc span{fill:#333;color:#333;}#mermaid-svg-p2Ve1s1ZZAJirftc .node rect,#mermaid-svg-p2Ve1s1ZZAJirftc .node circle,#mermaid-svg-p2Ve1s1ZZAJirftc .node ellipse,#mermaid-svg-p2Ve1s1ZZAJirftc .node polygon,#mermaid-svg-p2Ve1s1ZZAJirftc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-p2Ve1s1ZZAJirftc .rough-node .label text,#mermaid-svg-p2Ve1s1ZZAJirftc .node .label text,#mermaid-svg-p2Ve1s1ZZAJirftc .image-shape .label,#mermaid-svg-p2Ve1s1ZZAJirftc .icon-shape .label{text-anchor:middle;}#mermaid-svg-p2Ve1s1ZZAJirftc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-p2Ve1s1ZZAJirftc .rough-node .label,#mermaid-svg-p2Ve1s1ZZAJirftc .node .label,#mermaid-svg-p2Ve1s1ZZAJirftc .image-shape .label,#mermaid-svg-p2Ve1s1ZZAJirftc .icon-shape .label{text-align:center;}#mermaid-svg-p2Ve1s1ZZAJirftc .node.clickable{cursor:pointer;}#mermaid-svg-p2Ve1s1ZZAJirftc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-p2Ve1s1ZZAJirftc .arrowheadPath{fill:#333333;}#mermaid-svg-p2Ve1s1ZZAJirftc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-p2Ve1s1ZZAJirftc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-p2Ve1s1ZZAJirftc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-p2Ve1s1ZZAJirftc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-p2Ve1s1ZZAJirftc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-p2Ve1s1ZZAJirftc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-p2Ve1s1ZZAJirftc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-p2Ve1s1ZZAJirftc .cluster text{fill:#333;}#mermaid-svg-p2Ve1s1ZZAJirftc .cluster span{color:#333;}#mermaid-svg-p2Ve1s1ZZAJirftc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-p2Ve1s1ZZAJirftc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-p2Ve1s1ZZAJirftc rect.text{fill:none;stroke-width:0;}#mermaid-svg-p2Ve1s1ZZAJirftc .icon-shape,#mermaid-svg-p2Ve1s1ZZAJirftc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-p2Ve1s1ZZAJirftc .icon-shape p,#mermaid-svg-p2Ve1s1ZZAJirftc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-p2Ve1s1ZZAJirftc .icon-shape .label rect,#mermaid-svg-p2Ve1s1ZZAJirftc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-p2Ve1s1ZZAJirftc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-p2Ve1s1ZZAJirftc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-p2Ve1s1ZZAJirftc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
Extracted Nodes
名称归一 / 候选索引
批量生成 name embedding
node_similarity_search
召回已有节点候选
确定性匹配 / 相似度规则
仍无法确定?
LLM dedupe
Canonical EntityNode
uuid_map
duplicate pairs
关键优化思想
不是:
text
每个实体都问一次大模型:
"它是不是已有实体?"
而是:
text
便宜的确定性判断
↓
Embedding 候选缩小
↓
只把难判断的送给 LLM
这对成本和性能很关键。
8.5 _semantic_candidate_search()
主要步骤:
text
nodes
↓
Embedder.create_batch(names)
↓
每个 node 做 node_similarity_search
↓
返回少量候选
源码中候选规模和 cosine threshold 都用于控制:
- 召回质量;
- LLM 后续输入长度;
- 延迟;
- 成本。
8.6 uuid_map 为什么是整个写入链的"粘合剂"
抽取时 Edge 可能引用新节点临时 UUID:
text
edge.source = temp-A
edge.target = temp-B
实体去重后:
text
temp-A -> existing-OpenAI-UUID
temp-B -> existing-Sam-UUID
因此必须:
text
resolve_edge_pointers()
把边指向最终实体。
第9章 关系抽取、事实去重与时间失效
核心文件:
text
graphiti_core/utils/maintenance/edge_operations.py
9.1 extract_edges()
输入:
- Episode(s)
- 抽出的节点
- Episode reference time
- edge type schema
- edge type map
- prompt context
输出:
text
EntityEdge[]
每条候选 Edge 至少包含:
text
source_node_uuid
target_node_uuid
name
fact
episodes
reference_time
valid_at / invalid_at(如果抽取到)
9.2 edge_type_map
假设:
python
Person
Company
City
允许关系:
text
(Person, Company) -> WORKS_AT
(Person, City) -> LIVES_IN
Graphiti 会把这些约束形成 Prompt context。
意义:
不让 LLM 任意创造不符合业务 ontology 的关系。
9.3 resolve_extracted_edges()
这是最值得读的函数之一。
总体过程:
#mermaid-svg-MPCKdTGSWPJMBxwG{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MPCKdTGSWPJMBxwG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MPCKdTGSWPJMBxwG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MPCKdTGSWPJMBxwG .error-icon{fill:#552222;}#mermaid-svg-MPCKdTGSWPJMBxwG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MPCKdTGSWPJMBxwG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MPCKdTGSWPJMBxwG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MPCKdTGSWPJMBxwG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MPCKdTGSWPJMBxwG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MPCKdTGSWPJMBxwG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MPCKdTGSWPJMBxwG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MPCKdTGSWPJMBxwG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MPCKdTGSWPJMBxwG .marker.cross{stroke:#333333;}#mermaid-svg-MPCKdTGSWPJMBxwG svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MPCKdTGSWPJMBxwG p{margin:0;}#mermaid-svg-MPCKdTGSWPJMBxwG .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MPCKdTGSWPJMBxwG .cluster-label text{fill:#333;}#mermaid-svg-MPCKdTGSWPJMBxwG .cluster-label span{color:#333;}#mermaid-svg-MPCKdTGSWPJMBxwG .cluster-label span p{background-color:transparent;}#mermaid-svg-MPCKdTGSWPJMBxwG .label text,#mermaid-svg-MPCKdTGSWPJMBxwG span{fill:#333;color:#333;}#mermaid-svg-MPCKdTGSWPJMBxwG .node rect,#mermaid-svg-MPCKdTGSWPJMBxwG .node circle,#mermaid-svg-MPCKdTGSWPJMBxwG .node ellipse,#mermaid-svg-MPCKdTGSWPJMBxwG .node polygon,#mermaid-svg-MPCKdTGSWPJMBxwG .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MPCKdTGSWPJMBxwG .rough-node .label text,#mermaid-svg-MPCKdTGSWPJMBxwG .node .label text,#mermaid-svg-MPCKdTGSWPJMBxwG .image-shape .label,#mermaid-svg-MPCKdTGSWPJMBxwG .icon-shape .label{text-anchor:middle;}#mermaid-svg-MPCKdTGSWPJMBxwG .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MPCKdTGSWPJMBxwG .rough-node .label,#mermaid-svg-MPCKdTGSWPJMBxwG .node .label,#mermaid-svg-MPCKdTGSWPJMBxwG .image-shape .label,#mermaid-svg-MPCKdTGSWPJMBxwG .icon-shape .label{text-align:center;}#mermaid-svg-MPCKdTGSWPJMBxwG .node.clickable{cursor:pointer;}#mermaid-svg-MPCKdTGSWPJMBxwG .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MPCKdTGSWPJMBxwG .arrowheadPath{fill:#333333;}#mermaid-svg-MPCKdTGSWPJMBxwG .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MPCKdTGSWPJMBxwG .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MPCKdTGSWPJMBxwG .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MPCKdTGSWPJMBxwG .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MPCKdTGSWPJMBxwG .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MPCKdTGSWPJMBxwG .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MPCKdTGSWPJMBxwG .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MPCKdTGSWPJMBxwG .cluster text{fill:#333;}#mermaid-svg-MPCKdTGSWPJMBxwG .cluster span{color:#333;}#mermaid-svg-MPCKdTGSWPJMBxwG div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MPCKdTGSWPJMBxwG .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MPCKdTGSWPJMBxwG rect.text{fill:none;stroke-width:0;}#mermaid-svg-MPCKdTGSWPJMBxwG .icon-shape,#mermaid-svg-MPCKdTGSWPJMBxwG .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MPCKdTGSWPJMBxwG .icon-shape p,#mermaid-svg-MPCKdTGSWPJMBxwG .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MPCKdTGSWPJMBxwG .icon-shape .label rect,#mermaid-svg-MPCKdTGSWPJMBxwG .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MPCKdTGSWPJMBxwG .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MPCKdTGSWPJMBxwG .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MPCKdTGSWPJMBxwG :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
否
是
Extracted Edges
Exact duplicate fast path
生成 fact embeddings
查询相同 source/target 的 Existing Edges
搜索 broader related edges
resolve_extracted_edge
重复事实?
复用 Existing Edge
追加 provenance
矛盾事实?
时间区间检查
invalidate old edge
保存 new edge
输出 resolved / invalidated / new
9.4 三组输出分别是什么
resolved_edges
当前 Episode 最终应该关联到的 canonical facts。
可能包含:
- 新 Edge;
- 被认定为同一事实的 Existing Edge。
invalidated_edges
因为当前新事实而被修改有效期的旧 Edge。
new_edges
真正新创建的事实 Edge。
这个区分很重要,因为:
- resolved 用于"当前 Episode 最终关联哪些事实";
- invalidated 用于保存旧事实生命周期变化;
- new 用于后续属性/摘要增量更新。
9.5 时间抽取 _extract_edge_timestamps()
如果关系抽取阶段没有得到足够准确的时间,则 Graphiti 会针对 Fact 再做时间解析。
输入大意:
text
fact
episode reference time
输出:
text
valid_at
invalid_at
关键思想:
时间解析使用 Episode 的
reference_time做相对时间锚点,而不是总用当前服务器时间。
例如:
text
Episode reference_time = 2025-03-01
内容 = "他上个月加入公司"
"上个月"应该相对于 2025-03-01,而不是系统今天。
9.6 为什么查询"同端点已有 Edge"
假设:
text
Sam -> OpenAI
当前新 Fact:
text
Sam works at OpenAI
已有:
text
Sam joined OpenAI
Sam is employed by OpenAI
Sam works at OpenAI
仅做全库语义搜索成本更高,而且 source/target 是非常强的结构约束。
所以 Graphiti 会优先利用:
text
相同 Entity pair
再结合语义去重。
第10章 Episode、MENTIONS 与事实溯源
Graphiti 与很多"只保存最终知识"的系统不同:
它保留 Episode 作为第一等对象。
10.1 双向溯源思想
#mermaid-svg-U0eRRBEPyBpIEEjj{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-U0eRRBEPyBpIEEjj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-U0eRRBEPyBpIEEjj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-U0eRRBEPyBpIEEjj .error-icon{fill:#552222;}#mermaid-svg-U0eRRBEPyBpIEEjj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-U0eRRBEPyBpIEEjj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-U0eRRBEPyBpIEEjj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-U0eRRBEPyBpIEEjj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-U0eRRBEPyBpIEEjj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-U0eRRBEPyBpIEEjj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-U0eRRBEPyBpIEEjj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-U0eRRBEPyBpIEEjj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-U0eRRBEPyBpIEEjj .marker.cross{stroke:#333333;}#mermaid-svg-U0eRRBEPyBpIEEjj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-U0eRRBEPyBpIEEjj p{margin:0;}#mermaid-svg-U0eRRBEPyBpIEEjj .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-U0eRRBEPyBpIEEjj .cluster-label text{fill:#333;}#mermaid-svg-U0eRRBEPyBpIEEjj .cluster-label span{color:#333;}#mermaid-svg-U0eRRBEPyBpIEEjj .cluster-label span p{background-color:transparent;}#mermaid-svg-U0eRRBEPyBpIEEjj .label text,#mermaid-svg-U0eRRBEPyBpIEEjj span{fill:#333;color:#333;}#mermaid-svg-U0eRRBEPyBpIEEjj .node rect,#mermaid-svg-U0eRRBEPyBpIEEjj .node circle,#mermaid-svg-U0eRRBEPyBpIEEjj .node ellipse,#mermaid-svg-U0eRRBEPyBpIEEjj .node polygon,#mermaid-svg-U0eRRBEPyBpIEEjj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-U0eRRBEPyBpIEEjj .rough-node .label text,#mermaid-svg-U0eRRBEPyBpIEEjj .node .label text,#mermaid-svg-U0eRRBEPyBpIEEjj .image-shape .label,#mermaid-svg-U0eRRBEPyBpIEEjj .icon-shape .label{text-anchor:middle;}#mermaid-svg-U0eRRBEPyBpIEEjj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-U0eRRBEPyBpIEEjj .rough-node .label,#mermaid-svg-U0eRRBEPyBpIEEjj .node .label,#mermaid-svg-U0eRRBEPyBpIEEjj .image-shape .label,#mermaid-svg-U0eRRBEPyBpIEEjj .icon-shape .label{text-align:center;}#mermaid-svg-U0eRRBEPyBpIEEjj .node.clickable{cursor:pointer;}#mermaid-svg-U0eRRBEPyBpIEEjj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-U0eRRBEPyBpIEEjj .arrowheadPath{fill:#333333;}#mermaid-svg-U0eRRBEPyBpIEEjj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-U0eRRBEPyBpIEEjj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-U0eRRBEPyBpIEEjj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-U0eRRBEPyBpIEEjj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-U0eRRBEPyBpIEEjj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-U0eRRBEPyBpIEEjj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-U0eRRBEPyBpIEEjj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-U0eRRBEPyBpIEEjj .cluster text{fill:#333;}#mermaid-svg-U0eRRBEPyBpIEEjj .cluster span{color:#333;}#mermaid-svg-U0eRRBEPyBpIEEjj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-U0eRRBEPyBpIEEjj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-U0eRRBEPyBpIEEjj rect.text{fill:none;stroke-width:0;}#mermaid-svg-U0eRRBEPyBpIEEjj .icon-shape,#mermaid-svg-U0eRRBEPyBpIEEjj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-U0eRRBEPyBpIEEjj .icon-shape p,#mermaid-svg-U0eRRBEPyBpIEEjj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-U0eRRBEPyBpIEEjj .icon-shape .label rect,#mermaid-svg-U0eRRBEPyBpIEEjj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-U0eRRBEPyBpIEEjj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-U0eRRBEPyBpIEEjj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-U0eRRBEPyBpIEEjj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} MENTIONS
MENTIONS
RELATES_TO
entity_edges contains Fact UUID
episodes contains Episode UUID
Episode
Entity A
Entity B
EntityEdge / Fact
这使系统能够回答:
- 这个实体在哪些原始事件被提过?
- 这个 Fact 是由哪些 Episode 支撑的?
- 某个 Episode 抽出了哪些 Facts?
- 如果删除 Episode,哪些 Facts 可能失去来源?
10.2 build_episodic_edges()
职责:
text
Episode UUID + resolved entity UUIDs
↓
EpisodicEdge(MENTIONS)
批量抽取时还需要 node_episode_index_map:
一个批次里抽出的实体到底来自哪一个 Episode?
第11章 Saga:连续会话/事件链如何组织
Saga 可以理解为:
一个带顺序的 Episode Container。
例如:
text
"用户与小搭 8 月 19 日的一段会话"
可以作为一个 Saga。
11.1 _process_episode_data() 中的 Saga 处理
概念链:
#mermaid-svg-6I6ymEU99cidoum1{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6I6ymEU99cidoum1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6I6ymEU99cidoum1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6I6ymEU99cidoum1 .error-icon{fill:#552222;}#mermaid-svg-6I6ymEU99cidoum1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6I6ymEU99cidoum1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6I6ymEU99cidoum1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6I6ymEU99cidoum1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6I6ymEU99cidoum1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6I6ymEU99cidoum1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6I6ymEU99cidoum1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6I6ymEU99cidoum1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6I6ymEU99cidoum1 .marker.cross{stroke:#333333;}#mermaid-svg-6I6ymEU99cidoum1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6I6ymEU99cidoum1 p{margin:0;}#mermaid-svg-6I6ymEU99cidoum1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6I6ymEU99cidoum1 .cluster-label text{fill:#333;}#mermaid-svg-6I6ymEU99cidoum1 .cluster-label span{color:#333;}#mermaid-svg-6I6ymEU99cidoum1 .cluster-label span p{background-color:transparent;}#mermaid-svg-6I6ymEU99cidoum1 .label text,#mermaid-svg-6I6ymEU99cidoum1 span{fill:#333;color:#333;}#mermaid-svg-6I6ymEU99cidoum1 .node rect,#mermaid-svg-6I6ymEU99cidoum1 .node circle,#mermaid-svg-6I6ymEU99cidoum1 .node ellipse,#mermaid-svg-6I6ymEU99cidoum1 .node polygon,#mermaid-svg-6I6ymEU99cidoum1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6I6ymEU99cidoum1 .rough-node .label text,#mermaid-svg-6I6ymEU99cidoum1 .node .label text,#mermaid-svg-6I6ymEU99cidoum1 .image-shape .label,#mermaid-svg-6I6ymEU99cidoum1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-6I6ymEU99cidoum1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6I6ymEU99cidoum1 .rough-node .label,#mermaid-svg-6I6ymEU99cidoum1 .node .label,#mermaid-svg-6I6ymEU99cidoum1 .image-shape .label,#mermaid-svg-6I6ymEU99cidoum1 .icon-shape .label{text-align:center;}#mermaid-svg-6I6ymEU99cidoum1 .node.clickable{cursor:pointer;}#mermaid-svg-6I6ymEU99cidoum1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6I6ymEU99cidoum1 .arrowheadPath{fill:#333333;}#mermaid-svg-6I6ymEU99cidoum1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6I6ymEU99cidoum1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6I6ymEU99cidoum1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6I6ymEU99cidoum1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6I6ymEU99cidoum1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6I6ymEU99cidoum1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6I6ymEU99cidoum1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6I6ymEU99cidoum1 .cluster text{fill:#333;}#mermaid-svg-6I6ymEU99cidoum1 .cluster span{color:#333;}#mermaid-svg-6I6ymEU99cidoum1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6I6ymEU99cidoum1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6I6ymEU99cidoum1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-6I6ymEU99cidoum1 .icon-shape,#mermaid-svg-6I6ymEU99cidoum1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6I6ymEU99cidoum1 .icon-shape p,#mermaid-svg-6I6ymEU99cidoum1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6I6ymEU99cidoum1 .icon-shape .label rect,#mermaid-svg-6I6ymEU99cidoum1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6I6ymEU99cidoum1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6I6ymEU99cidoum1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6I6ymEU99cidoum1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 当前 Episode
get/create SagaNode
找到 previous episode
创建 NEXT_EPISODE
创建 HAS_EPISODE
更新 first_episode_uuid
更新 last_episode_uuid
save Saga
11.2 为什么 Saga 与 group_id 不是一回事
group_id:
更像数据隔离范围。
Saga:
是这个隔离范围内部的一条具体事件序列。
例:
text
group_id = user_001
Saga A = 与工作项目相关的一次长会话
Saga B = 旅行规划会话
Saga C = 某个持续 7 天的任务事件链
第12章 批量写入 add_episode_bulk()
单条 add_episode() 强调正确的时序上下文。
批量路径则更强调:
- 减少 LLM 调用;
- 批量 Embedding;
- 并发;
- 批量 DB IO。
12.1 Bulk 主流程
#mermaid-svg-5PccAJWxtTATljYL{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5PccAJWxtTATljYL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5PccAJWxtTATljYL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5PccAJWxtTATljYL .error-icon{fill:#552222;}#mermaid-svg-5PccAJWxtTATljYL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5PccAJWxtTATljYL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5PccAJWxtTATljYL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5PccAJWxtTATljYL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5PccAJWxtTATljYL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5PccAJWxtTATljYL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5PccAJWxtTATljYL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5PccAJWxtTATljYL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5PccAJWxtTATljYL .marker.cross{stroke:#333333;}#mermaid-svg-5PccAJWxtTATljYL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5PccAJWxtTATljYL p{margin:0;}#mermaid-svg-5PccAJWxtTATljYL .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5PccAJWxtTATljYL .cluster-label text{fill:#333;}#mermaid-svg-5PccAJWxtTATljYL .cluster-label span{color:#333;}#mermaid-svg-5PccAJWxtTATljYL .cluster-label span p{background-color:transparent;}#mermaid-svg-5PccAJWxtTATljYL .label text,#mermaid-svg-5PccAJWxtTATljYL span{fill:#333;color:#333;}#mermaid-svg-5PccAJWxtTATljYL .node rect,#mermaid-svg-5PccAJWxtTATljYL .node circle,#mermaid-svg-5PccAJWxtTATljYL .node ellipse,#mermaid-svg-5PccAJWxtTATljYL .node polygon,#mermaid-svg-5PccAJWxtTATljYL .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5PccAJWxtTATljYL .rough-node .label text,#mermaid-svg-5PccAJWxtTATljYL .node .label text,#mermaid-svg-5PccAJWxtTATljYL .image-shape .label,#mermaid-svg-5PccAJWxtTATljYL .icon-shape .label{text-anchor:middle;}#mermaid-svg-5PccAJWxtTATljYL .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5PccAJWxtTATljYL .rough-node .label,#mermaid-svg-5PccAJWxtTATljYL .node .label,#mermaid-svg-5PccAJWxtTATljYL .image-shape .label,#mermaid-svg-5PccAJWxtTATljYL .icon-shape .label{text-align:center;}#mermaid-svg-5PccAJWxtTATljYL .node.clickable{cursor:pointer;}#mermaid-svg-5PccAJWxtTATljYL .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5PccAJWxtTATljYL .arrowheadPath{fill:#333333;}#mermaid-svg-5PccAJWxtTATljYL .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5PccAJWxtTATljYL .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5PccAJWxtTATljYL .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5PccAJWxtTATljYL .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5PccAJWxtTATljYL .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5PccAJWxtTATljYL .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5PccAJWxtTATljYL .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5PccAJWxtTATljYL .cluster text{fill:#333;}#mermaid-svg-5PccAJWxtTATljYL .cluster span{color:#333;}#mermaid-svg-5PccAJWxtTATljYL div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5PccAJWxtTATljYL .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5PccAJWxtTATljYL rect.text{fill:none;stroke-width:0;}#mermaid-svg-5PccAJWxtTATljYL .icon-shape,#mermaid-svg-5PccAJWxtTATljYL .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5PccAJWxtTATljYL .icon-shape p,#mermaid-svg-5PccAJWxtTATljYL .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5PccAJWxtTATljYL .icon-shape .label rect,#mermaid-svg-5PccAJWxtTATljYL .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5PccAJWxtTATljYL .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5PccAJWxtTATljYL .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5PccAJWxtTATljYL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} add_episode_bulk
构造 EpisodicNodes
预保存 / 准备 Episodes
retrieve_previous_episodes_bulk
_extract_and_dedupe_nodes_bulk
Combined Extraction
build_episodic_edges
resolve_edge_pointers
dedupe_edges_bulk
_resolve_nodes_and_edges_bulk
修正 EpisodicEdge 指针
add_nodes_and_edges_bulk
Bulk Results
12.2 Combined Extraction
在维护目录中有:
text
combined_extraction.py
其重要价值是:
在适合的路径中,把 node + edge extraction 合并到一次结构化 LLM 调用中。
这样比:
text
LLM 抽节点
+
LLM 抽边
更省请求开销。
12.3 为什么官方更强调 Episode 顺序
如果事件之间高度依赖前文:
text
E1: 我现在住北京
E2: 下周我要搬家
E3: 新地址在上海
严格按 reference time 顺序逐条加入更容易正确建立上下文和事实生命周期。
Bulk 更适合:
- 大规模历史灌入;
- 可并行处理的数据;
- 已有比较明确时间和结构的数据。
第13章 搜索系统总览:不是单纯向量检索
核心:
text
graphiti_core/search/
Graphiti 高级搜索同时面对四类对象:
EntityEdgeEntityNodeEpisodicNodeCommunityNode
13.1 search() 与 search_()
Graphiti.search()
更方便的高层 API:
- 主要返回 EntityEdge;
- 默认走 Edge Hybrid Search;
- 如果给中心节点,可以使用 node-distance recipe。
Graphiti.search_()
更完整的 API:
text
SearchResults
├─ edges
├─ nodes
├─ episodes
├─ communities
├─ edge_reranker_scores
├─ node_reranker_scores
├─ episode_reranker_scores
└─ community_reranker_scores
默认偏向综合 Hybrid + Cross-Encoder 配方。
13.2 搜索流水线
#mermaid-svg-lNQVcUlJxDclM3yB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-lNQVcUlJxDclM3yB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-lNQVcUlJxDclM3yB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-lNQVcUlJxDclM3yB .error-icon{fill:#552222;}#mermaid-svg-lNQVcUlJxDclM3yB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-lNQVcUlJxDclM3yB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-lNQVcUlJxDclM3yB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-lNQVcUlJxDclM3yB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-lNQVcUlJxDclM3yB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-lNQVcUlJxDclM3yB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-lNQVcUlJxDclM3yB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-lNQVcUlJxDclM3yB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-lNQVcUlJxDclM3yB .marker.cross{stroke:#333333;}#mermaid-svg-lNQVcUlJxDclM3yB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-lNQVcUlJxDclM3yB p{margin:0;}#mermaid-svg-lNQVcUlJxDclM3yB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-lNQVcUlJxDclM3yB .cluster-label text{fill:#333;}#mermaid-svg-lNQVcUlJxDclM3yB .cluster-label span{color:#333;}#mermaid-svg-lNQVcUlJxDclM3yB .cluster-label span p{background-color:transparent;}#mermaid-svg-lNQVcUlJxDclM3yB .label text,#mermaid-svg-lNQVcUlJxDclM3yB span{fill:#333;color:#333;}#mermaid-svg-lNQVcUlJxDclM3yB .node rect,#mermaid-svg-lNQVcUlJxDclM3yB .node circle,#mermaid-svg-lNQVcUlJxDclM3yB .node ellipse,#mermaid-svg-lNQVcUlJxDclM3yB .node polygon,#mermaid-svg-lNQVcUlJxDclM3yB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-lNQVcUlJxDclM3yB .rough-node .label text,#mermaid-svg-lNQVcUlJxDclM3yB .node .label text,#mermaid-svg-lNQVcUlJxDclM3yB .image-shape .label,#mermaid-svg-lNQVcUlJxDclM3yB .icon-shape .label{text-anchor:middle;}#mermaid-svg-lNQVcUlJxDclM3yB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-lNQVcUlJxDclM3yB .rough-node .label,#mermaid-svg-lNQVcUlJxDclM3yB .node .label,#mermaid-svg-lNQVcUlJxDclM3yB .image-shape .label,#mermaid-svg-lNQVcUlJxDclM3yB .icon-shape .label{text-align:center;}#mermaid-svg-lNQVcUlJxDclM3yB .node.clickable{cursor:pointer;}#mermaid-svg-lNQVcUlJxDclM3yB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-lNQVcUlJxDclM3yB .arrowheadPath{fill:#333333;}#mermaid-svg-lNQVcUlJxDclM3yB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-lNQVcUlJxDclM3yB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-lNQVcUlJxDclM3yB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lNQVcUlJxDclM3yB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-lNQVcUlJxDclM3yB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lNQVcUlJxDclM3yB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-lNQVcUlJxDclM3yB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-lNQVcUlJxDclM3yB .cluster text{fill:#333;}#mermaid-svg-lNQVcUlJxDclM3yB .cluster span{color:#333;}#mermaid-svg-lNQVcUlJxDclM3yB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-lNQVcUlJxDclM3yB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-lNQVcUlJxDclM3yB rect.text{fill:none;stroke-width:0;}#mermaid-svg-lNQVcUlJxDclM3yB .icon-shape,#mermaid-svg-lNQVcUlJxDclM3yB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lNQVcUlJxDclM3yB .icon-shape p,#mermaid-svg-lNQVcUlJxDclM3yB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-lNQVcUlJxDclM3yB .icon-shape .label rect,#mermaid-svg-lNQVcUlJxDclM3yB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lNQVcUlJxDclM3yB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-lNQVcUlJxDclM3yB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-lNQVcUlJxDclM3yB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 可选重排
融合 / 去重
候选召回
Query
BM25
字面匹配
Cosine Similarity
语义匹配
BFS
图结构扩展
UUID 去重
RRF
MMR
Cross-Encoder
Node Distance
Episode Mentions
Top-K Results
注意:
不同 SearchConfig 不一定同时使用图中的所有模块。
13.3 四种对象的搜索能力
| 对象 | 召回方式 |
|---|---|
| Edge | BM25 / Cosine / BFS |
| Node | BM25 / Cosine / BFS |
| Episode | BM25 |
| Community | BM25 / Cosine |
随后各自选择不同 reranker。
第14章 BM25、Cosine、BFS、RRF、MMR、Cross-Encoder
14.1 BM25
全称通常写作:
Best Matching 25
它属于经典全文检索 ranking 算法。
擅长:
- 专有名词;
- 产品型号;
- 人名;
- 精确关键词;
- 词频相关性。
例如 Query:
text
ESP32-P4
BM25 往往比纯语义 Embedding 更稳。
14.2 Cosine Similarity
比较两个向量方向的相似程度。
在 Graphiti 中通常:
text
Query
↓
Embedding
↓
与 Node/Edge/Community embedding 比较
擅长找:
字面不一样但语义相近的内容。
14.3 BFS
BFS:
Breadth-First Search,广度优先搜索
它不是文本检索,而是图遍历。
例如:
text
User
├─ works_at -> Company
├─ owns -> Device
└─ lives_in -> City
如果一个相关 Node 已经被召回,BFS 可以进一步扩展它附近的结构上下文。
14.4 RRF
RRF:
Reciprocal Rank Fusion,倒数排名融合
它解决:
text
BM25 有一个排名
Vector 有一个排名
BFS 又有一个排名
不同检索器的原始 score 完全不是一个尺度,直接加分不合理。
RRF 主要依据:
候选在不同结果列表中排第几。
概念公式:
text
score(d) = Σ 1 / (k + rank_i(d))
所以它非常适合融合 heterogeneous retrievers。
14.5 MMR
MMR:
Maximal Marginal Relevance,最大边际相关性
它同时追求:
- 跟 Query 相关;
- 结果之间不要太重复。
如果 Top-10 全都在说同一个事实,只是文字换了说法,对 Agent 没有价值。
MMR 会增加结果多样性。
14.6 Cross-Encoder
普通 Embedding:
text
Query -> embedding
Doc -> embedding
↓
cosine
Cross-Encoder:
text
[Query, Candidate]
↓
同一个模型联合编码
↓
relevance score
优点:
- 精排通常更准。
缺点:
- 每个 Query-Candidate pair 都要重新推理;
- 贵;
- 慢。
因此 Graphiti 的合理方式是:
text
便宜召回一批候选
↓
RRF 粗融合
↓
缩小候选集
↓
Cross-Encoder 精排
14.7 Node Distance
有中心实体时:
text
center_node_uuid = User
Graphiti 可以根据图结构距离重排:
text
User -> direct edge
通常比:
text
User -> A -> B -> C -> edge
更强相关。
14.8 Episode Mentions
一个 Fact / Entity 被很多 Episode 反复提及,可能意味着它具有更强的"记忆显著性"。
因此 mention 次数可以作为 reranking 信号。
第15章 SearchConfig 与搜索配方
核心:
text
graphiti_core/search/search_config.py
graphiti_core/search/search_config_recipes.py
15.1 方法枚举
Edge Search
text
cosine_similarity
bm25
bfs
Node Search
text
cosine_similarity
bm25
bfs
Episode Search
text
bm25
Community Search
text
cosine_similarity
bm25
15.2 Reranker 类型
Edge/Node 常见:
rrfnode_distanceepisode_mentionsmmrcross_encoder
Episode:
rrfcross_encoder
Community:
rrfmmrcross_encoder
15.3 默认综合 Cross-Encoder 配方
概念上:
#mermaid-svg-CVXggxwwM9tFgSbA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CVXggxwwM9tFgSbA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CVXggxwwM9tFgSbA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CVXggxwwM9tFgSbA .error-icon{fill:#552222;}#mermaid-svg-CVXggxwwM9tFgSbA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CVXggxwwM9tFgSbA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CVXggxwwM9tFgSbA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CVXggxwwM9tFgSbA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CVXggxwwM9tFgSbA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CVXggxwwM9tFgSbA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CVXggxwwM9tFgSbA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CVXggxwwM9tFgSbA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CVXggxwwM9tFgSbA .marker.cross{stroke:#333333;}#mermaid-svg-CVXggxwwM9tFgSbA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CVXggxwwM9tFgSbA p{margin:0;}#mermaid-svg-CVXggxwwM9tFgSbA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-CVXggxwwM9tFgSbA .cluster-label text{fill:#333;}#mermaid-svg-CVXggxwwM9tFgSbA .cluster-label span{color:#333;}#mermaid-svg-CVXggxwwM9tFgSbA .cluster-label span p{background-color:transparent;}#mermaid-svg-CVXggxwwM9tFgSbA .label text,#mermaid-svg-CVXggxwwM9tFgSbA span{fill:#333;color:#333;}#mermaid-svg-CVXggxwwM9tFgSbA .node rect,#mermaid-svg-CVXggxwwM9tFgSbA .node circle,#mermaid-svg-CVXggxwwM9tFgSbA .node ellipse,#mermaid-svg-CVXggxwwM9tFgSbA .node polygon,#mermaid-svg-CVXggxwwM9tFgSbA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CVXggxwwM9tFgSbA .rough-node .label text,#mermaid-svg-CVXggxwwM9tFgSbA .node .label text,#mermaid-svg-CVXggxwwM9tFgSbA .image-shape .label,#mermaid-svg-CVXggxwwM9tFgSbA .icon-shape .label{text-anchor:middle;}#mermaid-svg-CVXggxwwM9tFgSbA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CVXggxwwM9tFgSbA .rough-node .label,#mermaid-svg-CVXggxwwM9tFgSbA .node .label,#mermaid-svg-CVXggxwwM9tFgSbA .image-shape .label,#mermaid-svg-CVXggxwwM9tFgSbA .icon-shape .label{text-align:center;}#mermaid-svg-CVXggxwwM9tFgSbA .node.clickable{cursor:pointer;}#mermaid-svg-CVXggxwwM9tFgSbA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CVXggxwwM9tFgSbA .arrowheadPath{fill:#333333;}#mermaid-svg-CVXggxwwM9tFgSbA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CVXggxwwM9tFgSbA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CVXggxwwM9tFgSbA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CVXggxwwM9tFgSbA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CVXggxwwM9tFgSbA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CVXggxwwM9tFgSbA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CVXggxwwM9tFgSbA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CVXggxwwM9tFgSbA .cluster text{fill:#333;}#mermaid-svg-CVXggxwwM9tFgSbA .cluster span{color:#333;}#mermaid-svg-CVXggxwwM9tFgSbA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CVXggxwwM9tFgSbA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CVXggxwwM9tFgSbA rect.text{fill:none;stroke-width:0;}#mermaid-svg-CVXggxwwM9tFgSbA .icon-shape,#mermaid-svg-CVXggxwwM9tFgSbA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CVXggxwwM9tFgSbA .icon-shape p,#mermaid-svg-CVXggxwwM9tFgSbA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CVXggxwwM9tFgSbA .icon-shape .label rect,#mermaid-svg-CVXggxwwM9tFgSbA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CVXggxwwM9tFgSbA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CVXggxwwM9tFgSbA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CVXggxwwM9tFgSbA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Query
Edges
BM25 + Cosine + BFS
Nodes
BM25 + Cosine + BFS
Episodes
BM25
Communities
BM25 + Cosine
Cross-Encoder rerank
Cross-Encoder rerank
Cross-Encoder rerank
Cross-Encoder rerank
15.4 search/search.py 的顶层并发
顶层 search(...) 会:
- 检查是否需要 Query Embedding;
- 只有配置包含 Vector/MMR 时才生成 Embedding;
- 并发运行:
edge_searchnode_searchepisode_searchcommunity_search
- 最后拼成
SearchResults。
这体现一个很好的性能设计:
不需要向量的搜索,不额外调用 Embedding API。
15.5 edge_search() 详细流程
#mermaid-svg-JwjJZWQlpKgIKvo7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JwjJZWQlpKgIKvo7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JwjJZWQlpKgIKvo7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JwjJZWQlpKgIKvo7 .error-icon{fill:#552222;}#mermaid-svg-JwjJZWQlpKgIKvo7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JwjJZWQlpKgIKvo7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JwjJZWQlpKgIKvo7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JwjJZWQlpKgIKvo7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JwjJZWQlpKgIKvo7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JwjJZWQlpKgIKvo7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JwjJZWQlpKgIKvo7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JwjJZWQlpKgIKvo7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JwjJZWQlpKgIKvo7 .marker.cross{stroke:#333333;}#mermaid-svg-JwjJZWQlpKgIKvo7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JwjJZWQlpKgIKvo7 p{margin:0;}#mermaid-svg-JwjJZWQlpKgIKvo7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JwjJZWQlpKgIKvo7 .cluster-label text{fill:#333;}#mermaid-svg-JwjJZWQlpKgIKvo7 .cluster-label span{color:#333;}#mermaid-svg-JwjJZWQlpKgIKvo7 .cluster-label span p{background-color:transparent;}#mermaid-svg-JwjJZWQlpKgIKvo7 .label text,#mermaid-svg-JwjJZWQlpKgIKvo7 span{fill:#333;color:#333;}#mermaid-svg-JwjJZWQlpKgIKvo7 .node rect,#mermaid-svg-JwjJZWQlpKgIKvo7 .node circle,#mermaid-svg-JwjJZWQlpKgIKvo7 .node ellipse,#mermaid-svg-JwjJZWQlpKgIKvo7 .node polygon,#mermaid-svg-JwjJZWQlpKgIKvo7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JwjJZWQlpKgIKvo7 .rough-node .label text,#mermaid-svg-JwjJZWQlpKgIKvo7 .node .label text,#mermaid-svg-JwjJZWQlpKgIKvo7 .image-shape .label,#mermaid-svg-JwjJZWQlpKgIKvo7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-JwjJZWQlpKgIKvo7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JwjJZWQlpKgIKvo7 .rough-node .label,#mermaid-svg-JwjJZWQlpKgIKvo7 .node .label,#mermaid-svg-JwjJZWQlpKgIKvo7 .image-shape .label,#mermaid-svg-JwjJZWQlpKgIKvo7 .icon-shape .label{text-align:center;}#mermaid-svg-JwjJZWQlpKgIKvo7 .node.clickable{cursor:pointer;}#mermaid-svg-JwjJZWQlpKgIKvo7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JwjJZWQlpKgIKvo7 .arrowheadPath{fill:#333333;}#mermaid-svg-JwjJZWQlpKgIKvo7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JwjJZWQlpKgIKvo7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JwjJZWQlpKgIKvo7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JwjJZWQlpKgIKvo7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JwjJZWQlpKgIKvo7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JwjJZWQlpKgIKvo7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JwjJZWQlpKgIKvo7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JwjJZWQlpKgIKvo7 .cluster text{fill:#333;}#mermaid-svg-JwjJZWQlpKgIKvo7 .cluster span{color:#333;}#mermaid-svg-JwjJZWQlpKgIKvo7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JwjJZWQlpKgIKvo7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JwjJZWQlpKgIKvo7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-JwjJZWQlpKgIKvo7 .icon-shape,#mermaid-svg-JwjJZWQlpKgIKvo7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JwjJZWQlpKgIKvo7 .icon-shape p,#mermaid-svg-JwjJZWQlpKgIKvo7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JwjJZWQlpKgIKvo7 .icon-shape .label rect,#mermaid-svg-JwjJZWQlpKgIKvo7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JwjJZWQlpKgIKvo7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JwjJZWQlpKgIKvo7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JwjJZWQlpKgIKvo7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} edge_search
Configured methods
edge_fulltext_search
edge_similarity_search
edge_bfs_search
并发召回候选
UUID dedupe
reranker
RRF
MMR
CrossEncoder.rank
node_distance_reranker
episode mentions
BFS 的一个细节
如果配置 BFS,但调用者没有提供明确 BFS origin nodes:
Graphiti 可以先从初步召回结果里的 source nodes 作为种子,再展开 BFS。
这使"文本召回 → 图结构扩展"自然连接起来。
第16章 Node / Edge Namespace:新一代数据访问 API
Graphiti 当前源码中有一个非常重要的架构演进。
设计文档:
text
spec/driver-operations-redesign.md
16.1 新目标
从过去"数据 Model 自己会访问数据库":
text
EntityNode.save(driver)
EntityEdge.get_by_uuid(driver)
逐步转向:
text
Graphiti
↓
Namespace
↓
Operations
↓
GraphDriver
16.2 新架构
#mermaid-svg-5SXU8posSLm4dbpE{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5SXU8posSLm4dbpE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5SXU8posSLm4dbpE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5SXU8posSLm4dbpE .error-icon{fill:#552222;}#mermaid-svg-5SXU8posSLm4dbpE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5SXU8posSLm4dbpE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5SXU8posSLm4dbpE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5SXU8posSLm4dbpE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5SXU8posSLm4dbpE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5SXU8posSLm4dbpE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5SXU8posSLm4dbpE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5SXU8posSLm4dbpE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5SXU8posSLm4dbpE .marker.cross{stroke:#333333;}#mermaid-svg-5SXU8posSLm4dbpE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5SXU8posSLm4dbpE p{margin:0;}#mermaid-svg-5SXU8posSLm4dbpE .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5SXU8posSLm4dbpE .cluster-label text{fill:#333;}#mermaid-svg-5SXU8posSLm4dbpE .cluster-label span{color:#333;}#mermaid-svg-5SXU8posSLm4dbpE .cluster-label span p{background-color:transparent;}#mermaid-svg-5SXU8posSLm4dbpE .label text,#mermaid-svg-5SXU8posSLm4dbpE span{fill:#333;color:#333;}#mermaid-svg-5SXU8posSLm4dbpE .node rect,#mermaid-svg-5SXU8posSLm4dbpE .node circle,#mermaid-svg-5SXU8posSLm4dbpE .node ellipse,#mermaid-svg-5SXU8posSLm4dbpE .node polygon,#mermaid-svg-5SXU8posSLm4dbpE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5SXU8posSLm4dbpE .rough-node .label text,#mermaid-svg-5SXU8posSLm4dbpE .node .label text,#mermaid-svg-5SXU8posSLm4dbpE .image-shape .label,#mermaid-svg-5SXU8posSLm4dbpE .icon-shape .label{text-anchor:middle;}#mermaid-svg-5SXU8posSLm4dbpE .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5SXU8posSLm4dbpE .rough-node .label,#mermaid-svg-5SXU8posSLm4dbpE .node .label,#mermaid-svg-5SXU8posSLm4dbpE .image-shape .label,#mermaid-svg-5SXU8posSLm4dbpE .icon-shape .label{text-align:center;}#mermaid-svg-5SXU8posSLm4dbpE .node.clickable{cursor:pointer;}#mermaid-svg-5SXU8posSLm4dbpE .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5SXU8posSLm4dbpE .arrowheadPath{fill:#333333;}#mermaid-svg-5SXU8posSLm4dbpE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5SXU8posSLm4dbpE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5SXU8posSLm4dbpE .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5SXU8posSLm4dbpE .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5SXU8posSLm4dbpE .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5SXU8posSLm4dbpE .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5SXU8posSLm4dbpE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5SXU8posSLm4dbpE .cluster text{fill:#333;}#mermaid-svg-5SXU8posSLm4dbpE .cluster span{color:#333;}#mermaid-svg-5SXU8posSLm4dbpE div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5SXU8posSLm4dbpE .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5SXU8posSLm4dbpE rect.text{fill:none;stroke-width:0;}#mermaid-svg-5SXU8posSLm4dbpE .icon-shape,#mermaid-svg-5SXU8posSLm4dbpE .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5SXU8posSLm4dbpE .icon-shape p,#mermaid-svg-5SXU8posSLm4dbpE .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5SXU8posSLm4dbpE .icon-shape .label rect,#mermaid-svg-5SXU8posSLm4dbpE .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5SXU8posSLm4dbpE .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5SXU8posSLm4dbpE .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5SXU8posSLm4dbpE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Application
Graphiti
graphiti.nodes.entity
graphiti.edges.entity
EntityNodeOps / EntityEdgeOps / ...
GraphDriver
Neo4j/FalkorDB/Neptune/Kuzu
16.3 为什么加 Namespace
例如:
text
graphiti.nodes.entity
graphiti.nodes.episode
graphiti.nodes.community
graphiti.nodes.saga
graphiti.edges.entity
graphiti.edges.episodic
...
好处:
- API 分类更清晰;
- Node / Edge Model 可以越来越"纯数据化";
- DB IO 不再散落在 Model;
- Namespace 可以负责 embedding/tracing;
- Operations 专注 DB 操作契约。
16.4 为什么源码里还能看到旧路径
因为 Driver Operations redesign 文档明确是 渐进迁移。
所以当前读源码会看到:
旧路径
text
model.save(driver)
graph_operations_interface
search_interface
新路径
text
graphiti.nodes...
graphiti.edges...
driver.entity_node_ops
driver.entity_edge_ops
driver.search_ops
...
这不是"重复设计失控",而是:
兼容迁移阶段同时存在两套 API。
读源码时务必意识到这一点。
第17章 Driver 层:Neo4j / FalkorDB / Neptune / Kuzu
核心:
text
graphiti_core/driver/
17.1 GraphDriver
driver.py 定义数据库抽象。
Provider 枚举包括:
text
NEO4J
FALKORDB
KUZU
NEPTUNE
17.2 Driver 的基本职责
#mermaid-svg-IiB4AajGt7QUAlOs{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-IiB4AajGt7QUAlOs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-IiB4AajGt7QUAlOs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-IiB4AajGt7QUAlOs .error-icon{fill:#552222;}#mermaid-svg-IiB4AajGt7QUAlOs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-IiB4AajGt7QUAlOs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-IiB4AajGt7QUAlOs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-IiB4AajGt7QUAlOs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-IiB4AajGt7QUAlOs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-IiB4AajGt7QUAlOs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-IiB4AajGt7QUAlOs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-IiB4AajGt7QUAlOs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-IiB4AajGt7QUAlOs .marker.cross{stroke:#333333;}#mermaid-svg-IiB4AajGt7QUAlOs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-IiB4AajGt7QUAlOs p{margin:0;}#mermaid-svg-IiB4AajGt7QUAlOs g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-IiB4AajGt7QUAlOs g.classGroup text .title{font-weight:bolder;}#mermaid-svg-IiB4AajGt7QUAlOs .cluster-label text{fill:#333;}#mermaid-svg-IiB4AajGt7QUAlOs .cluster-label span{color:#333;}#mermaid-svg-IiB4AajGt7QUAlOs .cluster-label span p{background-color:transparent;}#mermaid-svg-IiB4AajGt7QUAlOs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-IiB4AajGt7QUAlOs .cluster text{fill:#333;}#mermaid-svg-IiB4AajGt7QUAlOs .cluster span{color:#333;}#mermaid-svg-IiB4AajGt7QUAlOs .nodeLabel,#mermaid-svg-IiB4AajGt7QUAlOs .edgeLabel{color:#131300;}#mermaid-svg-IiB4AajGt7QUAlOs .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-IiB4AajGt7QUAlOs .label text{fill:#131300;}#mermaid-svg-IiB4AajGt7QUAlOs .labelBkg{background:#ECECFF;}#mermaid-svg-IiB4AajGt7QUAlOs .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-IiB4AajGt7QUAlOs .classTitle{font-weight:bolder;}#mermaid-svg-IiB4AajGt7QUAlOs .node rect,#mermaid-svg-IiB4AajGt7QUAlOs .node circle,#mermaid-svg-IiB4AajGt7QUAlOs .node ellipse,#mermaid-svg-IiB4AajGt7QUAlOs .node polygon,#mermaid-svg-IiB4AajGt7QUAlOs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-IiB4AajGt7QUAlOs .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-IiB4AajGt7QUAlOs g.clickable{cursor:pointer;}#mermaid-svg-IiB4AajGt7QUAlOs g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-IiB4AajGt7QUAlOs g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-IiB4AajGt7QUAlOs .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-IiB4AajGt7QUAlOs .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-IiB4AajGt7QUAlOs .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-IiB4AajGt7QUAlOs .dashed-line{stroke-dasharray:3;}#mermaid-svg-IiB4AajGt7QUAlOs .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-IiB4AajGt7QUAlOs #compositionStart,#mermaid-svg-IiB4AajGt7QUAlOs .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-IiB4AajGt7QUAlOs #compositionEnd,#mermaid-svg-IiB4AajGt7QUAlOs .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-IiB4AajGt7QUAlOs #dependencyStart,#mermaid-svg-IiB4AajGt7QUAlOs .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-IiB4AajGt7QUAlOs #dependencyStart,#mermaid-svg-IiB4AajGt7QUAlOs .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-IiB4AajGt7QUAlOs #extensionStart,#mermaid-svg-IiB4AajGt7QUAlOs .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-IiB4AajGt7QUAlOs #extensionEnd,#mermaid-svg-IiB4AajGt7QUAlOs .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-IiB4AajGt7QUAlOs #aggregationStart,#mermaid-svg-IiB4AajGt7QUAlOs .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-IiB4AajGt7QUAlOs #aggregationEnd,#mermaid-svg-IiB4AajGt7QUAlOs .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-IiB4AajGt7QUAlOs #lollipopStart,#mermaid-svg-IiB4AajGt7QUAlOs .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-IiB4AajGt7QUAlOs #lollipopEnd,#mermaid-svg-IiB4AajGt7QUAlOs .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-IiB4AajGt7QUAlOs .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-IiB4AajGt7QUAlOs .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-IiB4AajGt7QUAlOs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-IiB4AajGt7QUAlOs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-IiB4AajGt7QUAlOs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} <<abstract>>
GraphDriver
+entity_node_ops
+episode_node_ops
+entity_edge_ops
+search_ops
+graph_ops
+execute_query()
+session()
+close()
+build_indices_and_constraints()
+delete_all_indexes()
+with_database()
+clone()
+transaction()
Neo4jDriver
FalkorDriver
NeptuneDriver
KuzuDriver
17.3 QueryExecutor
它是更底层的 Query 执行契约。
思路:
text
QueryExecutor
↑
Operations interfaces
↑
GraphDriver
↑
Namespaces
↑
Graphiti
17.4 Operations 分类
driver/operations/ 按对象拆分:
text
community_edge_ops.py
community_node_ops.py
entity_edge_ops.py
entity_node_ops.py
episode_node_ops.py
episodic_edge_ops.py
graph_ops.py
graph_utils.py
has_episode_edge_ops.py
next_episode_edge_ops.py
saga_node_ops.py
search_ops.py
这比过去一个巨大的 Graph Operations interface 更容易维护。
17.5 Provider 特性
Neo4j
典型属性图数据库。
适合:
- Cypher;
- 节点/边查询;
- vector/fulltext indexes;
- 原生 transaction。
FalkorDB
基于 Redis 生态的图数据库。
Graphiti 对它有特殊的多 group_id 处理逻辑:
group 可能对应不同 graph,需要 clone driver 后分别查询并合并。
Neptune
AWS 图数据库。
Graphiti 还包含与 AWS/OpenSearch 相关的处理路径。
Kuzu
嵌入式图数据库方向。
项目结构中仍保留 Driver,但要结合当前项目文档看其支持状态;源码迁移过程中部分路径带有兼容/历史性质。
17.6 Transaction 抽象
#mermaid-svg-CwgDTKj1UmsLn0y0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CwgDTKj1UmsLn0y0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CwgDTKj1UmsLn0y0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CwgDTKj1UmsLn0y0 .error-icon{fill:#552222;}#mermaid-svg-CwgDTKj1UmsLn0y0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CwgDTKj1UmsLn0y0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CwgDTKj1UmsLn0y0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CwgDTKj1UmsLn0y0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CwgDTKj1UmsLn0y0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CwgDTKj1UmsLn0y0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CwgDTKj1UmsLn0y0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CwgDTKj1UmsLn0y0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CwgDTKj1UmsLn0y0 .marker.cross{stroke:#333333;}#mermaid-svg-CwgDTKj1UmsLn0y0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CwgDTKj1UmsLn0y0 p{margin:0;}#mermaid-svg-CwgDTKj1UmsLn0y0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-CwgDTKj1UmsLn0y0 .cluster-label text{fill:#333;}#mermaid-svg-CwgDTKj1UmsLn0y0 .cluster-label span{color:#333;}#mermaid-svg-CwgDTKj1UmsLn0y0 .cluster-label span p{background-color:transparent;}#mermaid-svg-CwgDTKj1UmsLn0y0 .label text,#mermaid-svg-CwgDTKj1UmsLn0y0 span{fill:#333;color:#333;}#mermaid-svg-CwgDTKj1UmsLn0y0 .node rect,#mermaid-svg-CwgDTKj1UmsLn0y0 .node circle,#mermaid-svg-CwgDTKj1UmsLn0y0 .node ellipse,#mermaid-svg-CwgDTKj1UmsLn0y0 .node polygon,#mermaid-svg-CwgDTKj1UmsLn0y0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CwgDTKj1UmsLn0y0 .rough-node .label text,#mermaid-svg-CwgDTKj1UmsLn0y0 .node .label text,#mermaid-svg-CwgDTKj1UmsLn0y0 .image-shape .label,#mermaid-svg-CwgDTKj1UmsLn0y0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-CwgDTKj1UmsLn0y0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CwgDTKj1UmsLn0y0 .rough-node .label,#mermaid-svg-CwgDTKj1UmsLn0y0 .node .label,#mermaid-svg-CwgDTKj1UmsLn0y0 .image-shape .label,#mermaid-svg-CwgDTKj1UmsLn0y0 .icon-shape .label{text-align:center;}#mermaid-svg-CwgDTKj1UmsLn0y0 .node.clickable{cursor:pointer;}#mermaid-svg-CwgDTKj1UmsLn0y0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CwgDTKj1UmsLn0y0 .arrowheadPath{fill:#333333;}#mermaid-svg-CwgDTKj1UmsLn0y0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CwgDTKj1UmsLn0y0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CwgDTKj1UmsLn0y0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CwgDTKj1UmsLn0y0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CwgDTKj1UmsLn0y0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CwgDTKj1UmsLn0y0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CwgDTKj1UmsLn0y0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CwgDTKj1UmsLn0y0 .cluster text{fill:#333;}#mermaid-svg-CwgDTKj1UmsLn0y0 .cluster span{color:#333;}#mermaid-svg-CwgDTKj1UmsLn0y0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CwgDTKj1UmsLn0y0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CwgDTKj1UmsLn0y0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-CwgDTKj1UmsLn0y0 .icon-shape,#mermaid-svg-CwgDTKj1UmsLn0y0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CwgDTKj1UmsLn0y0 .icon-shape p,#mermaid-svg-CwgDTKj1UmsLn0y0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CwgDTKj1UmsLn0y0 .icon-shape .label rect,#mermaid-svg-CwgDTKj1UmsLn0y0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CwgDTKj1UmsLn0y0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CwgDTKj1UmsLn0y0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CwgDTKj1UmsLn0y0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} driver.transaction()
Provider
Neo4j
native transaction
commit / rollback
其他 Provider
wrapper / provider-specific semantics
设计重点:
上层 Operations 使用统一 transaction contract,而不用知道底层数据库差异。
第18章 LLM Client 层
核心:
text
graphiti_core/llm_client/
18.1 主要抽象
text
LLMClient
├─ OpenAIClient
├─ AzureOpenAIClient
├─ AnthropicClient
├─ GeminiClient
├─ GroqClient
├─ OpenAIGenericClient
└─ GLiNER2Client
18.2 LLMClient.generate_response()
它不仅是:
text
messages -> API
还承担:
- response model schema 注入;
- structured output;
- 字符清洗;
- 多语言 extraction instruction;
- cache;
- retry;
- token tracking;
- tracing;
- error normalization。
18.3 调用流程
TokenTracker/Tracer Provider API Cache Pydantic Response Model LLMClient Extraction/Dedupe TokenTracker/Tracer Provider API Cache Pydantic Response Model LLMClient Extraction/Dedupe #mermaid-svg-eRbEIelOUw3Qxtz3{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eRbEIelOUw3Qxtz3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eRbEIelOUw3Qxtz3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eRbEIelOUw3Qxtz3 .error-icon{fill:#552222;}#mermaid-svg-eRbEIelOUw3Qxtz3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eRbEIelOUw3Qxtz3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eRbEIelOUw3Qxtz3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eRbEIelOUw3Qxtz3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eRbEIelOUw3Qxtz3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eRbEIelOUw3Qxtz3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eRbEIelOUw3Qxtz3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eRbEIelOUw3Qxtz3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eRbEIelOUw3Qxtz3 .marker.cross{stroke:#333333;}#mermaid-svg-eRbEIelOUw3Qxtz3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eRbEIelOUw3Qxtz3 p{margin:0;}#mermaid-svg-eRbEIelOUw3Qxtz3 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-eRbEIelOUw3Qxtz3 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-eRbEIelOUw3Qxtz3 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-eRbEIelOUw3Qxtz3 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-eRbEIelOUw3Qxtz3 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-eRbEIelOUw3Qxtz3 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-eRbEIelOUw3Qxtz3 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-eRbEIelOUw3Qxtz3 .sequenceNumber{fill:white;}#mermaid-svg-eRbEIelOUw3Qxtz3 #sequencenumber{fill:#333;}#mermaid-svg-eRbEIelOUw3Qxtz3 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-eRbEIelOUw3Qxtz3 .messageText{fill:#333;stroke:none;}#mermaid-svg-eRbEIelOUw3Qxtz3 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-eRbEIelOUw3Qxtz3 .labelText,#mermaid-svg-eRbEIelOUw3Qxtz3 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-eRbEIelOUw3Qxtz3 .loopText,#mermaid-svg-eRbEIelOUw3Qxtz3 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-eRbEIelOUw3Qxtz3 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-eRbEIelOUw3Qxtz3 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-eRbEIelOUw3Qxtz3 .noteText,#mermaid-svg-eRbEIelOUw3Qxtz3 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-eRbEIelOUw3Qxtz3 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-eRbEIelOUw3Qxtz3 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-eRbEIelOUw3Qxtz3 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-eRbEIelOUw3Qxtz3 .actorPopupMenu{position:absolute;}#mermaid-svg-eRbEIelOUw3Qxtz3 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-eRbEIelOUw3Qxtz3 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-eRbEIelOUw3Qxtz3 .actor-man circle,#mermaid-svg-eRbEIelOUw3Qxtz3 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-eRbEIelOUw3Qxtz3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} alt cache hit cache miss generate_response(messages, response_model) 生成/注入 JSON Schema 清理字符 + instruction start span 查 cache structured result provider request response parse / validate / retry if needed save cache usage + span metadata dict / structured response
18.4 Retry
Graphiti 的 LLM base client 有重试逻辑,用于:
- rate limit;
- 空结果;
- JSON decode;
- 部分 5xx。
这是生产 Agent 很重要的一层。
18.5 small_model
配置中区分:
text
model
small_model
含义:
不同复杂度任务可以使用不同成本模型。
例如时间解析、简单抽取等任务不一定要始终使用最强模型。
第19章 Prompt 系统:Graphiti 的"认知逻辑"放在哪里
核心:
text
graphiti_core/prompts/
很多人读 Agent 项目只看 Python 代码,会漏掉真正的业务逻辑。
Graphiti 中 Prompt 是系统行为的重要组成部分。
19.1 PromptLibrary
大体提供:
text
PromptLibrary
├─ extract_nodes
├─ dedupe_nodes
├─ extract_edges
├─ extract_nodes_and_edges
├─ dedupe_edges
├─ summarize_nodes
├─ summarize_sagas
└─ eval
19.2 Prompt 与算法模块对应关系
#mermaid-svg-8iCG2DvLxmQtH4z2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8iCG2DvLxmQtH4z2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8iCG2DvLxmQtH4z2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8iCG2DvLxmQtH4z2 .error-icon{fill:#552222;}#mermaid-svg-8iCG2DvLxmQtH4z2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8iCG2DvLxmQtH4z2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8iCG2DvLxmQtH4z2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8iCG2DvLxmQtH4z2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8iCG2DvLxmQtH4z2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8iCG2DvLxmQtH4z2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8iCG2DvLxmQtH4z2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8iCG2DvLxmQtH4z2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8iCG2DvLxmQtH4z2 .marker.cross{stroke:#333333;}#mermaid-svg-8iCG2DvLxmQtH4z2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8iCG2DvLxmQtH4z2 p{margin:0;}#mermaid-svg-8iCG2DvLxmQtH4z2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8iCG2DvLxmQtH4z2 .cluster-label text{fill:#333;}#mermaid-svg-8iCG2DvLxmQtH4z2 .cluster-label span{color:#333;}#mermaid-svg-8iCG2DvLxmQtH4z2 .cluster-label span p{background-color:transparent;}#mermaid-svg-8iCG2DvLxmQtH4z2 .label text,#mermaid-svg-8iCG2DvLxmQtH4z2 span{fill:#333;color:#333;}#mermaid-svg-8iCG2DvLxmQtH4z2 .node rect,#mermaid-svg-8iCG2DvLxmQtH4z2 .node circle,#mermaid-svg-8iCG2DvLxmQtH4z2 .node ellipse,#mermaid-svg-8iCG2DvLxmQtH4z2 .node polygon,#mermaid-svg-8iCG2DvLxmQtH4z2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8iCG2DvLxmQtH4z2 .rough-node .label text,#mermaid-svg-8iCG2DvLxmQtH4z2 .node .label text,#mermaid-svg-8iCG2DvLxmQtH4z2 .image-shape .label,#mermaid-svg-8iCG2DvLxmQtH4z2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-8iCG2DvLxmQtH4z2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8iCG2DvLxmQtH4z2 .rough-node .label,#mermaid-svg-8iCG2DvLxmQtH4z2 .node .label,#mermaid-svg-8iCG2DvLxmQtH4z2 .image-shape .label,#mermaid-svg-8iCG2DvLxmQtH4z2 .icon-shape .label{text-align:center;}#mermaid-svg-8iCG2DvLxmQtH4z2 .node.clickable{cursor:pointer;}#mermaid-svg-8iCG2DvLxmQtH4z2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8iCG2DvLxmQtH4z2 .arrowheadPath{fill:#333333;}#mermaid-svg-8iCG2DvLxmQtH4z2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8iCG2DvLxmQtH4z2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8iCG2DvLxmQtH4z2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8iCG2DvLxmQtH4z2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8iCG2DvLxmQtH4z2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8iCG2DvLxmQtH4z2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8iCG2DvLxmQtH4z2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8iCG2DvLxmQtH4z2 .cluster text{fill:#333;}#mermaid-svg-8iCG2DvLxmQtH4z2 .cluster span{color:#333;}#mermaid-svg-8iCG2DvLxmQtH4z2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8iCG2DvLxmQtH4z2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8iCG2DvLxmQtH4z2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-8iCG2DvLxmQtH4z2 .icon-shape,#mermaid-svg-8iCG2DvLxmQtH4z2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8iCG2DvLxmQtH4z2 .icon-shape p,#mermaid-svg-8iCG2DvLxmQtH4z2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8iCG2DvLxmQtH4z2 .icon-shape .label rect,#mermaid-svg-8iCG2DvLxmQtH4z2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8iCG2DvLxmQtH4z2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8iCG2DvLxmQtH4z2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8iCG2DvLxmQtH4z2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} node_operations.extract_nodes
prompts.extract_nodes
edge_operations.extract_edges
prompts.extract_edges
resolve nodes
prompts.dedupe_nodes
resolve edges
prompts.dedupe_edges
summary
prompts.summarize_nodes / sagas
19.3 为什么 Prompt 使用 Pydantic Model
LLM 不应该随便返回一段自由文本。
Graphiti 倾向让输出满足结构:
text
entities: [...]
edges: [...]
duplicates: [...]
valid_at: ...
invalid_at: ...
因此:
text
Prompt
+
response_model JSON schema
↓
LLM
↓
结构化数据
↓
Python 业务逻辑
这比用正则从自然语言答案里提取稳定很多。
第20章 Embedder 与 Cross-Encoder
20.1 Embedder
目录:
text
graphiti_core/embedder/
抽象:
text
EmbedderClient
├─ create(text)
└─ create_batch(texts)
Provider:
- OpenAI
- Azure OpenAI
- Gemini
- Voyage
默认 embedding dimension 可通过环境配置,源码存在 EMBEDDING_DIM 相关设置。
20.2 Embedding 用在哪里
#mermaid-svg-BmjzSDGimUJMlp53{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BmjzSDGimUJMlp53 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BmjzSDGimUJMlp53 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BmjzSDGimUJMlp53 .error-icon{fill:#552222;}#mermaid-svg-BmjzSDGimUJMlp53 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BmjzSDGimUJMlp53 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BmjzSDGimUJMlp53 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BmjzSDGimUJMlp53 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BmjzSDGimUJMlp53 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BmjzSDGimUJMlp53 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BmjzSDGimUJMlp53 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BmjzSDGimUJMlp53 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BmjzSDGimUJMlp53 .marker.cross{stroke:#333333;}#mermaid-svg-BmjzSDGimUJMlp53 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BmjzSDGimUJMlp53 p{margin:0;}#mermaid-svg-BmjzSDGimUJMlp53 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-BmjzSDGimUJMlp53 .cluster-label text{fill:#333;}#mermaid-svg-BmjzSDGimUJMlp53 .cluster-label span{color:#333;}#mermaid-svg-BmjzSDGimUJMlp53 .cluster-label span p{background-color:transparent;}#mermaid-svg-BmjzSDGimUJMlp53 .label text,#mermaid-svg-BmjzSDGimUJMlp53 span{fill:#333;color:#333;}#mermaid-svg-BmjzSDGimUJMlp53 .node rect,#mermaid-svg-BmjzSDGimUJMlp53 .node circle,#mermaid-svg-BmjzSDGimUJMlp53 .node ellipse,#mermaid-svg-BmjzSDGimUJMlp53 .node polygon,#mermaid-svg-BmjzSDGimUJMlp53 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BmjzSDGimUJMlp53 .rough-node .label text,#mermaid-svg-BmjzSDGimUJMlp53 .node .label text,#mermaid-svg-BmjzSDGimUJMlp53 .image-shape .label,#mermaid-svg-BmjzSDGimUJMlp53 .icon-shape .label{text-anchor:middle;}#mermaid-svg-BmjzSDGimUJMlp53 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BmjzSDGimUJMlp53 .rough-node .label,#mermaid-svg-BmjzSDGimUJMlp53 .node .label,#mermaid-svg-BmjzSDGimUJMlp53 .image-shape .label,#mermaid-svg-BmjzSDGimUJMlp53 .icon-shape .label{text-align:center;}#mermaid-svg-BmjzSDGimUJMlp53 .node.clickable{cursor:pointer;}#mermaid-svg-BmjzSDGimUJMlp53 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BmjzSDGimUJMlp53 .arrowheadPath{fill:#333333;}#mermaid-svg-BmjzSDGimUJMlp53 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BmjzSDGimUJMlp53 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BmjzSDGimUJMlp53 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BmjzSDGimUJMlp53 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BmjzSDGimUJMlp53 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BmjzSDGimUJMlp53 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BmjzSDGimUJMlp53 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BmjzSDGimUJMlp53 .cluster text{fill:#333;}#mermaid-svg-BmjzSDGimUJMlp53 .cluster span{color:#333;}#mermaid-svg-BmjzSDGimUJMlp53 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-BmjzSDGimUJMlp53 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BmjzSDGimUJMlp53 rect.text{fill:none;stroke-width:0;}#mermaid-svg-BmjzSDGimUJMlp53 .icon-shape,#mermaid-svg-BmjzSDGimUJMlp53 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BmjzSDGimUJMlp53 .icon-shape p,#mermaid-svg-BmjzSDGimUJMlp53 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BmjzSDGimUJMlp53 .icon-shape .label rect,#mermaid-svg-BmjzSDGimUJMlp53 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BmjzSDGimUJMlp53 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BmjzSDGimUJMlp53 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BmjzSDGimUJMlp53 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Embedder
Entity.name
EntityEdge.fact
Community.name / summary related representation
Search Query
主要用途:
- Entity semantic dedupe;
- Edge semantic dedupe;
- vector search;
- MMR;
- Community similarity。
20.3 CrossEncoder
目录:
text
graphiti_core/cross_encoder/
抽象:
text
rank(query, passages)
↓
[(passage, score), ...]
实现包括:
- BGE reranker;
- OpenAI reranker;
- Gemini reranker。
它主要处于:
text
Recall
↓
Candidate set
↓
CrossEncoder.rank
↓
high precision Top-K
第21章 Community:图社区与摘要
Community 不是 Episode,也不是普通实体。
它是:
一组紧密相关 Entity 的高层抽象。
21.1 Community 构建概念
#mermaid-svg-3iT9ONHQkBuLdYav{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3iT9ONHQkBuLdYav .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3iT9ONHQkBuLdYav .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3iT9ONHQkBuLdYav .error-icon{fill:#552222;}#mermaid-svg-3iT9ONHQkBuLdYav .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3iT9ONHQkBuLdYav .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3iT9ONHQkBuLdYav .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3iT9ONHQkBuLdYav .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3iT9ONHQkBuLdYav .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3iT9ONHQkBuLdYav .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3iT9ONHQkBuLdYav .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3iT9ONHQkBuLdYav .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3iT9ONHQkBuLdYav .marker.cross{stroke:#333333;}#mermaid-svg-3iT9ONHQkBuLdYav svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3iT9ONHQkBuLdYav p{margin:0;}#mermaid-svg-3iT9ONHQkBuLdYav .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-3iT9ONHQkBuLdYav .cluster-label text{fill:#333;}#mermaid-svg-3iT9ONHQkBuLdYav .cluster-label span{color:#333;}#mermaid-svg-3iT9ONHQkBuLdYav .cluster-label span p{background-color:transparent;}#mermaid-svg-3iT9ONHQkBuLdYav .label text,#mermaid-svg-3iT9ONHQkBuLdYav span{fill:#333;color:#333;}#mermaid-svg-3iT9ONHQkBuLdYav .node rect,#mermaid-svg-3iT9ONHQkBuLdYav .node circle,#mermaid-svg-3iT9ONHQkBuLdYav .node ellipse,#mermaid-svg-3iT9ONHQkBuLdYav .node polygon,#mermaid-svg-3iT9ONHQkBuLdYav .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-3iT9ONHQkBuLdYav .rough-node .label text,#mermaid-svg-3iT9ONHQkBuLdYav .node .label text,#mermaid-svg-3iT9ONHQkBuLdYav .image-shape .label,#mermaid-svg-3iT9ONHQkBuLdYav .icon-shape .label{text-anchor:middle;}#mermaid-svg-3iT9ONHQkBuLdYav .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-3iT9ONHQkBuLdYav .rough-node .label,#mermaid-svg-3iT9ONHQkBuLdYav .node .label,#mermaid-svg-3iT9ONHQkBuLdYav .image-shape .label,#mermaid-svg-3iT9ONHQkBuLdYav .icon-shape .label{text-align:center;}#mermaid-svg-3iT9ONHQkBuLdYav .node.clickable{cursor:pointer;}#mermaid-svg-3iT9ONHQkBuLdYav .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-3iT9ONHQkBuLdYav .arrowheadPath{fill:#333333;}#mermaid-svg-3iT9ONHQkBuLdYav .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-3iT9ONHQkBuLdYav .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-3iT9ONHQkBuLdYav .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3iT9ONHQkBuLdYav .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-3iT9ONHQkBuLdYav .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3iT9ONHQkBuLdYav .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-3iT9ONHQkBuLdYav .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-3iT9ONHQkBuLdYav .cluster text{fill:#333;}#mermaid-svg-3iT9ONHQkBuLdYav .cluster span{color:#333;}#mermaid-svg-3iT9ONHQkBuLdYav div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-3iT9ONHQkBuLdYav .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-3iT9ONHQkBuLdYav rect.text{fill:none;stroke-width:0;}#mermaid-svg-3iT9ONHQkBuLdYav .icon-shape,#mermaid-svg-3iT9ONHQkBuLdYav .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3iT9ONHQkBuLdYav .icon-shape p,#mermaid-svg-3iT9ONHQkBuLdYav .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-3iT9ONHQkBuLdYav .icon-shape .label rect,#mermaid-svg-3iT9ONHQkBuLdYav .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3iT9ONHQkBuLdYav .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-3iT9ONHQkBuLdYav .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-3iT9ONHQkBuLdYav :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Entity Graph
Community Detection
member nodes
LLM Summary
CommunityNode
CommunityEdge HAS_MEMBER
Embedding
Database
21.2 Graphiti.build_communities()
大意:
- 按 scope 清理/处理已有 community;
- 调维护函数构建 communities;
- 生成 Community embedding;
- 保存 community nodes/edges。
21.3 为什么 SearchResults 单独有 communities
因为 Query 有时要的是:
"这个主题整体是怎么回事?"
而不是某一条具体 Fact。
第22章 维护、去重、属性抽取工具链
目录:
text
graphiti_core/utils/maintenance/
这是除 graphiti.py 外最值得逐文件阅读的区域。
22.1 文件职责图
#mermaid-svg-glj7EFbSF56c13zS{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-glj7EFbSF56c13zS .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-glj7EFbSF56c13zS .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-glj7EFbSF56c13zS .error-icon{fill:#552222;}#mermaid-svg-glj7EFbSF56c13zS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-glj7EFbSF56c13zS .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-glj7EFbSF56c13zS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-glj7EFbSF56c13zS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-glj7EFbSF56c13zS .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-glj7EFbSF56c13zS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-glj7EFbSF56c13zS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-glj7EFbSF56c13zS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-glj7EFbSF56c13zS .marker.cross{stroke:#333333;}#mermaid-svg-glj7EFbSF56c13zS svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-glj7EFbSF56c13zS p{margin:0;}#mermaid-svg-glj7EFbSF56c13zS .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-glj7EFbSF56c13zS .cluster-label text{fill:#333;}#mermaid-svg-glj7EFbSF56c13zS .cluster-label span{color:#333;}#mermaid-svg-glj7EFbSF56c13zS .cluster-label span p{background-color:transparent;}#mermaid-svg-glj7EFbSF56c13zS .label text,#mermaid-svg-glj7EFbSF56c13zS span{fill:#333;color:#333;}#mermaid-svg-glj7EFbSF56c13zS .node rect,#mermaid-svg-glj7EFbSF56c13zS .node circle,#mermaid-svg-glj7EFbSF56c13zS .node ellipse,#mermaid-svg-glj7EFbSF56c13zS .node polygon,#mermaid-svg-glj7EFbSF56c13zS .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-glj7EFbSF56c13zS .rough-node .label text,#mermaid-svg-glj7EFbSF56c13zS .node .label text,#mermaid-svg-glj7EFbSF56c13zS .image-shape .label,#mermaid-svg-glj7EFbSF56c13zS .icon-shape .label{text-anchor:middle;}#mermaid-svg-glj7EFbSF56c13zS .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-glj7EFbSF56c13zS .rough-node .label,#mermaid-svg-glj7EFbSF56c13zS .node .label,#mermaid-svg-glj7EFbSF56c13zS .image-shape .label,#mermaid-svg-glj7EFbSF56c13zS .icon-shape .label{text-align:center;}#mermaid-svg-glj7EFbSF56c13zS .node.clickable{cursor:pointer;}#mermaid-svg-glj7EFbSF56c13zS .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-glj7EFbSF56c13zS .arrowheadPath{fill:#333333;}#mermaid-svg-glj7EFbSF56c13zS .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-glj7EFbSF56c13zS .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-glj7EFbSF56c13zS .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-glj7EFbSF56c13zS .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-glj7EFbSF56c13zS .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-glj7EFbSF56c13zS .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-glj7EFbSF56c13zS .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-glj7EFbSF56c13zS .cluster text{fill:#333;}#mermaid-svg-glj7EFbSF56c13zS .cluster span{color:#333;}#mermaid-svg-glj7EFbSF56c13zS div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-glj7EFbSF56c13zS .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-glj7EFbSF56c13zS rect.text{fill:none;stroke-width:0;}#mermaid-svg-glj7EFbSF56c13zS .icon-shape,#mermaid-svg-glj7EFbSF56c13zS .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-glj7EFbSF56c13zS .icon-shape p,#mermaid-svg-glj7EFbSF56c13zS .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-glj7EFbSF56c13zS .icon-shape .label rect,#mermaid-svg-glj7EFbSF56c13zS .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-glj7EFbSF56c13zS .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-glj7EFbSF56c13zS .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-glj7EFbSF56c13zS :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} graphiti.py
node_operations.py
edge_operations.py
community_operations.py
combined_extraction.py
dedup_helpers.py
attribute_utils.py
graph_data_operations.py
22.2 node_operations.py
职责:
extract_nodes- semantic candidate search
- entity resolution
- LLM dedupe fallback
- attributes extraction
- entity summaries
它负责:
"一句话里有哪些东西?"以及"这个东西是不是图里已经有了?"
22.3 edge_operations.py
职责:
extract_edgesbuild_episodic_edgesbuild_community_edgesresolve_extracted_edgesresolve_extracted_edge- 时间抽取
- 矛盾失效
它负责:
"这些东西之间发生了什么?这个事实是不是新的?是否推翻了旧事实?"
22.4 combined_extraction.py
将:
text
Node extraction
+
Edge extraction
在适合的 bulk 场景中合并。
目的:
- 降低 LLM round trips;
- 保持一次抽取的一致性。
22.5 dedup_helpers.py
集中放置去重辅助算法:
- 候选组织;
- 相似性处理;
- duplicate indexing;
- resolution 过程中的共享逻辑。
22.6 attribute_utils.py
处理自定义 entity/edge schema 的属性:
从 LLM structured output 中,把 ontology 定义的字段安全地装配到节点/边。
22.7 graph_data_operations.py
处理更偏图数据维护的操作,例如:
- clear;
- episode retrieval;
- 查询前序 Episode;
- 与图数据操作相关的工具。
它把"业务算法"和"数据取回"分离开。
第23章 FastAPI Server
目录:
text
server/
└─ graph_service/
├─ dto/
├─ routers/
├─ config.py
├─ main.py
└─ zep_graphiti.py
23.1 分层
#mermaid-svg-nGxZ1kuVLmzWat4k{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nGxZ1kuVLmzWat4k .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nGxZ1kuVLmzWat4k .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nGxZ1kuVLmzWat4k .error-icon{fill:#552222;}#mermaid-svg-nGxZ1kuVLmzWat4k .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nGxZ1kuVLmzWat4k .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nGxZ1kuVLmzWat4k .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nGxZ1kuVLmzWat4k .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nGxZ1kuVLmzWat4k .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nGxZ1kuVLmzWat4k .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nGxZ1kuVLmzWat4k .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nGxZ1kuVLmzWat4k .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nGxZ1kuVLmzWat4k .marker.cross{stroke:#333333;}#mermaid-svg-nGxZ1kuVLmzWat4k svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nGxZ1kuVLmzWat4k p{margin:0;}#mermaid-svg-nGxZ1kuVLmzWat4k .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nGxZ1kuVLmzWat4k .cluster-label text{fill:#333;}#mermaid-svg-nGxZ1kuVLmzWat4k .cluster-label span{color:#333;}#mermaid-svg-nGxZ1kuVLmzWat4k .cluster-label span p{background-color:transparent;}#mermaid-svg-nGxZ1kuVLmzWat4k .label text,#mermaid-svg-nGxZ1kuVLmzWat4k span{fill:#333;color:#333;}#mermaid-svg-nGxZ1kuVLmzWat4k .node rect,#mermaid-svg-nGxZ1kuVLmzWat4k .node circle,#mermaid-svg-nGxZ1kuVLmzWat4k .node ellipse,#mermaid-svg-nGxZ1kuVLmzWat4k .node polygon,#mermaid-svg-nGxZ1kuVLmzWat4k .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nGxZ1kuVLmzWat4k .rough-node .label text,#mermaid-svg-nGxZ1kuVLmzWat4k .node .label text,#mermaid-svg-nGxZ1kuVLmzWat4k .image-shape .label,#mermaid-svg-nGxZ1kuVLmzWat4k .icon-shape .label{text-anchor:middle;}#mermaid-svg-nGxZ1kuVLmzWat4k .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nGxZ1kuVLmzWat4k .rough-node .label,#mermaid-svg-nGxZ1kuVLmzWat4k .node .label,#mermaid-svg-nGxZ1kuVLmzWat4k .image-shape .label,#mermaid-svg-nGxZ1kuVLmzWat4k .icon-shape .label{text-align:center;}#mermaid-svg-nGxZ1kuVLmzWat4k .node.clickable{cursor:pointer;}#mermaid-svg-nGxZ1kuVLmzWat4k .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nGxZ1kuVLmzWat4k .arrowheadPath{fill:#333333;}#mermaid-svg-nGxZ1kuVLmzWat4k .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nGxZ1kuVLmzWat4k .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nGxZ1kuVLmzWat4k .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nGxZ1kuVLmzWat4k .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nGxZ1kuVLmzWat4k .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nGxZ1kuVLmzWat4k .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nGxZ1kuVLmzWat4k .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nGxZ1kuVLmzWat4k .cluster text{fill:#333;}#mermaid-svg-nGxZ1kuVLmzWat4k .cluster span{color:#333;}#mermaid-svg-nGxZ1kuVLmzWat4k div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nGxZ1kuVLmzWat4k .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nGxZ1kuVLmzWat4k rect.text{fill:none;stroke-width:0;}#mermaid-svg-nGxZ1kuVLmzWat4k .icon-shape,#mermaid-svg-nGxZ1kuVLmzWat4k .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nGxZ1kuVLmzWat4k .icon-shape p,#mermaid-svg-nGxZ1kuVLmzWat4k .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nGxZ1kuVLmzWat4k .icon-shape .label rect,#mermaid-svg-nGxZ1kuVLmzWat4k .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nGxZ1kuVLmzWat4k .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nGxZ1kuVLmzWat4k .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nGxZ1kuVLmzWat4k :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} HTTP Client
graph_service.main
FastAPI App
routers
dto
zep_graphiti.py
Graphiti Core
Graph DB
23.2 dto/
DTO:
Data Transfer Object,数据传输对象
主要分:
common.pyingest.pyretrieve.py
用于定义 HTTP 请求/响应模型,而不是领域核心 Model。
23.3 routers/
ingest.py:写入相关 API;retrieve.py:检索相关 API。
Router 应该被看作:
传输层适配器。
不要把核心知识图逻辑写在 Router 中,真正逻辑仍在 Graphiti Core。
23.4 config.py
服务配置:
- DB;
- 模型;
- 环境变量;
- 服务运行参数等。
23.5 zep_graphiti.py
作用可以理解为:
Server 与 Graphiti Core 的装配/适配层。
即负责构造 Graphiti 实例、绑定服务需要的依赖。
第24章 MCP Server
目录:
text
mcp_server/
├─ src/
│ ├─ config/
│ ├─ models/
│ ├─ services/
│ ├─ utils/
│ └─ graphiti_mcp_server.py
├─ config/
├─ docker/
├─ docs/
├─ tests/
├─ main.py
└─ pyproject.toml
24.1 MCP 是什么
MCP:
Model Context Protocol
可以理解为一个让 AI Client / Agent 统一发现和调用外部工具、资源、上下文的协议层。
Graphiti MCP Server 的作用就是:
#mermaid-svg-5XQJFxB1fwprX7BE{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5XQJFxB1fwprX7BE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5XQJFxB1fwprX7BE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5XQJFxB1fwprX7BE .error-icon{fill:#552222;}#mermaid-svg-5XQJFxB1fwprX7BE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5XQJFxB1fwprX7BE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5XQJFxB1fwprX7BE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5XQJFxB1fwprX7BE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5XQJFxB1fwprX7BE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5XQJFxB1fwprX7BE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5XQJFxB1fwprX7BE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5XQJFxB1fwprX7BE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5XQJFxB1fwprX7BE .marker.cross{stroke:#333333;}#mermaid-svg-5XQJFxB1fwprX7BE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5XQJFxB1fwprX7BE p{margin:0;}#mermaid-svg-5XQJFxB1fwprX7BE .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5XQJFxB1fwprX7BE .cluster-label text{fill:#333;}#mermaid-svg-5XQJFxB1fwprX7BE .cluster-label span{color:#333;}#mermaid-svg-5XQJFxB1fwprX7BE .cluster-label span p{background-color:transparent;}#mermaid-svg-5XQJFxB1fwprX7BE .label text,#mermaid-svg-5XQJFxB1fwprX7BE span{fill:#333;color:#333;}#mermaid-svg-5XQJFxB1fwprX7BE .node rect,#mermaid-svg-5XQJFxB1fwprX7BE .node circle,#mermaid-svg-5XQJFxB1fwprX7BE .node ellipse,#mermaid-svg-5XQJFxB1fwprX7BE .node polygon,#mermaid-svg-5XQJFxB1fwprX7BE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5XQJFxB1fwprX7BE .rough-node .label text,#mermaid-svg-5XQJFxB1fwprX7BE .node .label text,#mermaid-svg-5XQJFxB1fwprX7BE .image-shape .label,#mermaid-svg-5XQJFxB1fwprX7BE .icon-shape .label{text-anchor:middle;}#mermaid-svg-5XQJFxB1fwprX7BE .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5XQJFxB1fwprX7BE .rough-node .label,#mermaid-svg-5XQJFxB1fwprX7BE .node .label,#mermaid-svg-5XQJFxB1fwprX7BE .image-shape .label,#mermaid-svg-5XQJFxB1fwprX7BE .icon-shape .label{text-align:center;}#mermaid-svg-5XQJFxB1fwprX7BE .node.clickable{cursor:pointer;}#mermaid-svg-5XQJFxB1fwprX7BE .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5XQJFxB1fwprX7BE .arrowheadPath{fill:#333333;}#mermaid-svg-5XQJFxB1fwprX7BE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5XQJFxB1fwprX7BE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5XQJFxB1fwprX7BE .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5XQJFxB1fwprX7BE .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5XQJFxB1fwprX7BE .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5XQJFxB1fwprX7BE .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5XQJFxB1fwprX7BE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5XQJFxB1fwprX7BE .cluster text{fill:#333;}#mermaid-svg-5XQJFxB1fwprX7BE .cluster span{color:#333;}#mermaid-svg-5XQJFxB1fwprX7BE div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5XQJFxB1fwprX7BE .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5XQJFxB1fwprX7BE rect.text{fill:none;stroke-width:0;}#mermaid-svg-5XQJFxB1fwprX7BE .icon-shape,#mermaid-svg-5XQJFxB1fwprX7BE .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5XQJFxB1fwprX7BE .icon-shape p,#mermaid-svg-5XQJFxB1fwprX7BE .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5XQJFxB1fwprX7BE .icon-shape .label rect,#mermaid-svg-5XQJFxB1fwprX7BE .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5XQJFxB1fwprX7BE .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5XQJFxB1fwprX7BE .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5XQJFxB1fwprX7BE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Claude / IDE / Agent
MCP Protocol
Graphiti MCP Server
Graphiti
Context Graph
24.2 graphiti_mcp_server.py
这是 MCP 服务主实现。
它负责把 Graphiti 能力包装成 MCP 可调用接口。
24.3 services/factories.py
典型职责:
根据配置创建 Driver、LLM、Embedder、Graphiti 等依赖。
属于 Factory / Dependency Assembly。
24.4 services/queue_service.py
用于组织写入队列/任务处理。
原因:
Graphiti Episode ingestion 是多阶段异步过程:
text
LLM
Embedding
DB read
DB write
直接无控制地并发大量写入会造成:
- 顺序问题;
- rate limit;
- DB 压力;
- 事实时间解析上下文异常。
Queue Service 用来让 MCP 接入侧更好地控制处理。
24.5 models/
包括:
edge_types.pyentity_types.pyresponse_types.py
这些更偏 MCP API schema,而不是 graphiti_core 领域 Model。
24.6 utils/
formatting.pytype_config.pyutils.py
负责 MCP 层格式转换、类型配置、共用工具。
第25章 Tracing、Telemetry、并发与容错
25.1 Tracer 与 Telemetry 不要混淆
graphiti_core/tracer.py
这是 OpenTelemetry 风格的运行链路追踪抽象:
text
Graphiti operation
↓
span
├─ add_episode
├─ extract
├─ search
└─ llm.generate
默认可以是 NoOp,也可以接 OpenTelemetry。
graphiti_core/telemetry/
这是项目自己的匿名产品/使用 telemetry 逻辑,包含 PostHog 相关能力。
所以:
text
Tracing = 运行链路观测
Telemetry = 使用/产品统计
25.2 并发
Graphiti 大量使用:
text
async / await
semaphore
gather
尤其:
- 多节点 embedding;
- 多实体 candidate search;
- 多搜索通道;
- nodes / edges / episodes / communities 并发检索。
25.3 为什么需要 Semaphore
如果 Episode 一次抽出 30 个实体:
text
30 embeddings
30 searches
若干 LLM calls
完全裸 asyncio.gather() 可能瞬间触发:
- API rate limit;
- DB connection pool 爆满;
- 资源峰值。
所以项目中存在并发限制工具。
25.4 handle_multiple_group_ids
该 decorator 尤其用于处理 FalkorDB 多 graph 情况。
概念:
#mermaid-svg-yIJzF4KRhtIxxtp8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yIJzF4KRhtIxxtp8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yIJzF4KRhtIxxtp8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yIJzF4KRhtIxxtp8 .error-icon{fill:#552222;}#mermaid-svg-yIJzF4KRhtIxxtp8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yIJzF4KRhtIxxtp8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yIJzF4KRhtIxxtp8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yIJzF4KRhtIxxtp8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yIJzF4KRhtIxxtp8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yIJzF4KRhtIxxtp8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yIJzF4KRhtIxxtp8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yIJzF4KRhtIxxtp8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yIJzF4KRhtIxxtp8 .marker.cross{stroke:#333333;}#mermaid-svg-yIJzF4KRhtIxxtp8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yIJzF4KRhtIxxtp8 p{margin:0;}#mermaid-svg-yIJzF4KRhtIxxtp8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yIJzF4KRhtIxxtp8 .cluster-label text{fill:#333;}#mermaid-svg-yIJzF4KRhtIxxtp8 .cluster-label span{color:#333;}#mermaid-svg-yIJzF4KRhtIxxtp8 .cluster-label span p{background-color:transparent;}#mermaid-svg-yIJzF4KRhtIxxtp8 .label text,#mermaid-svg-yIJzF4KRhtIxxtp8 span{fill:#333;color:#333;}#mermaid-svg-yIJzF4KRhtIxxtp8 .node rect,#mermaid-svg-yIJzF4KRhtIxxtp8 .node circle,#mermaid-svg-yIJzF4KRhtIxxtp8 .node ellipse,#mermaid-svg-yIJzF4KRhtIxxtp8 .node polygon,#mermaid-svg-yIJzF4KRhtIxxtp8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yIJzF4KRhtIxxtp8 .rough-node .label text,#mermaid-svg-yIJzF4KRhtIxxtp8 .node .label text,#mermaid-svg-yIJzF4KRhtIxxtp8 .image-shape .label,#mermaid-svg-yIJzF4KRhtIxxtp8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-yIJzF4KRhtIxxtp8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yIJzF4KRhtIxxtp8 .rough-node .label,#mermaid-svg-yIJzF4KRhtIxxtp8 .node .label,#mermaid-svg-yIJzF4KRhtIxxtp8 .image-shape .label,#mermaid-svg-yIJzF4KRhtIxxtp8 .icon-shape .label{text-align:center;}#mermaid-svg-yIJzF4KRhtIxxtp8 .node.clickable{cursor:pointer;}#mermaid-svg-yIJzF4KRhtIxxtp8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yIJzF4KRhtIxxtp8 .arrowheadPath{fill:#333333;}#mermaid-svg-yIJzF4KRhtIxxtp8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yIJzF4KRhtIxxtp8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yIJzF4KRhtIxxtp8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yIJzF4KRhtIxxtp8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yIJzF4KRhtIxxtp8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yIJzF4KRhtIxxtp8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yIJzF4KRhtIxxtp8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yIJzF4KRhtIxxtp8 .cluster text{fill:#333;}#mermaid-svg-yIJzF4KRhtIxxtp8 .cluster span{color:#333;}#mermaid-svg-yIJzF4KRhtIxxtp8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yIJzF4KRhtIxxtp8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yIJzF4KRhtIxxtp8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-yIJzF4KRhtIxxtp8 .icon-shape,#mermaid-svg-yIJzF4KRhtIxxtp8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yIJzF4KRhtIxxtp8 .icon-shape p,#mermaid-svg-yIJzF4KRhtIxxtp8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yIJzF4KRhtIxxtp8 .icon-shape .label rect,#mermaid-svg-yIJzF4KRhtIxxtp8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yIJzF4KRhtIxxtp8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yIJzF4KRhtIxxtp8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yIJzF4KRhtIxxtp8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} search(group_ids=A,B,C)
@handle_multiple_group_ids
clone driver -> graph A
clone driver -> graph B
clone driver -> graph C
query A
query B
query C
merge results
关键点:
不在共享 Driver 上粗暴修改当前 database,而是 clone,以避免并发读的状态污染。
第26章 graphiti_core 每个模块源码地图
本章按"文件 → 职责 → 关键调用关系"建立可查表。
26.1 根目录文件
graphiti_core/__init__.py
职责:
- 包入口;
- 对外导出常用符号。
调用关系:
text
Application import
↓
graphiti_core
↓
Graphiti / types / public APIs
graphiti_core/graphiti.py
项目总编排器。
关键内容:
Graphitiadd_episodeadd_episode_bulkadd_tripletretrieve_episodesbuild_communitiessearchsearch_get_nodes_and_edges_by_episode- episode/saga summary 与维护相关辅助方法
_extract_and_resolve_nodes_extract_and_resolve_edges_process_episode_data
上游:
text
Python Application
FastAPI
MCP Server
下游:
text
maintenance/*
search/*
driver/*
llm_client/*
embedder/*
cross_encoder/*
nodes.py / edges.py
graphiti_core/nodes.py
定义核心节点 Model:
NodeEpisodicNodeEntityNodeCommunityNodeSagaNodeEpisodeType
还保留部分数据库访问兼容接口。
上游:
text
graphiti.py
maintenance/*
namespaces/*
search/*
下游:
text
Embedder
Driver / DB query layer
graphiti_core/edges.py
定义核心 Edge Model:
EdgeEntityEdgeEpisodicEdgeCommunityEdgeHasEpisodeEdgeNextEpisodeEdge
重要方法:
- EntityEdge embedding;
- save/get/delete 等兼容数据访问方法。
graphiti_core/graphiti_types.py
集中定义 Graphiti 层公共类型。
其中重要的是:
text
GraphitiClients
用于捆绑:
- Driver;
- LLM;
- Embedder;
- CrossEncoder;
- Tracer。
graphiti_core/graph_queries.py
集中放图数据库通用查询/索引/约束相关 Query 定义或辅助。
它属于:
数据库 Query 基础设施层,而不是 Agent 业务逻辑层。
读 Driver 时会频繁遇到。
graphiti_core/decorators.py
重要 decorator:
text
handle_multiple_group_ids
处理某些 Driver 的 group/database 分发与结果合并。
graphiti_core/helpers.py
通用高频 helper:
- 并发控制;
- semaphore gather;
- 输入/时间辅助;
- resolution 工具;
- 其他跨模块公用函数。
它属于"高扇出依赖"文件:
很多核心模块都会 import 它。
graphiti_core/errors.py
定义 Graphiti 核心异常类型。
目的:
- 不让上层直接依赖 Provider 原始异常;
- 对业务错误提供统一语义。
graphiti_core/tracer.py
定义:
- Tracer ABC
- Span ABC
- NoOp 实现
- OpenTelemetry 适配实现
被:
text
Graphiti
LLMClient
Search
调用。
graphiti_core/py.typed
PEP 561 标记文件。
含义:
告诉 Python 类型检查器:这个包发布时提供类型信息。
它不是运行时代码。
26.2 cross_encoder/
text
cross_encoder/
├─ __init__.py
├─ client.py
├─ bge_reranker_client.py
├─ gemini_reranker_client.py
└─ openai_reranker_client.py
client.py
定义:
text
CrossEncoderClient.rank(query, passages)
抽象契约。
bge_reranker_client.py
BGE Reranker 实现。
用于:
text
Query + Candidate
↓
BGE reranking model
↓
score
gemini_reranker_client.py
Gemini-backed reranking 实现。
openai_reranker_client.py
OpenAI-backed reranking 实现。
__init__.py
对外导出。
调用者主要是:
text
search/search.py
26.3 embedder/
text
embedder/
├─ __init__.py
├─ client.py
├─ openai.py
├─ azure_openai.py
├─ gemini.py
└─ voyage.py
client.py
定义 Embedder ABC:
text
create(text)
create_batch(texts)
以及 embedding dimension 配置。
openai.py
OpenAI Embedding Provider。
azure_openai.py
Azure OpenAI Embedding Provider。
gemini.py
Gemini Embedding Provider。
voyage.py
Voyage Embedding Provider。
调用者:
text
EntityNode.generate_name_embedding
EntityEdge.generate_embedding
node_operations
edge_operations
search
community building
26.4 llm_client/
text
llm_client/
├─ __init__.py
├─ client.py
├─ config.py
├─ cache.py
├─ errors.py
├─ utils.py
├─ token_tracker.py
├─ openai_base_client.py
├─ openai_client.py
├─ openai_generic_client.py
├─ azure_openai_client.py
├─ anthropic_client.py
├─ gemini_client.py
├─ groq_client.py
└─ gliner2_client.py
client.py
LLM 抽象与公共 orchestration:
generate_response- structured response schema
- retry
- cache
- tracing
- token tracking
是整个 LLM 层最值得先读的文件。
config.py
模型配置:
- model;
- small model;
- temperature;
- token limit;
- Provider 相关配置。
cache.py
LLM 响应 cache。
作用:
相同 Prompt/输入在调试、评测、重复处理时减少 API 请求。
errors.py
LLM-specific exception。
utils.py
Provider/LLM 共享工具。
token_tracker.py
记录 token usage,帮助:
- 成本统计;
- tracing;
- 性能分析。
openai_base_client.py
OpenAI 协议族的公共底层实现。
openai_client.py
官方 OpenAI Provider 适配。
openai_generic_client.py
兼容 OpenAI API 风格的第三方服务。
azure_openai_client.py
Azure OpenAI 适配。
anthropic_client.py
Anthropic 适配。
gemini_client.py
Google Gemini 适配。
groq_client.py
Groq 适配。
gliner2_client.py
GLiNER2-backed extraction client。
它更偏向信息抽取场景,可作为某些 LLM extraction 任务的替代/专用实现。
26.5 prompts/
text
prompts/
├─ __init__.py
├─ lib.py
├─ models.py
├─ prompt_helpers.py
├─ snippets.py
├─ extract_nodes.py
├─ extract_edges.py
├─ extract_nodes_and_edges.py
├─ dedupe_nodes.py
├─ dedupe_edges.py
├─ summarize_nodes.py
├─ summarize_sagas.py
└─ eval.py
lib.py
定义/装配 PromptLibrary。
它是 Prompt 总入口。
models.py
定义 Prompt structured output 使用的数据模型。
prompt_helpers.py
Prompt 构造辅助函数。
snippets.py
跨 Prompt 复用的提示片段。
extract_nodes.py
Entity extraction Prompt。
extract_edges.py
Relationship/Fact extraction Prompt。
extract_nodes_and_edges.py
Combined extraction Prompt。
dedupe_nodes.py
Entity deduplication/disambiguation Prompt。
dedupe_edges.py
Fact dedup / edge resolution / contradiction 判断相关 Prompt。
summarize_nodes.py
Entity summary Prompt。
summarize_sagas.py
Saga summary Prompt。
eval.py
评测/判断相关 Prompt。
26.6 search/
text
search/
├─ __init__.py
├─ search.py
├─ search_config.py
├─ search_config_recipes.py
├─ search_filters.py
├─ search_helpers.py
└─ search_utils.py
search.py
高级搜索 orchestrator。
重要函数:
text
search
edge_search
node_search
episode_search
community_search
调用:
text
SearchConfig
↓
search_utils primitive retrieval
↓
RRF/MMR/CrossEncoder
search_config.py
定义:
- SearchMethod enum;
- Reranker enum;
- Edge/Node/Episode/Community SearchConfig;
- SearchResults。
search_config_recipes.py
预设搜索方案,例如:
- combined hybrid RRF;
- combined hybrid MMR;
- combined hybrid Cross-Encoder;
- edge hybrid;
- node distance recipe 等。
它让应用不必每次手工搭所有 search config。
search_filters.py
定义过滤条件模型。
典型作用:
text
按 group
按时间
按 labels/types
按其他 graph filter
具体可用字段应以当前版本的 Pydantic 定义为准。
search_helpers.py
搜索编排中的 helper:
- 结果标准化;
- 过滤;
- score/result 组合;
- 其他 search.py 共享逻辑。
search_utils.py
真正的底层检索 primitive 集合。
可将它理解为:
text
search.py = "导演"
search_utils.py = "具体镜头"
其中包含/支撑:
- full-text search;
- vector similarity;
- BFS;
- RRF;
- MMR;
- node distance;
- episode mentions;
- embeddings retrieval;
- mentioned nodes / communities retrieval。
26.7 models/
text
models/
├─ __init__.py
├─ edges/
│ ├─ __init__.py
│ └─ edge_db_queries.py
└─ nodes/
├─ __init__.py
└─ node_db_queries.py
这里的 models 不等于根目录 nodes.py/edges.py。
可以这样理解:
text
nodes.py / edges.py
= Domain Data Models
models/nodes/node_db_queries.py
models/edges/edge_db_queries.py
= 与这些 Model 相关的数据库 Query 辅助
这是历史结构与 Driver 重构并存时很容易误解的地方。
26.8 namespaces/
text
namespaces/
├─ __init__.py
├─ nodes.py
└─ edges.py
nodes.py
实现:
text
NodeNamespace
EntityNodeNamespace
EpisodeNodeNamespace
CommunityNodeNamespace
SagaNodeNamespace
职责:
- 对外提供更清晰 API;
- 在 DB save 前处理 embedding 等横切逻辑;
- 调用对应 Driver Operations。
例如概念链:
text
graphiti.nodes.entity.save(node)
↓
generate name embedding
↓
driver.entity_node_ops.save(node)
edges.py
同理:
text
graphiti.edges.entity.save(edge)
↓
generate fact embedding
↓
driver.entity_edge_ops.save(edge)
26.9 driver/
text
driver/
├─ driver.py
├─ query_executor.py
├─ record_parsers.py
├─ neo4j_driver.py
├─ falkordb_driver.py
├─ neptune_driver.py
├─ kuzu_driver.py
│
├─ operations/
├─ graph_operations/
├─ search_interface/
│
├─ neo4j/
├─ falkordb/
├─ neptune/
└─ kuzu/
driver.py
核心 GraphDriver ABC。
query_executor.py
统一 query execution contract。
record_parsers.py
把数据库返回 record 转换为:
text
EntityNode
EpisodicNode
EntityEdge
...
也就是 Data Mapper 角色。
neo4j_driver.py
Neo4j concrete driver:
- connection;
- session;
- execute query;
- index/constraint;
- transaction;
- operations wiring。
falkordb_driver.py
FalkorDB concrete driver。
neptune_driver.py
AWS Neptune concrete driver。
kuzu_driver.py
Kuzu concrete driver。
26.9.1 driver/operations/
| 文件 | 负责对象 |
|---|---|
entity_node_ops.py |
EntityNode CRUD / query contract |
episode_node_ops.py |
EpisodicNode |
community_node_ops.py |
CommunityNode |
saga_node_ops.py |
SagaNode |
entity_edge_ops.py |
EntityEdge |
episodic_edge_ops.py |
MENTIONS edge |
community_edge_ops.py |
HAS_MEMBER edge |
has_episode_edge_ops.py |
Saga → Episode |
next_episode_edge_ops.py |
Episode → Episode |
search_ops.py |
Search DB operations |
graph_ops.py |
整图级操作 |
graph_utils.py |
Operations 公用 DB helper |
__init__.py |
export |
这些文件主要是 ABC / Contract。
Provider 目录下再给出 concrete implementation。
26.9.2 driver/graph_operations/
包含:
text
graph_operations.py
这是旧式/兼容期的更大粒度 Graph Operations interface。
在 Driver redesign 的迁移阶段仍保留。
26.9.3 driver/search_interface/
包含:
text
search_interface.py
也是旧式搜索 DB interface。
新设计逐步把行为迁到:
text
driver.search_ops
26.9.4 Provider 子目录
driver/neo4j/
Neo4j 专用 operations/query 实现。
driver/falkordb/
FalkorDB 专用实现,并包含:
text
fulltext.py
operations/
driver/neptune/
Neptune 专用 operations。
driver/kuzu/
Kuzu 专用 operations。
这些目录体现:
text
Generic Operations ABC
↓
Provider-specific implementation
26.10 utils/
text
utils/
├─ __init__.py
├─ bulk_utils.py
├─ content_chunking.py
├─ datetime_utils.py
├─ text_utils.py
├─ maintenance/
└─ ontology_utils/
bulk_utils.py
批量写入核心 helper。
典型职责:
text
add_nodes_and_edges_bulk
batch embeddings
bulk persistence orchestration
被:
text
Graphiti._process_episode_data
Graphiti.add_episode_bulk
使用。
content_chunking.py
处理长内容切分。
为什么 Graphiti 仍需要 chunk:
Episode 可以很长,而 LLM context 和 extraction 都有 token 限制。
datetime_utils.py
统一时间 parsing / timezone / UTC 相关工具。
时间型知识图非常依赖这一层的一致性。
text_utils.py
文本标准化、清洗、比较等共享工具。
26.10.1 utils/maintenance/
已在第 22 章详细讲解:
text
attribute_utils.py
combined_extraction.py
community_operations.py
dedup_helpers.py
edge_operations.py
graph_data_operations.py
node_operations.py
它们是知识构建算法核心。
26.10.2 utils/ontology_utils/
当前包括:
text
entity_types_utils.py
用途:
- 处理自定义 Entity schema;
- 类型验证;
- ontology 上下文构建;
- entity type 映射等。
26.11 migrations/
当前目录很轻,包含:
text
__init__.py
它是为 schema/data migration 预留的包结构。
26.12 telemetry/
text
telemetry/
├─ __init__.py
└─ telemetry.py
职责:
- 匿名使用 telemetry;
- PostHog integration;
- capture feature/events。
不要与 tracer.py 的 OpenTelemetry execution tracing 混淆。
第27章 服务、示例、测试与工程目录逐项说明
27.1 examples/
当前示例目录包括:
text
examples/
├─ azure-openai/
├─ data/
├─ ecommerce/
├─ gliner2/
├─ langgraph-agent/
├─ opentelemetry/
├─ podcast/
├─ quickstart/
└─ wizard_of_oz/
quickstart/
最适合第一次跑通:
text
connect DB
→ build indices
→ add episode
→ search
azure-openai/
展示替换:
- LLM Provider;
- Embedding Provider。
gliner2/
展示 GLiNER2 extraction client。
langgraph-agent/
展示 Graphiti 作为 LangGraph Agent memory/context backend 的集成思路。
opentelemetry/
展示 tracing。
ecommerce/
业务数据/电商场景示例。
podcast/
长文本/内容类 ingestion 场景。
wizard_of_oz/
用于更完整的叙事/图构建演示和测试数据场景。
data/
示例数据。
27.2 tests/
主要包括:
text
tests/
├─ cross_encoder/
├─ driver/
├─ embedder/
├─ evals/
├─ llm_client/
├─ utils/
├─ test_add_triplet.py
├─ test_edge_db_queries.py
├─ test_edge_int.py
├─ test_entity_exclusion_int.py
├─ test_graphiti_int.py
├─ test_graphiti_mock.py
├─ test_handle_multiple_group_ids.py
├─ test_node_int.py
├─ test_node_label_security.py
├─ test_text_utils.py
└─ ...
建议读源码时:
代码和测试一起读。
例如:
text
add_triplet()
↔
test_add_triplet.py
可以快速知道开发者认为这个函数的 contract 是什么。
_int 一般代表
integration test,集成测试。
27.3 spec/
当前最关键:
text
driver-operations-redesign.md
它解释了当前源码"为什么同时有两套 DB 访问方式"。
核心目标:
text
Graphiti Client
↓
Namespace Wrapper
↓
Operations ABC
↓
GraphDriver
并希望最终让 data models 更接近纯 Pydantic model。
这个文件非常值得在读 driver/ 前先看。
27.4 .github/
包括:
- workflows;
- issue templates;
- PR template;
- Dependabot;
- scripts;
- secret scanning;
- 自定义 GitHub Action 等。
它不是 runtime 架构,却反映:
- CI;
- security;
- release/quality process。
27.5 signatures/version1/
包含 CLA 相关 JSON。
CLA:
Contributor License Agreement,贡献者许可协议。
属于项目治理,不参与运行。
27.6 images/
README/文档资源:
- 图示;
- GIF;
- SVG;
- 论文/演示相关截图。
不参与 runtime。
27.7 根目录工程文件
pyproject.toml
核心 Python 包配置:
- package metadata;
- Python version;
- dependencies;
- optional dependencies;
- lint/test/tool config。
当前分析基线版本:
text
graphiti-core 0.29.3
Dockerfile
容器化构建。
docker-compose.yml
本地联调多个服务,例如:
text
Graphiti service
+
graph database
Makefile
常用开发任务封装。
第28章 完整函数调用关系总图
下面把"写 + 搜"放在一张图中。
#mermaid-svg-EPCWzamNraVIhftv{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-EPCWzamNraVIhftv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-EPCWzamNraVIhftv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-EPCWzamNraVIhftv .error-icon{fill:#552222;}#mermaid-svg-EPCWzamNraVIhftv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-EPCWzamNraVIhftv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-EPCWzamNraVIhftv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-EPCWzamNraVIhftv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-EPCWzamNraVIhftv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-EPCWzamNraVIhftv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-EPCWzamNraVIhftv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-EPCWzamNraVIhftv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-EPCWzamNraVIhftv .marker.cross{stroke:#333333;}#mermaid-svg-EPCWzamNraVIhftv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-EPCWzamNraVIhftv p{margin:0;}#mermaid-svg-EPCWzamNraVIhftv .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-EPCWzamNraVIhftv .cluster-label text{fill:#333;}#mermaid-svg-EPCWzamNraVIhftv .cluster-label span{color:#333;}#mermaid-svg-EPCWzamNraVIhftv .cluster-label span p{background-color:transparent;}#mermaid-svg-EPCWzamNraVIhftv .label text,#mermaid-svg-EPCWzamNraVIhftv span{fill:#333;color:#333;}#mermaid-svg-EPCWzamNraVIhftv .node rect,#mermaid-svg-EPCWzamNraVIhftv .node circle,#mermaid-svg-EPCWzamNraVIhftv .node ellipse,#mermaid-svg-EPCWzamNraVIhftv .node polygon,#mermaid-svg-EPCWzamNraVIhftv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-EPCWzamNraVIhftv .rough-node .label text,#mermaid-svg-EPCWzamNraVIhftv .node .label text,#mermaid-svg-EPCWzamNraVIhftv .image-shape .label,#mermaid-svg-EPCWzamNraVIhftv .icon-shape .label{text-anchor:middle;}#mermaid-svg-EPCWzamNraVIhftv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-EPCWzamNraVIhftv .rough-node .label,#mermaid-svg-EPCWzamNraVIhftv .node .label,#mermaid-svg-EPCWzamNraVIhftv .image-shape .label,#mermaid-svg-EPCWzamNraVIhftv .icon-shape .label{text-align:center;}#mermaid-svg-EPCWzamNraVIhftv .node.clickable{cursor:pointer;}#mermaid-svg-EPCWzamNraVIhftv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-EPCWzamNraVIhftv .arrowheadPath{fill:#333333;}#mermaid-svg-EPCWzamNraVIhftv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-EPCWzamNraVIhftv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-EPCWzamNraVIhftv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EPCWzamNraVIhftv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-EPCWzamNraVIhftv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EPCWzamNraVIhftv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-EPCWzamNraVIhftv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-EPCWzamNraVIhftv .cluster text{fill:#333;}#mermaid-svg-EPCWzamNraVIhftv .cluster span{color:#333;}#mermaid-svg-EPCWzamNraVIhftv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-EPCWzamNraVIhftv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-EPCWzamNraVIhftv rect.text{fill:none;stroke-width:0;}#mermaid-svg-EPCWzamNraVIhftv .icon-shape,#mermaid-svg-EPCWzamNraVIhftv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EPCWzamNraVIhftv .icon-shape p,#mermaid-svg-EPCWzamNraVIhftv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-EPCWzamNraVIhftv .icon-shape .label rect,#mermaid-svg-EPCWzamNraVIhftv .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EPCWzamNraVIhftv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-EPCWzamNraVIhftv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-EPCWzamNraVIhftv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Persistence
Search Path
AI Providers
Write Path
Application
Graphiti.add_episode
retrieve_episodes
extract_nodes
resolve_extracted_nodes
semantic candidate search
LLM node dedupe
_extract_and_resolve_edges
extract_edges
resolve_edge_pointers
resolve_extracted_edges
extract timestamps
edge dedupe
temporal invalidation
extract_attributes_from_nodes
process_episode_data
build_episodic_edges
add_nodes_and_edges_bulk
Saga / HAS_EPISODE / NEXT_EPISODE
community update
LLMClient.generate_response
Embedder.create/create_batch
CrossEncoder.rank
PromptLibrary
Graphiti.search
search.search
edge_search
node_search
episode_search
community_search
Fulltext / BM25
Cosine
BFS
RRF
MMR
CrossEncoder rerank
Namespaces
Operations
GraphDriver
Neo4j / FalkorDB / Neptune / Kuzu
第29章 如何扩展 Graphiti
Graphiti 的扩展点非常清楚。
29.1 自定义 Entity Type
你的业务可能需要:
text
Person
Project
Device
Reminder
Preference
Location
Product
可以通过 Pydantic schema 定义。
例如概念上:
python
class Preference(BaseModel):
category: str
value: str
confidence: float | None = None
然后交给 Graphiti extraction pipeline。
29.2 自定义 Edge Type
例如"小搭"记忆系统可定义:
text
Person --HAS_PREFERENCE--> Preference
Person --OWNS--> Device
Person --PARTICIPATES_IN--> Project
Reminder --ABOUT--> Entity
Person --LOCATED_IN--> Location
并通过 edge_type_map 约束 source/target。
29.3 自定义 LLM Provider
实现:
text
LLMClient
主要保证:
- messages input;
- structured output;
- error/retry semantics;
- response model compatible。
29.4 自定义 Embedder
实现:
text
EmbedderClient.create
EmbedderClient.create_batch
即可替换成本地/私有向量模型。
29.5 自定义 Reranker
实现:
text
CrossEncoderClient.rank
即可接:
- 本地 BGE;
- 专用 reranker;
- 企业私有模型。
29.6 自定义图数据库
这是最重的扩展。
需要实现:
text
GraphDriver
+
Operations contracts
+
Search Operations
+
record mapping
+
indexes/constraints
+
transaction semantics
建议优先沿新 Operations 架构扩展,不要再复制旧 monolithic interface。
第30章 源码阅读顺序与调试建议
如果你从头读,不建议按文件树从 __init__.py 一个个往下。
建议下面路线。
第一阶段:20 分钟建立模型
先读:
text
README
graphiti_core/nodes.py
graphiti_core/edges.py
回答三个问题:
- 有哪些 Node?
- 有哪些 Edge?
- 时间字段分别是什么?
第二阶段:抓住主写入链
读:
text
graphiti_core/graphiti.py
只追:
text
add_episode()
然后跳到:
text
utils/maintenance/node_operations.py
utils/maintenance/edge_operations.py
utils/bulk_utils.py
此时先不看 Driver 的 Cypher。
第三阶段:理解为什么"不会越记越乱"
重点:
text
resolve_extracted_nodes
resolve_extracted_edges
resolve_extracted_edge
把:
- Entity duplicate;
- Fact duplicate;
- Fact contradiction;
- Temporal invalidation
四件事分清。
第四阶段:完整理解搜索
读:
text
search/search_config.py
search/search_config_recipes.py
search/search.py
search/search_utils.py
建议用一个 Query 打断点,看:
text
query embedding
BM25 candidates
cosine candidates
BFS candidates
RRF result
CrossEncoder result
每阶段候选怎么变化。
第五阶段:最后看 Driver
先读:
text
spec/driver-operations-redesign.md
再读:
text
driver/driver.py
driver/operations/*
namespaces/*
最后才看:
text
neo4j/*
falkordb/*
neptune/*
kuzu/*
这样不会被大量数据库语句淹没。
第六阶段:看 Prompt
重点把 Python 函数与 Prompt 一一对应:
text
extract_nodes -> prompts/extract_nodes.py
extract_edges -> prompts/extract_edges.py
resolve nodes -> prompts/dedupe_nodes.py
resolve edges -> prompts/dedupe_edges.py
summaries -> prompts/summarize_*.py
你会发现:
Graphiti 的"智能行为"是 算法控制流 + Prompt 合约 + 数据模型 三者共同决定的。
第31章 术语与缩写字典
| 术语 | 全称 / 中文 | 在 Graphiti 中的意思 |
|---|---|---|
| Agent | 智能体 | 使用上下文、工具、记忆执行任务的 AI 系统 |
| Context Graph | 上下文图 | 保存 Entity/Fact/Episode/时间/来源的动态图 |
| Temporal Context Graph | 时间上下文图 | 事实有有效期、可被后续事实失效的 Context Graph |
| KG | Knowledge Graph,知识图谱 | Entity + Relationship 图结构 |
| Episode | 事件/片段 | 一次原始输入或发生过的事件 |
| Entity | 实体 | 人、组织、设备、地点、项目等对象 |
| Fact | 事实 | 两实体之间带自然语言描述和时间的关系 |
| Provenance | 溯源 | 知识来源于哪些 Episode |
| Ontology | 本体/领域模式 | 允许有哪些实体/关系/属性 |
| Prescribed Ontology | 预定义本体 | 开发者明确指定 schema |
| Learned Ontology | 学习出的本体 | 系统从数据中发现/形成结构 |
| LLM | Large Language Model | 大语言模型 |
| NER | Named Entity Recognition | 命名实体识别 |
| Embedding | 向量嵌入 | 把文本映射到稠密向量 |
| Vector Search | 向量检索 | 根据 embedding 相似度召回 |
| Cosine Similarity | 余弦相似度 | 比较向量方向相似程度 |
| Full-text Search | 全文检索 | 按词项/倒排索引搜索 |
| BM25 | Best Matching 25 | 经典全文相关度算法 |
| BFS | Breadth-First Search | 广度优先图遍历 |
| RRF | Reciprocal Rank Fusion | 倒数排名融合 |
| MMR | Maximal Marginal Relevance | 相关性与多样性平衡的重排 |
| Cross-Encoder | 交叉编码器 | Query 和 Candidate 联合编码评分 |
| Reranker | 重排器 | 对召回候选进行二次排序 |
| RAG | Retrieval-Augmented Generation | 检索增强生成 |
| Driver | 驱动/适配层 | 屏蔽不同图数据库实现 |
| Provider | 提供方 | OpenAI/Gemini/Neo4j 等具体实现 |
| Namespace | 命名空间 API | 按 Node/Edge 类型组织数据访问 API |
| Operations | 操作契约 | 每种图对象的 CRUD/Search 抽象接口 |
| ABC | Abstract Base Class | Python 抽象基类 |
| IoC | Inversion of Control | 通过注入实现替换 Provider |
| DTO | Data Transfer Object | API 层请求/响应对象 |
| UUID | Universally Unique Identifier | 全局唯一标识 |
| MCP | Model Context Protocol | Agent/LLM 工具与上下文连接协议 |
| OTEL | OpenTelemetry | 分布式 tracing/observability 标准 |
| AOSS | Amazon OpenSearch Serverless | AWS Serverless OpenSearch 服务 |
| Pydantic | Python 数据模型库 | schema、验证、structured output |
| Cypher | 图查询语言 | Neo4j/FalkorDB 等常用图查询语法 |
| CRUD | Create/Read/Update/Delete | 增删改查 |
| async/await | 异步语法 | 并行调用 LLM、Embedding、DB |
| Semaphore | 信号量 | 控制并发上限 |
| Dedupe | Deduplication | 去重 |
| Entity Resolution | 实体解析/消歧 | 判断两个名字是否同一真实实体 |
| Fact Resolution | 事实解析 | 判断新事实与已有事实的关系 |
group_id |
分组 ID | 数据隔离/图分区的重要 key |
| Saga | 连续事件链 | 有顺序的一组 Episodes |
| MENTIONS | 提及边 | Episode → Entity |
| RELATES_TO | 实体关系边 | Entity → Entity,载体是 EntityEdge |
| HAS_MEMBER | 社区成员边 | Community → Entity |
| HAS_EPISODE | Saga 包含事件 | Saga → Episode |
| NEXT_EPISODE | 下一事件 | Episode → Episode |
reference_time |
参考时间 | Episode 对事实时间解析的锚点 |
valid_at |
生效时间 | Fact 开始为真 |
invalid_at |
失效业务时间 | Fact 停止为真 |
expired_at |
系统发现失效时间 | Graphiti 判断旧事实被新事实替代的时间 |
created_at |
创建时间 | 数据进入 Graphiti 的系统时间 |
第32章 最终总结:把 Graphiti 看成什么最准确
如果只用一句话概括:
Graphiti = 一个以 Episode 为输入、以 Entity/Temporal Fact 为长期知识表示、以 Graph + Vector + Full-text 为存储检索基础、以 LLM 做抽取/消歧/时间理解、以 Hybrid Retrieval + Reranker 对外提供上下文的动态 Agent Memory Engine。
最关键的不是其中任何一个单点技术,而是它们的组合。
#mermaid-svg-OoDPMe48ugzlqP6v{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-OoDPMe48ugzlqP6v .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-OoDPMe48ugzlqP6v .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-OoDPMe48ugzlqP6v .error-icon{fill:#552222;}#mermaid-svg-OoDPMe48ugzlqP6v .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OoDPMe48ugzlqP6v .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-OoDPMe48ugzlqP6v .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OoDPMe48ugzlqP6v .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OoDPMe48ugzlqP6v .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-OoDPMe48ugzlqP6v .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OoDPMe48ugzlqP6v .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OoDPMe48ugzlqP6v .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OoDPMe48ugzlqP6v .marker.cross{stroke:#333333;}#mermaid-svg-OoDPMe48ugzlqP6v svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OoDPMe48ugzlqP6v p{margin:0;}#mermaid-svg-OoDPMe48ugzlqP6v .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-OoDPMe48ugzlqP6v .cluster-label text{fill:#333;}#mermaid-svg-OoDPMe48ugzlqP6v .cluster-label span{color:#333;}#mermaid-svg-OoDPMe48ugzlqP6v .cluster-label span p{background-color:transparent;}#mermaid-svg-OoDPMe48ugzlqP6v .label text,#mermaid-svg-OoDPMe48ugzlqP6v span{fill:#333;color:#333;}#mermaid-svg-OoDPMe48ugzlqP6v .node rect,#mermaid-svg-OoDPMe48ugzlqP6v .node circle,#mermaid-svg-OoDPMe48ugzlqP6v .node ellipse,#mermaid-svg-OoDPMe48ugzlqP6v .node polygon,#mermaid-svg-OoDPMe48ugzlqP6v .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-OoDPMe48ugzlqP6v .rough-node .label text,#mermaid-svg-OoDPMe48ugzlqP6v .node .label text,#mermaid-svg-OoDPMe48ugzlqP6v .image-shape .label,#mermaid-svg-OoDPMe48ugzlqP6v .icon-shape .label{text-anchor:middle;}#mermaid-svg-OoDPMe48ugzlqP6v .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-OoDPMe48ugzlqP6v .rough-node .label,#mermaid-svg-OoDPMe48ugzlqP6v .node .label,#mermaid-svg-OoDPMe48ugzlqP6v .image-shape .label,#mermaid-svg-OoDPMe48ugzlqP6v .icon-shape .label{text-align:center;}#mermaid-svg-OoDPMe48ugzlqP6v .node.clickable{cursor:pointer;}#mermaid-svg-OoDPMe48ugzlqP6v .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-OoDPMe48ugzlqP6v .arrowheadPath{fill:#333333;}#mermaid-svg-OoDPMe48ugzlqP6v .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-OoDPMe48ugzlqP6v .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-OoDPMe48ugzlqP6v .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OoDPMe48ugzlqP6v .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-OoDPMe48ugzlqP6v .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OoDPMe48ugzlqP6v .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-OoDPMe48ugzlqP6v .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-OoDPMe48ugzlqP6v .cluster text{fill:#333;}#mermaid-svg-OoDPMe48ugzlqP6v .cluster span{color:#333;}#mermaid-svg-OoDPMe48ugzlqP6v div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-OoDPMe48ugzlqP6v .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-OoDPMe48ugzlqP6v rect.text{fill:none;stroke-width:0;}#mermaid-svg-OoDPMe48ugzlqP6v .icon-shape,#mermaid-svg-OoDPMe48ugzlqP6v .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OoDPMe48ugzlqP6v .icon-shape p,#mermaid-svg-OoDPMe48ugzlqP6v .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-OoDPMe48ugzlqP6v .icon-shape .label rect,#mermaid-svg-OoDPMe48ugzlqP6v .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OoDPMe48ugzlqP6v .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-OoDPMe48ugzlqP6v .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-OoDPMe48ugzlqP6v :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Episode
发生了什么
LLM Extraction
有哪些实体/事实
Resolution
是不是已经知道
Temporal
什么时候为真
Provenance
从哪里得知
Graph
与什么有关
Search
现在该召回什么
Agent Context
从工程视角看,Graphiti 最值得学习的 5 个设计点是:
- Episode-first:不只存最终知识,也保存知识来源。
- Entity/Fact Resolution:写入前主动消歧和去重,而不是任由知识图膨胀。
- Temporal invalidation:新事实不会粗暴覆盖旧事实,而是维护有效时间。
- Hybrid Retrieval:BM25、向量和图遍历各做自己擅长的事,再统一重排。
- Provider abstraction:LLM、Embedding、Reranker、Graph DB 都通过接口替换。
如果把它用于长期陪伴型 Agent,最值得复用的不是"Graphiti 这个库本身"四个字,而是下面这套记忆思想:
text
原始事件层
↓
结构化事实层
↓
实体消歧层
↓
时间生命周期层
↓
来源追踪层
↓
多路召回层
↓
高精度重排层
↓
Agent Working Context
这正是一个可长期演进的 Agent 记忆系统所需要的骨架。
附录 A:核心源码路径速查
text
graphiti_core/
├─ graphiti.py # 总编排器
├─ nodes.py # 节点模型
├─ edges.py # 边模型
├─ graphiti_types.py # 公共类型 / GraphitiClients
├─ helpers.py # 通用工具
├─ decorators.py # 多 group 等 decorator
├─ graph_queries.py # 图查询基础
├─ errors.py # 核心异常
├─ tracer.py # tracing
│
├─ utils/
│ ├─ bulk_utils.py # 批量持久化
│ ├─ content_chunking.py # 内容切分
│ ├─ datetime_utils.py # 时间工具
│ ├─ text_utils.py # 文本工具
│ ├─ maintenance/
│ │ ├─ node_operations.py # 节点抽取/去重
│ │ ├─ edge_operations.py # 边抽取/去重/失效
│ │ ├─ combined_extraction.py # 节点+边联合抽取
│ │ ├─ community_operations.py # Community
│ │ ├─ dedup_helpers.py # 去重 helper
│ │ ├─ attribute_utils.py # 属性处理
│ │ └─ graph_data_operations.py # 图数据维护
│ └─ ontology_utils/
│ └─ entity_types_utils.py # Entity ontology
│
├─ search/
│ ├─ search.py # 搜索编排
│ ├─ search_utils.py # 底层搜索 primitive
│ ├─ search_config.py # 搜索配置类型
│ ├─ search_config_recipes.py # 预设搜索配方
│ ├─ search_filters.py # 过滤
│ └─ search_helpers.py # 搜索 helper
│
├─ llm_client/
│ ├─ client.py # LLM ABC + orchestration
│ ├─ openai_base_client.py
│ ├─ openai_client.py
│ ├─ openai_generic_client.py
│ ├─ azure_openai_client.py
│ ├─ anthropic_client.py
│ ├─ gemini_client.py
│ ├─ groq_client.py
│ ├─ gliner2_client.py
│ ├─ config.py
│ ├─ cache.py
│ ├─ token_tracker.py
│ ├─ utils.py
│ └─ errors.py
│
├─ embedder/
│ ├─ client.py
│ ├─ openai.py
│ ├─ azure_openai.py
│ ├─ gemini.py
│ └─ voyage.py
│
├─ cross_encoder/
│ ├─ client.py
│ ├─ bge_reranker_client.py
│ ├─ gemini_reranker_client.py
│ └─ openai_reranker_client.py
│
├─ prompts/
│ ├─ lib.py
│ ├─ models.py
│ ├─ prompt_helpers.py
│ ├─ snippets.py
│ ├─ extract_nodes.py
│ ├─ extract_edges.py
│ ├─ extract_nodes_and_edges.py
│ ├─ dedupe_nodes.py
│ ├─ dedupe_edges.py
│ ├─ summarize_nodes.py
│ ├─ summarize_sagas.py
│ └─ eval.py
│
├─ namespaces/
│ ├─ nodes.py
│ └─ edges.py
│
├─ driver/
│ ├─ driver.py
│ ├─ query_executor.py
│ ├─ record_parsers.py
│ ├─ neo4j_driver.py
│ ├─ falkordb_driver.py
│ ├─ neptune_driver.py
│ ├─ kuzu_driver.py
│ ├─ operations/
│ ├─ graph_operations/
│ ├─ search_interface/
│ ├─ neo4j/
│ ├─ falkordb/
│ ├─ neptune/
│ └─ kuzu/
│
├─ models/
│ ├─ nodes/node_db_queries.py
│ └─ edges/edge_db_queries.py
│
├─ telemetry/
│ └─ telemetry.py
└─ migrations/
附录 B:核心 API 到源码入口映射
| 你想研究的问题 | 从这里开始 |
|---|---|
| 一条记忆怎么写进去 | Graphiti.add_episode() |
| 实体怎么抽 | maintenance/node_operations.py::extract_nodes |
| 同名实体怎么去重 | resolve_extracted_nodes |
| 关系怎么抽 | maintenance/edge_operations.py::extract_edges |
| Fact 怎么去重 | resolve_extracted_edges / resolve_extracted_edge |
| 旧 Fact 怎么失效 | edge_operations.py temporal invalidation 逻辑 |
| 时间怎么抽 | _extract_edge_timestamps |
| Episode 与实体怎么连 | build_episodic_edges |
| 数据怎么批量入库 | utils/bulk_utils.py |
| Query 怎么搜索 | search/search.py::search |
| Edge 怎么搜 | edge_search |
| Node 怎么搜 | node_search |
| BM25/Vector/BFS 在哪 | search/search_utils.py + Driver Search Ops |
| Search recipe 在哪 | search/search_config_recipes.py |
| Graph DB 怎么抽象 | driver/driver.py |
| 新 DB API 架构 | namespaces/* + driver/operations/* |
| 为什么新旧 DB API 共存 | spec/driver-operations-redesign.md |
| Prompt 在哪 | prompts/* |
| LLM retry/cache 在哪 | llm_client/client.py |
| Embedding 在哪 | embedder/* |
| Reranker 在哪 | cross_encoder/* |
| Community 怎么建 | maintenance/community_operations.py |
| Saga 怎么组织 | graphiti.py + SagaNode + saga edge ops |
| FastAPI 在哪 | server/graph_service/* |
| MCP 在哪 | mcp_server/src/* |
| tracing 在哪 | tracer.py |
| 匿名 telemetry 在哪 | telemetry/telemetry.py |
附录 C:建议实际调试的 6 个断点
如果你用 VS Code 调 Graphiti,建议先放:
text
1. Graphiti.add_episode()
2. extract_nodes()
3. resolve_extracted_nodes()
4. resolve_extracted_edges()
5. _process_episode_data()
6. search/search.py::edge_search()
观察以下变量:
text
previous_episodes
extracted_nodes
resolved_nodes
uuid_map
extracted_edges
resolved_edges
invalidated_edges
new_edges
query_vector
search candidates
reranker scores
只要这几个变量看明白,Graphiti 80% 的核心机制就真正吃透了。
附录 D:源码参考
仓库:
text
https://github.com/getzep/graphiti
建议重点打开:
text
graphiti_core/graphiti.py
graphiti_core/nodes.py
graphiti_core/edges.py
graphiti_core/utils/maintenance/node_operations.py
graphiti_core/utils/maintenance/edge_operations.py
graphiti_core/search/search.py
graphiti_core/search/search_config.py
graphiti_core/search/search_config_recipes.py
graphiti_core/driver/driver.py
graphiti_core/namespaces/nodes.py
graphiti_core/namespaces/edges.py
graphiti_core/llm_client/client.py
graphiti_core/prompts/lib.py
spec/driver-operations-redesign.md
由于
main分支会持续变化,阅读时优先以"函数名 + 文件路径"定位,不建议长期依赖固定 GitHub 行号。