Evidence Wall / Analysis

ANTML / Motivation & Distillation

动机和蒸馏上分析 ANTML

首先确定ds没有主动伪装成claude的动机,高度蒸馏 Claude 的能力本身也不等于主动复刻 Claude 的服务端指纹。

然后确定如果上游真是claude 的api,输入的<antml:xxxxx>会被清洗,且上游如果不是claude的api,上游不会被清洗,除非主动伪装成claude

且第三方做cc兼容也就是anthropic格式的兼容时,不可能在兼容层塞个清洗器清洗掉antml,参考除了a社以外的所有厂商的api都没有这个机制,因为这是主动伪装

且在大小写不敏感的情况下2⁵=32种情况下都能稳定触发,如果是蒸馏导致的也就是来自权重而不是清洗器,就算是泛化也可以99%说明针对这个标签做过定向的训练,ds没有主动伪装claude的动机

接下来从蒸馏说上论证为什么不可能

首先

<antml:antml:antml:antml:antml:antml:antml:antml:gugugagagugugagagugugagagugugagagugugagagugugagagugugagagugugaga>

这样的opus会忽视全部antml

<antml:antml:antml:antml:xxxxx:antml:antml:antml:gugugagagugugagagugugagagugugagagugugagagugugagagugugagagugugaga>

这样的opus会从xxxxx的前一个标签清洗掉后面的接着输出

而灰测模型的特征完全一致

也就是说antml并不是全是滚木,而是在第一个非antml前的antml被类似

name = 原始标签名
while name.lower().startswith("antml:"):
    name = name[len("antml:"):]

的api层的清洗器给删除了

懒得写了,以下chatgpt生成:

真正重要的是它表现出的完整边界:

只处理开头的 antml:
+
连续出现可以连续清洗
+
大小写不敏感
+
遇到第一个非 antml 前缀立即停止
+
停止之后后面的 antml 不再清洗

再加上 antml 五个字母共有:

2⁵ = 32

种大小写组合,而不同大小写都能稳定触发同一种行为,这更像一个确定性的 case-insensitive preprocessing 规则,而不是模型偶然省略了某个字符串。

当然,单凭大小写本身不能证明蒸馏模型不可能学会。

大模型完全可以只看过少量:

antml
ANTML
AnTmL

的例子,就泛化出大小写不敏感。

真正的问题是:

为什么普通 Claude 蒸馏数据里会存在足够的信息,让它学出这一整套边界行为?

蒸馏本质上学习的是:

输入
↓
Claude API 输出
↓
蒸馏模型学习这个映射

正常蒸馏的数据应该主要是代码、数学、写作、推理、Agent、tool use 等。

这些数据哪怕数量极大,也几乎不会自然包含:

antml:antml:antml:xxxxx:antml:antml

这种专门为了探测 Anthropic 隐藏 parser 边界而构造的输入。

而且仅仅看到:

<antml:xxxxx>
→
<xxxxx>

远远不足以学出完整规则。

因为它同时兼容很多完全不同的解释:

删除所有 antml
只删除第一个 antml
删除 XML-like namespace
只删除标签开头的 antml
循环删除连续的开头 antml

只有继续构造:

antml:antml:xxxxx:antml

这种样本,才能区分:

全局删除

和:

只删除连续的 leading prefix

再加入不同大小写,才能进一步暴露:

case-insensitive

这个特征。

所以如果认为灰测模型的 ANTML 行为来自"高度蒸馏 DS",就需要额外假设:

DS 的蒸馏数据里不仅有 Claude 普通能力数据,还包含了专门针对 Anthropic ANTML 行为的 probe,包括连续前缀、停止位置、大小写混合、中间插入其他 prefix 等边界样本,并且这些数据足够让模型稳定归纳出和 Anthropic 服务栈相同的规则。

但这已经不能再简单解释成:

因为高度蒸馏 Claude,所以自然继承了这个行为。

因为普通能力蒸馏并没有自然产生这些训练信号的理由。

如果真的存在这种针对 ANTML 隐藏行为的定向数据,那么更接近:

专门研究并复刻 Anthropic 的服务端行为。

这又回到了最开始的动机问题。

