OpenRouter 上线 Extractions API(alpha),按字段从文本、图片和 PDF 抽取结构化数据
Introducing the Extractions API
- 1OpenRouter 上线 Extractions API(alpha),按描述的字段从文本、图片和 PDF 中提取类型化结果
- 2上线提供 Cloudflare Clairic、Inception Mercury Decide、ScaleDown Extract 三个模型,输出免费,输入价 $0.02–$0.10/M
- 3支持 9 种字段类型,返回值带 confidence、p_null、span 证据,估计和预测类字段返回分位数分布
- 4官方发票示例单次请求 $0.00011;收据商户名拼错时 spell_confidence 仅 0.73,官方称这正是应转人工的信号
OpenRouter 把文档字段抽取做成声明式 API,置信度、空值概率和证据位置内建在返回值里,抽取类工作有了标准化入口。
- 影响:发票、收据、合同等文档处理可按声明字段接入,示例单次成本在 $0.0001 量级;置信度和 p_null 让低置信转人工有了可设的阈值;接口处于 alpha,结构可能变化。
- 参考:可考虑挑一个票据或合同场景在 Playground 试跑,记录各字段置信度和单次成本;值得先算出自有文档量和现行人工录入成本,再决定是否纳入流程。
- 依据:OpenRouter 官方博客口径,价格为 2026 年 11 月 6 日目录价,示例结果来自官方演示,暂无独立评测。
Extractions API 现已以 alpha 版形式在 OpenRouter 上线。只需描述你需要的字段,即可从文本、图像和 PDF 中提取具体细节,比如邮件中的姓名或收据上的总金额。
我们此次推出了来自 Cloudflare、Inception 和 ScaleDown 的三个提取模型。你可以阅读文档,或在Playground中试用,开始上手。
提取(extraction)是一项请求,它指明你想从文档中获取哪些字段,并为每个字段返回一个带类型的值。state携带文本(或 assets 中图像或 PDF 的键名),fields则将每个名称映射到一个规格:一个 type,以及可选的 instructions,用于说明该字段的含义。
共有九种字段类型,每种都会以无需解析即可存储的 JSON 类型返回。这份发票请求了其中六种,发送形式为 state;表格中的示例是 Clairic 返回的结果,高亮显示的词语就是这些值的来源:
state · invoice,以文本形式
Larkspur Studio 开具的发票 INV-4417,开票日期为 2026-10-14,付款条件为 net 45。账单寄送对象:Harbor & Pine LLC。联系人:Dana Ruiz(dana@harborpine.example)、Priya Shah。明细项目:品牌审计 2,400.00;图标套装 1,150.00;加急费 300.00。应付总额 $3,850.00。逾期付款每月累计 1.5% 利息。
请求的字段为 invoice_number: text、total: number、due_date: date、contacts: list、po_number: text 和 days_to_pay: estimate。
| 类型 | 返回内容 | 示例 |
|---|---|---|
text | 从文档中读取的字符串 | "INV-4417" |
number | 一个数字,附带你可指定的 decimals 和 unit | 3850 |
date | ISO 日期,可读取或计算得出 | "2026-11-28" |
time | 一天中的 ISO 时刻 | 该发票未请求此类型 |
datetime | 一个 ISO 日期和时间 | 未对此发票询问此项 |
list | 一个由 text、number 或 date 项组成的数组(items 指定是哪一种) | ["Dana Ruiz", "Priya Shah"] |
duration | 一个数字,单位是你选择的 unit,从秒到年 | 带 unit: "days" 的 45 |
estimate | 文档所暗示的某个数量的分布,介于你设定的 min 与 max 之间 | median 45, p10 42, p90 47 |
forecast | 同上,用于未来 horizon 个步长,interval 由你设定;value、mean、median、p10 和 p90 是每个步长对应一个条目的数组 | 未对此发票询问此项 |
每个答案都携带其 value;此外还携带什么,取决于字段类型和模型。在 Clairic 上,从文本中读取的值附带一个 span,即以 Unicode 码点计数的 [start, end),这样你就可以切分文档并显示它来自哪里(一个 list 携带 spans,每项一个)。单个值携带 p_null,即文档对该字段不含任何内容的概率;当它超过 0.5 时,值变为 null(可通过为每个字段设置 null_threshold 来移动这条线),而即便如此,guess 仍是最可能的值。它们还携带 confidence,即模型对该值的置信度;从图像读取的字符串还会附加 spell_confidence 以表明其拼写。一个 estimate 或 forecast 不携带置信度;mean、median、p10 和 p90 描述其分布,p10 到 p90 的宽度即不确定性。Extract 对每个值返回一个 confidence 且不返回 p_null;对文本它也返回 span,对 PDF 则不返回(见第 3 节)。
这些字段构成了信任模型。设定一个置信度下限,低于它的都交给人工处理,其余的则存储起来。一个 null 是一个答案,而不是低分:模型判定该字段不存在(其 p_null 越过了阈值),guess 则说明它本来能达到什么。一个没有 confidence 的值,比如估算值,则改由其分布来评判。
输入的是文档和一份具名、有类型的字段列表。输出的是每个字段一个值、值从文本中读出时的一个 span、单个值上的 confidence 与 p_null,以及估算值的分布。
该请求在 Clairic 上运行,费用为 $0.00011:
curl https://openrouter.ai/api/alpha/extractions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "cloudflare/clairic",
"state": "Invoice INV-4417 from Larkspur Studio, issued 2026-10-14, payment terms net 45. Bill to: Harbor & Pine LLC. Contacts: Dana Ruiz (dana@harborpine.example), Priya Shah. Line items: brand audit 2,400.00; icon set 1,150.00; rush fee 300.00. Total due $3,850.00. Late payments accrue 1.5% per month.",
"fields": {
"invoice_number": { "type": "text" },
"total": { "type": "number", "decimals": 2, "unit": "USD" },
"due_date": { "type": "date", "instructions": "Issue date plus the net payment days" },
"contacts": { "type": "list", "items": "text", "instructions": "People named as contacts" },
"po_number": { "type": "text", "instructions": "Purchase order number, if any" },
"days_to_pay": { "type": "estimate", "min": 0, "max": 120, "step": 1, "instructions": "How many days after issue this invoice will actually be paid" }
},
"reference_date": "2026-11-06"
}'Clairic 读取了 1,138 个输入 token 并作出回答(响应,减去其 model 行):
{
"answers": {
"invoice_number": { "type": "text", "value": "INV-4417", "span": [8, 16], "p_null": 4.9e-6, "confidence": 0.9999 },
"total": { "type": "number", "value": 3850, "p_null": 1.6e-5, "confidence": 0.9999 },
"due_date": { "type": "date", "value": "2026-11-28", "p_null": 4.4e-5, "confidence": 0.9994 },
"contacts": { "type": "list", "value": ["Dana Ruiz", "Priya Shah"], "spans": [[118, 127], [155, 165]] },
"po_number": { "type": "text", "value": null, "guess": "INV-4417", "p_null": 0.9999 },
"days_to_pay": { "type": "estimate", "value": 45, "mean": 44.79, "median": 45, "p10": 42, "p90": 47 }
},
"truncated": false,
"usage": { "input_tokens": 1138, "output_tokens": 0, "cost": 0.0001138, "state_tokens": 118, "schema_tokens": 666, "passes": 4 },
"id": "gen-dec-1794000212-JVtrkaQ2JbqaR59u2bjZ",
"provider": "Cloudflare"
}due_date 在文本中没有日期,因此模型根据签发日期和条款计算得出;po_number 返回为 null,其中 guess 显示了它本可以索求的金额;days_to_pay 是一个 estimate,因此它返回的是一个分布而非单点,80% 的概率质量落在 42 到 47 天之间。用每个 span 对状态进行切片,在数值旁展示证据。在 Python 中,r 是上述调用的 requests 响应:
state = "Invoice INV-4417 from Larkspur Studio, issued 2026-10-14, payment terms net 45. Bill to: Harbor & Pine LLC. Contacts: Dana Ruiz (dana@harborpine.example), Priya Shah. Line items: brand audit 2,400.00; icon set 1,150.00; rush fee 300.00. Total due $3,850.00. Late payments accrue 1.5% per month."
answers = r.json()["answers"]
for name, answer in answers.items():
spans = answer.get("spans") or ([answer["span"]] if answer.get("span") else [])
evidence = [state[start:end] for start, end in spans]
print(f"{name}: {answer['value']!r} <- {evidence!r}")输入的是图像,采用 assets 格式,通过其来自 state 的键来引用,外加同样类型的字段列表。输出的是相同结构的记录,模型标记为从图片读取的值带有 source: "image"(source 是可选的,下面的 paid_on 就缺少它,因此不要以它为键),文本则带有 spell_confidence。片段中照片上的方框是为演示而绘制的;API 返回的是值,而不是图像坐标。
该请求在 Clairic 上运行,花费 $0.00025:
import base64
import os
import requests
API = "https://openrouter.ai/api/alpha/extractions"
HEADERS = {"Authorization": f"Bearer {os.environ['OPENROUTER_API_KEY']}"}
with open("receipt.png", "rb") as f:
receipt = base64.b64encode(f.read()).decode()
r = requests.post(
API,
headers=HEADERS,
json={
"model": "cloudflare/clairic",
"state": "receipt",
"assets": {"receipt": {"type": "image", "format": "png", "data_base64": receipt}},
"fields": {
"merchant": {"type": "text"},
"total": {"type": "number", "decimals": 2},
"paid_on": {"type": "date"},
"tax": {"type": "number", "decimals": 2, "instructions": "Sales tax charged"},
"tip": {"type": "number", "decimals": 2, "instructions": "Gratuity, if any"},
},
},
)
r.raise_for_status()
print(r.json()["answers"])Clairic 读取了 1,064 个图像 token,总计 2,532 个,并作出回答(响应,减去其 model 行):
{
"merchant": { "type": "text", "value": "NORTH HAROR C", "p_null": 8.0e-5, "confidence": 0.733, "source": "image", "spell_confidence": 0.733 },
"total": { "type": "number", "value": 29.04, "p_null": 5.3e-8, "confidence": 0.9995, "source": "image" },
"paid_on": { "type": "date", "value": "2026-10-24", "p_null": 0.0061, "confidence": 0.9999 },
"tax": { "type": "number", "value": 3.79, "p_null": 2.8e-4, "confidence": 0.9982, "source": "image" },
"tip": { "type": "number", "value": null, "guess": 0, "p_null": 0.9999, "confidence": 0.8923 }
}所有非空的数值和日期字段返回的置信度都在 0.99 以上,tip 是一个明确的 null,而不是凭空编造的零,p_null 为 0.9999。商户名称有误(收据上写着“NORTH HARBOR CAFE”),Clairic 也指出了这一点:spell_confidence 为 0.73,比响应中的其他所有字段低了约三分之一。这正是需要转给人工处理的字段,而响应已经告诉了你具体是哪一个。
PDF 也可以放入 assets,并带有 "type": "document" 和 "format": "pdf"。Clairic 只能读取图像,因此 PDF 交给 ScaleDown Extract 处理,它每次请求读取一个 PDF 或图像,并回答 text 和 list 字段。片段中页面上的方框是为演示而绘制的;Extract 返回的是值和置信度,而不是页面坐标。
该请求在 Extract 上运行,花费 $0.00016:
curl https://openrouter.ai/api/alpha/extractions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<EOF
{
"model": "scaledown/extract",
"state": "po",
"assets": { "po": { "type": "document", "format": "pdf", "data_base64": "$(base64 < purchase-order.pdf | tr -d '\n')" } },
"fields": {
"po_number": { "type": "text" },
"vendor": { "type": "text", "instructions": "The supplier the order is placed with" },
"total": { "type": "text", "instructions": "Order total including shipping" },
"delivery_date": { "type": "text", "instructions": "Requested delivery date" },
"items": { "type": "list", "items": "text", "instructions": "Ordered line items" },
"approver": { "type": "text", "instructions": "Who approved the order" }
}
}
EOFExtract 从 PDF 中读取了 3,972 个输入 token,并在 2.9 秒内作出回答(响应,减去其 model 行):
{
"answers": {
"po_number": { "type": "text", "value": "PO-20931", "confidence": 1, "source": "document" },
"vendor": { "type": "text", "value": "Meridian Office Supply", "confidence": 1, "source": "document" },
"total": { "type": "text", "value": "$4,200.00", "confidence": 0.814, "source": "document" },
"delivery_date": { "type": "text", "value": "November 18, 2026", "confidence": 0.979, "source": "document" },
"items": { "type": "list", "value": ["Standing desk, 60 in, walnut", "Task chair, mesh back", "Monitor arm, dual"], "confidences": [0.994, 0.999, 1], "source": "document" },
"approver": { "type": "text", "value": "Priya Shah", "confidence": 1, "source": "document" }
},
"truncated": false,
"usage": { "input_tokens": 3972, "output_tokens": 0, "cost": 0.00015888 },
"id": "gen-dec-1794274074-RzjUzkyrf7WfR9LpFUTO",
"provider": "ScaleDown"
}每个值都是正确的,包括从表格中提取的三个明细项。与 Clairic 相比有两点差异需要提前考虑:Extract 没有 number 或 date 类型,因此总额和交付日期会以页面上的字符串形式返回,而且它为每个值(以及每个列表项)报告置信度,但没有 p_null 或 span。总额为 0.81,是需要扫一眼的字段;其余的都在 1 或接近 1。
模型列表
发布时有 三个模型 可用,同一个请求在所有模型上都能使用,因此你可以选择适合任务的那一个。对于图像(比如收据照片),以及需要返回数字、日期或估算值时,使用 Clairic。使用 ScaleDown Extract 从 PDF 中提取文本,比如合同中的当事方。使用 Mercury Decide 从纯文本中提取名称或短语,比如电子邮件或支持工单。
| 模型 | 读取内容 | 字段类型 | 输入价格 | 提供商选项 |
|---|---|---|---|---|
Clairic(cloudflare/clairic) | 文本以及最多 4 张 PNG 或 JPEG 图像 | 所有类型 | $0.10/M | provider.options.cloudflare 下的 include_quantiles、return_state_text |
Extract(scaledown/extract) | 文本,或一个 PDF 或图像 | text,以及 text 的 list | $0.04/M | provider.options.scaledown 下的 threshold、top_n |
Mercury Decide(inception/mercury-decide) | 仅文本 | text,以及 text 的 list | $0.02/M | provider.options.inception 下的 snap_to_words、threshold 和 group_fields |
三个模型的输出均免费。价格为 2026 年 11 月 6 日的目录价;当前价格见各模型页面。
Cloudflare 的 Clairic
Clairic(cloudflare/clairic)是 Cloudflare 在 Workers AI 上的信息抽取模型,是你应该首先尝试的一个。它每次请求可读取文本以及最多四张 PNG 或 JPEG 图像,支持所有字段类型,并且是首发模型中唯一能返回 p_null、span 以及 estimate 和 forecast 的分布的模型。上文第 1 节和第 2 节就是在它上面运行的。有两个 provider 选项可以扩展响应:include_quantiles: true 为每个 estimate 和 forecast 返回 99 个百分位数,return_state_text: true 则会回显 span 偏移量所索引的确切原文,这样你可以对照检查某个切片。
Extract(scaledown/extract)每次请求可读取文本,或一份 PDF 或一张图像,并为每个值附带置信度来回答 text 和 list 字段。它是目前处理 PDF 的模型(第 3 节)。它不报告 null 概率,因此会拒绝 null_threshold;provider.options.scaledown 下的 threshold 和 top_n 用于调节它选取值的方式。
Inception 的 Mercury Decide
Mercury Decide(inception/mercury-decide)只读取文本,以三者中最低的输入价格回答 text 和 list 字段。它会拒绝 reference_date;provider.options.inception 下的 snap_to_words、threshold 和 group_fields 是它的选项。
纯文本字段在哪里都能运行。我们把第 1 节发票的 text 和 list 字段发给了 Mercury Decide 和 Extract:两者返回了相同的值,在文本上也给出了与 Clairic 相同的 span,价格分别为 $0.000015 和 $0.000014。Extract 对 PDF 不返回 span(第 3 节)。
两条路线使用相同的信封(model、state、assets、provider),区别在于你交给模型什么、模型又交还给你什么。
Decisions:答案由你来写,模型对它们进行权衡。Decisions 请求携带 questions,每个问题都自带答案空间:noul 是一个或真或假的命题,choice 列出各选项,score 指定一个量表,box 要求给出图像中的某个区域。对于 noul、choice 或 score,模型绝不会产生你没有写下的值;它在你写下的答案上分配概率(box 返回你所描述区域的坐标)。这正是它成为一切主观判断类任务的合适工具的原因:这是不是一张发票,这五项条款中哪一项适用,这有多严重,这张图像里是否含有收据。输出是一个经过校准、可供设定阈值的数字,而错误的答案也只是你已经在处理的选项之一。
Extractions:字段由你来命名,模型去找值。Extractions 请求携带 fields,每个字段是一个名称加一个类型:text、number、date、list、duration、estimate、forecast。答案空间是类型本身,而不是你写下的列表,因此模型必须在文档中定位这个值(或者进行计算,比如根据开票日期和条款算出到期日;或者进行估算,比如算出付款所需天数)。因为值是开放的,答案会附带证据:它所读取的 span、表明文档中是否根本不存在任何对应内容的 p_null,以及 confidence。当答案就是内容本身时,这才是合适的工具:收据上的金额、合同上的名称、表格上的日期。
与第 1 节相同的发票,通过 Clef Flash 上的 Decisions 处理:
{
"questions": {
"overdue": { "type": "noul", "instructions": "The invoice is past due as of 2026-11-06." },
"terms": { "type": "choice", "instructions": "What are the payment terms?", "criteria": { "net 15": null, "net 30": null, "net 45": null, "net 60": null, "due on receipt": null } },
"has_late_fee": { "type": "noul", "instructions": "The invoice states a penalty for late payment." }
}
}{
"answers": {
"overdue": { "type": "noul", "noul": 0.2069 },
"terms": { "type": "choice", "choice": "net 45", "probabilities": { "net 15": 0.0096, "net 30": 0.0131, "net 45": 0.9623, "net 60": 0.0096, "due on receipt": 0.0055 }, "confidence": 0.908 },
"has_late_fee": { "type": "noul", "noul": 0.9358 }
},
"usage": { "input_tokens": 466, "output_tokens": 0, "cost": 0.000008854 }
}在同一张发票上,Decisions 以 0.96 的置信度回答付款条款为 net 45,且该发票并未逾期。Extractions(第 1 节)返回发票号 INV-4417,位于第 8 到第 16 个字符处,总金额为 3850。
经验法则是:如果发送请求之前你就能列出可能的答案,就用 Decisions。如果答案是写在文档中的某个值,就用 Extractions。
你也可以把两者结合使用。Decisions 可以检查一份文档是否是发票,然后 Extractions 再从那些是发票的文档中抽取字段。
这两个 API 接受的请求几乎相同。区别在于 Decisions 提出的问题有一组可能的答案,比如是或否,或从选项中选择,而 Extractions 请求从文档中填写的字段。要把一个请求从 Decisions 切换到 Extractions,把 questions 重命名为 fields,并把每一项改写为一个字段。
入门
获取一个API 密钥,在Clairic 模型页面上打开 Playground,用你自己的字段运行上面的发票示例,然后阅读Extractions 指南和API 参考。要用 Responses API 和 ScaleDown Extract 完成同样的任务,请参阅cookbook。
在 Discord 的 #feedback 频道告诉我们你在提取什么。
常见问题
这个 API 稳定吗?
它目前是 alpha 版。其形态可能会变化,指南会最先记录这些变更。
请求出错时会发生什么?
校验在 OpenRouter 上进行,任何内容到达提供商之前就会完成:未知的键、Mercury Decide 上的 date 字段、Clairic 上的第五张图片、Clairic 上的 PDF,或没有任何内容引用的资源,都会返回一个 400,其消息会指出问题所在。向该路由发送 questions 会得到一个 400,它会指引你到 /api/alpha/decisions。
字段如何变为 null?
在 Clairic 上,当 p_null 超过 0.5 时。为每个字段设置 null_threshold 来调整这条线,读取 guess 可以看到模型本来会给出的值。Extract 不报告 p_null,因此来自它的 null 是模型的直接答案,并且它会拒绝 null_threshold。
如果文档中的日期没有年份怎么办?
传入 reference_date,模型会将这些日期锚定到它。没有 date 类型的模型会拒绝它:Mercury Decide 和 Extract。
如果文档很长怎么办?
响应中的 truncated: true 表示提供商只读取了状态的一段前缀。usage.passes 统计当你的字段无法放入一次调用时所需的上游调用次数,而 schema_tokens 是你的字段规格在每次请求中的开销。
我可以迁移一个 Decisions 请求吗?
外层结构是一样的;把 questions 重命名为 fields,并重写每个规格,因为带选项的 choice 与 text 字段是不同的请求。
span 如何计数?
以 Unicode 码点计算,[start, end) 到 state。在以 UTF-16 单位索引字符串的语言中,请按码点切片:在 JavaScript 中,用 Array.from(state).slice(start, end).join(''),而不是 state.slice(start, end)。Clairic 上的 return_state_text: true 会原样返回偏移量所指向的文本,因此你可以检查切片。
Playground 支持它吗?
支持:Clairic 模型页面上有一个 Playground,接受 state 和 fields,并显示带类型的答案。
来源:OpenRouter:Blog(Announcements) · openrouter.ai