返回博客列表

输出的不是 token 而是分布:Cloudflare 发布 Clairic

2026-10-20T11:40:00+08:00
CloudflareAIWorkers AISystem One推理优化

输出的不是 token 而是分布:Cloudflare 发布 Clairic

当答案是数字时,用生成模型去"写"这个数字,本身就是一种浪费。

10 月 19 日,Cloudflare 在 Workers AI 上放出了一个预览模型,编号 @cf/cloudflare/clairic。它不做对话,不写文案,也不做分类。你给它一段文本加最多四张图,再给它一张「字段名 → 类型」的表,它还你每个字段一个值。

听起来像又一个结构化输出工具,但有三处不一样:它不生成任何 token,它不是返回一个数字而是返回一个分布,它在找不到答案时返回 null 而不是编一个看起来合理的值。

官方给的对比数字是:同一套客服理赔流程,全 LLM 版本 61.7 秒、每百万次 $11,740;换成 Clairic → Clef → GLM 的三段流水线,19.3 秒、$6,032。

我把这篇 16 分钟的博客读了两遍,中间那些代码示例比结论更有意思。

本文提纲

  1. 三类输出,三种模型
  2. 「结构化输出」和「抽取模型」差在哪
  3. 一个请求长什么样
  4. 从抽取到估计:为什么分布比数字有用
  5. 预测的实测成绩单
  6. 三段流水线:19.3 秒是怎么来的
  7. 官方自己承认的四个短板
  8. 这个分类值得关注的地方

三类输出,三种模型

Cloudflare 的起点不是模型架构,是任务分类。他们把所有模型任务归成三种输出:一个数字、一个有限集合里的选项、一段开放文本。

按这个切法,模型也就分成三类:

System One:抽取 System One:判断 System Two
代表模型 Clairic Jev、Clef GPT、Claude、Gemini、DeepSeek
采样方式 一次并行前向 一次并行前向 逐 token 生成
机器学习框架 回归 + 抽取 分类 生成
输出 带类型的值:span、数字、日期、列表、分布 带概率的选项 自由文本
输出空间 连续,但被你的 schema 限定 你列出的有限选项 任何东西
是否总是合法输出 是,值或 null 是,必是选项之一 否,得解析和校验

这个划分背后是 TypeSafe 一个月前提出的 System One 模型概念(取自卡尼曼的快思考/慢思考),他们先做了 Jev,Cloudflare 接着做了 Clef——一个在给定选项里做判断、返回每个选项概率的模型。Clairic 是同一族里的第三个角色:它不判断、不生成,只负责把世界上的杂乱输入变成有类型的值。

三者的分工,Cloudflare 的原话是「抽取模型把原始输入变成值,判断模型把值变成决策,LLM 把决策变成文字」。这句话值得单独拎出来,因为它描述的是一条数据被逐级「提纯」的路径,每一级的输入都比上一级干净。

「结构化输出」和「抽取模型」差在哪

现在让 LLM 返回 JSON 已经不难,难的是出错之后你不知道。原文列了四个失败模式,做过抽取流水线的人都遇到过:

  • 返回的 JSON 可能不合法,得重试
  • 数字是在生成过程中一个个吐出来的,中间某一位读错就错了
  • 一段文本抽出来之后,无法回溯它在原文的哪个位置
  • 每个字段都要付推理和输出 token 的钱

第一到第三条是质量问题,第四条是成本问题。多数团队的做法是叠防线:解析、schema 校验、重试、抽样人工核对。

Clairic 换了个思路——把约束放在输出之前而不是之后。因为不生成 token,它输出的第一个东西已经是「这个字段的值」,格式错这件事在物理上不可能发生。剩下的问题只有「值对不对」,而这个问题它给了三个可用于判断的指标:p_null(答案不在输入里的概率)、confidence(对这个值的置信度)、以及估计类字段的区间宽度。

这三个指标的用处不是让你更信任模型,而是让你能路由:置信度高的自动过,p_null 高的转人工,区间宽的退回补充材料。这一点比「准确率提升了多少」更实用,因为真实业务流程缺的往往不是准确率,是「哪些能自动、哪些必须人看」的判据。

