工程师选型问答页的可抓取化实战:用 QAPage 与 FAQPage 把选型问题变成 AI 引用的答案源
先说一个数字。我们把一家仪器厂商三个月的售前沟通记录做了词频统计,发现被问到最多的 20 个问题占了全部咨询量的 61%,而这些问题在官网上的可抓取答案覆盖率是 0%——全部活在销售的聊天记录里。
这不是内容不够,而是内容形态不对。这篇讲我们怎么把这 20 个高频问题变成结构化的问答页,以及为什么"问答页"要用两种不同的 Schema 来输出。
一、先分清两种"问答":QAPage 与 FAQPage
很多团队把两者混着用,结果 AI 引擎读到的语义是错的。规范层面的区别如下:
| 维度 | FAQPage | QAPage |
|---|---|---|
| 语义 | 站点官方对常见问题的解答 | 一个具体问题下的讨论与回答 |
| 主体 | 问题 + 官方答案 | 问题 + 多个回答(可含最佳答案) |
| 适用场景 | 选型常识、流程、售后政策 | 具体型号的选型判断、对比结论 |
| 引用表现 | 常被整段引用 | 常被引用为"结论/建议" |
经验判断法很简单:答案是唯一且官方口径的,用 FAQPage;问题存在多种合理答案、需要基于条件给出建议的,用 QAPage。 选型场景恰好两种都有——“保修几年”是 FAQ,“3 米距离测 0.5mm 缺陷该选哪个型号”是 QA。
1.1 两者混用会怎样
混用不会报错,但会丢语义。把多答复的讨论塞进 FAQPage,引擎拿到的结构是"这是个官方答案",重复问题出现多个不同答案时,可信度会被打折;反过来把官方政策塞进 QAPage,容易被理解成"社区讨论"。
二、原理剖析:问答类结构化数据为什么更容易被引用
要理解这件事,得看生成式引擎的引用单元(Citation Unit)。
flowchart TD
A[用户提问] --> B[检索候选文档]
B --> C[切分为语义片段]
C --> D{片段是否自洽}
D -->|是| E[可作为引用单元]
D -->|否| F[丢弃或拼接]
E --> G[生成回答并标注来源]
引擎不是整页引用,而是按片段引用。一个片段能成为引用单元,需要满足两个条件:
- 自洽:片段单独拿出来也能读懂,不需要前文补全指代;
- 可信:片段有明确来源、有明确的适用范围,并且能对应到一个具体实体。
问答结构的先天优势就在这里。一个问题加一个答案天然自洽——“Q:测量距离 3 米、被测件是金属外壳,选哪种传感器?A:建议选 X 系列,因为……” 这段话被单独摘出来依然成立。相比之下,产品页里"采用高灵敏度设计,适应复杂工况"这类描述,脱离上下文就什么也证明不了。
这也解释了另一个现象:同样的信息,写成问答形式被引用的概率显著高于写成散文。 不是因为引擎偏爱问答,而是因为问答的切分边界与自洽性天然符合引用单元的要求。
三、实战:从聊天记录到结构化问答页
整条链路的四个环节:
flowchart LR
A[聊天记录导出] --> B[问题聚类]
B --> C[专家答案撰写与审核]
C --> D[结构化入库]
D --> E[页面渲染 + JSON-LD 输出]
3.1 第一步:问题聚类
人工读三个月聊天记录不现实,我们用的是"先用语义相似度粗聚类、再由产品工程师合并"的两段式。聚类脚本基于 jieba + 词向量简化实现,够用就不过度设计:
# 环境:Python 3.10+,依赖 jieba==0.42.1、scikit-learn==1.4.*
# 作用:把聊天记录里的问句按语义相似度粗聚类,输出待人工合并的候选组
import json
import re
from collections import defaultdict
import jieba
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
SENT_SPLIT = re.compile(r'[。!?!?\n]')
def extract_questions(path: str) -> list[str]:
"""从导出的对话文本里抽出疑似问句"""
questions = []
with open(path, encoding='utf-8') as fh:
for line in fh:
for sent in SENT_SPLIT.split(line):
sent = sent.strip()
# 长度过滤 + 疑问词过滤,减少噪声
if 8 <= len(sent) <= 60 and re.search(r'(吗|呢|多少|怎么|哪种|哪个|能不能|是否)', sent):
questions.append(sent)
return questions
def cluster(questions: list[str], threshold: float = 0.62) -> list[list[str]]:
"""TF-IDF + 余弦相似度做单遍聚类,threshold 越大分得越细"""
tokens = [' '.join(jieba.cut(q)) for q in questions]
matrix = TfidfVectorizer(token_pattern=r'(?u)\b\w+\b').fit_transform(tokens)
groups, used = [], set()
for i in range(len(questions)):
if i in used:
continue
sims = cosine_similarity(matrix[i], matrix).ravel()
members = [j for j in range(len(questions)) if sims[j] >= threshold and j not in used]
used.update(members)
groups.append([questions[j] for j in members])
return groups
if __name__ == '__main__':
qs = extract_questions('chat_export.txt')
result = cluster(qs)
# 按组内条数排序,优先处理高频问题
result.sort(key=len, reverse=True)
with open('question_groups.json', 'w', encoding='utf-8') as fh:
json.dump(result[:60], fh, ensure_ascii=False, indent=2)
print(f'问句 {len(qs)} 条 -> 候选组 {len(result)} 组,已输出前 60 组')
这个脚本的价值不在算法多精致,而在把"要不要做"变成了"每天合并 5 组"。粗聚类结果里必然有错分,所以输出的是候选组而不是最终结论,人工合并环节保留了。
3.2 第二步:答案撰写规范
答案质量决定引用质量。我们定了四条写作规则,都是踩过坑之后加的:
| 规则 | 反例 | 正例 |
|---|---|---|
| 先给结论 | "这个问题需要综合考虑……" | "建议选 X 系列,量程选 2mm 档。" |
| 给适用边界 | "适用所有工况" | "适用于金属外壳;塑料件建议 Y 系列。" |
| 参数只引用已验证值 | "精度很高" | "分辨率 0.01mm,重复精度 ±0.5%。" |
| 不写营销词 | "行业领先方案" | 直接写方案构成 |
审核流程上,我们没让市场部门单方面定稿,而是把每个答案拆成"技术判断"和"表述"两层:技术判断由产品工程师确认,表述由内容同学按上面的规则打磨。这样分工的好处是工程师只需要判断对错,不需要费心组织语言,审核通过率比让一个人从头写到尾高出不少。另一个实践细节是给每条答案标注适用型号与失效条件——当某个型号停产时,可以按 related_sku 一次性筛出需要更新的问答,避免官网长期挂着针对停产型号的建议。
3.3 第三步:入库与 Schema 输出
问答数据入库后,页面渲染层按类型输出对应 Schema。数据表结构:
| 字段 | 含义 | 说明 |
|---|---|---|
| question | 问题文本 | 与页面 H3 一致 |
| answer_html | 答案正文 | 服务端直出,禁止异步加载 |
| schema_type | FAQPage / QAPage | 决定输出哪类结构 |
| related_sku | 关联型号 | 用于实体关联 |
| reviewed_at | 审核时间 | 输出到 dateModified |
C# 侧的 Schema 组装按类型分派:
public sealed class QaSchemaBuilder
{
// 按类型分派:官方口径走 FAQPage,条件性建议走 QAPage
public object Build(QaItem item, string pageUrl)
{
return item.SchemaType switch
{
SchemaType.Faq => BuildFaq(item, pageUrl),
SchemaType.Qa => BuildQa(item, pageUrl),
_ => throw new NotSupportedException($"未知类型 {item.SchemaType}")
};
}
private static object BuildFaq(QaItem item, string pageUrl) => new
{
@context = "https://schema.org",
@type = "FAQPage",
mainEntity = new[]
{
new
{
@type = "Question",
name = item.Question,
acceptedAnswer = new { @type = "Answer", text = item.AnswerText }
}
},
dateModified = item.ReviewedAt.ToString("yyyy-MM-dd"), // 时效信号
url = pageUrl
};
private static object BuildQa(QaItem item, string pageUrl) => new
{
@context = "https://schema.org",
@type = "QAPage",
mainEntity = new
{
@type = "Question",
name = item.Question,
text = item.QuestionDetail,
answerCount = 1,
suggestedAnswer = new
{
@type = "Answer",
text = item.AnswerText,
upvoteCount = item.HelpfulCount, // 来自站内"有帮助"按钮的真实计数
dateCreated = item.ReviewedAt.ToString("yyyy-MM-dd")
}
},
url = pageUrl
};
}
有一处需要注意:upvoteCount 必须来自真实交互数据。填一个好看的固定值虽然不会立刻出事,但当引擎发现数值长期不变、与站内可见的互动数据对不上,可信度是会下降的。
3.4 第四步:给问答页做内链
问答页建成后如果没有任何入口,AI 爬虫很难发现它们。我们在产品详情页的"常见问题"区块、以及同型号的技术文章里做了双向内链:详情页链到问答页,问答页的答案里链回对应型号页。这条内链的价值不只在于抓取,更在于把问答结论与产品实体绑定,让引擎知道"这条建议是关于 X 系列的"。
四、上线数据
问答页上线 58 个(其中 QAPage 21 个、FAQPage 37 个),观察前后各 30 天:
| 指标 | 上线前 | 上线后 | 说明 |
|---|---|---|---|
| 站点被 AI 引用的事实片段/周 | 14 | 52 | 问答片段占新增的六成以上 |
| 选型类提问被正确回答的比例 | 12% | 47% | 人工抽检 60 题 |
| 售前咨询中重复问题占比 | 61% | 38% | 客户先查到了答案 |
| 问答页 AI 爬虫抓取占比 | — | 22% | 高于产品页 |
| 官网自然搜索落地页数 | 190 | 265 | 问答页带来了长尾 |
一个值得注意的细节:被引用最多的不是写得最详细的答案,而是结论前置、边界清晰的短答案。我们把答案按"结论 + 依据 + 边界"三段结构重写过一遍之后,引用量又有一次提升,说明结构化的表达方式本身就是可引用性的一部分。
还有一个数据侧的观察:问答页带来的搜索流量以长尾为主,单页峰值不高,但落地页数量从 190 增加到 265,长尾总量明显上涨。这类页面的收益曲线比较平缓,不像热点内容那样有单日峰值,适合按季度看总量而不是按周看排名。
五、误区与趋势
误区一:把客服话术直接搬到官网。 话术为了显得亲切会有大量铺垫和客套,这些内容在页面上是噪声。落到官网的必须是"结论 + 依据 + 边界"的紧凑句式。
误区二:把问答页做成动态加载的浮层。 见过不少站点把 FAQ 做成点击才展开、内容由接口异步拉的组件,对用户友好,对爬虫等于不存在。要么服务端直出全部答案,要么用 <details> 元素做展开——内容是直出的,只是默认折叠。
误区三:为覆盖关键词批量生成问答。 生成几百条重复语义的问答,短期看页面多了,长期看会稀释站点质量。我们的取舍是"少而准":58 个问答页,每个都对应真实重复出现的问题。
趋势上,问答型内容的引用价值还会继续上升,因为它是引擎最容易消费、最不需要推理的形态。技术上收个尾:选型问答的落地难点不在 Schema 怎么写,而在问题从哪来、答案谁审——把聊天记录变成问题池、把工程师的判断变成有边界的答案,这两步做扎实,结构化数据只是最后的输出动作。你们的行业里有哪些被反复问的问题还没上官网,欢迎在评论区聊聊。
参考与延伸
- Schema.org QAPage 类型定义:https://schema.org/QAPage
- Schema.org FAQPage 类型定义:https://schema.org/FAQPage
- Google 搜索中心:FAQ 结构化数据指南:https://developers.google.com/search/docs/appearance/structured-data/faqpage
- scikit-learn 文本特征提取文档:https://scikit-learn.org/stable/modules/feature_extraction.html
关键词:GEO 生成式引擎优化、AI 优化 AIO、QAPage、FAQPage、JSON-LD 结构化数据、选型问答、引用单元、语义聚类