🤖 第三章 应用实战:公众号创作智能助手
📄 一句话概括

这条流程只干一件事:把表里的人填的四个字段,拼成一段规范的话,送进 Agent 的输入框,然后记住【这一段对话是谁】。它简单,但它是整条流水线的入口——入口的脏数据,会在最后一步才暴露。

📝 本节和前面几节的关系

3.3 造好了 Agent,本节开始给它送活。它是 3.2 那张链路图里的第 ② 步。它必须与 3.4.2 配对理解:本节负责【开口说话】,3.4.2 负责【把话说完并听懂回答】。

一、先明确一件事:本章的 RPA 走哪条路

第二章的小红书没有接口,RPA 只能模仿人点界面。本章的公众号有接口——但请注意,本章要送进去的是【自定义 GPT】,不是公众号。

这是一个很容易混淆的点,先摆清楚:

环节 目标 有没有接口 RPA 怎么干
提交创作信息 自定义 GPT(本节的活) 没有对外接口 只能走浏览器界面
取回结果 同上 没有 走浏览器界面
排版 本地 不需要 跑代码
送进公众号 微信公众平台 有官方接口 调接口(3.4.4)
⚠️ 这条事实决定了本节的技术形态

自定义 GPT 没有给外部程序调用的接口——它只能在网页上用。所以要让它自动干活,RPA 必须走【浏览器自动化】这条路:打开网页、定位输入框、输入文字、点发送按钮。 界面自动化的稳定性天然不如接口(页面一改版就失效),所以本节把大量篇幅放在【防呆与预检】上——既然界面这一侧本来就脆,就要让送进去的东西尽可能干净。

二、什么叫【提交创作信息】

把表里的四列,按一个固定模板拼成一段话:

选题:{topic}
关键词:{keywords}
风格:{style}
目标字数:{words}

这四行就是【创作信息】的全部内容。 它对应 3.3.1 里指令中【# 输入】那一段——Agent 那边期待的输入格式,和 RPA 这里拼出来的格式,必须一字不差地对上。

表字段 拼成 约束
topic 选题: 后面 非空,建议 5~30 字
keywords 关键词: 后面 英文逗号分隔,2~5 个
style 风格: 后面 枚举(干货/科普/随笔/评论/故事)
words 目标字数: 后面 600~3000
📝 为什么要【拼模板】而不是【把表直接倒进去】

因为Agent 认的是格式,不是数据。你把一行 CSV 原样丢进去(001,玄关收纳,干货,1000),模型要靠猜才知道哪个是选题、哪个是字数——猜错一次,后面全错。 【拼模板】这个动作,本质上是把 RPA 的字段名【翻译】成 Agent 能看懂的自然语言。 这就是 1.6.1 讲的【两种东西说话要翻译】,只不过这里的翻译特别简单,就是四个标签。

三、提交的六步动作(浏览器自动化视角)

一条浏览器自动化的流程,拆开永远是这六步:

步 动作 常见失败 兜底
1 打开/切换到 Agent 页面 页面加载慢,元素还没出来就去找 等元素出现,不要等固定秒数
2 确保是在【新对话】状态 上一轮的内容还留在框里 每次提交前先点【新对话】
3 定位输入框 定位方式太脆弱(写了绝对坐标) 用元素属性定位,不要用坐标
4 输入文本 长文本输入慢、丢字符 输入后回读一遍校验
5 点发送 点了但没发出去(按钮未激活) 发送前确认按钮可用
6 记录会话标识 忘了记,3.4.2 找不到这段对话 立刻把标识写回表

第 1 步和第 3 步是界面自动化里 90% 的故障来源。 两条纪律值得刻在脑子里:

四、第 6 步是本节最容易被忽略的一步

提交完,必须立刻做一件事:把【这一段对话的标识】写回表里。

为什么要:因为下一步 3.4.2 要追着这段对话继续说。如果你只是【发了就完事】,那么下一次运行流程时,你不知道该接哪段对话——只能重新开一段,前面生成的提纲就白费了。

这个标识在表里新占一列(回到 3.2 的字段表,补上它):

字段 谁写 谁读 说明
conversation_ref 3.4.1 RPA 3.4.2 RPA 会话标识:可以是对话链接,也可以是浏览器里保存的会话句柄/标签页引用
⚠️ 界面自动化里的【会话状态】比接口调用难得多

