评测与迁移项目

项目目标

本项目用两套完全隔离的手工向量空间练习四件事:

  1. 空间契约与向量输入校验;
  2. ACL 过滤后的 exact similarity search;
  3. Recall@k、MRR、nDCG 与子组报告;
  4. 模型迁移的 inventory/canonical 对账与 top-k 变化审计。

它不下载或运行真实 embedding 模型,输出也明确声明 hand-authored vectors。这能验证代码和门禁,不代表任何模型的业务效果。

项目文件

  • [[Knowledge/AI Agent Engineer/docs-CN/Embedding/examples/evaluate_embedding_space.py|evaluate_embedding_space.py]]:严格加载、数学函数、检索、指标、inventory 和 migration audit;
  • [[Knowledge/AI Agent Engineer/docs-CN/Embedding/examples/embedding-fixture.json|embedding-fixture.json]]:两个空间、20 个空间内 items 和 4 条分级相关 query cases;
  • [[Knowledge/AI Agent Engineer/docs-CN/Embedding/examples/test_evaluate_embedding_space.py|test_evaluate_embedding_space.py]]:32 项标准库 unittest。

脚本只输出 ID、分数、指标与契约摘要,不输出真实凭据;fixture 只有教学文本和手工向量。

两套空间刻意不兼容

字段toy-v1toy-v2
provider/modellocal-fixture / toy-bi-encoder相同教学名称
revisionv1v2
dimension45
metriccosinedot
normalizedfalsetrue
dtypefloat32float32
items6 documents + 4 queries相同 canonical items

即使两套空间的文本与 item IDs 相同,revision、dimension、metric 和 normalization 已不同,向量不能直接交叉比较。migration_audit因此报告 vectors_directly_comparable=false。

每个空间中的 query/document role 都显式为 query / document。真实模型可能使用不同 method、task type 或 prompt,应把实际值写入契约。

严格输入门禁

Fixture 顶层只有 contracts/items/queries。加载器拒绝:

  • 重复 JSON key、NaN/Infinity 和超过 5 MiB 的 fixture;
  • 多余/缺失字段;
  • 重复 space 或 item;
  • 不存在的空间、错误 role;
  • bool 冒充数字、错维、零向量、NaN/Inf,以及会在转换为 float 时溢出的超大整数;
  • normalized=true 但 norm 不在容差内;
  • 空文本、重复 ACL 和坏 source revision;
  • query/gold 缺项、grade 不在 1..3;
  • gold document 对查询主体未授权。

文本先做 LF 与 Unicode NFC 规范化,再计算 content_sha256。迁移审计用 role、text、ACL、source revision 与 hash 比较 canonical 数据。

检索流程

search 对一个空间执行:

  1. 找到该空间的 query item;
  2. 验证它使用 contract.query_role;
  3. 主体 groups 为空时 fail-closed 返回空;
  4. 只保留同空间、document role、ACL 相交的 documents;
  5. 用该空间 contract.metric 算 exact score;
  6. 按 score 降序、item ID 升序稳定打破平分;
  7. 返回 top-k。

未授权文档即使与 query 向量完全相同,也不会进入评分候选。项目只演示 group OR 语义,不是完整租户/IAM 实现。

项目没有 score threshold,所以 authorized 集里即使低分/零分也可能补足 top-k。这正好提醒:最近邻不等于可回答;无答案阈值必须在真实开发集按空间校准,本 fixture 不评测端到端拒答。

三个检索指标

Recall@k

把 relevance grade 大于 0 的 documents 都视为相关:

它关注必要候选是否找全,不关心相关项内部排序。

MRR

对每个 query 找第一个相关项的排名 ,记 ;未命中为 0,再对查询平均。MRR 强调首个相关项出现多早,但不能保证多证据齐全。

nDCG@k

项目允许 grade 1..3。第 位的增益:

再除以理想排序的 IDCG@k。nDCG 会惩罚高等级证据排在低等级证据之后。一个 ranked list 中每个 item ID 必须唯一;重复同一高等级 ID 会重复计算 gain,甚至制造大于 1 的伪 nDCG。项目因此在 Recall、MRR 与 nDCG 的公共入口统一拒绝重复 ID,并验证 qrels grade 是 1~3 的非布尔整数。指标仍必须一起看:Recall 1.0 可能伴随较低 nDCG。

运行项目

从项目根目录(同时包含 docs/ 与 .website/)运行:

$env:PYTHONDONTWRITEBYTECODE = '1'  # 禁止写入 Python 字节码缓存,保持项目目录可复现。
python -B -W error '.\docs\Embedding\examples\evaluate_embedding_space.py'  # 用默认 k=3 执行离线 exact 检索和迁移审计。

可显式改变 k 或 fixture:

python -B -W error '.\docs\Embedding\examples\evaluate_embedding_space.py' --k 2  # 覆盖默认值,只取每条查询的前两个授权候选。

非正整数 k 会失败,不会静默改成默认值。

当前确定性结果

截至 2026-07-22,默认 k=3:

空间item 数原始向量理论 bytesmean Recall@3MRRmean nDCG@3
toy-v1101601.01.01.0
toy-v2102001.01.01.0

estimated_raw_vector_bytes = item_count × dimension × 4,不含 ID、metadata、索引、对齐或副本。

迁移报告:

  • inventory match:true;
  • canonical match:true;
  • mechanical gates pass:true;
  • 三个质量均值 delta:0;
  • mean top-k Jaccard:0.875;
  • quality decision required:true。

