Skip to content

Commit fd12bb8

Browse files
committed
fix(p0-2): address critical review feedback for PR #544
**Critical Issue #1 (P0)**: Remove duplicate reranking from SearchService - Removed _apply_reranking() calls at lines 683-688 (CoT path) - Removed _apply_reranking() calls at lines 926-931 (regular path) - Removed get_reranker() method (lines 172-237) - Removed _apply_reranking() method (lines 238-270) - Removed _reranker field from __init__ - Added explanatory comments that reranking moved to PipelineService **Issue #2 (P1)**: Inconsistent reranker initialization - Fixed by removing duplicate code from SearchService - PipelineService is now the single source of truth for reranking **Issue #4 (P2)**: Type annotations - Added BaseReranker import to pipeline_service.py - Changed _reranker type from 'Any | None' to 'BaseReranker | None' - Changed get_reranker() return type from 'Any' to 'BaseReranker | None' **Issue #5 (P2)**: Logging clarity - Improved logging in _apply_reranking() to show before/after counts - New log format: 'Reranking reduced results from X to Y documents (top_k=Z)' - Makes performance monitoring easier All changes preserve functionality while eliminating code duplication and improving type safety. Reranking now happens ONLY in PipelineService, BEFORE LLM generation (not after).
1 parent 26991c4 commit fd12bb8

File tree

2 files changed

+16
-120
lines changed

2 files changed

+16
-120
lines changed