调接口时,会话通常是服务端给的一个编号(一串字符),存下来就能续。但界面自动化没有这个编号——你能依赖的只有:一个还没关掉的浏览器标签页,或者对话列表里那一条的链接。 这意味着:流程必须是连续跑完的(提交 → 追问 → 取回),或者要把标签页/链接持久化下来。如果中间的流程会断开(比如等人审提纲),那就必须靠【对话链接】把状态存进表里。 这是本章最实操的一个坑,很多人在做多轮对话时卡在这里。

五、预检:把脏数据挡在门外

RPA 的第一条纪律:宁可停下,不要猜。 所以在提交之前,必须先做一遍预检。

预检查四件事:

检查项 不合格的样子 处理
选题非空 空白 阻断
关键词 2~5 个 1 个、或 6 个以上 阻断
字数在范围内 8 字、或 50000 字 阻断
风格在枚举内 写了【随便】 阻断

注意:预检不合格时,不是【猜一个默认值填上】,而是【停下来,把原因写进备注,把状态改回【待提交】】。 因为这一行数据最终会变成一篇公开发表的文章——入口处每一个被忽略的异常,都会变成篇内容上的一个错误。

六、动手 Demo:写一个预检器,并看它拦下三行坏数据

下面这段代码可以在任何 Python 环境里直接跑(不需要 RPA 平台)。它做的事,就是本节第五节的预检——在真正提交之前,把不合格的行拦下来。

# -*- coding: utf-8 -*-
"""3.4.1 Demo:创作信息组装与预检"""
rows = [
    {"id": "001", "topic": "我家玄关收纳的三件东西", "keywords": "玄关收纳,小户型,收纳好物",
     "style": "干货", "words": "1000"},
    {"id": "002", "topic": "秋季养生的三个误区", "keywords": "秋季养生,作息",
     "style": "科普", "words": "1200"},
    {"id": "003", "topic": "", "keywords": "职场沟通", "style": "干货", "words": "900"},       # 缺选题
    {"id": "004", "topic": "AI 帮我写周报", "keywords": "AI,效率", "style": "干货", "words": "8"},  # 字数越界
    {"id": "005", "topic": "远程办公两年记", "keywords": "远程办公,效率,协作,心态,复盘,时间管理",
     "style": "随笔", "words": "1500"},  # 关键词过多
]

TEMPLATE = """选题:{topic}
关键词:{keywords}
风格:{style}
目标字数:{words}"""


def check(row):
    problems = []
    if not row["topic"].strip():
        problems.append("选题为空")
    kws = [k.strip() for k in row["keywords"].split(",") if k.strip()]
    if not (2 <= len(kws) <= 5):
        problems.append("关键词应为 2~5 个,当前 %d 个" % len(kws))
    try:
        w = int(row["words"])
        if not (600 <= w <= 3000):
            problems.append("目标字数应在 600~3000,当前 %d" % w)
    except ValueError:
        problems.append("字数不是数字")
    if row["style"] not in ("干货", "科普", "随笔", "评论", "故事"):
        problems.append("风格不在枚举内:%s" % row["style"])
    return problems


for row in rows:
    problems = check(row)
    if problems:
        print("[阻断] id=%s  %s" % (row["id"], "/".join(problems)))
    else:
        prompt = TEMPLATE.format(**row)
        print("[通过] id=%s  拼好的 prompt 长度=%d 字" % (row["id"], len(prompt)))

实际运行输出(真跑,不是示意):

==============================================================
创作信息预检报告
==============================================================
[通过] id=001  拼好的 prompt 长度=48 字
[通过] id=002  拼好的 prompt 长度=40 字
[阻断] id=003  选题为空/关键词应为 2~5 个,当前 1 个
[阻断] id=004  目标字数应在 600~3000,当前 8
[阻断] id=005  关键词应为 2~5 个,当前 6 个
--------------------------------------------------------------
通过 2 行,阻断 3 行

=== id=001 实际提交的文本 ===
选题:我家玄关收纳的三件东西
关键词:玄关收纳,小户型,收纳好物
风格:干货
目标字数:1000

=== 阻断行不会进入提交流程,状态改回【待提交】并写备注 ===
  id=003  note=选题为空/关键词应为 2~5 个,当前 1 个
  id=004  note=目标字数应在 600~3000,当前 8
  id=005  note=关键词应为 2~5 个,当前 6 个

读结果,三个值得注意的地方:

  1. id=003 一次报了两个问题(选题为空 + 关键词只有 1 个)——这说明预检要把所有问题一次报全,而不是发现一个就退出。否则人改一轮、再跑一轮、又发现一个问题,来回折腾;
  2. id=005 的六个关键词只超了一个——边界上的错最容易被忽略,所以约束必须写成可判定的数字(2~5),而不是【别太多】;
  3. 通过的行只打印了 prompt 长度——真正的流程里,这里会接着执行【写入输入框 → 点发送 → 记录会话标识】。打印长度只是一个占位动作,用来确认拼装正确。

