项目:离线合成评测数据流水线

项目目标

在 Windows 11、PowerShell 7 与 Python 3 标准库环境中,完成一条不联网、不调用模型、不使用真实数据或密钥的合成评测数据流水线:

  • 严格解析并验证版本化 JSON spec,拒绝重复 key、NaN、未知字段和布尔冒充数字;
  • 从“语言 × 场景”条件矩阵生成带稳定 ID、family、标签与 provenance 的候选;
  • 隔离 schema/来源错误、疑似个人信息和规范化精确重复,并保留拒绝原因;
  • 按 family 做 development/test 划分,验证条件覆盖与完整性;
  • 用冻结质量门输出 PASS、REVIEW 或 BLOCK,用独立退出码区分契约错误;
  • 生成内容指纹、manifest、限制清单,并以 43 项测试验证关键边界。

解释边界

所有文本都是作者设计的虚构模板。contains_real_data: false 是来源声明,不是对任意外部语料的相似性证明;正则扫描和精确去重也不是匿名化。本项目没有真实留出集、生成模型、近重复模型或差分隐私机制,因此不能声称生产效用、分布代表性、无版权风险或隐私保证。

项目文件

环境准备

项目没有第三方依赖。若需要练习隔离环境,把 venv 建在 vault 之外:

$venvDir = Join-Path $env:TEMP "ai-agent-engineer-synthetic-data-venv"
python -m venv $venvDir
& (Join-Path $venvDir "Scripts\Activate.ps1")
# 本项目无需 pip install。

从同时包含 docs/ 与 .website/ 的项目根目录进入示例目录:

$projectDir = (Resolve-Path -LiteralPath 'docs\数据合成\03-项目与自测\examples').Path
Push-Location -LiteralPath $projectDir

后续命令全部使用 -B,避免在知识库产生 __pycache__ 或 .pyc。

严格 spec 契约

spec 把数据工程中的隐含决定变成可审计输入:

区域说明不能替代什么
dataset ID/version/schema标识发布与兼容边界内容质量
purpose/non-goals限定支持的用途与非目标真实效用测试
generator类型、版本、核对日期、是否接触真实数据授权或匿名性证明
splitseed 与 development family 数随机逐行划分
quality gates每格/总量/重复率/覆盖门人工标签与真实留出
teaching faults是否注入可追踪坏样本真实故障分布
conditions语言、场景、oracle、关键性与模板生产发生频率

加载器拒绝重复 JSON key 和非标准 NaN/Infinity;每层字段必须精确匹配。数值 gate 不接受 true/false,因为 Python 中布尔值是整数子类,若不显式拒绝可能把 true 静默当成 1。

生成、隔离与去重

正常 spec 定义 2 种语言 × 3 个场景 × 每格 2 个模板,共 12 个有效候选。脚本额外注入:

  1. 一个内容完全相同但 ID 不同的候选,用于验证规范化精确去重;
  2. 一个缺少 expected_action 的候选,用于验证契约隔离。

候选包含 candidate_id、family_id、条件、输入、oracle、critical 标记、synthetic: true 与 provenance。provenance 不只检查字段存在:其 generator type/version、真实数据声明、模板 ID 的条件前缀与变量映射必须与冻结 spec 一致,防止旧生成器或另一条件的模板伪装成当前批次。它仍是技术 trace,不是授权、版权或匿名性证明。过滤顺序是:

  1. 精确字段/schema 与 oracle 一致性;
  2. provenance 字段和真实数据声明一致性;
  3. 演示用邮箱/电话模式扫描;
  4. candidate ID 唯一性;
  5. 语言、场景与规范化输入的精确去重。

拒绝项进入 rejection_log,包含阶段和原因。扫描未命中只能说明这组规则未发现问题,不能推出“无个人信息”;近重复和语义复制仍需额外工具与人工审查。

Family 划分与质量门

同一语言/场景模板 family 的变体整体进入 development 或 test,防止近似改写跨集。发布后验证:ID 唯一、规范化输入唯一、family 不跨 split、两个 split 都存在、全部条件格覆盖、所有记录标记 synthetic,且 provenance 完整。

质量门按以下顺序解释:

  1. 条件缺失、每格数量不足、总量不足或真实来源声明未审查 → BLOCK;
  2. 重复比例超过软门 → REVIEW;
  3. 所有冻结门通过 → PASS;
  4. 文件、JSON 或 schema 不合法 → 契约错误,不生成数据报告。

BLOCK 表示流水线成功执行但不允许发布;契约错误表示连比较/生成前提都不成立。两者不能混成“脚本失败”。

运行正常 spec

