You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Reranking strategies are selected by string name and dispatched through a hardcoded if/elif chain in the processors. In lexical-graph/src/graphrag_toolkit/lexical_graph/retrieval/processors/rerank_statements.py:250-258:
rerank_topics.py repeats the same pattern for topic_reranker ('none' | 'tfidf' | 'bedrock').
Consequences:
Every new strategy requires a change to toolkit source. Adding Bedrock support ([FEATURE] Add reranker fallback chains to statement reranking #406) meant adding a _score_values_with_bedrock method plus a new branch plus validation of the new name — the same cost for Cohere, a SageMaker endpoint, a cross-encoder, or any customer-specific business logic.
The dispatch method is a poor extension surface. Provider wiring lives inline in the processor (rerank_statements.py:157-206 constructs the boto3 client, builds the ARN, and shapes the request/response in the middle of the processor), so each addition grows a class whose job is reranking statements, not talking to providers.
Users with proprietary or domain-specific ranking logic have no supported option other than forking, monkey-patching the processor, or reranking outside the retrieval pipeline — which loses the entity-context enrichment and max_statements truncation the processors apply.
RerankerMixin already exists but isn't the extension point for this path. retrieval/post_processors/reranker_mixin.py defines batch_size and rerank_pairs(pairs, batch_size), and SentenceReranker/BGEReranker implement it — but the only consumer is the deprecated retrievers/deprecated/rerank_beam_search.py. The statement/topic processors never consult it, so a user implementing RerankerMixin today does not get picked up by the current pipeline.
The fallback chain work in [FEATURE] Add reranker fallback chains to statement reranking #406 multiplies the cost. Chains (reranker=['bedrock', 'tfidf']) plus reranker_fallback_policy make the set of names something users will want to compose, and each element of a chain is still limited to a name the toolkit ships.
Proposed solution
Introduce a first-class reranker interface and accept instances of it wherever a reranker name is accepted today.
Define a scorer-shaped protocol/ABC that matches what the processors actually need, e.g.:
Returning a {value: score} map keeps it drop-in compatible with the existing scored_values contract (rerank_statements.py:270-295).
Reconcile with the existing RerankerMixin: either extend/adapt it so rerank_pairs-style implementations are usable from the processors, or clearly scope the two (node post-processor vs. statement scorer) and document which to implement. Decide whether the deprecated beam-search consumer keeps its own path.
Allow ProcessorArgs.reranker / topic_reranker to accept an instance (or list of instances, for [FEATURE] Add reranker fallback chains to statement reranking #406-style chains) in addition to the current string names — built-in names resolve to built-in implementations through a small registry so the dispatch chain disappears.
Extract the built-in strategies (tfidf, model, bedrock) into implementations of the new interface so the built-ins and user-supplied rerankers travel the same code path — this is also what proves the interface is sufficient.
Should the interface cover statement and topic reranking with one type, or two? Both currently need query + values → scores, but topics carry pre-existing scores.
Naming/registry: is a plain Dict[str, Callable] registry enough, or should custom names be registrable so config-driven setups can reference them by string?
Backward compatibility: all existing string values must keep working unchanged.
Acceptance criteria
A documented public interface for custom rerankers, exported from a stable module path.
Package
lexical-graph
Problem statement
Reranking strategies are selected by string name and dispatched through a hardcoded if/elif chain in the processors. In lexical-graph/src/graphrag_toolkit/lexical_graph/retrieval/processors/rerank_statements.py:250-258:
rerank_topics.pyrepeats the same pattern for topic_reranker ('none' | 'tfidf' | 'bedrock').Consequences:
Proposed solution
Introduce a first-class reranker interface and accept instances of it wherever a reranker name is accepted today.
{value: score}map keeps it drop-in compatible with the existing scored_values contract (rerank_statements.py:270-295).RerankerMixin: either extend/adapt it so rerank_pairs-style implementations are usable from the processors, or clearly scope the two (node post-processor vs. statement scorer) and document which to implement. Decide whether the deprecated beam-search consumer keeps its own path.ProcessorArgs.reranker/topic_rerankerto accept an instance (or list of instances, for [FEATURE] Add reranker fallback chains to statement reranking #406-style chains) in addition to the current string names — built-in names resolve to built-in implementations through a small registry so the dispatch chain disappears.tfidf,model,bedrock) into implementations of the new interface so the built-ins and user-supplied rerankers travel the same code path — this is also what proves the interface is sufficient.Considerations / open questions
Acceptance criteria
Related
Alternatives considered
No response