backend/rag_solution/services/pipeline_service.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from rag_solution.query_rewriting.query_rewriter import QueryRewriter
2020
from rag_solution.repository.pipeline_repository import PipelineConfigRepository
2121
from rag_solution.retrieval.factories import RetrieverFactory
22+
from rag_solution.retrieval.reranker import BaseReranker
2223
from rag_solution.retrieval.retriever import BaseRetriever
2324
from rag_solution.schemas.llm_parameters_schema import LLMParametersInput
2425
from rag_solution.schemas.pipeline_schema import (
@@ -72,7 +73,7 @@ def __init__(self: Any, db: Session, settings: Settings) -> None:
7273
# Lazy initialized components
7374
self._document_store: DocumentStore | None = None
7475
self._retriever: BaseRetriever | None = None
75-
self._reranker: Any | None = None # Lazy init reranker
76+
self._reranker: BaseReranker | None = None # Lazy init reranker
7677

7778
# Property-based lazy initialization
7879
@property
@@ -138,7 +139,7 @@ def retriever(self) -> BaseRetriever:
138139
self._retriever = RetrieverFactory.create_retriever({}, self.document_store)
139140
return self._retriever
140141

141-
def get_reranker(self, user_id: UUID4) -> Any:
142+
def get_reranker(self, user_id: UUID4) -> BaseReranker | None:
142143
"""Get or create reranker instance for the given user.
143144
144145
Args:
@@ -226,13 +227,18 @@ def _apply_reranking(
226227
logger.debug("Reranking disabled, returning original results")
227228
return results
228229

229-
logger.info("Applying reranking to %d results", len(results))
230+
original_count = len(results)
230231
reranked_results = reranker.rerank(
231232
query=query,
232233
results=results,
233234
top_k=self.settings.reranker_top_k,
234235
)
235-
logger.info("Reranking complete, returned %d results", len(reranked_results))
236+
logger.info(
237+
"Reranking reduced results from %d to %d documents (top_k=%d)",
238+
original_count,
239+
len(reranked_results),
240+
self.settings.reranker_top_k or len(results),
241+
)
236242
return reranked_results
237243

238244
except Exception as e: # pylint: disable=broad-exception-caught

backend/rag_solution/services/search_service.py

Lines changed: 6 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def __init__(self, db: Session, settings: Settings) -> None:
7979
self._llm_provider_service: LLMProviderService | None = None
8080
self._chain_of_thought_service: Any | None = None
8181
self._token_tracking_service: TokenTrackingService | None = None
82-
self._reranker: Any | None = None
82+
# Note: Reranking moved to PipelineService (P0-2 fix)
8383

8484
@property
8585
def file_service(self) -> FileManagementService:
@@ -169,106 +169,9 @@ def token_tracking_service(self) -> TokenTrackingService:
169169
self._token_tracking_service = TokenTrackingService(self.db, self.settings)
170170
return self._token_tracking_service
171171

172-
def get_reranker(self, user_id: UUID4) -> Any:
173-
"""Get or create reranker instance for the given user.
174-
175-
Args:
176-
user_id: User UUID for creating LLM-based reranker
177-
178-
Returns:
179-
Reranker instance (LLMReranker or SimpleReranker)
180-
"""
181-
if not self.settings.enable_reranking:
182-
return None
183-
184-
if self._reranker is None:
185-
logger.debug("Lazy initializing reranker")
186-
# pylint: disable=import-outside-toplevel
187-
# Justification: Lazy import to avoid circular dependency with reranker and services
188-
from rag_solution.retrieval.reranker import LLMReranker, SimpleReranker
189-
from rag_solution.services.prompt_template_service import PromptTemplateService
190-
191-
if self.settings.reranker_type == "llm":
192-
try:
193-
# Get LLM provider
194-
provider_config = self.llm_provider_service.get_default_provider()
195-
if not provider_config:
196-
logger.warning("No LLM provider found, using simple reranker")
197-
self._reranker = SimpleReranker()
198-
return self._reranker
199-
200-
# pylint: disable=import-outside-toplevel
201-
# Justification: Lazy import to avoid circular dependency with LLMProviderFactory
202-
from rag_solution.generation.providers.factory import LLMProviderFactory
203-
204-
factory = LLMProviderFactory(self.db)
205-
llm_provider = factory.get_provider(provider_config.name)
206-
207-
# Get reranking prompt template
208-
prompt_service = PromptTemplateService(self.db)
209-
try:
210-
# pylint: disable=import-outside-toplevel
211-
# Justification: Lazy import to avoid circular dependency with schema types
212-
from rag_solution.schemas.prompt_template_schema import PromptTemplateType
213-
214-
template = prompt_service.get_by_type(user_id, PromptTemplateType.RERANKING)
215-
except Exception as e: # pylint: disable=broad-exception-caught
216-
# Justification: Fallback to simple reranker if template loading fails
217-
logger.warning("Could not load reranking template: %s, using simple reranker", e)
218-
self._reranker = SimpleReranker()
219-
return self._reranker
220-
221-
self._reranker = LLMReranker(
222-
llm_provider=llm_provider,
223-
user_id=user_id,
224-
prompt_template=template,
225-
batch_size=self.settings.reranker_batch_size,
226-
score_scale=self.settings.reranker_score_scale,
227-
)
228-
logger.debug("LLM reranker initialized successfully")
229-
except Exception as e: # pylint: disable=broad-exception-caught
230-
# Justification: Fallback to simple reranker for any initialization error
231-
logger.warning("Failed to initialize LLM reranker: %s, using simple reranker", e)
232-
self._reranker = SimpleReranker()
233-
else:
234-
self._reranker = SimpleReranker()
235-
logger.debug("Simple reranker initialized")
236-
237-
return self._reranker
238-
239-
def _apply_reranking(self, query: str, results: list[QueryResult], user_id: UUID4) -> list[QueryResult]:
240-
"""Apply reranking to search results if enabled.
241-
242-
Args:
243-
query: The search query
244-
results: List of QueryResult objects from retrieval
245-
user_id: User UUID
246-
247-
Returns:
248-
Reranked list of QueryResult objects (or original if reranking disabled/failed)
249-
"""
250-
if not self.settings.enable_reranking or not results:
251-
return results
252-
253-
try:
254-
reranker = self.get_reranker(user_id)
255-
if reranker is None:
256-
logger.debug("Reranking disabled, returning original results")
257-
return results
258-
259-
logger.info("Applying reranking to %d results", len(results))
260-
reranked_results = reranker.rerank(
261-
query=query,
262-
results=results,
263-
top_k=self.settings.reranker_top_k,
264-
)
265-
logger.info("Reranking complete, returned %d results", len(reranked_results))
266-
return reranked_results
267-
268-
except Exception as e: # pylint: disable=broad-exception-caught
269-
# Justification: Fallback to original results for any reranking failure
270-
logger.warning("Reranking failed: %s, returning original results", e)
271-
return results
172+
# Note: Reranking methods removed - now handled by PipelineService (P0-2 fix)
173+
# - get_reranker() moved to PipelineService
174+
# - _apply_reranking() moved to PipelineService
272175

273176
def _should_use_chain_of_thought(self, search_input: SearchInput) -> bool:
274177
"""Automatically determine if Chain of Thought should be used for this search.
@@ -679,13 +582,7 @@ async def search(self, search_input: SearchInput) -> SearchOutput:
679582
# Fall through to regular search
680583
else:
681584
logger.info("🔍 SEARCH SERVICE: Pipeline SUCCESS, proceeding with CoT")
682-
# Apply reranking to retrieved results before CoT
683-
if pipeline_result.query_results:
684-
pipeline_result.query_results = self._apply_reranking(
685-
query=search_input.question,
686-
results=pipeline_result.query_results,
687-
user_id=search_input.user_id,
688-
)
585+
# Note: Reranking now happens INSIDE pipeline (before LLM generation)
689586
# Convert to CoT input with document context
690587
try:
691588
logger.debug("Converting to CoT input")
@@ -922,14 +819,7 @@ async def search(self, search_input: SearchInput) -> SearchOutput:
922819
logger.error("Pipeline execution failed: %s", pipeline_result.error)
923820
raise ConfigurationError(pipeline_result.error or "Pipeline execution failed")
924821

925-
# Apply reranking to retrieved results
926-
if pipeline_result.query_results:
927-
pipeline_result.query_results = self._apply_reranking(
928-
query=search_input.question,
929-
results=pipeline_result.query_results,
930-
user_id=search_input.user_id,
931-
)
932-
822+
# Note: Reranking now happens INSIDE pipeline (before LLM generation)
933823
# Generate metadata
934824
try:
935825
logger.debug("Generating document metadata for regular search")

0 commit comments

Comments
 (0)