# PaddleOCR + PP-ChatOCR + LLM 联调 Runbook（V1）

本手册用于把阶段 2 的“真实联调”落到可重复执行的步骤，尽量与当前 Java 侧实现行为对齐。

## 1. 环境与服务前置检查

1. 启动 OCR 平台后端

```bash
cd /Users/alphaPlanet/vibecoding/ocr-platform
cd backend
mvn spring-boot:run
```

2. 确认后端配置生效

```bash
curl -s http://127.0.0.1:18090/actuator/health | jq
curl -s http://127.0.0.1:18090/api/v1/engines | jq
```

- `OCR_PLATFORM` 启动日志建议包含：数据库迁移、默认引擎、任务扫描。
- `GET /api/v1/engines` 中，`paddle-layout` 在 `available=true` 时表示已接入 PaddleOCR 主结构链路。
- 如果启用了 `PP_CHAT_OCR_ENABLED=true`，`pp-chatocr` 在 `available=true` 时表示已接入 PP-ChatOCR 视觉和语义链路。

3. 检查算法端点连通（按你部署方式替换主机）

```bash
curl -i http://192.168.1.13:18080/health
curl -i http://192.168.1.13:18083/health
```

4. 若接 Paddle 结构链路，同步确认

```bash
curl -i http://192.168.1.13:18080/layout-parsing
```

## 2. 平台配置核对

在 `backend/src/main/resources/application.yml` 或对应环境变量中确认：

- `OCR_ENGINE_DEFAULT_CODE=paddle-layout`
- `PADDLE_LAYOUT_ENABLED=true`
- `PADDLE_LAYOUT_ENDPOINT=http://192.168.1.13:18080/layout-parsing`
- `PADDLE_LAYOUT_TIMEOUT=60s`（按实际链路调整）
- 如果要验证 PP-ChatOCR 语义抽取，再设置 `PP_CHAT_OCR_ENABLED=true`
- `PP_CHAT_OCR_VISUAL_ENDPOINT=http://192.168.1.13:18083/chatocr-visual`
- `PP_CHAT_OCR_CHAT_ENDPOINT=http://192.168.1.13:18083/chatocr-chat`
- `PP_CHAT_OCR_EXTRACTION_KEYS=经营者名称,申请日期,经营场所地址`
- 算法端：若接入 LLM，请同步 `PADDLEOCR_CHAT_BOT_*` 与 `chatBotConfig` 注入参数

> 说明：本项目未强制要求 `PADDLEOCR_*` 必须都在 Java 层配置；如果 PP-ChatOCR 的 `/chatocr-chat` 依赖大模型，请将等价配置按算法服务侧要求注入到算法容器。

## 3. 上传样张执行基础联调

1. 上传一张真实样张

```bash
curl -s -F "sourceSystem=WINDOW_APP" \
  -F "businessType=FOOD_BUSINESS_LICENSE" \
  -F "templateCode=FORM_FOOD_LICENSE_V1" \
  -F "priority=10" \
  -F "file=@/path/to/sample.jpg" \
  http://127.0.0.1:18090/api/v1/ocr/tasks | jq
```

2. 记录响应中的 `taskId`，等待任务状态变为 `COMPLETED`。

3. 获取详情并校验 `latestRunNo` 与 run 回放数据：

```bash
curl -s http://127.0.0.1:18090/api/v1/ocr/tasks/${TASK_ID}/detail | jq
curl -s http://127.0.0.1:18090/api/v1/ocr/tasks/${TASK_ID}/raw-results | jq
curl -s http://127.0.0.1:18090/api/v1/ocr/tasks/${TASK_ID}/text-blocks | jq
curl -s http://127.0.0.1:18090/api/v1/ocr/tasks/${TASK_ID}/key-values | jq
```

关键信息核对：

- `raw-results` 中 `runNo` 是否为 `1` 且有 `requestPayloadJson`。
- `raw-results` 中有 `elapsedMs`，且成功时 `errorCode` / `errorMessage` 为空。
- 键值字段命中率体现在 `extractionQuality.hitRate`、`extractedFieldCount`。
- `manualCorrectionRate` 基于 `reviewStatus != PENDING` 的比例。

## 4. 对比不同参数配置（多 run）

1. 修改 `PADDLE_LAYOUT_*`、`PP_CHAT_OCR_*` 或后端默认引擎参数。
2. 重复上传同一张样张并记录 `runNo`。
3. 比较同一 `taskId` 下不同 `runNo` 的输出（建议字段、置信度和原始 raw-json）：

```bash
curl -s "http://127.0.0.1:18090/api/v1/ocr/tasks/${TASK_ID}/raw-results" | jq 'map({runNo, engineCode, engineVersion, createdAt, elapsedMs, errorCode})'
curl -s "http://127.0.0.1:18090/api/v1/ocr/tasks/${TASK_ID}/key-values" | jq 'group_by(.runNo) | map({runNo: .[0].runNo, count: length})'
```

## 5. LLM 配置校验点

当 LLM 未配置时，不应静默返回空键值而无原因：

- 成功返回时应带有有意义的 `keyValues` / 明确失败原因；
- `raw-results` 中应能追踪到失败上下文（`errorMessage`）或成功链路中的 `requestPayloadJson`；
- 若算法侧返回 LLM 相关错误，后端应将错误码写入 `raw-result.error_code`。

## 6. 回填链路抽查

将任务与模板进行回填映射，验证取值是否来自最新 `runNo`：

```bash
curl -s "http://127.0.0.1:18090/api/fill-data/${TASK_ID}/form3" | jq
```

检查点：

- 未命中字段以 `warnings` 告警；
- 业务表单映射中默认优先采用最新 `runNo` 的标准键值；
- `value` 来源与 `reviewStatus` 与前置抽取结果一致。

## 7. 失败与重试可见性（可选）

如果识别失败：

- 查看是否写入 `TASK_RETRY_SCHEDULED` 或 `TASK_FAILED`。
- 确认 `raw-results` 有错误记录、`runNo` 连续递增。
- 验证异常信息可回溯到 `errorCode` / `errorMessage`。