一个请求长什么样

请求体只有两个东西:state(要读的内容)和 fields(字段定义)。

const { answers } = await env.AI.run("@cf/cloudflare/clairic", {
  state: email,
  fields: {
    order_id: { type: "text", instructions: "Order number" },
    delivered_on: { type: "date", instructions: "Delivery date" },
    amount_paid: { type: "number", decimals: 2, unit: "USD",
                   instructions: "Total paid including tax" },
    days_since_delivery: { type: "duration", unit: "days", integer: true,
                   instructions: "Days from delivery to the date the customer wrote" },
    damage: { type: "list", items: "text", instructions: "Each kind of damage described" },
    tracking_number: { type: "text" },
  },
});

支持的类型有 text、number、date、time、datetime、duration、list、estimate、forecast。字段数量没有上限——塞不进一次前向的话,服务端会拆成多个并行 pass,每个 pass 都看完整输入,最后合并答案。

原文的邮件例子是这一段:

Hi, order A-88412 arrived on Sept 28, 2026 with a cracked screen and a dented corner. I paid $649.00 plus $52.10 tax. It's now Oct 9, 2026 and I'd like this fixed or refunded.

返回里有两处细节值得看。

第一处,amount_paid 返回的是 701.1,邮件里根本没有这个数——649 加 52.10,模型在一次前向里顺手算完了。days_since_delivery 返回 11,也是从两个日期推出来的。这两条说明它的定位不止于「抄」,还包括「算」。不过后面官方自己承认,这种算术只在一步两步内可靠。

第二处,也是最精彩的一处,tracking_number 并不在这封邮件里,它的返回是:

"tracking_number": {
  "type": "text",
  "p_null": 1,
  "span": [106, 112],
  "guess": "$52.10",
  "confidence": 0.416016,
  "value": null
}

value 是 null,p_null 是 1(百分百确定原文没有),但 guess 里老老实实写着「如果要硬猜,我会选 $52.10」。这个设计等于把模型的内部挣扎也输出出来了:结果给你的是 null,过程给你留着,方便你判断它到底是不确定还是真没有。

对比一下 LLM 在这里会怎么做——它大概率会吐一个看起来很像运单号的字符串,然后你的下游系统开开心心地把 $52.10 当成运单号存进数据库。

图片输入走同一条路。原文给了张角度歪、字迹不清的收据照片,模型把单号、时间、数量、单价、小计、税费、小费都抽了出来,discount 字段返回 null,p_null 是 0.9994——判断依据是那张小票上确实没有折扣行。

从抽取到估计:为什么分布比数字有用

这是全文我觉得最有价值的一段,因为它解释的不是「模型能干什么」,而是「什么样的输出才适合接进自动化流程」。

有些值不在输入里,但输入提供了证据——修这块屏要多少钱、这套房能卖多少、明天机场会有多少人。让 LLM 估,你拿到的是一个数,外加一堆不确定性无法表达的自信。而这个数传到下游,$180 就是 $180,没人知道这是「很确定的 180」还是「瞎猜的 180」,所以没人敢据此自动决策。

让判断模型(比如 Clef)分桶呢?「100 以下」「100 到 500」——桶太粗,每个桶都要吃输入 token,桶越多模型越容易晕。

Clairic 的做法是直接回归到一个分布上:你给 min、max、step,告诉它用线性还是对数刻度,它返回一个落在区间内的值、一个中位数、一个 80% 区间(p10 到 p90),要的话还能给全部 99 个分位数。

fields: {
  sale_price: { type: "estimate", unit: "USD", min: 50000, max: 5000000,
                scale: "log", step: 1000 }
}
// → { value: 418000, median: 415000, p10: 370000, p90: 470000 }

