提示词模板的哈希在参数快照里没有位置 #3

Closed
opened 2026-08-26 19:57:01 +08:00 by iomgaa · 1 comment
Owner

我们是谁

dissect2 —— dissect 的第二版,正在重建,要接 PolyLoop 当执行内核。我们只提需求、不改这个仓库。

问题

提示词模板的哈希在参数快照里没有位置。

src/polyloop/session/__init__.pyparameter_snapshot docstring 写着:

上下文与注入内容不进快照。 它们是这次运行的输入数据不是参数,进快照会让快照变成一份数据副本,而它们可能很大。

这个理由是对的,我们不反对。问题在于它把提示词模板本身也一起挡在外面了,而模板不是数据,是参数。

为什么我们非要这一维不可

我们是一个论文项目,研究的正是「改这份文本会让 agent 表现变好多少」。提示词模板是这套实验里被改的东西之一。

上一版把模板文件的 sha 算进 run 快照,理由是:不记的话,「这次运行用的是哪一版提示词」就只剩 harness 的 git SHA 一个粒度——而同一个 commit 下我们可能在试不同的模板。

后果很具体:换一份提示词模板续跑,ParameterDriftError 不会报。 前几步用 A 模板、后几步用 B 模板,全程零报错,而那次运行的数据已经废了,我们还不知道。

你们已经知道这件事

这一条不是新发现。dissect 仓库的 issue #1(你们提的那份迁移方案)第三节第 2 条已经写了:

这一条我认为是 PolyLoop 的缺口而不是 dissect 的,登记在这里等你们的意见——如果确认需要,我在库里补一个正式的位置。

我们确认需要。 这个 issue 就是那句话要等的回复。

绕过去的代价

把 sha 塞进 model_binding。它的每个键值都会进快照,所以功能上work。

但那个字段的语义是「项目自己的标识,库不解释」,塞模板哈希进去是借用——语义不对,而且下一个下游看到我们这么用会跟着学。

一个可能的做法(不强加)

RunRequest 上开一个明确命名的字段,收「影响这次运行、但不是数据本身」的那类指纹。名字和形状你们定。

注意它和 model_binding 的区别model_binding 是坐标(这次运行属于哪一格),这个是指纹(这次运行用的配方是哪一版)。两者都该进快照,但含义不同,混在一个字段里事后分不开。

## 我们是谁 dissect2 —— dissect 的第二版,正在重建,要接 PolyLoop 当执行内核。我们只提需求、不改这个仓库。 ## 问题 提示词模板的哈希在参数快照里没有位置。 `src/polyloop/session/__init__.py` 的 `parameter_snapshot` docstring 写着: > **上下文与注入内容不进快照。** 它们是这次运行的输入数据不是参数,进快照会让快照变成一份数据副本,而它们可能很大。 这个理由是对的,我们不反对。问题在于它把**提示词模板本身**也一起挡在外面了,而模板不是数据,是参数。 ## 为什么我们非要这一维不可 我们是一个论文项目,研究的正是「改这份文本会让 agent 表现变好多少」。**提示词模板是这套实验里被改的东西之一。** 上一版把模板文件的 sha 算进 run 快照,理由是:不记的话,「这次运行用的是哪一版提示词」就只剩 harness 的 git SHA 一个粒度——而同一个 commit 下我们可能在试不同的模板。 后果很具体:**换一份提示词模板续跑,`ParameterDriftError` 不会报。** 前几步用 A 模板、后几步用 B 模板,全程零报错,而那次运行的数据已经废了,我们还不知道。 ## 你们已经知道这件事 这一条不是新发现。dissect 仓库的 issue #1(你们提的那份迁移方案)第三节第 2 条已经写了: > 这一条我认为是 PolyLoop 的缺口而不是 dissect 的,登记在这里等你们的意见——如果确认需要,我在库里补一个正式的位置。 **我们确认需要。** 这个 issue 就是那句话要等的回复。 ## 绕过去的代价 把 sha 塞进 `model_binding`。它的每个键值都会进快照,所以功能上work。 但那个字段的语义是「项目自己的标识,库不解释」,塞模板哈希进去是借用——语义不对,而且下一个下游看到我们这么用会跟着学。 ## 一个可能的做法(不强加) 在 `RunRequest` 上开一个明确命名的字段,收「影响这次运行、但不是数据本身」的那类指纹。名字和形状你们定。 **注意它和 `model_binding` 的区别**:`model_binding` 是坐标(这次运行属于哪一格),这个是指纹(这次运行用的配方是哪一版)。两者都该进快照,但含义不同,混在一个字段里事后分不开。
Author
Owner

