Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions graphrag_sdk/src/graphrag_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@
from graphrag_sdk.retrieval.reranking_strategies.base import RerankingStrategy
from graphrag_sdk.retrieval.reranking_strategies.cosine import CosineReranker
from graphrag_sdk.retrieval.strategies.base import RetrievalStrategy
from graphrag_sdk.retrieval.strategies.cypher_first import (
CypherFirstAggregationStrategy,
DefaultPhraseExtractor,
PhraseExtractor,
)
from graphrag_sdk.retrieval.strategies.multi_path import MultiPathRetrieval

# ── Storage ─────────────────────────────────────────────────────
Expand Down Expand Up @@ -160,7 +165,10 @@
"SemanticResolution",
# Retrieval
"CosineReranker",
"CypherFirstAggregationStrategy",
"DefaultPhraseExtractor",
"MultiPathRetrieval",
"PhraseExtractor",
"RerankingStrategy",
"RetrievalStrategy",
# Storage
Expand Down
44 changes: 44 additions & 0 deletions graphrag_sdk/src/graphrag_sdk/api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,27 @@
"or is NOT true, preserve that meaning."
)

# Optional addendum appended to the system prompt only when the retriever
# produced an "Authoritative Graph Query Results" section (currently emitted
# by ``CypherFirstAggregationStrategy`` and by ``MultiPathRetrieval`` with
# ``enable_cypher=True``). Kept out of the base prompts so callers who never
# use cypher retrieval don't pay the prompt-token cost or risk subtle
# behavior changes on factoid questions.
_CYPHER_AUTH_RULE = (
"\n8. When the context contains a section labeled "
"'Authoritative Graph Query Results', that section is computed "
"deterministically from the knowledge graph. For quantitative or "
"'which has the most/fewest/exactly N' questions, prefer those "
"numbers over prose passages, even if passages mention other "
"entities more frequently."
)

# Marker the retriever uses in section content / metadata to signal that an
# authoritative cypher result is present. Kept as a module-level constant so
# tests can pin the contract.
_CYPHER_RESULTS_SECTION = "cypher_results"
_AUTH_RESULTS_HEADING_MARKER = "Authoritative Graph Query Results"

_RAG_PROMPT = "<context>\n{context}\n</context>\n\nQuestion: {question}\n\nAnswer:"

# Matches a literal ``</context>`` closing tag (case-insensitive, whitespace
Expand All @@ -105,6 +126,23 @@ def _neutralize_context_close_tag(text: str) -> str:
return _CONTEXT_CLOSE_RE.sub("</ context>", text)


def _has_authoritative_cypher_results(retriever_result: RetrieverResult) -> bool:
"""True when any retrieved item is an authoritative graph-query result.

Used to decide whether to append the cypher-authority rule to the
default system prompt. We check both the section metadata (preferred,
cheap) and the heading marker in the content (defensive — covers
third-party strategies that don't tag the metadata).
"""
for item in retriever_result.items or []:
section = (item.metadata or {}).get("section") if item.metadata else None
if section == _CYPHER_RESULTS_SECTION:
return True
if isinstance(item.content, str) and _AUTH_RESULTS_HEADING_MARKER in item.content:
return True
return False


_QUESTION_REWRITE_PROMPT = (
"Given the conversation history, rewrite the user's last question "
"as a standalone question that includes all entity names, dates, "
Expand Down Expand Up @@ -709,6 +747,12 @@ async def completion(
context_str = "\n---\n".join(item.content for item in retriever_result.items)
default_system_content = _RAG_SYSTEM_PROMPT

# Conditionally append the cypher-authority rule. Only fires when the
# retriever produced an authoritative-results section — keeps the base
# system prompt unchanged for callers who don't use cypher retrieval.
if _has_authoritative_cypher_results(retriever_result):
default_system_content = default_system_content + _CYPHER_AUTH_RULE

# Step 4: Build messages — unified path for single-turn and multi-turn.
# If history starts with role="system", honor it as-is (trust the
# consumer). Otherwise inject the SDK's default instructions.
Expand Down
13 changes: 12 additions & 1 deletion graphrag_sdk/src/graphrag_sdk/retrieval/strategies/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
# GraphRAG SDK — Retrieval: Strategies

from graphrag_sdk.retrieval.strategies.base import RetrievalStrategy
from graphrag_sdk.retrieval.strategies.cypher_first import (
CypherFirstAggregationStrategy,
DefaultPhraseExtractor,
PhraseExtractor,
)
from graphrag_sdk.retrieval.strategies.multi_path import MultiPathRetrieval

__all__ = ["RetrievalStrategy", "MultiPathRetrieval"]
__all__ = [
"CypherFirstAggregationStrategy",
"DefaultPhraseExtractor",
"MultiPathRetrieval",
"PhraseExtractor",
"RetrievalStrategy",
]
Loading