文章要求评测运行先核对模型标识和服务端版本,只有与基线一致时才允许比较分数。否则,提示词退化、模型替换和服务端变化会混在同一个分差中,即使测试输入和评分器固定也无法可靠归因。
当 model stamp(模型标识)或 server revision(服务端版本)也发生变化时,分数差值就不能作为 prompt 发生变化的证据。每晚调用可替换模型端点的评测程序,即使一行 prompt 都没改,也可能把这些变量混在一起。记录下来的运行结果应当拒绝参与比较,直到 model stamp 和 server revision 都与存储的基线一致。这种拒绝本身就是回归信号,而且应当在任何评分器断言获准执行之前显现出来。
团队经常把免费的模型路由当成昨天候选模型的直接替代品,然后把新的平均分当成质量指标。替换成本很低,所以在事故复盘、配额暂停和日常主机维护期间,这种操作都会发生。分数降低,可能确实是 prompt 回归,也可能是模型能力更弱,或者服务端镜像改变了分词方式。如果没有身份标识,这三种原因就会被压成一个数字,留给值班工程师的连一份堆栈跟踪都没有。
已有的检查会在信任差值之前,先固定测试 fixture、评分器和用例位置。这些固定措施能防止不断变化的评分标准改写历史,却没有指明生成 completion 的模型是谁。fixture hash 可以保持不变,而端点却悄悄路由到了另一套模型权重。缺失的字段就是 model stamp:它应当和 fixture hash 一起存储,而不是从分数里推断。
实际的修复方案,是让每次夜间运行和每次手动重跑都携带一份由三部分构成的记录。用例 manifest 列出标准输入、预期 envelope(输出结构),以及根据规范文件字节计算出的内容 hash。候选 adapter 返回 completion,以及主机报告的模型标识和服务端版本。隔离检查只有在 manifest hash、model stamp 和 server revision 全部与基线记录一致时,才计算分数差值。
可以把 stamp 理解为湿实验室里试剂瓶上的批号。两次检测可以使用同一张实验流程卡,却仍然因为试剂瓶在夜里被换掉而得到不同结果。在两个批号都与实验记录本一致之前,你不会把这种差异发表为方法改进。prompt eval 也值得得到同样的对待,因为免费主机可能更换试剂瓶,却不通知评分榜。
下面展示的 manifest 是一份方案示例,并非从任何在线评测主机捕获的生产运行记录。每个用例都包含模型可以看到的输入,以及评分器只能在调用返回后看到的预期 envelope。把标准答案排除在 prompt 之外,是另一项独立控制措施,本文不再讨论这个问题。这里新增的要求是对文件字节计算 hash,避免对预期字段的悄悄修改隐藏在一次模型替换之中。
{
"suite": "envelope-v3",
"cases": [
{
"id": "refund-status",
"input": {"ticket": "T-1842", "ask": "status"},
"expected": {"tool": "lookup_ticket", "args": {"id": "T-1842"}}
}
]
}
adapter 的接口约定保持足够精简,让审查者无需引入新框架,就能重新实现同样的检查。伪造的 stamp 会让本来不同的运行看起来可以比较,因此,主机没有提供的标识必须保留为 unknown。unknown 应当使隔离检查失败,而不是被悄悄替换成某个默认值,假装连接的仍然是昨天的模型。下面的代码是尚未执行的方案代码,只会对本地文件计算 hash,不会发起网络调用。
#!/usr/bin/env python3
"""Proposal harness: refuse score diffs when stamps differ. Not a measured run."""
import hashlib
import json
import sys
from pathlib import Path
STAMP_FIELDS = ("manifest_hash", "model_stamp", "server_revision")
def file_hash(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def grade_envelope(completion: dict, expected: dict) -> dict:
missing = [key for key in expected if key not in completion]
wrong = [
key
for key in expected
if key in completion and completion[key] != expected[key]
]
return {
"passed": not missing and not wrong,
"missing": missing,
"wrong": wrong,
}
def quarantine(baseline: dict, candidate: dict) -> dict:
reasons = [
field
for field in STAMP_FIELDS
if baseline.get(field) != candidate.get(field)
]
if baseline.get("passed") not in (0, 1) or candidate.get("passed") not in (0, 1):
reasons.append("passed")
if reasons:
return {"comparable": False, "reasons": reasons, "delta": None}
return {
"comparable": True,
"reasons": [],
"delta": int(candidate["passed"]) - int(baseline["passed"]),
}
def load_run(path: Path) -> dict:
record = json.loads(path.read_text())
for field in ("model_stamp", "server_revision"):
if field not in record or record[field] in ("", None):
record[field] = "unknown"
return record
def main() -> int:
if len(sys.argv) != 4:
print(
"usage: quarantine_diff.py MANIFEST BASELINE CANDIDATE",
file=sys.stderr,
)
return 64
manifest = Path(sys.argv[1])
baseline = load_run(Path(sys.argv[2]))
candidate = load_run(Path(sys.argv[3]))
candidate["manifest_hash"] = file_hash(manifest)
decision = quarantine(baseline, candidate)
print(json.dumps(decision, indent=2))
return 0 if decision["comparable"] else 2
if __name__ == "__main__":
raise SystemExit(main())
本地检查使用两个 fixture 文件,它们只有记录的 model stamp 不同,其他内容完全一致。当隔离检查拦下这组跨模型比较时,下面的命令应当以状态码 2 退出。状态码 0 则意味着三个标识字段匹配,并且数值差值已经输出到标准输出。无论是哪种退出状态,都不能说明 prompt 本身变好了、发生了回归,或者在语义上保持一致。
python3 quarantine_diff.py cases/manifest.json runs/baseline.json runs/swapped_model.json
echo "exit=$?"
python3 -c "import quarantine_diff as q; d=q.quarantine({'manifest_hash':'a','model_stamp':'m1','server_revision':'r1','passed':1},{'manifest_hash':'a','model_stamp':'m2','server_revision':'r1','passed':1}); assert d['delta'] is None; print(d)"
一条通过审查的基线记录,可以像下面这个对象一样,将 passed 存储为整数。把 passed 存成整数,可以让后续的 delta 是一次减法,而不是一段主观判断。model stamp 是从主机响应中复制的不透明字符串,不是评测程序自己起的昵称。如果主机后来针对同一个营销名称返回了不同字符串,隔离检查就会把这个字符串视为新的批号。
{
"manifest_hash": "recorded-sha256",
"model_stamp": "host-reported-id",
"server_revision": "image-digest",
"passed": 1
}
假设基线的 passed 标记是 1,候选的 passed 标记也是 1,但 model stamp 发生了变化。直接把这两个标记相减,结果会是零,在看图表的人眼里,这似乎意味着稳定。隔离检查返回的却是 null delta,因为不同 stamp 下的分数相同,不能作为稳定的证据。显示一个零,会是这个评测程序在此情形下可能产生的最具误导性的结果。
当候选保留 manifest hash,却改变 model_stamp 时,打印出来的判定结果会点名这个字段,并把 delta 设为 null。这个 null 必须在 dashboard 中保留下来,因为把 null 强制转换成零,会掩盖隔离结果,让原来的 bug 再次出现。应当把 reasons 列表和 null 一起存储,并在 comparable 为 false 时告警,而不是等分数越过某个阈值才告警。阈值告警默认这些运行可以比较,而验证这个前提,正是这个评测程序存在的目的。
即使只有 server revision 变化,而模型的营销名称保持不变,也应当拒绝比较。新的镜像 digest 可能改变 tokenizer、超时设置或 tool schema,而对外宣传的模型名称仍然不变。revision 字段的作用,就是防止这类变化冒充 prompt 的修改。主机成本是另一个独立维度,运行 adapter 的地方更便宜,并不意味着身份就被冻结了。
披露:本文作为 MonkeyCode 产品推广的一部分撰写。运营方将 MonkeyCode 描述为一个开源项目,提供免费模型访问和免费服务器选项。这两项可用性声明均由运营方提供;之所以与本文有关,是因为候选 adapter 需要一个成本足够低、能够支撑每晚运行一次的主机。本文未列出具体的 token 配额、模型标识、硬件和优惠持续时间,因为这份草稿没有附上任何一手文档。
方案脚本只有在三个标识字段匹配,并且数值 delta 已经输出时,才返回状态码 0。状态码 2 表示隔离检查触发,这是成功检测到问题,而不是进程意外崩溃。wrapper 应当把状态码 2 作为呼叫值班人员的告警,并把输入文件缺失视为独立的运维错误。如果把这两种结果混进同一条告警规则,值班团队就会逐渐学会忽略这种告警。
分数保持不变时,尤其容易发生静默回归,因为一条平坦的曲线不会引来审查者。如果模型替换后通过数没有变化,那么除非在绘制图表之前比较 stamp,否则这种替换就是不可见的。这也解释了为什么即使两个 passed 标记恰好相同,判定对象仍然要携带 reasons 列表。图表仍然可以稍后绘制,但只能使用隔离检查已经标记为 comparable 的记录。
一个实用的夜间流程,会按固定顺序执行四项检查,它们都不是关于模型质量的口号。首先对 manifest 计算 hash,如果基线索引中没有这个 hash,就拒绝本次运行。其次调用候选 adapter,即使 completion 失败,也要持久化主机报告的 model stamp 和 server revision。第三,对存储的 completion 评分;然后执行隔离检查,在运行结果不可比较时呼叫人工处理。
这些检查比 adapter 使用哪种语言更重要,shell wrapper 也可以在手动重放后调用同样的判定逻辑。每条候选记录都写入一个新路径,只有在人接受两个 stamp 和 delta 之后,才能将它提升为基线。自动化可以追加运行文件,但不应自行批准新的批号。只有人在读过两个 stamp 之后,才有权替换参考记录。
对原始文件字节计算内容 hash,意味着编辑器重写换行符,或者调整 manifest 中键的顺序,都会改变 hash。这种敏感性是有意为之,因为一次悄无声息的格式化,也可能修改某个被人工漏看的预期字段。如果需要在不同机器上得到稳定的 hash,就应当先将 JSON 规范化,再计算 hash,并存储这些规范化后的字节。方案脚本对文件保存时的原始内容计算 hash,因此,不同的换行符会触发隔离,直到字节完全一致。
精确的 envelope 相等判断,会把不错的改述判为失败,也会漏掉那些仍然携带预期键、却有害的 completion。对于开放式写作质量、偏好排序,或任何需要第二个模型担任裁判的评分器,这种方法都不适用。当主机无法报告稳定标识时,它也不适用,因为每次运行都会被隔离,告警最终会变成噪声。尚未冻结用例 manifest 的团队,应当先把这个文件建立起来,因为即使有 stamp,不断变化的用例集仍然会产生无法解读的 delta。
已经在同一个固定模型内比较差值的团队,可以直接添加两个 stamp 字段,无需重建评测套件。给旧记录回填字符串 unknown,并将 unknown 视为不可比较,直到在人工观察下记录一份新的基线。不要凭记忆猜一个营销名称来回填,因为猜出来的 stamp 会制造可以比较的假象。缺失的 stamp 是一次诚实的阻断,而猜出来的 stamp 则会悄悄把原来的 bug 引回来。
如果当前记录已经存储了主机标识,就比较两条已保存的记录,看看服务端迁移是否会改变这个字符串。只做一次比较,就足以判断隔离检查是否会在上周的夜间任务中触发。这项检查不需要新的评分标准、新的供应商,也不需要宣称哪个模型更好。它只是在问:图表上已有的分数,是否是在同一个批号下得到的。
如需进一步处理,可以考虑屏蔽此人和/或举报滥用行为。