Zeggai Abdellah commited on
Commit
a6cedca
·
1 Parent(s): a043019

fix max iterations

Browse files
Files changed (1) hide show
  1. rag_pipeline.py +58 -53
rag_pipeline.py CHANGED
@@ -121,7 +121,7 @@ You provide evidence-based guidance using only information from official vaccine
121
  Answer the doctor's question accurately and concisely using only the provided information.
122
 
123
  ## FALLBACK MODE INSTRUCTIONS
124
- - You have access to only 2 powerful tools: Guide_vector_tool (Algerian National Vaccination Guide) and Immunization_in_Practice_tool (WHO global guidance).
125
  - **MANDATORY TOOL USAGE**: Always use the relevant tool(s) to search for information before answering, even if you initially think no information is available.
126
  - Be direct and efficient - search once with each tool if needed, then provide your answer.
127
  - Do not overthink or search repeatedly - these tools are comprehensive.
@@ -132,7 +132,7 @@ Answer the doctor's question accurately and concisely using only the provided in
132
  1. For each fact in your response, include an inline citation in the format [Source ID] immediately following the information, e.g., [e795ebd28318886c0b1a5395ac30ad90].
133
  2. The Source ID must be the exact alphanumeric identifier from the search results, NOT the tool name or any other text.
134
  3. Do NOT use 'Source:' in the citation format; use only the Source ID in square brackets.
135
- 4. Do NOT use tool names (like Guide_vector_tool, Immunization_in_Practice_tool) as citations.
136
  5. If a fact is supported by multiple sources, use adjacent citations: [e795ebd28318886c0b1a5395ac30ad90][21a932b2340bb16707763f57f0ad2]
137
  6. Use ONLY the provided information from tool outputs and never include facts from your general knowledge.
138
 
@@ -146,20 +146,18 @@ Answer the doctor's question accurately and concisely using only the provided in
146
 
147
  ### CRITICAL: Efficient Fallback Strategy
148
  1. **MANDATORY SEARCH**: Use each relevant tool at least once to search for information, even if you suspect the information might not be available.
149
- 2. **BREAK DOWN COMPLEX QUERIES**: For comparative or multi-part questions (e.g., comparing Algerian and WHO guidelines), break the query into sub-queries and use the appropriate tool for each part:
150
- - Use Guide_vector_tool for Algerian-specific information (e.g., national schedules, coverage targets).
151
- - Use Immunization_in_Practice_tool for WHO-specific information (e.g., global recommendations, coverage targets).
152
  3. **DO NOT STOP PREMATURELY**: Do not conclude "no information is available" without using the relevant tool(s) to search for the answer.
153
  4. **BE DECISIVE**: Once you find relevant information for each sub-query, formulate your response immediately.
154
  5. **ANSWER FULLY**: Address all parts of the question, using multiple tools if required by the query.
 
155
 
156
  ### Response Guidelines
157
  - **MANDATORY TOOL SELECTION**:
158
- - For queries mentioning "WHO," "World Health Organization," "international," "global guidance," or WHO documents (e.g., page numbers), use Immunization_in_Practice_tool first.
159
- - For queries mentioning "Algerian," "national guide," or Algerian-specific terms (e.g., page numbers), use Guide_vector_tool first.
160
- - For comparative queries (e.g., Algerian vs. WHO), use both Guide_vector_tool and Immunization_in_Practice_tool, addressing each part systematically.
161
  - **EXPLICIT REASONING**: Before answering, log your reasoning steps, including which tools you will use and why, based on the query’s content.
162
- - **Query Decomposition**: Break comparative or multi-part queries into sub-queries (e.g., one for Algerian information, one for WHO information) and use the appropriate tool for each.
163
  - Provide all found information with proper citations using Source IDs only.
164
  - If information is limited, clearly state: "Based on the available documents, I can provide the following information..." and indicate what is not available.
165
 
@@ -178,7 +176,7 @@ Answer the doctor's question accurately and concisely using only the provided in
178
  1. For each fact in your response, include an inline citation in the format [Source ID] immediately following the information, e.g., [e795ebd28318886c0b1a5395ac30ad90].
179
  2. The Source ID must be the exact alphanumeric identifier from the search results, NOT the tool name or any other text.
180
  3. Do NOT use 'Source:' in the citation format; use only the Source ID in square brackets.
181
- 4. Do NOT use tool names (like Guide_vector_tool, Immunization_in_Practice_tool) as citations.
182
  5. If a fact is supported by multiple sources, use adjacent citations: [e795ebd28318886c0b1a5395ac30ad90][21a932b2340bb16707763f57f0ad2]
