AI Tools

Agentic 内容刷新:n8n + ChatGPT 自动找出、更新、重新发布衰退中的旧文

Agentic 内容刷新:n8n + ChatGPT 自动找出、更新、重新发布衰退中的旧文
目录

这个 Agent 第一次自己发了一篇我没读过的文章,我连续刷新了 14 次页面,等着它哪里崩掉。没崩。那是一篇 1,400 字的 GA4 事件跟踪指南,从三月起就没人动过,排名 14,每月 2,800 次曝光。Agent 周一早上发现它,从实时 SERP(Search Engine Results Page,搜索引擎结果页)里生成了新引言和一块新的 FAQ,对比了字数确认没变薄,然后上午 8:47 把更新推到了 WordPress 草稿箱。周二索引重建。周五排名 9。我三个月没打开过那篇稿子。

这就是这个语境下"agentic"的意思,它和今年早些时候我写的那篇"内容刷新冲刺"不是一回事。冲刺是人工节奏的 200 篇两个周末跑完,三道数据关卡,有意压住节奏避开 Helpful Content 重评。Agentic 刷新是更小、持续运行的版本:系统自己找衰退文章、自己判断哪些值得刷新、自己起草、自己检查、自己发布。人在队列层面把关,不在每一篇上把关。在一个 1,200 篇的档案库上跑了八周,Agent 发了 73 次刷新,2 篇回滚,1 次是 Agent 的锅,1 次是我的锅。

下面是完整搭建——n8n(一个公平代码协议的工作流自动化工具)工作流、三段 ChatGPT(OpenAI 出品的大语言模型)提示词、四道校验门、真实踩过的三种失败模式。

Agent 做了什么——以及它故意没做什么

整个工作流是一张 n8n 画布上的 12 个节点。Cron 触发、自己找衰退文章、自己起草更新、自己校验、回写到追踪表。常规情况下没有人介入。人才会看到结果。

# 阶段 职责 是否需要人
1 拉取 读 GSC(Google Search Console,谷歌站长工具)过去 90 天页面级数据
2 打分 计算排名变化、CTR(Click-Through Rate,点击率)相对预期偏差、距发布天数
3 过滤 只留"在衰退 + 可恢复"的行(曝光≥200、排名 9-25、正在下滑或 CTR 偏低)
4 简报 ChatGPT 把指标 + 实时抓回来的页面片段变成刷新简报
5 起草 ChatGPT 写新引言、FAQ 块、更新数据段
6 校验 四道门:字数、引用真实性、内部链接不失效、不变薄
7 发布 通过则 PATCH 到 WordPress;不通过则写入"needs human"表 偶尔
8 追踪 把每次运行记录到 Google 表,含改前/改后指标和 diff 大小
9 通知 每天上午 9:00 一条 Slack 汇总,含当天的刷新 是(只读)

真正重要的边界在第 5 步和第 6 步之间。Agent 。Agent 不会没校验就发。草稿和 CMS 之间立着四道校验门,任何一道不过,文章都路由到人的队列而不是线上系统。这套机制能在 1,200 篇档案库上让我放心跑的原因,是 Agent 允许改动,但不允许未校验的改动。

Agent 故意不做的事:不改 URL、slug、title tag、meta description。这些字段赌注太大,无人值守的循环里不能让模型碰。刷新只动 body,只动 body。Slug、canonical(告诉 Google 哪个 URL 是"主版本"的标记)和 meta 都不动,除非人显式批准。

准备工作

工作流真正干任何有用的事之前,有六样东西要先接好:

  • n8n Cloud($24/月 Starter 套餐够用)或自托管(Docker 镜像 90 秒起)
  • OpenAI API Key(开通 GPT-4o 或 GPT-4o-mini 访问),在 n8n 里配成凭证——GPT-4o-mini 是主力;GPT-4o 只在简报阶段用
  • GSC API 访问到已验证站点(只读搜索分析数据)
  • WordPress 站点(REST API 开启,配一个 Application Password——WP 原生机制,用一个独立密码授权 REST 调用而不暴露真实密码)——任何暴露 PATCH 端点的 CMS 都通用
  • Google 表格一张,命名 Refresh Queue,含工作流要写入的列
  • Slack Incoming Webhook(或 Slack OAuth 凭证),指向接收每日汇总的频道

如果你的 CMS(Content Management System,文章实际住的后台)不是 WordPress,变的只有 PATCH 节点。Notion、Ghost、Webflow、Contentful 全都有基于 HTTP 的更新端点,能套同一套模式。Ghost 适配器我已经在客户那里生产环境跑过。四道校验门跟 CMS 无关。

