关于 model-registry-governance
这项技能指导团队建立模型制品、提示词、适配器和评估证据的治理记录体系,适合需要可追溯审批、生命周期控制和审计记录的 ML 平台团队。
主要功能
- 01模型元数据规范
- 02基于 CI 的注册与晋级
- 03策略驱动的审批工作流
- 04自动化生命周期管理
- 05不可变审计记录
适用场景
- 01集中登记模型制品
- 02依据评估结果控制生产晋级
- 03退役过期或无人负责的模型
- 04为 AI 系统合规审计做准备
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ bagelhole/ devops-security-agent-skills --skill model-registry-governance安装后在 Claude Code 中输入/model-registry-governance确认已加载。
详细介绍
模型注册表治理
为模型制品、提示词、适配器和评估证据建立可信的记录系统。
何时使用此技能
- 为组织建立集中式模型注册表
- 定义模型制品的元数据标准
- 为模型晋级到生产环境构建审批工作流
- 实施模型退役生命周期策略
- 为 AI 系统的合规审计做准备
前提条件
- 已部署 MLflow Tracking Server 或 Weights & Biases 实例
- 用于存储模型制品的对象存储(S3、GCS 或 MinIO)
- 可访问注册表 API 的 CI/CD 流水线
- 用于治理检查的 OPA 或类似策略引擎
- 用于存储策略定义和晋级脚本的 Git 仓库
核心原则
- 可追溯性:每个生产模型都能关联到源代码、数据快照和评估结果。
- 可复现性:构建过程具有确定性,并固定依赖项。
- 策略驱动的晋级:关键安全检查不得手动绕过。
- 生命周期卫生:过时、有漏洞或无人负责的模型会自动退役。
MLflow 注册表设置
# Install MLflow with required backends
pip install mlflow[extras] psycopg2-binary boto3
# Start MLflow tracking server with PostgreSQL backend and S3 artifact store
mlflow server \
--backend-store-uri postgresql://mlflow:password@db:5432/mlflow \
--default-artifact-root s3://mlflow-artifacts/models \
--host 0.0.0.0 \
--port 5000 \
--serve-artifacts
# docker-compose.yaml for MLflow
services:
mlflow:
image: ghcr.io/mlflow/mlflow:2.12.0
command: >
mlflow server
--backend-store-uri postgresql://mlflow:${DB_PASSWORD}@db:5432/mlflow
--default-artifact-root s3://mlflow-artifacts/models
--host 0.0.0.0
--port 5000
--serve-artifacts
ports:
- "5000:5000"
environment:
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: mlflow
POSTGRES_USER: mlflow
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
必需的元数据架构
# model_metadata_schema.py
from pydantic import BaseModel, Field
from typing import List, Optional
from datetime import datetime
from enum import Enum
class LifecycleState(str, Enum):
DRAFT = "draft"
CANDIDATE = "candidate"
APPROVED = "approved"
DEPRECATED = "deprecated"
RETIRED = "retired"
class RiskRating(str, Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
class ModelMetadata(BaseModel):
"""Required metadata for every registered model."""
# Identity
name: str = Field(description="Model name matching registry key")
version: str = Field(description="Semantic version")
checksum: str = Field(description="SHA-256 of model artifact")
storage_uri: str = Field(description="Artifact store path")
# Lineage
base_model: str = Field(description="Parent model identifier")
fine_tune_method: Optional[str] = Field(default=None)
training_dataset: Optional[str] = Field(default=None)
training_date: Optional[datetime] = Field(default=None)
source_commit: str = Field(description="Git SHA of training code")
# Evaluation
eval_datasets: List[str] = Field(description="Evaluation dataset IDs")
eval_report_uri: str = Field(description="Path to evaluation results")
quality_score: float = Field(ge=0, le=1)
safety_score: float = Field(ge=0, le=1)
# Governance
license: str = Field(description="SPDX license identifier")
allowed_use_cases: List[str]
prohibited_use_cases: List[str]
risk_rating: RiskRating
security_controls: List[str]
# Ownership
owner: str = Field(description="Primary owner email")
backup_owner: str = Field(description="Backup owner email")
escalation_contact: str
team: str
# Lifecycle
state: LifecycleState = LifecycleState.DRAFT
created_at: datetime = Field(default_factory=datetime.utcnow)
approved_at: Optional[datetime] = None
approved_by: Optional[str] = None
expires_at: Optional[datetime] = None
模型注册脚本
# register_model.py
import mlflow
from mlflow.tracking import MlflowClient
import json
import hashlib
def register_model(
model_path: str,
model_name: str,
metadata: dict,
mlflow_uri: str = "http://mlflow:5000"
):
"""Register a model with full metadata and governance tags."""
mlflow.set_tracking_uri(mlflow_uri)
client = MlflowClient()
# Compute artifact checksum
with open(model_path, "rb") as f:
checksum = hashlib.sha256(f.read()).hexdigest()
metadata["checksum"] = checksum
# Log model with metadata
with mlflow.start_run(run_name=f"register-{model_name}-{metadata['version']}") as run:
# Log all metadata as params
mlflow.log_params({
"model_name": model_name,
"version": metadata["version"],
"base_model": metadata["base_model"],
"risk_rating": metadata["risk_rating"],
"owner": metadata["owner"],
"license": metadata["license"],
})
# Log quality metrics
mlflow.log_metrics({
"quality_score": metadata["quality_score"],
"safety_score": metadata["safety_score"],
})
# Log full metadata as artifact
with open("metadata.json", "w") as f:
json.dump(metadata, f, indent=2, default=str)
mlflow.log_artifact("metadata.json")
# Log model artifact
mlflow.log_artifact(model_path)
# Register in model registry
model_uri = f"runs:/{run.info.run_id}/model"
result = mlflow.register_model(model_uri, model_name)
# Set lifecycle tags
client.set_model_version_tag(
model_name, result.version, "state", "draft"
)
client.set_model_version_tag(
model_name, result.version, "risk_rating", metadata["risk_rating"]
)
client.set_model_version_tag(
model_name, result.version, "checksum", checksum
)
return result
审批工作流
- 由 CI 创建注册请求。
- 执行安全检查(制品扫描、依赖项扫描、来源信息)。
- 上传评估包(质量、毒性、越狱、偏见、延迟、成本)。
- 必需审批:平台 + 产品 + 安全(按策略规定)。
- 根据已签名的决策记录晋级到 stage/prod。
晋级脚本
# promote_model.py
import mlflow
from mlflow.tracking import MlflowClient
from datetime import datetime
import sys
def promote_model(
model_name: str,
version: str,
target_stage: str,
approver: str,
mlflow_uri: str = "http://mlflow:5000"
):
"""Promote a model version after governance checks pass."""
mlflow.set_tracking_uri(mlflow_uri)
client = MlflowClient()
# Verify current state allows promotion
mv = client.get_model_version(model_name, version)
current_state = mv.tags.get("state", "draft")
valid_transitions = {
"draft": ["candidate"],
"candidate": ["approved", "draft"],
"approved": ["deprecated"],
"deprecated": ["retired"],
}
if target_stage not in valid_transitions.get(current_state, []):
raise ValueError(
f"Invalid transition: {current_state} -> {target_stage}. "
f"Allowed: {valid_transitions.get(current_state, [])}"
)
# Verify required eval scores for production promotion
if target_stage == "approved":
run = client.get_run(mv.run_id)
quality = float(run.data.metrics.get("quality_score", 0))
safety = float(run.data.metrics.get("safety_score", 0))
if quality < 0.85:
raise ValueError(f"Quality score {quality} below threshold 0.85")
if safety < 0.95:
raise ValueError(f"Safety score {safety} below threshold 0.95")
# Record promotion
now = datetime.utcnow().isoformat()
client.set_model_version_tag(model_name, version, "state", target_stage)
client.set_model_version_tag(model_name, version, f"promoted_to_{target_stage}_at", now)
client.set_model_version_tag(model_name, version, f"promoted_to_{target_stage}_by", approver)
# Transition MLflow stage alias
stage_map = {
"candidate": "Staging",
"approved": "Production",
"deprecated": "Archived",
}
if target_stage in stage_map:
client.transition_model_version_stage(
model_name, version, stage_map[target_stage]
)
print(f"Model {model_name} v{version}: {current_state} -> {target_stage}")
print(f"Approved by: {approver} at {now}")
if __name__ == "__main__":
promote_model(
model_name=sys.argv[1],
version=sys.argv[2],
target_stage=sys.argv[3],
approver=sys.argv[4],
)
生命周期状态
| 状态 | 描述 | 允许服务 | 新用途 |
|---|---|---|---|
draft | 内部实验 | 仅限开发环境 | 仅限开发环境 |
candidate | 通过基线测试 | 预发布环境 | 预发布环境 |
approved | 已获准用于生产环境 | 所有环境 | 是 |
deprecated | 已宣布替代版本 | 仅限现有用途 | 已阻止 |
retired | 已归档以供审计 | 无 | 无 |
生命周期自动化
# lifecycle_policy.py
from mlflow.tracking import MlflowClient
from datetime import datetime, timedelta
def enforce_lifecycle_policies(mlflow_uri: str = "http://mlflow:5000"):
"""Run periodic lifecycle enforcement."""
client = MlflowClient()
for rm in client.search_registered_models():
for mv in client.search_model_versions(f"name='{rm.name}'"):
tags = mv.tags
state = tags.get("state", "draft")
# Auto-deprecate models with expired approvals (90 days)
if state == "approved":
approved_at = tags.get("promoted_to_approved_at")
if approved_at:
approved_date = datetime.fromisoformat(approved_at)
if datetime.utcnow() - approved_date > timedelta(days=90):
print(f"Auto-deprecating {rm.name} v{mv.version}: approval expired")
client.set_model_version_tag(rm.name, mv.version, "state", "deprecated")
client.set_model_version_tag(
rm.name, mv.version, "auto_deprecated_reason", "approval_expired"
)
# Auto-retire deprecated models after 30 days
if state == "deprecated":
deprecated_at = tags.get("promoted_to_deprecated_at")
if deprecated_at:
deprecated_date = datetime.fromisoformat(deprecated_at)
if datetime.utcnow() - deprecated_date > timedelta(days=30):
print(f"Auto-retiring {rm.name} v{mv.version}")
client.set_model_version_tag(rm.name, mv.version, "state", "retired")
client.transition_model_version_stage(
rm.name, mv.version, "Archived"
)
# Flag drafts with no activity for 14 days
if state == "draft":
created = datetime.fromisoformat(mv.creation_timestamp / 1000)
if datetime.utcnow() - created > timedelta(days=14):
print(f"Stale draft: {rm.name} v{mv.version}")
治理策略(OPA/Rego)
# policy/model_governance.rego
package model.governance
# Reject artifacts without SBOM
deny[msg] {
not input.metadata.sbom_uri
msg := "Model must include SBOM artifact URI"
}
# Block promotion if critical CVEs remain
deny[msg] {
input.target_state == "approved"
input.security_scan.critical_cves > 0
msg := sprintf("Cannot promote: %d critical CVEs unresolved", [input.security_scan.critical_cves])
}
# Require refreshed evals after prompt changes
deny[msg] {
input.target_state == "approved"
input.prompt_changed
not input.eval_refreshed_after_prompt_change
msg := "Evaluation must be re-run after prompt template changes"
}
# Require minimum eval scores for production
deny[msg] {
input.target_state == "approved"
input.metadata.quality_score < 0.85
msg := sprintf("Quality score %.2f below threshold 0.85", [input.metadata.quality_score])
}
# Require dual approval for high-risk models
deny[msg] {
input.target_state == "approved"
input.metadata.risk_rating == "high"
count(input.approvals) < 2
msg := "High-risk models require at least 2 approvals"
}
审计准备
维护以下内容的不可篡改记录:
- 谁在何时批准
- 执行了哪些策略检查
- 授予了哪些例外
- 在每个客户请求时间窗口内,哪个模型/版本提供了服务
故障排除
| 问题 | 诊断 | 解决方案 |
|---|---|---|
| 模型注册失败 | 检查 MLflow 服务器连接和制品存储权限 | 验证 S3/GCS 凭据和存储桶策略 |
| 晋级被策略阻止 | 查看 CI 输出中的 OPA 拒绝消息 | 补全元数据或申请策略例外 |
| 过时模型未自动退役 | 生命周期 cron 作业未运行 | 检查 Kubernetes 中的 CronJob 状态 |
| 模型版本重复 | CI 流水线中的竞态条件 | 通过注册表 API 或数据库添加锁定机制 |
| 缺少评估证据 | 评估流水线被跳过或失败 | 重新运行评估套件并重新注册 |
相关技能
- sbom-supply-chain - 来源信息和签名
- policy-as-code - 使用策略引擎强制执行治理
- llm-fine-tuning - 对适配器和训练产物进行版本管理
- llmops-platform-engineering - 平台 CI/CD 和晋级工作流
- ai-sre-incident-response - 模型问题的事件响应
评论
支持 Markdown