先固定输出字段再换模型 / Gemini 3.6 Flash 在抽取任务里的取舍边界

文章导读
从文档里抽字段时好时坏,多数情况不是模型能力不够,而是提示里没规定清楚三件事:返回哪些字段、字段顺序是什么、缺字段时写什么。建议先把字段清单和输出结构固定下来,用同一批样本分别跑一次自由输出和固定字段输出,看字段齐全度和字段名漂移,再决定是否值得换成 Gemini 3.6 Flash 这类模型。换模型改变的是理解和归纳的上限,改不了没有约束的输出格式。
📋 目录
  1. 一 把要抽的字段列成清单并区分必需与可选
  2. 二 用同一批样本比较两种输出方式
  3. 三 写一版输出字段模板放进提示
  4. 四 检查缺失字段时的表现
  5. 五 划定适合自动抽取与需人工复核的范围
A A

从文档里抽字段时好时坏,多数情况不是模型能力不够,而是提示里没规定清楚三件事:返回哪些字段、字段顺序是什么、缺字段时写什么。建议先把字段清单和输出结构固定下来,用同一批样本分别跑一次自由输出和固定字段输出,看字段齐全度和字段名漂移,再决定是否值得换成 Gemini 3.6 Flash 这类模型。换模型改变的是理解和归纳的上限,改不了没有约束的输出格式。

字段抽取按“先定字段清单、再定输出模板、最后才换模型”的顺序做。字段清单区分必需与可选,并写清缺失时留空还是跳过;提示里固定字段顺序、空值写法和禁止补充原文外信息;同一批样本各跑一次自由输出与固定字段输出,记录字段齐全度、键名是否漂移、有没有出现原文没有的内容。能在原文里定位到的字段可以自动采用,日期、金额、编号这类一旦编造代价高的字段必须人工过一遍。

把要抽的字段列成清单并区分必需与可选

先不要写提示,先写字段表。自由输出时模型会自己决定输出哪些字段,同一批文档里有的记录多两个字段、有的少一个字段,程序侧就得为每条记录写额外判断。把字段固定成清单后,模型只负责填值,不负责决定结构。

字段名含义是否必需缺失时行为
doc_id文档编号必需留空字符串
party_a甲方名称必需留空字符串,并标记待复核
sign_date签署日期必需留 null,不做推测
amount_total总金额必需留 null,并标记待复核
payment_terms付款条款可选跳过,不写进输出
remark备注可选留空字符串

必需字段的判断标准是:这条记录缺了该字段还能不能继续走后续流程。不能走的列必需,只能用于展示或统计的列可选。“留空”和“跳过”必须提前定死,不要交给模型决定;同一个可选字段一条记录出现、一条记录不出现,下游解析就要写两套分支。

用同一批样本比较两种输出方式

取一批覆盖不同版式的文档,建议几十条量级,同一批样本各跑一次:第一种只给抽取目标、不限制输出格式;第二种给出固定字段模板。每条记录登记三类信息:返回字段数与应返字段数的对比、键名是否与模板一致、返回内容里有没有原文找不到的片段。

样本方式字段数 / 应返键名与模板一致含原文外内容
S01自由输出3 / 5否(使用了“甲方”)无
S01固定字段5 / 5是无

比对可以用一段不依赖具体接口的校验脚本完成,把模型返回的原文喂进去即可:

import json

REQUIRED = ["doc_id", "party_a", "sign_date", "amount_total"]
OPTIONAL = ["payment_terms", "remark"]

def check(raw):
    try:
        obj = json.loads(raw)
    except json.JSONDecodeError:
        return {"ok": False, "reason": "非合法 JSON"}
    missing = [k for k in REQUIRED if k not in obj]
    extra = [k for k in obj if k not in REQUIRED + OPTIONAL]
    empty = [k for k in REQUIRED if obj.get(k) in ("", None)]
    return {"ok": not missing and not extra,
            "missing": missing, "extra": extra, "empty": empty}

这一步的作用是把“感觉不稳定”变成可逐条看的问题:是键名漂移,还是字段缺失,还是模型补了原文没有的内容。三类问题的修法不一样,键名漂移改提示模板就能压住,编造则要靠缺失样本单独验证。

写一版输出字段模板放进提示

模板骨架放在系统提示或用户消息里都行,具体位置按所用接口的文档核对,不要预设参数名。骨架只需要交代字段顺序、空值写法和禁止项:

先固定输出字段再换模型 / Gemini 3.6 Flash 在抽取任务里的取舍边界
你是文档字段抽取器。只依据原文抽取,不推断、不补全。

输出要求:
1. 只输出一个 JSON 对象,不要输出解释文字,不要包 Markdown 代码块。
2. 键名与顺序严格按下表,不得增删字段、不得改名、不得嵌套重命名。
3. 原文中找不到对应内容时按缺失写法处理,不要用常识补全。

字段顺序:doc_id, party_a, sign_date, amount_total, payment_terms, remark
缺失写法:文本字段填空串 "";日期与金额填 null;
          不要写“未知”“N/A”“不详”“未提及”。
禁止:不得输出原文未出现的名称、日期、金额;
      不得把多个字段合并成一段描述;
      不得新增字段顺序表以外的键。

原文:
<<<
{text}
>>>

“不要包 Markdown 代码块”这条容易被忽略,模型默认爱加代码围栏,加了之后程序侧要么先剥壳要么解析失败,写进模板比在代码里兜底更省事。模板改完后仍然用同一批样本跑,比较的是键名一致率和缺失率,不是主观观感。

检查缺失字段时的表现

正常文档大多字段齐全,看不出模型在缺字段时的行为。需要手工构造几条确实缺字段的样本:删掉整段签署日期、把金额改成“面议”、去掉甲方名称只留盖章位置。然后逐条记录返回形态:

  • 留空:键存在,值为空串或 null,模板字段数量不变。这种最容易接,程序按空值分支处理即可。
  • 跳过:该键直接不出现。程序解析不会报错,但取值的代码要写默认值,否则下游会拿到 undefined 一类结果。
  • 补内容:返回了一个原文里没有的日期或金额,通常看着很合理。这种必须记录样本原文和返回原文,作为该字段不能自动采用的依据。

判断标准很简单:把返回值和原文做一次定位,能在原文里找到对应片段的是抽取,找不到的是生成。缺字段样本里出现生成内容,说明提示里的禁止项压不住,此时换模型也不保证消失,需要换写法或改人工复核。

划定适合自动抽取与需人工复核的范围

字段清单、模板和缺失表现都跑过一轮后,边界基本能按字段类型分出来:

  • 可自动采用:编号、标题、机构名称这类在原文中逐字出现的字段。判断依据是返回值和原文能做子串或近似定位,定位成功即视为抽取。
  • 抽样人工过一遍:日期、金额、比例这类需要归一化的字段。模型经常输出“二〇二五年三月”或“人民币壹万元”这类原文写法,转换规则在程序侧,转换结果按字段抽样核对。
  • 必须人工复核:原文没有直接给出、需要推断的字段,例如金额是否含税、某条款归属哪一方、汇总项是否已包含子项。这类字段模型给的值无法在原文中自证,只能作为提示,不能直接入库。

换模型的时机放在这张边界表之后:字段清单稳定、模板稳定、失败集中在语义理解而不是格式的时候,再用同一批样本对比新模型,比较的仍是字段齐全度、键名漂移和原文外内容这三项,而不是换完直接看效果好不好。