七、⚙️ 2026 现状:扣子有 API,GPT 没有

自定义 GPT(教材原方案) 扣子(替代方案)
外部程序能不能直接调用 不能(只能网页操作) 可以(可发布为 API/通过工作流调用)
RPA 走哪条路 浏览器界面自动化 可以直接调接口
稳定性 脆(页面一变就失效) 稳(接口相对稳定)

如果你用扣子替代,本节的技术形态会大幅简化:不用打开网页、不用定位输入框,直接把拼好的四个字段当参数调接口,返回的就是结果。本节第四节的【会话标识难题】也随之消失——接口会给你一个明确的会话字段。

📝 但本节讲的东西一样都不白学

预检、模板拼装、防呆、状态回写——这四样在任何方案里都要做,而且它们才是本节真正的价值。 【界面还是接口】只是传输方式;【送进去的东西干不干净】才决定流水线的成败。 用接口也一样要把脏数据挡在门外。

30 秒实验

看这四行,说说那一行会被预检直接阻断(不看上面的代码,凭你的判断):

A  选题:我家厨房收纳   关键词:厨房收纳   风格:干货   目标字数:900
B  选题:远程办公两年记  关键词:远程办公,效率,协作   风格:随笔   目标字数:1500
C  选题:秋季养生      关键词:养生,作息,饮食,运动,睡眠,心态   风格:科普   目标字数:1200
D  选题:装修避坑      关键词:装修,避坑   风格:随便   目标字数:1100

答案:A、C、D 三行都会被阻断。

只有 B 是合格的。

结论:看起来【差不多能用】的数据,往往过不了预检。 而这恰恰是好事——这四行如果直接送进 Agent,你会得到四篇【风格不明、字数不对、关键词乱塞】的稿子,然后在最后一步才发现问题。

常见误区

  1. 【表里的数据是我自己填的,不会有问题,不用预检】——错。 恰恰是自己填的最容易出错(复制粘贴串行、字数忘改、关键词多打一个)。预检不是防别人,是防自己。
  2. 【预检发现一个问题就退出,让人改完再跑】——错。 要把所有问题一次报全(示例里的 id=003 就是两个问题一起报的),否则会陷入【改一轮、跑一轮】的反复。
  3. 【输入框里打完字就完事,不用回读】——错。 界面自动化会丢字符(尤其长文本)。输入后回读一遍再发送,成本很低,能挡掉一类最隐蔽的错误。
  4. 【忘了记录会话标识,下次重新开一段就行】——错。 重新开一段意味着前面的提纲和对话全白费,而且多轮对话的口径会断裂(模型不记得上一轮说过什么)。提交后立刻回写标识,这是本节最容易被漏掉的一步。
  5. 【用【等待 3 秒】比用【等元素出现】简单,反正够用】——错。 固定等待在开发机上永远够用,在别的机器上永远不够。等元素出现这个写法,是界面自动化的基本素养。
自测三问(点开对答案) 1. **为什么本章的 RPA 提交创作信息要【拼一段模板文字】,而不是把表格行直接扔进去?** 因为**Agent 认的是格式,不是数据**。原样丢进去,模型要靠猜才知道哪个是选题、哪个是字数,**猜错一次后面全错**。拼模板这个动作,本质上是**把 RPA 的字段名翻译成 Agent 能看懂的自然语言**,让两边的接口一字不差地对上。 2. **界面自动化里【会话标识】为什么比接口调用难处理?** 因为**调接口时会话通常是服务端给的一个编号**,存下来就能续;而**界面自动化没有这个编号**,能依赖的只有一个还开着的标签页,或对话列表里的那条链接。所以流程要么**连续跑完**,要么**必须把对话链接持久化进表里**。这也是本节在 3.2 字段表之外**额外补了 `conversation_ref` 一列**的原因。 3. **预检不合格时,为什么是【停下并把原因写进备注】而不是【填一个默认值往下走】?** 因为这一行数据**最终会变成一篇公开发表的文章**。进口处任何一个被悄悄补上的默认值,都会变成文章里的一个错误,**而且到发布那一刻才会被发现**(那时已经晚了)。**宁可停下,不要猜**——这既是本节的纪律,也是第二章一路延续下来的同一条纪律。

相关笔记