1 · 你在哪里会用到它
文档助手常见任务是把字段提取成表格。OpenAI API 另提供按 schema 约束响应的 Structured Outputs。这不意味着 ChatGPT 每个表格功能都使用同一实现。这里由你提供候选 JSON,本地代码负责验证,不调用模型。
官方产品/API 文档 ↗来源核对日期 2026-10-25。产品行为来自官方公开说明,下方代码是独立教学实现。
2 · 关键工程决策
使用两个独立关卡:结构验证拒绝缺失、多余和类型错误字段;证据验证检查引文是否存在并支持声明金额。任何单一关卡都不能解决语义歧义:文档可能同时有小计、税额和总计,它们都是有效数字。应明确展示拒绝,不能默默将字符串转数字或用零替代。
- 示例候选具有四个允许字段,金额为有限非负数。
- 发票 ID 出现在原文,引文 USD 42.50 也存在。
- 42.5 格式化为两位小数得到 42.50,与证据匹配。
- 把金额改为 425:shapeValid 仍为 true,但 accepted 为 false,区分结构与事实依据。
3 · 运行并修改输入
完全在浏览器运行,无模型调用、网络请求、API Key 或上传。输入为 JSON,这是确定性组件演示,不是生成式助手。
{
"shapeValid": true,
"accepted": true,
"errors": [],
"limitation": "Exact-text checks only; conflicting totals and invoice context need further validation."
}初始输出是构建时实际计算的示例结果。修改后点击运行以计算你的结果。
4 · 完整源代码
需要现代浏览器或 Node.js 18+。下载模块,将下方 runner 存为同目录 demo.mjs,执行 node demo.mjs,无需 npm 依赖。
下载源代码 ↓// Validate a candidate output supplied by a person or model. No model call.
export const example = {
source: 'Invoice A-17. Total: USD 42.50.',
candidate: {invoice_id: 'A-17', currency: 'USD', amount: 42.5, evidence: 'USD 42.50'}
};
export function run({source, candidate}) {
const errors = [];
if (typeof source !== 'string' || source.length > 20000) throw Error('Invalid source');
if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) throw Error('candidate must be an object');
const keys = ['invoice_id', 'currency', 'amount', 'evidence'];
if (Object.keys(candidate).some(key => !keys.includes(key))) errors.push('Unexpected field');
for (const key of ['invoice_id', 'currency', 'evidence']) {
if (typeof candidate[key] !== 'string' || !candidate[key].trim()) errors.push(`Invalid ${key}`);
}
if (!Number.isFinite(candidate.amount) || candidate.amount < 0) errors.push('Invalid amount');
if (!['USD', 'EUR', 'CNY'].includes(candidate.currency)) errors.push('Unsupported currency');
const shapeValid = errors.length === 0;
if (shapeValid) {
if (!source.includes(candidate.invoice_id)) errors.push('Invoice ID absent from source');
if (!source.includes(candidate.evidence)) errors.push('Evidence quote absent from source');
const expected = `${candidate.currency} ${candidate.amount.toFixed(2)}`;
if (!candidate.evidence.includes(expected)) errors.push('Amount/currency not supported by quote');
}
return {shapeValid, accepted: errors.length === 0, errors,
limitation: 'Exact-text checks only; conflicting totals and invoice context need further validation.'};
}
import {run, example} from './validated-extraction.mjs';
console.log(JSON.stringify(run(example), null, 2));5 · 失败案例与生产差距
精确子串检查是教学约束,不等于理解发票。多张发票、冲突金额、本地格式和小数精度需要更强处理。生产财务系统通常使用 Decimal 或整数最小货币单位。接入真实模型时,需分别处理拒绝、不完整输出与解析失败。
6 · 你的实现练习
增加缺失引文、数字字符串、多余字段和冲突总额案例。扩展来源区间与发票身份字段,并解释哪些案例仍需复核。
交付修改后的代码、至少一个成功与一个失败案例,并解释测试不能证明什么。
继续学习关联知识点 →