注意区间的宽度本身携带信息。同一个模型在同一个任务上,房价的区间是 $370,000–$470,000(相对窄),挂牌天数的区间是 24–148 天(很宽)。宽窄不同不是模型不认真,是输入对这两个量的信息量不同。下游拿到这个宽度,就能决定「这个值直接用」还是「这个值再查一次」。

这个思路其实不新——量化不确定性的老办法。新鲜的是把它做成了默认输出而不是可选功能,而且区间宽度在训练时被校准过(calibrated),不是事后拍的。

预测的实测成绩单

原文拿 TSA 每日安检人数做了个 21 天的实验:每天早上喂过去的历史数据,让它预测明天,连续 21 天。

结果:平均误差 3.3%,21 天里有 17 天的实际值落在它给的 80% 区间内。17/21 ≈ 81%,和「80% 区间」这个承诺几乎对上了。

这个数字比准确率更有意义。一个模型说「我有八成把握」,实际八成兑现,这叫校准;说八成把握但只中五成,那区间就是装饰品。

它甚至从纯数字里读出了周节律:周二、周六偏淡,周四、周五、周日偏旺。没人告诉它美国人周末出门。

失手的 4 天里有 3 天在哥伦布日周末——那几天出行量超出前几周的模式。这个失败很典型:它只能从序列里的模式外推,序列里没有的信息(节假日)它看不见。原文自己也说得很清楚,这个模型不该用来替代专门的时间序列模型,适合非关键场景的一般模式匹配。

三段流水线:19.3 秒是怎么来的

最有说服力的部分是那个理赔 demo 的三段对比。同一封邮件、同一套政策、同样由 GLM-5.3 写回复,只换前面两步:

Clairic → Clef → GLM-5.3 全是 GLM-5.3
端到端延迟 19.3 s 61.7 s
① 抽取 Clairic 0.46 s 16.1 s
② 判断 Clef 0.22 s 21.9 s
③ 写回复 18.6 s 16.4 s
输入 token 701($184) 390($546)
输出 token 1,329($5,848) 2,544($11,194)
每百万次成本 $6,032 $11,740
flowchart LR
    IN["Raw Email"] --> C1["Clairic: Extract Typed Values"]
    C1 --> C2["Clef: Decide Resolution"]
    C2 --> C3["LLM: Write Reply"]
    C3 --> OUT["Customer Response"]
    IN --> L1["LLM: Extract"]
    L1 --> L2["LLM: Decide"]
    L2 --> L3["LLM: Write Reply"]
    L3 --> OUT

    classDef red fill:#FF6B6B,color:#000000
    classDef teal fill:#4ECDC4,color:#000000
    classDef blue fill:#45B7D1,color:#000000
    classDef sage fill:#96CEB4,color:#000000
    classDef yellow fill:#FFEAA7,color:#000000
    classDef plum fill:#DDA0DD,color:#000000
    class IN red
    class C1,OUT teal
    class C2 sage
    class C3 yellow
    class L1,L2,L3 plum

    linkStyle default stroke:#764ba2,stroke-width:2px

三条数据要拆开看。

速度省在哪儿。 前两步从 38 秒压到 0.68 秒,这是 3.2 倍提速的全部来源。但第三步写回复还是 18.6 秒,反而比全 LLM 版本慢了 2.2 秒——因为它的输入更具体了。换句话说,只要回答里还需要「写一段人话」,端到端延迟就永远卡在生成那一段,取模型能做的只是把前面的时间抹掉。19.3 秒这个数字本身没什么,能抹掉 38 秒这件事才有意义。

省的不是输入 token,是输出 token。 表格里很反直觉的一点:流水线的输入 token 是 701,比全 LLM 的 390 还多。原因不难猜——Clairic 要把完整原文和字段 schema 一起吃进去,判断那一步还要再带一遍整理好的值。但输出 token 从 2,544 掉到 1,329,成本大头就在这一项($11,194 里有 $5,848 那块)。所以「站内信里说的成本降 49%」不是靠压缩上下文省下来的,是靠「不再用 token 生成结构化数据」省下来的。

