在開發 AI 應用的過程中,你一定遇過這些狀況:API 突然超時、模型回應格式錯誤、Token 限制爆掉、服務暫時不可用...今天我們要深入探討如何優雅地處理這些錯誤,讓你的 AI 應用更加穩定可靠。
AI 應用與傳統應用最大的差異在於其不確定性:
import openai
from openai import OpenAI
client = OpenAI()
try:
    response = [client.chat](http://client.chat).completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": "Hello"}]
    )
except openai.APIConnectionError as e:
    print(f"網路連線失敗:{e.__cause__}")
    # 實作重連邏輯
except openai.APITimeoutError as e:
    print(f"請求超時:{e}")
    # 考慮增加 timeout 或簡化請求
import time
from tenacity import retry, wait_exponential, stop_after_attempt
@retry(
    wait=wait_exponential(multiplier=1, min=4, max=60),
    stop=stop_after_attempt(5)
)
def call_api_with_retry():
    try:
        response = [client.chat](http://client.chat).completions.create(
            model="gpt-4o",
            messages=[{"role": "user", "content": "分析這段文字..."}]
        )
        return response
    except openai.RateLimitError as e:
        print(f"達到速率限制:{e.status_code}")
        # 從 response header 取得 retry-after
        retry_after = e.response.headers.get("retry-after")
        if retry_after:
            time.sleep(int(retry_after))
        raise  # 重新拋出異常讓 retry 裝飾器處理
import json
from typing import Dict, Any
class OutputParser:
    def __init__(self, max_retries=3):
        self.max_retries = max_retries
    
    def parse_json_response(self, text: str, llm_client) -> Dict[str, Any]:
        """嘗試解析 JSON,失敗時要求 LLM 修正"""
        
        for attempt in range(self.max_retries):
            try:
                # 嘗試解析 JSON
                return json.loads(text)
            except json.JSONDecodeError as e:
                if attempt == self.max_retries - 1:
                    # 最後一次嘗試失敗,返回錯誤
                    raise ValueError(f"無法解析 JSON: {e}")
                
                # 要求 LLM 修正格式
                repair_prompt = f"""
                以下 JSON 格式有誤,請修正並只回傳正確的 JSON:
                
                錯誤訊息:{str(e)}
                原始內容:{text}
                
                請只回傳修正後的 JSON,不要加任何說明。
                """
                
                response = llm_[client.chat](http://client.chat).completions.create(
                    model="gpt-4o-mini",
                    messages=[{"role": "user", "content": repair_prompt}],
                    temperature=0
                )
                
                text = response.choices[0].message.content
                print(f"嘗試修復 JSON (第 {attempt + 1} 次)")
        
        return {}
import httpx
from openai import OpenAI
# 細緻的超時控制
client = OpenAI(
    timeout=httpx.Timeout(
        connect=5.0,      # 連線超時
        read=30.0,        # 讀取超時
        write=10.0,       # 寫入超時
        pool=2.0          # 連線池超時
    ),
    max_retries=3        # 自動重試次數
)
# 針對特定請求調整設定
response = client.with_options(
    timeout=60.0,  # 長文本處理需要更多時間
    max_retries=5
).chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "處理這份長文件..."}]
)
from typing import Optional, List
from dataclasses import dataclass
@dataclass
class ModelConfig:
    name: str
    max_tokens: int
    cost_per_1k: float
class AIServiceWithFallback:
    def __init__(self):
        # 設定模型優先順序
        self.models = [
            ModelConfig("gpt-4o", 128000, 0.005),
            ModelConfig("gpt-4o-mini", 128000, 0.00015),
            ModelConfig("gpt-3.5-turbo", 16385, 0.0005)
        ]
        self.client = OpenAI()
    
    def complete(self, prompt: str, max_retries: int = 2) -> Optional[str]:
        """嘗試使用不同模型完成請求"""
        errors = []
        
        for model in self.models:
            for attempt in range(max_retries):
                try:
                    response = [self.client.chat](http://self.client.chat).completions.create(
                        model=[model.name](http://model.name),
                        messages=[{"role": "user", "content": prompt}],
                        max_tokens=min(1000, model.max_tokens)
                    )
                    print(f"成功使用 {[model.name](http://model.name)}")
                    return response.choices[0].message.content
                    
                except openai.APIStatusError as e:
                    error_msg = f"{[model.name](http://model.name)} 失敗 (嘗試 {attempt + 1}): {e}"
                    errors.append(error_msg)
                    print(error_msg)
                    
                    # 如果是 token 限制錯誤,直接換模型
                    if e.status_code == 400 and "token" in str(e).lower():
                        break
                    
                    # 其他錯誤等待後重試
                    if attempt < max_retries - 1:
                        time.sleep(2 ** attempt)  # 指數退避
        
        # 所有嘗試都失敗
        raise Exception(f"所有模型都失敗:\n" + "\n".join(errors))
import logging
from datetime import datetime
from typing import Any, Dict
import json
class AIErrorMonitor:
    def __init__(self, log_file="ai_errors.log"):
        # 設定日誌
        logging.basicConfig(
            filename=log_file,
            level=[logging.INFO](http://logging.INFO),
            format='%(asctime)s - %(levelname)s - %(message)s'
        )
        self.logger = logging.getLogger(__name__)
        
        # 錯誤統計
        self.error_stats = {
            "total_requests": 0,
            "successful_requests": 0,
            "errors_by_type": {},
            "errors_by_model": {}
        }
錯誤處理是 AI 應用成熟度的重要指標。一個優秀的錯誤處理系統不僅能提升使用者體驗,還能節省開發時間和營運成本。記住,錯誤不可避免,但我們可以優雅地處理它們。