KingbaseES 进阶(一):AI 模型元数据管理 —— 表设计与版本追踪

——别再用 Excel 管模型了,你的 AI 资产值得一个“户口本”

大家好,我是那个总在模型上线后被问“这个 AUC 0.89 的模型是哪天训的?用了哪些特征?谁批准的?”、又不得不翻遍邮件和 Slack 记录的老架构。你可能已经把模型存进了 KES 的 BYTEA 字段,甚至跑通了离线预测。

但如果你只存了模型二进制,那只是把“尸体”埋进了数据库
真正的 AI 工程化,需要一套完整的 元数据管理体系——记录模型从出生到退役的全生命周期。

今天我们就用纯 SQL + Java,在电科金仓 KingbaseES(KES)中构建一套轻量但完备的 模型元数据注册中心。不依赖 MLflow、不搞复杂 metadata store,只为回答三个灵魂问题:

  • 这是谁的模型?
  • 它为什么可信?
  • 出了问题怎么回溯?

一、为什么需要模型元数据?

在国产化项目中,我们常看到:

  • 模型文件散落在各个服务器;
  • 版本靠文件名区分(rf_v2_final_really_final.model);
  • 训练参数写在 README 里,没人更新;
  • 出了问题,没人知道该找谁。

这根本不是工程,这是考古

而金融、政务、能源等行业对 AI 系统有明确合规要求:

  • 模型必须可审计;
  • 变更必须可追溯;
  • 责任必须可定位。

KES 作为企业级数据库,天然适合承担这一角色——它不仅是数据的仓库,更是 AI 资产的“户籍系统”。


二、核心表设计:四张表,管住模型全生命周期