183
  6. Use ONLY the provided information from tool outputs and never include facts from your general knowledge.
184
 
@@ -193,28 +191,23 @@ Answer the doctor's question accurately and concisely using only the provided in
193
  ### CRITICAL: Efficient Response Strategy
194
  1. **MANDATORY SEARCH**: Always use the relevant tool(s) to search for information before answering, even if you initially think no information is available.
195
  2. **MANDATORY TOOL SELECTION**:
196
- - For queries mentioning "WHO," "World Health Organization," "international," "global guidance," or WHO documents (e.g., page numbers), use Immunization_in_Practice_tool first.
197
- - For queries mentioning "Algerian," "national guide," or Algerian-specific terms (e.g., page numbers), use Guide_vector_tool first.
198
- - For comparative queries (e.g., Algerian vs. WHO), use both Guide_vector_tool and Immunization_in_Practice_tool, addressing each part systematically.
199
- 3. **Query Decomposition**: Break comparative or multi-part queries into sub-queries (e.g., one for Algerian information, one for WHO information) and use the appropriate tool for each.
200
  4. **DO NOT STOP PREMATURELY**: Do not conclude "no information is available" without using the relevant tool(s) to search for the answer.
201
- 5. **EXPLICIT REASONING**: Before answering, log your reasoning steps, including which tools you will use and why, based on the query’s content.
202
- 6. **BE DECISIVE**: Once you find relevant information for each sub-query, formulate your response immediately.
203
- 7. **ANSWER FULLY**: Address all parts of the question, using multiple tools if required by the query.
204
- 8. **STOP WHEN SUFFICIENT**: If you have found adequate information to answer all parts of the question, provide the response and stop.
 
 
 
205
 
206
  ### Response Guidelines for Complex Questions
207
- - For comparative questions: Break the query into sub-queries (e.g., Algerian vs. WHO), use Guide_vector_tool for Algerian specifics and Immunization_in_Practice_tool for WHO specifics, then provide the comparison.
208
  - For multi-part questions: Address each part systematically, using the appropriate tool for each sub-query.
209
  - If information is not found after using the relevant tool(s): State clearly: "Based on the available documents, I can provide the following information..." and specify what is not available.
210
- - Do not repeatedly search for the same terms or rephrase searches excessively.
211
-
212
- ### When Information is Limited
213
- If you cannot find complete information to fully answer a question:
214
- 1. Provide whatever relevant information you did find with proper citations using Source IDs only.
215
- 2. Clearly state: "Based on the available documents, I can provide the following information..."
216
- 3. Indicate what specific information is not available: "However, information about [specific topic] was not found in the provided documents after searching with the relevant tool(s)."
217
- 4. Do not conclude "no information is available" without attempting a search with the appropriate tool(s).
218
 
219
  ---
