← 返回列表
未验证
固定请求配置卡片,漂移时结构化报告差异字段
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/8/31 · 已提供中文文档
DeepSeek Harness 插件:指纹提供方、模型 ID、采样、工具 schema 和系统提示词前缀;固定卡片并在漂移时以结构化方式失败。
综合分
28.2
GitHub 分
28.2
用户评分
—
★ Stars
0
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add jwilson411/dsh-modelprint该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/16(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-tools@deepseek-ai/cordis用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
dsh-modelprint
一个 DeepSeek Harness 函数插件,它将每个请求指纹化为一张小型卡片——提供方、模型 id、所请求的采样参数、模型实际被提供的工具 schema 的哈希,以及模型实际被赋予的系统提示前缀的哈希——并通过一个面向模型的工具 modelprint_check,将这张实时卡片与磁盘上固定的卡片进行对比。
其范围只涉及一个问题:这是否和上次是同一套配置? 当某次运行已知良好时,固定该卡片;此后该工具会以结构化匹配作答,或列出每一个发生漂移的字段。它不访问网络、不加载模型,也不需要密钥——唯一的 I/O 是读取固定文件。
它不是什么
- 不是水印。 提示中不嵌入任何内容,输出中也不恢复任何内容。卡片由 harness 组装的请求构建而成,且只会与你写入的文件进行比较。
- 不是权重替换检测器。 若提供方在稳定别名背后更换权重,会生成字节完全相同的卡片。这能捕获请求所显示的内容;它无法看穿别名背后。
- 不是模型认证产品。 没有证明、没有签名、没有质询——匹配的卡片只能证明你这一侧的调用没有变化,而非证明是什么做出了应答。
这些都不是指控。漂移的常见原因是你自己的仓库:注册了一个工具、编辑了系统提示、有人在补丁层设置了 temperature。这正是本插件使其可见的那类变更。
一旦你有意更改工具或系统提示,它就会误报——这正是重点。 从进程内部看,有意的更改和未被察觉的更改看起来完全相同,因此插件会同时报告两者,由你判断。之后重新固定,噪声就会停止。
安装
dsh plugin --profile web add github:jwilson411/dsh-modelprint
dsh plugin 会在 $DSH_HOME/profiles/web 内转发给 pnpm,然后协调 profile:由于此包的清单声明了 dsh.bundle.patch,它会被追加到 profile 清单有序的 dsh.profile.bundles 列表中,其 cordis.patch.yml 则成为一个层。移除方式相同,只需将 add 换成 remove。
固定的 DSH 候选发布版
此包是针对固定的候选发布版 0.1.1-rc.2 编写和测试的——@deepseek-ai/dsh-tools@0.1.1-rc.2 被精确固定在 devDependencies 中,以便测试针对一个已知 API 运行,而 peer 范围为 ^0.1.1-rc.2,与 harness 自身工具包的声明方式一致。
请注意,@deepseek-ai/dsh-tools 的 npm latest 标签仍指向较旧的 0.0.1-rc.1;0.1.1-rc.2 系列发布在 next 下。请显式固定,而不要依赖该标签。
它注册的内容
| | |
|---|---|
| Cordis 插件 id | modelprint(cordis.patch.yml 中的行 id) |
| 注入 | tools——硬依赖;插件会等待而非降级 |
| 工具 | modelprint_check |
| 参数 | pin(字符串,可选)、request_json(字符串,可选) |
pin 默认为已配置的 pin 路径。request_json 会为那一次调用而非实时卡片生成已保存请求的指纹,并且刻意不覆盖它——一次性检查绝不能覆盖描述测试框架实际发送内容的卡片。
每条路径都返回相同的结构,包括每一次失败:{ match, ok, pin, live, pinned, mismatches, reason, detail, plugin }。缺失的 pin 文件是 PIN_MISSING,而不是抛出的 ENOENT;无法解析的 JSON 是 PIN_INVALID;在记录任何内容之前进行检查是 NO_LIVE_CARD。匹配时 reason 为 OK,否则为按比较顺序出现的第一个不同字段——model、provider、tools、system prompt,然后是 sampling——因此诊断会先给出别名,而不是温度。
卡片
| 字段 | 来自请求 | 备注 |
|---|---|---|
| provider | provider | 当请求未指定任何 provider 时为 null |
| model | model / modelId / model_id | 实际发送的 id,而非营销名称 |
| temperature | temperature | 当未要求任何温度时为 null |
| top_p | top_p / topP | 仅在存在时记录;绝不使用默认值 |
| tools_hash | tools | 规范工具列表的 SHA-256 |
| system_prompt_prefix_hash | 见下文 | 规范化前缀的 SHA-256 |
即使 DSH 当前的 GenerateOptions 没有这样的旋钮,top_p 也会被记录:它没有成本,并且能让未来的旋钮——或另一个主机的请求——可见,而不是被静默忽略。缺失的 pin 记为 null,而 null 与 null 匹配,因此未指定任何温度的 pin 会匹配未要求任何温度的请求。pin 文件中的额外键(日期、注释、备注)会被丢弃,而不是被比较。
tools_hash 按名称排序
工具列表在哈希之前被规范化为 [{ name, description, parameters }, …] 并按 name 排序。注册顺序不是关于模型表面的事实,因此它被排序消除,而不是被允许产生误报——两个以不同顺序注册相同工具的配置文件会哈希相同。函数会被丢弃:模型永远看不到 execute 主体,只看到 schema。数组(普通数组,或 OpenAI 风格的 { type: 'function', function: {…} })和 { [name]: descriptor } 映射都被接受。完全没有工具时会对空列表 [] 进行哈希。
系统前缀规范化
前缀按优先级顺序为:
1. 请求上的 system / systemPrompt / system_prompt,按文本读取;或
2. messages(或 input)中开头连续一段 role: "system" 消息,用 \n 连接,并在遇到第一个其他角色的消息时停止——在对话中途注入的系统消息不是前缀,不会被哈希。
内容从普通字符串、块数组({ type: 'text', text } 或裸字符串)或带有 text 字段的对象中读取;其他任何内容——图像、工具结果——都不贡献任何内容。然后文本在
哈希:CRLF 和 CR 折叠为 LF,并且前导和尾随空白会被
修剪。 其他内容都不会被改动,因此提示词内部更改一个词仍然会
改变哈希,而跨平台迁移的文件则不会。
没有系统文本的请求其前缀为 '',其哈希是空字符串的 SHA-256
—— e3b0c442… —— 而不是某个哨兵值。空工具列表同理:缺失和
空是同一个可观察事实,两者都会哈希为一个真实的摘要。
固定
固定(pin)是一个 JSON 文件,保存你希望将运行约束到的卡片:
{
"provider": "deepseek",
"model": "deepseek-chat",
"temperature": 0.2,
"top_p": null,
"tools_hash": "841e5f22…",
"system_prompt_prefix_hash": "d2c86f05…"
}
完整的示例见 examples/modelprint.pin.json。
编写第一个固定文件最简单的方式,是对一个不存在的路径调用一次
modelprint_check,然后从 PIN_MISSING 结果中复制出 live
卡片。
文件的读取位置,按优先级顺序:
| 来源 | |
|---|---|
| config.pinPath | 组合补丁中插件行的 config |
| DSH_MODELPRINT_PIN | 环境变量回退 |
| modelprint.pin.json | 默认值,相对于工作目录 |
无论哪种方式,路径都会被解析为绝对路径,并且补丁行优先于
环境变量:补丁行是部署所声明的意图,因此不应被环境变量
静默覆盖。
从配置文件自身的 cordis.patch.yml 中设置它——注意,以 id 为目标的
补丁会替换该行的整个 config,因此要重新声明你打算保留的每个字段:
- id: modelprint
config:
pinPath: ./modelprint.pin.json
该 bundle 自身的行故意不携带 config:一个不固定任何内容的配置文件
仍然会记录指纹,并且仍然会从工具获得结构化的
PIN_MISSING。
实时卡片如何被记录
该插件在 agent/request 上记录——即 agent 组装后的请求——并且,
对于只发出较低层级事件的主机,在 llm/stream 上记录,后者携带
等价的 GenerateOptions。两者都是可选的,将同一张卡片记录两次
是无害的。
每个监听器都是直通式的:它调用瀑布流的其余部分,记录输入和输出中
仍然看起来像请求的那一个——next 返回的值优先,因为卡片应当描述
真正将要发送的内容——并原样返回该链的值。一个不携带卡片所读取的
任何字段的值会被忽略,而不是被指纹化为谎言。
既不发出这两个事件的主机有两条途径,并且完全不需要事件:
import { recordRequest } from 'dsh-modelprint'
recordRequest(request) // returns the card it stored
或者将请求作为 request_json 传给工具以进行单次检查。
布局
package.json manifest + dsh.bundle.patch — what makes this a bundle
cordis.patch.yml the bundle's patch layer: one insert, one plugin row
src/fingerprint.js 纯逻辑部分:卡片、哈希、pin 文件、diff
src/index.js 插件:name、inject、apply(ctx, config)、工具
examples/ 一份可供复制的 pin 文件
test/ 基于已提交 fixtures 的离线测试
package-lock.json npm ci 在 CI 中安装的锁定依赖树
测试
sh
npm install
npm test
从构造上就是离线的。fingerprint 这一半除了 node: 和本包之外不导入任何东西,并且它的文件读取都经过注入的 readFile 接缝,因此缺失 pin 和无效 pin 的路径无需接触磁盘即可被覆盖。
apply 接收一个桩上下文,该上下文会记录注册项和事件监听器,而该工具通过与注册表调用的同一个 execute 来驱动,结果会对照锁定为 0.1.1-rc.2 的真实 @deepseek-ai/dsh-tools 进行验证。不会启动任何 profile,不会打开任何套接字,不会读取任何密钥。
CI(.github/workflows/ci.yml)会在 Node 22 和 24 上,基于已提交的 lockfile 运行 npm ci 和 npm test,且仅针对公共 registry。它不需要任何凭据,测试套件也不会访问网络。
不在范围内
- 检测权重替换。 上文已说明:相同请求,相同卡片。
- 水印或输出取证。 不嵌入任何内容,也不读取任何响应文本。
- 对提供商进行身份验证。 没有签名,没有证明,没有挑战。
- 存储历史记录。 内存中只有一张实时卡片,磁盘上只有一张固定卡片。
没有账本,没有 sidecar,也没有需要迁移的状态。
- 替你做决定。 该工具会报告不匹配;至于这是漂移还是你刚刚所做的更改,它不会尝试作出判断。
许可证
MIT — 见 LICENSE。同作者(jwilson411)的其他插件
扫码进群