可复现性

docs.stripe.com · 审计于 2026-07-27 · AgentFit v3.4.0 · 评分标准 v4 · Claude Opus 5

无法重复的分数不是测量。所以这里是我们该交出的检验:同一天里我们对同一个站点审计了六次——三次让语言模型套用文档评分标准,三次运行 AgentFit——并把记录下来的内容都公开,包括对我们不利的部分。

问一个模型 · 3 次运行

78 · 80 · 65 15 分的离散度

三个互相独立的智能体,同一份公开提示词,同一个模型,同一天。它们彼此不知情,也不知道为什么被问到这件事。

运行 AgentFit · 3 次运行

57 · 57 · 57 0 分的离散度 eabbb2f6abcdea473b600dc4ee8e25282fd002344f1e8425519caa32ff858b01 一个 sha256,三个文件

连续三次真实审计,三个 JSON 文件,一个校验和。这不是缓存:每一次运行都重新访问了站点。

请纵向读这两列,不要横向对比。左边那套评分标准有 26 条,AgentFit 有 28 条,而且权重并不相同:机器可读规范在左边值 25 分,在这里值 17 分。57 不是「正确答案」,78 也不是「错的」。本页的主张要窄得多,而且这也是数据唯一支持的一条:这两套流程里,有一套每次都给出同一个数字,另一套不是。


三次运行在哪里分歧

三次模型运行都是认真做事的:它们抓取了实时 URL,逐条走完评分项,并报告了所见。按我们自己在记录中的统计——这些记录我们并未公开——每次运行调用工具 36 到 47 次,且没有一次编造事实。这两点请当作我们对运行过程的转述,而不是下面的文件能让您核对的内容。它们最终仍相差 15 分,其中十一分落在同一个类别里。

三次模型运行的分类得分。同一站点、同一提示词、同一天。
类别 满分 A B C 离散度
A — 可发现性181313121
B — 页面产物221213121
C — 机器可读规范2520211011
D — 内容201819181
E — 渲染与卫生151514132
总计10078806515

这里混着两类分歧。小的那类——A5、B3、B5、B6、D1、D3、D6,一两分的出入,方向不一——正是三位认真读同一页面的读者会有的差别:一次在 DOM 里找到了 SDK 标签页,另外两次认定它们只存在于 JavaScript 负载中。这是否属于寻常的测量噪声,三次运行说明不了,这一点我们只是在猜。公开的摘要里只看得到 D1 上的分歧,其余来自我们自己对三份记录的比对。大的那类分歧性质不同,这个页面正是为它而写。

C 类中其余各条在三次运行里都恰好得了 10 分。整整十一分的差距,全部来自两条标准。

C1a:同样的事实,三个不同的分数

评分项 C1a——出自模型那套 26 项标准;AgentFit 把「能否发现」和「是否有效」合并为一个 C1——问的是这个 API 有没有一份代理能够到达的机器可读规范。三次运行就 docs.stripe.com 确认了完全相同的两个事实:

没有人判断错误,也没有人产生幻觉。三次的评分是 8 分里的 0 分、3 分和 4 分。

三次运行分歧最大的三个评分项,以及各自给出的分数。
标准ABC
C1a · spec discoverable3/84/80/8
C1b · spec valid7/77/70/7
E5 · terms of use3/32/31/3

分歧不在站点,而在一个评分标准从未提出的问题上:如果规范放在别人的域名下、还要多跳一次才能拿到,它算不算已发布?这是一个没有显然答案的真实岔路,而每一次运行都是在一项长任务的中途、独自走到这个岔口,手边没有可查的规则。三次运行,三种判法。

从这里开始就是连锁反应。C1b 评的是你找到的那份规范的质量。判定 GitHub 不算数的那次运行无物可验,得了 7 分里的 0 分。抓到规范的两次都给了 7 分中的 7 分——随后报告的路径数却不同,一次 414、一次 136,因为 Stripe 仓库里不止一个规范文件,它们各取了一个(spec3.json 与 spec3.yaml)。两次运行给出同一个分数,理由却相反。

E5——「是否声明了使用条款?」——结果是 3/3、2/3 和 1/3。一次运行在页脚找到了指向 stripe.com/legal/ssa 的链接。一次否掉了那个链接,转而认可 robots.txt 里的 Content-Signal 指令。还有一次在文档主机上找 /terms、/legal 和 /privacy,拿到三个 404,就按所见评分。同一行评分标准,三种都站得住脚的读法。