Step 1 — Cron 触发 + 拉 GSC

触发器是一个 Schedule Trigger 节点,配为本地时间每天 07:30 触发。我选 07:30 是因为汇总要在我开电脑之前到位;前一晚 23:00 触发也可以。第一个动作是一个 HTTP Request 节点,调用 GSC 的 Search Analytics API:

GET https://www.googleapis.com/webmasters/v3/sites/{siteUrl}/searchAnalytics

参数:startDateendDate 设为最近 90 天,dimensions[] 设为 pagerowLimit 封顶 5,000,dataState: "final"。返回结果是每个 URL 一行,含 clicks、impressions、CTR、平均排名。5,000 的上限和审计 Agent 里用的是同一个——超过这个数的几乎都是 tag/分类归档页,刷新 Agent 不该去追它们。

结果塞进工作流状态的 gscPages 字段,进入下一步循环。

Step 2 — 给每个 URL 打分

一个 Code 节点,一遍跑完,~40 行 JavaScript。对每行我算:

  • positionDelta——本期排名 vs 上一个 90 天(正数=在下滑)
  • ctrVsExpected——实际 CTR vs 按位置加权的预期基准(#9 名理论上该拿 ~3.5% CTR,#16 该拿 ~1.5%)
  • daysSincePublish——从 WP REST API 的 date 字段拉
  • daysSinceLastModified——同一个 API 调用的 modified 字段
  • decayScore——四项的综合分,公式 positionDelta * 0.4 + ctrDeficit * 0.3 + daysSinceModified * 0.003

decay score 是真正起决定性作用的那一项。一篇 90 天里掉了 6 个排名、400 天没动过的文章,是真在快速衰退。一篇掉了 2 个排名、上个月刚编辑过的,不是——哪怕绝对数字看起来差不多。Code 节点的职责就是确保只有前一类文章能进 ChatGPT 的门。

Step 3 — "在衰退 + 可恢复"过滤

Filter 节点是控制成本最关键的一刀。我只保留同时满足以下条件的行:

  • impressions >= 200(过去 90 天)
  • position >= 9position <= 25
  • positionDelta >= 2(下滑 ≥ 2 位) ctrVsExpected <= 0.5(不到该位置应有 CTR 的一半)
  • daysSinceLastModified >= 120
  • decayScore >= 4

这把 1,000-5,000 行的数据集砍到每天 5-15 个候选。200 曝光的下限把 tag 页和单篇博文挡在刷新队列之外。120 天的陈旧下限把刚编辑过的文章挡在外面——再刷一篇刚刷过的文章,会产生一种 Google 能识别为自动化操纵的"新鲜度信号模式"。这一条是我在第三周用真金白银学到的。

Step 4 — ChatGPT 写刷新简报

第一次 LLM(Large Language Model,大语言模型)调用。喂给 ChatGPT 的输入是 URL、标题、四个算好的指标,以及从实时页面抓回来的 1,500 字片段。System prompt 短而具体:

You are a senior SEO editor writing a refresh brief for a single decaying post.

Inputs you will receive:
- URL, title, current position, 90-day position delta, CTR vs expected,
  days since last modified, days since publish
- A 1,500-character snippet of the current post body

Your job: produce a brief that a separate writer model will use to draft
the update. The brief should specify:
1. Which 2-3 sections need new stats or examples
2. The current People Also Ask questions the writer should answer in a new FAQ
3. The target word count (must be ≥ original word count; never thinner)
4. The 3 internal links the writer should add or refresh
5. A one-sentence "why this post is decaying" diagnosis

Output a JSON object with exactly these keys:
{ "diagnosis": string, "sectionsToUpdate": [string],
  "faqQuestions": [string], "targetWordCount": number,
  "internalLinksToRefresh": [string] }

Rules:
- Never invent URLs, stats, or author names. Reference live data only.
- If you cannot identify a clear decay cause, return diagnosis="UNCLEAR"
- Be specific. "Update stats" is not a section. "Replace 2022 HubSpot
  benchmark with 2024-2025 data" is.

UNCLEAR 逃生口很关键。大约每 8 个候选里会有 1 个拿到不清晰的诊断——通常是那种"话题本身在死"而不是"稿子本身差"的衰退。这类不进入起草阶段,直接去"needs human"表。硬塞进去会让 ChatGPT 重写一篇"压根没人会再搜"的稿子。

这一阶段我用 gpt-4o,第 5、6 阶段用 gpt-4o-mini。简报是唯一真正考验推理质量的地方。简报烂,下游起草就烂;起草烂,是代价最高的失败模式。

Step 5 — ChatGPT 写实际更新

第二次 LLM 调用。输入是第 4 阶段的简报加整篇正文。输出是一个字段 bodyMarkdown,工作流把它 PATCH 到 WordPress。System prompt:

You are refreshing an existing blog post. You will receive the full
original body and a refresh brief.

Your job: produce a NEW version of the body that:
- Preserves the original's voice, structure, and section ordering
- Updates stats and examples per the brief
- Inserts the new FAQ block in the right place (end of post, before conclusion)
- Adds the internal links the brief specifies
- Meets or exceeds the target word count from the brief

Output a JSON object with exactly:
{ "bodyMarkdown": string, "newWordCount": number,
  "sectionsChanged": [string], "linksAdded": [string] }

Rules:
- Never make the post shorter than the original. If you cannot hit the
  target without padding, return newWordCount=0 and sectionsChanged=[].
- Never invent facts. If a stat is needed and you don't have a source,
  write [SOURCE NEEDED] in the body and the human will fill it in.
- Never add new external links. Only refresh the existing internal ones
  the brief specified.
- Preserve all existing 

and

tags exactly.

"不准变薄"这条规则和 [SOURCE NEEDED] 标记,是救我最多的两段提示工程。前者防止生成缩水版刷新。后者防止 Agent 在自己其实不知道出处的时候编一个——第 6 步的校验门会捕获所有 [SOURCE NEEDED] 标记,把稿子路由到人工队列。

Step 6 — 四道校验门

这是"agentic 内容刷新"那些吹捧文永远跳过的部分。一个能写刷新的模型,也能写一篇比原版更差的刷新,或者带事实错误的刷新,或者丢了一个本来在带流量的内链的刷新。草稿和 CMS 之间立着四道门。

门 1——字数检查。 Code 节点对比 newWordCount 和原版。新文比原文短就失败。在目标的 5% 之内就过。超目标 30% 以上就失败(失控变长是写手最常见的失败)。

门 2——SOURCE NEEDED 扫描。 用一条正则扫 body。任何匹配都失败。文章路由到人工队列,写手已经明确标好了哪一句需要引用,人 30 秒就能填上。

门 3——内部链接完整性。 一个小型 Code 节点抽出原文里所有内链 URL。逐条发 HEAD 请求(只返回响应状态码的轻量检查,比 GET 快得多)。任何 404 都失败。文章进人工队列,附一份失效链接清单。Agent 不会静默丢弃失效链接——丢一个链接比不刷新代价更大。

门 4——新增内部链接校验。 写手返回的 linksAdded 数组对照实时 sitemap 抓取核对。每条新加的内链都必须能解析。Agent 不允许往一个根本不存在的 URL 上加链接。大约每 30 篇草稿里会有 1 篇栽在这一关——写手编了一个看起来合理的 /blog/... 路径但其实从没发过。

四道门全过的草稿就 PATCH 上去。任何一道不过,就追加到同一张 Google 表的 Needs Human tab 里,附具体失败原因。73 篇刷新里,校验门拦下了 9 篇,其中 7 篇是真抓到了问题——缩水草稿、编造的数据、失效链接。

Step 7 — PATCH WordPress + 记日志

PATCH 节点打到 WordPress REST API:

POST https://{site}/wp-json/wp/v2/posts/{id}
Authorization: Basic 
Content-Type: application/json

Body 是 {"content": "<newBodyMarkdown>"}。文章留在 draft 状态——WordPress 不会自动发布,人(我)下次进 WP 后台时点发布按钮。这是故意的:Agent 允许写 body,但不允许翻已发布文章的状态字段。

写到追踪表的那一行含:URL、decay score、改前/改后排名、改动的章节、新增的链接、使用的模型、token 成本,以及 published_at 时间戳(人为发布时填)。73 篇刷新的中位"从 Agent 写到人发布"时长是 18 小时。拖这么久基本只是因为我一天没打开 WP。

Step 8 — 每日 Slack 汇总

每天上午 9:00 一条 Slack 消息,列过去 24 小时的所有刷新:

:arrows_counterclockwise: *一夜之间刷新 3 篇*
Decay 分数阈值:4.0 · 模型:gpt-4o-mini · 总成本:$0.11

• `/blog/ga4-event-tracking-guide/` — 排名 14 → ?, decay 6.2
  3 个章节更新,新增 2 个链接。[WP 草稿]
• `/blog/email-deliverability-2024/` — 排名 11 → ?, decay 5.4
  1 个数据更新,0 个链接新增。[WP 草稿]
• `/blog/looker-studio-templates/` — 排名 17 → ?, decay 4.3
  新增 FAQ 块,新增 3 个链接。[WP 草稿]

:warning: 1 篇在 `Needs Human` 队列:`/blog/...`
门 2 失败——引言段出现 [SOURCE NEEDED] 标记。

"排名 → ?"是我觉得最有用的部分。改前数字来自 GSC。改后数字由第二天早上的 GSC 拉取填上——那时候才有足够数据记一次变动。我正在追踪表里慢慢攒一个六周视图,画每篇刷新稿的排名曲线。模式是:重新索引期间排名先持平 7-10 天,之后 3 周爬升 1-4 位。前面提到的那 2 篇回滚,都是先涨又跌回去的——一次是 Agent 真把一个章节标题改坏了,一次是我同一天合并了两篇相似文章把索引器搞晕了。

八周里真实坏过的事

三个生产经验,文档里都没有。

第一版在循环里反复刷同一篇文章。 decay score 里有个 bug——daysSinceLastModified 读的是一份不会在 WP 保存时重写 modified 字段的旧缓存。Agent 刷一篇稿,缓存里这个字段不更新,第二天的运行还把它当成"陈旧",Agent 又刷一遍。我发现的时候,三篇稿子在 9 天里被各编辑了 5 次。修法是在 WP 节点加一行缓存失效,再加一条硬规则:一篇稿子 90 天内只能刷一次,在 Filter 里强制执行。规则才是真正的安全网;缓存修复只是善后。

简报阶段有时诊断出一个起草阶段修不了的问题。 当衰退原因是"话题本身在褪色"(Google Trends 是判据——搜索量曲线 18 个月跌了 60%),简报返回 diagnosis="topic_is_dying"。如果放行,起草阶段会产出一篇完美的更新——更新到一篇根本没人会再读的文章上。修法是简报 prompt 里的 UNCLEAR 逃生口,加 Filter 里一条显式检查:diagnosis == "topic_is_dying" 就路由给人工。人看一眼 Google Trends,决定要重写、转向还是 410(一种状态码,告诉 Google 永久从索引里移除该页面)。Agent 不被允许自行下线一篇文章。

GSC 的 dataState: "final" 滞后 3 天。 第一个月我一直用默认设置。Agent 刷新的依据是不含最近 72 小时点击的数据,其中有两次导致去刷新一篇其实正在自己恢复的稿子。修法是 dataState: "all",加一个小型 Code 节点去重 finalunfinalized 数据。3 天滞后也是为什么 cron 触发是 07:30 而不是 06:00——07:30 的时候,前一天的 final 数据通常已经落定。

这套东西不该用在哪

Agent 不是刷新冲刺的替代品,也不是人工编辑的替代品。它是一个分诊和执行层,专门处理"模型能看见的指标在衰退"的文章。三种情况不该用:

  • **挂营收的稿子。**定价页、带联盟链接的对比稿、带具名客户的案例研究。一次坏刷新的代价太高,简报阶段又不被允许知道营收。
  • **强声音的细分领域。**思想领袖、创始人随笔、设计哲学。Agent 能"保留"声音,但"保留"≠"捕捉"。这种稿子每次都需要人。
  • **Agent 评估不了的稿子。**一篇衰退是因为站点信息架构变了、是因为竞品出了更好的版本、是因为公司重新定位了。简报返回 UNCLEAR,稿子进人工队列,正解很少是"刷新 body"。

老实账

八周。发了 73 篇刷新。校验门在 9 篇进 CMS 之前就拦下来了。发布后 2 次回滚。30 天后测量,中位排名改善:+2.7 位(统计的是那些实际动了的稿子)。OpenAI 总花费:$9.40 跑完全程。n8n 总执行次数:56(每天一次,加上 API 抖动的重试)。

Agent 最擅长的事不是写。它擅长的是记住。刷新队列本身是一份"哪些稿子在衰退、上次什么时候动的、Agent 觉得原因是什么"的活档案。半年的每日运行会攒成一份站点自己的内容策略文档,格式跟 Agent 已经用的那种一致。这才是真正的回报——不是单篇刷新,是让下一次 200 篇冲刺规划更快的审计轨迹。

如果你要搭,先做 Filter,不是提示词。先把 decay score 算对。Filter 好的话,LLM 阶段中等水平你也能看到效果。Filter 烂的话,LLM 阶段会刷一堆不需要刷的稿子,你所有时间都花在回滚上。

Agent 自己抓出的第一篇稿子,就是你会再错过一季度的那一篇。我每周跑都是这个规律。