🐦 第8章 实战案例:图文混合的火爆推文生成器
📄 一句话概括

结束节点是整条链的输出契约:交出去几个字段、每个什么类型。 不声明就是一大串文字,下游取不出任何字段——而且它不报错。 只声明下游真要用的那几个。声明十个用两个,剩下八个是维护负担。

📝 本章和前面几章的关系

上一节把图生成了,这一节把东西交出去。 这一节很短,但它决定了下游能不能接。 第 7.2 节讲数据库定字段,这里是同一件事——只是一个在表里,一个在节点上。 「不声明也不报错」这一条是本节的重点。所有静默失败的坑都是同一个形状。

一、两种输出形态

声明过的:一个对象,三个字段——text、img、title。每个字段单独取。 没声明的:一整串字,二十七字。它就是一串字符,没有结构。 演示里下游要取 img,声明过的直接拿到地址;没声明的拿不到,只能拿到一整串。

这不是「取不到报错」,是「取不到返回空」。 差别很大:报错你会去修,返回空你会以为没数据。

二、没声明时会怎么坏

最轻的坏法:下游拼出一句「(是一整串,取不出 img)」这种缺角的文案。 最重的坏法:卡片节点的占位一个都填不上,渲染出一张空卡。 中间的坏法:把整串字塞进了 title 字段,卡片上显示一整段文章。

三种坏法的共同点:链是通的,日志是绿的。 所以它是最难查的一类故障——你得主动去看输出,而不是等它报错。

三、该声明什么

一、每个字段一个名字,用英文或拼音。中文在引用里能拼,在代码节点里容易出编码问题。 二、每个字段一个类型:文本、图片地址、数字、布尔。类型写错,下游解析时会出问题。 三、只声明下游真要用的那几个。 声明十个,下游只用两个,剩下八个是维护负担。

第三条容易被忽略。多声明一个字段,就多一处要保证它有值的地方。

四、不同渠道要不同字段

场景 要声明的字段
发到公众号 title、text、img
发到小红书 title、text、img、tags
只回一句话 text

同一张工作流要发三个平台,怎么办?两种做法。 做法一,声明三套,用选择器挑。 一张图搞定三个渠道,但结束节点前面多一个分支。 做法二,复制三份工作流。 简单,但改一处要改三份——这是第 6.4 节说的「复制会变的东西」的坑。

推荐做法一。能用一个分支解决的,别复制整张图。

五、输出契约和输入契约

一张工作流有两个契约:开始节点的入参、结束节点的输出。 两个都要定清楚。开始节点定不清,调用方会漏填;结束节点定不清,下游会取空。 有个对称的观察:入参错一般是「报错」,出参错一般是「静默」。

因为入参有人喂,喂错了喂的人知道;出参没人验,取空了取的也不知道。所以出参那一侧要格外小心。

六、什么时候回来定这个

第 8.2 节说过:先让链跑通,再回来定结束节点。 跑通之前,你不知道中间会产出什么字段。定早了要反复改。 但也不能一直不定。判断标准:中间节点的输出稳定了(三天没改),就回来定契约。

定完之后,改契约才算「改接口」。改之前先搜一遍哪些下游在取这些字段。

七、动手 Demo:结束节点:输出不声明,下游接不住

同一份内容准备两个版本:一个声明了三个字段,一个就是一整串字。 再让下游分别去取 text、img、title,看两边结果。

APPLE  = {u'text': 文案, u'img': u'https://x/1.png', u'title': 标题}
STRING = 文案 + u' ' + u'https://x/1.png'      # 没声明:一整串

def take(out, field):
    if isinstance(out, dict):
        return out.get(field, u'(没有这个字段)')
    return u'(是一整串,取不出 %s)' % field

实跑输出:

--------------------------------------------------------------------
结束节点:输出不声明,下游接不住
--------------------------------------------------------------------


  ① 两种输出形态
  --------------------------------------------------------------------
  声明的:一个对象,三个字段——text、img、title。
    text = AI 眼镜销量翻倍……
    img = https://x/1.png
    title = AI 眼镜卖爆了
  没声明的:一整串 27 字。

  ② 下游取字段
  --------------------------------------------------------------------

| 要的字段 | 声明了 | 没声明 |
|---|---|---|
| text | AI 眼镜销量翻倍…… | (是一整串,取不出 text) |
| img | https://x/1.png | (是一整串,取不出 img) |
| title | AI 眼镜卖爆了 | (是一整串,取不出 title) |

  声明了三个字段都能取到;没声明的三个全取不出——它就是一串字,没有结构。

  ③ 没声明时会怎么坏
  --------------------------------------------------------------------
  最轻的坏法:下游拼出一句「(是一整串,取不出 img)」这种缺角的文案。
  最重的坏法:卡片节点的占位一个都填不上,渲染出一张空卡。
  而且它不报错。 链是通的,日志是绿的。

  ④ 结束节点该声明什么
  --------------------------------------------------------------------
  一、每个字段一个名字,名字用英文或拼音,别用中文(下游引用要拼)。
  二、每个字段一个类型:文本、图片地址、数字、布尔。
  三、只声明下游真要用的那几个。 声明十个字段,下游只用两个,剩下八个是维护负担。

  ⑤ 一条对照
  --------------------------------------------------------------------

| 场景 | 要声明的字段 |
|---|---|
| 发到公众号 | title、text、img |
| 发到小红书 | title、text、img、tags |
| 只回一句话 | text |

  同一张工作流要发三个平台,就在结束节点声明三套,用选择器挑。别为每个平台复制一份工作流。
  ! 结束节点是整条链的输出契约。契约不写清,下游全靠猜。
  这一条和第 7.2 节「字段要定清楚」是同一个道理,只是一个在表里,一个在节点上。

①第一段声明过的:一个对象三个字段,每个都能单独取。 ②第二张表三行对照。声明了三个都能取到;没声明的三个全取不出——它没有结构。 ③第三段讲坏法:最轻是缺角文案,最重是空卡,中间是把整段文章塞进标题。 ④三种坏法的共同点:链是通的,日志是绿的。这是最难查的一类故障。 ⑤最后那段讲入参与出参的不对称:入参错会报错,出参错会静默。所以出参那侧要格外小心。

30 秒实验

  1. 打开你的结束节点,数一下声明了几个字段。超过五个的,砍到下游真用的那几个。
  2. 顺一遍下游:它取的那几个字段,结束节点里都有吗。
  3. 检查一下字段名有没有中文。有就改成英文或拼音,省得以后在代码节点里出编码问题。

常见误区

  1. 「输出是一段文字就够了。」下游要按字段取。不声明就是一大串,什么都取不出。
  2. 「字段多声明几个保险。」多一个字段就多一处要保证有值。声明十个用两个是负担。
  3. 「取不到会报错。」不会,返回空。链照跑、日志照绿,你得主动去看输出。
自测三问(点开对答案) 1. 结束节点的作用是什么? —— 输出契约:交出去几个字段、每个什么类型。不声明下游就取不出任何字段。 2. 为什么不声明不报错? —— 它输出的是一整串合法文字,没有「错」。只是没有结构,下游取字段时返回空。 3. 入参错和出参错有什么不对称? —— 入参错一般报错(喂的人知道),出参错一般静默(取的人也不知道)。所以出参要格外小心。

五个模块都装好了,下一节整条链跑一遍。要跑三种输入,不是一种。

相关笔记