220
  """
@@ -248,7 +241,8 @@ def create_agent(tools, llm, is_fallback=False):
248
  """Create the ReAct agent with custom prompt"""
249
 
250
  agent_type = "FALLBACK" if is_fallback else "STANDARD"
251
- max_iter =10
 
252
 
253
  print(f"[LOG] Creating {agent_type} ReAct agent with {len(tools)} tools and max_iterations={max_iter}")
254
 
@@ -257,7 +251,7 @@ def create_agent(tools, llm, is_fallback=False):
257
  tools,
258
  llm=llm,
259
  verbose=True,
260
- max_iterations=max_iter, # Reduced iterations for fallback agent
261
  )
262
 
263
  # Create and apply safe custom prompt
@@ -274,9 +268,9 @@ def create_agent(tools, llm, is_fallback=False):
274
 
275
 
276
  def create_fallback_tools(all_tools):
277
- """Extract only the guide_retrieval_tool and immunization_tool for fallback agent"""
278
 
279
- print("[LOG] Creating fallback tools (guide + immunization only)")
280
 
281
  fallback_tools = []
282
  tool_names_found = []
@@ -334,7 +328,14 @@ def initialize_rag_pipeline(tools):
334
 
335
 
336
  def detect_max_iterations_error(response_text):
337
- """Detect if the response indicates a max iterations error"""
 
 
 
 
 
 
 
338
 
339
  max_iteration_indicators = [
340
  "max iterations",
@@ -344,11 +345,10 @@ def detect_max_iterations_error(response_text):
344
  "iteration limit"
345
  ]
346
 
347
- response_lower = response_text.lower()
348
-
349
- # Check for max iterations indicators
350
  for indicator in max_iteration_indicators:
351
  if indicator in response_lower:
 
352
  return True
353
 
354
  # Check for very short or empty responses (often indicates failure)
@@ -389,7 +389,7 @@ def process_question(agents_dict, question: str) -> str:
389
 
390
  # Check if we need to use fallback
391
  if detect_max_iterations_error(response_text):
392
- print("[LOG] 🔄 Max iterations detected, switching to FALLBACK AGENT...")
393
 
394
  if fallback_agent is None:
395
  print("[LOG] ❌ Fallback agent not available, returning error message")
@@ -419,7 +419,7 @@ def process_question(agents_dict, question: str) -> str:
419
 
420
  # Check if fallback also failed
421
  if detect_max_iterations_error(fallback_text):
422
- print("[LOG] ❌ Fallback agent also hit max iterations")
423
  return ("I apologize, but I'm having difficulty finding specific information about your question in the available documents. "
424
  "Please try asking a more specific question or rephrasing your query.")
425
 
@@ -501,16 +501,17 @@ def process_question_with_sequential_citations(agents_dict, question: str, chunk
501
  print(f"[LOG] Chunks directory: {chunks_directory}")
502
  start_time = time.time()
503
 
504
- used_fallback = False
505
 
506
  try:
507
  # Get the response using the enhanced process_question function
508
  response_text = process_question(agents_dict, question)
509
 
510
- # Check if this looks like a fallback was used (simple heuristic)
511
- if "fallback" in response_text.lower() or len(response_text) < 50:
 
512
  used_fallback = True
513
- print("[LOG] 🛡️ Fallback agent was likely used")
514
 
515
  agent_time = time.time() - start_time
516
  print(f"[LOG] Agent processing completed in {agent_time:.2f} seconds")
@@ -534,6 +535,10 @@ def process_question_with_sequential_citations(agents_dict, question: str, chunk
534
 
535
  for json_file in min_chunks_files:
536
  json_path = os.path.join(chunks_directory, json_file)
 
 
 
 
537
  print(f"[LOG] Loading {json_file}...")
538
  try:
539
  with open(json_path, "r", encoding="utf-8") as f:
@@ -549,23 +554,23 @@ def process_question_with_sequential_citations(agents_dict, question: str, chunk
549
  print("[LOG] Finding cited elements...")
550
  cited_elements_ordered = []
551
  for i, source_id in enumerate(unique_ids): # This preserves the order
552
- print(f"[LOG] Looking for source ID {i+1}/{len(unique_ids)}: {source_id}")
553
  found = False
554
  for element in all_chunks_data:
 
555
  if element.get("type") == 'TableElement':
556
- if element.get("elements",{}).get("element_id") == source_id:
557
- cited_elements_ordered.append(element.get("elements",{}))
558
  found = True
559
  break
560
- else:
561
- if "elements" in element:
562
- for nested_element in element["elements"]:
563
- if nested_element.get("element_id") == source_id:
564
- cited_elements_ordered.append(nested_element)
565
- found = True
566
- break
567
- else:
568
- continue
569
  break
570
  if not found:
571
  print(f"[LOG] ⚠️ Source ID {source_id} not found in chunks data")
 
121
  Answer the doctor's question accurately and concisely using only the provided information.
122
 
123
  ## FALLBACK MODE INSTRUCTIONS
124
+ - You have access to only 2 powerful tools: general_guide_tool (Algerian National Vaccination Guide) and who_immunization_tool (WHO global guidance).
125
  - **MANDATORY TOOL USAGE**: Always use the relevant tool(s) to search for information before answering, even if you initially think no information is available.
126
  - Be direct and efficient - search once with each tool if needed, then provide your answer.
127
  - Do not overthink or search repeatedly - these tools are comprehensive.
 
132
  1. For each fact in your response, include an inline citation in the format [Source ID] immediately following the information, e.g., [e795ebd28318886c0b1a5395ac30ad90].
133
  2. The Source ID must be the exact alphanumeric identifier from the search results, NOT the tool name or any other text.
134
  3. Do NOT use 'Source:' in the citation format; use only the Source ID in square brackets.
135
+ 4. Do NOT use tool names (like general_guide_tool, who_immunization_tool) as citations.
136
  5. If a fact is supported by multiple sources, use adjacent citations: [e795ebd28318886c0b1a5395ac30ad90][21a932b2340bb16707763f57f0ad2]
137
  6. Use ONLY the provided information from tool outputs and never include facts from your general knowledge.
138
 
 
146
 
147
  ### CRITICAL: Efficient Fallback Strategy
148
  1. **MANDATORY SEARCH**: Use each relevant tool at least once to search for information, even if you suspect the information might not be available.
149
+ 2. **BREAK DOWN COMPLEX QUERIES**: For comparative or multi-part questions (e.g., comparing Algerian and WHO guidelines), break the query into sub-queries and use the appropriate tool for each part.
 
 
150
  3. **DO NOT STOP PREMATURELY**: Do not conclude "no information is available" without using the relevant tool(s) to search for the answer.
151
  4. **BE DECISIVE**: Once you find relevant information for each sub-query, formulate your response immediately.
152
  5. **ANSWER FULLY**: Address all parts of the question, using multiple tools if required by the query.
153
+ 6. **FINAL ANSWER**: Once you have your answer, present it directly. Do not output your internal 'thought' or 'action' steps. Your final output must be the synthesized answer itself.
154
 
155
  ### Response Guidelines
156
  - **MANDATORY TOOL SELECTION**:
157
+ - For queries mentioning "WHO," "World Health Organization," "international," "global guidance," or WHO documents, use who_immunization_tool first.
158
+ - For queries mentioning "Algerian," "national guide," or Algerian-specific terms, use general_guide_tool first.
159
+ - For comparative queries (e.g., Algerian vs. WHO), use both tools, addressing each part systematically.
160
  - **EXPLICIT REASONING**: Before answering, log your reasoning steps, including which tools you will use and why, based on the query’s content.
 
161
  - Provide all found information with proper citations using Source IDs only.
162
  - If information is limited, clearly state: "Based on the available documents, I can provide the following information..." and indicate what is not available.
163
 
 
176
  1. For each fact in your response, include an inline citation in the format [Source ID] immediately following the information, e.g., [e795ebd28318886c0b1a5395ac30ad90].
177
  2. The Source ID must be the exact alphanumeric identifier from the search results, NOT the tool name or any other text.
178
  3. Do NOT use 'Source:' in the citation format; use only the Source ID in square brackets.
179
+ 4. Do NOT use tool names (like general_guide_tool, cold_chain_tool) as citations.
180
  5. If a fact is supported by multiple sources, use adjacent citations: [e795ebd28318886c0b1a5395ac30ad90][21a932b2340bb16707763f57f0ad2]
181
  6. Use ONLY the provided information from tool outputs and never include facts from your general knowledge.
182
 
 
191
  ### CRITICAL: Efficient Response Strategy
192
  1. **MANDATORY SEARCH**: Always use the relevant tool(s) to search for information before answering, even if you initially think no information is available.
193
  2. **MANDATORY TOOL SELECTION**:
194
+ - For queries about global standards or WHO, use who_immunization_tool.
195
+ - For broad questions about the Algerian guide, use general_guide_tool.
196
+ - For specific topics like cold chain, disease info, etc., use the most specific tool (e.g., cold_chain_tool, disease_info_tool).
197
+ 3. **Query Decomposition**: Break comparative or multi-part queries into sub-queries and use the appropriate tool for each.
198
  4. **DO NOT STOP PREMATURELY**: Do not conclude "no information is available" without using the relevant tool(s) to search for the answer.
199
+ 5. **EXPLICIT REASONING**: Before answering, log your reasoning steps, including which tools you will use and why.
200
+ 6. **BE DECISIVE**: Once you find relevant information, formulate your response.
201
+
202
+ ### Final Answer Generation
203
+ - **STOP WHEN SUFFICIENT**: Once you have gathered enough information from the tools to answer the user's question completely, you MUST stop using tools and formulate a final answer.
204
+ - **SYNTHESIZE THE ANSWER**: Formulate a comprehensive, final answer based ONLY on the observed tool outputs.
205
+ - **PRESENT CLEANLY**: Present this final answer directly to the user. Your final output must be the answer itself, not your internal 'thought' or 'action' steps.
206
 
207
  ### Response Guidelines for Complex Questions
208
+ - For comparative questions: Break the query into sub-queries, use the appropriate tools, then provide the comparison.
209
  - For multi-part questions: Address each part systematically, using the appropriate tool for each sub-query.
210
  - If information is not found after using the relevant tool(s): State clearly: "Based on the available documents, I can provide the following information..." and specify what is not available.
 
 
 
 
 
 
 
 
211
 
212
  ---
213
  """
 
