ailiteracynepal 🇳🇵
पाठ आकार

अध्याय ३ · खण्ड III · 20 मिनेट

असफलतालाई gracefully सम्हाल्ने

Models time out हुन्छन्, APIs errors फर्काउँछन्, retrieval टुट्छ, प्रयोगकर्ताहरूले garbage पठाउँछन्। यीमध्ये हरेकलाई service crash बाट मैत्रीपूर्ण recovery मा बदल्ने patterns: timeouts, retries with backoff, fallbacks, र ईमानदार user-facing messages।

AI प्रणालीको हरेक भाग अन्ततः असफल हुन्छ। Model provider को खराब घण्टा हुन्छ। Vector store empty फर्काउँछ। प्रयोगकर्ताले payload पठाउँछ जुन दुर्लभ bug trip गर्दछ। एक राम्रो service लाई नाजुक service बाट अलग गर्ने कुरा भनेको ती चीजहरू हुन्छन् कि हुँदैनन् भन्ने होइन — तिनीहरू सधैँ हुन्छन् — तर प्रणालीले तिनीहरू भएको बेला के गर्दछ। यो खण्ड चार patterns हुन् जुन असफलतालाई crash बाट graceful recovery मा बदल्दछन्।

चार असफलता patterns

हरेक LLM service लाई चार defenses चाहिन्छ:

  1. Timeouts — कुनै call ले सदाको लागि नलिने ग्यारेन्टी।
  2. Retries with backoff — transient failures सम्हाल्ने pattern।
  3. Fallbacks — जब primary path टुटेको हुन्छ के गर्ने।
  4. ईमानदार user messages — प्रयोगकर्ताहरूलाई के भयो भन्ने सानो दयालुता।

एकसाथ तिनीहरूले “API असफल भयो” लाई P0 incident बाट अस्थायी रूपमा degraded अनुभवमा बदल्दछन्।

Pattern 1 — Timeouts

एकल सबैभन्दा-छोडिने pattern। Timeout बिना, एक slow मोडेल call ले तपाईंको worker लाई 60 सेकेन्ड होल्ड गर्न सक्दछ, capacity लाई बाँध्दै र हरेक अन्य प्रयोगकर्ताको request मा ढिलाइ हुन्छ। एक मरेको API ले सधैँको लागि requests block गर्न सक्दछ।

हरेक बाह्य call मा एक hard timeout सेट गर्नुहोस्:

import httpx
from anthropic import Anthropic

# Anthropic SDK accepts a timeout parameter
client = Anthropic(timeout=30.0)  # 30-second timeout

response = client.messages.create(
    model="claude-3-5-sonnet-latest",
    max_tokens=500,
    messages=[...],
    # per-call override:
    # timeout=15.0,
)

अधिकांश LLM calls को लागि, 30-60 सेकेन्ड उचित cap हो। यदि तपाईंको service लाई लामो चाहिन्छ भने (धेरै लामा documents, image analysis), त्यो endpoint को लागि cap उठाउनुहोस् तर यसलाई bounded राख्नुहोस्।

आफ्नो web server मा whole-request timeout पनि सेट गर्नुहोस्। FastAPI + uvicorn को लागि:

uvicorn service:app --timeout-keep-alive 60

Pattern 2 — Retries with backoff

केही failures transient हुन्छन्। API ले 503 फर्कायो, वा request timeout भयो। पुन: प्रयास प्राय: सफल हुन्छ। तर हरेक failure retry हुनु हुँदैन:

  • Retry: 429 (rate limit), 500-599 (server errors), 408 (timeout)।
  • Retry नगर्ने: 400 (bad request — retry ले मद्दत गर्दैन), 401/403 (auth), 404 (not found), 422 (validation)।

Retry गर्ने सही तरिका — exponential backoff र jitter सँग (Course 04 खण्ड 2.3 बाट):

import random
import time
from anthropic import APIError, APIStatusError

def call_with_retry(fn, max_retries=3):
    for attempt in range(max_retries):
        try:
            return fn()
        except APIStatusError as e:
            if e.status_code not in {429, 500, 502, 503, 504}:
                raise  # non-retryable
            if attempt == max_retries - 1:
                raise
            wait = 2 ** attempt + random.uniform(0, 1)
            time.sleep(wait)
        except APIError:
            if attempt == max_retries - 1:
                raise
            wait = 2 ** attempt + random.uniform(0, 1)
            time.sleep(wait)