python -B .\build_synthetic_evalset.py --spec .\synthesis_spec.json
if ($LASTEXITCODE -ne 0) { throw "PASS fixture exit code mismatch" }

预期:

  • action=PASS,退出码 0;
  • raw=14、contract_rejected=1、duplicate_rejected=1、released=12;
  • 6 个条件格均保留 2 条;
  • development 有 2 个 family/4 条,test 有 4 个 family/8 条;
  • manifest 含 sha256: 内容指纹;
  • stdout 是 JSON,不写任何输出文件。

运行质量回归

python -B .\build_synthetic_evalset.py `
  --spec .\synthesis_spec_quality_regression.json
if ($LASTEXITCODE -ne 1) { throw "quality regression exit code mismatch" }

该 spec 的结构和生成逻辑都合法,但把 min_records_per_cell 冻结为 3,而每格只有 2 条,预期 action=BLOCK、退出码 1。这证明“成功生成很多行”不等于达到发布门。

运行契约错误

python -B .\build_synthetic_evalset.py `
  --spec .\synthesis_spec_contract_error.json
if ($LASTEXITCODE -ne 2) { throw "contract error exit code mismatch" }

该 fixture 故意包含未知顶层字段,预期 stderr 说明字段不匹配,stdout 为空,退出码 2。

CLI 约定:

  • 0:PASS;
  • 1:REVIEW 或 BLOCK;
  • 2:文件、JSON、字段、类型或取值契约错误。

三模式测试与语法检查

python -B -m unittest -v test_build_synthetic_evalset
if ($LASTEXITCODE -ne 0) { throw "normal tests failed" }
 
python -B -O -m unittest -v test_build_synthetic_evalset
if ($LASTEXITCODE -ne 0) { throw "optimized tests failed" }
 
python -B -W error -m unittest -v test_build_synthetic_evalset
if ($LASTEXITCODE -ne 0) { throw "warnings-as-errors tests failed" }
 
python -B -c "from pathlib import Path; [compile(p.read_text(encoding='utf-8'), str(p), 'exec') for p in map(Path, ('build_synthetic_evalset.py', 'test_build_synthetic_evalset.py'))]"
if ($LASTEXITCODE -ne 0) { throw "syntax check failed" }
Pop-Location

测试覆盖重复 key、NaN、未知/缺失字段、布尔数值、非法 gate、空模板、候选/来源错误、生成器版本/模板 lineage/变量映射不一致、疑似个人信息、重复 ID、family 划分、覆盖、PASS/REVIEW/BLOCK、真实来源硬门、指纹和三类 CLI 退出码。生产代码不使用 assert,因此 -O 不会移除关键验证。

动手练习

  1. 把 max_duplicate_fraction 调为 0.01,验证结果变成 REVIEW 而非 BLOCK;
  2. 增加 tool-timeout 条件,同时写 oracle、critical 标记和两条模板,再解释它与哪些场景组合有业务意义;
  3. 新增一个 candidate 的邮箱样式内容,验证进入拒绝日志,并解释为何仍不能称 PII 扫描完整;
  4. 设计 n-gram/Embedding 候选对报告,但把最终合并交给有证据的规则或人工;
  5. 准备一个不参与生成或调参的授权真实小留出,设计合成数据对系统错误模式的效用实验;
  6. 若要使用真实日志,先画授权、最小化、保留、访问、删除和发布审批流程,再改 contains_real_data,不要为了跑通直接关闭硬门。

自测题

  1. 为什么 contains_real_data: false 不是匿名性证明?
  2. 为什么重复率可设软门,而缺失关键条件通常应设硬门?
  3. 固定 seed 能保证什么,不能保证什么?
  4. 为什么同一 family 的改写不能跨 development/test?
  5. fingerprint 变化能说明什么,不能说明什么?
  6. 43 项测试通过后,为什么仍不能声称数据对真实模型训练有效?

掌握检查

  • 能解释 spec、候选、发布记录、拒绝日志与 manifest 的职责;
  • 能区分样本契约错误、数据集质量 BLOCK 和软门 REVIEW;
  • 能证明 family 划分与条件覆盖由代码实际检查;
  • 能运行 43 项测试和三类 CLI 场景,并解释退出码;
  • 能列出近重复、真实效用、隐私、许可与人工审核的剩余边界;
  • 不会把 synthetic、哈希、扫描或无真实输入声明写成形式隐私保证。

项目边界与下一步

本项目建立的是透明、可重复的模板合成基线。接入模型生成时,沿用同一契约、provenance、拒绝日志和独立验证,并回到 模型生成与条件覆盖。正式发布前按 质量、效用与真实数据校准 使用独立真实证据,再按 隐私、记忆、偏差与版权 与 版本、评测与发布 完成风险和维护审批。

参考资料