跳到正文
OpenRouter Announcements·· 2 天前AI 评分58

OpenRouter 上线 Extractions API 测试版,支持从文本、图片和 PDF 抽取结构化字段

Introducing the Extractions API

AI 导读

OpenRouter 上线 alpha 版 Extractions API,用户描述所需字段即可从文本、图片和 PDF 中抽取结构化值,首发接入 Cloudflare Clairic、ScaleDown Extract 和 Inception Mercury Decide 三个模型。

正文 · AI 翻译

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 和 unit3850
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" }
  }
}
EOF

Extract 从 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/Minclude_quantiles、return_state_text 在 provider.options.cloudflare 下
Extract(scaledown/extract)文本,或一个 PDF 或图像text,以及 text 的 list$0.04/Mthreshold、top_n 在 provider.options.scaledown 下
Mercury Decide(inception/mercury-decide)仅文本text,以及 text 的 list$0.02/Msnap_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