Tối ưu cấu hình httpx để xử lý lỗi Timeout khi gọi API Large Language Model (LLM)

Khi triển khai các kịch bản gọi API từ các mô hình ngôn ngữ lớn (LLM) như GPT-4 hay Claude với số lượng yêu cầu lớn, lập trình viên thường xuyên gặp phải các lỗi như httpx.ReadTimeout, httpx.ConnectTimeout hoặc RemoteProtocolError. Những lỗi này thường xuất hiện ngẫu nhiên sau khi hệ thống đã chạy được một thời gian, gây gián đoạn quy trình xử lý dữ liệu hàng loạt.

Nguyên nhân gây ra lỗi Timeout và kết nối

Thư viện httpx (được sử dụng bên dưới OpenAI SDK và nhiều thư viện Python khác) có các thiết lập mặc định khá khắt khe, không phù hợp với đặc thù phản hồi chậm của các mô hình AI:

  • Thời gian phản hồi lâu: Các mô hình LLM có thể mất từ 30 đến 90 giây để hoàn thành một lượt tạo văn bản dài, trong khi httpx mặc định giới hạn read timeout chỉ 5 giây.
  • Giới hạn Pool kết nối: Mặc định httpx chỉ cho phép 100 kết nối đồng thời và 20 kết nối ở trạng thái keep-alive. Khi chạy tác vụ song song cao, các yêu cầu mới phải đợi kết nối cũ giải phóng, dẫn đến PoolTimeout.
  • Vấn đề HTTP/2: Việc duy trì kết nối HTTP/2 đôi khi gặp lỗi RemoteProtocolError nếu phía server ngắt kết nối trước mà client không kịp nhận diện.

Cấu hình httpx tối ưu cho LLM

Để khắc phục triệt để các vấn đề trên, bạn cần tinh chỉnh Timeout, Limits và cơ chế Transport. Dưới đây là cách thiết lập Client tối ưu cho môi trường Production:

import httpx
from openai import OpenAI

# Tùy chỉnh cấu hình httpx Client
custom_http_client = httpx.Client(
    # Tăng thời gian chờ cho các giai đoạn khác nhau
    timeout=httpx.Timeout(
        connect=15.0,  # Thời gian thiết lập kết nối
        read=150.0,    # Thời gian chờ phản hồi (quan trọng nhất cho LLM)
        write=15.0,
        pool=45.0      # Thời gian đợi lấy kết nối từ pool
    ),
    # Mở rộng quy mô pool kết nối
    limits=httpx.Limits(
        max_connections=300,
        max_keepalive_connections=100,
        keepalive_expiry=30.0
    ),
    # Cấu hình cơ chế truyền tải
    transport=httpx.HTTPTransport(retries=3),
    # Ưu tiên HTTP/1.1 để tăng tính ổn định nếu HTTP/2 gây lỗi ngắt quãng
    http2=False,
)

# Tích hợp vào OpenAI SDK
ai_provider_client = OpenAI(
    api_key="your_api_key_here",
    http_client=custom_http_client,
    max_retries=2, # Số lần thử lại ở cấp độ SDK (cho lỗi 429, 5xx)
)

Phân tích các thông số quan trọng

  1. Read Timeout (150s): Giá trị này nên được đặt lớn hơn thời gian sinh văn bản tối đa của mô hình. Với các mô hình mạnh như GPT-4o hoặc Claude 3.5 Sonnet khi yêu cầu output dài, 150 giây là mức an toàn.
  2. keepalive_expiry (30s): Việc đặt thời gian hết hạn keep-alive ngắn giúp client chủ động đóng các kết nối cũ, tránh hiện tượng server ngắt kết nối đột ngột gây lỗi RemoteProtocolError.
  3. Vô hiệu hóa HTTP/2: Mặc dù HTTP/2 nhanh hơn nhờ đa luồng trên một kết nối, nhưng nếu kết nối đó gặp trục trặc, tất cả các request đang chạy trên đó sẽ thất bại. Chuyển về HTTP/1.1 giúp cô lập lỗi tốt hơn.
  4. Retries tại Transport: Đây là cơ chế thử lại ở tầng mạng (lỗi DNS, lỗi kết nối vật lý), khác với cơ chế retry của SDK (thường xử lý lỗi logic hoặc rate limit).

Áp dụng với các thư viện khác (requests, aiohttp)

Nếu dự án của bạn không sử dụng httpx, các tham số cấu hình vẫn cần tuân theo logic tương tự.

Ví dụ với Requests

import requests
from requests.adapters import HTTPAdapter
from urllib3.util import Retry

session = requests.Session()
# Cấu hình retry cho các mã trạng thái lỗi phổ biến
retry_strategy = Retry(
    total=4,
    backoff_factor=1,
    status_forcelist=[429, 500, 502, 503, 504],
)
adapter = HTTPAdapter(
    pool_connections=100,
    pool_maxsize=300,
    max_retries=retry_strategy
)
session.mount("https://", adapter)

response = session.post(
    "https://api.openai.com/v1/chat/completions",
    json={"model": "gpt-4", "messages": [...]},
    timeout=(15, 150) # (connect_timeout, read_timeout)
)

Ví dụ với aiohttp (Bất đồng bộ)

import aiohttp
import asyncio

async def call_llm_api():
    # Cấu hình timeout và connector
    session_timeout = aiohttp.ClientTimeout(
        total=180,
        sock_connect=15,
        sock_read=150
    )
    conn = aiohttp.TCPConnector(
        limit=300,
        limit_per_host=100,
        keepalive_timeout=30
    )

    async with aiohttp.ClientSession(
        timeout=session_timeout,
        connector=conn
    ) as session:
        async with session.post(url, json=data) as resp:
            return await resp.json()

Bảng tra cứu lỗi và hướng xử lý

Mã lỗi / Thông báo Nguyên nhân phổ biến Giải pháp đề xuất
ConnectTimeout Sự cố mạng hoặc DNS chậm Tăng connect timeout lên 10-15s
ReadTimeout Mô hình sinh phản hồi quá lâu Tăng read timeout lên >120s
PoolTimeout Số lượng thread/async task vượt quá pool Tăng max_connections
RemoteProtocolError Server ngắt kết nối HTTP/2 hoặc Keep-alive Tắt HTTP/2, giảm keepalive_expiry
RateLimitError (429) Vượt quá giới hạn gói API Sử dụng Exponential Backoff khi retry

Thẻ: httpx openai-api python-requests aiohttp llm-optimization

Đăng vào ngày 14 tháng 11 lúc 17:06