自检本身也在漂移

该提示词自带一个校准锚点:一张此前测量过的站点表,Stripe 在表中为 56 分,测于 2026 年 5 月 13 日。它的存在正是为了发现漂移。这张表也解释了这里为什么是 docs.stripe.com——在我们运行任何东西之前,Stripe 就已经写在别人的校准锚点里,站点是替我们选好的,而且是在实验之前选定的。

三次运行都用上了它。三次都注意到了自己的偏差——+22、+24、+9。三次随后都重新检查了各条标准,推断五月以来可能发生了什么变化,并得出结论:锚点过时了,自己的数字更可信。三次,各自独立,方向一致,数字却各不相同。

这一段是我们觉得最有启发的地方。这不是敷衍——当流程里仍留有一个自由参数时,认真的工作看上去就是这样。一项自检,如果它的结论在每次运行之间都会变,那它就不是自检。

这个锚点恰好距离 AgentFit 的 57 只差一分。请不要多想:那是一次人工测量,用的是另一套评分标准,来自另一个月份,它并不能证明 57 就是真实分数。


代码为什么每次都给同一个答案

没有什么巧妙之处。每条标准都是一次请求加一条规则,而两者都在审计开始之前就写死了。

AgentFit 报告中的四行——三次运行逐字节一致。
标准 结果 请求 记录
A1 · llms.txt 索引 通过 3/3 GET /llms.txt → 200 Stripe Documentation
C1 · 规范发现 缺失 0/8 固定探测列表,无响应
D2 · 示例真实度 通过 5/5 抽样的端点页面 → 200 placeholder_ratio = 0.00, 0/3 blocks
E6 · 无障碍 部分通过 1/4 首页 → 200 a11y: 3 violations (e.g. button-name)

D2 就是用到机器学习的那一条。审计内部跑着两个小分类器:一个给代码示例的真实程度打分,另一个判断端点页面的完整度。它们是权重冻结、编译进二进制的 ONNX 图。同样的输入永远给出同样的张量和同样的浮点数。确定性并不要求回避模型;它要求回避那些输出无法钉死的模型。

C1 正是三次运行走岔的那个分叉,AgentFit 在这里给 0 分(满分 8)。我们的规则不是「GitHub 不算数」,而是一份固定的查找清单:被审计主机上的十七个惯用路径、一个符合 RFC 9727 的 api-catalog 链接,以及我们抓取的首页上出现的任何规范链接。在 docs.stripe.com 上,这些路径都没有返回规范,那个页面上也没有这样的链接,所以什么也没找到。一条多走一跳、追到厂商仓库里去的规则并不会更不正确。我们这条规则只是在审计开始前就已固定,对语料库中每个站点一视同仁地套用,评分方式公开在评分标准页上。差别全在于此——不是更好的答案,而是固定的答案。 C1 如何评分.

用一次实时运行来核对

仓库是私有的,我们也不发布任何二进制文件,所以我们不会让你「自己编译再运行」——你做不到。不靠我们能验证的东西要窄一些,我们宁可把它说准。上面那些文件,是 2026 年 7 月 27 日在我们机器上由命令行构建写出来的。公开服务是另一份构建,跑在别处,它会就同一个站点交给你它自己的报告。如果流程真如我们所说,这两份报告在每一项得分上都会一致。下面是怎么做这个比对,以及它的分量。

什么都不用跑(不消耗配额)

公开数据集里为每个主机记录了最近一次有效审计的运行标识。取出 Stripe 的那一个,从 API 把这次运行读回来,把两份文档都缩减到打分字段,然后比对:

$ RUN=$(curl -s https://agentfit.dev/dataset.csv \
        | awk -F, '$1=="docs.stripe.com" && $3=="true" {print $7; exit}')

$ curl -s https://agentfit.dev/static/reproducibility/agentfit-run1.json \
  | jq -S '{total_score, max_score, categories,
            criteria: [.criteria[] | {id, status, score, max}]}' > ours.json

$ curl -s https://agentfit.dev/api/public/audit/$RUN \
  | jq -S '.report | {total_score, max_score, categories,
            criteria: [.criteria[] | {id, status, score, max}]}' > theirs.json

$ diff ours.json theirs.json

2026 年 7 月 27 日,这条 diff 什么也没打印:200 行,零输出。两份不同的构建,两台不同的机器,同样的 28 条判定。

自己跑一次(每个站点每天一次)