241
  """Create the ReAct agent with custom prompt"""
242
 
243
  agent_type = "FALLBACK" if is_fallback else "STANDARD"
244
+ # **FIX**: Increased max_iterations to give the agent more steps to reason
245
+ max_iter = 15
246
 
247
  print(f"[LOG] Creating {agent_type} ReAct agent with {len(tools)} tools and max_iterations={max_iter}")
248
 
 
251
  tools,
252
  llm=llm,
253
  verbose=True,
254
+ max_iterations=max_iter,
255
  )
256
 
257
  # Create and apply safe custom prompt
 
268
 
269
 
270
  def create_fallback_tools(all_tools):
271
+ """Extract only the general_guide_tool and who_immunization_tool for fallback agent"""
272
 
273
+ print("[LOG] Creating fallback tools (guide + WHO only)")
274
 
275
  fallback_tools = []
276
  tool_names_found = []
 
328
 
329
 
330
  def detect_max_iterations_error(response_text):
331
+ """Detect if the response indicates a max iterations error OR is an unfinished thought."""
332
+
333
+ response_lower = response_text.lower().strip()
334
+
335
+ # **FIX**: Check if the response is the agent's raw thought process.
336
+ if response_lower.startswith("a:```thought") or response_lower.startswith("```thought"):
337
+ print("[LOG] Detected unfinished agent thought process.")
338
+ return True
339
 
