跳到主要内容
IM智引科技

研究 / 外贸与 B2B 增长

AI Skill:pSEO 场景页批量生成 Prompt 模板

第 29 篇给了批量生成的脚本,这篇解决它的核心问题:如何让 50 个同结构页面不变成 50 篇换词的复读机。给出分层差异化的提示词模板、重复度自动检测脚本,以及批次质量门槛。

BLKTECH 编辑部2026年8月4日13 分钟难度 实战低成本Node.jsClaudeAI Agent

防止批量页面同质化的三个手段:数据层差异化(每个场景的 challenges/standards 必须真实不同)、提示词层强制引用具体数据(禁止通用描述)、生成后跑重复度检测(shingle 算法,任意两页相似度需 < 40%)。超标的页面重新生成或合并。

AI Skill:pSEO 场景页批量生成 Prompt 模板

批量生成的真实风险

第 29 篇给了完整的批量生成脚本。但脚本能跑通不代表页面能被收录。

最常见的失败模式:50 个页面生成出来,内容结构一样、论述方式一样,只是把 “chemical transfer” 换成 “water treatment”。Google 的 Helpful Content 系统会把这批页面整体判为低价值,结果是大量 Crawled - currently not indexed

这篇解决的就是:如何让批量生成的页面各自有实质差异


一、三层差异化机制

差异化不能只靠提示词,要从数据层就开始。

层一:数据层差异化(最根本)

第 28 篇设计的 applications.yaml,每个场景必须有真实不同的技术细节。

反面例子(会导致同质化)

- id: chemical_transfer
  challenges:
    - "需要耐腐蚀"
    - "需要可靠密封"
    - "需要符合标准"

- id: water_treatment
  challenges:
    - "需要耐腐蚀"
    - "需要可靠密封"
    - "需要符合标准"

这两组 challenges 实质相同,AI 生成的内容必然雷同。

正面例子

- id: chemical_transfer
  challenges:
    - "Corrosion resistance across pH 1–13 media range"
    - "Zero-leakage requirement for hazardous chemical containment"
    - "ATEX Zone 1/2 compliance for explosive atmosphere"
  keySelectionCriteria:
    - parameter: "Casing Material"
      recommendation: "SS316 (pH 2–12) / Hastelloy C-276 (strong acids) / PVDF (H₂SO₄ >70%)"
  industryStandards: ["API 685", "NACE MR0175", "ATEX 2014/34/EU"]

- id: water_treatment
  challenges:
    - "High flow rates (50–500 m³/h) at relatively low head"
    - "Energy efficiency for 24/7 continuous operation"
    - "Chloramine resistance in disinfected water systems"
  keySelectionCriteria:
    - parameter: "Motor Efficiency"
      recommendation: "IE3 minimum; IE4/IE5 for >4000 annual operating hours"
  industryStandards: ["NSF/ANSI 61", "ISO 9906", "EN 733"]

数据层不同,生成的内容自然不同。数据准备的投入决定批量生成的质量上限。

层二:提示词层强制引用具体数据

在提示词里明确禁止通用描述,强制引用数据文件里的具体值。

层三:生成后重复度检测

用脚本量化检测,超标的重新生成。


二、分层提示词模板

按内容段落分层给约束,而不是一个笼统的“写一篇文章”。

# pSEO 场景页生成提示词模板

## 第一部分:注册表规格(不可违反的硬约束)

URL: {page_slug}
页面类型: cluster-app
搜索意图: engineering
PKW(H1 和 Title 必须包含): {product_name} for {application_name}
SKW(至少 2 个 H2 自然包含):
  - {product_slug} {application_slug} selection
  - best {product_slug} for {application_slug}
NKW(严禁出现,含语义等同表达):
  manufacturer, supplier, OEM, buy, price, quote,
  what is {product_slug}, how does pump work,
  {其他场景的核心词,避免横向抢词}
目标地区: {target_locale}

## 第二部分:可用数据(必须全部用到,不得编造额外数据)

产品信息:
- 名称:{product.name}
- 核心优势:{product.keyAdvantages}
- 不适用场景:{product.notSuitableFor}

场景信息:
- 场景全称:{app.nameFull}
- 所属行业:{app.industry}
- 技术挑战(必须逐条展开,不得概括):
  {app.challenges}
- 选型参数(必须做成 HTML 表格,逐行呈现):
  {app.keySelectionCriteria}
- 行业标准(必须至少引用 2 个,标注在相关段落):
  {app.industryStandards}

## 第三部分:分段写作指令