2.1 模型注册主表(model_registry

CREATE TABLE ai_meta.model_registry (
    model_id        SERIAL PRIMARY KEY,
    model_name      VARCHAR(100) NOT NULL,      -- 业务名,如 'loan_risk_rf'
    model_type      VARCHAR(50)  NOT NULL,      -- RandomForest, XGBoost...
    version         VARCHAR(20)  NOT NULL,      -- 语义化版本 v1.2.0
    description     TEXT,                       -- 用途说明
    owner           VARCHAR(50)  NOT NULL,      -- 负责人
    created_at      TIMESTAMP DEFAULT NOW(),
    updated_at      TIMESTAMP DEFAULT NOW(),
    
    -- 元数据快照
    feature_list    TEXT[],                     -- 训练用特征列表
    training_data_sql TEXT,                   -- 训练数据来源SQL(可选)
    
    -- 性能指标
    auc_score       REAL,
    f1_score        REAL,
    accuracy        REAL,
    
    -- 状态控制
    is_active       BOOLEAN DEFAULT false,
    approved_by     VARCHAR(50),                -- 审批人
    approval_time   TIMESTAMP,
    
    -- 模型本体(可选,也可单独存)
    model_blob      BYTEA
);

✅ 关键设计:元数据与模型二进制可分离。大模型可存 OSS,小模型直接内嵌。


2.2 模型训练日志(model_training_log

CREATE TABLE ai_meta.model_training_log (
    log_id          SERIAL PRIMARY KEY,
    model_id        INT REFERENCES ai_meta.model_registry(model_id),
    start_time      TIMESTAMP,
    end_time        TIMESTAMP,
    duration_sec    INT,
    training_rows   BIGINT,
    hyperparams     JSONB,                      -- 超参:{"num_trees":100, "max_depth":10}
    environment     JSONB,                      -- JDK版本、OS、KES版本
    git_commit      VARCHAR(40),                -- 代码版本
    status          VARCHAR(20) DEFAULT 'success' -- success/failure
);

💡 用 JSONB 存非结构化配置,KES 原生支持 JSON 查询。


2.3 模型部署记录(model_deployment

CREATE TABLE ai_meta.model_deployment (
    deploy_id       SERIAL PRIMARY KEY,
    model_id        INT REFERENCES ai_meta.model_registry(model_id),
    env             VARCHAR(20) NOT NULL,       -- dev/test/prod
    deployed_at     TIMESTAMP DEFAULT NOW(),
    deployed_by     VARCHAR(50),
    service_name    VARCHAR(100),               -- 如 risk-scoring-api
    rollback_to     INT REFERENCES ai_meta.model_registry(model_id) -- 回滚目标
);

2.4 模型评估报告(model_evaluation

CREATE TABLE ai_meta.model_evaluation (
    eval_id         SERIAL PRIMARY KEY,
    model_id        INT REFERENCES ai_meta.model_registry(model_id),
    dataset_name    VARCHAR(100),               -- 如 'q3_2025_test_set'
    eval_time       TIMESTAMP DEFAULT NOW(),
    metrics         JSONB                       -- {"precision":0.85, "recall":0.78...}
);

三、Java 封装:元数据操作工具类

3.1 注册新模型

public class ModelRegistry {

    public static int registerModel(Connection conn, ModelMetadata meta) 
            throws SQLException {
        String sql = """
            INSERT INTO ai_meta.model_registry 
            (model_name, model_type, version, description, owner, 
             feature_list, auc_score, f1_score, training_data_sql)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
            RETURNING model_id
            """;
        
        try (PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setString(1, meta.name);
            ps.setString(2, meta.type);
            ps.setString(3, meta.version);
            ps.setString(4, meta.description);
            ps.setString(5, meta.owner);
            
            // TEXT[] 需转换为 PGobject(KES 兼容)
            Array featureArray = conn.createArrayOf("TEXT", meta.features.toArray());
            ps.setArray(6, featureArray);
            
            ps.setDouble(7, meta.auc);
            ps.setDouble(8, meta.f1);
            ps.setString(9, meta.trainingSql);
            
            try (ResultSet rs = ps.executeQuery()) {
                if (rs.next()) return rs.getInt(1);
            }
        }
        throw new RuntimeException("Failed to register model");
    }
}

🔗 使用 电科金仓 JDBC 驱动 支持 TEXT[]JSONB 类型。


3.2 激活模型(上线)

public static void activateModel(Connection conn, int modelId, String approver) 
        throws SQLException {
    // 先停用同名其他版本
    String deactivate = "UPDATE ai_meta.model_registry SET is_active = false WHERE model_name = (SELECT model_name FROM ai_meta.model_registry WHERE model_id = ?)";
    try (PreparedStatement ps = conn.prepareStatement(deactivate)) {
        ps.setInt(1, modelId);
        ps.executeUpdate();
    }
    
    // 再激活当前版本
    String activate = """
        UPDATE ai_meta.model_registry 
        SET is_active = true, approved_by = ?, approval_time = NOW() 
        WHERE model_id = ?
        """;
    try (PreparedStatement ps = conn.prepareStatement(activate)) {
        ps.setString(1, approver);
        ps.setInt(2, modelId);
        ps.executeUpdate();
    }
}

四、实战:一次完整的模型上线流程

// 1. 训练模型(略)
RandomForest model = trainModel(...);
EvaluationResult eval = evaluate(model, testData);

// 2. 构建元数据
ModelMetadata meta = new ModelMetadata(
    name = "loan_risk_rf",
    type = "RandomForest",
    version = "v2.1.0",
    description = "优化了 debt_ratio 处理逻辑",
    owner = "zhang.san",
    features = Arrays.asList("age", "income", "debt_ratio", ...),
    auc = eval.auc,
    f1 = eval.f1,
    trainingSql = "SELECT * FROM ai_features.loan_train_v3"
);

// 3. 注册到 KES
int modelId = ModelRegistry.registerModel(conn, meta);

// 4. (可选)保存模型二进制
ModelBlobStorage.saveModelBlob(conn, modelId, model);

// 5. 审批上线
ModelRegistry.activateModel(conn, modelId, "li.si"); // 审批人

// 6. 记录部署
ModelDeployment.deploy(conn, modelId, "prod", "risk-api");

五、查询示例:快速定位问题

5.1 查当前线上模型

SELECT model_name, version, owner, auc_score, approved_by 
FROM ai_meta.model_registry 
WHERE is_active = true AND model_name = 'loan_risk_rf';

5.2 查某版本的训练参数

SELECT m.version, t.hyperparams, t.environment
FROM ai_meta.model_registry m
JOIN ai_meta.model_training_log t ON m.model_id = t.model_id
WHERE m.model_name = 'loan_risk_rf' AND m.version = 'v2.0.0';

5.3 查历史性能趋势

SELECT version, auc_score, eval_time
FROM ai_meta.model_registry
WHERE model_name = 'loan_risk_rf'
ORDER BY created_at;

✅ 所有操作通过标准 SQL 完成,无需额外工具。


六、为什么这套设计适合国产化?

  1. 自主可控:不依赖外部 metadata 系统(如 MLflow);
  2. 安全合规:复用 KES 的权限、审计、加密能力;
  3. 轻量高效:四张表覆盖 90% 场景,无冗余字段;
  4. 可扩展:通过 JSONB 支持任意自定义属性。

而这套能力,正建立在 电科金仓 KES 提供的企业级事务、JSON 支持、数组类型等特性之上——它不仅是数据库,更是 AI 治理平台。


结语:元数据,是 AI 工程化的基石

在 AI 项目中,我们常追求算法创新,却忽视了最基础的治理。
但真正的专业,体现在每一次模型变更都有记录,每一个指标都有出处,每一行代码都可追溯

当你能在 KES 中用一条 SQL 查出“上周上线的模型是谁批的、用了什么参数、AUC 是多少”——你就已经建立了可审计、可迭代、可问责的 AI 工程文化

因为你知道:没有元数据的模型,就像没有身份证的人——存在,但不可信

下一期,我们会讲:KingbaseES 进阶(二):基于元数据的模型自动监控与告警
敬请期待。

—— 一位相信“治理,比算法更重要”的架构师

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