
常见做法:prompt + JSON schema
常见的写法是:在提示词里列出字段和 JSON schema,拿到输出后再解析。搭起来快,很多团队也确实这么上线了。
剩下的活儿都在你这边:校验每个值的类型,确认这个值原文里真有,再决定缺了怎么办。
编造值的问题,以及 Clairic 怎么处理
生成式模型天生倾向于给出一个"说得通"的答案。Clairic 则在标量字段上额外返回 pNull:超过 null 阈值(默认 0.5)时 value 为 null,guess 里可能还留着一个值。阈值可以用 options.nullThreshold 整体调整,也可以在单个字段上设 nullThreshold。
官方博客的投诉邮件例子里,邮件根本没写物流单号,于是 tracking_number 返回 null,而不是编一个出来。

类型化和 span 带来的可审计性
Clairic 支持 9 种字段类型:text、number、date、time、datetime、duration、list、estimate、forecast。number 可以设 decimals。text 字段可以带 span,也就是这个值在 state 里的起止字符位置,审核的人能直接在原文里看到高亮。
list 也能带 spans。官方投诉邮件例子中,「屏幕碎裂」「外壳凹陷」两项损坏都各自标出了在原文里的位置。

下表只比较接口和输出形状,不比速度、准确率或价格。
| 提示词让大模型输出 JSON | Clairic | |
|---|---|---|
| 返回什么 | 生成的文本,需自行解析成 JSON | 每个字段一个类型化值 |
| 缺失值 | 取决于提示词和你的校验 | pNull 超过阈值时返回 null |
| 置信信号 | 需自行设计 | 标量字段可带 confidence、pNull |
| 原文定位 | 需自行实现 | text 可带 span,list 可带 spans |
| 类型 | 需自行校验 | 9 种内置类型,SDK 里有 TypeScript 类型 |
| 计费方式 | 取决于你用的服务 | 每次请求一次,按输入大小,不按字段数 |
| 生成文本? | 是 | 否 |
同一封投诉邮件,用代码写出来是这样:
tsimport {
createSystemOne, defineFields, textField, numberField, dateField, durationField, listField,
} 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 email = `(Fictional sample for illustration.)
Hi Example Shop team,
Order ORD-10482 was delivered on 2026-09-30. I'm writing on 2026-10-11.
The item was $649 plus $52.10 tax. The screen is cracked and the case is dented.
Please help. - Alex Sample`;
const fields = defineFields({
order_number: textField({ instructions: 'The order number in the email.' }),
delivery_date: dateField({ instructions: 'The date the order was delivered.' }),
total_paid: numberField({ decimals: 2, instructions: 'Item price plus tax actually paid.' }),
days_since_delivery: durationField({ unit: 'days', instructions: 'Days from delivery to the date of the email.' }),
damage: listField({ items: 'text' }),
tracking_number: textField({ instructions: 'The shipment tracking number, if the email gives one.' }),
});
const result = await client.extract({ model: 'clairic', state: email, fields });
const { tracking_number, damage } = result.answers;
console.log({
trackingNumber: tracking_number.value, // 邮件里没有物流单号时为 null
trackingPNull: tracking_number.pNull,
damage: damage.value,
damageSpans: damage.spans,
});
安装:npm 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,在 .env 里设置 SYSTEM_ONE_API_KEY,用 node --env-file=.env 加文件名运行。每运行一次就是一次计费请求。
示意输出(数值只取自官方例子):
json{
"total_paid": 701.10,
"days_since_delivery": 11,
"damage": ["cracked screen", "dented corner"],
"tracking_number": null
}
走 HTTP 的话,端点是 POST https://system-one.dev/v1/systemone,SDK 里的驼峰字段名会变成蛇形(如 referenceDate → reference_date)。
计算出来的值
有些值原文里压根没写。官方例子中,邮件没有直接给出实付总额,是 Clairic 把 649 和 52.10 的税费相加得到 701.10;从送达到写邮件的 11 天,也是由两个日期算出来的。
但也有边界。官方博客说,预览版对长链计算、多行汇总还不可靠,格式正确不等于内容正确。上线前请用自己的样本测一遍,并对 confidence、pNull 设阈值。
想直观看 null 的效果,可以试试发票信息提取 demo(需登录):应付合计写着"待确认"时,金额返回 null,发票号照常取出。
成本模型对比
Clairic 按输入大小每次请求收一次费,不会随字段数相乘。具体费率见 Clairic 模型页和定价页。
新账号注册即送 100 积分。
什么时候还是该用大模型
需要写文字的时候,比如写回复、写摘要,就交给大模型。Clairic 不生成文本。
官方的三步处理理赔例子:Clairic 从邮件里取值,Clef 对照政策在退款和维修之间做决定,最后由大模型写回复。决策那一步看到的是结构化的值,不是原始邮件,所以不容易被邮件的措辞带偏。详见先抽取再决策;如果输入是图片,见图片输入。

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