第 3 章 · 社区与社区报告:图的分层归纳
这章讲什么: GraphRAG 区别于普通 RAG 的核心资产,是把知识图切成一层层"社区"、再给每个社区预先写好一份摘要报告。本章讲 Leiden 分层聚类怎么把图切成树状社区(
create_communities),以及社区报告怎么自底向上滚动生成(create_community_reports)。
3.1 为什么要"社区"
回到最初那个痛点:全局问题("这批文档整体在讲什么")的答案不在任何单个文本块里。GraphRAG 的解法是:既然实体图上"联系紧密的一撮实体"往往对应一个主题,那就把图切成一撮一撮(社区),每撮写一份摘要——全局问题就变成"读这些摘要再汇总"。
"联系紧密的一撮节点"在图论里叫社区检测。GraphRAG 用的是 Leiden 算法(一种社区检测算法,能把图划分成模块度高的簇),而且用它的分层版本,得到一棵社区树。
3.2 分层 Leiden:把图切成一棵社区树
怎么读这张图:level 0 是最粗的大社区,往下每层把大社区再切成更小的子社区,形成父子树;每个实体在每一层都属于某个社区。
level 0: [ 社区 C0 ........................... ] (整张图/最大连通块粗分)
│ 细分
level 1: [ C0-a ] [ C0-b ] [ C0-c ] ... (每个再切小)
│
level 2: [C0-a-1][C0-a-2] ... (继续切,直到够小)
聚类入口 cluster_graph(packages/graphrag/graphrag/index/operations/cluster_graph.py)的处理链:
- 归一化 + 去重边:把每条边的 (source,target) 排序成无向对、去掉反向重复(
_compute_leiden_communities里lo/hi+drop_duplicates)。 - 可选取最大连通块:
use_lcc为真时只保留最大连通子图(stable_lcc),丢掉零散孤岛。 - 跑分层 Leiden:
hierarchical_leiden(edge_list, max_cluster_size, random_seed)(packages/graphrag/graphrag/graphs/hierarchical_leiden.py),受max_cluster_size约束——一个社区太大就继续往下切一层,这正是"分层"的来源。 - 整理成 (level, cluster, parent, nodes) 四元组返回。
create_communities(packages/graphrag/graphrag/index/workflows/create_communities.py)拿到聚类结果后,做几件"填表"的事:给每个社区聚合它的 entity_ids;只聚合社区内部的边(source 和 target 同属一个社区,见 intra = with_both[community_x == community_y])当 relationship_ids;用 parent/children 把树的双向指针建好。产物是 communities 表(列见 data_model/schemas.py(COMMUNITIES_FINAL_COLUMNS))。
可复现性:
seed会透传给 Leiden(random_seed=seed),配上stable_lcc的"stable",让聚类结果在同输入下可复现——对"想每次跑出一样的图"很关键。
3.3 社区报告:自底向上滚动生成(最妙的一步)
有了社区树,就要给每个社区写一份摘 要报告。天真做法是"把社区里所有实体+关系描述喂给 LLM",但上层大社区的原料会远超上下文窗口。GraphRAG 的解法是自底向上、逐层滚动:
最底层社区 (叶子):原料 = 自己的实体 + 关系 + (可选)claims 描述
│ LLM 各写一份报告
▼
上一层社区:原料够小就同上;
原料太大(超 max_input_length)就【改用其子社区已写好的报告】当输入
│ LLM 写报告
▼
... 一直滚到 level 0,每个社区都有一份报告
主循环在 summarize_communities(packages/graphrag/graphrag/index/operations/summarize_communities/summarize_communities.py):它按 get_levels 从底层到高层遍历,对每层用 level_context_builder(即 build_level_context)拼这一层每个社区的上下文——关键就在 这里:当某社区的"本地上下文"(自己的实体/边)放不下时,build_level_context 会用下层已生成的报告替代,从而把信息"压缩着往上带"。
# 示意,非源码。对应 summarize_communities 的分层循环骨架
for level in levels: # 从底层往上
level_context = build_level_context(
pd.DataFrame(reports), # 已经写好的下层报告
community_hierarchy_df=...,
local_context_df=local_contexts, # 每个社区的"本地"实体/边上下文
level=level, max_context_tokens=max_input_length)
local_reports = await derive_from_rows(level_context, run_generate, ...) # 并发写报告
reports.extend(local_reports) # 累积,供更上层复用
为什么这样最省又不丢信息(精华): 底层报告已经把"一小撮实体讲了什么"浓缩好了;上层直接拿下层报告当积木,就不必把成千上万条原始描述再塞一次——用"报告的报告"逼近"全体原料的摘要",既不爆上下文、又保留了层级信息。这也正是 global search 能"读几百份报告答全局"的前提。
3.4 一份社区报告长什么样
单个社区的报告由 CommunityReportsExtractor(packages/graphrag/graphrag/index/operations/summarize_communities/community_reports_extractor.py)用 JSON 模式生成,结构化字段(CommunityReportResponse):
| 字段 | 含义 |
|---|---|
title | 这个社区的主题名 |
summary | 一段总摘要 |
findings | 若干"发现",每条含 summary + explanation(详述 + 依据) |
rating | 该社区"重要性/影响力"评分(浮点) |
rating_explanation | 评分理由 |
_get_text_output 会把这些拼成一份 Markdown 全文(full_content),既存结构化 JSON 也存拼好的文本,两种形态查询期都用得上。最后 finalize_community_reports 把报告接回社区元信息,产出 community_reports 表(列见 COMMUNITY_REPORTS_FINAL_COLUMNS:含 summary, full_content, rating, findings, full_content_json, size 等)。
那个 rating(重要性评分)不是摆设:global search 排序、动态社区选择都会用它当"这个社区值不值得读"的信号(见第 04 章)。
3.5 代码地图
| 主题 | 文件路径 | 符号名 |
|---|---|---|
| 聚类算子(去重/LCC/Leiden) | packages/graphrag/graphrag/index/operations/cluster_graph.py | cluster_graph,_compute_leiden_communities |
| 分层 Leiden 实现 | packages/graphrag/graphrag/graphs/hierarchical_leiden.py | hierarchical_leiden |
| 最大连通块 | packages/graphrag/graphrag/graphs/stable_lcc.py | stable_lcc |
| 建社区表 | packages/graphrag/graphrag/index/workflows/create_communities.py | create_communities |
| 社区报告 workflow | packages/graphrag/graphrag/index/workflows/create_community_reports.py | create_community_reports |
| 自底向上滚动摘要 | packages/graphrag/graphrag/index/operations/summarize_communities/summarize_communities.py | summarize_communities |
| 分层上下文(报告代原料) | .../summarize_communities/graph_context/context_builder.py | build_level_context,build_local_context |
| 单份报告生成(JSON 结构) | .../summarize_communities/community_reports_extractor.py | CommunityReportsExtractor,CommunityReportResponse |
| 社区/报告列定义 | packages/graphrag/graphrag/data_model/schemas.py | COMMUNITIES_FINAL_COLUMNS,COMMUNITY_REPORTS_FINAL_COLUMNS |