4. RESTful API 设计原则:评分接口规范、请求/响应数据结构设计、错误码与异常处理
在风控评分通道的 Model Serving 实践中,API 是上游业务系统与模型推理引擎之间的唯一契约。一个设计良好的 RESTful 评分接口,不仅要保证数据交换的准确性与实时性,还必须具备清晰的语义、健壮的异常处理机制以及可扩展的数据结构。本章围绕评分接口的规范、请求/响应结构设计以及错误码体系展开,确保接口在生产环境中具备高可用性与可维护性。
4.1 评分接口规范
评分接口遵循标准的 RESTful 风格,使用 HTTP POST 方法提交特征数据并获取评分结果。接口路径设计应体现资源语义,避免动词化。
| 规范项 | 要求 | 说明 |
|---|---|---|
| HTTP 方法 | POST | 评分请求通常包含敏感特征数据,POST 可避免 URL 长度限制与日志泄露 |
| 接口路径 | /api/v1/score |
版本号置于路径中,便于多版本共存与灰度切换 |
| Content-Type | application/json |
统一使用 JSON 格式,支持嵌套结构与动态字段 |
| 幂等性 | 非幂等 | 每次评分可能因模型版本、时间窗口特征产生不同结果,不强制幂等 |
| 超时设置 | 500ms ~ 3000ms | 根据特征工程复杂度与模型推理耗时动态配置,超时返回 504 |
实践建议:接口路径中的版本号建议使用整数主版本(v1, v2),避免使用日期或语义化版本号,以降低上游调用方的适配成本。
4.2 请求数据结构设计
评分请求体采用扁平化 JSON 对象,包含三个核心字段:request_id、features、context。其中 features 为必填字段,承载模型推理所需的全部特征变量。
{
"request_id": "202503211234567890001",
"features": {
"age": 35,
"income": 250000,
"credit_limit": 50000,
"loan_amount": 120000,
"loan_term": 36,
"overdue_days_30": 0,
"overdue_days_90": 1,
"query_count_3m": 5,
"existing_loans": 2
},
"context": {
"channel": "APP",
"product_code": "P001",
"timestamp": "2025-03-21T14:30:00+08:00"
}
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id |
string | 是 | 全局唯一请求标识,用于链路追踪与去重 |
features |
object | 是 | 特征键值对,键名与模型训练特征一致,值类型支持 number/string/boolean |
context |
object | 否 | 请求上下文,包含渠道、产品码、时间戳等元信息,用于策略分流与日志审计 |
避坑提示:特征字段名禁止使用特殊字符(如空格、点号、连字符),建议统一使用下划线命名法。模型训练与线上推理的特征字典必须严格对齐,否则会导致推理异常或评分偏差。
4.3 响应数据结构设计
评分响应体同样采用 JSON 格式,包含 code、message、data 三个顶层字段。其中 data 字段封装评分结果与辅助信息,便于上游系统直接消费。
{
"code": 0,
"message": "success",
"data": {
"score": 725,
"decision": "approve",
"reason_code": "R001",
"model_version": "v2.3.1",
"score_timestamp": "2025-03-21T14:30:01.123+08:00",
"extra": {
"probability": 0.87,
"bucket": "A"
}
}
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
code |
int | 是 | 业务状态码,0 表示成功,非 0 表示异常 |
message |
string | 是 | 状态描述,成功时为 "success",异常时返回具体错误信息 |
data.score |
int | 是 | 模型输出的信用评分,范围 0~1000 |
data.decision |
string | 是 | 策略决策结果:approve / reject / review |
data.reason_code |
string | 否 | 拒绝或人工审核的原因码,用于下游解释 |
data.model_version |
string | 是 | 实际执行推理的模型版本号,用于审计与回滚追溯 |
data.extra |
object | 否 | 扩展字段,可携带概率值、分桶、特征贡献度等辅助信息 |
设计要点:响应体中的
data 对象应保持稳定,新增字段优先放入 extra 子对象,避免破坏已有调用方的解析逻辑。
4.4 错误码与异常处理
错误码体系采用分层设计,分为 HTTP 状态码与业务状态码两层。HTTP 状态码用于表示通信层面的成功或失败,业务状态码用于表示评分业务层面的具体异常类型。
4.4.1 HTTP 状态码定义
| HTTP 状态码 | 含义 | 典型场景 |
|---|---|---|
| 200 | 请求成功 | 评分正常返回,业务状态码为 0 |
| 400 | 请求参数错误 | 缺少必填字段、特征值格式错误、JSON 解析失败 |
| 401 | 认证失败 | API Key 无效或过期 |
| 429 | 请求频率超限 | 超过 QPS 配额,返回 Retry-After 头部 |
| 500 | 服务端内部错误 | 模型加载失败、数据库连接异常、未知运行时错误 |
| 504 | 网关超时 | 模型推理超过配置的超时阈值 |
4.4.2 业务状态码定义
| 业务码 | 分类 | 说明 | 处理建议 |
|---|---|---|---|
| 0 | 成功 | 评分正常完成 | 直接消费 data 字段 |
| 1001 | 参数校验 | 必填特征缺失 | 检查请求体 features 字段完整性 |
| 1002 | 参数校验 | 特征值类型错误 | 核对特征类型与模型要求一致 |
| 1003 | 参数校验 | 特征值超出合法范围 | 检查特征值是否在训练集分布范围内 |
| 2001 | 推理异常 | 模型推理超时 | 优化特征工程或升级推理硬件 |
| 2002 | 推理异常 | 模型版本不存在 | 检查 model_version 配置或回滚版本 |
| 3001 | 策略异常 | 策略引擎执行失败 | 检查策略规则配置与依赖数据源 |
| 4001 | 限流熔断 | 请求被限流 | 降低请求频率或申请提升配额 |
| 5001 | 系统异常 | 未知内部错误 | 联系运维查看服务端日志 |
4.4.3 异常处理策略
- 重试机制:对于 504 网关超时与 2001 模型推理超时,采用指数退避重试策略,初始间隔 200ms,最大重试次数 3 次。
- 降级策略:当模型服务不可用时,根据
context.product_code返回预设的默认评分或缓存评分,确保业务连续性。 - 熔断保护:基于滑动窗口统计错误率,当 30 秒内错误率超过 50% 时触发熔断,熔断时长 60 秒,熔断期间直接返回降级结果。
- 告警通知:业务码 3001 及以上异常自动触发告警,通过钉钉/企业微信机器人通知值班人员,并记录完整请求日志用于事后分析。
最佳实践:所有异常响应必须包含
request_id 字段,便于上下游系统快速关联日志,定位问题根因。建议在响应头中也透传 X-Request-Id。
4.5 接口安全与版本管理
评分接口涉及用户敏感特征数据,必须实施传输层安全与访问控制。同时,接口版本管理应支持平滑升级与灰度切换。
- 传输安全:强制使用 HTTPS,TLS 版本不低于 1.2,证书由内部 CA 签发或使用云厂商托管证书。
- 访问控制:请求头携带
X-API-Key字段,网关层校验有效性,支持按渠道、产品码进行细粒度权限控制。 - 版本管理:路径版本号(v1, v2)与模型版本解耦,接口版本升级时保留旧版本至少 3 个月,通过网关权重配置实现灰度切换。
- 审计日志:所有评分请求与响应均记录至审计日志系统,包含 request_id、时间戳、调用方身份、模型版本、评分结果,满足合规要求。
安全提醒:禁止在响应体中返回原始特征数据或模型参数,防止敏感信息泄露。审计日志中的特征数据应进行脱敏处理,如对身份证号、手机号等字段进行掩码。