实验9:在秘塔搜索上做一次 GEO 小型实证
选择可观测中文入口、对同一主题起 20 个 query、记录引用源、按 GEO 策略改写自己的博文后再测
实验概述
本实验将完成你的第一次 GEO 实证——在可观测的中文生成式搜索入口上测量自己内容的被引率,按 GEO 策略改写后再次测量,并分析策略收益。
| 项目 | 详情 |
|---|---|
| 目标引擎 | 秘塔搜索(metaso.cn)为主;可选 DeepSeek Web 作对照 |
| 主题选择 | 自由——建议选你已有博文或学术笔记的主题 |
| 查询规模 | 20 个同主题变体 query |
| 核心任务 | 基线测量 → 选定策略改写 → 冷却 7 天 → 再测 → 对比分析 |
| 预计时间 | 首轮约 100 分钟(含数据整理),二轮 + 分析 30 分钟 |
冷却期提示:本实验第二轮测量需要在改写发布后至少 7 天进行。建议第一课时完成基线测量 + 改写发布,第二课时(下周)做后测和分析。请合理安排课程时间线。
实验步骤
步骤 1:选定主题与查询集(15 分钟)
主题选取原则:
- 你已有一篇(或可写一篇)中文博文 / 笔记的主题
- 主题要足够具体(不要是"Python 入门"这种红海),但也要有一定搜索量
- 推荐方向:技术工具教程、某领域概念解释、一个小众学术主题、一个地方/校园办事流程
示例主题:
- "LoRA 在 Qwen3 微调中的实际显存占用"
- "DITA 结构化写作 vs Markdown 的可维护性"
- "北大研究生学位论文 LaTeX 模板配置"
查询集设计(20 条):
queries = [
# 5 条直接查询(与你标题高度相关)
"LoRA 微调 Qwen3 显存占用",
"LoRA r=32 和 r=8 显存差多少",
...
# 5 条同义变体(不同措辞表达相同意图)
"Qwen3 LoRA 训练需要多少显存",
...
# 5 条长尾查询(更具体的子问题)
"LoRA alpha 32 显存会怎么变化",
...
# 5 条横向对比查询(与你内容竞争但不完全重合)
"LoRA vs QLoRA 显存对比",
...
]
assert len(queries) == 20把 queries 保存到 queries.json,后续每次实验复用同一份。
步骤 2:基线测量(25 分钟)
手动或半自动测量每条 query 在秘塔搜索上的表现。
测量脚本(半自动推荐):
import json
from datetime import datetime
from pathlib import Path
# ===== 1. 加载查询集 =====
queries = json.loads(Path("queries.json").read_text(encoding="utf-8"))
# ===== 2. 记录模板 =====
def record_query(query: str, engine: str = "metaso") -> dict:
"""
对每条 query,在秘塔搜索上手动查询后填写以下字段。
建议每条 query 重复 3 次取最稳定的结果。
"""
return {
"query": query,
"engine": engine,
"timestamp": datetime.now().isoformat(),
"answer_text": "", # 粘贴秘塔完整答案文本
"all_cited_urls": [], # 答案中所有编号引用的 URL 列表
"my_url": "", # 你自己博文的 URL
"my_cited": False, # 是否被引用
"my_rank": None, # 被引用时的编号位次(1-based;未引用填 None)
"my_word_count": 0, # 你内容中有多少词元出现在答案里(人工估计或脚本计算)
"competitor_cited": [], # 竞争内容被引的 URL
"notes": "", # 主观观察
}
# ===== 3. 为每条 query 手动填写 =====
baseline_records = []
for q in queries:
for repeat in range(3): # 每条重复 3 次
rec = record_query(q)
# ... 手动填入 ...
baseline_records.append(rec)
Path("baseline.json").write_text(
json.dumps(baseline_records, ensure_ascii=False, indent=2),
encoding="utf-8"
)位置加权词数的计算:
def position_adjusted_wc(answer_text: str, my_content_tokens: list[str]) -> float:
"""
统计 my_content_tokens 中有多少出现在 answer_text 中,
并按位置倒数加权。
"""
answer_tokens = answer_text.split() # 简化:按空格切;中文可用 jieba
pawc = 0.0
for my_tok in my_content_tokens:
if my_tok in answer_tokens:
pos = answer_tokens.index(my_tok) + 1 # 1-based
pawc += 1.0 / pos
return pawc聚合统计:
import statistics
def summarize(records):
grouped = {}
for r in records:
grouped.setdefault(r["query"], []).append(r)
summary = {}
for q, runs in grouped.items():
cited = [r["my_cited"] for r in runs]
ranks = [r["my_rank"] for r in runs if r["my_rank"] is not None]
pawc = [r.get("pawc", 0) for r in runs]
summary[q] = {
"cite_rate": sum(cited) / len(cited),
"mean_rank": statistics.mean(ranks) if ranks else None,
"mean_pawc": statistics.mean(pawc),
}
return summary
baseline_summary = summarize(baseline_records)记录到此时的关键问题:
- 在 20 条 query 中,你的内容被引多少次?(命中率)
- 被引时平均位次多少?
- 哪些 query 从未命中?为什么?
- 竞争内容(被频繁引用的其它 URL)有什么共同特征?
步骤 3:策略选择与改写(30 分钟)
根据基线分析,从 9.2 节策略表中选 1 条进行单变量干预。推荐优先级:
适用:你的博文偏"观点 + 叙述"型,缺乏具体引用和数据。
改写清单:
- 每个主要论断后加至少 1 条权威引用(论文、官方文档、权威媒体)
- 至少插入 2—3 处直接引语("根据 X 的研究……")
- 补充具体数字(百分比、年份、样本量)
改写强度指标:
- 原文命题句密度:约 1.2 条 / 段 → 目标 ≥ 2 条 / 段
- 原文引用密度:< 1 条 / 1000 字 → 目标 ≥ 3 条 / 1000 字
适用:你的博文偏"大段散文",段落过长、缺少小标题。
改写清单:
- 段落长度调整至 150—300 词(偏长的切分)
- 每个 H2 下至少 2 个 H3
- 格式多样元素(列表 / 表格 / 代码块 / 引用块)占 25%—35%
- 核心关键词放在段首 30% 的位置
改写前后可量化对比:
def structural_features(markdown_text: str) -> dict:
lines = markdown_text.split("\n")
return {
"n_h2": sum(1 for l in lines if l.startswith("## ")),
"n_h3": sum(1 for l in lines if l.startswith("### ")),
"n_list_items": sum(1 for l in lines if l.startswith(("- ", "* ", "1. "))),
"n_code_blocks": markdown_text.count(chr(96) * 3) // 2,
"avg_para_len": statistics.mean([len(p) for p in markdown_text.split("\n\n") if p.strip()]),
}适用:有预算或人脉资源;不适合纯学生练习。可作为分析题讨论。
- 在相关技术社区(知乎 / CSDN / 掘金 / SegmentFault)发布导向你博文的深度帖
- 请同学互为评测博客——你写他的评测,他写你的
- 把博文内容改写为可投稿的文章,投给相关公众号 / 行业媒体
本方案不做实测,只做策略讨论与计划。
发布改写版本:
- 新建 URL(如
post-v2或在同 URL 上更新) - 记录发布时间,开始冷却期(≥ 7 天)
- 在改写前后各自提交一次 sitemap 让搜索引擎重新索引
步骤 4:冷却期观察(同步做其它课程,7 天后返回)
冷却期做以下事情:
- 每 2 天快速查 3—5 条 query,观察引用生态是否已更新
- 记录观察日志(主观)
- 如果发现改写后内容在 3 天内就被引,说明引擎已重建索引
冷却期可选的并行阅读:Aggarwal 等人(2024)GEO 原始论文的 Section 4 实验方法部分、Puerto 等人(2025)C-SEO Bench 的负面发现。对比他们如何处理"非确定性"和"混淆变量"。
步骤 5:后测与对比分析(25 分钟)
重复步骤 2 的测量流程,保存到 post.json。然后做对比:
def compare(baseline_summary, post_summary):
comparison = []
for q in baseline_summary:
b = baseline_summary[q]
p = post_summary.get(q, {})
comparison.append({
"query": q,
"cite_rate_delta": p.get("cite_rate", 0) - b["cite_rate"],
"rank_delta": (p.get("mean_rank") or 99) - (b["mean_rank"] or 99),
"pawc_delta": p.get("mean_pawc", 0) - b["mean_pawc"],
})
return comparison
comparison = compare(baseline_summary, post_summary)
# 统计检验
from scipy import stats
cite_rate_pre = [baseline_summary[q]["cite_rate"] for q in baseline_summary]
cite_rate_post = [post_summary[q]["cite_rate"] for q in post_summary]
t_stat, p_value = stats.ttest_rel(cite_rate_pre, cite_rate_post)
print(f"paired t-test: t={t_stat:.3f}, p={p_value:.4f}")可视化:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# 被引率分布
axes[0].hist([c["cite_rate_delta"] for c in comparison], bins=10)
axes[0].set_title("Cite Rate Delta per Query")
axes[0].axvline(0, color='red', linestyle='--')
# 位次变化
axes[1].hist([c["rank_delta"] for c in comparison], bins=10)
axes[1].set_title("Rank Delta per Query")
# PAWC 变化
axes[2].hist([c["pawc_delta"] for c in comparison], bins=10)
axes[2].set_title("PAWC Delta per Query")
plt.tight_layout()
plt.savefig("geo_experiment_result.png", dpi=150)
plt.show()步骤 6:写 1 页分析报告(10 分钟)
必答:
- 你选择的策略是什么?为什么?(基于基线分析)
- 20 条 query 上的平均被引率变化如何?统计显著吗?
- 哪些 query 上策略最有效?哪些上无效或反向? 尝试给出机制解释。
- 位置加权词数 PAWC 的变化比被引率更大还是更小? 说明什么?
- 有没有观察到"事后合理化"现象?(答案似乎和你的改写一致,但没 cite 你)
选答(加分项):
- 对比秘塔与 DeepSeek 上的同一主题结果,讨论中文入口差异
- 用反事实扰动(把你的页面内容替换成无关文本)验证"真实引用 vs 合理化引用"
- 讨论这条策略如果长期应用是否会产生 Hu (2025) 所说的"军备竞赛"动态
常见陷阱与调试
| 现象 | 原因 | 对策 |
|---|---|---|
| 改写后被引率反而下降 | 可能触发了 Keyword Stuffing 陷阱 | 检查关键词密度;看改写是否破坏了语义自然度 |
| 结果高度不稳定 | 重复次数不够,或 query 过于热点 | 每 query 重复 ≥ 3 次;避开热点话题 |
| 第二轮测不到 cite | 冷却期不够或 URL 未被重新抓取 | 在搜索引擎站长后台提交 URL;延长冷却期 |
| 秘塔搜索不支持 API | 需要手动查询 | 用 Playwright 做半自动化;或减少到 10 条 query |
| 部分 query 引用全是百科类内容 | 你的内容不在 "权威生态"中 | 考虑方案 C(赢得媒体)作为长期计划 |
交付物清单
完成实验后,请提交以下内容:
- queries.json(20 条查询)
- baseline.json(基线 60 条记录 = 20 query × 3 次)
- post.json(后测 60 条记录)
- 改写前后的博文 URL(或 markdown 快照)
- geo_experiment_result.png(三张 delta 分布图)
- 1 页分析报告(必答 5 题 + 选答至少 1 题)
时间预估:
- 查询集与基线测量:~40 分钟
- 策略选择与改写:~30 分钟
- 冷却期:7 天(异步)
- 后测与对比:~25 分钟
- 分析报告:~10 分钟
- 总计(净实操):约 100—110 分钟
加分项:跨引擎对照
有余力的同学可以把同一份查询集在 秘塔 + DeepSeek Web + Perplexity(中文 query) 三个入口上各做一轮,对比:
- 同一策略在不同引擎上的收益差异
- 引用来源生态的差异(印证 Chen et al. 2025 的"语言生态切换")
- 针对 Integrated 架构(DeepSeek)与 Iterative 架构(秘塔)的最优策略是否不同
这类对照实验有希望产出一份可公开发表的小型研究报告,推荐作为期末项目深化方向。