把 https://docs.stripe.com 粘进首页的表单。跑完之后,地址栏里是 /r/<运行标识>。把它换到 $RUN 的位置,再跑同样的两条命令。要清楚它加了什么、没加什么:审计仍然从我们的服务器发出,所以属于你的是这次请求和这个时刻,而不是出口。

同一个站点、同一个网络,24 小时内只能审计一次。第二次会拿到 429,没有运行标识——这是故意的,免得有人把这个服务当锤子去砸别人的文档。如果你撞上了配额,上面那条路根本不需要提交任何东西。MCP 服务器与网站共用同一份配额:让智能体在同一天再审一次同一个站点,会撞上同一堵墙。而在这堵墙前面还有第二堵,它跟你没关系:十分钟内对同一个主机的两次审计——不论是谁发起的——会耗尽一份共享额度,下一个调用者拿到的是 429,错误码是 rate_limited 而不是 site_quota。这一堵十分钟后自己就消了。

不用 curl 和 jq

在一个标签页里打开 agentfit-run1.json,在另一个标签页里打开这次运行的报告页 /r/<运行标识>。决定结果的是七个数字:六个类别得分和总分。它们就印在下面,所以光看这一页也能核对。

AgentFit 对 docs.stripe.com 的结果,2026 年 7 月 27 日 —— 三个文件里完全一致
类别 得分 满分
A — 可发现性1114
B — 页面要素1121
C — API 契约417
D — 内容1623
E — 渲染与卫生1521
F — 代理能力04
总计57100

有三处会不一样,而且应该不一样

一致只说明一件事:同一套流程、同一个站点,在另一份构建、另一台机器上给出了同一个判定。它不说明 57 就是对的——本页从未这样主张。而且它取决于站点本身:如果 docs.stripe.com 自 2026 年 7 月 27 日以来变过,数字就会动,那是仪器在工作,不是在坏掉。从不一致里下结论之前,先看数据集那一行的 audited_on 日期。

这些文件是冻结的,我们不会每次发版都重新生成。两个原因:本页的校验和正是对这些字节取的,上面文字里的每一个数字也都是从它们里读出来的——一份会自动刷新的展品,这两样都担不起。报警线在活的那一侧,不在冻结文件里:你上面读到的那一行数据集,第 9 列就是 rubric_version,只要本页还挂着,它就必须是 4。展品比这一列还老,本身并不带它——所以能拿来对照的,只有这句话里印出来的数字。我们是直接声明它,而不是让你自己找到它;这是更弱的保证,正因如此才把它写出来。哪天那一列变成别的数字,就说明评分尺在本页写成之后换过了:按字段的比对作废,你看到的是一份历史文件。与其让页面悄悄重跑到自己跟自己一致,不如让它把这句话说出口。

28 条标准里有两条——D2 和 C3——不是由规则判的,而是由两个小分类器判的。它们编译进二进制文件,并随之一起版本化:没有模型服务,谁的重训练也动不了一个已经发布的分数。


我们没有主张什么

模型在这件事上真正擅长什么

这一切并不使模型的那三次运行变得无用——它们只是另一种工具。三次运行各自的诊断本身都不错:缺少规范为什么会伤害智能体、应该改为发布什么、Stripe 的哪些页面经得起不用浏览器的阅读。这是解释,而模型解释得非常好。

语言模型极其擅长解释该修什么。作为衡量你是否修好了的量具,它很不称职。我们做的是后者。AgentFit 是量具;把它的数字拿给模型,问该怎么办。这才是正确的分工,也是我们自己的用法。

数据

六次运行都由本站提供。三份 AgentFit 报告就是工具写出的文件,逐字节原样——校验和正是对它们取的。三份模型运行文件则出自我们之手:

原始记录并未公开。模型这一栏给出的是我们事后依据这些记录整理的结构化摘要:最终分数、各类别小计,以及上文引用的逐项说明。分数和小计是每次运行自身的输出;说明的措辞出自我们。

我们没有筛掉任何东西——既没有筛运行,也没有筛站点。三次模型审计、三次工具审计,都在提示词校准表早已点名的那一个站点上;我们没有跑过别的站点,也没有丢弃任何结果。如果第四次运行给出 57,我们同样会公开,而这个页面会更短。


审计你的文档 →

免费、无需注册,约 30 秒。28 条标准,每条下面都有 HTTP 证据,还有一个可分享的报告链接——如果什么都没变,明天还是同一个数字。