### 段落 1:场景挑战(100–150 词)
要求:
- 逐条展开上方 challenges 中的每一项
- 每条必须给出**为什么**这是挑战(工程原理层面),
  不要只重述现象
- 严禁使用以下通用句式:
  ❌ "This application requires reliable pumps"
  ❌ "Quality is important in this industry"
  ❌ "Selecting the right pump is crucial"
- 必须包含至少 1 个具体数值(来自 challenges 或 criteria)

### 段落 2:为什么选此泵型(100–150 词)
要求:
- 结合 product.keyAdvantages 说明适配性
- 必须提及 product.notSuitableFor 中与本场景相关的限制,
  并给出替代方案建议(这一点最容易被跳过,但它是
  专业性的体现)
- 引用至少 1 个具体参数支撑论述

### 段落 3:选型标准表(HTML table)
要求:
- 使用原生 <table>,包含 <caption>
- caption 格式:Key Selection Criteria: {PKW}
- 三列:Parameter / Recommended Specification / Engineering Rationale
- 第三列必须解释**为什么**,不能重复第二列内容
- 逐行对应 keySelectionCriteria,不增不减

### 段落 4:合规要求(80–120 词)
要求:
- 按地区分别说明(欧洲 / 北美 / 全球标准)
- 每个标准必须给出编号和适用条件
- 不要只列标准名,要说明"什么情况下强制要求"

### 段落 5:推荐型号(卡片形式)
要求:
- 2–3 个型号,每个给出针对本场景的核心参数(不是全部参数)
- 每个型号说明 1–2 条针对本场景的优势
- 内链锚文本使用型号名
- 使用提供的型号列表:{recommended_models}

### 段落 6:FAQ(3–5 条)
要求:
- 每条用 ### 标题,疑问句
- 答案首句给结论 + 具体数值,且包含主体名称
  (不用 it / this / 该产品 指代)
- 至少 2 条引用行业标准
- 每条答案 80–150 词
- 问题必须针对本场景的**具体技术疑问**
  不要问通用问题(如 "How do I choose a pump?")

## 第四部分:全局格式要求

- 所有参数给双单位:公制 (英制)
- 语言:{locale} 英语(美式或英式,按 target_locale)
- 禁用词:world-class, leading, best, top-quality,
  cutting-edge, one-stop, professional manufacturer
- 不要写 About Us 式的公司介绍段落
- 不要在正文写商业 CTA(CTA 由模板统一处理)

## 第五部分:输出格式

只输出 Markdown 正文,不包含 frontmatter。
从段落 1 开始,不要写引言或总结性开场白。

三、重复度检测脚本

生成后必须量化检测。用 shingle(词组切片)算法计算任意两个页面的相似度。

// scripts/pseo-similarity.mjs
import fs from 'fs/promises';
import path from 'path';

const DIR = 'src/content/applications';
const SHINGLE_SIZE = 5;        // 5 词一组
const THRESHOLD = 0.40;        // 相似度上限 40%

