| |
|
| | import json
|
| |
|
| | def run_agent_safely(agent, max_retries=3, return_string=False, **kwargs):
|
| | """
|
| | Безопасно запускает агента с повторными попытками при ошибках.
|
| |
|
| | Args:
|
| | agent: Экземпляр агента smolagents
|
| | max_retries: Максимальное количество попыток
|
| | return_string: Если True, возвращает строку вместо парсинга JSON
|
| | **kwargs: Аргументы для передачи агенту
|
| |
|
| | Returns:
|
| | dict или str: Распарсенный JSON ответ или строка (в зависимости от return_string)
|
| | """
|
| | last_error = None
|
| |
|
| | for attempt in range(1, max_retries + 1):
|
| | try:
|
| | result = agent.run(**kwargs)
|
| |
|
| |
|
| |
|
| | raw = None
|
| |
|
| |
|
| |
|
| | if hasattr(result, 'to_string'):
|
| | raw = result.to_string()
|
| | elif hasattr(result, 'text'):
|
| | raw = result.text
|
| | elif hasattr(result, '__getitem__'):
|
| |
|
| | try:
|
| | if 'answer' in result:
|
| | raw = result['answer']
|
| | except:
|
| | pass
|
| | elif isinstance(result, dict):
|
| |
|
| | if "answer" in result:
|
| | raw = result["answer"]
|
| | elif "content" in result:
|
| | raw = result["content"]
|
| | elif "text" in result:
|
| | raw = result["text"]
|
| | elif "response" in result:
|
| | raw = result["response"]
|
| | else:
|
| |
|
| | raw = json.dumps(result, ensure_ascii=False)
|
| | elif isinstance(result, str):
|
| | raw = result
|
| | else:
|
| |
|
| | raw = str(result)
|
| |
|
| | if not isinstance(raw, str):
|
| | raise ValueError(f"Agent output is not a string, got {type(raw)}")
|
| |
|
| |
|
| | raw = raw.strip()
|
| |
|
| |
|
| |
|
| | if raw.startswith('{"') and '"answer"' in raw:
|
| | try:
|
| |
|
| | outer_json = json.loads(raw)
|
| | if isinstance(outer_json, dict) and "answer" in outer_json:
|
| | raw = outer_json["answer"]
|
| | except json.JSONDecodeError:
|
| |
|
| |
|
| | pass
|
| |
|
| |
|
| | if return_string:
|
| | return raw
|
| |
|
| |
|
| |
|
| | if raw.startswith('{') and not raw.rstrip().endswith('}'):
|
| |
|
| | last_brace = raw.rfind('}')
|
| | if last_brace > len(raw) * 0.8:
|
| | raw = raw[:last_brace + 1]
|
| |
|
| |
|
| | try:
|
| | return json.loads(raw)
|
| | except json.JSONDecodeError as e:
|
| |
|
| |
|
| | start_idx = raw.find('{')
|
| | end_idx = raw.rfind('}')
|
| | if start_idx >= 0 and end_idx > start_idx:
|
| | json_part = raw[start_idx:end_idx + 1]
|
| | try:
|
| | return json.loads(json_part)
|
| | except:
|
| | pass
|
| |
|
| |
|
| | if not raw.startswith('{') and not raw.startswith('['):
|
| | raise ValueError(f"Expected JSON but got plain text (first 200 chars): {raw[:200]}")
|
| | raise ValueError(f"JSON decode error: {e}. Raw (first 500 chars): {raw[:500]}")
|
| |
|
| | except Exception as e:
|
| | last_error = e
|
| | print(f"[{agent.name}] Attempt {attempt}/{max_retries} failed: {e}")
|
| |
|
| | raise ValueError(
|
| | f"[{agent.name}] Failed after {max_retries} attempts.\nLast error: {last_error}"
|
| | )
|
| |
|