4. 可重复计算基础

在保险精算、准备金评估、偿付能力计量和利润测试中,同一个指标往往需要被反复计算:月初算一次、月末再算一次,监管口径算一次、内部管理口径再算一次。如果每次计算都依赖不同的人、不同的脚本、不同的中间表,结果就很难对齐。可重复计算(Reproducible Computation)要解决的正是这个问题——它要求在给定相同输入、相同代码、相同环境和相同参数的前提下,任何人在任何时间都能得到完全一致的结果。

一、核心定义:可重复计算到底“可重复”什么

可重复计算不是简单地“再跑一遍脚本”,它包含四个层面的可重复性:

  • 输入可重复:数据版本、快照时间、抽取范围必须被固定并记录,不能依赖“当前最新数据”。
  • 逻辑可重复:计算规则、公式、假设、参数取值必须版本化,代码与配置一并受控。
  • 环境可重复:数据库、计算引擎、依赖库、运行时版本需要可描述、可重建。
  • 结果可重复:输出结果及其校验值(如记录数、汇总金额、哈希)可被比对和追溯。

在保险模型中,这四层缺一不可。只固定代码而不固定数据,会得到“同码不同果”;只固定数据而不固定参数,会得到“同数不同解”。

二、可重复计算的基本原则

结合保险模型数据血缘的实践,可归纳为以下原则:

  1. 单一事实来源:同一指标只允许有一个权威计算路径,避免多套脚本并行。
  2. 显式依赖:所有输入、参数、中间结果都必须显式声明,禁止隐式读取“默认表”。
  3. 幂等性:重复执行不改变最终状态,重跑不会产生重复记录或金额翻倍。
  4. 可追溯:每次运行都留下运行标识、时间、操作者、输入版本和输出位置。
  5. 可验证:结果需有对账规则和校验指标,能自动判断是否“算对了”。
  6. 环境隔离:开发、测试、生产环境分离,避免相互污染。

关键判断:如果一个计算任务无法回答“这次结果是用哪版数据、哪版代码、哪组参数算出来的”,它就不具备可重复计算能力,也就无法支撑审计与监管报送。

三、可重复计算与数据血缘的关系

数据血缘描述的是数据从源头到结果的流转路径:字段从哪里来、经过哪些加工、流向哪些报表和指标。可重复计算与数据血缘是互为支撑的关系:血缘为可重复计算提供“依赖地图”,可重复计算为血缘提供“可验证的执行证据”。

具体来说,血缘在三个环节发挥作用:

  • 计算前:通过血缘确定本次计算需要锁定哪些上游表和字段,形成输入清单。
  • 计算中:血缘记录每一步的输入输出映射,使中间结果可定位、可回放。
  • 计算后:血缘支撑影响分析,当上游数据变更时,能快速判断哪些结果需要重算。

反过来,可重复计算要求血缘必须精确到字段级和参数级。如果血缘只停留在“表A到表B”,就无法锁定输入版本,也无法复现参数取值。因此,可重复计算是数据血缘从“展示型”走向“执行型”的驱动力。

可重复计算 × 数据血缘:依赖锁定与执行回放 输入层 保单/理赔/再保数据 数据版本 + 快照时间 字段级血缘清单 计算层 模型代码 + 参数集 运行标识 RunID 中间结果血缘映射 输出层 准备金/偿付能力指标 校验值 + 对账结果 结果版本归档 数据血缘贯穿三层的执行证据链 上游变更影响分析 定位需重算范围 字段级依赖锁定 保证输入可复现 结果回溯与审计 支撑监管报送

四、方法流程:把可重复计算落到工程上

在保险模型平台中,可重复计算通常按以下流程落地:

1. 锁定输入版本
   data_version = "policy_202406_snapshot_v3"
   snapshot_time = "2024-06-30T23:59:59"

2. 声明参数集
   params = {
     "discount_rate": 0.025,
     "mortality_table": "CL2020_2023",
     "expense_assumption": "v2.1"
   }

3. 生成运行标识
   run_id = "RESV-20240701-001"

4. 执行计算并记录血缘
   output = run_model(data_version, params, run_id)

5. 输出校验与归档
   checksum = sha256(output)
   archive(run_id, data_version, params, checksum)

其中第4步是关键:计算引擎需要把每一步的输入表、输出表、字段映射和参数取值写入血缘库。这样当结果出现异常时,可以按 run_id 回放整条链路。

五、案例场景:准备金重算中的血缘校验

某寿险公司月末评估未到期责任准备金,监管要求可重复。第一次计算得到准备金 12.36 亿元。两周后因理赔数据补录,需要重算。此时:

  • 若只重跑代码而不更新输入版本,结果仍为 12.36 亿元,但实际已不准确。
  • 若更新了输入但未记录参数变化,新旧结果无法解释差异来源。
  • 若血缘完整,可快速定位差异来自“理赔补录表 → 已发生赔款 → 准备金”这条路径,并只重算受影响部分。

实践提示:建议为每次运行生成一张“运行血缘卡”,包含 run_id、输入版本、参数集、输出校验值和影响范围。这张卡既是技术记录,也是审计证据。

六、常见误区与复盘

误区 表现 后果 纠正方式
只版本化代码 代码有 Git,数据用“最新表” 同码不同果 数据快照 + 版本号
血缘只到表级 知道表A到表B,不知字段映射 无法锁定输入 字段级血缘采集
参数写在代码里 利率、死亡率硬编码 无法复现参数 参数外置并版本化
无运行标识 结果文件按日期命名 无法回溯 引入 run_id 与归档
忽略环境差异 开发能跑,生产报错 结果不可比 环境描述与隔离

复盘要点:可重复计算不是一次性项目,而是持续纪律。每次模型变更、数据补录、参数调整,都应触发血缘更新和重算范围评估。否则血缘会逐渐失真,可重复计算也会退化为“看起来能跑”。

总结来看,可重复计算为保险模型提供了“可验证的确定性”,数据血缘为这种确定性提供了“可追溯的路径”。两者结合,才能让准备金、偿付能力和利润测试结果经得起监管、审计和时间的检验。