// 提取正文(去掉 frontmatter 和 HTML 标签)
function extractText(md) {
  return md
    .replace(/^---[\s\S]*?---/, '')      // 去 frontmatter
    .replace(/<[^>]+>/g, ' ')            // 去 HTML 标签
    .replace(/[#*`\[\](/zh/)]/g, ' ')        // 去 Markdown 符号
    .replace(/\s+/g, ' ')
    .toLowerCase()
    .trim();
}

// 生成 shingle 集合
function shingles(text, size = SHINGLE_SIZE) {
  const words = text.split(' ').filter(Boolean);
  const set = new Set();
  for (let i = 0; i <= words.length - size; i++) {
    set.add(words.slice(i, i + size).join(' '));
  }
  return set;
}

// Jaccard 相似度
function jaccard(a, b) {
  let intersection = 0;
  for (const s of a) if (b.has(s)) intersection++;
  const union = a.size + b.size - intersection;
  return union === 0 ? 0 : intersection / union;
}

// 读取所有生成的页面
const files = (await fs.readdir(DIR)).filter(f => f.endsWith('.md'));
const docs = [];
for (const file of files) {
  const md = await fs.readFile(path.join(DIR, file), 'utf8');
  const text = extractText(md);
  docs.push({
    file,
    wordCount: text.split(' ').length,
    shingles: shingles(text),
  });
}

// 两两比对
const pairs = [];
for (let i = 0; i < docs.length; i++) {
  for (let j = i + 1; j < docs.length; j++) {
    const sim = jaccard(docs[i].shingles, docs[j].shingles);
    if (sim >= THRESHOLD) {
      pairs.push({
        fileA: docs[i].file,
        fileB: docs[j].file,
        similarity: (sim * 100).toFixed(1) + '%',
        raw: sim,
      });
    }
  }
}

pairs.sort((a, b) => b.raw - a.raw);

// 找出"高相似度中心"——与多个页面都相似的页面(最需要重写)
const offenderCount = new Map();
for (const p of pairs) {
  offenderCount.set(p.fileA, (offenderCount.get(p.fileA) ?? 0) + 1);
  offenderCount.set(p.fileB, (offenderCount.get(p.fileB) ?? 0) + 1);
}
const topOffenders = [...offenderCount.entries()]
  .sort((a, b) => b[1] - a[1])
  .slice(0, 10)
  .map(([file, count]) => ({ file, similarPairCount: count }));

// 字数异常检测
const wordCounts = docs.map(d => d.wordCount);
const avgWords = wordCounts.reduce((a, b) => a + b, 0) / wordCounts.length;
const tooShort = docs
  .filter(d => d.wordCount < avgWords * 0.6)
  .map(d => ({ file: d.file, wordCount: d.wordCount }));

console.log(JSON.stringify({
  summary: {
    totalPages: docs.length,
    avgWordCount: Math.round(avgWords),
    overThresholdPairs: pairs.length,
    threshold: (THRESHOLD * 100) + '%',
    verdict: pairs.length === 0 ? 'PASS' : 'NEEDS_REWRITE',
  },
  // 需要优先重写的页面
  topOffenders,
  // 具体的高相似对
  similarPairs: pairs.slice(0, 30),
  // 内容偏薄的页面
  tooShort,
}, null, 2));

process.exit(pairs.length > 0 ? 1 : 0);

阈值说明

相似度 判定 处理
< 30% 正常 通过
30–40% 偏高但可接受 观察,看 GSC 收录情况
40–60% 超标 重写相似度最高的一方
> 60% 严重 考虑合并成一个页面

为什么用 40% 作为门槛:同结构页面必然有一定重复(表格表头、FAQ 问句模式),30% 以下几乎不可能达到。40% 是“结构重复但内容有实质差异”的合理区间。


四、Skill 说明书

# Skill:pSEO 场景页批量生成

## 何时使用
- 批量生成应用场景页 / 参数组合页
- 已有一批同结构页面需要检测同质化

## 前置条件(必须先确认)
1. `src/data/applications.yaml` 中每个场景的 challenges、
   keySelectionCriteria、industryStandards 都是真实不同的内容
   → 如果多个场景的这些字段实质相同,先补全数据再生成
2. `combinations.yaml` 已过滤无意义组合
3. 注册表已为每个待生成页面添加对应行

## 执行步骤

### Step 1:数据层预检(必须,不可跳过)
执行 `scripts/pseo-data-check.mjs`

检查每个场景的 challenges 字段两两相似度。
如果两个场景的 challenges 相似度 > 50%,
说明数据准备不充分——**先补数据,不要开始生成**

### Step 2:批量生成
执行第 29 篇的 `scripts/generate-pseo-pages.mjs`
使用本篇的分层提示词模板。

建议分批:每批 10 个页面,跑完检测再跑下一批。
一次跑 50 个,如果提示词有问题,50 个都要重做。

### Step 3:重复度检测
执行 `scripts/pseo-similarity.mjs`

- verdict = PASS → 进入 Step 4
- verdict = NEEDS_REWRITE → 对 topOffenders 中的页面
  重新生成,并在提示词里追加:
  "以下段落与其他页面高度重复,重写时必须使用
   {场景名} 特有的技术细节,禁止使用通用论述:[粘贴重复段落]"

### Step 4:人工抽查(10%)
随机抽 10% 的页面,检查:
□ challenges 展开是否有实质内容(不是重述现象)
□ notSuitableFor 的限制是否提到了
□ 选型表第三列是否解释了"为什么"
□ FAQ 是否针对本场景的具体疑问
□ 行业标准引用是否准确(这一项最容易出错,
  AI 可能编造标准编号——必须核实)

### Step 5:NKW 校验
执行 `scripts/nkw-check.mjs`(第 45 篇的变体),
检查生成内容是否含 NKW。

## 输出格式

pSEO 批量生成报告

批次:[N] 个页面 数据层预检:[通过/不通过] 平均字数:[N] 重复度检测:[PASS/NEEDS_REWRITE]

数据层预检结果

场景数据相似度最高的组合:

  • chemical_transfer × solvent_transfer:42%(可接受)
  • water_treatment × wastewater:61%(⚠️ 需补充差异化数据)

重复度检测

超标页面对([N] 对):

页面 A 页面 B 相似度
centrifugal-pump-water-treatment.md centrifugal-pump-wastewater.md 58.3%

优先重写(与多页相似):

页面 相似对数
centrifugal-pump-hvac.md 4

人工抽查结果

抽查 [N] 篇,发现问题:

  • centrifugal-pump-mining.md:引用了 “ISO 5199-3”, 实际不存在该分册 → 需修正
  • centrifugal-pump-food.md:未提及 notSuitableFor 限制

待处理

□ 补充 wastewater 场景的差异化数据 □ 重写 4 篇高相似页面 □ 修正 1 处标准编号错误


## 禁止行为
- 数据层预检不通过时,不要开始生成
- 不要跳过标准引用的准确性核实(AI 会编造标准编号)
- 不要一次生成超过 10 个页面
- 重复度超标的页面不要靠"改几个词"应付,要重新生成

五、数据层预检脚本

// scripts/pseo-data-check.mjs
import fs from 'fs/promises';
import yaml from 'js-yaml';

const apps = yaml.load(
  await fs.readFile('src/data/applications.yaml', 'utf8')
);

// 把场景的关键文本字段拼成一个字符串
function fingerprint(app) {
  return [
    ...(app.challenges ?? []),
    ...(app.keySelectionCriteria ?? []).map(c =>
      `${c.parameter} ${c.recommendation}`
    ),
    ...(app.industryStandards ?? []),
  ].join(' ').toLowerCase();
}

function tokenSet(text) {
  return new Set(
    text.replace(/[^a-z0-9\s]/g, ' ').split(/\s+/).filter(w => w.length > 3)
  );
}

function jaccard(a, b) {
  let inter = 0;
  for (const t of a) if (b.has(t)) inter++;
  return inter / (a.size + b.size - inter);
}

const prints = apps.map(a => ({
  id: a.id,
  name: a.name,
  tokens: tokenSet(fingerprint(a)),
  challengeCount: (a.challenges ?? []).length,
  criteriaCount: (a.keySelectionCriteria ?? []).length,
  standardCount: (a.industryStandards ?? []).length,
}));

// 数据完整性检查
const incomplete = prints.filter(p =>
  p.challengeCount < 3 || p.criteriaCount < 3 || p.standardCount < 2
);

// 两两相似度
const pairs = [];
for (let i = 0; i < prints.length; i++) {
  for (let j = i + 1; j < prints.length; j++) {
    const sim = jaccard(prints[i].tokens, prints[j].tokens);
    pairs.push({
      a: prints[i].id,
      b: prints[j].id,
      similarity: (sim * 100).toFixed(1) + '%',
      raw: sim,
      needsWork: sim > 0.50,
    });
  }
}
pairs.sort((a, b) => b.raw - a.raw);

const problematic = pairs.filter(p => p.needsWork);

console.log(JSON.stringify({
  summary: {
    scenarioCount: apps.length,
    incompleteData: incomplete.length,
    highSimilarityPairs: problematic.length,
    verdict: (incomplete.length === 0 && problematic.length === 0)
      ? 'READY_TO_GENERATE'
      : 'NEEDS_DATA_WORK',
  },
  // 数据不完整的场景
  incomplete: incomplete.map(p => ({
    id: p.id,
    challenges: p.challengeCount,
    criteria: p.criteriaCount,
    standards: p.standardCount,
    required: 'challenges≥3, criteria≥3, standards≥2',
  })),
  // 相似度过高的场景对
  problematicPairs: problematic,
  // 全部相似度(供参考)
  topSimilarities: pairs.slice(0, 10),
}, null, 2));

process.exit(
  (incomplete.length > 0 || problematic.length > 0) ? 1 : 0
);

六、批次质量门槛

一批页面在发布前应同时满足:

□ 数据层预检 verdict = READY_TO_GENERATE
□ 重复度检测 verdict = PASS(无 >40% 的页面对)
□ 平均字数 ≥ 1000 词
□ 无页面字数低于平均值的 60%
□ NKW 检查全部通过
□ 10% 抽查中的标准引用全部核实无误

任一项不满足就不要发布这批页面。批量生成的风险是批量的——一批低质量页面上线,可能拖累整站的质量评分,修复成本远高于生成前多花两小时准备数据。


→ AI Skill:Author + Organization Schema 批量生成

NEXT ACTION / 下一步

继续系列:AI 外贸站建设全系列

把读到的方法变成一个小行动,完成后再回来迭代。

继续

RELATED / 相关推荐

接着读这些

按同一分类、系列与标签为你挑选。