Anthropic र OpenAI SDKs दुबैसँग built-in retry छ — तर तिनीहरूले fixed retry counts प्रयोग गर्दछन्, र आफ्नो retry लाई SDK को साथ mix गर्नुले प्राय: अप्रत्याशित delays उत्पादन गर्दछ। एउटा छनोट गर्नुहोस्। यदि तपाईंले SDK retries प्रयोग गर्नुहुन्छ भने, max_retries स्पष्ट रूपमा सेट गर्नुहोस्।

Retries ले latency थप्दछन्। एक single call जुन 2 s लाग्यो त्यो दुई retries पछि 2 s + 4 s + 8 s = 14 s call बन्दछ। प्रयोगकर्ताहरूले नोटिस गर्दछन्। कुल समय bounded हुनको लागि retries लाई per-request timeout सँग combine गर्नुहोस्।

Pattern 3 — Fallbacks

जब primary path टुटेको हुन्छ, तपाईं सट्टामा के प्रस्ताव गर्नुहुन्छ?

Provider fallback। Anthropic down छ, त्यसैले OpenAI मा route गर्नुहोस्। दुई SDKs र equivalent prompts चाहिन्छ, तर यसले तपाईंलाई provider outages बाट सुरक्षित गर्दछ:

def call_llm(prompt: str) -> str:
    try:
        return call_anthropic(prompt)
    except (APIError, TimeoutError):
        log_event("provider_fallback", from_="anthropic", to="openai")
        return call_openai(prompt)

Model fallback। Sonnet timeout हुँदैछ; Haiku मा degrade गर्नुहोस् (छिटो, सस्तो, थोरै कम quality)। प्रयोगकर्ताहरूले जवाफ पाउँछन्; तपाईंले incident को बेला सानो quality hit स्वीकार्नुहुन्छ।

Static fallback। एउटा सानो FAQ माथि शुद्ध Q&A को लागि, जब मोडेल down छ, FAQ माथि keyword search मा fall back गर्नुहोस् र top match फर्काउनुहोस्। प्रयोगकर्ताहरूले उपयोगी जानकारी पाउँछन्; तपाईंले शून्य cost पाउनुहुन्छ।

Explicit degradation message। यदि माथिको कुनै viable छैन भने, एक स्पष्ट सन्देश फर्काउनुहोस्: “हाम्रो AI अहिले समस्यामा छ। कृपया केही मिनेटमा फेरि प्रयास गर्नुहोस्।”

हरेक service ले कम्तिमा अन्तिम एक बाट लाभ पाउँछ। Provider र model fallbacks revenue-critical products को लागि यो लायकको छ।

Pattern 4 — ईमानदार user messages

जब केही असफल हुन्छ र तपाईं पूर्ण रूपमा recover गर्न सक्नुहुन्न, प्रयोगकर्तालाई के भयो भन्नुहोस्। तुलना गर्नुहोस्:

खराब:

Error 500. Something went wrong.

अर्को तरिकाले खराब:

An error occurred while processing your request. Please contact
support with error code: NUL-4192-OP-8283-FAIL-99.

राम्रो:

Our AI assistant is running slowly right now. Please try again in
a minute. If this keeps happening, let us know at
support@nepse-mitra.np and we'll fix it fast.

राम्रो failure सन्देशका तीन भागहरू:

  1. के भयो, plain language मा।
  2. प्रयोगकर्ताले के गर्नुपर्दछ (फेरि प्रयास गर्नुहोस्, पर्खनुहोस्, हामीलाई सम्पर्क गर्नुहोस्)।
  3. मान्छे सम्म पुग्ने तरिका, यदि यो matter गर्दछ।

नेपाली प्रयोगकर्ताहरूको लागि, सन्देश नेपाली र अंग्रेजी दुबैमा प्रस्ताव गर्नुहोस्:

हाम्रो AI सहायक अहिले बिस्तारै चलिरहेको छ। एक मिनेटमा फेरि प्रयास गर्नुहोस्।

Our AI assistant is running slowly right now. Please try again in a minute.

Bilingual सन्देशले हेरचाह संकेत गर्दछ। यसलाई उत्पादन गर्न केही खर्च हुँदैन र यसले प्रयोगकर्ताहरू retain गर्दछ।

Layered defence

एउटा real endpoint को लागि चार patterns एक साथ राख्दै:

@app.post("/summarise")
def summarise(req: SummariseRequest, user_id: str = Depends(get_current_user)):
    request_id = str(uuid.uuid4())

    # Boundary checks (from Section 1.2)
    if len(req.text) > MAX_INPUT_CHARS:
        raise HTTPException(400, "Text too long.")

    if not check_and_record_usage(user_id):
        raise HTTPException(429, "Daily quota reached.")

    # The main path, with defence
    try:
        summary = call_with_retry(
            lambda: call_llm_with_timeout(build_prompt(req), timeout=30)
        )
    except (APIError, TimeoutError) as e:
        log_event("primary_failed", request_id=request_id, error=str(e))

        # Fallback: try a lighter model
        try:
            summary = call_llm(build_prompt(req), model=FALLBACK_MODEL)
            log_event("fallback_used", request_id=request_id, model=FALLBACK_MODEL)
        except Exception:
            # Full failure — return an honest error
            raise HTTPException(
                status_code=503,
                detail="Our AI is having trouble right now. Please try again in a few minutes.",
            )

    return SummariseResponse(summary=summary, input_length=len(req.text))

