Behaviour for community summarization in GraphRAG.
Community summarizers generate natural language descriptions of entity communities. These summaries provide high-level context for global queries that need broad understanding rather than specific document chunks.
Built-in Implementations
Arcana.Graph.CommunitySummarizer.LLM- LLM-based summarization (default)
Configuration
Configure your community summarizer in config.exs:
# Default: LLM-based summarization
config :arcana, :graph,
community_summarizer: {Arcana.Graph.CommunitySummarizer.LLM, llm: &MyApp.llm/3}
# Disable summarization (communities won't have summaries)
config :arcana, :graph,
community_summarizer: nil
# Custom module implementing this behaviour
config :arcana, :graph,
community_summarizer: {MyApp.ExtractiveSum, max_sentences: 3}
# Inline function
config :arcana, :graph,
community_summarizer: fn entities, relationships, _opts ->
{:ok, "Community with #{length(entities)} entities"}
endImplementing a Custom Summarizer
Create a module that implements this behaviour:
defmodule MyApp.ExtractiveSum do
@behaviour Arcana.Graph.CommunitySummarizer
@impl true
def summarize(entities, relationships, opts) do
max_sentences = Keyword.get(opts, :max_sentences, 3)
# Extract key sentences from entity descriptions...
{:ok, summary}
end
endSummary Format
Summarizers should return a concise string (2-5 sentences) that:
- Identifies the community's central theme or domain
- Names the most important entities
- Describes key relationships between entities
Summary
Callbacks
Generates a summary for a community.
Functions
Digest of the entities and relationships a summary was generated from.
The change-count threshold above which a clean summary is regenerated.
Checks if a community needs its summary regenerated.
Returns a map of fields to reset after regenerating a summary.
Generates a summary using the configured summarizer.
Callbacks
@callback summarize( entities :: [map()], relationships :: [map()], opts :: keyword() ) :: {:ok, String.t()} | {:error, term()}
Generates a summary for a community.
Parameters
entities- List of entity maps with:name,:type, and optional:descriptionrelationships- List of relationship maps connecting entitiesopts- Options passed from the summarizer configuration
Returns
{:ok, summary}- The generated summary string{:error, reason}- On failure
Functions
Digest of the entities and relationships a summary was generated from.
Membership alone can't answer "is this summary still accurate?": a summary is written from relationship text too, and ingesting another document adds relationships without moving anyone between communities. Storing this alongside the summary is what makes the question answerable later.
Covers the fields a summarizer is given: entity name, type and description, and relationship type and description. The built-in prompt only renders names and types, so a description edit can cost one redundant call - deliberate, since a custom summarizer is free to read descriptions, and over-refreshing is the safe direction. It never goes the other way.
The change-count threshold above which a clean summary is regenerated.
Exposed so callers that predict what a summarize run will process (the dashboard's hint, for one) can apply the same rule.
Checks if a community needs its summary regenerated.
Regeneration Triggers
dirty: true- Community was modified since last summarychange_count >= threshold- Many changes accumulatedsummary: nil- No summary exists yetsummary_fingerprint: nil- Summary predates fingerprinting, so there is no way to tell whether it still matches the graph. It regenerates once, the run records a fingerprint, and it settles from then on
Options
:threshold- Number of changes before regeneration (default: 10)
Returns a map of fields to reset after regenerating a summary.
Use with Ecto.Changeset.change/2 to mark a community as clean:
community
|> Community.changeset(CommunitySummarizer.reset_change_tracking())
|> Repo.update()
Generates a summary using the configured summarizer.
The summarizer can be:
- A
{module, opts}tuple where module implements this behaviour A function
(entities, relationships, opts) -> {:ok, summary} | {:error, reason}nilto skip summarization (returns empty string)
Falls back to LLM summarizer if not configured but :llm option is provided.