fix: rename generation model setting to ollama_llm_model to avoid OLLAMA_MODEL env collision

The deployed container sets OLLAMA_MODEL=nomic-embed-text for embeddings,
which shadowed the generation-model setting and broke Phase 0 keyword
extraction and Phase 4 LLM re-ranking on every request. The setting is now
ollama_llm_model (env: OLLAMA_LLM_MODEL, default gemma4:e2b), startup logs
the resolved generation model, and Phase 0/Phase 4 LLM calls are wrapped in
a 12s asyncio.wait_for with graceful fallback so a hung call cannot gate
retrieval for the full 120s client timeout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 09:57:57 +02:00
co-authored by Claude Fable 5
parent d0e712760d
commit 94482bcb59
8 changed files with 51 additions and 16 deletions
+2 -2
View File
@@ -505,7 +505,7 @@ JSON:"""
# Call Ollama for analysis (temperature=0.0 for consistent classification)
response = await self.ollama.generate_text(
prompt=prompt,
model=self.settings.ollama_model,
model=self.settings.ollama_llm_model,
stream=False,
temperature=0.0
)
@@ -1079,7 +1079,7 @@ JSON:"""
try:
response = await self.ollama.generate_text(
prompt=prompt,
model=self.settings.ollama_model,
model=self.settings.ollama_llm_model,
stream=False,
temperature=0.0
)
+34 -9
View File
@@ -34,6 +34,10 @@ from src.core.multi_tenancy import get_neo4j_user_base_label, get_neo4j_user_lab
logger = logging.getLogger(__name__)
# Timeout for auxiliary LLM calls (keyword extraction, re-ranking).
# A hung Ollama call must not gate retrieval for the full client timeout.
LLM_CALL_TIMEOUT_SECONDS = 12.0
class HybridRAGService:
"""
@@ -69,7 +73,7 @@ class HybridRAGService:
self.content_extractor = content_extractor
self.settings = settings
self.volatile = volatile_service
self.reranker_model = settings.ollama_model
self.reranker_model = settings.ollama_llm_model
async def search(
self,
@@ -224,10 +228,13 @@ Return format:
JSON:"""
try:
response = await self.ollama.generate_text(
prompt=prompt,
model=self.reranker_model,
temperature=0.0 # Deterministic for consistent extraction
response = await asyncio.wait_for(
self.ollama.generate_text(
prompt=prompt,
model=self.reranker_model,
temperature=0.0 # Deterministic for consistent extraction
),
timeout=LLM_CALL_TIMEOUT_SECONDS
)
# Parse JSON response (handle potential extra text)
@@ -261,6 +268,16 @@ JSON:"""
"synonyms": {},
"expansions": {}
}
except asyncio.TimeoutError:
logger.warning(
f"Keyword extraction timed out after {LLM_CALL_TIMEOUT_SECONDS}s, using fallback"
)
return {
"core_keywords": query.split(),
"entities": [],
"synonyms": {},
"expansions": {}
}
except Exception as e:
logger.error(f"Keyword extraction failed: {e}", exc_info=True)
return {
@@ -772,10 +789,13 @@ Example output: 3,1,5,2,4
Ranking:"""
response = await self.ollama.generate_text(
prompt=prompt,
model=self.reranker_model,
temperature=0.0 # Deterministic for consistent rankings
response = await asyncio.wait_for(
self.ollama.generate_text(
prompt=prompt,
model=self.reranker_model,
temperature=0.0 # Deterministic for consistent rankings
),
timeout=LLM_CALL_TIMEOUT_SECONDS
)
# Parse response: "3,1,5,2,4" → [2, 0, 4, 1, 3] (0-indexed)
@@ -796,6 +816,11 @@ Ranking:"""
logger.info(f"LLM re-ranking: reordered {len(reranked)} results")
return reranked
except asyncio.TimeoutError:
logger.warning(
f"LLM re-ranking timed out after {LLM_CALL_TIMEOUT_SECONDS}s, using RRF order"
)
return results # Fallback to RRF order
except Exception as e:
logger.warning(f"LLM re-ranking failed: {e}, using RRF order")
return results # Fallback to RRF order
+1 -1
View File
@@ -34,7 +34,7 @@ class WikiPageWriter:
settings: Application settings
"""
self.ollama = ollama_client
self.model = settings.ollama_model
self.model = settings.ollama_llm_model
async def create_page(
self,