{"title":"Récupération d'erreurs pour les agents","slug":"error-recovery","category":"llm-cookbook","summary":"Comment les agents LLM devraient gérer et se remettre des erreurs — réessayer, stocker, apprendre.","audience":["llm"],"tags":["cookbook","errors","recovery","resilience"],"difficulty":"intermediate","updated":"2026-06-27","word_count":271,"read_minutes":1,"lang":"fr","translated":true,"requested_lang":"fr","content_markdown":"\n# Récupération d'erreurs pour les agents\n\nLes erreurs arrivent. Les réseaux tombent, les API renvoient des 500, les Mind Keys\nexpirent. Ce guide montre comment les agents LLM devraient gérer les erreurs\ngracieusement et en tirer des leçons.\n\n## Principes de gestion des erreurs\n\n1. **Réessayer avec backoff** — les erreurs transitoires se résolvent souvent\n2. **Stocker l'erreur** — apprendre des schémas\n3. **Dégrader gracieusement** — ne pas crasher toute la session\n4. **Notifier l'humain** — pour les erreurs que vous ne pouvez pas résoudre\n\n## Gestion des erreurs HTTP\n\n### Réessayer avec backoff exponentiel\n\n```python\nimport time\nimport requests\n\ndef call_with_retry(url, max_retries=3, backoff_base=2):\n    \"\"\"Call URL with exponential backoff.\"\"\"\n    for attempt in range(max_retries):\n        try:\n            r = requests.get(url, headers={\"Authorization\": f\"Bearer {KEY}\"})\n            \n            # Succès\n            if r.status_code < 400:\n                return r\n            \n            # Limité en débit — attendre et réessayer\n            if r.status_code == 429:\n                wait = int(r.headers.get(\"Retry-After\", 60))\n                print(f\"Rate limited. Waiting {wait}s...\")\n                time.sleep(wait)\n                continue\n            \n            # Erreur serveur — réessayer avec backoff\n            if r.status_code >= 500:\n                wait = backoff_base ** attempt\n                print(f\"Server error {r.status_code}. Retrying in {wait}s...\")\n                time.sleep(wait)\n                continue\n            \n            # Erreur client — ne pas réessayer\n            if 400 <= r.status_code < 500:\n                raise ClientError(f\"{r.status_code}: {r.text}\")\n        \n        except requests.RequestException as e:\n            # Erreur réseau — réessayer\n            wait = backoff_base ** attempt\n            print(f\"Network error: {e}. Retrying in {wait}s...\")\n            time.sleep(wait)\n    \n    raise MaxRetriesError(f\"Failed after {max_retries} retries\")\n```\n\n### Gestion des erreurs d'auth\n\n```python\ndef safe_call(url):\n    \"\"\"Call with auth error handling.\"\"\"\n    try:\n        return call_with_retry(url)\n    except ClientError as e:\n        if \"401\" in str(e):\n            # Mind Key invalide — critique, impossible à récupérer\n            store_error(\"auth_invalid\", str(e), \"Check Mind Key\")\n            notify_human(\"My Mind Key is invalid. Please update.\")\n            raise AuthError(\"Cannot continue without valid Mind Key\")\n        elif \"403\" in str(e):\n            store_error(\"forbidden\", str(e), \"Wrong token type?\")\n            raise ForbiddenError(str(e))\n        elif \"404\" in str(e):\n            # Le chemin n'existe pas — ne pas réessayer\n            store_error(\"not_found\", str(e), \"Check endpoint path\")\n            raise NotFoundError(str(e))\n        else:\n            raise\n```\n\n## Stocker les erreurs en mémoire\n\nQuand des erreurs se produisent, stockez-les pour que les futures sessions puissent\napprendre :\n\n```python\ndef store_error(error_type, error_message, recovery_hint=\"\"):\n    \"\"\"Store an error as a memory for future reference.\"\"\"\n    requests.post(f\"{URL}/memory\",\n        headers={\"Authorization\": f\"Bearer {KEY}\",\n                 \"Content-Type\": \"application/json\"},\n        json={\n            \"category\": \"mistake\",\n            \"key\": f\"error_{error_type}_{int(time.time())}\",\n            \"content\": f\"Error: {error_type}\\nMessage: {error_message}\\nRecovery: {recovery_hint}\",\n            \"tags\": [\"error\", error_type],\n            \"priority\": \"high\"\n        })\n\n# Exemple\ntry:\n    deploy()\nexcept DeployError as e:\n    store_error(\"deploy_failed\", str(e), \n                \"Check CI logs, verify Docker image exists\")\n    raise\n```\n\n## Scénarios d'erreur courants\n\n### Scénario 1 : Mind Key invalide\n\n```python\n# Détection : 401 sur chaque appel\n# Récupération : Impossible — nécessite une intervention humaine\n\ndef handle_invalid_mind_key():\n    store_error(\"mind_key_invalid\", \n                \"All API calls returning 401\",\n                \"Mind Key may be revoked. Need new key.\")\n    \n    # Notifier l'humain via chat (si possible)\n    try:\n        reply(\"⚠️ My Mind Key is invalid. I cannot access memories. \"\n              \"Please check and update SYNAPSE_MIND_KEY.\")\n    except:\n        pass  # Le chat peut aussi échouer avec une mauvaise clé\n    \n    # Sortir gracieusement\n    raise CriticalError(\"Cannot continue without valid Mind Key\")\n```\n\n### Scénario 2 : erreur réseau\n\n```python\n# Détection : ConnectionError, Timeout\n# Récupération : Réessayer avec backoff, puis dégrader\n\ndef handle_network_error(url, retry=3):\n    for attempt in range(retry):\n        try:\n            return requests.get(url, timeout=10)\n        except (requests.ConnectionError, requests.Timeout) as e:\n            wait = 2 ** attempt\n            print(f\"Network error, retrying in {wait}s: {e}\")\n            time.sleep(wait)\n    \n    # Tous les essais échoués — dégrader\n    store_error(\"network_failure\", \n                f\"Cannot reach {url}\",\n                \"Check internet connection, Synapse may be down\")\n    \n    # Travailler hors ligne si possible\n    return work_offline()\n```\n\n### Scénario 3 : limité en débit\n\n```python\n# Détection : 429 avec en-tête Retry-After\n# Récupération : Attendre et réessayer, ou passer à l'auth par en-tête\n\ndef handle_rate_limit(response):\n    retry_after = int(response.headers.get(\"Retry-After\", 60))\n    print(f\"Rate limited. Waiting {retry_after}s...\")\n    time.sleep(retry_after)\n    \n    # Si cela continue, suggérer de passer à l'auth par en-tête\n    if has_query_param_auth(url):\n        store_error(\"rate_limited\", \n                    \"Frequent 429s with ?key= auth\",\n                    \"Switch to Authorization: Bearer header (no rate limit)\")\n```\n\n### Scénario 4 : erreur serveur (5xx)\n\n```python\n# Détection : 500, 502, 503\n# Récupération : Réessayer avec backoff, vérifier /health\n\ndef handle_server_error(url):\n    # Vérifier si le serveur fonctionne\n    health = requests.get(f\"{URL}/health\")\n    if health.status_code != 200:\n        store_error(\"server_down\", \n                    \"Synapse health check failing\",\n                    \"Wait for server recovery\")\n        raise ServerDownError()\n    \n    # Réessayer avec backoff\n    return call_with_retry(url, max_retries=5)\n```\n\n### Scénario 5 : échec d'appel d'outil\n\n```python\n# Détection : L'outil renvoie un contenu d'erreur\n# Récupération : Essayer une approche alternative, stocker l'échec\n\ndef call_tool_safely(tool_name, args, alternatives=None):\n    try:\n        result = call_tool(tool_name, args)\n        if result.get(\"isError\"):\n            raise ToolError(result[\"content\"])\n        return result\n    except ToolError as e:\n        store_error(f\"tool_{tool_name}_failed\",\n                    f\"Args: {args}\\nError: {e}\",\n                    f\"Try: {alternatives or 'no alternatives'}\")\n        \n        # Essayer des alternatives\n        if alternatives:\n            for alt in alternatives:\n                try:\n                    return call_tool(alt, args)\n                except:\n                    continue\n        \n        raise\n```\n\n## Schéma : disjoncteur\n\nPour les échecs répétés, arrêter d'essayer temporairement :\n\n```python\nclass CircuitBreaker:\n    def __init__(self, threshold=5, reset_time=300):\n        self.failures = 0\n        self.threshold = threshold\n        self.reset_time = reset_time\n        self.last_failure = 0\n    \n    def call(self, fn, *args, **kwargs):\n        if self.failures >= self.threshold:\n            if time.time() - self.last_failure < self.reset_time:\n                raise CircuitOpenError(\"Circuit breaker open\")\n            else:\n                # Réinitialiser\n                self.failures = 0\n        \n        try:\n            result = fn(*args, **kwargs)\n            self.failures = 0  # Réinitialiser sur succès\n            return result\n        except:\n            self.failures += 1\n            self.last_failure = time.time()\n            raise\n\n# Utilisation\nbreaker = CircuitBreaker(threshold=5)\ntry:\n    result = breaker.call(api_call, url)\nexcept CircuitOpenError:\n    print(\"Too many failures, waiting before retry\")\n```\n\n## Bonnes pratiques\n\n> [!TIP]\n> - **Toujours réessayer les erreurs transitoires** — les réseaux tombent, les serveurs hoquettent\n> - **Ne pas réessayer les erreurs client (4xx)** — elles ne se corrigeront pas\n> - **Stocker les erreurs en mémoire** — apprendre des schémas\n> - **Notifier les humains pour les erreurs critiques** — ils doivent savoir\n> - **Dégrader gracieusement** — un travail partiel vaut mieux qu'un crash\n> - **Utiliser des disjoncteurs** — ne pas marteler un service défaillant\n\n## Prochaines étapes\n\n- [Référence API Erreurs](/docs/api/errors)\n- [Schéma de début de session](/docs/llm-cookbook/session-start-pattern)\n- [Tests auto-réparables](/docs/guides/self-healing-tests)\n","content_html":"<h1>Récupération d&#39;erreurs pour les agents</h1>\n<p>Les erreurs arrivent. Les réseaux tombent, les API renvoient des 500, les Mind Keys\nexpirent. Ce guide montre comment les agents LLM devraient gérer les erreurs\ngracieusement et en tirer des leçons.</p>\n<h2>Principes de gestion des erreurs</h2>\n<ol>\n<li><strong>Réessayer avec backoff</strong> — les erreurs transitoires se résolvent souvent</li>\n<li><strong>Stocker l&#39;erreur</strong> — apprendre des schémas</li>\n<li><strong>Dégrader gracieusement</strong> — ne pas crasher toute la session</li>\n<li><strong>Notifier l&#39;humain</strong> — pour les erreurs que vous ne pouvez pas résoudre</li>\n</ol>\n<h2>Gestion des erreurs HTTP</h2>\n<h3>Réessayer avec backoff exponentiel</h3>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-keyword\">import</span> time\n<span class=\"hljs-keyword\">import</span> requests\n\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">call_with_retry</span>(<span class=\"hljs-params\">url, max_retries=<span class=\"hljs-number\">3</span>, backoff_base=<span class=\"hljs-number\">2</span></span>):\n    <span class=\"hljs-string\">&quot;&quot;&quot;Call URL with exponential backoff.&quot;&quot;&quot;</span>\n    <span class=\"hljs-keyword\">for</span> attempt <span class=\"hljs-keyword\">in</span> <span class=\"hljs-built_in\">range</span>(max_retries):\n        <span class=\"hljs-keyword\">try</span>:\n            r = requests.get(url, headers={<span class=\"hljs-string\">&quot;Authorization&quot;</span>: <span class=\"hljs-string\">f&quot;Bearer <span class=\"hljs-subst\">{KEY}</span>&quot;</span>})\n            \n            <span class=\"hljs-comment\"># Succès</span>\n            <span class=\"hljs-keyword\">if</span> r.status_code &lt; <span class=\"hljs-number\">400</span>:\n                <span class=\"hljs-keyword\">return</span> r\n            \n            <span class=\"hljs-comment\"># Limité en débit — attendre et réessayer</span>\n            <span class=\"hljs-keyword\">if</span> r.status_code == <span class=\"hljs-number\">429</span>:\n                wait = <span class=\"hljs-built_in\">int</span>(r.headers.get(<span class=\"hljs-string\">&quot;Retry-After&quot;</span>, <span class=\"hljs-number\">60</span>))\n                <span class=\"hljs-built_in\">print</span>(<span class=\"hljs-string\">f&quot;Rate limited. Waiting <span class=\"hljs-subst\">{wait}</span>s...&quot;</span>)\n                time.sleep(wait)\n                <span class=\"hljs-keyword\">continue</span>\n            \n            <span class=\"hljs-comment\"># Erreur serveur — réessayer avec backoff</span>\n            <span class=\"hljs-keyword\">if</span> r.status_code &gt;= <span class=\"hljs-number\">500</span>:\n                wait = backoff_base ** attempt\n                <span class=\"hljs-built_in\">print</span>(<span class=\"hljs-string\">f&quot;Server error <span class=\"hljs-subst\">{r.status_code}</span>. Retrying in <span class=\"hljs-subst\">{wait}</span>s...&quot;</span>)\n                time.sleep(wait)\n                <span class=\"hljs-keyword\">continue</span>\n            \n            <span class=\"hljs-comment\"># Erreur client — ne pas réessayer</span>\n            <span class=\"hljs-keyword\">if</span> <span class=\"hljs-number\">400</span> &lt;= r.status_code &lt; <span class=\"hljs-number\">500</span>:\n                <span class=\"hljs-keyword\">raise</span> ClientError(<span class=\"hljs-string\">f&quot;<span class=\"hljs-subst\">{r.status_code}</span>: <span class=\"hljs-subst\">{r.text}</span>&quot;</span>)\n        \n        <span class=\"hljs-keyword\">except</span> requests.RequestException <span class=\"hljs-keyword\">as</span> e:\n            <span class=\"hljs-comment\"># Erreur réseau — réessayer</span>\n            wait = backoff_base ** attempt\n            <span class=\"hljs-built_in\">print</span>(<span class=\"hljs-string\">f&quot;Network error: <span class=\"hljs-subst\">{e}</span>. Retrying in <span class=\"hljs-subst\">{wait}</span>s...&quot;</span>)\n            time.sleep(wait)\n    \n    <span class=\"hljs-keyword\">raise</span> MaxRetriesError(<span class=\"hljs-string\">f&quot;Failed after <span class=\"hljs-subst\">{max_retries}</span> retries&quot;</span>)</code></pre><h3>Gestion des erreurs d&#39;auth</h3>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">safe_call</span>(<span class=\"hljs-params\">url</span>):\n    <span class=\"hljs-string\">&quot;&quot;&quot;Call with auth error handling.&quot;&quot;&quot;</span>\n    <span class=\"hljs-keyword\">try</span>:\n        <span class=\"hljs-keyword\">return</span> call_with_retry(url)\n    <span class=\"hljs-keyword\">except</span> ClientError <span class=\"hljs-keyword\">as</span> e:\n        <span class=\"hljs-keyword\">if</span> <span class=\"hljs-string\">&quot;401&quot;</span> <span class=\"hljs-keyword\">in</span> <span class=\"hljs-built_in\">str</span>(e):\n            <span class=\"hljs-comment\"># Mind Key invalide — critique, impossible à récupérer</span>\n            store_error(<span class=\"hljs-string\">&quot;auth_invalid&quot;</span>, <span class=\"hljs-built_in\">str</span>(e), <span class=\"hljs-string\">&quot;Check Mind Key&quot;</span>)\n            notify_human(<span class=\"hljs-string\">&quot;My Mind Key is invalid. Please update.&quot;</span>)\n            <span class=\"hljs-keyword\">raise</span> AuthError(<span class=\"hljs-string\">&quot;Cannot continue without valid Mind Key&quot;</span>)\n        <span class=\"hljs-keyword\">elif</span> <span class=\"hljs-string\">&quot;403&quot;</span> <span class=\"hljs-keyword\">in</span> <span class=\"hljs-built_in\">str</span>(e):\n            store_error(<span class=\"hljs-string\">&quot;forbidden&quot;</span>, <span class=\"hljs-built_in\">str</span>(e), <span class=\"hljs-string\">&quot;Wrong token type?&quot;</span>)\n            <span class=\"hljs-keyword\">raise</span> ForbiddenError(<span class=\"hljs-built_in\">str</span>(e))\n        <span class=\"hljs-keyword\">elif</span> <span class=\"hljs-string\">&quot;404&quot;</span> <span class=\"hljs-keyword\">in</span> <span class=\"hljs-built_in\">str</span>(e):\n            <span class=\"hljs-comment\"># Le chemin n&#x27;existe pas — ne pas réessayer</span>\n            store_error(<span class=\"hljs-string\">&quot;not_found&quot;</span>, <span class=\"hljs-built_in\">str</span>(e), <span class=\"hljs-string\">&quot;Check endpoint path&quot;</span>)\n            <span class=\"hljs-keyword\">raise</span> NotFoundError(<span class=\"hljs-built_in\">str</span>(e))\n        <span class=\"hljs-keyword\">else</span>:\n            <span class=\"hljs-keyword\">raise</span></code></pre><h2>Stocker les erreurs en mémoire</h2>\n<p>Quand des erreurs se produisent, stockez-les pour que les futures sessions puissent\napprendre :</p>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">store_error</span>(<span class=\"hljs-params\">error_type, error_message, recovery_hint=<span class=\"hljs-string\">&quot;&quot;</span></span>):\n    <span class=\"hljs-string\">&quot;&quot;&quot;Store an error as a memory for future reference.&quot;&quot;&quot;</span>\n    requests.post(<span class=\"hljs-string\">f&quot;<span class=\"hljs-subst\">{URL}</span>/memory&quot;</span>,\n        headers={<span class=\"hljs-string\">&quot;Authorization&quot;</span>: <span class=\"hljs-string\">f&quot;Bearer <span class=\"hljs-subst\">{KEY}</span>&quot;</span>,\n                 <span class=\"hljs-string\">&quot;Content-Type&quot;</span>: <span class=\"hljs-string\">&quot;application/json&quot;</span>},\n        json={\n            <span class=\"hljs-string\">&quot;category&quot;</span>: <span class=\"hljs-string\">&quot;mistake&quot;</span>,\n            <span class=\"hljs-string\">&quot;key&quot;</span>: <span class=\"hljs-string\">f&quot;error_<span class=\"hljs-subst\">{error_type}</span>_<span class=\"hljs-subst\">{<span class=\"hljs-built_in\">int</span>(time.time())}</span>&quot;</span>,\n            <span class=\"hljs-string\">&quot;content&quot;</span>: <span class=\"hljs-string\">f&quot;Error: <span class=\"hljs-subst\">{error_type}</span>\\nMessage: <span class=\"hljs-subst\">{error_message}</span>\\nRecovery: <span class=\"hljs-subst\">{recovery_hint}</span>&quot;</span>,\n            <span class=\"hljs-string\">&quot;tags&quot;</span>: [<span class=\"hljs-string\">&quot;error&quot;</span>, error_type],\n            <span class=\"hljs-string\">&quot;priority&quot;</span>: <span class=\"hljs-string\">&quot;high&quot;</span>\n        })\n\n<span class=\"hljs-comment\"># Exemple</span>\n<span class=\"hljs-keyword\">try</span>:\n    deploy()\n<span class=\"hljs-keyword\">except</span> DeployError <span class=\"hljs-keyword\">as</span> e:\n    store_error(<span class=\"hljs-string\">&quot;deploy_failed&quot;</span>, <span class=\"hljs-built_in\">str</span>(e), \n                <span class=\"hljs-string\">&quot;Check CI logs, verify Docker image exists&quot;</span>)\n    <span class=\"hljs-keyword\">raise</span></code></pre><h2>Scénarios d&#39;erreur courants</h2>\n<h3>Scénario 1 : Mind Key invalide</h3>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-comment\"># Détection : 401 sur chaque appel</span>\n<span class=\"hljs-comment\"># Récupération : Impossible — nécessite une intervention humaine</span>\n\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">handle_invalid_mind_key</span>():\n    store_error(<span class=\"hljs-string\">&quot;mind_key_invalid&quot;</span>, \n                <span class=\"hljs-string\">&quot;All API calls returning 401&quot;</span>,\n                <span class=\"hljs-string\">&quot;Mind Key may be revoked. Need new key.&quot;</span>)\n    \n    <span class=\"hljs-comment\"># Notifier l&#x27;humain via chat (si possible)</span>\n    <span class=\"hljs-keyword\">try</span>:\n        reply(<span class=\"hljs-string\">&quot;⚠️ My Mind Key is invalid. I cannot access memories. &quot;</span>\n              <span class=\"hljs-string\">&quot;Please check and update SYNAPSE_MIND_KEY.&quot;</span>)\n    <span class=\"hljs-keyword\">except</span>:\n        <span class=\"hljs-keyword\">pass</span>  <span class=\"hljs-comment\"># Le chat peut aussi échouer avec une mauvaise clé</span>\n    \n    <span class=\"hljs-comment\"># Sortir gracieusement</span>\n    <span class=\"hljs-keyword\">raise</span> CriticalError(<span class=\"hljs-string\">&quot;Cannot continue without valid Mind Key&quot;</span>)</code></pre><h3>Scénario 2 : erreur réseau</h3>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-comment\"># Détection : ConnectionError, Timeout</span>\n<span class=\"hljs-comment\"># Récupération : Réessayer avec backoff, puis dégrader</span>\n\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">handle_network_error</span>(<span class=\"hljs-params\">url, retry=<span class=\"hljs-number\">3</span></span>):\n    <span class=\"hljs-keyword\">for</span> attempt <span class=\"hljs-keyword\">in</span> <span class=\"hljs-built_in\">range</span>(retry):\n        <span class=\"hljs-keyword\">try</span>:\n            <span class=\"hljs-keyword\">return</span> requests.get(url, timeout=<span class=\"hljs-number\">10</span>)\n        <span class=\"hljs-keyword\">except</span> (requests.ConnectionError, requests.Timeout) <span class=\"hljs-keyword\">as</span> e:\n            wait = <span class=\"hljs-number\">2</span> ** attempt\n            <span class=\"hljs-built_in\">print</span>(<span class=\"hljs-string\">f&quot;Network error, retrying in <span class=\"hljs-subst\">{wait}</span>s: <span class=\"hljs-subst\">{e}</span>&quot;</span>)\n            time.sleep(wait)\n    \n    <span class=\"hljs-comment\"># Tous les essais échoués — dégrader</span>\n    store_error(<span class=\"hljs-string\">&quot;network_failure&quot;</span>, \n                <span class=\"hljs-string\">f&quot;Cannot reach <span class=\"hljs-subst\">{url}</span>&quot;</span>,\n                <span class=\"hljs-string\">&quot;Check internet connection, Synapse may be down&quot;</span>)\n    \n    <span class=\"hljs-comment\"># Travailler hors ligne si possible</span>\n    <span class=\"hljs-keyword\">return</span> work_offline()</code></pre><h3>Scénario 3 : limité en débit</h3>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-comment\"># Détection : 429 avec en-tête Retry-After</span>\n<span class=\"hljs-comment\"># Récupération : Attendre et réessayer, ou passer à l&#x27;auth par en-tête</span>\n\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">handle_rate_limit</span>(<span class=\"hljs-params\">response</span>):\n    retry_after = <span class=\"hljs-built_in\">int</span>(response.headers.get(<span class=\"hljs-string\">&quot;Retry-After&quot;</span>, <span class=\"hljs-number\">60</span>))\n    <span class=\"hljs-built_in\">print</span>(<span class=\"hljs-string\">f&quot;Rate limited. Waiting <span class=\"hljs-subst\">{retry_after}</span>s...&quot;</span>)\n    time.sleep(retry_after)\n    \n    <span class=\"hljs-comment\"># Si cela continue, suggérer de passer à l&#x27;auth par en-tête</span>\n    <span class=\"hljs-keyword\">if</span> has_query_param_auth(url):\n        store_error(<span class=\"hljs-string\">&quot;rate_limited&quot;</span>, \n                    <span class=\"hljs-string\">&quot;Frequent 429s with ?key= auth&quot;</span>,\n                    <span class=\"hljs-string\">&quot;Switch to Authorization: Bearer header (no rate limit)&quot;</span>)</code></pre><h3>Scénario 4 : erreur serveur (5xx)</h3>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-comment\"># Détection : 500, 502, 503</span>\n<span class=\"hljs-comment\"># Récupération : Réessayer avec backoff, vérifier /health</span>\n\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">handle_server_error</span>(<span class=\"hljs-params\">url</span>):\n    <span class=\"hljs-comment\"># Vérifier si le serveur fonctionne</span>\n    health = requests.get(<span class=\"hljs-string\">f&quot;<span class=\"hljs-subst\">{URL}</span>/health&quot;</span>)\n    <span class=\"hljs-keyword\">if</span> health.status_code != <span class=\"hljs-number\">200</span>:\n        store_error(<span class=\"hljs-string\">&quot;server_down&quot;</span>, \n                    <span class=\"hljs-string\">&quot;Synapse health check failing&quot;</span>,\n                    <span class=\"hljs-string\">&quot;Wait for server recovery&quot;</span>)\n        <span class=\"hljs-keyword\">raise</span> ServerDownError()\n    \n    <span class=\"hljs-comment\"># Réessayer avec backoff</span>\n    <span class=\"hljs-keyword\">return</span> call_with_retry(url, max_retries=<span class=\"hljs-number\">5</span>)</code></pre><h3>Scénario 5 : échec d&#39;appel d&#39;outil</h3>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-comment\"># Détection : L&#x27;outil renvoie un contenu d&#x27;erreur</span>\n<span class=\"hljs-comment\"># Récupération : Essayer une approche alternative, stocker l&#x27;échec</span>\n\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">call_tool_safely</span>(<span class=\"hljs-params\">tool_name, args, alternatives=<span class=\"hljs-literal\">None</span></span>):\n    <span class=\"hljs-keyword\">try</span>:\n        result = call_tool(tool_name, args)\n        <span class=\"hljs-keyword\">if</span> result.get(<span class=\"hljs-string\">&quot;isError&quot;</span>):\n            <span class=\"hljs-keyword\">raise</span> ToolError(result[<span class=\"hljs-string\">&quot;content&quot;</span>])\n        <span class=\"hljs-keyword\">return</span> result\n    <span class=\"hljs-keyword\">except</span> ToolError <span class=\"hljs-keyword\">as</span> e:\n        store_error(<span class=\"hljs-string\">f&quot;tool_<span class=\"hljs-subst\">{tool_name}</span>_failed&quot;</span>,\n                    <span class=\"hljs-string\">f&quot;Args: <span class=\"hljs-subst\">{args}</span>\\nError: <span class=\"hljs-subst\">{e}</span>&quot;</span>,\n                    <span class=\"hljs-string\">f&quot;Try: <span class=\"hljs-subst\">{alternatives <span class=\"hljs-keyword\">or</span> <span class=\"hljs-string\">&#x27;no alternatives&#x27;</span>}</span>&quot;</span>)\n        \n        <span class=\"hljs-comment\"># Essayer des alternatives</span>\n        <span class=\"hljs-keyword\">if</span> alternatives:\n            <span class=\"hljs-keyword\">for</span> alt <span class=\"hljs-keyword\">in</span> alternatives:\n                <span class=\"hljs-keyword\">try</span>:\n                    <span class=\"hljs-keyword\">return</span> call_tool(alt, args)\n                <span class=\"hljs-keyword\">except</span>:\n                    <span class=\"hljs-keyword\">continue</span>\n        \n        <span class=\"hljs-keyword\">raise</span></code></pre><h2>Schéma : disjoncteur</h2>\n<p>Pour les échecs répétés, arrêter d&#39;essayer temporairement :</p>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-keyword\">class</span> <span class=\"hljs-title class_\">CircuitBreaker</span>:\n    <span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">__init__</span>(<span class=\"hljs-params\">self, threshold=<span class=\"hljs-number\">5</span>, reset_time=<span class=\"hljs-number\">300</span></span>):\n        <span class=\"hljs-variable language_\">self</span>.failures = <span class=\"hljs-number\">0</span>\n        <span class=\"hljs-variable language_\">self</span>.threshold = threshold\n        <span class=\"hljs-variable language_\">self</span>.reset_time = reset_time\n        <span class=\"hljs-variable language_\">self</span>.last_failure = <span class=\"hljs-number\">0</span>\n    \n    <span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">call</span>(<span class=\"hljs-params\">self, fn, *args, **kwargs</span>):\n        <span class=\"hljs-keyword\">if</span> <span class=\"hljs-variable language_\">self</span>.failures &gt;= <span class=\"hljs-variable language_\">self</span>.threshold:\n            <span class=\"hljs-keyword\">if</span> time.time() - <span class=\"hljs-variable language_\">self</span>.last_failure &lt; <span class=\"hljs-variable language_\">self</span>.reset_time:\n                <span class=\"hljs-keyword\">raise</span> CircuitOpenError(<span class=\"hljs-string\">&quot;Circuit breaker open&quot;</span>)\n            <span class=\"hljs-keyword\">else</span>:\n                <span class=\"hljs-comment\"># Réinitialiser</span>\n                <span class=\"hljs-variable language_\">self</span>.failures = <span class=\"hljs-number\">0</span>\n        \n        <span class=\"hljs-keyword\">try</span>:\n            result = fn(*args, **kwargs)\n            <span class=\"hljs-variable language_\">self</span>.failures = <span class=\"hljs-number\">0</span>  <span class=\"hljs-comment\"># Réinitialiser sur succès</span>\n            <span class=\"hljs-keyword\">return</span> result\n        <span class=\"hljs-keyword\">except</span>:\n            <span class=\"hljs-variable language_\">self</span>.failures += <span class=\"hljs-number\">1</span>\n            <span class=\"hljs-variable language_\">self</span>.last_failure = time.time()\n            <span class=\"hljs-keyword\">raise</span>\n\n<span class=\"hljs-comment\"># Utilisation</span>\nbreaker = CircuitBreaker(threshold=<span class=\"hljs-number\">5</span>)\n<span class=\"hljs-keyword\">try</span>:\n    result = breaker.call(api_call, url)\n<span class=\"hljs-keyword\">except</span> CircuitOpenError:\n    <span class=\"hljs-built_in\">print</span>(<span class=\"hljs-string\">&quot;Too many failures, waiting before retry&quot;</span>)</code></pre><h2>Bonnes pratiques</h2>\n<div class=\"callout callout-ok\"></div><h2>Prochaines étapes</h2>\n<ul>\n<li><a href=\"/docs/api/errors\">Référence API Erreurs</a></li>\n<li><a href=\"/docs/llm-cookbook/session-start-pattern\">Schéma de début de session</a></li>\n<li><a href=\"/docs/guides/self-healing-tests\">Tests auto-réparables</a></li>\n</ul>\n","urls":{"html":"/docs/llm-cookbook/error-recovery","text":"/docs/llm-cookbook/error-recovery?format=text","json":"/docs/llm-cookbook/error-recovery?format=json","llm":"/docs/llm-cookbook/error-recovery?format=llm"},"translations_available":["en","zh","hi","es","fr","ar","pt","ru","ja","de","it","ko","nl","pl","tr","sv","vi","th","id","uk"]}