Coverage for src/local_deep_research/advanced_search_system/questions/flexible_browsecomp_question.py: 98%

28 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-22 21:20 +0000

1""" 

2Flexible BrowseComp question generator with less prescriptive instructions. 

3 

4Inherits from BrowseComp but gives the LLM more freedom in search strategy. 

5""" 

6 

7from typing import Dict, List 

8 

9from ...utilities.json_utils import get_llm_response_text 

10from .browsecomp_question import BrowseCompQuestionGenerator 

11from ...utilities.llm_utils import invoke_llm_sync 

12 

13 

14class FlexibleBrowseCompQuestionGenerator(BrowseCompQuestionGenerator): 

15 """ 

16 BrowseComp variant with simplified, less prescriptive prompts. 

17 

18 Gives the LLM more freedom to explore different search strategies 

19 instead of strict entity-combination rules. 

20 """ 

21 

22 def _generate_progressive_searches( 

23 self, 

24 query: str, 

25 current_knowledge: str, 

26 entities: Dict[str, List[str]], 

27 questions_by_iteration: dict, 

28 results_by_iteration: dict, 

29 num_questions: int, 

30 iteration: int, 

31 ) -> List[str]: 

32 """Generate searches with more freedom and less rigid instructions.""" 

33 

34 # Check if recent searches are failing 

35 recent_iterations = list(range(max(1, iteration - 5), iteration)) 

36 zero_count = sum( 

37 1 for i in recent_iterations if results_by_iteration.get(i, 1) == 0 

38 ) 

39 searches_failing = zero_count >= 3 

40 

41 # Simpler strategy hint 

42 if searches_failing: 

43 hint = "Recent searches returned 0 results. Try broader, simpler queries." 

44 else: 

45 hint = "Continue exploring to answer the query." 

46 

47 # Much simpler prompt - less prescriptive 

48 prompt = f"""Generate {num_questions} new search queries for: {query} 

49 

50{hint} 

51 

52Available terms: {", ".join(entities["names"] + entities["temporal"] + entities["descriptors"])} 

53 

54Previous searches with results: 

55{self._format_previous_searches(questions_by_iteration, results_by_iteration)} 

56 

57Current findings: 

58{current_knowledge[: self.knowledge_truncate_length] if self.knowledge_truncate_length else current_knowledge} 

59 

60Create {num_questions} diverse search queries. Avoid exact duplicates. One per line. 

61""" 

62 

63 response = invoke_llm_sync(self.model, prompt) 

64 content = get_llm_response_text(response) 

65 

66 # Extract searches 

67 searches = [] 

68 for line in content.strip().split("\n"): 

69 line = line.strip() 

70 if line and not line.endswith(":") and len(line) > 5: 

71 for prefix in [ 

72 "Q:", 

73 "Search:", 

74 "-", 

75 "*", 

76 "•", 

77 "1.", 

78 "2.", 

79 "3.", 

80 "4.", 

81 "5.", 

82 ]: 

83 if line.startswith(prefix): 

84 line = line[len(prefix) :].strip() 

85 if line: 85 ↛ 68line 85 didn't jump to line 68 because the condition on line 85 was always true

86 searches.append(line) 

87 

88 # If not enough, fall back to parent's logic 

89 if len(searches) < num_questions: 

90 parent_searches = super()._generate_progressive_searches( 

91 query, 

92 current_knowledge, 

93 entities, 

94 questions_by_iteration, 

95 results_by_iteration, 

96 num_questions - len(searches), 

97 iteration, 

98 ) 

99 searches.extend(parent_searches) 

100 

101 return searches[:num_questions]