# LeAudit 并发与重试参数说明

这份文档记录当前 `leaudit-platform` 已经落地的并发与重试参数，避免后面再忘。

---

## 1. 为什么没有用 `RETRY_BACKOFF_SECONDS = [1, 2, 4]`

这次我没有把退避时间设计成数组，而是改成了：

- `*_RETRY_MAX_ATTEMPTS`
- `*_RETRY_BACKOFF_BASE_SECONDS`

原因很简单：

- 配置更短，更容易看懂
- 不用每次都手写 `[1, 2, 4]`
- 代码统一按“指数退避”算等待时间

计算方式：

```text
第 1 次重试等待 = base
第 2 次重试等待 = base * 2
第 3 次重试等待 = base * 4
...
```

例如：

```toml
LLM_RETRY_MAX_ATTEMPTS = 3
LLM_RETRY_BACKOFF_BASE_SECONDS = 1
```

表示：

- 第 1 次请求失败后，等 `1s`
- 第 2 次再失败后，等 `2s`
- 总共最多尝试 `3` 次

---

## 2. 当前已正式化的参数

当前 `app.toml` 中已启用：

```toml
[LEAUDIT]
LLM_MAX_CONCURRENCY = 5
VLM_MAX_CONCURRENCY = 3

LLM_REQUEST_TIMEOUT = 120
LLM_RETRY_MAX_ATTEMPTS = 3
LLM_RETRY_BACKOFF_BASE_SECONDS = 1

VLM_REQUEST_TIMEOUT = 45
VLM_RETRY_MAX_ATTEMPTS = 2
VLM_RETRY_BACKOFF_BASE_SECONDS = 1

OCR_VLM_CONCURRENCY = 32
OCR_RETRY_MAX_ATTEMPTS = 3
OCR_RETRY_BACKOFF_BASE_SECONDS = 1

SIGNATURE_PROBE_CONCURRENCY = 2
SIGNATURE_PROBE_TIMEOUT = 20
SIGNATURE_PROBE_RETRY_MAX_ATTEMPTS = 2
SIGNATURE_PROBE_RETRY_BACKOFF_BASE_SECONDS = 0.5
```

---

## 3. 各链路当前策略

### 3.1 LLM

- 客户端：`ResilientOpenAICompatibleClient`
- 超时：`LLM_REQUEST_TIMEOUT`
- 最大尝试次数：`LLM_RETRY_MAX_ATTEMPTS`
- 退避基数：`LLM_RETRY_BACKOFF_BASE_SECONDS`
- 重试条件：
  - 超时
  - 连接错误
  - `5xx`
  - `408`
  - `429`

### 3.2 VLM

- 客户端：`ResilientQwenVLMClient`
- 超时：`VLM_REQUEST_TIMEOUT`
- 最大尝试次数：`VLM_RETRY_MAX_ATTEMPTS`
- 退避基数：`VLM_RETRY_BACKOFF_BASE_SECONDS`
- 重试条件：
  - 超时
  - 连接错误
  - `5xx`
  - `408`
  - `429`

### 3.3 OCR

- 客户端：`ResilientChandraOCRClient`
- OCR HTTP 超时：沿用 `[OCR].TIMEOUT`
- 最大尝试次数：`OCR_RETRY_MAX_ATTEMPTS`
- 退避基数：`OCR_RETRY_BACKOFF_BASE_SECONDS`
- 重试条件：
  - 超时
  - 连接错误
  - `5xx`
  - `408`
  - `429`

### 3.4 Signature Probe

这是 DOCX 签名候选补识别，不是主 OCR。

- 并发：`SIGNATURE_PROBE_CONCURRENCY`
- 单次超时：`SIGNATURE_PROBE_TIMEOUT`
- 最大尝试次数：`SIGNATURE_PROBE_RETRY_MAX_ATTEMPTS`
- 退避基数：`SIGNATURE_PROBE_RETRY_BACKOFF_BASE_SECONDS`
- 第 1 次失败后，会用 fresh VLM client 再试

---

## 4. 为什么把 signature probe 调小

之前这里容易长时间卡住，根因是：

- 它是补探测
- 但单次超时太长
- 且失败后还会再试一次

所以现在把它收成：

- `SIGNATURE_PROBE_CONCURRENCY = 2`
- `SIGNATURE_PROBE_TIMEOUT = 20`

这样它仍然能补识别，但不会把整条 OCR 长尾拖得太夸张。

---

## 5. 当前代码位置

- 配置定义：`fastapi_admin/config/_settings.py`
- 客户端工厂：`fastapi_modules/fastapi_leaudit/leaudit_bridge/client_factory.py`
- 重试封装：`fastapi_modules/fastapi_leaudit/leaudit_bridge/resilient_clients.py`
- signature probe：`fastapi_modules/fastapi_leaudit/leaudit_bridge/ocr_bridge.py`

