尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

信贷系统模型表设计与管理:从字段规划到灰度上线

信贷系统模型表设计与管理:从字段规划到灰度上线 做信贷系统多年有一个最容易被低估、但每次上线都绕不开的东西就是“模型表”。很多新入行的同学以为信贷系统的核心是贷款账务、支付清结算这些模块其实真正决定业务赚不赚钱、风险大不大的恰恰是散落在风控和决策引擎里的那一张张模型表。写这篇文章就是想把这几年在信贷系统里和模型表打交道的心得做个梳理把这类表从哪里来、到哪里去、踩过哪些坑、怎么把它管好一次讲透。内容适合三类人看一是正在设计信贷系统或风控平台的后端、数据开发同学二是刚转行做风控建模但不太清楚模型上线后长什么样的算法同学三是想了解审批、额度、定价背后数据逻辑的业务产品经理。下面讲的都是我在实际项目里用过的方案不一定是最先进的但一定是能落地、能排障、能撑住业务的。1. 先从一张“模型表”说起整体框架与分层设计1.1 模型表到底是干什么的信贷系统里的“模型表”不是指某个机器学习模型本身而是指支撑模型运行和结果存储的数据库表。模型本质上一段算法逻辑它要吃进特征数据、吐出预测结果中间涉及样本、变量、参数、评分、决策等一系列数据这些数据都要落到表里才有办法管理、追溯、排查。我见过不少团队模型在开发环境跑得好好的一上线就出各种意外要么结果对不上要么审批链路报错最后查下来往往是模型表设计得不对或者表和数据流压根没规划好。信贷系统的特点就是对账、审计、可解释性要求极高每一笔审批拒绝的理由、每一个额度调整的依据都要说得清楚这时候模型表就成了整个风控体系的数据地基。1.2 模型表在信贷系统里的分层位置如果把信贷系统拆开看模型相关的表一般分布在四层输入层承接原始数据比如用户授权信息、征信报文、三方数据源返回结果通常以接口日志表或原始数据落地表为主。特征层把原始数据加工成模型可用的变量比如“近6个月最大逾期天数”“近3个月申请次数”特征层的表也叫变量表或特征宽表。决策层决策引擎读取特征调用模型打分结合规则和策略输出审批结果。这层的表包括模型调用日志表、评分结果表、决策明细表。监控层记录模型上线后的表现比如每日评分分布、逾期率、PSI群体稳定性指数指标等用来监控模型是否失效。这四层比较简单但仍然有一个中心也就是所谓的“模型主表”记录模型版本、参数、特征版本、入模变量清单等元信息。所有其他表都通过模型ID和版本号跟主表关联。1.3 一个最小可用模型表的字段设计刚开始做信贷系统的时候我设计过一版最朴素的模型表结构大致是这样CREATE TABLE credit_model_info ( id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 主键, model_code VARCHAR(64) NOT NULL COMMENT 模型编码如APP_SCORE_A, model_version VARCHAR(32) NOT NULL COMMENT 模型版本号如V1.2.0, model_name VARCHAR(128) COMMENT 模型名称, model_type TINYINT COMMENT 模型类型1-申请评分 2-行为评分 3-催收评分 4-反欺诈, feature_version VARCHAR(32) COMMENT 特征版本号, param_json TEXT COMMENT 模型参数序列化存储, cutoff_value DECIMAL(10,4) COMMENT 建议cutoff阈值, status TINYINT COMMENT 状态0-开发 1-验证 2-上线 3-下线, effective_date DATE COMMENT 生效日期, expired_date DATE COMMENT 失效日期, creator VARCHAR(32), create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) COMMENT 信贷模型元信息表;别小看这张表模型管理的大部分麻烦都出在“版本”上。没有明确的主模型表不同团队各自为政线上跑一个版本开发那边迭代另一个版本到时候模型到底哪个生效、特征口径到底用哪套能吵一整天。2. 常见信贷模型表的拆解评分卡、额度、定价、催收2.1 申请评分卡A卡相关表信贷系统里最核心的模型就是申请评分卡通常叫A卡它在用户申请时评估其违约概率输出一个分数。A卡对应的表除了模型元信息表最主要的是一张评分结果表。评分结果表记录每次请求的上下文包括用户唯一标识、申请单号、模型编码、版本号、分数、命中拒绝规则等。为什么要把评分结果落表一方面是为了支持后续的贷后分析和模型迭代另一方面是监管审计要求——用户投诉“为什么不给我批”你必须能拿出当时的评分和决策依据。我曾经做过一个优化把评分结果表按用户ID做哈希分片这样同一个用户的请求都落在同一分片上排查单个用户的问题时SQL效率高很多。这是信贷系统比较实用的设计技巧但要特别注意分片键的选择如果用申请单号分片一个用户多条记录会散到各个分片查起来就麻烦了。2.2 行为评分卡B卡与额度管理表用户贷后表现会持续产生数据行为评分卡B卡用来动态评估存量客户的风险。B卡的输出一般用于额度调整、贷中预警。额度管理表跟B卡强相关它会记录用户每个时期的额度和调额依据。额度管理表有几个关键字段用户ID、合同或产品编号、当前额度、临时额度、模型评分、额度决策码、生效时间、失效时间。做额度管理的时候最怕的是额度变化没有留痕用户后台一看额度变了客服找不到原因。我接手过一个项目的额度表居然只有当前额度一个字段没有历史流水线上发生过好几起用户额度无故变化被投诉的事件。后来我们加了一张额度流水表每次调额都插入一条记录包含调额前额度、调额后额度、触发的模型版本、审批人或系统任务、备注。这张流水表后续做异常排查和模型效果分析都非常有用。2.3 定价模型表与催收模型表很多信贷系统会忽略定价模型觉得利率是产品定死的。但实际业务里差异化定价越来越普遍优质客户降息挽留高风险客户加价覆盖损失。定价模型的输出往往是一个定价标识或利率档位对应表叫定价策略表里面会有评分区间、对应年化利率区间、还款方式限制等。催收评分卡C卡则是进入贷后阶段后评估逾期客户的还款意愿和能力输出催收策略优先级。催收模型对应的表一般是催收任务分配表核心字段包括用户ID、逾期天数、催收评分、分配队列、催收员、联系方式、外呼结果等。催收模型表最容易踩的坑是评分结果和催收行动数据分离。评分表记录的是模型分外呼系统记录的是联系记录如果两套数据不打通你根本不知道分配规则调整后催回率是不是真的提升了。我建议在催收任务分配表里冗余催收评分和催收策略码这样分析人员不用来回join也能快速看出策略效果。2.4 模型结果表通用字段约定不管哪类模型结果表有几个字段几乎是标配而且建议全公司统一口径字段名类型说明req_novarchar请求流水号每次模型调用唯一user_idvarchar用户唯一标识一般用加密IDmodel_codevarchar模型编码model_versionvarchar模型版本号必须精确到上线版本scoredecimal模型输出分数decisionvarchar决策结果如APPROVE/REJECT/MANUALreason_codevarchar拒绝或转人工的原因码集合feature_versionvarchar特征版本号用于回溯变量口径create_timedatetime模型调用时间这里要特别强调feature_version有些系统的模型表里压根没这个字段导致后续想复现某个时候的评分结果变量已经被新版本覆盖了怎么都对不上。加一个特征版本号成本很低收益很大。3. 实操从模型开发到模型表落地的完整流程3.1 特征宽表怎么建建模同学通常习惯在Python里用DataFrame处理特征但到了生产环境特征必须工程化。最常用的方案是建一张特征宽表一个用户一行特征作为列存储。建特征宽表的时候要特别注意两个问题一是特征时效性比如“近3个月申请次数”计算基准日是哪一天如果批处理是每天凌晨跑那特征应该按T-1日的数据计算如果是在线实时决策那特征要能实时取数而不是直接读T-1的宽表。二是特征口径的统一。同一个“近6个月查询次数”征信解析团队算的和建模团队自己算的很可能差几条记录。我们当时的做法是建立特征字典每个特征有唯一编码、口径说明、来源表、计算SQL并且纳入版本管理。特征宽表只从特征字典里取特征不允许建模同学自己在宽表里加“私有特征”。3.2 变量口径与标签对齐特征表和模型表之间最容易出问题的是标签。建模样本里的目标定义在线上评估时常常对不上。比如“逾期30天以上”这个标签建模的时候可能是以还款日为基准但线上系统里判断逾期是以自然日还是宽限期还款日当天没还算不算逾期这些口径如果没对齐模型表现大概率不会好。我建议建模团队和生产团队一起维护一张“标签口径表”明确目标定义、观察期、表现期、排除规则。这张表要挂到模型主表下面每次迭代模型时先检查标签口径是否发生变化如果样本标签的定义变了模型比较基准也就不成立。另外变量口径对齐之后一定要做“线上线下一致性验证”。简单说就是跑一批历史用户在离线环境用同一特征版本计算出评分再把这批用户在生产环境重新调用一次模型比较两次分数是否一致。如果有偏差大概率是特征逻辑在工程实现时被改掉了。3.3 模型版本管理与灰度上线模型表设计得再规范如果版本管理混乱照样出问题。信贷系统上线新模型时我强烈建议走“灰度策略”。第一步新模型离线验证通过后把新模型版本注册到模型元信息表状态设为“验证”。第二步线上决策引擎里做模型双跑也就是同一个请求同时调用旧模型和新模型但实际决策仍然用旧模型的结果新模型结果只落日志表。这一步能攒下足够的对比数据判断新模型与旧模型的差异、是否出现极端分数。第三步选择某个流量分片比如按用户ID尾号切一部分真实流量到新模型观察一段时间的通过率和逾期表现确认稳定后全量切换。灰度上线这件事没有模型表的支持是不行的。模型调用日志表里必须同时记录模型版本号和评分结果否则你根本不知道当前流量是哪个模型在决策出了问题也没法快速回滚。我在实际项目里一般还会保留“回滚开关”发现新模型异常时决策引擎配置中心一键切回旧版本而不用重新发版。3.4 模型表联调与口径核对模型上线前的联调绝对不是开发说“功能跑通了”就行。我会带着测试同学专门核对三张表的数据模型元信息表和决策引擎配置里的模型路径是否一致防止配置中心引用了一个旧版模型文件。评分结果表里落库的请求流水和决策引擎日志的请求流水是否能一一对上。对不上时优先检查双方的时间戳时区、序列化格式。特征表关联字段是否和审批主流程一致。有些系统会保存两份特征一份是申请时点的快照特征一份是后台批处理生成的宽表特征如果两者口径不同贷后分析时很容易得出矛盾结论。口径核对这事建议写成一个自动化脚本每次上线前跑一遍而不是靠人工用SQL反复查。人查容易漏脚本查虽然机械但胜在稳定。4. 模型表使用中常见的坑排查与调优实录4.1 变量空值和数据延迟信贷系统上最典型的线上事故就是外部数据源接口超时导致特征表里部分变量为空模型直接打分异常。有些模型对空值处理不好可能把空值当成0也可能直接拒绝。我遇到过一笔正常用户被误拒的case最后查下来是三方征信接口晚了几秒返回特征表落库就写了NULL而模型决策逻辑是“如果某个关键变量为空则拒绝”。从系统角度这不算bug但从业务角度体验极差。解决思路有两个第一在线特征计算时增加默认值兜底逻辑比如查询次数为空时填-1然后模型端将-1视为缺失分箱而不是直接拒绝。第二在特征表里增加缺失标记字段记录哪些特征缺失方便事后分析。这个标记字段在监控模型稳定性和排查异常案例时特别有用。4.2 模型ID、版本号混乱问题模型表最容易被吐槽的就是字段命名不统一。有的表里叫model_id有的叫model_version还有的叫score_card_id搞得各张表之间关联全靠人工转换。更可怕的是有些系统直接用模型文件路径当版本标识一旦部署文件名变更历史数据就失去关联能力。我的建议是全公司统一用model_code model_version作为唯一标识任何日志、流水、宽表、监控表都带这两个字段。同时模型ID必须是稳定且语义化的比如申请评分A卡就是APP_SCORE_AB卡就是BEHAVIOR_SCORE_B不要用无意义的自增ID作为业务关联主体。另外版本号要有明确的命名规则比如主版本号.次版本号.修订号主版本号变化表示入模变量集合或模型结构有重大调整次版本号变化表示重训但结构一致修订号一般是bug修复。这套规范能让你快速理解两个版本间的差异有多大。4.3 训练-线上数据不一致穿越问题最近几年大家越来越关注模型的“时间穿越”问题。简单说就是训练样本里用了未来信息模型在线上却拿不到导致线下效果虚高、上线后表现崩塌。典型场景训练样本的“用户最后还款状态”这个标签本质上是未来信息没问题因为这是目标。但有些特征也会无意中用到未来数据比如用整个时间窗内的平均额度去预测首月逾期而额度在样本期内是动态调整的建模时可能按最终值算但线上申请那个时点根本不知道最终值。模型表在这里的角色就是提供“可审计的数据血缘”。特征宽表里的每个特征都要有“计算基准时间”字段或者至少能在特征字典里找到口径说明。训练样本必须严格保持“特征时间 决策时间”否则模型上线必然翻车。4.4 监控表怎么建才能及时发现模型退化模型上线后不是一劳永逸的客群结构变化、外部环境变化都会导致模型效果衰减。监控层的表如果建得好能在模型崩掉前提前预警。我常用的监控表有两种第一种是日度评分分布统计表按天统计模型评分的均值、分位数、通过率、拒绝率。如果某天通过率突然从30%掉到20%就要警惕是不是特征数据源出问题或者客群突变。第二种是PSI监控表定期计算当前评分分布相对于建模训练集评分分布的PSIPSI超过0.25就要预警超过0.5基本意味着模型需要重新训练或调整。监控表的设计细节在于不仅要存指标值还要存“对比基准”。比如PSI表里要存训练集的标准分数分箱线上每天的分箱要和标准分箱比较。没有基准的监控等于没监控。5. 从一张表到一套模型资产管理体系5.1 模型血缘与口径文档模型表用久了会发现最稀缺的不是存储空间而是“文档”。一个模型上线半年后建模同学离职了谁能说清楚这张表的每个字段是怎么算的换个人来看只能对着SQL猜。建议在模型元信息表的基础上增加一张模型血缘表记录模型依赖了哪些特征、哪些原始表、哪些三方数据。血缘表不一定要复杂核心字段就是下游模型ID、上游表名或特征编码、依赖类型必需/可选、引用频率、数据更新时间。有了血缘表当某个上游数据源变更时可以快速评估影响范围而不至于把所有模型都拉出来体检一遍。附带做一份“模型口径说明”我用的是Markdown格式挂在知识库里内容包含模型目的、适用客群、评分区间含义、cutoff推导过程、入模变量清单、异常处理方式。这份文档不用写得很长但要把上面这些关键信息讲清楚。5.2 模型表的管理规范和权限信贷数据非常敏感模型表更不例外。评分结果、额度策略、定价档位都是核心机密不能全团队都能随便查。我建议对模型表做分层权限控制开发环境建模、开发、测试可读写但数据必须是脱敏的或虚拟样本。预发环境仅开发和测试可读写数据用少量真实样本做联调。生产环境只有运维和风控核心人员有权限查询禁止修改修改必须走审批流程。同时生产环境模型表一律开启审计日志谁在什么时间查了哪张表、执行了什么SQL都要有记录。一方面是为了配合内部合规检查另一方面是防止内部数据泄露。有一点容易被忽视模型表的权限管理不只是数据库层面的权限还包括下游应用接口的权限。比如决策引擎查询模型评分的接口要限制调用频次和调用方IP防止被内部其他系统滥用。5.3 后续可扩展方向如果团队精力允许模型表体系还可以向两个方向扩展一是引入特征平台把特征表的开发、上线、监控、共享从模型表中独立出来形成更标准化的特征服务二是引入模型生命周期管理平台把模型注册、实验对比、灰度发布、监控告警、自动重训全部串起来模型表成为其中的数据底座。这个方向我在后续项目里实践了一部分最大的感受是无论上层平台多花哨底层模型表设计得清清爽爽永远是第一重要的。表结构乱糟糟再好的工具也救不了表结构清楚了哪怕用最土的办法写SQL探查问题也很快。最后分享一个小技巧设计模型表的时候每个表都尽量加上一个自增主键和时间戳字段但不要用自增ID作为业务唯一键。信贷系统里数据回溯、对账、追查问题的场景非常多自增ID只能作为物理主键使用业务关联请用流水号或业务编号避免因为ID重置或迁移导致数据串了。这个习惯让我少踩了太多坑。
返回列表