🐦 第9章 实战案例:看图学英语智能助手
📄 一句话概括

把三段文字拆成五个字段:word、phonetic、pos、def_en、example。 不给 schema,三张图给出三种键名,下游一行代码都写不出来。 给了 schema 也不是万事大吉:字段数能查出「漏」,查不出「糊」。

📝 本章和前面几章的关系

这一步是整条链的腰。上面是自由文字,下面是固定字段,全靠这里转。 书里用「信息提取」节点配一张 JSON Schema。 本沙箱没有这个节点,用规则从同一段文字里抠——抠不出来的地方,模型那次同样会漏。 这一节的重点不是怎么写正则,是为什么必须有 schema,以及 schema 管不到什么。

一、不给 schema:三张图三种写法

同一句「把图上的信息提成字段」,跑三张图,键名能给你三种:

图 回来的键 几个
card_01 单词、读音、中文、例句 4
card_02 word、phonetic、pos、meaning、example 5
card_03 内容 1

三张图加起来十种键名。下游写 g['word'],只有第二张对得上。 注意第一张:它甚至没有词性。不是抽漏了,是模型觉得这张图上没有词性——图上确实写着 n.,它没认。 这就是 schema 存在的理由:不是让输出好看,是让下游能写代码。

二、schema 三个字段:名字、类型、缺了怎么办

schema 不是只写五个名字。每个名字后面还要两样东西:类型、缺失规则。

字段 类型 缺了怎么办
word string 必填,缺失整条作废
phonetic string 可空,填 null
pos string 可空,统一用 n. / v. / adj.
def_en string 必填
example string 可空

「缺了怎么办」这一列最容易被跳过。跳过的后果是:缺的时候模型随手编一个,你分不清哪个是真的。 必填项缺失要整条作废,不要凑。凑出来的卡片比没有卡片更糟——用户会照着错的去背。

三、给了 schema,抽出 5/5、4/5、1/5

同一套规则跑三张图:第一张五个全在,第二张四个,第三张一个。 第二张缺的是词性。原因很朴素:图上写的是中文「名词」,而 schema 要的是 n. 这种缩写。 规则认缩写,不认中文。 第三张最阴:它抽到了 1 个——把「无」当成了释义。

空图不是抽不到,是抽到一个假的。 下游拿到一条有释义、没单词的记录,如果只检查「字段数大于 0」,这条就混过去了。 所以必填项的检查不能只数个数。word 为空就直接作废,别管别的字段有几个。

四、抽全了不等于抽对了

第一张五个全在,看着满分。可它的音标是 / bʌs /——斜杠里多了两个空格。 这张卡的文字里,音标前后确实有空格(排版留白),原样抄就抄进来了。拿这个串去查词典,查不到。 字段数没掉,类型也没错(还是 string),只有格式错了。

这就是 schema 管不到的那一层。类型管的是「是不是字符串」,管不了「字符串长得对不对」。 补法是加格式校验:音标必须匹配 ^/[^/]+/$,词性必须是那几个缩写之一。校验放在提取之后、下游之前。 字段数能查出「漏」,查不出「糊」。糊的那种只能靠格式校验。

五、温度、重试、兜底

这一步温度调到 0。要的是同一张图两次跑出一样的结果,不是多样性。 重试一次有意义:模型偶尔会多打一个括号、少一个引号,JSON 解析失败。重试一次多半就好了。 重试两次还失败,就走兜底:把原始描述交出去,让智能体说「这张图我没看懂,你自己看看」。

兜底不是认输,是让失败变成一句人话。这比抛一个 500 给用户强。

六、动手 Demo:信息提取:五个字段,一个都不能少

先看不给 schema 时三张图各给什么键名,再看给了 schema 之后抽到几个。 最后单独看第一张图:五个字段全在,但音标的格式是错的。

