检索与召回系统
搜索与检索系统
相关源文件
以下文件为本 Wiki 页面的上下文来源:
examples/podcast/podcast_runner.pygraphiti_core/prompts/prompt_helpers.pygraphiti_core/search/search.pygraphiti_core/search/search_config.pygraphiti_core/search/search_config_recipes.pygraphiti_core/search/search_filters.pygraphiti_core/search/search_helpers.pygraphiti_core/search/search_utils.pytests/test_graphiti_int.py
目的与范围
本文档介绍 Graphiti 的混合搜索与检索系统,该系统结合了多种搜索方法和重排序策略,能够高效查询时序知识图谱。系统会并发执行 BM25 全文搜索、向量相似度搜索和图遍历方法,然后使用倒数排名融合(RRF)和可选的重排序来融合结果。关于如何从 Graphiti 主客户端调用搜索功能,请参见 Graphiti 核心客户端。关于搜索返回的数据模型详情,请参见 数据模型与模式。
高层架构
搜索系统实现了三阶段管线:(1)在不同范围(节点、边、片段、社区)内并发执行多种搜索方法;(2)使用 RRF 或 MMR 进行结果融合;(3)使用交叉编码器或基于图的指标进行可选的重排序。
搜索流程与代码实体映射
下图将逻辑搜索流程映射到代码库中的具体类和函数。
来源:graphiti_core/search/search.py:98-219, graphiti_core/search/search_utils.py:1-1070, graphiti_core/search/search_config.py:112-119
搜索入口点
主搜索函数是 search(),位于 graphiti_core/search/search.py:98-183。它接受一个查询字符串、可选的组 ID、一个 SearchConfig、SearchFilters,以及用于中心搜索(center_node_uuid)和 BFS 起始节点(bfs_origin_node_uuids)的可选参数。
该函数通过 semaphore_gather() 协调并行搜索操作 graphiti_core/search/search.py:173-219:
| 搜索范围 | 函数 | 用途 |
|---|---|---|
| 边搜索 | edge_search() | 查找匹配查询的关系 graphiti_core/search/search.py:222 |
| 节点搜索 | node_search() | 查找匹配查询的实体 graphiti_core/search/search.py:344 |
| 片段搜索 | episode_search() | 查找匹配查询的片段节点 graphiti_core/search/search.py:452 |
| 社区搜索 | community_search() | 查找匹配查询的社区集群 graphiti_core/search/search.py:511 |
如果任何搜索方法需要向量相似度(余弦相似度或 MMR),系统会自动使用配置的 embedder 生成查询嵌入向量 graphiti_core/search/search.py:120-152。
来源:graphiti_core/search/search.py:98-219, graphiti_core/search/search_utils.py:1-1070
搜索方法
BM25 全文搜索
BM25 利用数据库原生的全文索引。系统通过 fulltext_query() 构建特定于提供商的查询 graphiti_core/search/search_utils.py:85-113。
- Neo4j:使用 Lucene 语法。需要通过
lucene_sanitize进行消毒,以防止语法错误graphiti_core/search/search_utils.py:106-111。 - Kuzu:支持简单的空格分隔查询,且
MAX_QUERY_LENGTH严格限制为 128graphiti_core/search/search_utils.py:88-92。 - FalkorDB:使用通过
driver.build_fulltext_query()构建的 RedisSearch 语法graphiti_core/search/search_utils.py:93-94。
边全文搜索 graphiti_core/search/search_utils.py:185-294 针对 EntityEdge 关系的 fact 属性。 节点全文搜索 graphiti_core/search/search_utils.py:576-666 针对 EntityNode 的 name 和 summary 属性。
来源:graphiti_core/search/search_utils.py:85-113, graphiti_core/search/search_utils.py:185-294, graphiti_core/search/search_utils.py:576-666
向量相似度搜索
向量搜索执行查询嵌入向量与存储嵌入向量之间的余弦相似度比较。
- 节点相似度:搜索
name_embeddinggraphiti_core/search/search_utils.py:669-793。 - 边相似度:搜索
fact_embeddinggraphiti_core/search/search_utils.py:297-442。
实现方式因 GraphProvider 而异:
- Neo4j/FalkorDB:在 Cypher 中使用原生向量相似度查询。
- Kuzu:需要显式类型转换:
CAST($search_vector AS FLOAT[1536])graphiti_core/search/search_utils.py:365-373。 - Neptune:使用 Amazon OpenSearch Serverless(AOSS)进行向量索引,通过
driver.run_aoss_query实现graphiti_core/search/search_utils.py:326-340。
来源:graphiti_core/search/search_utils.py:297-442, graphiti_core/search/search_utils.py:669-793, graphiti_core/search/search_utils.py:365-373
图广度优先搜索(BFS)
BFS 遍历从特定节点开始探索图结构。
- 边 BFS:遍历
RELATES_TO路径,深度不超过bfs_max_depthgraphiti_core/search/search_utils.py:445-573。 - 节点 BFS:检索遍历范围内的所有实体
graphiti_core/search/search_utils.py:796-877。
在 node_search() 中,如果未提供起始节点,系统会执行"两遍"搜索:首先通过 BM25/相似度查找节点,然后将这些节点作为 BFS 的起始点,查找相关上下文 graphiti_core/search/search.py:393-405。
来源:graphiti_core/search/search_utils.py:445-573, graphiti_core/search/search_utils.py:796-877, graphiti_core/search/search.py:393-405
结果融合与重排序
倒数排名融合(RRF)
RRF 通过将排名的倒数相加,将多个排名列表合并为一个排名。它是混合搜索的默认融合策略。 实现位置:graphiti_core/search/search_utils.py:903-928。
最大边际相关性(MMR)
MMR 在相关性与多样性之间取得平衡,以避免检索上下文中出现冗余结果。它使用 search_vector 和候选结果的嵌入向量,对与已选项目过于相似的项目进行惩罚。 实现位置:graphiti_core/search/search_utils.py:931-984。
交叉编码器重排序
交叉编码器通过将查询和文档文本一起输入模型,对候选结果进行高精度重新评分。这种方法计算成本更高,但比仅使用嵌入向量的搜索更准确。
- 边重排序:
graphiti_core/search/search.py:304-310 - 节点重排序:
graphiti_core/search/search.py:425-434
专用重排序器
- 节点距离:根据结果到
center_node_uuid的最短路径距离进行排名graphiti_core/search/search_utils.py:987-1030。 - 片段提及:根据实体或边出现在多少个不同片段中进行排名
graphiti_core/search/search_utils.py:1033-1070。
来源:graphiti_core/search/search_utils.py:903-1070, graphiti_core/search/search.py:304-434
搜索过滤器
SearchFilters 类 graphiti_core/search/search_filters.py:55-67 支持复杂的布尔逻辑和时间约束。
过滤逻辑实现
下图展示了 SearchFilters 如何转换为数据库特定的查询组件。
来源:graphiti_core/search/search_filters.py:27-120, graphiti_core/search/search_filters.py:120-262
时间过滤
时间过滤器使用 DateFilter graphiti_core/search/search_filters.py:38-43 对 Graphiti 的双时态模型进行查询:
created_at:按数据入库时间过滤graphiti_core/search/search_filters.py:65。valid_at:按事实在"现实世界"中成立的时间过滤graphiti_core/search/search_filters.py:62。invalid_at:按事实不再成立的时间过滤graphiti_core/search/search_filters.py:63。expired_at:按事实被逻辑删除/取代的时间过滤graphiti_core/search/search_filters.py:65。
属性过滤
PropertyFilter graphiti_core/search/search_filters.py:45-53 允许使用 ComparisonOperator graphiti_core/search/search_filters.py:27-35 中定义的标准比较运算符,对存储在节点或边上的自定义属性进行过滤。
来源:graphiti_core/search/search_filters.py:27-67, graphiti_core/search/search_filters.py:120-262
搜索配置配方
Graphiti 在 search_config_recipes.py 中为常见用例提供了预定义的搜索配方:
| 配方 | 描述 |
|---|---|
COMBINED_HYBRID_SEARCH_RRF | 对所有类型使用 BM25 + 相似度,通过 RRF 融合 graphiti_core/search/search_config_recipes.py:34-53 |
COMBINED_HYBRID_SEARCH_MMR | BM25 + 相似度,通过 MMR 融合以实现多样性 graphiti_core/search/search_config_recipes.py:56-78 |
COMBINED_HYBRID_SEARCH_CROSS_ENCODER | BM25 + 相似度 + BFS,通过交叉编码器重排序 graphiti_core/search/search_config_recipes.py:81-108 |
NODE_HYBRID_SEARCH_RRF | 专门针对节点的混合搜索 graphiti_core/search/search_config_recipes.py:156-161 |
来源:graphiti_core/search/search_config_recipes.py:34-206
搜索结果与上下文
搜索结果以 SearchResults Pydantic 模型返回 graphiti_core/search/search_config.py:121-130。要将这些结果用于大语言模型(LLM)提示,search_results_to_context_string() 辅助函数会将节点、边和社区转换为结构化字符串 graphiti_core/search/search_helpers.py:27-72。
上下文格式化
上下文字符串包括:
- FACTS:带有
valid_at和invalid_at日期的事实关系graphiti_core/search/search_helpers.py:29-36。 - ENTITIES:实体名称及其摘要
graphiti_core/search/search_helpers.py:37-39。 - EPISODES:片段内容和来源描述
graphiti_core/search/search_helpers.py:40-46。 - COMMUNITIES:社区名称和摘要
graphiti_core/search/search_helpers.py:47-50。
格式化过程使用 to_prompt_json graphiti_core/prompts/prompt_helpers.py:23-40 确保数据安全序列化以供大语言模型(LLM)使用,同时保留非 ASCII 字符。
来源:graphiti_core/search/search_config.py:121-130, graphiti_core/search/search_helpers.py:27-72, graphiti_core/prompts/prompt_helpers.py:23-40