[Bug]: Community report context seems to keep only one edge per node

オープン
#2,583 コメント 3 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 5 日以内に返信

@nightcityblade がすでに取り組んでいます。

2026年10月1日 から。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
73/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
pandas, python
領域
data

調査の方向性

Start in summarize_communities/graph_context/context_builder.py, especially _prepare_reports_at_level and the source/target edge aggregation described in the issue. Run the provided triangle-graph reproduction and inspect the context string; done means all three edges are retained before the token budget is applied, with relevant tests passing.

索引モデルが issue の本文から書いたものです。

説明

bug triage
Do you need to file an issue?
  • I have searched the existing issues and this bug is not already filed.
  • My model is hosted on OpenAI or Azure. If not, please look at the "model providers" issue and don't file a new one here.
  • I believe this is a legitimate bug, not just a question. If this is a question, please use the Discussions area.
Describe the bug

Hi! I may be missing something, but it looks like _prepare_reports_at_level keeps only one edge per node when it builds the report context...

In 3.2.0 (and on main), edges are grouped by source and by target keeping only the first one, and the two results are then merged with combine_first:

# 3.2.0, summarize_communities/graph_context/context_builder.py, on lines 101-125
source_edges = (
    level_edge_df
    .groupby(schemas.EDGE_SOURCE)
    .agg({schemas.EDGE_DETAILS: "first"})
    ...
)
target_edges = (
    level_edge_df
    .groupby(schemas.EDGE_TARGET)
    .agg({schemas.EDGE_DETAILS: "first"})
    ...
)
...
merged_node_df.loc[:, schemas.EDGE_DETAILS] = merged_node_df.loc[
    :, f"{schemas.EDGE_DETAILS}_x"
].combine_first(merged_node_df.loc[:, f"{schemas.EDGE_DETAILS}_y"])

So an edge that is not the first of any node gets dropped, whatever the token budget. Let's see a small exaple, a triangle graph like A->B, A->C and C->B:

import pandas as pd
import graphrag.data_model.schemas as s
from graphrag.index.operations.summarize_communities.graph_context.context_builder import _prepare_reports_at_level

class Tok:
    def encode(self, t): return t.split()
    def num_tokens(self, t): return len(t.split())

nodes = pd.DataFrame({s.TITLE: list("ABC"), s.SHORT_ID: [0, 1, 2], s.DESCRIPTION: ["x"] * 3,
                      s.NODE_DEGREE: [2] * 3, s.COMMUNITY_ID: [0] * 3, s.COMMUNITY_LEVEL: [0] * 3})
nodes[s.NODE_DETAILS] = nodes[[s.SHORT_ID, s.TITLE, s.DESCRIPTION, s.NODE_DEGREE]].to_dict(orient="records")
edges = pd.DataFrame({s.EDGE_SOURCE: list("AAC"), s.EDGE_TARGET: list("BCB"),
                      s.SHORT_ID: [0, 1, 2], s.DESCRIPTION: ["e"] * 3, s.EDGE_DEGREE: [4] * 3})
edges[s.EDGE_DETAILS] = edges[[s.SHORT_ID, s.EDGE_SOURCE, s.EDGE_TARGET, s.DESCRIPTION, s.EDGE_DEGREE]].to_dict(orient="records")

print(_prepare_reports_at_level(nodes, edges, None, Tok(), 0, 10**9).iloc[0][s.CONTEXT_STRING])

Only A->B and C->B are printed. A keeps A->B, C keeps C->B, and B (with no outgoing edges) keeps its first incoming one, A->B again... so A->C is lost.

It caught my attention that up to 0.5.0 this part was different. Every edge was attached to both of its nodes and aggregated into a list, so nothing was dropped before the budget was applied:

# 0.5.0, summarize_communities/prepare_community_reports.py, lines 92-107
# concat all edge details per node
merged_node_df = pd.concat(
    [
        get_edge_details(level_node_df, level_edge_df, edge_source_column),
        get_edge_details(level_node_df, level_edge_df, edge_target_column),
    ],
    axis=0,
)
merged_node_df = (
    merged_node_df.groupby([...])
    .agg({node_details_column: "first", edge_details_column: list})
    .reset_index()
)

The current version appears in 0.9.0 and hasn't changed since. The comment above it still says "aggregate into lists", and in issue 1850 a maintainer said that leaf-level reports include all intra-community edges, so I think the change was unintended. Something like this seems to bring back the 0.5.0 behavior, since the rest of the function already handles lists and sort_context removes duplicates and applies the budget:

source_edges = level_edge_df.loc[:, [schemas.EDGE_SOURCE, schemas.EDGE_DETAILS]].rename(
    columns={schemas.EDGE_SOURCE: schemas.TITLE}
)
target_edges = level_edge_df.loc[:, [schemas.EDGE_TARGET, schemas.EDGE_DETAILS]].rename(
    columns={schemas.EDGE_TARGET: schemas.TITLE}
)
merged_node_df = level_node_df.merge(
    pd.concat([source_edges, target_edges]), on=schemas.TITLE, how="left"
)

Tested with GraphRAG 3.2.0, Python 3.12 on Linux.

It's very possible I'm missing some logic behind this, so apologies if that's the case. Thanks a lot in advance!

Steps to reproduce

No response

Expected Behavior

No response

GraphRAG Config Used
# Paste your config here

Logs and screenshots

No response

Additional Information
  • GraphRAG Version: 3.2.0
  • Operating System: Ubuntu 20.04
  • Python Version: 3.12
  • Related Issues: #1850
主要言語
Python
スター
36.6k
フォーク
3.9k
平均マージ
4日 11時間
マージ済み PR(30日)
1

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

microsoft/graphrag のほかの issue

microsoft/graphrag の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。