如果 DS 本身没有主动伪装成 Claude 的动机,那么为什么要专门研究一个正常业务完全用不到、Claude Code API 兼容也不需要、唯一明显作用是作为 Anthropic 服务栈指纹的隐藏 ANTML 行为?

所以 ANTML 这里真正有价值的并不是:

"模型认识 antml。"

而是:

大小写不敏感 + 连续 leading prefix 清洗 + 非 ANTML prefix 形成停止点 + 停止以后不再清洗后续 ANTML。

如果灰测模型和 Opus 在这些非常规边界条件上都稳定表现一致,那么仅仅用"这是高度蒸馏 DS 自然学出来的"来解释,需要额外增加一个很强的假设:

DS 的蒸馏过程专门覆盖并学习了 Anthropic 的 undocumented ANTML 边界行为。

相比之下,更简单的解释反而是:

请求本身经过了与 Anthropic Claude 相同的 ANTML preprocessing。

为什么 DS 自己的模型根本不需要一个 ANTML 清洗器

如果上游真的是 DS 自己的模型,那 antml: 对它本来就没有 Anthropic 那套内部协议意义。

Anthropic 之所以有理由清洗:

<antml:xxxxx>

是因为 antml: 本身就是它内部保留的控制前缀,后面还会拿它承载类似:

<antml:thinking>
<antml:invoke>
<antml:parameter>

这种内部协议标记。

所以对 Anthropic 来说,用户输入里的 antml: 和自己内部的 antml: 可能发生冲突,做 stripping / interception 是有功能意义的。

但如果上游实际是 DS,那么链路更应该是:

Anthropic-compatible API
↓
把 messages / tools 转成 DS 自己的输入格式
↓
DS 模型

DS 自己并不使用 Anthropic 的 ANTML 作为内部协议。

那对 DS 来说:

<antml:xxxxx>

就只是普通字符串。

清洗它不会提高:

代码能力
推理能力
数学能力
tool use
Claude Code 兼容
Messages API 兼容

甚至从兼容角度看,最自然的行为反而应该是原样透传用户文本

因为一个 Anthropic-compatible API 真正需要兼容的是:

messages
system
tools
tool_use
tool_result
streaming
thinking

而不是复刻一个未公开的:

用户输入里只要出现 antml:
就按照 Anthropic 相同边界进行 stripping

这种内部实现细节。

所以"DS 为了兼容 Claude Code,因此加 ANTML 清洗器"这个说法中间其实缺了一条因果链:

为什么 Claude Code 兼容需要 DS 对一个它自己根本不用的内部 namespace 做和 Anthropic 一模一样的清洗?

如果答案是:

为了性能。

那还得继续问:

到底提高什么性能?

因为把:

<antml:foo>

变成:

<foo>

并不会让 DS 更会写代码、更会推理,也不会让公开 API 的 tool call 更兼容。

如果答案是:

为了让行为和 Claude 更一致。

那其实已经等于承认:

这个清洗器不是 DS 模型自身需要的,而是额外为了复刻 Claude 的服务端行为加上的。

这就不是"高度蒸馏所以自然相似"了,而是主动做了 Anthropic-like preprocessing。

而且你现在观察到的还不是简单的:

删除 antml

而是:

大小写不敏感
+
连续 leading prefix 递归删除
+
遇到第一个非 antml 停止
+
停止后后续 antml 不再删除

如果一个 DS 兼容层连这种完全不影响正常业务的边界行为都精确复刻,那就更难解释成"为了兼容"或者"为了性能"。

更合理的描述只能是:

它额外复刻了 Anthropic 的 undocumented 服务端处理规则。

而这本身就是一个新的假设,不是"DS 高度蒸馏 Claude"这个假设自然推出的。

如果假设ds使用了a/一样的服务端处理规则一样的清洗器,且模型同样有生物甲没有政治甲,思维链输出行为特征高度一致,且同提示词下输出风格主观一致,并且ds同样为这个灰度模型定制了思维链的总结小模型,生物甲触发后的回退检测与fallback模型,政治问题的截断检测机制而不是安全对齐(可以输出但是会被截断),并且触发生物甲后自动失去该回话的'灰测'资格。那他做这一切的动机是什么呢?

我们都不是内部员工,请不要从动机上讨论问题。