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:
parent
d405b4feed
commit
a831a7b77b
3 changed files with 5530 additions and 791 deletions
|
|
@ -1806,7 +1806,18 @@ def _register_routes(app: FastAPI):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
import traceback
|
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}")
|
logger.error(f"Error in /v1/default/banks/{bank_id}/memories (retain): {error_detail}")
|
||||||
raise HTTPException(status_code=500, detail=str(e))
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,31 @@ class LLMProvider:
|
||||||
response = await self._client.chat.completions.create(**call_params)
|
response = await self._client.chat.completions.create(**call_params)
|
||||||
|
|
||||||
content = response.choices[0].message.content
|
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:
|
if skip_validation:
|
||||||
result = json_data
|
result = json_data
|
||||||
|
|
|
||||||
6282
package-lock.json
generated
6282
package-lock.json
generated
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue