推出 Clairic:System One 家族的新成员——抽取模型
今天我们发布了 System One 风格模型家族的新成员预览:抽取模型(extraction models)。首款模型 Clairic 已在 Workers AI 上线,标识为 @cf/cloudflare/clairic。我们计划很快以开放权重(open-weights)的形式发布该模型。
Clairic 是一款抽取模型,能从非结构化输入中提取、计算、估算和预测数值。相比传统大语言模型(LLM),它准确率更高、响应更快、成本也更低。
背景
一个月前,TypeSafe 发布 System One 模型,在业内掀起不小的波澜。按照 TypeSafe 博客中的说法以及 Daniel Kahneman 在《思考,快与慢》一书中的定义,System One 模型应该快速而精准;与之相对的是 System Two 模型,具备审慎推理的能力(比如 LLM)。
借此,TypeSafe 推出了 Jev——一款针对特定场景专门打造的模型,考虑到其细分领域,定价也相当亲民。它做到了 LLM 做不到的事情,帮助用户基于概率和类型规范的输出做出决策。
Jev 的问世,让人们开始思考:是否还存在一类并非 LLM 的新模型?又该如何把这些模型融入自己的工作流?
我们受到 System One 模型概念的启发,开始思考 LLM 效率低下的其他任务。如今,大量请求发往前沿 LLM,要求返回结构化输出,而且模式反反复复都是那几种:发票总额是多少?什么时候送达的?晚到了几天?这次维修要花多少钱?接下来 24 小时的交通状况如何?这些问题的答案都无法事先枚举,而决策模型恰恰需要预先列出的选项才能计算概率。
于是,我们找到了今天要介绍的这一类模型:System One 抽取模型。
认识 System One 抽取模型
在此之前,所有 System One 模型都是决策模型:Jev 和 Clef 接收输入状态和一组问题,然后针对输入和你列出的问题给出概率。
Clairic 是这个新类别里的第一个模型:System One 提取模型。它依然快速、带类型、便宜,但回答方式是从输入中直接提取值、基于输入计算,或者对输入之外的值做出预测。
大多数模型任务需要的输出无非三类:一个数字、从固定选项里挑一个、或者开放式文本。Clairic 负责第一类,返回带 80% 区间的数字,同时还能把姓名、日期、列表这类带类型的值从输入里抽出来。Clef 负责第二类:在多个选项里做选择,并给出每个选项的概率。LLM 负责第三类。
我们把 Clairic 和 Clef 称为 System One 模型,因为它们一次通过就给出答案,不做推理、不生成 token。它们只按输入计费,通常不到一秒就返回;而让 LLM 把同样的步骤推理一遍,得花好几秒。
提取模型可以返回以下几类结果:
- 提取值: 从输入中复制出来的文本,比如姓名、订单号或一段描述。每一项都以文本片段(span)的形式返回,附带字符偏移和置信度分数。
- 含计算值: 数字、日期、时间、日期时间、时长和列表,从输入中读取或基于输入算出。它们遵循各自的类型规则(例如金额保留两位小数),并附带置信度分数。
- 估计值: 输入没有明说、但提供了依据的值。每一项都以分布的形式返回,范围限定在你声明的边界内、落在你指定的网格上,同时给出中位数和 80% 区间。
- 预测值: 时间序列的未来取值,每一步给出一个估计,各自带 80% 区间。
由于不生成 token,它不会像 LLM 那样给出类型错乱的答案,也不会产生同类的「幻觉」(当然,它仍然可能出错)。
输出要么是你所要求类型的值,要么在模型无法从输入中找到答案时返回 null。每个输出都会附带置信度分数,帮你判断是否该信任模型,还是需要再核实一下。
提取模型在 System One 和 System Two 模型的版图中处于什么位置,可以看下图:
| System One:提取 | System One:决策 | System Two | |
|---|---|---|---|
| 示例模型 | Clairic | Jev、Clef | GPT、Claude、Gemini、DeepSeek |
| 采样方式 | 一次并行处理 | 一次并行处理 | 一次一个 token |
| 用途 | 预测数值 | 做决策 | 写作与推理 |
| 机器学习定位 | 回归与提取 | 分类 | 生成 |
| 思考模式 | System 1:快,一次完成 | System 1:快,一次完成 | System 2:慢,深思熟虑 |
| 输出 | 带类型的值:字符区间、数字、日期、时间、列表、分布,并附带校准后的概率 | 带类型的决策:选项及校准后的概率 | 自由格式字符串 |
| 输出空间 | 连续,但由你的 schema 限定类型和边界 | 你列出的有限选项集 | 任意内容 |
| 它回答什么 | 金额是多少?何时发生?会是多少? | 属于哪个类别?是否合规?应采取哪个动作? | 为什么会发生?该如何处理?你能修复吗? |
| 输出总是有效响应吗? | 是:每个答案都是其声明类型的值(或 null),且在你的边界内 | 是:答案始终是你给出的选项之一 | 否:字符串必须解析和检查 |
一个例子:提取数值
提取大概是当今交给 LLM 最常见的工作:"把发票号、供应商和到期日以 JSON 返回。"大多数时候它能用,但失败模式很难被发现。输出可能不是合法的 JSON;生成数字时可能看错一位;而且拿到一段文本摘录后,没法追溯它在原文中的位置。大多数人会为此搭建提取流水线,加上多层解析、schema 校验、重试和抽查。除此之外,你还要为每份文档的每个字段支付推理和输出 token 的费用。
Clairic 的工作方式不同;它不生成文本答案。你得到的是:
- 从输入中提取的值,因此答案是有依据的。
- 计算出的值,因此它可以在不预先清洗的情况下解析非结构化数据。
- 字符偏移区间,因此你可以引用数据在输入中出现的位置。
- 置信度标签,因此你可以判断哪些值需要复核。
- 强类型输出,因此数字和日期按各自类型的规则构造(例如,以分为单位的字段保留两位小数)。
- 对空值的处理,缺失字段会以 null 作为答案返回(同时给出 null 的估计概率和一个猜测值)。
- 更便宜、更快的答案,因为每个字段都在同一趟并行处理中作答。所以请求三十个字段的成本和请求三个差不多。
我们用一个例子走一遍,说明 Clairic 从非结构化数据中提取数值并做出估计的方式。看这封客服邮件:
你好,订单 A-88412 于 2026 年 9 月 28 日送达,屏幕有裂纹,一角有凹陷。我付了 $649.00,另加 $52.10 税。现在是 2026 年 10 月 9 日,我希望修好或退款。谢谢,Dana
在 Worker 中,你会向 Clairic 发请求来处理这份数据:
Clairic 返回提取出的值、输入中的区间、为 null 的概率(p_null)以及置信度分数:
有几点值得注意:
amount_paid在邮件里并没有写出来。在这个例子中,Clairic 在同一趟处理中把价格和税加了起来并返回总和。days_since_delivery也是由文本中的两个日期算出的,并非直接存在于输入中。damage以精确区间的形式列出两种损坏,因此你可以在原文中高亮它们。tracking_number不在邮件里,所以返回 null,而不是一个看起来合理的猜测。guess展示了模型否则会选什么。
Clairic 也能处理图片
这是一张真实的收据照片——文字并不完美,图片的角度也不利于辨认。我们把这张图片交给 Clairic,看看它能提取出什么:
如你所见,它能够从图片中提取所有值,并附带置信度分数。它还正确指出收据上没有显示折扣,把值设为 null。
一个例子:估计数值
有些值根本不在输入里,但输入中带有支持它们的证据。例如,值可能不是以纯文本出现,但可以从周围的值推断出来。如果你让 LLM 做估计,通常只会得到一个数字,完全不知道模型有多确定。它会做出保守的猜测,或者产生幻觉,或者靠推理绕开答案。如果你最终得到一个估计值,任何下游处理都无法分辨一个有信心的 $180 和一个没信心的 $180,所以它没法帮你决定在这种情况下适合自动化什么。用 LLM 做推理也慢得多、贵得多。决策模型可以通过在区间中做选择来近似估计(“低于 $100”、“$100–500”……),但区间很粗,每个区间都会增加输入 token,每新增一个类别都会在决策过程中给模型增加更多混淆来源。
Clairic 会在你声明的范围内返回一个分布:一个点值、一个中位数、一个 80% 区间,以及按需返回的每个百分位数。估计值被设计为落在你的边界内,所以之后不需要再做截断或取整。区间的宽度反映数据置信度:窄区间表示高确定性,宽区间表示低确定性,这些信息可以用来触发另一次检查。
再看一个例子,Clairic 查看历史房价和可比销售,来确定一个估计值:
const { answers } = await env.AI.run("@cf/cloudflare/clairic", {
state: `Comparable sales:
sqft,beds,year_built,neighborhood,sale_price
1450,3,1998,Elm Park,412000
2100,4,2006,Elm Park,585000
980,2,1975,Riverside,265000
1600,3,2003,Elm Park,449000
1300,3,1990,Riverside,318000
Subject property:
sqft,beds,year_built,neighborhood
1620,3,2001,Elm Park`,
fields: {
sale_price: { type: "estimate", unit: "USD", min: 50000, max: 5000000, scale: "log", step: 1000 }
});
Clairic 会返回一个估计值:
{
"sale_price": { "type": "estimate", "value": 418000, "median": 415000, "p10": 370000, "p90": 470000, "p_below": 0.0, "p_above": 0.0 }
}
结果始终落在你设定的范围内,区间宽度反映输入信息对预测的支撑程度:价格区间较窄(37万至47万美元),而在售天数区间较宽(24至148天)。字段数量不设限且并行返回,因此一次调用就能给多条数据打分(每个候选、线索或房源各得一个估价),再在代码里排序。
预测数值
对通用模型来说,预测时间序列中的数值相当困难。通常只有两条路:要么为每个指标单独搭一套流程(解析数据、拟合模型、调参、部署),要么把36个月的数字粘贴进大语言模型(LLM),让它预测未来三个月。前者准确,但每来一个新序列就要花大量时间和成本搭建;后者简单,但只给出点预测、没有区间,预测结果还会随提示词措辞漂移,置信度也有限。
Clairic 介于两者之间。它并不声称要取代专门的时间序列模型,但比一般的大语言模型更快、更便宜。预测字段把历史数据以纯文本形式放进 state,针对每个向前步长返回一个数值和一个 80% 区间,且都落在你声明的边界内。它按你现有的格式读取历史,无论是 CSV 导出、粘贴的仪表盘,还是夹杂备注的行,往往无需事先清洗数据。
为验证在真实数据上的表现,我们用一个公开序列:美国运输安全管理局(TSA)每天在机场安检口筛查的人数。连续 21 天,我们每天早上把截至目前真实计数交给 Clairic,请它预测第二天的数字:
const { answers } = await env.AI.run("@cf/cloudflare/clairic", {
state: `Daily number of people screened at TSA checkpoints at US airports.
date,weekday,travelers
2026-07-16,Thu,2850229
...
2026-10-13,Tue,2353356
Forecast date: 2026-10-14 (Wed)`,
fields: {
travelers: { type: "forecast", horizon: 1, interval: "day",
min: 500000, max: 4000000, scale: "log",
instructions: "Number of people screened tomorrow" },
},
});
返回结果:
{
"travelers": { "type": "forecast", "value": [2416117], "median": [2419283], "p10": [2270774], "p90": [2556769] }
}
实际情况是,TSA 当天筛查了 2,419,474 人,正好落在 Clairic 预测的中位数 2,419,283 附近。数据来自 TSA 检查站客流数字,访问时间为 2026 年 10 月 15 日。
在这 21 天里,Clairic 的预测平均偏差为 3.3%;21 个实际值中有 17 个落在它给出的 80% 区间内,这正是 80% 区间应有的表现。它仅凭这些数字就捕捉到了每周的节律:周二、周六人少,周四、周五、周日人多。预测失准的地方也很有意思:落在区间外的 4 天里有 3 天正好是哥伦布日周末,那几天乘飞机出行的人比前几周的趋势所暗示的更多。Clairic 依据时间序列中的模式做预测,但无法考虑序列本身没有体现的事件,比如节假日。
快思考与慢思考
这类模型的设计目标,是能直接嵌入你现有的 agent 工作流。抽取模型负责预测数值,决策模型决定拿这些数值做什么,大语言模型(LLM)则据此采取行动。这是 System One 模型与 System Two 模型的完美结合。它填补了现有的空白:过去你要么得手工为 LLM 抽取数据,要么让 LLM 自己去解析杂乱的数据,而后者成本高、耗时长,还容易产生幻觉。有了 System One 抽取模型,你就能更快、更高效、更精确地处理真实世界的数据。
下面还是用前面那个破损商品理赔的例子,说明这些模型如何协同工作。
推出 Clairic:全新的 System One 类抽取模型
// 1. Clairic turns the email into values
const facts = (await env.AI.run("@cf/cloudflare/clairic", {
state: email,
fields: {
customer_name: { type: "text", instructions: "Customer's first name" },
order_id: { type: "text", instructions: "Order number" },
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" },
repair_cost: { type: "estimate", unit: "USD", min: 10, max: 5000, scale: "log", step: 1,
instructions: "Cost to repair the damage described" },
},
})).answers;
const { customer_name, order_id, amount_paid, days_since_delivery, damage, repair_cost } = facts;
// 2. Clef decides from Clairic's values and the policy, not from the raw email
const options = {
refund: "Full refund of the amount paid",
repair: "Free repair, with a prepaid shipping label",
};
const { choice } = (await env.AI.run("@cf/cloudflare/clef", {
state: `Damage claim for order ${order_id.value}.
Paid: $${amount_paid.value.toFixed(2)}. Delivered ${days_since_delivery.value} days ago.
Damage reported: ${damage.value.join(", ")}.
Estimated repair cost: $${repair_cost.median} (80% range $${repair_cost.p10}-$${repair_cost.p90}).
Policy: refunds within 30 days of delivery. Prefer repair when it costs less than 60% of the price and the damage doesn't stop the product from working.`,
questions: {
resolution: { type: "choice", instructions: "What should we offer?", criteria: options },
},
})).answers.resolution;
// 3. An LLM writes the reply, from the decision and the facts it needs
const { response } = await env.AI.run("@cf/zai-org/glm-5.3", {
messages: [{
role: "user",
content: `Write a short, warm reply to ${customer_name.value}. Use only these facts: order ${order_id.value}; ` +
`damage: ${damage.value.join(", ")}; what happens next: ${options[choice]}. Under 60 words.`,
}],
});
每一步的输入都比上一步更干净。Clef 只根据五行结构化值的摘要来做决策,而不再读那封自由格式的邮件——邮件本身也可能被提示注入攻击。LLM 从头到尾看不到邮件,只拿到决策结果和它需要的预测值,能滥用的数字更少。每一步都有类型、可审计,而且只有一个步骤生成文本。如果换成全 LLM 版本,三步全是生成式调用,回复里每个值都得人工核对。
我们拿这套流水线和全 LLM 版本做了对比,两边都用 GLM-5.3 写回复。全 LLM 版本里,GLM-5.3 还要基于同一封邮件、同一份策略和提示,完成抽取和决策:
| Clairic → Clef → GLM-5.3 | 每一步都用 GLM-5.3 | |
|---|---|---|
| 端到端延迟 | 19.3 秒 | 61.7 秒 |
| 1. 抽取 | Clairic:0.46 秒 | GLM-5.3:16.1 秒 |
| 2. 决策 | Clef:0.22 秒 | GLM-5.3:21.9 秒 |
| 3. 回复 | GLM-5.3:18.6 秒 | GLM-5.3:16.4 秒 |
| 输入 token | 701(每百万单 $184) | 390(每百万单 $546) |
| 输出 token | 1,329(每百万单 $5,848) | 2,544(每百万单 $11,194) |
| 每百万单成本 | $6,032 | $11,740 |
级联版本 19.3 秒跑完,全 LLM 版本要 61.7 秒:省了 69% 的时间,大约快 3.2 倍。Clairic 和 Clef 加起来不到一秒就完成了抽取和决策,同样的两步 GLM-5.3 花了 38 秒。成本方面,级联流水线比全 LLM 流水线便宜 49%。
用 GLM 时,两套流水线每次运行都能把事实和决策做对,但 Clairic 给出的维修估价每次都一样,GLM-5.3 则每次都在变($250、$250、$220,每次区间也不同)。值得注意的是,全 LLM 流水线下 Gemma 4 和 Qwen 都在这项任务上失败了,它们无法从输入中推断出 repair_cost 这类值,说明 LLM 并不擅长数据抽取任务。
预览发布
今天,我们在 Workers AI 上线了 Clairic 的托管接口。接下来还打算以开放权重的方式发布模型。不过我们想先花点时间讲讲 System One 提取模型这个概念,让大家开始思考这类模型适合放进什么样的工作流。目前这个接口还是早期检查点,预计后续会不断完善。以下是我们现阶段的初步印象:
- 阅读能力强,但多步算术还不行。 一两步的计算(求和、差值、单位换算、日期运算)看起来比较可靠。步骤再多、前后依赖的计算,对任何单次推理模型来说都很难,除非给它配个草稿纸。跨越多行做表格汇总也是同样的情况。至少目前,建议让 Clairic 给出预测值,实际计算交给代码。
- 估算要有依据。 Clairic 最擅长从输入里的可比对象、历史数据或描述性文字中做估算。如果让它给出毫无依据的数字,具体程度可能会打折扣。
- 校准是测出来的,不是保证的。 区间经过了校准训练,在大多数留出集上表现符合预期,但遇到不熟悉的数据时可能偏窄。
- 预测能力比较基础。 这个模型不是用来替代或预测基于特定数据训练的时间序列模型的。适合用在不需要高精度的场景,比如一般性的模式匹配,别指望它做长周期精细预测。
- 用好置信度。 这套架构能保证每个答案格式规范,但不保证答案正确。请结合
confidence、p_null和区间来判断:哪些环节可以在合适的流程里自动执行,哪些需要送去人工复核。
之后的每个检查点,我们都会继续打磨模型的算术、估算和预测能力。等工作再成熟一些,我们计划以开放权重的形式发布这个模型,让所有人都能上手体验。