1010from urllib .parse import quote
1111
1212from .engine .hybrid_search import BM25 , reciprocal_rank_fusion
13- from .engine .quality_gate import SearchQualityGate , SearchMetaLearner , compute_search_confidence
13+ from .engine .quality_gate import (
14+ SearchQualityGate ,
15+ SearchMetaLearner ,
16+ compute_search_confidence ,
17+ )
1418
1519logger = logging .getLogger (__name__ )
1620
@@ -100,18 +104,13 @@ def _resolve_fused_docs(
100104 def _run_hybrid_rerank (
101105 self , store_name : str , query : str , semantic_results : List
102106 ) -> Tuple [List [Dict [str , Any ]], float ]:
103- """BM25 + ChronosGrid semantic -> RRF -> resolved docs + confidence score.
104-
105- Returns:
106- (resolved_docs, confidence) where confidence is rank-divergence-gated [0, 1].
107- """
107+ """BM25 + ChronosGrid semantic -> RRF -> resolved docs + confidence score."""
108108 if store_name not in self ._bm25_indices or store_name in self ._bm25_dirty :
109109 self ._rebuild_bm25 (store_name )
110110
111111 # alpha->0 (keyword-dominant): expand BM25 pool; alpha->1: contract it.
112112 alpha = (getattr (self , "_meta_alpha" , {})).get (store_name , 0.5 )
113- bm25_multiplier = max (0.5 , 1.5 - alpha ) # alpha=0.2->1.3x, 0.5->1.0x, 0.8->0.7x
114- bm25_top_k = max (1 , int (self .config .max_sources * 2 * bm25_multiplier ))
113+ bm25_top_k = int (self .config .max_sources * 2 * max (0.5 , 1.5 - alpha ))
115114
116115 bm25_ranked = self ._collect_bm25_ranked (store_name , query , bm25_top_k )
117116 sem_ranked = self ._collect_sem_ranked (store_name , semantic_results )
@@ -120,11 +119,10 @@ def _run_hybrid_rerank(
120119 [sem_ranked , bm25_ranked ], k = 60 , top_k = self .config .max_sources
121120 )
122121
123- bm25_uri_set = {r ["id" ] for r in bm25_ranked }
124- sem_uri_set = {r ["id" ] for r in sem_ranked }
125122 raw_score = fused [0 ]["score" ] if fused else 0.0
126- confidence = compute_search_confidence (raw_score , bm25_uri_set , sem_uri_set )
127-
123+ confidence = compute_search_confidence (
124+ raw_score , {r ["id" ] for r in bm25_ranked }, {r ["id" ] for r in sem_ranked }
125+ )
128126 return self ._resolve_fused_docs (store_name , fused ), confidence
129127
130128 # ------------------------------------------------------------------
@@ -186,22 +184,28 @@ def _local_search(
186184 }
187185
188186 if not docs :
189- result = {
187+ res = {
190188 "status" : "success" ,
191189 "answer" : "No documents indexed yet." ,
192190 "sources" : [],
193191 ** base ,
194192 }
195193 if search_mode in ["semantic" , "hybrid" , "multimodal" ]:
196- result ["semantic_results" ] = semantic_results or []
197- return result
194+ res ["semantic_results" ] = semantic_results or []
195+ return res
198196
199- quality_gate : SearchQualityGate = getattr (self , "_quality_gate" , SearchQualityGate ())
200- meta_learner : SearchMetaLearner = getattr (self , "_meta_learner" , SearchMetaLearner ())
197+ quality_gate : SearchQualityGate = getattr (
198+ self , "_quality_gate" , SearchQualityGate ()
199+ )
200+ meta_learner : SearchMetaLearner = getattr (
201+ self , "_meta_learner" , SearchMetaLearner ()
202+ )
201203
202204 # Hybrid: BM25 + semantic RRF with quality gate
203205 if search_mode == "hybrid" and semantic_results :
204- fused_docs , confidence = self ._run_hybrid_rerank (store_name , query , semantic_results )
206+ fused_docs , confidence = self ._run_hybrid_rerank (
207+ store_name , query , semantic_results
208+ )
205209 verdict = quality_gate .evaluate (confidence )
206210
207211 if fused_docs :
@@ -270,7 +274,9 @@ def _local_search(
270274 result ["semantic_results" ] = semantic_results or []
271275 return result
272276
273- def _run_meta_adapt (self , store_name : str , meta_learner : "SearchMetaLearner" ) -> None :
277+ def _run_meta_adapt (
278+ self , store_name : str , meta_learner : "SearchMetaLearner"
279+ ) -> None :
274280 """Apply MetaLearner alpha recommendation when adaptation cycle triggers."""
275281 if not meta_learner .should_adapt ():
276282 return
@@ -282,7 +288,10 @@ def _run_meta_adapt(self, store_name: str, meta_learner: "SearchMetaLearner") ->
282288 self ._meta_alpha [store_name ] = new_alpha
283289 logger .info (
284290 "[QualityGate] store=%s alpha %.3f -> %.3f trend=%s" ,
285- store_name , current , new_alpha , meta_learner .store_trend (store_name ),
291+ store_name ,
292+ current ,
293+ new_alpha ,
294+ meta_learner .store_trend (store_name ),
286295 )
287296
288297 # ------------------------------------------------------------------
@@ -313,7 +322,8 @@ def _resolve_semantic_sources(
313322 if not resolved :
314323 return None
315324 snippets = [
316- self ._build_snippet (d .get ("content" , "" ), query ) or d .get ("content" , "" )[:200 ]
325+ self ._build_snippet (d .get ("content" , "" ), query )
326+ or d .get ("content" , "" )[:200 ]
317327 for d in resolved [:5 ]
318328 ]
319329 answer = " " .join (s for s in snippets if s ) or (
0 commit comments