跳到主要内容
IM智引科技

研究 / 外贸与 B2B 增长

AI Skill:注册表审计——关键词抢词与归属冲突检测

把注册表的唯一性约束检查固化成一个可复用 Skill:确定性脚本负责扫描注册表和页面内容,模型负责判断语义级抢词和给出合并建议,中间用一份写清判定规则和输出格式的说明书连接。

BLKTECH 编辑部2026年8月4日14 分钟难度 实战免费Node.jsAI AgentYAML

注册表审计 Skill 分两层:确定性脚本检查字面级冲突(同一 keyword 出现在多行、PKW 与其他页面 NKW 矛盾、slug 重复),模型检查语义级冲突(不同字面但同义的 PKW、意图分类错误)。输出报告按 error/warn 分级,error 阻断新页面创建。

AI Skill:注册表审计——关键词抢词与归属冲突检测

先说结论

注册表的核心承诺是“一个词只属于一个页面”。但这个承诺不会自动执行——人会忘、AI 会自作主张、团队协作会出错。

审计 Skill 要解决的就是:把这个承诺变成可以定期自动验证的规则

关键的拆分原则和站内 SEO Skills 系列一致:

字面级冲突交给脚本(确定性),语义级冲突交给模型(需要判断),中间用一份写死了判定规则和输出格式的说明书连接。


一、要检测的五类冲突

冲突一:同一 keyword 出现在多行(字面级)

最直接的违规。注册表里 centrifugal pump manufacturer 出现了两次,分别归属 /products/centrifugal-pumps//about/

判定error(必须修复)

冲突二:PKW 与其他页面的 NKW 矛盾(字面级)

页面 A 的 PKW 是 centrifugal pump specifications,但页面 B 的 NKW 里写了这个词——说明 B 明确声明不争这个词,这是正确的。

但反过来:如果页面 A 的 PKW 出现在它自己的 NKW 里,这是配置错误。

判定error

冲突三:SKW 与其他页面的 PKW 重叠(字面级)

页面 A 的 SKW 里有 industrial pump supplier,而这个词是页面 B 的 PKW。

这不一定是错——SKW 是次级词,轻微重叠可以接受。但如果 A 是 Resource 页而 B 是 Pillar 页,Resource 页争 Pillar 的主词就是问题。

判定warn(需要人工判断)

冲突四:语义同义的 PKW(语义级,需要模型)

页面 A:PKW = "centrifugal pump manufacturer"
页面 B:PKW = "centrifugal pump maker"
页面 C:PKW = "industrial centrifugal pump producer"

字面不同,脚本检测不出来,但 Google 会视为同一搜索意图——三个页面在抢同一个词。

判定warn,由模型识别并给出合并建议

冲突五:意图分类错误(语义级,需要模型)

keyword: "what is a centrifugal pump"
intent_type: commercial   ← 错误,应该是 informational
page_type: pillar         ← 错误,应该是 cluster-resource

判定warn,模型给出修正建议


二、Skill 说明书(核心资产)

这份说明书是 Skill 的本体。放进 Claude Code 是 SKILL.md,放进 Cursor 是一条 rule,放进 Codex 是 AGENTS.md 的一节。

# Skill:关键词注册表审计

## 何时使用
- 用户要求审计注册表
- 用户新增页面前要求检查冲突
- 定期(每季度)健康检查

## 输入
- `registry.json` 或 Notion 导出的 CSV(路径由用户提供)
- 可选:站点 sitemap.xml(用于验证 page_slug 是否真实存在)

## 执行步骤

### Step 1:运行确定性脚本
执行 `scripts/registry-lint.mjs`,获得字面级冲突列表。
不要自己用眼睛比对 keyword——一定要跑脚本,人工比对会漏。

### Step 2:语义级检查(你来做判断)
对脚本输出的全部 PKW 列表,按以下规则检查:

**同义词检测**
把所有 PKW 按主题分组,找出语义等同但字面不同的组。
判定标准:如果两个词在 Google 搜索会返回高度重叠的结果页,
视为同义。常见同义模式:
- manufacturer / maker / producer / supplier(商业采购意图,视为同义)
- specifications / specs / datasheet / technical data(参数意图,视为同义)
- for [场景] / [场景] application / used in [场景](场景意图,视为同义)

**意图分类验证**
逐行检查 intent_type 是否与 keyword 的实际意图匹配。
判定规则(按优先级):
1. 含 manufacturer/supplier/OEM/factory/wholesale/quote/buy → commercial
2. 含 specs/datasheet/dimensions/flow rate/vs/for [场景] → engineering
3. 含 what is/how does/types of/guide/explained → informational
4. 含具体型号名 → engineering

**page_type 匹配验证**
- commercial 意图 → 只能是 pillar 或 cluster-sku
- engineering 意图 → 只能是 cluster-sku 或 cluster-app
- informational 意图 → 只能是 cluster-resource
不匹配的标为 warn。

### Step 3:输出报告
严格按下方格式输出。不要添加额外的建议章节,
不要用"建议进一步优化"这类没有具体动作的话。

## 输出格式

注册表审计报告

生成时间:[YYYY-MM-DD] 注册表行数:[N] error:[N] 项 warn:[N] 项

ERROR(必须修复)

E1. 关键词重复归属

  • keyword: centrifugal pump manufacturer
  • 出现在:/products/centrifugal-pumps/(pillar) /about/(未分类)
  • 修复动作:从 /about/ 移除该词,改为 about aquaflow industrial,并在 /about/ 的 NKW 加入 centrifugal pump manufacturer

WARN(需人工判断)

