---
title: "让大模型输出 JSON，还是用专门的抽取模型？"
description: "让大模型吐 JSON 和用专门的抽取模型有什么不同：null 处理、置信度、原文定位、按请求计费。"
canonical: "https://system-one.dev/zh-CN/blog/clairic-vs-llm-extraction"
language: "zh-CN"
---

# 让大模型输出 JSON，还是用专门的抽取模型？

**要点**\n\n1. 让大模型输出 JSON，本质是生成"长得像 JSON"的文本；Clairic 每个字段返回一个类型化的值，不生成文本。
2. 输入确定不了的值，Clairic 返回 null（pNull 超过阈值），而不是一个看起来合理的猜测；text 字段还能指回原文位置（span）。
3. 用 Clairic 取值、Jev 或 Clef 做决定，只在需要写文字（比如回复）时才用大模型。

让大模型输出 JSON 当然能用，但缺失值怎么处理、类型对不对、值从哪来，都得你自己兜底。Clairic 这类抽取模型把这些直接做进了返回结构里。

![提示词让大模型输出 JSON 与 Clairic 类型化字段的对比](TODO-IMG: 封面，左右分栏。左："Prompt → 长得像 JSON 的文本"；右："Fields → 类型化值 + null"。设计制作。)

## 常见做法：prompt + JSON schema

常见的写法是：在提示词里列出字段和 JSON schema，拿到输出后再解析。搭起来快，很多团队也确实这么上线了。

剩下的活儿都在你这边：校验每个值的类型，确认这个值原文里真有，再决定缺了怎么办。

## 编造值的问题，以及 Clairic 怎么处理

生成式模型天生倾向于给出一个"说得通"的答案。Clairic 则在标量字段上额外返回 `pNull`：超过 null 阈值（默认 0.5）时 `value` 为 `null`，`guess` 里可能还留着一个值。阈值可以用 `options.nullThreshold` 整体调整，也可以在单个字段上设 `nullThreshold`。

官方博客的投诉邮件例子里，邮件根本没写物流单号，于是 `tracking_number` 返回 `null`，而不是编一个出来。

![邮件里没有物流单号时 Clairic 返回 null](TODO-IMG: 示意卡片：tracking_number: null，旁边标注"pNull > 阈值"。设计制作。)

## 类型化和 span 带来的可审计性

Clairic 支持 9 种字段类型：text、number、date、time、datetime、duration、list、estimate、forecast。number 可以设 `decimals`。text 字段可以带 `span`，也就是这个值在 `state` 里的起止字符位置，审核的人能直接在原文里看到高亮。

list 也能带 `spans`。官方投诉邮件例子中，「屏幕碎裂」「外壳凹陷」两项损坏都各自标出了在原文里的位置。

![用 Clairic 的 span 在原邮件中高亮损坏项](TODO-IMG: 投诉邮件原文，两项损坏被高亮，依据 span 数据制作。设计制作。)

下表只比较接口和输出形状，不比速度、准确率或价格。

| | 提示词让大模型输出 JSON | Clairic |
|---|---|---|
| 返回什么 | 生成的文本，需自行解析成 JSON | 每个字段一个类型化值 |
| 缺失值 | 取决于提示词和你的校验 | pNull 超过阈值时返回 null |
| 置信信号 | 需自行设计 | 标量字段可带 confidence、pNull |
| 原文定位 | 需自行实现 | text 可带 span，list 可带 spans |
| 类型 | 需自行校验 | 9 种内置类型，SDK 里有 TypeScript 类型 |
| 计费方式 | 取决于你用的服务 | 每次请求一次，按输入大小，不按字段数 |
| 生成文本？ | 是 | 否 |

同一封投诉邮件，用代码写出来是这样：

```ts
import {
  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 SDK 文档](https://docs.system-one.dev/zh-CN/docs/sdk/clairic) *（CTA 按钮）*

## 计算出来的值

有些值原文里压根没写。官方例子中，邮件没有直接给出实付总额，是 Clairic 把 649 和 52.10 的税费相加得到 701.10；从送达到写邮件的 11 天，也是由两个日期算出来的。

但也有边界。官方博客说，预览版对长链计算、多行汇总还不可靠，格式正确不等于内容正确。上线前请用自己的样本测一遍，并对 confidence、pNull 设阈值。

想直观看 null 的效果，可以试试[发票信息提取 demo](https://system-one.dev/zh-CN/demo/invoice-extraction)（需登录）：应付合计写着"待确认"时，金额返回 null，发票号照常取出。

## 成本模型对比

Clairic 按输入大小每次请求收一次费，不会随字段数相乘。具体费率见 [Clairic 模型页](https://system-one.dev/zh-CN/models/clairic)和[定价页](https://system-one.dev/zh-CN/pricing)。

新账号注册即送 100 积分。

[查看 Clairic 计费](https://system-one.dev/zh-CN/models/clairic) *（CTA 按钮）*

## 什么时候还是该用大模型

需要写文字的时候，比如写回复、写摘要，就交给大模型。Clairic 不生成文本。

官方的三步处理理赔例子：Clairic 从邮件里取值，Clef 对照政策在退款和维修之间做决定，最后由大模型写回复。决策那一步看到的是结构化的值，不是原始邮件，所以不容易被邮件的措辞带偏。详见[先抽取再决策](https://system-one.dev/zh-CN/blog/clairic-vs-jev-clef)；如果输入是图片，见[图片输入](https://system-one.dev/zh-CN/use-cases/screenshot-to-json)。

![Clairic 取值、Clef 决策、大模型写回复](TODO-IMG: 流程：Clairic 取值 → Clef 决定退款/维修 → 大模型写回复。设计制作。)

## 相关阅读

- [Clairic 是什么？一文看懂抽取模型](https://system-one.dev/zh-CN/blog/what-is-clairic)
- [Clairic 和 Jev、Clef 怎么选：先抽取再决策](https://system-one.dev/zh-CN/blog/clairic-vs-jev-clef)
- [截图转 JSON：给 Agent 用的图片字段抽取](https://system-one.dev/zh-CN/use-cases/screenshot-to-json)
- [Clairic 模型页](https://system-one.dev/zh-CN/models/clairic)

[查看 Clairic 计费](https://system-one.dev/zh-CN/models/clairic) *（CTA 按钮，文末）*

核验日期：2026-10-22

## 常见问题

### Clairic 是大模型吗？

不是。它不生成文本，而是按你定义的字段返回类型化的值。

### 可以和大模型一起用吗？

可以。常见链路是 Clairic 取值，Jev 或 Clef 做决定，需要回复时再交给大模型写。

### 字段多了会更贵吗？

不会。Clairic 按输入大小每次请求收一次费，不按字段数相乘。

### 原文里没有某个值时会怎样？

pNull 超过 null 阈值（默认 0.5）时 value 返回 null；guess 里可能还有值。

### Clairic 一定对吗？

不一定。预览版对长链计算和多行汇总还不可靠，格式正确也不代表内容正确。上线前用自己的样本测试，并对 confidence 和 pNull 设阈值。