340
  max_iteration_indicators = [
341
  "max iterations",
 
345
  "iteration limit"
346
  ]
347
 
348
+ # Check for explicit max iterations indicators
 
 
349
  for indicator in max_iteration_indicators:
350
  if indicator in response_lower:
351
+ print(f"[LOG] Detected max iteration indicator: '{indicator}'")
352
  return True
353
 
354
  # Check for very short or empty responses (often indicates failure)
 
389
 
390
  # Check if we need to use fallback
391
  if detect_max_iterations_error(response_text):
392
+ print("[LOG] 🔄 Max iterations or unfinished thought detected, switching to FALLBACK AGENT...")
393
 
394
  if fallback_agent is None:
395
  print("[LOG] ❌ Fallback agent not available, returning error message")
 
419
 
420
  # Check if fallback also failed
421
  if detect_max_iterations_error(fallback_text):
422
+ print("[LOG] ❌ Fallback agent also hit max iterations or failed to produce an answer.")
423
  return ("I apologize, but I'm having difficulty finding specific information about your question in the available documents. "
424
  "Please try asking a more specific question or rephrasing your query.")
425
 
 
501
  print(f"[LOG] Chunks directory: {chunks_directory}")
502
  start_time = time.time()
503
 
504
+ used_fallback = False # This flag is a heuristic
505
 
506
  try:
507
  # Get the response using the enhanced process_question function
508
  response_text = process_question(agents_dict, question)
509
 
510
+ # Check if fallback was likely used (simple heuristic based on logs)
511
+ # A more robust way would be for `process_question` to return a tuple (response, used_fallback)
512
+ if "switching to fallback agent" in response_text.lower():
513
  used_fallback = True
514
+ print("[LOG] 🛡️ Fallback agent was likely used based on log indicators.")
515
 
516
  agent_time = time.time() - start_time
517
  print(f"[LOG] Agent processing completed in {agent_time:.2f} seconds")
 
535
 
536
  for json_file in min_chunks_files:
537
  json_path = os.path.join(chunks_directory, json_file)
538
+ if not os.path.exists(json_path):
539
+ print(f"[LOG] ⚠️ Skipping non-existent file: {json_path}")
540
+ continue
541
+
542
  print(f"[LOG] Loading {json_file}...")
543
  try:
544
  with open(json_path, "r", encoding="utf-8") as f:
 
554
  print("[LOG] Finding cited elements...")
555
  cited_elements_ordered = []
556
  for i, source_id in enumerate(unique_ids): # This preserves the order
557
+ # print(f"[LOG] Looking for source ID {i+1}/{len(unique_ids)}: {source_id}") # This is too verbose for normal operation
558
  found = False
559
  for element in all_chunks_data:
560
+ # Handle TableElement structure
561
  if element.get("type") == 'TableElement':
562
+ if element.get("elements", {}).get("element_id") == source_id:
563
+ cited_elements_ordered.append(element.get("elements", {}))
564
  found = True
565
  break
566
+ # Handle other element structures
567
+ elif "elements" in element and isinstance(element["elements"], list):
568
+ for nested_element in element["elements"]:
569
+ if isinstance(nested_element, dict) and nested_element.get("element_id") == source_id:
570
+ cited_elements_ordered.append(nested_element)
571
+ found = True
572
+ break
573
+ if found:
 
574
  break
575
  if not found:
576
  print(f"[LOG] ⚠️ Source ID {source_id} not found in chunks data")