# 错误码清单与处理策略

## 1. 错误码体系

### 1.1 错误码分类

- **4xx 系列**：客户端错误（上游调用方问题）
- **5xx 系列**：服务端错误（本服务或依赖服务问题）

### 1.2 错误响应结构

```json
{
  "error_code": "MISSING_INPUT_PARAMS",
  "message": "human-readable error message",
  "details": {
    // 可选：额外的错误详情
  },
  "trace_id": "3f5d6c1c-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```

---

## 2. 客户端错误码（4xx）

### 2.1 INVALID_REQUEST（400）

**含义**：请求参数不合法

**触发条件**：
- 必填字段缺失（kn_id/ot_id/query/unique_identities/properties）
- 参数类型错误（如 properties 不是数组）
- unique_identities 为空数组

**返回示例**：
```json
{
  "error_code": "INVALID_REQUEST",
  "message": "参数 properties 不能为空数组",
  "trace_id": "..."
}
```

**处理建议**：上游检查参数完整性后重试

---

### 2.2 MISSING_INPUT_PARAMS（400）

**含义**：LLM 无法从上下文生成某些 value_from="input" 的参数

**触发条件**：
- query/additional_context 信息不足以推断某些必需参数
- now_ms 缺失且无法生成时间相关参数（理论上不应发生，因为服务端会兜底）

**返回示例**：
```json
{
  "error_code": "MISSING_INPUT_PARAMS",
  "message": "dynamic_params 缺少必需的 input 参数",
  "missing": [
    {
      "property": "approved_drug_count",
      "params": [
        {
          "name": "start",
          "type": "INTEGER",
          "hint": "在 additional_context 中补充明确时间范围（start/end 或 "最近半年"），或在 query 中明确时间范围"
        }
      ]
    }
  ],
  "trace_id": "..."
}
```

**处理建议**：
1. 根据 `hint` 补充 `additional_context`
2. 或追问用户获取缺失信息
3. 重新调用本接口

---

### 2.3 INVALID_PROPERTY（400）

**含义**：请求的 property 在对象类定义中不存在或不是 logic_property

**触发条件**：
- properties 中包含不存在的属性名
- properties 中包含 data_property（MVP 不支持混合查询）

**返回示例**：
```json
{
  "error_code": "INVALID_PROPERTY",
  "message": "属性 invalid_property_name 在对象类 company 中不存在或不是逻辑属性",
  "details": {
    "invalid_properties": ["invalid_property_name"],
    "valid_logic_properties": ["approved_drug_count", "business_health_score"]
  },
  "trace_id": "..."
}
```

**处理建议**：上游检查 properties 列表后重试

---

### 2.4 OBJECT_TYPE_NOT_FOUND（404）

**含义**：指定的对象类不存在

**触发条件**：
- ontology-manager 返回 404（kn_id 或 ot_id 不存在）

**返回示例**：
```json
{
  "error_code": "OBJECT_TYPE_NOT_FOUND",
  "message": "对象类 company 在知识网络 kn_medical 中不存在",
  "trace_id": "..."
}
```

**处理建议**：上游检查 kn_id/ot_id 是否正确

---

## 3. 服务端错误码（5xx）

### 3.1 LLM_CALL_FAILED（500）

**含义**：LLM 调用失败（已重试仍失败）

**触发条件**：
- LLM 服务返回 5xx 错误（已重试 max_retry 次）
- LLM 服务响应超时（已重试 max_retry 次）
- LLM 服务返回非 JSON 输出（已执行 max_repair_rounds 修复仍失败）

**返回示例**：
```json
{
  "error_code": "LLM_CALL_FAILED",
  "message": "LLM 调用失败（已重试 2 次）",
  "details": {
    "property": "approved_drug_count",
    "llm_error": "timeout after 10s",
    "attempts": 3
  },
  "trace_id": "..."
}
```

**处理建议**：
- 短期：上游重试整个请求
- 长期：排查 LLM 服务稳定性或提示词问题

---

### 3.2 LLM_OUTPUT_INVALID（500）

**含义**：LLM 输出不符合预期格式（JSON 修复后仍不合法）

**触发条件**：
- LLM 输出不是合法 JSON（已执行 max_repair_rounds 修复仍失败）
- LLM 输出的 JSON 结构不符合约束（如缺少顶层 property key）
- step 枚举值非法（不在 day/week/month/quarter/year 中）

**返回示例**：
```json
{
  "error_code": "LLM_OUTPUT_INVALID",
  "message": "LLM 输出格式不合法（已尝试修复 1 次）",
  "details": {
    "property": "approved_drug_count",
    "validation_error": "step 值 'monthly' 不在枚举范围内（应为 day/week/month/quarter/year）",
    "llm_output": "{ \"approved_drug_count\": { \"step\": \"monthly\" } }"
  },
  "trace_id": "..."
}
```

**处理建议**：
- 短期：上游重试（LLM 有随机性可能成功）
- 长期：排查提示词设计或补充约束

---

### 3.3 ONTOLOGY_MANAGER_ERROR（502）

**含义**：ontology-manager 服务调用失败

**触发条件**：
- ontology-manager 返回 5xx 错误
- ontology-manager 响应超时
- 网络连接失败

