OpenRouter 上线 Extractions API 测试版,支持从文本、图片和 PDF 抽取结构化字段
Introducing the Extractions API
OpenRouter 上线 alpha 版 Extractions API,用户描述所需字段即可从文本、图片和 PDF 中抽取结构化值,首发接入 Cloudflare Clairic、ScaleDown Extract 和 Inception Mercury Decide 三个模型。
Extractions API 现已在 OpenRouter 上以 alpha 版本上线。你可以用它从文本、图像和 PDF 中提取特定细节,只需描述你需要的字段,例如邮件中的人名或收据上的总额。
我们首批推出三个提取模型,分别来自 Cloudflare、Inception 和 ScaleDown。请阅读文档开始使用,或在Playground中试用。
一次提取就是一个请求:你指定想从文档中获取的字段,每个字段返回一个带类型的值。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 为单位的数字,从秒到年 | 45 配合 unit: "days" |
estimate | 文档所暗示数量的分布,介于你设定的 min 和 max 之间 | median 45, p10 42, p90 47 |
forecast | 同上,针对未来 horizon 步、以你设定的 interval 为间隔;value、mean、median、p10 和 p90 是每步一个条目的数组 | 未对此发票请求 |
每个答案都带有其 value;还带有什么取决于字段类型和模型。在 Clairic 上,从文本读取的值带有 span,即计入 state 的 [start, end),按 Unicode 码点计数,因此你可以切片文档并展示其来源(一个 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;在文本上还会返回跨度,在 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 | include_quantiles、return_state_text 在 provider.options.cloudflare 下 |
Extract(scaledown/extract) | 文本,或一个 PDF 或图像 | text,以及 text 的 list | $0.04/M | threshold、top_n 在 provider.options.scaledown 下 |
Mercury Decide(inception/mercury-decide) | 仅文本 | text,以及 text 的 list | $0.02/M | snap_to_words、threshold、group_fields 在 provider.options.inception 下 |
三个模型的输出均免费。价格为 2026 年 11 月 6 日的目录值;模型页面有当前价格。
Cloudflare 的 Clairic
Clairic(cloudflare/clairic)是 Cloudflare 在 Workers AI 上的抽取模型,可以从它开始。它每次请求读取文本以及最多四张 PNG 或 JPEG 图像,支持所有字段类型,并且是唯一一个会返回 p_null、跨度以及 estimate 和 forecast 分布的发布模型。上文第 1 节和第 2 节就是在它上面运行的。有两个提供商选项可以扩展响应:include_quantiles: true 会为每个 estimate 和 forecast 返回 99 百分位数,而 return_state_text: true 会回显跨度偏移所索引的确切文本,因此你可以用切片来核对。
Extract(scaledown/extract)每次请求读取文本,或一个 PDF 或图像,并以每个值的置信度回答 text 和 list 字段。它是目前用于 PDF 的模型(第 3 节)。它不报告空值概率,因此会拒绝 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 相同的跨度,费用分别为 $0.000015 和 $0.000014。Extract 对 PDF 不返回跨度(第 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 回答付款条款为净 45 天,置信度为 0.96,并且发票未逾期。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 字段是不同的请求。
跨度如何计数?
以 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 Announcements · openrouter.ai