用 Docker Sandboxes 构建可复现的 AI 评测工作流

2026-09-02 35 预计阅读时间: 1 分钟
来源: docker.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

AI 评测最难处理的,往往不是把模型调用起来,而是回答一个更基础的问题:这次结果到底是在什么环境里产生的?依赖版本、提示词、输入数据、运行参数和工具行为只要有一项变化,评测结果就可能失去可比性。

Docker Sandboxes 可以把评测过程放进隔离且可记录的运行环境中,让团队更容易固定执行条件、保存结构化产物,并为每个结果留下运行时证据。它不会自动解决评测设计问题,但能显著减少“同一份代码在不同机器上跑出不同结论”的情况。

把评测拆成可追踪的输入和输出

一个可复现的评测任务,至少应该明确记录以下内容:

  • 模型名称和版本
  • 系统提示词、用户提示词或提示词模板
  • 测试集版本和样本数量
  • 依赖文件与基础镜像
  • 温度、最大输出长度等推理参数
  • 评测脚本的提交哈希
  • 原始模型响应
  • 聚合后的指标和错误信息

不要只保存一个最终分数。例如 accuracy: 0.82 无法说明哪些样本失败,也无法判断失败来自模型、解析器还是运行环境。更实用的产物通常包含一份逐样本 JSONL、一份汇总 JSON,以及一份描述运行环境的元数据文件。

用容器固定执行环境

可以先用普通 Docker 容器建立评测基线,再把同样的镜像接入 Docker Sandboxes。下面是一个最小示例。假设项目目录包含 evaluate.pyrequirements.txt

Dockerfile

FROM python:3.11-slim

WORKDIR /workspace
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY evaluate.py .
ENTRYPOINT ["python", "evaluate.py"]

evaluate.py

import json
import os
import platform
from datetime import datetime, timezone
from pathlib import Path

OUTPUT = Path(os.environ.get("OUTPUT_DIR", "/workspace/artifacts"))
OUTPUT.mkdir(parents=True, exist_ok=True)

examples = [
    {"id": "case-001", "input": "2 + 2 = ?", "expected": "4"},
    {"id": "case-002", "input": "首都是北京的国家是?", "expected": "中国"},
]

# 这里替换成实际的模型 API 调用或本地推理逻辑。
def run_model(text: str) -> str:
    return "4" if text == "2 + 2 = ?" else "中国"

results = []
for example in examples:
    actual = run_model(example["input"])
    results.append({
        "id": example["id"],
        "input": example["input"],
        "expected": example["expected"],
        "actual": actual,
        "correct": actual == example["expected"],
    })

correct = sum(item["correct"] for item in results)
summary = {
    "timestamp": datetime.now(timezone.utc).isoformat(),
    "python": platform.python_version(),
    "platform": platform.platform(),
    "total": len(results),
    "correct": correct,
    "accuracy": correct / len(results),
}

(OUTPUT / "results.jsonl").write_text(
    "".join(json.dumps(item, ensure_ascii=False) + "\n" for item in results),
    encoding="utf-8",
)
(OUTPUT / "summary.json").write_text(
    json.dumps(summary, ensure_ascii=False, indent=2),
    encoding="utf-8",
)
print(json.dumps(summary, ensure_ascii=False))

构建并运行:

docker build --tag ai-eval:local .
mkdir -p artifacts
docker run --rm \
  --network none \
  --read-only \
  --tmpfs /tmp \
  --mount "type=bind,src=$PWD/artifacts,dst=/workspace/artifacts" \
  ai-eval:local

cat artifacts/summary.json
cat artifacts/results.jsonl

这个例子关闭了网络,并把结果目录单独挂载出来。实际评测如果需要访问模型 API,应改为受控网络策略,并通过环境变量或密钥管理系统注入凭据,不要把 API Key 写入镜像或结果文件。

把容器运行升级为 Sandbox 运行

Docker Sandboxes 的价值在于进一步隔离运行过程,尤其适合会执行代码、调用工具或操作工作区的 AI 评测任务。具体命令和参数取决于安装的 Docker 版本及 Sandbox CLI,因此可以先检查本机支持的接口:

docker sandbox --help
docker sandbox run --help

如果当前环境支持从已有镜像启动 Sandbox,可以采用类似下面的流程。命令中的挂载参数需要按照本机 CLI 的帮助信息调整:

docker build --tag ai-eval:local .
mkdir -p artifacts

docker sandbox run \
  --network none \
  --mount "type=bind,src=$PWD/artifacts,dst=/workspace/artifacts" \
  ai-eval:local

可以把每次评测封装成一个脚本,统一生成运行证据:

#!/usr/bin/env bash
set -euo pipefail

RUN_ID="$(date -u +%Y%m%dT%H%M%SZ)"
OUT="artifacts/$RUN_ID"
mkdir -p "$OUT"

printf '{"run_id":"%s","git_commit":"%s","image":"%s"}\n' \
  "$RUN_ID" \
  "$(git rev-parse HEAD 2>/dev/null || printf unknown)" \
  "ai-eval:local" > "$OUT/manifest.json"

# 根据本机 Docker Sandbox CLI 的实际参数运行。
docker sandbox run \
  --network none \
  --mount "type=bind,src=$PWD/$OUT,dst=/workspace/artifacts" \
  ai-eval:local

运行证据不应只包含终端日志。建议至少保存以下文件:

artifacts/<run-id>/
├── manifest.json     # 提交哈希、镜像标签、运行 ID
├── summary.json      # 汇总指标
├── results.jsonl     # 逐样本结果
└── stdout.log        # 原始标准输出,按需保存

如果评测依赖外部模型服务,还应记录服务端点的逻辑名称、请求参数、超时和重试策略。涉及隐私数据时,要在写入 results.jsonl 前脱敏,并限制日志中出现完整提示词和模型响应。

可复现不等于结果永远相同

容器能固定 Python 版本和依赖,但不能自动消除所有随机性。模型服务可能发生版本更新,GPU 推理可能存在非确定性,外部搜索或工具调用也会改变返回内容。因此评测系统要区分“环境可复现”和“结果确定性”。

可以采用这些控制手段:

  • 固定基础镜像版本,不使用没有版本号的 latest
  • 提交锁定的依赖文件,并在构建阶段记录镜像摘要。
  • 固定随机种子;如果底层框架支持,开启确定性算法。
  • 对外部 API 使用录制响应、测试替身或固定快照。
  • 保存原始响应,而不是只保存解析后的标签。
  • 为评测脚本和数据集生成版本号或内容哈希。
  • 将失败样本、超时和解析异常单独计数。

落地检查清单

开始使用 Docker Sandboxes 前,可以先验证四件事:

  1. 同一个镜像在两台机器上能够生成相同格式的产物。
  2. 评测结果目录不依赖容器内部的临时文件。
  3. 运行记录包含代码、镜像、数据和参数的版本信息。
  4. 网络、密钥、数据脱敏和日志保留策略已经明确。

Docker Sandboxes 最适合作为评测执行层,而不是评测方法本身。团队仍然需要定义合理的数据集、指标和失败分类;Sandbox 则负责让每次执行更隔离、更容易审计,也更方便在 CI 或批量实验中重放。先从一个小型基准集和结构化产物开始,再逐步加入网络控制、响应快照和自动化对比,通常比一次性改造整套评测平台更稳妥。


相关推荐