W1. 语义同义 PKW

  • 组内成员:
    • centrifugal pump manufacturer → /products/centrifugal-pumps/
    • centrifugal pump maker → /products/pump-factory/
  • 判断依据:manufacturer 与 maker 在商业采购意图下语义等同
  • 建议动作:保留 /products/centrifugal-pumps/ 作为唯一归属, 将 /products/pump-factory/ 301 重定向或改为不同意图的页面

W2. 意图分类错误

  • keyword: what is a centrifugal pump
  • 当前:intent_type=commercial, page_type=pillar
  • 应为:intent_type=informational, page_type=cluster-resource
  • 原因:含 “what is” 为知识学习意图

通过项

  • 唯一性约束:[N] 行无重复
  • NKW 自引用检查:无违规
  • page_slug 与 sitemap 一致性:[N]/[N] 匹配

## 禁止行为
- 不要修改注册表文件(只报告,不自动改)
- 不要跳过脚本直接用眼睛比对
- 不要输出没有具体修复动作的 warn 项

三、确定性脚本

脚本只做一件事:字面级检查。所有需要判断的部分留给模型。

// scripts/registry-lint.mjs
import fs from 'fs/promises';

const registry = JSON.parse(await fs.readFile('registry.json', 'utf8'));

const errors = [];
const warns = [];

// 检查 1:keyword 唯一性
const keywordMap = new Map();
for (const row of registry) {
  if (row.status === 'deprecated') continue;
  const kw = row.keyword.toLowerCase().trim();
  if (keywordMap.has(kw)) {
    errors.push({
      type: 'duplicate_keyword',
      keyword: row.keyword,
      pages: [keywordMap.get(kw), row.page_slug],
    });
  } else {
    keywordMap.set(kw, row.page_slug);
  }
}

// 检查 2:PKW 出现在自己的 NKW 里
for (const row of registry) {
  const pkw = row.pkw.toLowerCase();
  const nkwList = (row.nkw || []).map(n => n.toLowerCase());
  if (nkwList.some(n => pkw.includes(n) || n.includes(pkw))) {
    errors.push({
      type: 'pkw_in_own_nkw',
      page: row.page_slug,
      pkw: row.pkw,
    });
  }
}

// 检查 3:SKW 与其他页面的 PKW 重叠
const pkwMap = new Map(
  registry.map(r => [r.pkw.toLowerCase(), r.page_slug])
);
for (const row of registry) {
  for (const skw of row.skw || []) {
    const owner = pkwMap.get(skw.toLowerCase());
    if (owner && owner !== row.page_slug) {
      warns.push({
        type: 'skw_overlaps_pkw',
        skw,
        skwPage: row.page_slug,
        pkwOwner: owner,
      });
    }
  }
}

// 检查 4:page_slug 格式规范
for (const row of registry) {
  const slug = row.page_slug;
  if (slug !== slug.toLowerCase()) {
    errors.push({ type: 'slug_not_lowercase', page: slug });
  }
  if (slug.includes('_')) {
    errors.push({ type: 'slug_uses_underscore', page: slug });
  }
  if (!slug.startsWith('/') || !slug.endsWith('/')) {
    warns.push({ type: 'slug_missing_slash', page: slug });
  }
}

// 检查 5:必填字段完整性
const REQUIRED = ['keyword', 'intent_type', 'page_slug', 'page_type', 'pkw', 'priority'];
for (const row of registry) {
  const missing = REQUIRED.filter(f => !row[f]);
  if (missing.length) {
    errors.push({
      type: 'missing_fields',
      page: row.page_slug,
      fields: missing,
    });
  }
}

// 输出结构化 JSON,交给模型做语义分析
console.log(JSON.stringify({
  summary: {
    totalRows: registry.length,
    activeRows: registry.filter(r => r.status !== 'deprecated').length,
    errorCount: errors.length,
    warnCount: warns.length,
  },
  errors,
  warns,
  // 全部 PKW 列表,供模型做同义词分组
  allPkw: registry.map(r => ({
    pkw: r.pkw,
    page: r.page_slug,
    intent: r.intent_type,
    pageType: r.page_type,
  })),
}, null, 2));

四、为什么必须两层分工

只用脚本的问题:检测不出 manufacturermaker 是同一个意图。字面比对永远无法覆盖语义。

只用模型的问题:让模型逐行比对30行注册表的 keyword 唯一性,它会漏。这是确定性任务,脚本100%可靠,模型不是。

两层配合:脚本给出确定的字面冲突 + 完整的 PKW 清单,模型在这个清单上做语义判断。脚本保证不漏,模型保证不浅。


五、接入工作流

触发时机一:新建页面前(最重要)

新页面 PKW: "industrial centrifugal pump supplier"

跑 registry-lint.mjs

error 有 → 停止,先修复
error 无 → 让模型做语义检查

语义同义警告 → 人工确认是否真的需要新页面

通过 → 在注册表新增行,开始写作

触发时机二:每季度全量审计

跑完整流程,输出报告,处理累积的 warn 项。

触发时机三:CI 集成(可选)

如果注册表存在代码仓库里(registry.json),可以加一个 GitHub Action:

name: Registry Lint
on:
  pull_request:
    paths: ['registry.json']
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: node scripts/registry-lint.mjs > lint-result.json
      - run: |
          ERRORS=$(jq '.summary.errorCount' lint-result.json)
          if [ "$ERRORS" -gt 0 ]; then
            echo "Registry has $ERRORS errors"
            jq '.errors' lint-result.json
            exit 1
          fi

error 阻断 PR 合并,warn 只提示。


→ AI Skill:页面覆盖度审计——找出注册表中无对应页面的词

NEXT ACTION / 下一步

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

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

继续

RELATED / 相关推荐

接着读这些

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