Hamdy005 commited on
Commit
5afbc36
·
1 Parent(s): d4a7a60

feat: fix LLM model names, increase RAG retrieval and memory limits

Browse files
Files changed (2) hide show
  1. rag/constants.py +8 -4
  2. rag/rag.py +31 -12
rag/constants.py CHANGED
@@ -5,12 +5,16 @@ BATCH_WINDOW_S = 0.05
5
  WARMUP_INTERVAL_S = 300
6
 
7
  # Web search configuration — Wiki + DDG for topics, DDG only for PDF/URL materials.
8
- WIKI_TOP_K_RESULTS = 1
9
- WIKI_DOC_CONTENT_CHARS_MAX = 1200 # max chars from Wikipedia result
10
 
11
  # DuckDuckGO Search
12
- DUCKDUCKGO_NUM_RESULTS = 5 # number of DDG snippet results returned per search
13
- DUCKDUCKGO_DOC_CONTENT_CHARS_MAX = 3000 # max chars kept from the combined DDG result block
 
 
 
 
14
 
15
  RAG_PROMPT_TEMPLATE_BASE = """\
16
  <role>
 
5
  WARMUP_INTERVAL_S = 300
6
 
7
  # Web search configuration — Wiki + DDG for topics, DDG only for PDF/URL materials.
8
+ WIKI_TOP_K_RESULTS = 2 # Number of top Wikipedia articles retrieved
9
+ WIKI_DOC_CONTENT_CHARS_MAX = 3500 # Max chars from Wikipedia results
10
 
11
  # DuckDuckGO Search
12
+ DUCKDUCKGO_NUM_RESULTS = 8 # Number of DDG snippet results returned per search
13
+ DUCKDUCKGO_DOC_CONTENT_CHARS_MAX = 6000 # Max chars kept from combined DDG result block
14
+
15
+ # RAG & Memory Configuration
16
+ MEMORY_WINDOW_SIZE = 20 # Number of previous conversation turns (40 messages) preserved in memory window
17
+ TOP_K_CHUNKS = 8 # Number of top relevant material chunks retrieved for context
18
 
19
  RAG_PROMPT_TEMPLATE_BASE = """\
20
  <role>
rag/rag.py CHANGED
@@ -25,6 +25,8 @@ from .constants import (
25
  WIKI_DOC_CONTENT_CHARS_MAX,
26
  DUCKDUCKGO_NUM_RESULTS,
27
  DUCKDUCKGO_DOC_CONTENT_CHARS_MAX,
 
 
28
  )
29
  from .schemas import EmbeddingJob
30
 
@@ -163,12 +165,29 @@ def get_quiz_llm():
163
  )
164
 
165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  def get_gemma_31b_llm():
167
  if not os.environ.get("GEMINI_API_KEY"):
168
  raise ValueError("GEMINI_API_KEY not found. Please set it in config.env.")
169
- logger.info("Initializing primary LLM with model: google/gemma-4-31b-it")
170
  return ChatGoogleGenerativeAI(
171
- model="google/gemma-4-31b-it",
172
  api_key=settings.gemini_api_key,
173
  temperature=0.3,
174
  max_output_tokens=2500,
@@ -179,9 +198,9 @@ def get_gemma_31b_llm():
179
  def get_gemma_26b_llm():
180
  if not os.environ.get("GEMINI_API_KEY"):
181
  raise ValueError("GEMINI_API_KEY not found. Please set it in config.env.")
182
- logger.info("Initializing fallback LLM with model: google/gemma-4-26b-it")
183
  return ChatGoogleGenerativeAI(
184
- model="google/gemma-4-26b-it",
185
  api_key=settings.gemini_api_key,
186
  temperature=0.3,
187
  max_output_tokens=2500,
@@ -228,7 +247,7 @@ def direct_wiki_search(query: str) -> str:
228
 
229
  class SupabaseRetriever(BaseRetriever):
230
  material_id: str
231
- k: int = 4
232
 
233
  def _get_relevant_documents(self, query: str) -> list[Document]:
234
  results = similarity_search(query, self.material_id, self.k)
@@ -289,7 +308,7 @@ def rag_answer(
289
  ):
290
  if memory is None:
291
  memory = ConversationBufferWindowMemory(
292
- input_key="input", memory_key="chat_history", return_messages=True, k=5
293
  )
294
 
295
  # Fetch material info if material_id is provided
@@ -308,7 +327,7 @@ def rag_answer(
308
 
309
  if not is_topic:
310
  # --- Material-based query (PDF/URL): vector similarity search ---
311
- results = similarity_search(query, material_id, k=4)
312
  if results:
313
  has_chunks = True
314
  chunks = [r["content"] for r in results]
@@ -380,13 +399,13 @@ def rag_answer(
380
  "agent_scratchpad": "",
381
  })
382
 
383
- answer = response.content
384
  # Only persist non-refusal answers to memory
385
  if not _is_refusal(answer):
386
  memory.save_context({"input": query}, {"output": answer})
387
  return answer, memory
388
  except Exception as e:
389
- logger.warning(f"Gemma 4 31B API call failed or rate-limited: {e}. Falling back to google/gemma-4-26b-it immediately.")
390
  try:
391
  fallback_llm = get_gemma_26b_llm()
392
  chain = prompt | fallback_llm
@@ -399,7 +418,7 @@ def rag_answer(
399
  "chat_history": chat_history,
400
  "agent_scratchpad": "",
401
  })
402
- answer = response.content
403
  # Only persist non-refusal answers to memory
404
  if not _is_refusal(answer):
405
  memory.save_context({"input": query}, {"output": answer})
@@ -425,7 +444,7 @@ def extract_chat_title(query: str, material_title: Optional[str] = None) -> str:
425
  chain = prompt | primary_llm
426
  response = chain.invoke({"query": query})
427
  except Exception as e:
428
- logger.warning(f"Gemma 4 31B API call failed or rate-limited in extract_chat_title: {e}. Falling back to google/gemma-4-26b-it immediately.")
429
  try:
430
  fallback_llm = get_gemma_26b_llm()
431
  chain = prompt | fallback_llm
@@ -434,7 +453,7 @@ def extract_chat_title(query: str, material_title: Optional[str] = None) -> str:
434
  logger.error(f"Fallback Gemma 4 26B LLM call also failed in extract_chat_title: {fallback_err}")
435
  raise fallback_err
436
 
437
- title = response.content.strip().strip('"').strip("'")
438
  if len(title) > 50:
439
  title = title[:50].rsplit(' ', 1)[0] + '...'
440
  return title
 
25
  WIKI_DOC_CONTENT_CHARS_MAX,
26
  DUCKDUCKGO_NUM_RESULTS,
27
  DUCKDUCKGO_DOC_CONTENT_CHARS_MAX,
28
+ MEMORY_WINDOW_SIZE,
29
+ TOP_K_CHUNKS,
30
  )
