Improve LLM JSON parsing error handling with retry logic and detailed logging (#61)

* Improve LLM JSON parsing error handling with retry logic and detailed logging

* npm changes (packaging)

---------

Co-authored-by: CAL <cal@datumcon.com>
This commit is contained in:
cesarandreslopez 2025-12-22 12:44:02 +03:00 committed by GitHub
parent d405b4feed
commit a831a7b77b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 5530 additions and 791 deletions

View file

@ -1806,7 +1806,18 @@ def _register_routes(app: FastAPI):
except Exception as e:
import traceback
error_detail = f"{str(e)}\n\nTraceback:\n{traceback.format_exc()}"
# Create a summary of the input for debugging
input_summary = []
for i, item in enumerate(request.items):
content_preview = item.content[:100] + "..." if len(item.content) > 100 else item.content
input_summary.append(f" [{i}] content={content_preview!r}, context={item.context}, timestamp={item.timestamp}")
input_debug = "\n".join(input_summary)
error_detail = (
f"{str(e)}\n\n"
f"Input ({len(request.items)} items):\n{input_debug}\n\n"
f"Traceback:\n{traceback.format_exc()}"
)
logger.error(f"Error in /v1/default/banks/{bank_id}/memories (retain): {error_detail}")
raise HTTPException(status_code=500, detail=str(e))

View file

@ -227,7 +227,31 @@ class LLMProvider:
response = await self._client.chat.completions.create(**call_params)
content = response.choices[0].message.content
json_data = json.loads(content)
# Log raw LLM response for debugging JSON parse issues
try:
json_data = json.loads(content)
except json.JSONDecodeError as json_err:
# Truncate content for logging (first 500 and last 200 chars)
content_preview = content[:500] if content else "<empty>"
if content and len(content) > 700:
content_preview = f"{content[:500]}...TRUNCATED...{content[-200:]}"
logger.warning(
f"JSON parse error from LLM response (attempt {attempt + 1}/{max_retries + 1}): {json_err}\n"
f" Model: {self.provider}/{self.model}\n"
f" Content length: {len(content) if content else 0} chars\n"
f" Content preview: {content_preview!r}\n"
f" Finish reason: {response.choices[0].finish_reason if response.choices else 'unknown'}"
)
# Retry on JSON parse errors - LLM may return valid JSON on next attempt
if attempt < max_retries:
backoff = min(initial_backoff * (2**attempt), max_backoff)
await asyncio.sleep(backoff)
last_exception = json_err
continue
else:
logger.error(f"JSON parse error after {max_retries + 1} attempts, giving up")
raise
if skip_validation:
result = json_data

6282
package-lock.json generated

File diff suppressed because it is too large Load diff