一致性。 同样的输入跑三次,GLM-5.3 给出的维修估价是 $250、$250、$220,每次区间还不一样;Clairic 的估计三次完全相同。对一个要进财务流程的数字来说,可复现性比精度更要紧。

还有个细节:全 LLM 版本里,Gemma 4 和 Qwen 都在这个任务上失败了——它们无法从输入里推出 repair_cost 这种「没写出来但有依据」的值。这个对比被 Cloudflare 用来支撑「LLM 不擅长数据抽取」这个论点,样本量是不是够不好说,但方向确实符合经验。

官方自己承认的四个短板

这篇博客罕见地把局限写在正文里,而不是藏在附录。逐条看:

读得准,多步算术不行。 一步两步的计算(求和、差值、单位换算、日期算术)可靠,更长的依赖链条对任何单次前向模型都难——没有草稿纸。跨多行表格做聚合也一样。官方的建议很直接:让 Clairic 预测值,让代码做数学。

估计需要证据。 有可比案例、有历史、有描述性文字时估得好;问一个输入里毫无依据的值,具体程度会明显下降。

校准是测出来的,不是保证的。 区间在训练时按校准目标优化,在多数留出集上成立,但遇到不熟悉的数据会偏窄。这句话很诚实:区间偏窄意味着你以为的 80% 其实可能是 60%。

预测是基础能力。 官方明说不打算替代专门的时间序列模型,适合非关键场景的一般模式匹配,不适合长周期精细预测。

另外两条没写进局限但也算约束:模型目前只在 Workers AI 上托管,开放权重「soon」但还没放;预览阶段的 checkpoint 会更新,行为可能变。

这个分类值得关注的地方

这件事的意义可能不在 Clairic 这个具体模型,而在它把「模型」这个词的边界又推开了一格。

过去两年大家的默认假设是「一个足够强的 LLM 加上好的 prompt 和 schema 校验,什么都能干」。这条路线在生成类任务上确实成立,但在「从文档里抠出一个数字」这类任务上一直别扭:用几百亿参数的生成模型,去完成一件本质上是回归的事,然后靠解析和重试掩盖它的不适合。

Clairic 的赌注是:这类任务足够多、足够同质,值得单独训练一类模型来做,而且做出来在准确率、延迟、成本三个维度上都能赢。数字上它暂时赢了——0.46 秒 vs 16.1 秒不是调参能追上的差距,这是架构差异。

对做工程的人来说,更值得借走的是三个想法:

让输出空间被 schema 限死。 格式正确不靠校验,靠不可能出错。

把不确定性做成一等公民。 p_null、confidence、区间宽度不是调试信息,是路由依据。

分工时按输出类型切,而不是按能力切。 「抽取归抽取、判断归判断、生成归生成」比「全交给最强的那个模型」更容易做成本核算,也更容易做故障隔离——判断那一步看到的是五行结构化值,不是一整封可能是提示注入的邮件,攻击面小了一个数量级。

该怀疑的地方也说清楚。这篇博客的对比全部在 Cloudflare 自己的托管服务上跑,延迟和成本数字跟基础设施强相关;模型没开源权重,第三方无法复现;三个例子(邮件抽取、房价估计、TSA 预测)都挑得比较讨巧,多步算术这类弱项只给了定性描述没有数据。以及最现实的一点——它现在是个预览版 checkpoint,官方明说会变。

要不要现在用?如果手里有一条每天跑几十万次、字段固定的抽取流水线,值得拿一批真实样本去比一比,重点看 p_null 校准得准不准。如果只是偶尔抽几个字段,LLM 加校验的链路成本更低,没必要为它改架构。

参考文档与链接

你手上有多少 token 是花在「把文档里的数字读出来」上的?评论区聊聊你的抽取流水线,觉得有收获点个赞。


作者: itech001
来源: 公众号:AI人工智能时代(the-ai-era)
网站: https://www.theaiera.top/ 关注每日最新AI新闻和技术博客,主页有更多的文章的AI 技术参考:https://www.theaiera.top

本文首发于 AI人工智能时代,转载请注明出处。

分享给朋友