31
  from .schemas import EmbeddingJob
32
 
 
165
  )
166
 
167
 
168
+ def _clean_llm_response(content) -> str:
169
+ if isinstance(content, str):
170
+ return content
171
+ if isinstance(content, list):
172
+ texts = []
173
+ for part in content:
174
+ if isinstance(part, str):
175
+ texts.append(part)
176
+ elif isinstance(part, dict):
177
+ if part.get("type") == "text":
178
+ texts.append(part.get("text", ""))
179
+ elif "text" in part and part.get("type") != "thinking":
180
+ texts.append(part.get("text", ""))
181
+ return "\n".join(t for t in texts if t)
182
+ return str(content)
183
+
184
+
185
  def get_gemma_31b_llm():
186
  if not os.environ.get("GEMINI_API_KEY"):
187
  raise ValueError("GEMINI_API_KEY not found. Please set it in config.env.")
188
+ logger.info("Initializing primary LLM with model: gemma-4-31b-it")
189
  return ChatGoogleGenerativeAI(
190
+ model="gemma-4-31b-it",
191
  api_key=settings.gemini_api_key,
192
  temperature=0.3,
193
  max_output_tokens=2500,
 
198
  def get_gemma_26b_llm():
199
  if not os.environ.get("GEMINI_API_KEY"):
200
  raise ValueError("GEMINI_API_KEY not found. Please set it in config.env.")
201
+ logger.info("Initializing fallback LLM with model: gemma-4-26b-a4b-it")
202
  return ChatGoogleGenerativeAI(
203
+ model="gemma-4-26b-a4b-it",
204
  api_key=settings.gemini_api_key,
205
  temperature=0.3,
206
  max_output_tokens=2500,
 
247
 
248
  class SupabaseRetriever(BaseRetriever):
249
  material_id: str
250
+ k: int = TOP_K_CHUNKS
251
 
252
  def _get_relevant_documents(self, query: str) -> list[Document]:
253
  results = similarity_search(query, self.material_id, self.k)
 
308
  ):
309
  if memory is None:
310
  memory = ConversationBufferWindowMemory(
311
+ input_key="input", memory_key="chat_history", return_messages=True, k=MEMORY_WINDOW_SIZE
312
  )
313
 
314
  # Fetch material info if material_id is provided
 
327
 
328
  if not is_topic:
329
  # --- Material-based query (PDF/URL): vector similarity search ---
330
+ results = similarity_search(query, material_id, k=TOP_K_CHUNKS)
331
  if results:
332
  has_chunks = True
333
  chunks = [r["content"] for r in results]
 
399
  "agent_scratchpad": "",
400
  })
401
 
402
+ answer = _clean_llm_response(response.content)
403
  # Only persist non-refusal answers to memory
404
  if not _is_refusal(answer):
405
  memory.save_context({"input": query}, {"output": answer})
406
  return answer, memory
407
  except Exception as e:
408
+ logger.warning(f"Gemma 4 31B API call failed or rate-limited: {e}. Falling back to gemma-4-26b-a4b-it immediately.")
409
  try:
410
  fallback_llm = get_gemma_26b_llm()
411
  chain = prompt | fallback_llm
 
418
  "chat_history": chat_history,
419
  "agent_scratchpad": "",
420
  })
421
+ answer = _clean_llm_response(response.content)
422
  # Only persist non-refusal answers to memory
423
  if not _is_refusal(answer):
424
  memory.save_context({"input": query}, {"output": answer})
 
444
  chain = prompt | primary_llm
445
  response = chain.invoke({"query": query})
446
  except Exception as e:
447
+ logger.warning(f"Gemma 4 31B API call failed or rate-limited in extract_chat_title: {e}. Falling back to gemma-4-26b-a4b-it immediately.")
448
  try:
449
  fallback_llm = get_gemma_26b_llm()
450
  chain = prompt | fallback_llm
 
453
  logger.error(f"Fallback Gemma 4 26B LLM call also failed in extract_chat_title: {fallback_err}")
454
  raise fallback_err
455
 
456
+ title = _clean_llm_response(response.content).strip().strip('"').strip("'")
457
  if len(title) > 50:
458
  title = title[:50].rsplit(' ', 1)[0] + '...'
459
  return title