。设计制作。)
要抽取的字段
| 字段 | 类型 / 工厂函数 | 说明 |
|---|---|---|
| invoice_number / order_number | text / textField() | 单据号,可带 span |
| 开票日期、due_date | date / dateField() | 日历日期 |
| purchase_time | datetime / dateTimeField() | 日期 + 时间 |
| total、subtotal、tax、tip、unit_price | number / numberField({ decimals: 2 }) | decimals 取值 0–6 |
| quantity | number / numberField({ integer: true }) | 整数 |
| contacts / 明细名称 | list / listField({ items: 'text' }) | items 必填:text、number 或 date |
| days_to_pay | estimate / estimateField({ min, max }) | 返回 median、p10、p90 等 |
文本发票示例(INV-2291)
下面是 Clairic SDK 文档里的发票示例。先装 SDK:
bashnpm install @system-one-ai/core@0.8.0 @system-one-ai/adapter-system-one@0.7.0 @system-one-ai/transport-fetch@0.8.0
保存为 extract-invoice.mts,在 .env 里设置 SYSTEM_ONE_API_KEY:
tsimport {
createSystemOne, defineFields, textField, numberField, dateField, listField, estimateField,
} from '@system-one-ai/core';
import { systemOneAdapter } from '@system-one-ai/adapter-system-one';
import { createFetchTransport } from '@system-one-ai/transport-fetch';
const apiKey = process.env.SYSTEM_ONE_API_KEY;
if (!apiKey) throw new Error('Set SYSTEM_ONE_API_KEY.');
const client = createSystemOne({
adapter: systemOneAdapter,
transport: createFetchTransport(),
apiKey,
timeoutMs: 30_000,
maxRetries: 0,
});
const fields = defineFields({
invoice_number: textField({ instructions: 'The invoice id printed on the document.' }),
due_date: dateField({ instructions: 'Issue date plus the net payment days.' }),
total: numberField({ decimals: 2, instructions: 'The total amount due.' }),
contacts: listField({ items: 'text' }),
days_to_pay: estimateField({ min: 0, max: 120, step: 1 }),
});
const result = await client.extract({
model: 'clairic',
state: [
'INVOICE INV-2291',
'From: Northwind Supply',
'To: Contoso Ltd',
'Issued: 2026-09-02, net 30',
'Total due: 1080.00 including shipping',
'Contact: Dana Ruiz, Priya Shah',
].join('\n'),
fields,
referenceDate: '2026-10-19',
options: { includeQuantiles: false },
});
const invoice: string | null = result.answers.invoice_number.value;
console.log({
model: result.model,
invoice,
dueDate: result.answers.due_date.value,
total: result.answers.total.value,
contacts: result.answers.contacts.value,
daysToPay: result.answers.days_to_pay.median,
truncated: result.truncated,
usage: result.usage,
});
运行:node --env-file=.env extract-invoice.mts。每运行一次就会产生一次计费请求。
contacts 是 list 类型,返回联系人数组;days_to_pay 是 estimate 类型,读它的 median 即可,p10、p90 也会一并返回。

歪斜、模糊的小票照片
官方博客里有个例子:一张拍歪了、字迹也不清楚的小票照片,Clairic 从中取出了订单号、购买时间、数量、单价、小计、税费和小费。小票上本来就没有折扣,所以折扣一项返回 null。
照片版代码如下(保存为 extract-receipt.mts),每次请求最多可以传 4 张图:
tsimport { readFile } from 'node:fs/promises';
import {
createSystemOne, defineFields, textField, numberField, dateTimeField,
type ImageInput,
} from '@system-one-ai/core';
import { systemOneAdapter } from '@system-one-ai/adapter-system-one';
import { createFetchTransport } from '@system-one-ai/transport-fetch';
const apiKey = process.env.SYSTEM_ONE_API_KEY;
const imagePath = process.argv[2];
if (!apiKey || !imagePath) throw new Error('Set SYSTEM_ONE_API_KEY and supply a JPEG path.');
const images: readonly ImageInput[] = [{
mediaType: 'image/jpeg',
base64: (await readFile(imagePath)).toString('base64'),
}];
const client = createSystemOne({
adapter: systemOneAdapter,
transport: createFetchTransport(),
apiKey,
timeoutMs: 30_000,
maxRetries: 0,
});
const fields = defineFields({
order_number: textField({ instructions: 'The order or receipt number.' }),
purchase_time: dateTimeField({ instructions: 'Date and time of purchase.' }),
quantity: numberField({ integer: true }),
unit_price: numberField({ decimals: 2 }),
subtotal: numberField({ decimals: 2 }),
tax: numberField({ decimals: 2 }),
tip: numberField({ decimals: 2 }),
discount: numberField({ decimals: 2, instructions: 'Discount amount, only if the receipt shows one.' }),
});
const result = await client.extract({ model: 'clairic', state: '', images, fields });
for (const [name, answer] of Object.entries(result.answers)) {
console.log(name, answer.value, answer.confidence, answer.pNull);
}
小票上没有折扣时,discount 返回 null。正式上线前,请用自己拍的照片测一遍,并给 confidence、pNull 设好阈值。
;右:真实运行 extract-receipt.mts 的输出,discount 为 null,key 打码。)
referenceDate 与账期计算
referenceDate(HTTP 里写作 reference_date)用来确定没写年份的日期属于哪一年,比如只印了月和日的小票。
到期日可以直接算。发票示例里,due_date 字段的 instructions 写的是 "Issue date plus the net payment days.",Clairic 会根据 2026-09-02 和 net 30 推出到期日。
没有的字段返回 null
pNull 超过 null 阈值(默认 0.5)时,value 返回 null,guess 里可能还有值。阈值可以用 options.nullThreshold 统一调,也可以按字段单独设。
发票信息提取 demo 里就有这种情况:应付合计写着"待确认"时,金额返回 null,发票号照常取出。
计费
Clairic 按输入大小每次请求收一次费,不按字段数计,详见 Clairic 模型页。新账号注册即送 100 积分。
试一下 demo
同样的发票任务,可以直接在发票信息提取 demo 里试(需登录)。想直接调 API 的话,POST https://system-one.dev/v1/systemone 的请求体如下:
json{
"model": "clairic",
"state": "INVOICE INV-2291\nIssued: 2026-09-02, net 30\nTotal due: 1080.00",
"reference_date": "2026-10-19",
"fields": {
"invoice_number": { "type": "text" },
"total": { "type": "number", "decimals": 2 }
}
}
认证、幂等和请求头见 API 文档。在重放记录仍可用期间,用同一个 key 重试同一操作不会重复扣费。

相关阅读
核验日期:2026-10-22