**返回示例**：
```json
{
  "error_code": "ONTOLOGY_MANAGER_ERROR",
  "message": "获取对象类定义失败",
  "details": {
    "upstream_service": "ontology-manager",
    "upstream_error": "HTTP 503 Service Unavailable",
    "kn_id": "kn_medical",
    "ot_id": "company"
  },
  "trace_id": "..."
}
```

**处理建议**：
- 短期：上游重试整个请求
- 长期：排查 ontology-manager 服务可用性

---

### 3.4 ONTOLOGY_QUERY_ERROR（502）

**含义**：ontology-query 服务调用失败

**触发条件**：
- ontology-query 返回 5xx 错误
- ontology-query 响应超时
- 网络连接失败

**返回示例**：
```json
{
  "error_code": "ONTOLOGY_QUERY_ERROR",
  "message": "查询逻辑属性值失败",
  "details": {
    "upstream_service": "ontology-query",
    "upstream_error": "HTTP 500 Internal Server Error",
    "kn_id": "kn_medical",
    "ot_id": "company",
    "properties": ["approved_drug_count", "business_health_score"]
  },
  "trace_id": "..."
}
```

**处理建议**：
- 短期：上游重试整个请求
- 长期：排查 ontology-query 服务可用性或 dynamic_params 合法性

---

### 3.5 TIMEOUT（504）

**含义**：请求总体超时（超过 total_timeout）

**触发条件**：
- 整个请求处理时间超过 total_timeout（默认 30s）

**返回示例**：
```json
{
  "error_code": "TIMEOUT",
  "message": "请求超时（超过 30s）",
  "details": {
    "timeout_ms": 30000,
    "elapsed_ms": 30124
  },
  "trace_id": "..."
}
```

**处理建议**：
- 短期：上游重试（可能是偶发网络问题）
- 长期：检查 properties 数量是否过多或 LLM 调用是否异常慢

---

### 3.6 INTERNAL_ERROR（500）

**含义**：未预期的内部错误

**触发条件**：
- 代码 bug 或未处理的异常

**返回示例**：
```json
{
  "error_code": "INTERNAL_ERROR",
  "message": "服务内部错误",
  "trace_id": "..."
}
```

**处理建议**：
- 立即排查日志（通过 trace_id 定位）
- 根据日志修复 bug 后重新部署

---

## 4. 错误码映射关系

| 错误码 | HTTP Status | 是否可重试 | 重试建议 |
|--------|-------------|-----------|---------|
| INVALID_REQUEST | 400 | 否 | 修正参数后重试 |
| MISSING_INPUT_PARAMS | 400 | 是 | 补充 additional_context 后重试 |
| INVALID_PROPERTY | 400 | 否 | 修正 properties 后重试 |
| OBJECT_TYPE_NOT_FOUND | 404 | 否 | 检查 kn_id/ot_id |
| LLM_CALL_FAILED | 500 | 是 | 延迟后重试（LLM 服务可能恢复） |
| LLM_OUTPUT_INVALID | 500 | 是 | 重试（LLM 随机性可能成功） |
| ONTOLOGY_MANAGER_ERROR | 502 | 是 | 延迟后重试 |
| ONTOLOGY_QUERY_ERROR | 502 | 是 | 延迟后重试 |
| TIMEOUT | 504 | 是 | 延迟后重试 |
| INTERNAL_ERROR | 500 | 是 | 延迟后重试（可能是瞬态问题） |

---

## 5. 监控告警建议

### 5.1 关键指标

- **错误率**（按 error_code 分组）:
  - `error_rate.MISSING_INPUT_PARAMS` > 20% → 提示词或上游上下文质量问题
  - `error_rate.LLM_CALL_FAILED` > 5% → LLM 服务不稳定
  - `error_rate.ONTOLOGY_*_ERROR` > 1% → 依赖服务不稳定

- **延迟**:
  - `latency.p95` > 10s → 需要优化并发或 LLM 调用
  - `latency.p99` > 20s → 可能触发 total_timeout

### 5.2 告警规则

- `error_rate.LLM_CALL_FAILED` > 10%（持续 5 分钟）→ P1 告警
- `error_rate.ONTOLOGY_*_ERROR` > 5%（持续 5 分钟）→ P1 告警
- `error_rate.TIMEOUT` > 10%（持续 5 分钟）→ P2 告警
- `latency.p95` > 15s（持续 10 分钟）→ P2 告警

---

## 6. 错误处理最佳实践（上游）

### 6.1 可重试错误

对于 `MISSING_INPUT_PARAMS`:
1. 解析 `missing` 清单
2. 根据 `hint` 补充 `additional_context`
3. 或追问用户获取缺失信息
4. 重新调用本接口

对于 `LLM_CALL_FAILED` / `ONTOLOGY_*_ERROR` / `TIMEOUT`:
1. 延迟 1~3 秒后重试
2. 最多重试 2 次
3. 仍失败则向用户返回友好错误提示

### 6.2 不可重试错误

对于 `INVALID_REQUEST` / `INVALID_PROPERTY` / `OBJECT_TYPE_NOT_FOUND`:
1. 记录错误日志
2. 向用户返回明确的错误提示（如"指定的对象类不存在"）
3. 不要重试（会浪费资源）

### 6.3 日志记录

所有错误必须记录:
- `trace_id`（用于链路追踪）
- 请求参数（脱敏后）
- 错误码和错误信息
- 重试次数（如果重试了）