हरेक layer को उद्देश्य छ। हरेक failure को recovery path छ। प्रयोगकर्ताले हरेक fallback प्रयास गरिसकेपछि मात्र ईमानदार error message देख्दछन्।

सामान्य failure modes र तिनको fixes

एक छोटो सूची:

मोडेलले garbled वा empty output फर्काउँछ।

  • Fix: फर्काउनुभन्दा पहिले validate गर्नुहोस्। यदि output empty छ वा basic sanity check असफल हुन्छ भने, यसलाई failure रूपमा उपचार गर्नुहोस् र retry गर्नुहोस् (वा fall back गर्नुहोस्)।

Retrieval ले केही फर्काउँदैन।

  • Fix: यदि top_score threshold भन्दा तल छ भने, LLM लाई असम्बन्धित कागजात फीड गर्नुको सट्टा प्रयोगकर्तालाई “मलाई थाहा छैन” भन्नुहोस्।

Prompt context window भन्दा लामो छ।

  • Fix: call भन्दा पहिले token count जाँच गर्नुहोस्; history वा documents truncate गर्नुहोस्; truncation log गर्नुहोस् ताकि तपाईं chronic offenders को लागि हेर्न सक्नुहुन्छ।

प्रयोगकर्ताको IP address त्यहाँ छ जहाँ provider ले अनुमति दिँदैन।

  • Fix: तपाईंको service मार्फत request proxy गर्नुहोस् (जुन एउटा allowed IP मा छ)। कहिल्यै provider API keys लाई client मा expose नगर्नुहोस्।

Provider ले तपाईंले प्रयोग गरिरहेको मोडेल deprecates गर्दछ।

  • Fix: provider deprecation notices monitor गर्नुहोस्; समयमै candidate replacements test गर्नुहोस्; आफ्नो model choice version गर्नुहोस् (Chapter 5)।

यीमध्ये हरेकले real projects हिट गरेको छ। हरेक थोरै मात्रामा defensive design सँग रोक्न सकिन्छ।

Reliability mindset

यसको मूलमा, graceful failure एक mindset हो: कुरा गलत हुनेछन् भन्ने मान्नुहोस्, र failure mode ठिकै छ भनेर सुनिश्चित गर्नुहोस्। Perfect होइन। अदृश्य होइन। बस ठीक।

  • Slow API? Timeout, retry, fall back, ईमानदार सन्देश।
  • खराब input? सीमामा स्वच्छ रूपमा अस्वीकार गर्नुहोस्।
  • Model down? सानो model मा fall back गर्नुहोस्; त्यो असफल भएमा, व्याख्या गर्नुहोस् र अगाडि बढ्नुहोस्।
  • प्रयोगकर्ता भ्रमित? interaction log गर्नुहोस् र FAQ सुधार गर्नुहोस्।

यीमध्ये कुनैले failure रोक्दैन। तिनीहरू सबैले failure लाई catastrophe हुनबाट रोक्दछन्। प्रयोगकर्ताहरूले क्षणिक degradation सहन्छन्। तिनीहरूले रहस्यमय silence, भ्रमित errors, वा बस गायब हुने systems सहँदैनन्।

आफ्नो बुझाइ जाँच्नुहोस्

Quick check

एक टिमले LLM timeout बिना chatbot ship गर्दछ। Provider को slow morning छ, र calls जुन 2 सेकेन्ड लिन्थे अब 45 सेकेन्ड लिन्छन्। systemic परिणाम के हो?

Quick check

असफल LLM call retry गर्ने सही policy यीमध्ये कुन हो?

अब के आउँछ

तपाईंको service भरोसायोग्य छ। यो खराब परिस्थितिहरूमा up रहन्छ। अब गाह्रो प्रश्न: के यो राम्रो छ? Chapter 4 ले तपाईंको AI प्रणालीलाई production मा evaluate गर्ने discipline सुरु गर्दछ — तपाईंको मोडेलले वास्तवमै मानिसहरूलाई सही जवाफहरू दिइरहेको छ कि छैन थाहा पाउने, र जब यो छैन fix गर्न पर्याप्त छिटो थाहा पाउने।