近段时间在批量建站,又看了QuickCreator 文章(作者:Tony Yan,请查看文章结尾参考资料-参考 1),感觉关键词聚类操作可变成可复用、可调参、成本可控的内容生成流程。
关键词聚类分组后便于新建栏目和支柱页(Pillar page),以及后续内容生产。之前都是使用 WriterZen的Keyword Planner进行聚类分组,而且分组后有搜索量/黄金得分等参考数据,便于筛选pramary keywords来编写文章。奈何囊中羞涩,WriterZen太贵了,实在不想充值就想着找找替代方案。
基于以上原因有了本篇文章。大体思路都是 ChatGPT 和 Gemini 给的。先让 ChatGPT 给思路,跑了几版代码,结果不符合预期。后来换成Gemini 给的思路,使用“SERP 条件 + BGE 语义 + 图聚类”,再反复调参数,才得到一版能用于内容规划的关键词聚类方案。
本文不是“科普”,而是一篇复盘,其中包含大量失败方案,而且最后跑通方案和参数也不具备通用性,可能不同品类新站都需要调整参数等,仅仅作为参考。聚类后补充搜索量、CPC、`allintitle搜索结果` 和关键词黄金得分(以下简称“KGR”,请查看文章结尾处-参考 2 获取详细信息),以及下一步文章生产仅作为补充内容。
为什么要自己做关键词聚类?
| 需求 | WriterZen | 本地版本SERP+BGE+图聚类 |
| 成本 | 高(会员+token) | 低(接口费用) |
| 参数调整 | 有限 | 可调聚类阈值、接口参数等 |
| 聚类方法 | 黑盒 | 可调整不同聚类方法 |
| 工程化 | 不方便 | 便于新站工作流/站群流接入 |
1. 关键词聚类思路整理
结合参考资料 1 和万能的chatgpt,得到如下思路:
- 基于SERP的聚类
- 基于语义关键词聚类(NLP 聚类)
- 混合聚类(图聚类)
- 大模型聚类(英文:ChatGPT/Gemini;中文:千问/DeepSeek。最好多个模型结果参考着进行聚类)
4种聚类方案差异对比
| 评估维度 / 指标 | 大模型聚类 | SERP 聚类 | NLP聚类 | 混合聚类 |
| 成本(万词) | $25.00 ~ $45.00(调GPT接口计算) | $10.00 | $0.00 | $1.00 ~ $2.00 |
| 时间效率(万词) | 约 13.5 min | 约 8.3 min | 约 4.5 s | 约 1.2 min |
| 内存占用 | 极低 | 约20MB | 约 1.5GB(加载向量模型) | 约 2GB |
| 聚类质量(SEO对齐度,人工预估) | 70% | 80% | 55%(语义聚类,无搜索意图) | 92% |
| 漏词率 | 5% ~ 10%(特别是长文本,极易发生幻觉和漏词) | 0% | 0% | < 1% |
| 增量更新成本 | 极低 | 极高(新增词需重跑) | 极低(新词计算向量计算即可) | 中等(对新簇动态微调) |
结论:
- 关键词个数 500 内,直接使用大模型+人工校对。
- 关键词个数 500 以上,使用混合聚类。(本文主要以混合聚类为主介绍)
为什么不直接使用 ChatGPT/千问 直接聚类?
关键词数量几百而且成本有限的话,也不是不可以。毕竟数量少可人工兜底。如果关键词数量太大时会有如下问题:
- –缺乏敏感度。超长长尾词、行业专属词/黑话、新兴词(大模型停留在其训练截止日期,晚于训练日期的新兴产品/工具/品牌)存在错乱问题。
- 与 google 真实情况不一致。大模型归为相同主题,但google 真实反馈不一致。比如:AI工作流自动化工具 vs 如何自己开发AI工作流。AI工作流自动化工具,前 10 名全是 B2B 商业落地页/软件官网(搜索意图为 Commercial), 如何自己开发AI工作流,前 10 名全是 GitHub 、技术博客、教程为主(搜索意图为 Informational),不应该归为一个主题。
- 幻觉和不稳定性。一定概率存在输入 800 词,吐出 801 词或者模型修改后的长尾关键词。
基于以上考虑如果关键词量级更小,比如 300 内,可以使用大模型+人工来最快捷且成本低。如果关键词量级比较大,如果 大几百甚至几万,最好以 SERP为主。
2. 实测样本、工具、接口选择评估
2.1 SERP接口选择
通过对比Tavily、Serper、SerpAPI、serpbase、Exa、spider.cloud、valueserp等接口结果与真实google搜索结果,最终选择Tavily、Serper、serpbase,结合费用成本和并行情况,最终选择如下:
- 免费:优先使用Tavily(每月 1000)、Serper(每个账号 2500次 免费调用)
- 付费:使用SerpBase(最便宜$0.5 / 1k,量大可达$0.3 / 1k)。Serper差不多$1 / 1k,而且$50起充。Tavily更贵,$8 / 1k。使用ValueSerp,因为其支持查看搜索结果数和related search和related questions($2.5 / 1k)
2.2 模型选择
因本地mac运行embedding模型,通过比较模型大小、CPU效率(1000字符转换为向量所耗时)、准确度等,最终选择模型如下:
bge-base-zh-v1.5 (优先使用:准确度高,250MB,512维度,速度快)
bge-small-zh-v1.5 (准确度一般,48MB,512维度,速度极快)
bge-small-en-v1.5(优先使用:准确度一般,37MB,512维度,速度极快)
all-MiniLM-L6-v2(准确度一般,91MB,512维度,速度快)
2.3 聚类方法选择
大模型测试:使用chatgpt测试小关键词样本、中关键词样本、真实关键词样本,测试效果并不理想。
NLP 测试:在不知道簇数的情况下聚类,可选择层次聚类、HDBSCAN、图聚类算法。测试NLP下使用层次聚类、HDBSCAN算法聚类,结果未达到预期,跟真实结果不差距较大,还不如直接使用大模型。
| 聚类方法 | 优点 | 缺点 |
| 层次聚类 | 不必指定中心词 | 阈值换一批词就要重调 |
| HDBSCAN | 能识别噪声 | 参数敏感,结果不稳定 |
| 纯 BGE 相似度 | 本地快、成本低 | 语义相近不等于同一搜索意图 |
混合聚类:
ChatGPT 版:SERP * 0.7 + NLP * 0.3,阈值为综合评分 > 0.75 即可聚类
Gemini 版本:SERP URL ≧ 3;SERP URL = 2 && NLP ≧0.55 ; NLP ≧0.85,满足以上条件即可聚类
结论:
跑通流程最终选择了Serper 最为 SERP 接口,bge-base-zh-v1.5 跑中文,bge-small-en-v1.5 跑英文,混合聚类为主。以下表格为补充其他选择准备。
| 项目 | 测试设置 |
| 关键词测试集 | 小规模跑通代码流程:6 个关键词(测试集) 中规模测试算法实际应用:47 个关键词(测试集) 大规模实践应用:800 个关键词(验证集) |
| 主要语言 | 测试集关键词以中文为主 实践以英文为主 |
| SERP 来源 | Serper 为主,必要时对比 Serpbase / ValueSERP |
| 模型 | 中文 bge-base-zh-v1.5,英文 bge-small-en-v1.5 |
| 聚类方法 | 混合聚类为主 |
| 验收方式 | 人工验证(抽查主词、长尾词、页面类型、误合并、漏合并) 结合WriterZen 已聚类数据对比(验证集) |
3. 关键词聚类实践
3.1 ChatGPT版: SERP+NLP+阀值聚类思路失败
结合实际内容生产和代码落地,方案为:Graph Clustering + SERP Similarity,使用图聚类(Union-Find)。
核心思路如下:

部分核心代码:
# 相似度计算
def serp_overlap(urls1, urls2):
return len(set(urls1) & set(urls2)) / 10.0 # 归一化
def final_score(semantic, serp, semantic_weight=0.7, serp_weight=0.3):
return semantic * semantic_weight + serp * serp_weight
# 聚类
class UnionFind:
def __init__(self, n):
self.parent = list(range(n))
def find(self, x):
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def union(self, a, b):
pa, pb = self.find(a), self.find(b)
if pa != pb:
self.parent[pb] = pa
# 运行聚类
class ClusterPipeline:
def __init__(self, config):
self.config = config
def run(self, keywords, vectors, candidate_indices):
uf = UnionFind(len(keywords))
for i, kw in enumerate(keywords):
for j in candidate_indices[i]:
if i >= j:
continue
semantic = float(np.dot(vectors[i], vectors[j]))
serp = serp_overlap(kw.urls, keywords[j].urls)
score = final_score(
semantic, serp,
self.config.semantic_weight,
self.config.serp_weight
)
if score >= self.config.merge_threshold:
uf.union(i, j)
clusters = {}
for idx, kw in enumerate(keywords):
root = uf.find(idx)
clusters.setdefault(root, []).append(kw.text)
return list(clusters.values())不过运行测试集数据后发现并不能达到预期目标,而且拉完了,连最小样本测试都跑不通。
后面又基于GPT优化了两三个版本,不过也不太理想,最终放弃。
本次得到如下心得:
第一版失败在两个地方:阈值太保守导致长尾词被拆散,公共平台URL又导致无关词被粘在一起。
- 不要直接使用 URL,而使用域名。(需要考虑域名重复的问题;知名域名网站的影响,需要剔除子域名影响)
- 搜索结果 SERP 修改为 20 条,或者添加更多维度People Also Ask + Related Search 后并没有效果提升。
- 调整算法HDBSCAN后能提升效果,但更换关键词后需要手动调整参数才能跟预期一致。
后续改进:
- 使用tldextract这个库提取主域名。然后使用自定义域名库剔除视频/社媒、综合/问答/社区、厂商文档/代码托管、百科/AI官方/公共容器影响。
- 搜索结果使用 10条。
- 后续可以调整聚类算法看哪个效果更加。
问:为什么要剔除子域名影响?
答:剔除多语言站点情况和 剔除 PC 端和移动端相同内容但 URL 不一致情况。例如:
https://example/123.html
https://m.example/123.html
3.2 Geimin 版:混合图聚类开始接近预期
核心思路如下:
URL/域名重合度 >= 3,视为绝对同一种搜索意图。
URL/域名重合度 == 2 且 语义相似度 >= 0.7
URL/域名重合度 ==1 且 语义相似度 >= 0.8
纯语义相似度 >= 0.88,用于归纳长尾词。部分核心代码:
...(省略代码)...
if overlap >= 3:
G.add_edge(kw1, kw2, weight=1.5)
elif overlap == 2 and semantic_sim >= 0.7:
G.add_edge(kw1, kw2, weight=1.0)
elif overlap == 1 and semantic_sim >= 0.8:
G.add_edge(kw1, kw2, weight=0.8)
elif semantic_sim >= 0.88:
G.add_edge(kw1, kw2, weight=semantic_sim)
...(省略代码)...
# 引入Louvain算法进行聚类,解决“超级大类”问题。
# 默认 resolution 是 1.0。调整resolution类目总数会减少,如果调小(例如 0.5 - 0.8)
import networkx.algorithms.community as nx_comm
communities = nx_comm.louvain_communities(G, weight='weight', resolution=0.7, seed=42)
raw_clusters = [list(c) for c in communities if len(c) > 0]
raw_clusters.sort(key=len, reverse=True)(完整可运行代码已放在文章末尾资源区,下滑至末尾可获取下载方式)
经过多轮调整,人工检查测试小样本测试集和中样子测试集后比较符合预期。