1.0.2 已发布,字段加上了。

RunRequest.fingerprints: Mapping[str, str],默认空映射,全部键值以 request.fingerprint.<name> 进参数快照(单数,和已有的 request.binding.<key> 对齐)。你们那个模板 sha 直接放进去就行。

model_binding 的分界写进 docstring 了,就是你们说的那个:绑定是坐标(这次运行属于哪一格:哪个账本、第几轮、哪道题、第几次尝试),指纹是配方版本(这次用的材料是哪一版)。两者都进快照、都由你们自由定键名,但含义不同。有了正确的位置,往 model_binding 里塞 sha 这件事就不必发生了。

一条建议,不是校验:值里带上算法前缀,写成 sha256:<hex> 这种形状。换算法那天,不带前缀的新旧记录会以「两个不同的十六进制串」的形式比对,报出的漂移看不出是换了算法;带前缀则一眼看出。库不解释这个值,所以这只是建议。

默认空映射时快照里一个键都不写(不是写一个空串键),所以你们今天已经在跑的配置算出来的快照逐字节不变。

你们提的那个失败场景有测试正面钉着:tests/unit/test_session.py::test_resume_refuses_when_only_a_fingerprint_changed——只改一条指纹用同一个运行标识续跑,抛 ParameterDriftError

顺带补了一道校验

fingerprintsmodel_binding 的键值必须都是字符串,在构造 RunRequest 的那一刻就拒绝;五个接缝 parameters() 上报的键值在聚合成快照时同样校验。在此之前塞一个整数进去不会当场报错,要等到续跑读日志那一刻才炸——而那时这次运行已经完整跑过一遍、钱已经花了。

对抗审查还发现 frozen=True 不禁止改字段里那个 dict,构造完往里塞一个整数照样能绕过校验,所以这三个映射字段(还有 injections)现在在构造期被冻成只读。类型注解仍然是 Mapping[str, str],那本来就是只读接口,你们按只读用它不受影响;如果你们哪里在构造后改它们,会拿到 TypeError

理由与取舍在 research-wiki/design/0015-parameter-snapshot-contract.md 决策一与决策三。

**1.0.2 已发布**,字段加上了。 `RunRequest.fingerprints: Mapping[str, str]`,默认空映射,全部键值以 **`request.fingerprint.<name>`** 进参数快照(单数,和已有的 `request.binding.<key>` 对齐)。你们那个模板 sha 直接放进去就行。 **和 `model_binding` 的分界写进 docstring 了,就是你们说的那个**:绑定是**坐标**(这次运行属于哪一格:哪个账本、第几轮、哪道题、第几次尝试),指纹是**配方版本**(这次用的材料是哪一版)。两者都进快照、都由你们自由定键名,但含义不同。有了正确的位置,往 `model_binding` 里塞 sha 这件事就不必发生了。 **一条建议,不是校验**:值里带上算法前缀,写成 `sha256:<hex>` 这种形状。换算法那天,不带前缀的新旧记录会以「两个不同的十六进制串」的形式比对,报出的漂移看不出是换了算法;带前缀则一眼看出。库不解释这个值,所以这只是建议。 **默认空映射时快照里一个键都不写**(不是写一个空串键),所以你们今天已经在跑的配置算出来的快照逐字节不变。 你们提的那个失败场景有测试正面钉着:`tests/unit/test_session.py::test_resume_refuses_when_only_a_fingerprint_changed`——只改一条指纹用同一个运行标识续跑,抛 `ParameterDriftError`。 ## 顺带补了一道校验 `fingerprints` 与 `model_binding` 的键值必须都是字符串,**在构造 `RunRequest` 的那一刻就拒绝**;五个接缝 `parameters()` 上报的键值在聚合成快照时同样校验。在此之前塞一个整数进去不会当场报错,要等到续跑读日志那一刻才炸——而那时这次运行已经完整跑过一遍、钱已经花了。 对抗审查还发现 `frozen=True` 不禁止改字段里那个 dict,构造完往里塞一个整数照样能绕过校验,所以这三个映射字段(还有 `injections`)现在在构造期被冻成只读。**类型注解仍然是 `Mapping[str, str]`**,那本来就是只读接口,你们按只读用它不受影响;如果你们哪里在构造后改它们,会拿到 `TypeError`。 理由与取舍在 `research-wiki/design/0015-parameter-snapshot-contract.md` 决策一与决策三。
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: iomgaa/PolyLoop#3