def extract(desc):
    seg = dict(s.split(u':', 1) for s in desc.split(u'|'))
    parts = seg[u'文字'].split(u';')
    got = {}
    for p in parts:
        if p.startswith(u'/') and p.endswith(u'/'):  got[u'phonetic'] = p
        elif POS.match(p):                            got[u'pos'] = p
        elif p.endswith(u'.') and u' ' in p:          got[u'example'] = p
        ...
    return got

实跑输出:

--------------------------------------------------------------------
信息提取:五个字段,一个都不能少
--------------------------------------------------------------------


  ① 不给 schema,三张图三种写法
  --------------------------------------------------------------------

| 图 | 模型给回来的键 | 几个 |
|---|---|---|
| card_01.jpg | 单词、读音、中文、例句 | 4 |
| card_02.jpg | word、phonetic、pos、meaning、example | 5 |
| card_03.jpg | 内容 | 1 |

  三张图加起来 10 种键名。下游写死 g[word],只有第二张对得上。
  这就是 schema 存在的理由:不是让输出好看,是让下游能写代码。

  ② 给一张 schema:五个字段、类型、缺了怎么办
  --------------------------------------------------------------------

| 字段 | 类型 | 缺了怎么办 |
|---|---|---|
| word | string | 必填,缺失就整条作废 |
| phonetic | string | 可空,填 null |
| pos | string | 可空,统一用 n. / v. / adj. 这种缩写 |
| def_en | string | 必填 |
| example | string | 可空 |


  ③ 同一套规则跑三张图
  --------------------------------------------------------------------

| 图 | 抽到几个 | 抽到哪些 |
|---|---:|---|
| card_01.jpg | 5/5 | def_en、example、phonetic、pos、word |
| card_02.jpg | 4/5 | def_en、example、phonetic、word |
| card_03.jpg | 1/5 | def_en |

  card_02 只抽到 4 个:图上的词性写成了中文「名词」,而 schema 要的是 n. 这种缩写。
  第三张图更阴:它抽到了 1 个——把「无」当成了释义。空图不是抽不到,是抽到一个假的。
  card_02 的音标出来是「/ bʌs /」,斜杠里多了两个空格。
  拿这个串去查词典会查不到。它的字段数是 4/5,音标那一个还算「在」。
  ! 字段数能查出「漏」,查不出「糊」。糊的那种只能靠格式校验:音标必须匹配 ^/[^/]+/$。

①第一张表三行键名:4 个、5 个、1 个,加起来十种写法。 ②第二张表是 schema:名字、类型、缺了怎么办。三列缺一列都不算完整的 schema。 ③第三张表:5/5、4/5、1/5。第二张缺词性,因为图上写的是中文「名词」。 ④第三张抽到的那 1 个是假的——把「无」当成了释义。空图不是抽不到,是抽到假值。 ⑤最后两句讲格式:音标 / bʌs / 多两个空格,字段数不掉,照样是错的。

30 秒实验

  1. 给你现在的提取节点补一列「缺了怎么办」。必填项写「整条作废」,别写「尽力补全」。
  2. 写一条格式校验:音标必须匹配 ^/[^/]+/$。拿第一张图跑一次,看它过不过。
  3. 把温度从默认值改成 0,同一张图连跑三次,看三次结果是不是一模一样。

常见误区

  1. 「给五个字段名就够了。」还要给类型和缺失规则。少一列,缺的时候模型就自己编。
  2. 「字段全在就是对的。」音标带空格、词性写中文,字段数照样满分,值全是错的。
  3. 「空图抽不到字段。」会抽到假字段,比如把「无」当释义。必填项为空才作废。
自测三问(点开对答案) 1. 为什么必须有 schema? —— 不给 schema,三张图给出三种键名,下游一行代码都写不出来。schema 是给程序用的契约。 2. schema 除了字段名还要写什么? —— 类型和缺失规则。缺了怎么办最容易漏,漏了模型就自己编一个填上。 3. 「抽全了」和「抽对了」差在哪? —— 字段数够不代表值对。音标带空格、词性写中文,数着满分,用起来全错。得加格式校验。

字段有了,但释义还是英文。下一节把它翻成中文——难点在一个词有好几个意思。

相关笔记