测试过程中关键版本与参数调整:
| 版本 | 规则 | 结果 |
| v1.0.0 | URL >= 3;URL == 2 且 NLP >= 0.55;NLP >= 0.88 | 小样本测试不通过 |
| v1.0.1 | URL >= 2;URL == 1 且 NLP >= 0.7;NLP >= 0.88 | 小样本通过、中样本不通过 |
| v1.0.2 | URL >= 3;URL == 2 且 NLP >= 0.7;URL == 1 且 NLP >= 0.8;NLP >= 0.88 引入Louvain 算法 | 中样本通过 |
总结如下经验:
- “超级大类”问题:通过调整参数和引入Louvain 算法。
- 无法降低分类数目问题。孤立节点无法聚类(关键词SERP无重合URL,且语义相似度也达不到 0.88),需添加策略强制与跟它最像的前 1~2 个词连上线。强连接节点太稳固(关键词 SERP 重合URL达2以上),降低resolution参数至0.5。
4. 聚类后添加关键词指标数据,便于指导后续文章生产
聚类完成后,可以补搜索量、CPC、KD、allintitle 和关键词黄金得分(KGR)等数据,便于指导写作优先级。
| 字段 | 定义 |
| cluster_id | 聚类编号 |
| main_keyword | 每组主关键词,可以使用大模型给出更贴切便于理解的 |
| keywords | 组内关键词列表 |
| intent | Informational / Commercial / Transactional / Navigational |
| avg_volume | 月度搜索量 |
| cpc | 商业价值 |
| kd | SEO 难度 |
| allintitle_count | google中输入 allintitle:"关键词" 返回的搜索结果数量。 |
| kgr | 关键词黄金得分,通过allintitle_count 和volume 获取 |
| monthly_volume(非必须) | 近 12 个月每月的搜索量,看搜索趋势 |
| page_type(非必须) | 文章页、落地页、分类页、工具页、FAQ |
指标说明:
- 搜索量(avg_volume)/搜索量趋势图:决定写这篇文章有没有流量。一般选择搜索量>100,搜索量呈增加趋势最佳,次之选择平稳或周期波动且稳定的。
- KD值/KGR:决定优化该关键词的难度。KD 值和 KGR 都是越低越佳。KD 低于 20,KGR 低于 1.68 最佳。
- CPC:决定商业价值,特别是主要以ads 变现为主的网站。
| 指标 | 用途 | 数据来源建议 |
| avg_volume | 判断有没有流量 | DataForSEO / Semrush/google ads plan 数据接口 |
| CPC | 判断商业价值 | DataForSEO / Semrush |
| KD | 判断关键词 SEO 难度 | Semrush / Ahrefs |
| allintitle | 判断标题级竞争 | DataForSEO SERP/ |
| KGR | 判断关键词 SEO 难度 | 自行计算获取 |
DataForSeo:获取SERP结果(allintitle搜索结果数)、月度平均搜索量、cpc数据。可以一次提交最多100关键词,需要异步等待超过5min才返回结果,价格最便宜。
Rapid和Apify:均有获取Semrush Keyword Magic Tool接口,通过关键词的数据获取包括月度平均搜索量/cpc/搜索意图等数据,差别在于价格。
Apify:$20~$40/ 1000 request
Rapid:$9.99/5,330 requset,每分钟20个请求的限制
5. 补充说明
5.1 黄金关键词比率(KGR)定义
关键词黄金得分,是用于衡量一个关键词“是否值得做SEO内容”的综合指标,通过对比搜索需求与竞争强度来计算,得分越低,代表越容易排名且潜在价值越高。(详情请参考参考资料-参考 2)
Allintitle Volume:google中输入 allintitle:"关键词" 返回的搜索结果数量
Avg Volume:近 1 年的平均月度搜索量量。
公式在计算Allintitle Volume 数值较大或者Avg Volume 数值较大场景下并不能很好反应关键词价值,结合writerzen官方解释,让Gemini推导了一个新的KGR公式。(详情请参考参考资料-参考 3)
:对Allintitle Volume进行对数压缩。当值很小时,分值极低;当值超过 100 甚至上千时,分值对数增长。+1 是为了防止Allintitle Volume = 0 时数学报错。
:核心公式。如果搜索量(Avg Volume)极大,它就像一个巨大的分母,能剧烈稀释掉高 Allintitle Volume 带来的竞争压力。
:搜索量越大,这一项减去的正数就越多(得分越低)。双重对数是为了防止大搜索量过度扭曲结果,确保获得合理的“加分补偿”。
核心代码:
def golden_keywords_Ratio(ait: int, sv: int) -> float:
if sv <= 0:
return 99.0 # 无搜索量,直接淘汰
# 1. 大Allintitle Volume对数压缩
f_ait = math.log(ait + 1)
# 2. 交叉稀释项 (针对高基数 Allintitle Volume,引入 0.05 的随机森林修正系数)
f_ait_sv = ((ait + 1) / math.log(sv + 2)) * (0.05 if ait > 100 else 1.0)
# 3. 加分补偿
f_sv = -math.log(math.log(sv + 2))
# 综合得分
score = f_ait + f_ait_sv + f_sv
return round(score, 4)5.2 SERP 数据怎么清洗
SERP 清洗的关键,是用根域名判断意图,同时剔除高频公共平台。
| 清洗动作 | 为什么要这么做 |
| URL获取根域名 | 解决多端、多语言、参数页、同站不同路径导致的漏重合 |
| 剔除子域名 | 解决多端、多语言重合 |
| 过滤公共平台 | 避免 YouTube、GitHub、Reddit、知乎等制造假重合 |
域名提取可以用 tldextract:
def extract_clean_domain(url_string):
ext = tldextract.extract(url_string)
main_domain = ext.registered_domain.lower()
return main_domain if main_domain else None黑名单建议先从这些实体开始:
GLOBAL_PLATFORM_BLACKLIST = {
"youtube.com", "bilibili.com", "facebook.com", "x.com",
"instagram.com", "linkedin.com", "reddit.com", "pinterest.com",
"tiktok.com", "vimeo.com", "zhihu.com", "csdn.net",
"baidu.com", "douban.com", "xiaohongshu.com", "github.com",
"aliyun.com", "tencent.com", "huaweicloud.com", "microsoft.com",
"oracle.com", "aws.amazon.com", "amazon.com", "wikipedia.org",
"openai.com", "wix.com", "wordpress.com", "medium.com",
"quora.com", "sourceforge.net", "npmjs.com", "pypi.org"
}
6. 总结
这套关键词聚类方案的核心,并不能替代“WriterZen”,可以作为一种补充和工程化内容生产的一种解决方案。
| 最终结论 | 说明 |
|---|---|
| SERP 定意图 | 优先相信 Google organic 结果 |
| BGE 补召回 | 处理同义词、长尾词和轻微变体 |
| Louvain 拆大类 | 避免图连通导致超级 cluster |
| KGR 排序 | 解决把聚类结果转成写作优先级 |
我的结论是:SERP 负责判断搜索意图,BGE 负责补语义召回,图聚类负责形成 cluster,Louvain 负责拆超级大类,搜索量、CPC、KD、allintitle 和 Golden Score 负责排序。这样输出的不是一张分组表,而是一张可以直接指导新跨境网站建站和写文章的内容地图。
参考资料:
参考 1:关键词聚类:出海企业如何在 AI 搜索时代建立主题权威
参考 2:All-in-title and KGR (Keyword Golden Ratio)
参考 3:How Golden Filter was developed (Part 2) – KGR updated