为什么质量均值全相同但 Jaccard 不是 1?image-example的首个相关文档两边都正确,后两个零分候选因空间坐标和平分顺序不同而变化。业务指标没有退化,但候选集合发生改变。真实迁移要检查 per-query 变化和下游影响,不能只看三个均值。

“机械门禁通过”也不自动表示可以上线;许可、隐私、延迟、费用、关键子组和回滚仍需决策,所以报告固定保留 quality_decision_required=true。

运行测试

$env:PYTHONDONTWRITEBYTECODE = '1'  # 不把测试运行产生的缓存文件留在课程目录中。
python -B -m unittest discover -s '.\docs\Embedding\examples' -p 'test_evaluate_embedding_space.py' -v  # 正常模式运行全部单元测试并显示每个用例。
python -B -O -m unittest discover -s '.\docs\Embedding\examples' -p 'test_evaluate_embedding_space.py' -v  # 优化模式复跑,检查没有依赖裸 assert。
python -B -W error -m unittest discover -s '.\docs\Embedding\examples' -p 'test_evaluate_embedding_space.py' -v  # 将 warning 升级为错误,发现弃用或资源问题。
python -B -O -W error -m unittest discover -s '.\docs\Embedding\examples' -p 'test_evaluate_embedding_space.py' -v  # 同时覆盖优化与严格 warning 的最严运行组合。

测试覆盖:

  • contract 签名、非法 dimension/metric/role/dtype;
  • normalize、cosine、dot、Euclidean 与坏数值;
  • 严格 JSON、精确字段、重复 ID、错空间;
  • 向量维度、bool、零向量、normalized norm;
  • query/gold existence、grade 与授权;
  • 两空间预期排名、ACL 评分前过滤、空主体 fail-closed;
  • Recall/MRR/nDCG 已知算例、重复排名与非法 grade 失败关闭;
  • 子组、inventory bytes 与 norm;
  • 迁移的 inventory/canonical drift;
  • CLI 普通与 -O 输出逐字节一致;
  • 非正 k 失败且 stderr 为 UTF-8。

如何读迁移审计

Mechanical gates

  • inventory_match:旧新 item ID 集合一致;
  • canonical_match:同 ID 的 role/text/ACL/source revision/hash 一致;
  • mechanical_gates_pass:以上两项都通过。

这些门禁抓“漏编码、错正文、ACL 漂移”,不比较向量数值是否相同;新空间本来就应产生不同向量。

Quality delta

对同一 query/gold,计算新均值减旧均值。Delta 为 0 不代表两空间相同,也不代表没有关键 query 退化。查看 details、subgroups 和 per_query_agreement。

Top-k Jaccard

它测候选集合变化,不判断哪边更相关。必须与人工 relevance、rerank 和最终回答联合解释。

必做实践

A. 制造可解释退化

修改 toy-v2 的 q-retry 或 doc-retry 向量,让高等级相关文档掉到第二/第四位。预测 Recall、MRR、nDCG 哪些变化,再运行验证。不要修改 gold 迎合结果。

B. 测试 canonical drift

只改 toy-v2 doc-timeout 的正文,保持 item ID。观察 canonical_mismatches 和 mechanical gate;解释为什么“向量生成成功”仍不得切换。

C. 测试角色和归一化错误

分别:

  • 把 document role 写成 query;
  • 给 normalized=true 的向量 norm=2;
  • 用 bool 代替一个数值。

记录加载器在哪一层失败,以及这类错误若未拦截会怎样污染索引。

D. 增加子组

新增专名、数字、英文或代码 query,不改变现有 query。为每条标 grade 1..3,并比较总体与子组指标。确保 gold documents 对主体可见。

E. 设计无答案阈值实验

不要直接给脚本写一个“0.8 通用阈值”。先准备有答案/无答案开发集,分别在 toy-v1/toy-v2 校准;保存 precision/recall 或误报/漏报;最后在未调参测试集评估。

接入真实模型的最小改造

保持 QueryCase、relevance 与指标层不变,新增 provider adapter:

  1. 固定 canonical texts 和 input hashes;
  2. 保存官方 model/revision/role/dimension/metric/normalize/SDK/获取日期;
  3. 文档和 query 分别按官方契约编码;
  4. 对响应逐项 ID/维度/finite/norm 对账;
  5. 写入新 space_id,不覆盖 toy 或旧生产空间;
  6. 先用 exact float 比较候选模型;
  7. 再单独测降维、量化、ANN 和 rerank;
  8. 原始 per-query 结果保留为可审计产物,但不要提交敏感正文或大型向量数据。

无密钥或无网络时明确记录“未执行”,不能把 fixture 结果写成真实模型成绩。

发布验收清单

  • Gold、开发集与保留测试集用途分开。
  • Canonical item、ACL、revision 和删除水位对账。
  • 每个空间有完整签名且物理/逻辑隔离。
  • Query/document 角色按当前官方文档编码。
  • 质量报告含 per-query、关键子组与多个指标。
  • Score threshold 在每个空间开发集单独校准。
  • 延迟、吞吐、存储、重建时间和费用在预算内。
  • 越权、空主体与 parent 展开测试 fail-closed。
  • 影子/灰度、原子 alias、监控和回滚演练通过。
  • 许可、隐私、保留与删除策略获批。
  • Fixture 成绩没有被表述为真实模型效果。

参考资料

来源获取日期:2026-07-22。完成后返回 [[Knowledge/AI Agent Engineer/docs-CN/Embedding/00-目录|Embedding 目录]],继续 [[Knowledge/AI Agent Engineer/docs-CN/向量数据库/00-目录|向量数据库]]。