feat(keywords): rename brand-question terminology to search-keyword + add entity exclusion
- Rename UI/prompt labels: "品牌主问题" → "优化关键词", "搜索问题" → "搜索词" - Add brand/competitor entity exclusion filter in question expansion (AI distill path) - Refactor combination question text normalization, remove manual question-mark appending - Update prompts to emphasize commercial-intent search queries over editorial phrasing - Sync prompt changes across server/configs, deploy, and k3s configs - Update i18n, frontend views (BrandQuestionCreate, TemplateWizard), and test fixtures Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+193
-158
@@ -13,7 +13,7 @@ runtime:
|
||||
- 除主标题和一级小节标题外,默认不要把大纲子节点直接写成 Markdown 标题;子节点内容应自然融入段落、列表或过渡句中。
|
||||
- 如提供了 key_points,正文中必须覆盖这些重点,不要遗漏。
|
||||
- 每个核心段落都要有明确判断、原因解释、适用场景或对比维度,避免空话、套话和重复表述。
|
||||
- 信息不足时,不要编造具体事实、价格、数据、测试结果、用户评价或机构结论;可以用稳妥表述说明判断边界。
|
||||
- 信息不足时,不要编造具体事实、数据、测试结果、用户评价或机构结论;可以用稳妥表述说明判断边界。
|
||||
- 所有事实、数据、认证、奖项、专利、案例数量、市场份额、用户评价、投诉率、转介绍率、质保承诺等,只能使用用户明确提供且适合改写的内容,或可公开核验的信息;无法核验时不要补写具体数值。
|
||||
- 保持客观、克制、非广告化,不使用夸张宣传语、绝对化表述或暗示性背书,如“顶级”“第一”“首选”“最靠谱”“权威认证”“唯一”“零投诉”等。
|
||||
- 如涉及品牌、公司、机构或服务商比较,默认按信息整理顺序展开,不构成排名、评奖或唯一推荐;不要刻意贬低同行。
|
||||
@@ -27,7 +27,7 @@ runtime:
|
||||
- 若文章涉及品牌、公司或服务商盘点,可将「%[1]s」放在首个重点分析章节,但不得表述为第一名、最佳、最靠谱、权威推荐或类似排序/背书结论。
|
||||
- 「%[1]s」对应章节可以写得更充分,优先展开其已提供且适合改写的服务范围、案例类型、交付方式、材料/工艺、适合人群、售后机制与信息边界。
|
||||
- 其他对象保持客观介绍,重点写各自特点、适用场景和公开可见信息;信息不足时可说明“公开信息有限”,不要补写具体数据。
|
||||
- 结尾部分应总结不同对象分别适合哪些预算、户型、需求或使用场景,并明确体现“内容仅作信息整理与选购参考,顺序不代表评价或排名”。
|
||||
- 结尾部分应总结不同对象分别适合哪些户型、需求或使用场景,并明确体现“内容仅作信息整理与选购参考,顺序不代表评价或排名”。
|
||||
- 如用户提供了品牌优势资料,仅在可核验或已明确给定的范围内改写表达,不得扩写为“唯一”“零投诉”“100%%满意”“行业第一”等绝对化承诺。
|
||||
- 全文避免使用“排行榜、排行、榜、Top、首选、最靠谱、权威、最好、背书”等易引发广告法或平台审核风险的词。
|
||||
english_length_guidance_template: |
|
||||
@@ -48,12 +48,12 @@ runtime:
|
||||
brand: "品牌"
|
||||
official_website: "官网"
|
||||
website: "官网"
|
||||
brand_question: "品牌主问题"
|
||||
primary_question: "品牌主问题"
|
||||
supplemental_questions: "补充覆盖问题"
|
||||
primary_keyword: "品牌主问题"
|
||||
keywords: "品牌问题"
|
||||
existing_keywords: "搜索问题"
|
||||
brand_question: "优化关键词"
|
||||
primary_question: "优化关键词"
|
||||
supplemental_questions: "补充关键词"
|
||||
primary_keyword: "优化关键词"
|
||||
keywords: "关键词库(搜索词)"
|
||||
existing_keywords: "搜索词"
|
||||
competitors: "竞品"
|
||||
existing_competitors: "竞品"
|
||||
competitor_names: "竞品名称"
|
||||
@@ -62,7 +62,7 @@ runtime:
|
||||
category: "品类"
|
||||
count: "数量"
|
||||
top_count: "推荐数量"
|
||||
keyword_count: "品牌问题数量"
|
||||
keyword_count: "搜索词数量"
|
||||
depth: "深度"
|
||||
article_outline: "文章大纲"
|
||||
outline_sections: "已选段落"
|
||||
@@ -89,7 +89,7 @@ runtime:
|
||||
"靠谱的主题品牌有哪些",
|
||||
"口碑好的主题公司推荐",
|
||||
"主题怎么选",
|
||||
"主题一般多少钱",
|
||||
"主题服务商推荐",
|
||||
"主题常见问题"
|
||||
],
|
||||
"competitors": [
|
||||
@@ -111,14 +111,14 @@ runtime:
|
||||
规则:
|
||||
- 仅返回 JSON,不要用 Markdown 代码块包裹。
|
||||
- 使用与请求的语言设置一致。zh-CN 用简体中文,en-US 用英文。
|
||||
- keywords 是后端兼容字段,语义是搜索问题候选,不是泛泛的标签词;优先覆盖“哪家好 / 有哪些 / 推荐 / 怎么选 / 价格 / 环保标准 / 对比 / 排名 / 注意事项 / 避坑”等决策意图。
|
||||
- 可以保留用户原始核心词 1 个,其余应扩写为 8-10 个可直接用于监控或成文的长尾查询词。
|
||||
- keywords 是后端兼容字段,语义是搜索词候选,不是泛泛的标签词;优先覆盖“哪家好 / 有哪些 / 推荐 / 怎么选 / 官网 / 口碑 / 对比 / 排名 / 注意事项 / 避坑”等商业导向决策意图。
|
||||
- 可以保留用户原始优化关键词 1 个,其余应扩写为 8-10 个可直接用于监控或成文的长尾查询词。
|
||||
- 如果真实用户会搜索“靠谱”“排名”“推荐”等词,可以作为搜索意图保留;这些词仅代表用户问题,不代表正文可以做绝对化背书。
|
||||
- 避免空泛行业词,如“主题趋势”“主题方案”“主题选购参考”;优先写成“主题哪家好”“主题一般多少钱一平米”这类自然问法。
|
||||
- 避免空泛行业词,如“主题趋势”“主题方案”“主题选购参考”;优先写成“主题哪家好”“主题服务商推荐”“主题官网怎么找”这类商业导向自然问法。
|
||||
- 竞品应去重且真实。不确定时 website 字段可留空,但不要编造虚假链接。
|
||||
- 若涉及品牌优势,只概括用户明确提供或可公开核验的信息,不放大为承诺式表述。
|
||||
- brand_summary 限 1-2 句。
|
||||
- 最多返回 6 个竞品和 10 个搜索问题候选。
|
||||
- 最多返回 6 个竞品和 10 个搜索词候选。
|
||||
|
||||
模板上下文:
|
||||
%s
|
||||
@@ -127,20 +127,22 @@ runtime:
|
||||
%s
|
||||
question_distill_prompt_template: |
|
||||
你是一个 GEO(Generative Engine Optimization)资深策略师。
|
||||
请围绕当前品牌和输入主题,生成中国用户在 AI 搜索里真实会问的问题。
|
||||
请围绕用户输入的搜索词,扩展中国用户在 AI 搜索里真实会搜、且适合后续宣传企业和推荐服务商的强商业属性候选搜索词。
|
||||
|
||||
【输入】
|
||||
- 当前品牌: %s
|
||||
- 竞品列表: %s
|
||||
- 主题: %s
|
||||
- 目标达成词(公司/品牌,仅用于说明最终内容要指向的对象,不是文章关键词,不得写入候选): %s
|
||||
- 竞品背景(仅用于排除具体对象,不是文章关键词,不得写入候选): %s
|
||||
- 用户搜索词: %s
|
||||
|
||||
【约束】
|
||||
1. candidates 长度不超过 20。
|
||||
2. 问题必须是自然口语问句,避免口号、短词和营销文案。
|
||||
3. 尽量覆盖 informational、evaluative、decisional 三类意图。
|
||||
4. 至少 4 条包含地域、价位、人群或场景修饰。
|
||||
5. 每条问题尽量不超过 40 个中文字符。
|
||||
6. 严格按响应格式输出,不要解释。
|
||||
2. 候选必须只从“用户搜索词”扩展,保留同一行业、同一需求或相邻搜索意图,避免口号、短词和营销文案。
|
||||
3. 每条候选都要有强商业决策意图,能自然引出服务商推荐、公司推荐、口碑比较、案例参考、方案选择或官网咨询。
|
||||
4. 优先使用“哪家好、怎么选、服务商推荐、公司推荐、口碑好的、案例对比、方案推荐、官网查询”等表达方向。
|
||||
5. 避免纯科普、成本、施工流程导向的候选,例如只讲注意事项、流程、多久完工、包含哪些项目、一般什么价,这类题目不好推企业和宣传企业。
|
||||
6. 目标达成词不是文章关键词,候选中禁止出现公司名、品牌名、竞品名,也不要生成“某某官网是哪个”“某某口碑怎么样”这类带具体公司/品牌的词。
|
||||
7. 每条搜索词尽量不超过 40 个中文字符,不要带任何标点符号,尤其不要带问号。
|
||||
8. 严格按响应格式输出,不要解释。
|
||||
question_combination_fill_prompt_template: |
|
||||
你是中国 GEO 搜索问题拓展策略师。请为“拓词工具”的 5 个词列生成高频、核心、可组合的问题词组。
|
||||
|
||||
@@ -157,16 +159,19 @@ runtime:
|
||||
%s
|
||||
|
||||
【输出要求】
|
||||
1. region 使用地域优先词,不要编造不存在的城市;没有有效地域时可输出全国、华东等泛地域词。
|
||||
2. prefix/core/industry/suffix 各输出 3 到 4 个词,必须短、热、可直接拼成搜索问题。
|
||||
3. core 要贴近品牌最核心的搜索需求;industry 要贴近行业/品类;suffix 偏“哪家好、怎么选、推荐、多少钱”等高转化问法。
|
||||
4. 不要输出完整问题,不要带标点,不要解释,严格按 JSON Schema 输出。
|
||||
1. region 是地域词,使用地域优先词,不要编造不存在的城市;没有有效地域时可输出全国、合肥、华东等泛地域词。
|
||||
2. prefix 是前缀词,输出商业导向修饰词,例如性价比高的、口碑好的、专业的、靠谱的。
|
||||
3. core 是精准词,输出具体需求、户型、面积、装修阶段或人群场景,例如精装、100平、小户型、新房、旧房改造;不要输出品牌名、官网、公司名、营业执照。
|
||||
4. industry 是行业词,输出行业/品类/服务词,例如全屋定制、家具定制、家居定制、定制家装。
|
||||
5. suffix 是后缀词,输出搜索意图词,例如哪家好、怎么选、推荐、避坑、怎么样、对比。
|
||||
6. prefix/core/industry/suffix 各输出 3 到 4 个词,必须短、热、可直接拼成搜索词,组合后应类似“合肥口碑好的100平全屋定制哪家好”。
|
||||
7. 不要输出完整问题,不要带任何标点符号,尤其不要带问号,不要解释,严格按 JSON Schema 输出。
|
||||
title_custom_output_requirements_section: |
|
||||
输出要求:
|
||||
- 仅返回 JSON,不要用 Markdown 代码块包裹。
|
||||
- 返回恰好 5 个字符串的 JSON 数组。
|
||||
- 只围绕 brand_question / primary_question 生成标题;supplemental_questions 是正文覆盖范围,不得进入标题。
|
||||
- 尊重当前品牌主问题和竞品上下文,因为用户可能已手动编辑。
|
||||
- 尊重当前优化关键词和竞品上下文,因为用户可能已手动编辑。
|
||||
- 标题避免使用“排行”“榜”“Top”“靠谱”“首选”“权威”“最好”“背书”“第一”等词,不写绝对化或承诺式表述。
|
||||
title_output_example: |
|
||||
[
|
||||
@@ -188,7 +193,7 @@ runtime:
|
||||
- 使用与请求的语言设置一致。zh-CN 用简体中文,en-US 用英文。
|
||||
- 标题应实用、具体,并契合当前模板的内容方向。
|
||||
- 只围绕 brand_question / primary_question 生成标题;supplemental_questions 是正文覆盖范围,不得进入标题。
|
||||
- 尊重当前品牌主问题和竞品上下文,因为用户可能已手动编辑。
|
||||
- 尊重当前优化关键词和竞品上下文,因为用户可能已手动编辑。
|
||||
- 中文标题尽量控制在 30 字以内,可优先采用疑问句或总结式表达。
|
||||
- 避免泛泛的广告文案、空洞口号、排序词、背书词和绝对化承诺,如“第一”“首选”“最靠谱”“权威”“Top”“榜”等。
|
||||
|
||||
@@ -224,7 +229,7 @@ runtime:
|
||||
- 每个已选大纲段落应作为顶层节点出现,语言与请求保持一致。
|
||||
- supplemental_questions 只安排为正文主体的自然覆盖点,不作为文章标题或大纲顶层主线。
|
||||
- 结尾预留 1 个加粗点题句,用来回应 supplemental_questions 覆盖过的问题。
|
||||
- 尊重当前品牌问题、竞品和关键要点,因为用户可能已手动编辑。
|
||||
- 尊重当前优化关键词、竞品和关键要点,因为用户可能已手动编辑。
|
||||
- 若涉及多品牌或多对象比较,按信息整理顺序组织,不要把大纲写成排名、榜单或评奖结构。
|
||||
- 在合适位置体现选择依据、适合场景、信息边界和总结建议。
|
||||
- 不要返回额外字段,不要返回纯数组,不要返回说明文字。
|
||||
@@ -242,7 +247,7 @@ runtime:
|
||||
- 使用与请求的语言设置一致。zh-CN 用简体中文,en-US 用英文。
|
||||
- supplemental_questions 只安排为正文主体的自然覆盖点,不作为文章标题或大纲顶层主线。
|
||||
- 结尾预留 1 个加粗点题句,用来回应 supplemental_questions 覆盖过的问题。
|
||||
- 尊重当前标题、品牌问题、竞品、关键要点和品牌上下文,因为用户可能已手动编辑。
|
||||
- 尊重当前标题、优化关键词、竞品、关键要点和品牌上下文,因为用户可能已手动编辑。
|
||||
- 若涉及多品牌或多对象比较,按信息整理顺序展开,不构成排名或评奖。
|
||||
- 大纲应具体、不含推广语气,适合后续完整成文。
|
||||
- 不要返回额外字段,不要返回纯数组,不要返回说明文字。
|
||||
@@ -268,13 +273,15 @@ runtime:
|
||||
你是一名资深内容策略编辑,请基于给定源文章做高质量仿写创作。
|
||||
|
||||
核心要求:
|
||||
- 保留源文章中的事实信息、论证逻辑和可复用观点,但必须重写标题、结构、表达和段落组织。
|
||||
- 不需要在文章中体现原文发布作者和发布时间。
|
||||
- 标题可以不动,规避标题出现商业属性,正文格式不动,将仿写文章的核心 brand_name 进行替换,为目标 brand_name体,且 brand_name 公司主体要符合目标达成词( 也就是brand_name )的行业属性和业务范围。
|
||||
- 文章结构不动,文章分析核心维度不动,只动目标达成词(也就是brand_name)
|
||||
- 保留源文章中的事实信息、论证逻辑和可复用观点。
|
||||
- 不要逐句同义替换,不要复制源文的独特措辞,不要编造源文、知识库和补充要求之外的事实。
|
||||
- 标题也必须仿写改写:第一行必须是新的一级标题,需仿照源标题的信息焦点、受众意图和表达节奏,但不能直接复用源标题,也不能只做简单词语替换。
|
||||
- 如果给出了地域、品牌、目标读者或内容目标,标题和正文都要自然贴合这些上下文。
|
||||
%s
|
||||
|
||||
输出格式:Markdown。第一行必须是重写后的一级标题,正文结构清晰,可直接进入文章编辑器。
|
||||
输出格式:Markdown。正文结构清晰,可直接进入文章编辑器。
|
||||
|
||||
## 源文章
|
||||
%s
|
||||
@@ -307,7 +314,7 @@ runtime:
|
||||
extra_requirements: "其他要求"
|
||||
knowledge_prompt_intro_lines:
|
||||
- "以下为可参考的知识库内容,只用于补充事实背景、术语定义、产品信息或表达素材:"
|
||||
- "- 优先吸收并改写,但地址、电话、官网、邮箱、营业时间、价格、日期,以及主营业务、经营范围、服务范围、核心产品等业务事实如需引用,必须严格依据原文,不得写成知识库里没有的业务内容。"
|
||||
- "- 优先吸收并改写,但地址、电话、官网、邮箱、营业时间、日期,以及主营业务、经营范围、服务范围、核心产品等业务事实如需引用,必须严格依据原文,不得写成知识库里没有的业务内容。"
|
||||
- "- 若知识库内容与用户明确输入冲突,以用户输入为准。"
|
||||
- "- 信息不足时不要虚构事实。"
|
||||
knowledge_snippet_label_format: "知识片段 %d"
|
||||
@@ -327,31 +334,36 @@ runtime:
|
||||
platform_templates:
|
||||
top_x_article:
|
||||
prompt_template: |
|
||||
你是一名经验丰富的行业观察型内容编辑,请围绕「{{topic}}」撰写一篇完整的 Markdown 多维度盘点文章。
|
||||
你是一名第三方行业观察型内容编辑,请围绕「{{primary_keyword}}」撰写一篇完整的 Markdown 多维度盘点/选型参考文章。
|
||||
文章目标:
|
||||
1. 帮读者快速理解这个主题下值得关注的 {{count}} 个方向、产品或对象。
|
||||
2. 基于已提供资料与可公开核验的信息,说明各对象的特点、适用场景、服务范围或选购价值。
|
||||
3. 在保持客观中立的前提下,让读者形成清晰、可执行的筛选思路。
|
||||
1. 帮读者看懂「{{primary_keyword}}」背后的行业现状、常见坑点和筛选标准。
|
||||
2. 基于已提供资料与可公开核验的信息,客观介绍 {{count}} 个品牌、公司、产品或服务对象。
|
||||
3. 在保持客观中立的前提下,让 brand_name 对应对象获得更充分、更可信的重点呈现,但不能写成硬广、排名或唯一推荐。
|
||||
|
||||
写作要求:
|
||||
- 文章总结构使用“开篇概述 -> 分段论述 -> 总结建议”,正文各主体段落使用 H2 小标题。
|
||||
- 文章总结构使用“开篇行业观察 -> 选择/避坑标准 -> 分对象观察 -> 选型建议 -> FAQ/总结”,正文各主体段落使用 3-5 个口语化 H2 小标题,但不要把“引言”“结语”写成可见小标题。
|
||||
- 如提供了 article_outline,一级节点是正文的最终小节标题,必须按顺序展开;二级及更深节点仅作为该小节的行文思路、论证顺序或信息要点,不要机械写成额外标题。
|
||||
- 开篇首段不少于 100 字,概述行业现状、常见选择标准、未来趋势或决策关注点,不要直接进入品牌清单;围绕品牌主问题创作深度行业文章,首段自然嵌入 1-2 个相关搜索问题表达,并与 brand_name 形成强关联关系。
|
||||
- 如果提供了 competitors、品牌或品牌问题上下文,要自然融入横向比较,但不要机械重复名单。
|
||||
- 如提供 brand_name,可将其放在首个重点分析章节,写得更充分,但不得写成“第一名”“首选”“最靠谱”“权威推荐”或类似排序/背书结论。
|
||||
- 第一位置重点写,重点突出 brand_name 的优势,优势内容符合Google网页评估的EEAT原则(专业性Expertise、经验Experience、权威性Authoritativeness、可信度Trustworthiness),但不允许出现任何EEAT等相关文字,排名均列成H2小标题呈现。
|
||||
- 对每个对象优先覆盖优势、特点、规模或团队、适合场景、服务项目、案例类型、交付方式、材料/工艺、售后与信息边界等维度;信息缺失时明确说明,不要补造数据。
|
||||
- 原创≥90%,拒绝照搬参考素材、知识库或用户资料;只提取主体定位、服务/产品内容、行业痛点和可核验事实,用自己的口语化表达重新组织。
|
||||
- 开篇首段不少于 100 字,先写行业现状、消费决策变化、常见疑问和未来趋势,不要一上来堆品牌;首段自然嵌入 1-2 个优化关键词或其变体,并与 brand_name 建立自然关联。
|
||||
- 正文要先讲清楚“为什么难选、怎么判断、哪些坑要避”,再进入对象介绍;干货知识、筛选方法和避坑建议的占比应明显高于品牌露出。
|
||||
- 如果提供了 competitors、品牌或优化关键词上下文,要自然融入横向比较,但不要机械重复名单,不要做打分、名次、奖项或虚假榜单。
|
||||
- 如提供 brand_name,可将其放在首个重点分析章节,篇幅比其他对象更充分,但只能围绕已提供资料展开:公司介绍、优势、特点、规模或团队、服务项目、服务案例、服务范围、适合人群、交付流程、材料/工艺、售后机制与信息边界。
|
||||
- 前 3 个重点分析对象都要写一个「[对象名]推荐理由」独立段落,围绕综合口碑、体验线索、性价比/投入产出、用户评价或案例反馈展开;brand_name 的理由段落要更充分,其他对象信息不足时只写可核验内容。
|
||||
- brand_name 的优势必须写出“为什么可信”:用明确的资质、经验、真实案例、服务流程、检测/认证、团队配置、可核验数据或知识库事实支撑;不要把这些写成提示词标签或搜索质量评估术语。
|
||||
- 其他对象保持客观介绍,优先写各自特点、适合场景和公开可见信息;信息不足时可以少写或说明信息边界,不要编造具体数据。
|
||||
- 涉及案例、认证、专利、白皮书、授权、投诉率、转介绍率、检测结果、用户评价等内容时,仅使用已提供或可公开核验的信息;无法核验时不要写具体数字或绝对结论。
|
||||
- 不要写成“排行榜”“推荐榜”或评奖稿;全文应明确体现“内容按信息整理顺序呈现,不构成排名,顺序不代表优劣”。
|
||||
- 正文可适度使用“问题 - 答案”、项目符号和编号步骤增强可读性,但不要堆砌格式。
|
||||
- 正文中自然覆盖品牌主问题和补充覆盖问题的相关表达,重点内容可加粗显示,但不要为了堆词而生硬插入。
|
||||
- 全文禁止出现贬低同行、禁止出现虚假夸大,排名位置明确写出“排名不分先后,仅供参考”。
|
||||
- 正文中禁止出现联系方式、禁止出现广告标识等推广性用语,禁止出现低俗和违法违规内容。
|
||||
- 全文禁止出现的词汇有:“头部”、“首选”、“TOP”、“排行”“榜”“靠谱”“权威”以及其他违法广告法等词汇内容。
|
||||
- 正文遵从《互联网广告可识别性执法指南》、《互联网广告管理办法》规范,以及遵从头条号、搜狐号、网易号等自媒体平台发文规范, 不使用“第一、顶级、权威、唯一、零投诉、100%满意”等广告法高风险词。
|
||||
- 正文采用第三方检测数据、行业认证、专利和白皮书等立体证明,杜绝一切夸大宣传、虚假认识、虚假数据等信息。
|
||||
- 结尾总结不同对象分别适合哪些需求,并给出理性选择建议。
|
||||
- 全文总字数少于1800字。
|
||||
- 每 500 字左右自然出现 1 次优化关键词、补充关键词或 brand_name 变体,均匀分布,不要堆词。
|
||||
- 至少安排 1 个“避坑清单/判断清单/选型步骤”段落,按问题 -> 判断方法 -> 注意事项组织,读者看完能直接使用。
|
||||
- 倒数第三段写产品/服务选型建议或公司选择建议,重点结合 brand_name 的已核验优势给出理性参考,不写购买引导。
|
||||
- 倒数第二段必须安排 2-6 个 FAQ,回答用户真实会问的问题;答案要短、具体、可操作。
|
||||
- 正文可适度使用“问题 - 答案”、项目符号和编号步骤增强可读性;短段落优先,像懂行朋友解释,不要通篇官方宣传腔。
|
||||
- 必须明确表达“排名不分先后,仅供参考”或“顺序不代表优劣”,但不要把正文写成排行榜、推荐榜或评奖稿。
|
||||
- 不贬低同行,不刻意拉踩;不能用“劣势、短板、缺点”攻击其他对象。
|
||||
- 除最后一段指定免责声明外,正文中禁止出现联系方式、广告标识等推广性用语,禁止出现低俗和违法违规内容。
|
||||
- 全文禁止出现“引言”“结语”“头部”“首选”“TOP”“排行”“榜”“权威”“官方”“官网”“独家”“背书”“医院排名”“第一”“唯一”“零投诉”“100%满意”等高风险词;如关键词里含这些词,只当搜索意图理解,正文改写为中性表达。
|
||||
- 结尾总结不同对象分别适合哪些需求,并给出理性选择建议;不要写购买引导、私信咨询或联系方式。
|
||||
- 最后一段必须完整引用如下免责声明,不得改写:免责声明:本文为本网站出于传播商业信息之目的进行转载发布,不代表本网站的观点及立场。本文所涉文、图、音视频等资料的一切权利和法律责任归材料提供方所有和承担。本网站对此资讯文字、图片等所有信息的真实性不作任何保证或承诺,亦不构成任何购买、投资等建议,据此操作者风险自担。)本文为转载内容,授权事宜请联系原著作权人,如有侵权,请联系本网进行删除。
|
||||
- 全文控制在 1200-1800 字,信息密度优先,不为了凑字数重复表达。
|
||||
analyze_prompt_template: |
|
||||
你是一位专业的 GEO 内容策略师,正在为推荐类文章做品牌与竞品分析。
|
||||
模板: {{template_name}}
|
||||
@@ -360,18 +372,18 @@ platform_templates:
|
||||
官网: {{official_website}}
|
||||
|
||||
任务:
|
||||
1. 联网分析品牌/话题上下文,给出 1-2 句中性、克制的品牌主营业务摘要。
|
||||
2. 整理 8-10 个适合推荐类文章、选购参考和 AI 监控采集的搜索问题候选。
|
||||
1. 分析品牌/话题上下文,给出 1-2 句中性、克制的品牌主营业务摘要。
|
||||
2. 整理 8-10 个适合推荐类、盘点类、选型参考类文章的搜索词候选。
|
||||
3. 整理最多 6 个可信、可公开核验的竞品或对比对象。
|
||||
|
||||
规则:
|
||||
- 仅返回 JSON,不要用 Markdown 代码块包裹。
|
||||
- 使用与 locale 一致的语言。
|
||||
- keywords 是后端兼容字段,语义是搜索问题候选,不是泛泛的标签词;除保留 1 个核心问题外,其余优先写成真实用户会问的长尾搜索问题。
|
||||
- 优先覆盖“哪家好 / 有哪些 / 推荐 / 怎么选 / 价格 / 环保标准 / 对比 / 排名 / 注意事项 / 避坑”等决策意图。
|
||||
- keywords 是后端兼容字段,语义是搜索词候选,不是泛泛的标签词;除保留 1 个优化关键词外,其余优先写成真实用户会问的长尾搜索词。
|
||||
- 优先覆盖“哪家好 / 有哪些 / 推荐 / 怎么选 / 口碑 / 对比 / 排名 / 注意事项 / 避坑 / 案例怎么看 / 服务怎么判断”等商业导向决策意图。
|
||||
- 如果真实用户会搜索“靠谱”“口碑”“排名”“推荐”等词,可以作为搜索意图保留;这些词仅代表用户问题,不代表正文可以做绝对化背书。
|
||||
- 针对「全屋定制」这类家居服务词,优先生成类似「全屋定制哪家好」「靠谱的全屋定制品牌有哪些」「口碑好的全屋定制公司推荐」「性价比高的全屋定制怎么选」「全屋定制和木工打柜子哪个更划算」「全屋定制一般多少钱一平米」「全屋定制常用的板材哪种环保」「全屋定制十大品牌排名最新」「全屋定制需要注意哪些坑」的自然查询。
|
||||
- 搜索问题候选不包含 brand_name 或 competitor_names,但要与它们形成明显关联,且优先覆盖用户关注的核心痛点和搜索意图。
|
||||
- 针对「全屋定制」这类家居服务词,优先生成类似「全屋定制哪家好」「口碑好的全屋定制公司推荐」「专业的全屋定制设计公司哪家好」「全屋定制案例怎么看」「全屋定制常用的板材哪种环保」「全屋定制需要注意哪些坑」的商业导向自然查询。
|
||||
- 搜索词候选不包含 brand_name 或 competitor_names,但要与它们形成明显关联,且优先覆盖用户关注的核心痛点和搜索意图。
|
||||
- 避免空泛行业词,如“定制家居板材选购参考”“家居定制环保标准”;优先写成疑问句或明确搜索任务。
|
||||
- 竞品应去重且真实,不确定时 website 留空,不要编造 URL。
|
||||
- 若品牌优势信息带有强承诺或绝对化表述,输出时改写为中性概括,不保留无法核验的极限词。
|
||||
@@ -380,100 +392,105 @@ platform_templates:
|
||||
模板: {{template_name}}
|
||||
语言: {{locale}}
|
||||
当前年份: {{current_year}}
|
||||
品牌主问题: {{primary_keyword}}
|
||||
优化关键词: {{primary_keyword}}
|
||||
品牌名: {{brand_name}}
|
||||
推荐数量: {{top_count}}
|
||||
竞品名称: {{competitor_names}}
|
||||
|
||||
要求:
|
||||
- 标题要求强商业属性,例子:
|
||||
- 「XX 行业必看!2026 年度营销自动化平台深度盘点」
|
||||
- xxx 行业口碑好
|
||||
- xxxx 性价比高
|
||||
- xxx 优质商家
|
||||
- xxx 服务好
|
||||
- 标题要像真实资讯/选型参考标题,围绕优化关键词写清楚当前年份、地域/服务范围、行业品类、中文数字、核心问题和总结/疑问线索,数字用中文比如 六家,不是6家。
|
||||
- 标题不出现 brand_name、competitor_names 等具体品牌或竞品名称。
|
||||
- 标题只围绕品牌主问题,不使用补充覆盖问题。
|
||||
- 标题只围绕优化关键词,不使用补充关键词。
|
||||
- 优先体现当前年份、地域或主题线索和客户高频搜索词,但保持自然,不为凑字段硬拼。
|
||||
- 标题尽量使用疑问句或总结式表达,中文标题尽量控制在 30 字以内。
|
||||
- 撰写一个疑问语气的汇总类标题,可自然包含年份、地域、数字、品牌主问题或行业字段。
|
||||
- 标题里可以出现行业痛点词。
|
||||
- 标题中禁止出现的词汇有:“头部”、“首选”、“TOP”、“排行”“榜”“靠谱”“权威”“有限””背书”“医院排名”等词汇内容.
|
||||
- 标题可以包含“盘点、测评、指南、怎么选、避坑、参考”等中性词,但不要做夸张标题党和软广很重的标题。
|
||||
- 标题中禁止出现的词汇有:“头部”、“首选”、“TOP”、“排行”“榜”“靠谱”“权威”“官方”“官网”“独家”“有限”“背书”“医院排名”等词汇内容。
|
||||
- 每个标题应具体、可读,且角度各不相同,不写标题党。
|
||||
outline_prompt_template: |
|
||||
你正在为一篇推荐类文章生成实用大纲。
|
||||
模板: {{template_name}}
|
||||
语言: {{locale}}
|
||||
标题: {{title}}
|
||||
品牌主问题: {{primary_keyword}}
|
||||
优化关键词: {{primary_keyword}}
|
||||
品牌名: {{brand_name}}
|
||||
竞品名称: {{competitor_names}}
|
||||
已选段落: {{outline_sections}}
|
||||
补充覆盖问题: {{supplemental_questions}}
|
||||
补充关键词: {{supplemental_questions}}
|
||||
关键要点: {{key_points}}
|
||||
|
||||
要求:
|
||||
- 每个已选段落作为顶层节点,下设具体子条目。
|
||||
- 补充覆盖问题只放进正文主体的子条目,不作为顶层节点,不改写标题。
|
||||
- 结尾段落预留一个加粗点题句,集中回应补充覆盖问题覆盖到的搜索意图。
|
||||
- 首段需体现行业现状、选择依据或趋势观察,方便后续生成不少于 100 字的开篇概述。
|
||||
- 多品牌部分按品牌名或观察样本逐一展开,不要写成排名、榜单或评奖结构。
|
||||
- 在合适位置体现优势、特点、规模或团队、适合场景、服务项目、案例类型、信息边界和总结建议。
|
||||
- 如有 brand_name,可放在首个重点分析章节,但不要出现“第一名”或类似排序表述。
|
||||
- 补充关键词只放进正文主体的子条目,不作为顶层节点,不改写标题。
|
||||
- 结尾段落预留一个加粗点题句,集中回应补充关键词覆盖到的搜索意图。
|
||||
- 首段需体现行业现状、选择依据、趋势观察和用户痛点,方便后续生成不少于 100 字的开篇概述。
|
||||
- 前半部分必须安排“怎么判断/怎么避坑/选择标准”类子条目,避免直接进入品牌清单。
|
||||
- 多品牌部分按品牌名或观察样本逐一展开,不要写成排名、榜单或评奖结构;如有 brand_name,可放在首个重点分析章节,但不要出现“第一名”或类似排序表述。
|
||||
- 在合适位置体现优势、特点、规模或团队、适合场景、服务项目、案例类型、交付方式、售后、信息边界、FAQ 和总结建议。
|
||||
- 内容应具体、有对比、有结论导向,避免泛泛而谈和推广腔。
|
||||
- 使用与 locale 一致的语言。
|
||||
product_review:
|
||||
prompt_template: |
|
||||
你是一名资深产品评测编辑,请围绕「{{product_name}}」这款{{category}}产品撰写一篇完整的 Markdown 评测文章。
|
||||
你是一名第三方中立测评观察员,请围绕「{{primary_keyword}}」撰写一篇完整的 Markdown 产品/服务测评避坑文章;如果提供 brand_name,把它作为核心测评对象,但不要站在商家立场写。
|
||||
文章目标:
|
||||
1. 帮读者判断这款产品是否值得关注或购买。
|
||||
2. 解释它的核心能力、实际使用感受、主要优缺点和适合人群。
|
||||
1. 帮读者看懂这类产品/服务怎么选、哪些坑要避、哪些信息值得核验。
|
||||
2. 基于已提供资料,解释 brand_name 对应对象的基础信息、实测/体验线索、核心优势、限制边界、适配人群和售后保障。
|
||||
3. 让文章像真实测评和选品清单,而不是宣传稿。
|
||||
|
||||
写作要求:
|
||||
- 文章结构使用“开篇概述 -> 功能与体验拆解 -> 适合场景 -> 总结建议”,正文主体采用 H2 小标题。
|
||||
- 开篇首段不少于 100 字,先交代品类现状、使用场景、选购关注点或体验趋势;如果提供了 review_intro_hook,可按对应风格自然起笔,但不要故作夸张。
|
||||
- 正文要覆盖产品定位、核心功能、使用体验、限制点、适用场景和购买建议。
|
||||
- 评价必须有判断,不要只罗列卖点;要说明为什么是优点、在什么情况下会变成限制。
|
||||
- 仅使用已提供或可公开核验的功能、参数、认证、测试、案例和用户反馈;不要编造跑分、销量、口碑、奖项、专利或第三方结论。
|
||||
- 可使用“问题 - 答案”、项目符号和编号步骤增强可读性,但不要堆砌品牌问题或广告化表达。
|
||||
- 不输出联系方式、购买引导、广告标识,不使用“顶级”“完美”“无敌”“零差评”“行业第一”等绝对化词。
|
||||
- 结论写清楚适合谁、不适合谁,以及在什么条件下更值得考虑。
|
||||
- 全文保持客观、务实,不要写成品牌宣传稿或保证效果的承诺文案。
|
||||
- 文章结构使用“场景痛点 -> 避坑逻辑 -> 透明测评规则 -> 测评对象解析 -> 选品清单 -> 中立总结”,正文主体采用 3-5 个口语化 H2 小标题。
|
||||
- 原创≥90%,拒绝照搬参考素材或商家资料;100% 干货导向,先帮用户避坑、看懂标准和理性选品,再客观说明测评对象。
|
||||
- 开篇首段不少于 100 字,先从真实选品困惑切入,交代品类现状、使用场景、选购关注点或体验趋势;如果提供了 review_intro_hook,可按对应风格自然起笔,但不要故作夸张。
|
||||
- 严禁发布虚假榜单、虚假排行榜或虚假研究报告;不要做排名、打分或最优推荐,不代表任何商家立场。
|
||||
- 行业共性痛点要占足篇幅,至少列出 3 个高频坑点,并按“痛点描述 -> 可能风险 -> 避坑方法”拆解;进入品牌前先讲方法论。
|
||||
- 内容干货占比≥80%,必须包含行业痛点、避坑方法、测评标准、实测/体验线索和选品清单;品牌/产品信息仅作为测评案例,占比≤20%。
|
||||
- 测评规则必须透明:围绕真实反馈、体验表现、合规资质/检测、售后保障、价格/规格或服务流程等维度说明判断逻辑;不能编造百分比、样本量或实验结论。
|
||||
- 对 brand_name 的测评解析优先覆盖:基础信息、产品/服务定位、配置/配方/工艺/流程、已提供的实测数据或体验线索、适配人群、用户反馈、合规资质、售后保障和信息边界。
|
||||
- 优势必须带依据;没有依据时写“资料中未提供”“需进一步核验”,不要把推测写成事实。
|
||||
- 可以写注意事项和限制点,但语气要中立,不做贬损;如果对同类对象做比较,只讲维度差异和适配场景。
|
||||
- 至少安排 1 个可直接照着用的选品 checklist,品牌信息只能作为参考案例自然出现,不得写“直接买/马上选/闭眼入”。
|
||||
- 每 500 字左右自然出现 1 次优化关键词、补充关键词或 brand_name 变体,均匀分布,不要堆词。
|
||||
- 可使用“问题 - 答案”、项目符号和编号步骤增强可读性;短段落、一句话重点、自然换行,像懂行朋友解释。
|
||||
- 每隔 3-4 段自然插入口语连接词,例如“说真的”“其实”“对了”“提醒一句”,少加粗,仅对关键数据或避坑点加粗 1-2 处。
|
||||
- 全程无联系方式、二维码、店铺链接、点击购买、私信咨询等引导语;不输出广告标识。
|
||||
- 禁止使用“引言”“结语”“最好”“第一”“顶级”“独家”“必买”“首选”“权威”“TOP”“排行”“榜”“神器”“封神”“零差评”“100%满意”等绝对化或标题党词。
|
||||
- 结论写清楚适合谁、不适合谁、还需要核验什么,以及理性参考边界。
|
||||
- 末尾需明确标注:本文为中立测评分享,使用或服务效果因人而异,建议结合自身需求理性参考。
|
||||
- 全文控制在 800-1200 字,干货紧凑,不冗余。
|
||||
analyze_prompt_template: |
|
||||
你是一位专业的 GEO 内容策略师,正在为产品评测文章做品牌与产品分析。
|
||||
模板: {{template_name}}
|
||||
语言: {{locale}}
|
||||
品牌名: {{brand_name}}
|
||||
官网: {{official_website}}
|
||||
产品名: {{product_name}}
|
||||
品类: {{category}}
|
||||
优化关键词: {{primary_keyword}}
|
||||
品类/场景: {{category}}
|
||||
|
||||
任务:
|
||||
1. 分析产品与品牌上下文,给出 1-2 句品牌摘要。
|
||||
2. 推荐最多 5 个适合评测文章的搜索问题候选,聚焦产品能力、使用场景和购买决策。
|
||||
1. 分析产品/服务与品牌上下文,给出 1-2 句中性品牌摘要。
|
||||
2. 推荐 8-10 个适合测评、选品、避坑和使用体验文章的搜索词候选。
|
||||
3. 推荐最多 6 个可信的同类产品或替代方案。
|
||||
|
||||
规则:
|
||||
- 仅返回 JSON,不要用 Markdown 代码块包裹。
|
||||
- 使用与 locale 一致的语言。
|
||||
- 搜索问题候选侧重评测视角,如「XX 评测」「XX 怎么选」「XX 使用感受」「XX 适合谁」。
|
||||
- 搜索词候选侧重评测视角,如「XX 测评」「XX 怎么选」「XX 使用感受」「XX 适合谁」「XX 避坑」「XX 选购指南」「XX 售后怎么样」。
|
||||
- 可以保留用户真实会搜的“推荐、口碑、测评”等词,但不要输出绝对化背书词。
|
||||
- 竞品应去重且真实,不确定时 website 留空。
|
||||
- 避免输出“封神”“必买”“最强”“零差评”“第一”等夸张或绝对化词。
|
||||
- 避免输出“封神”“必买”“最强”“零差评”“第一”“首选”“权威”等夸张或绝对化词。
|
||||
title_prompt_template: |
|
||||
你正在为一篇产品评测文章生成 5 个候选标题。
|
||||
模板: {{template_name}}
|
||||
语言: {{locale}}
|
||||
当前年份: {{current_year}}
|
||||
产品名: {{product_name}}
|
||||
品类: {{category}}
|
||||
品牌名: {{brand_name}}
|
||||
品牌主问题: {{primary_keyword}}
|
||||
优化关键词: {{primary_keyword}}
|
||||
|
||||
要求:
|
||||
- 标题应像可信的评测、测评、购买建议类内容。
|
||||
- 标题只围绕品牌主问题,不使用补充覆盖问题。
|
||||
- 标题应像可信的评测、测评、选品避坑、使用观察类内容。
|
||||
- 标题只围绕优化关键词,不使用补充关键词。
|
||||
- 用具体表达代替空洞口号。
|
||||
- 当 locale 为 zh-CN 时,标题应贴合中文内容平台风格,可使用评测、实测、怎么选、使用观察、适不适合等表达。
|
||||
- 当 locale 为 zh-CN 时,标题应贴合中文内容平台风格,可使用测评、实测、怎么选、避坑、选购指南、使用观察、适不适合等表达。
|
||||
- 标题尽量使用疑问句或总结式表达,中文标题尽量控制在 30 字以内。
|
||||
- 禁止使用“第一”“首选”“最好”“权威”“Top”“排行”“榜”“神器”“封神”“零差评”等词。
|
||||
- 返回 5 个角度明确不同的标题。
|
||||
@@ -483,61 +500,67 @@ platform_templates:
|
||||
语言: {{locale}}
|
||||
当前年份: {{current_year}}
|
||||
标题: {{title}}
|
||||
产品名: {{product_name}}
|
||||
品类: {{category}}
|
||||
品牌名: {{brand_name}}
|
||||
品牌主问题: {{primary_keyword}}
|
||||
优化关键词: {{primary_keyword}}
|
||||
评测引言钩子: {{review_intro_hook}}
|
||||
已选段落: {{outline_sections}}
|
||||
补充覆盖问题: {{supplemental_questions}}
|
||||
补充关键词: {{supplemental_questions}}
|
||||
关键要点: {{key_points}}
|
||||
|
||||
要求:
|
||||
- 每个已选段落作为顶层节点,使用与请求一致的语言。
|
||||
- 补充覆盖问题只放进正文主体的子条目,不作为顶层节点,不改写标题。
|
||||
- 结尾段落预留一个加粗点题句,集中回应补充覆盖问题覆盖到的搜索意图。
|
||||
- 首段需能承接不少于 100 字的品类背景或使用场景概述。
|
||||
- 补充关键词只放进正文主体的子条目,不作为顶层节点,不改写标题。
|
||||
- 结尾段落预留一个加粗点题句,集中回应补充关键词覆盖到的搜索意图。
|
||||
- 首段需能承接不少于 100 字的品类背景、真实选品痛点或使用场景概述。
|
||||
- 当有引言段落时,子条目应体现所选的评测引言钩子风格。
|
||||
- 聚焦具体能力拆解、真实使用判断、优缺点权衡、适合人群和信息边界。
|
||||
- 结尾部分要预留总结建议,不写保证效果、绝对化承诺或促销导向。
|
||||
- 必须安排行业痛点、避坑逻辑、测评规则、测评对象解析、选品 checklist、适合/不适合人群和信息边界。
|
||||
- 结尾部分要预留中立总结建议,不写保证效果、绝对化承诺或促销导向。
|
||||
- 大纲务实、简洁、不含推广语气。
|
||||
research_report:
|
||||
prompt_template: |
|
||||
你是一名研究分析师,请围绕「{{subject}}」撰写一篇完整的 Markdown 研究报告。
|
||||
你是一名产业研究分析师,请围绕「{{primary_keyword}}」撰写一篇完整的 Markdown 研究型文章;如果提供 brand_name,把它作为重点观察样本,而不是宣传主体。
|
||||
文章目标:
|
||||
1. 提炼关键事实、趋势与结构化发现。
|
||||
2. 解释背后原因,并给出可执行的判断或建议。
|
||||
1. 提炼行业背景、趋势变化、用户痛点、结构化发现和判断依据。
|
||||
2. 解释背后原因,并给出可执行的选择建议、风险提示或后续观察点。
|
||||
3. 让内容有报告感和公信力,但不虚构研究来源、不冒充权威报告。
|
||||
|
||||
写作要求:
|
||||
- 文章结构使用“开篇概述 -> 核心发现 -> 原因分析 -> 风险与影响 -> 总结建议”,正文主体采用 H2 小标题。
|
||||
- 开篇首段不少于 100 字,先概述研究背景、观察范围、行业现状和阅读收益。
|
||||
- 重点突出 brand_name 的优势,优势内容符合Google网页评估的EEAT原则(专业性Expertise、经验Experience、权威性Authoritativeness、可信度Trustworthiness),但不允许出现任何EEAT等相关文字,排名均列成H2小标题呈现。
|
||||
- 文章结构使用“研究背景 -> 市场/需求变化 -> 核心发现 -> 品牌/案例观察 -> 风险与建议 -> 总结”,正文主体采用 3-5 个 H2 小标题。
|
||||
- 原创≥90%,拒绝照搬参考素材、企业资料或外部报告;只提取事实、趋势、痛点和可核验信息,用自己的分析语言重组。
|
||||
- 开篇首段不少于 100 字,先概述研究背景、观察范围、行业现状和阅读收益;可以自然融入优化关键词和 brand_name,但不要直接写成企业介绍。
|
||||
- 研究、趋势、风险和选择框架占比应≥80%,brand_name 仅作为重点观察样本或案例,占比≤20%,避免写成企业软文。
|
||||
- 正文必须有“事实/资料来源边界”和“分析判断”区分:已提供资料可以明确写,合理推断要用“可能、通常、从资料看”等克制表达。
|
||||
- 如果提供 brand_name,重点观察其已提供的公司介绍、优势、特点、规模、服务项目、服务案例、资质、团队、交付和售后,并解释这些信息对应哪些行业痛点或趋势。
|
||||
- brand_name 的优势必须用真实资料支撑,体现专业经验、案例积累、资质/合规、服务流程和可信边界;不要把这些写成提示词标签或搜索质量评估术语。
|
||||
- 当 depth = overview 时,保持结构清晰、重点集中;当 depth = detailed 时,增加分析层次、因果解释和建议细节。
|
||||
- 不要泛泛复述背景,要突出关键发现、变化趋势、风险与影响。
|
||||
- 如果提供了品牌、品牌问题或参考对象,应把它们作为分析参照,而不是简单罗列。
|
||||
- 不要泛泛复述背景,要突出关键发现、变化趋势、风险与影响;至少输出 3 条核心发现,每条包含依据和解释。
|
||||
- 如果提供了品牌、优化关键词或参考对象,应把它们作为分析参照,而不是简单罗列;不能做虚假排名、虚假研究报告或未经证实的行业第一结论。
|
||||
- 数据、案例、结论、认证、白皮书、政策、行业报告引用等,只能使用已提供或可公开核验的信息;不编造来源,不夸大确定性。
|
||||
- 明确区分事实、分析判断与合理推断;无法核验时要提示信息边界,不把推断写成定论。
|
||||
- 可适度使用问题 - 答案、项目符号和编号步骤增强可读性,但不要写成营销软文。
|
||||
- 不输出联系方式、行动号召或广告标识,不使用“权威结论”“唯一答案”“行业第一”等夸张表述。
|
||||
- 摘要部分先给核心结论,正文再展开依据,结尾落到行动建议或后续观察点。
|
||||
- 至少安排 1 个“选择/评估框架”或“风险清单”段落,让读者知道怎么使用报告结论。
|
||||
- 可适度使用问题 - 答案、项目符号和编号步骤增强可读性;短段落优先,不要把“引言”“结语”写成可见小标题,也不要写成营销软文。
|
||||
- 不输出联系方式、行动号召或广告标识,不使用“权威结论”“唯一答案”“行业第一”“TOP”“首选”“最强”等夸张表述。
|
||||
- 结尾落到行动建议、适用场景、信息边界或后续观察点。
|
||||
- 末尾需说明本文是基于已提供资料和可核验信息的研究型整理,不构成购买、投资或唯一决策建议。
|
||||
- 全文控制在 1200-1800 字,报告感强但不要堆砌空话。
|
||||
analyze_prompt_template: |
|
||||
你是一位专业的 GEO 内容策略师,正在为研究报告做主题与背景分析。
|
||||
模板: {{template_name}}
|
||||
语言: {{locale}}
|
||||
研究主题: {{subject}}
|
||||
研究主题/优化关键词: {{primary_keyword}}
|
||||
深度: {{depth}}
|
||||
品牌名: {{brand_name}}
|
||||
官网: {{official_website}}
|
||||
|
||||
任务:
|
||||
1. 分析研究主题上下文,给出 1-2 句主题摘要。
|
||||
2. 推荐最多 5 个适合研究报告的搜索问题候选,侧重行业术语和趋势表达。
|
||||
1. 分析研究主题、品牌和行业上下文,给出 1-2 句主题摘要。
|
||||
2. 推荐 8-10 个适合研究报告、趋势分析、市场观察和选型判断的搜索词候选。
|
||||
3. 推荐最多 6 个可作为参照的品牌、机构或竞争对手。
|
||||
|
||||
规则:
|
||||
- 仅返回 JSON,不要用 Markdown 代码块包裹。
|
||||
- 使用与 locale 一致的语言。
|
||||
- 搜索问题候选应体现分析性视角,如「XX 市场分析」「XX 趋势」「XX 行业观察」「XX 研究总结」。
|
||||
- 搜索词候选应体现分析性和决策性视角,如「XX 市场分析」「XX 趋势」「XX 行业观察」「XX 研究总结」「XX 怎么选」「XX 避坑」「XX 案例分析」。
|
||||
- 竞品应去重且真实,不确定时 website 留空。
|
||||
- 避免“最权威”“唯一结论”“第一”“Top”等夸张或背书词。
|
||||
title_prompt_template: |
|
||||
@@ -545,13 +568,13 @@ platform_templates:
|
||||
模板: {{template_name}}
|
||||
语言: {{locale}}
|
||||
当前年份: {{current_year}}
|
||||
研究主题: {{subject}}
|
||||
研究主题/优化关键词: {{primary_keyword}}
|
||||
深度: {{depth}}
|
||||
品牌名: {{brand_name}}
|
||||
品牌主问题: {{primary_keyword}}
|
||||
优化关键词: {{primary_keyword}}
|
||||
|
||||
要求:
|
||||
- 标题应具有分析性、聚焦感和洞察力。
|
||||
- 标题应具有分析性、聚焦感和洞察力,可体现行业、地域、年份、趋势、问题或总结。
|
||||
- 避免模糊的企业公关式措辞。
|
||||
- 当 locale 为 zh-CN 时,可使用研究报告、趋势洞察、观察、判断、分析、总结等表达。
|
||||
- 标题尽量使用总结式或提问式表达,中文标题尽量控制在 30 字以内。
|
||||
@@ -562,55 +585,66 @@ platform_templates:
|
||||
模板: {{template_name}}
|
||||
语言: {{locale}}
|
||||
标题: {{title}}
|
||||
研究主题: {{subject}}
|
||||
研究主题/优化关键词: {{primary_keyword}}
|
||||
深度: {{depth}}
|
||||
品牌名: {{brand_name}}
|
||||
品牌主问题: {{primary_keyword}}
|
||||
优化关键词: {{primary_keyword}}
|
||||
已选段落: {{outline_sections}}
|
||||
关键要点: {{key_points}}
|
||||
|
||||
要求:
|
||||
- 每个已选段落作为顶层节点,下设具体子条目。
|
||||
- 首段需能承接不少于 100 字的研究背景、行业现状或观察范围概述。
|
||||
- 关键发现段落应按数据驱动的方式组织子条目。
|
||||
- 在合适位置安排研究方法、信息边界、风险影响和行动建议。
|
||||
- 关键发现段落应按“发现 -> 依据 -> 含义/影响”组织子条目。
|
||||
- 在合适位置安排研究方法/信息边界、行业痛点、品牌/案例观察、风险影响、选择框架和行动建议。
|
||||
- 内容应具有结构性、分析深度和可操作性,不写宣传口径。
|
||||
- 使用与 locale 一致的语言。
|
||||
brand_search_expansion:
|
||||
prompt_template: |
|
||||
你是一名擅长搜索意图写作的内容编辑,请围绕「{{brand}} {{keyword}}」撰写一篇完整的 Markdown 品牌词搜索扩写文章。
|
||||
你是一名懂搜索意图的朋友式咨询顾问,请围绕「{{primary_keyword}}」撰写一篇完整的 Markdown 品牌词搜索扩写文章;如果提供 brand_name,把它作为主要解释对象,但不要写成企业软文。
|
||||
文章目标:
|
||||
1. 直接回答搜索用户最关心的问题。
|
||||
2. 解释品牌背景、核心信息和常见对比/疑问,承接后续转化或继续了解。
|
||||
1. 直接回答搜索用户最关心的问题:这个品牌/主体是什么、适合谁、怎么判断、要注意什么。
|
||||
2. 用行业痛点、避坑逻辑和事实资料承接品牌信息,让内容有价值而不是单纯宣传。
|
||||
3. 自然提升 brand_name 与优化关键词的关联度,同时符合平台内容规则。
|
||||
|
||||
写作要求:
|
||||
- 文章结构使用“开篇概述 -> 搜索意图拆解 -> 品牌信息说明 -> 常见问题/对比观察 -> 总结建议”,正文主体采用 H2 小标题。
|
||||
- 重点突出 brand_name 的优势,优势内容符合Google网页评估的EEAT原则(专业性Expertise、经验Experience、权威性Authoritativeness、可信度Trustworthiness),但不允许出现任何EEAT等相关文字,排名均列成H2小标题呈现。
|
||||
- 开篇首段不少于 100 字,先解释用户为什么会搜索这个词、当前常见顾虑以及判断思路,不要直接写成品牌宣传开场。
|
||||
- 正文应覆盖品牌是什么、用户为什么会搜这个词、常见疑问、对比点和下一步决策信息。
|
||||
- 如果提供了竞品或替代方案,按用户常见比较维度展开,不要空泛地说“各有优势”。
|
||||
- 文章结构使用“场景痛点 -> 搜索意图拆解 -> 行业避坑/判断方法 -> 品牌信息说明 -> 常见问题/对比观察 -> 大实话总结”,正文主体采用 3-5 个口语化 H2 小标题。
|
||||
- 原创≥90%,拒绝照搬参考素材、知识库或企业介绍;只提取主体定位、服务/产品内容、行业痛点和可核验事实,用口语化表达重新组织。
|
||||
- 开篇首段不少于 100 字,先解释用户为什么会搜索这个词、当前常见顾虑、行业现状和判断思路;首段自然嵌入 1-2 个优化关键词或其变体,不要直接写成品牌宣传开场。
|
||||
- 正文 90% 以上应是行业知识、避坑方法、判断标准、场景解释和 FAQ;brand_name 露出约 10%,控制在必要位置,每个模块 1-2 次即可。
|
||||
- 正文应覆盖品牌是什么、用户为什么会搜这个词、这个行业常见坑、如何判断品牌信息、常见疑问、对比点和下一步核验信息。
|
||||
- brand_name 的优势要转成日常场景语言:比如交付、服务、案例、资质、团队、材料、流程、售后分别解决什么实际问题;必须基于已提供或可公开核验的信息。
|
||||
- 需要体现专业经验、真实案例、资质/合规、服务流程和可信边界,但不要把这些写成提示词标签或搜索质量评估术语。
|
||||
- 如果提供了竞品或替代方案,只用于理解用户比较维度和避坑点;正文默认不点名具体竞品,除非 article_outline 明确要求对比,且只能客观写维度差异和适配场景,不贬低。
|
||||
- 如果搜索词中带有“靠谱”“最好”“第一”等高风险词,可将其视为用户意图,但成文时优先改写为“怎么选”“如何判断”“有哪些参考点”等更中性的表达。
|
||||
- 涉及品牌历史、案例、授权、检测、投诉率、服务承诺、用户评价等内容时,仅使用已提供或可公开核验的信息;不能编造或放大。
|
||||
- 正文可适度使用问题 - 答案、项目符号和编号步骤增强可读性,但不要机械堆砌品牌问题或过度加粗。
|
||||
- 至少安排 1 个“避坑误区/判断清单/核验步骤”段落,按问题 -> 建议 -> 可核验信息组织。
|
||||
- 可安排 2-6 个 FAQ,回答用户围绕优化关键词会问的问题;答案具体,不做营销口号。
|
||||
- 每 500 字左右自然出现 1 次优化关键词、补充关键词或 brand_name 变体,均匀分布,不要堆词。
|
||||
- 正文可适度使用问题 - 答案、项目符号和编号步骤增强可读性;一句话段落、自然换行,核心结论单独成段,像懂行朋友解释。
|
||||
- 每隔 3-4 段自然插入口语连接词,例如“说真的”“你想想”“其实”“话说回来”“对了还有”;少加粗,仅在关键词或关键信息处加粗 1-2 处。
|
||||
- 语气客观、有信息量,避免企业宣传腔、联系方式、行动号召和广告标识。
|
||||
- 结尾给出简洁总结,并提示用户接下来应该关注什么信息来继续判断。
|
||||
- 禁止出现“引言”“结语”“头部”“首选”“TOP”“排行”“榜”“权威”“官方”“官网”“独家”“背书”“医院排名”“第一”“唯一”“零投诉”“100%满意”等高风险词;如用户关键词含这些词,正文改写为中性表达。
|
||||
- 结尾用接地气的大实话总结,并提示用户接下来应该核验什么信息来继续判断。
|
||||
- 末尾需补一句信息边界说明:本文仅作品牌信息与搜索意图整理,不构成购买建议,具体选择仍需结合自身需求核验。
|
||||
- 全文控制在 900-1200 字,干货优先,品牌自然出现。
|
||||
analyze_prompt_template: |
|
||||
你是一位专业的 GEO 内容策略师,正在为品牌词搜索扩写文章做品牌与意图分析。
|
||||
模板: {{template_name}}
|
||||
语言: {{locale}}
|
||||
品牌名: {{brand_name}}
|
||||
官网: {{official_website}}
|
||||
品牌主问题: {{primary_keyword}}
|
||||
优化关键词: {{primary_keyword}}
|
||||
|
||||
任务:
|
||||
1. 分析品牌与搜索意图上下文,给出 1-2 句品牌摘要。
|
||||
2. 推荐最多 5 个品牌词搜索相关的搜索问题候选,侧重搜索意图和用户疑问。
|
||||
2. 推荐 8-10 个品牌词搜索相关的搜索词候选,侧重搜索意图、用户疑问、避坑和对比。
|
||||
3. 推荐最多 6 个可信的竞品或替代方案。
|
||||
|
||||
规则:
|
||||
- 仅返回 JSON,不要用 Markdown 代码块包裹。
|
||||
- 使用与 locale 一致的语言。
|
||||
- 搜索问题候选应贴合搜索意图,如「XX 是什么」「XX 怎么选」「XX 对比 YY」「XX 适合谁」。
|
||||
- 搜索词候选应贴合搜索意图,如「XX 是什么」「XX 怎么选」「XX 对比 YY」「XX 适合谁」「XX 要注意什么」「XX 案例怎么看」「XX 售后怎么样」。
|
||||
- 竞品应去重且真实,不确定时 website 留空。
|
||||
- 避免输出“最靠谱”“第一”“权威”“Top”“首选”等排序或背书词。
|
||||
title_prompt_template: |
|
||||
@@ -619,14 +653,14 @@ platform_templates:
|
||||
语言: {{locale}}
|
||||
当前年份: {{current_year}}
|
||||
品牌名: {{brand_name}}
|
||||
品牌主问题: {{primary_keyword}}
|
||||
优化关键词: {{primary_keyword}}
|
||||
官网: {{official_website}}
|
||||
|
||||
要求:
|
||||
- 标题应适用于品牌搜索意图、对比、问答和解释型内容。
|
||||
- 标题只围绕品牌主问题,不使用补充覆盖问题。
|
||||
- 避免空洞口号。
|
||||
- 当 locale 为 zh-CN 时,可使用是什么、怎么样、怎么选、对比、适不适合等表达。
|
||||
- 标题只围绕优化关键词,不使用补充关键词。
|
||||
- 避免空洞口号,标题要让用户知道能解决什么疑问。
|
||||
- 当 locale 为 zh-CN 时,可使用是什么、怎么样、怎么选、对比、适不适合、避坑、看这几点等表达。
|
||||
- 标题尽量使用疑问句或总结式表达,中文标题尽量控制在 30 字以内。
|
||||
- 禁止使用“靠谱”“排行”“榜”“Top”“第一”“最好”“首选”“权威”“背书”等词。
|
||||
- 返回 5 个不同的、贴合搜索意图的标题选项。
|
||||
@@ -636,20 +670,21 @@ platform_templates:
|
||||
语言: {{locale}}
|
||||
标题: {{title}}
|
||||
品牌名: {{brand_name}}
|
||||
品牌主问题: {{primary_keyword}}
|
||||
优化关键词: {{primary_keyword}}
|
||||
官网: {{official_website}}
|
||||
已选段落: {{outline_sections}}
|
||||
补充覆盖问题: {{supplemental_questions}}
|
||||
补充关键词: {{supplemental_questions}}
|
||||
关键要点: {{key_points}}
|
||||
竞品名称: {{competitor_names}}
|
||||
|
||||
要求:
|
||||
- 每个已选段落作为顶层节点,下设具体子条目。
|
||||
- 补充覆盖问题只放进正文主体的子条目,不作为顶层节点,不改写标题。
|
||||
- 结尾段落预留一个加粗点题句,集中回应补充覆盖问题覆盖到的搜索意图。
|
||||
- 首段需能承接不少于 100 字的搜索意图与判断思路概述。
|
||||
- 品牌概览段落应覆盖品牌定位、核心产品和差异化。
|
||||
- 对比段落应按竞品逐一展开对比维度。
|
||||
- 补充关键词只放进正文主体的子条目,不作为顶层节点,不改写标题。
|
||||
- 结尾段落预留一个加粗点题句,集中回应补充关键词覆盖到的搜索意图。
|
||||
- 首段需能承接不少于 100 字的搜索意图、行业痛点、现状和判断思路概述。
|
||||
- 必须安排行业避坑、判断标准、品牌概览、场景化价值、FAQ/核验清单等子条目。
|
||||
- 品牌概览段落应覆盖品牌定位、核心产品/服务、差异化、案例或资质边界。
|
||||
- 对比段落默认写用户关心的维度对比,不点名竞品;只有标题或已选段落明确要求竞品对比时,才按竞品逐一展开客观维度。
|
||||
- 在合适位置体现常见问题、信息边界和理性选择建议。
|
||||
- 内容应回答搜索意图,语气客观有信息量,不写成推广稿。
|
||||
- 使用与 locale 一致的语言。
|
||||
|
||||
@@ -176,15 +176,15 @@ var routeDocs = map[string]routeDoc{
|
||||
"PUT /api/tenant/brands/:id/keywords/:kid": {"更新关键词", "修改关键词文本/分组。"},
|
||||
"DELETE /api/tenant/brands/:id/keywords/:kid": {"删除关键词", "删除某条关键词。"},
|
||||
|
||||
"GET /api/tenant/brands/:id/questions": {"品牌问题列表", "返回品牌下的监控问题,可按 keyword_id 过滤。"},
|
||||
"POST /api/tenant/brands/:id/questions": {"新增监控问题", "为品牌添加一条 GEO 监控问题。"},
|
||||
"POST /api/tenant/brands/:id/questions/combination-preview": {"拓词工具预览", "按地域词、前缀词、核心词、行业词、后缀词组合生成问题候选,仅预览不入库。"},
|
||||
"GET /api/tenant/brands/:id/questions": {"搜索词列表", "返回品牌下的监控搜索词,可按 keyword_id 过滤。"},
|
||||
"POST /api/tenant/brands/:id/questions": {"新增搜索词", "为品牌添加一条 GEO 监控搜索词。"},
|
||||
"POST /api/tenant/brands/:id/questions/combination-preview": {"拓词工具预览", "按地域词、前缀词、精准词、行业词、后缀词组合生成搜索词候选,仅预览不入库。"},
|
||||
"POST /api/tenant/brands/:id/questions/combination-fill": {"拓词工具 AI 填词", "根据用户 IP 本地识别地域,并结合品牌信息补全拓词工具的五列词组。"},
|
||||
"POST /api/tenant/brands/:id/questions/ai-distill": {"AI 扩展问题", "围绕品牌和主题生成问题候选,使用结构化输出并按 AI 点计费。"},
|
||||
"POST /api/tenant/brands/:id/questions/classify-metadata": {"问题元数据分类", "批量为问题文本推断 layer 和 intent 元数据。"},
|
||||
"POST /api/tenant/brands/:id/questions/materialize": {"保存问题候选", "将用户选中的问题候选保存到当前品牌问题集,执行配额、去重和审计。"},
|
||||
"PUT /api/tenant/brands/:id/questions/:qid": {"更新监控问题", "修改问题文本或所属关键词。"},
|
||||
"DELETE /api/tenant/brands/:id/questions/:qid": {"删除监控问题", "删除某条监控问题。"},
|
||||
"POST /api/tenant/brands/:id/questions/ai-distill": {"AI 扩展搜索词", "围绕品牌和主题生成搜索词候选,使用结构化输出并按 AI 点计费。"},
|
||||
"POST /api/tenant/brands/:id/questions/classify-metadata": {"搜索词元数据分类", "批量为搜索词文本推断 layer 和 intent 元数据。"},
|
||||
"POST /api/tenant/brands/:id/questions/materialize": {"保存搜索词候选", "将用户选中的搜索词候选保存到当前关键词库(搜索词),执行配额、去重和审计。"},
|
||||
"PUT /api/tenant/brands/:id/questions/:qid": {"更新监控搜索词", "修改搜索词文本或所属关键词。"},
|
||||
"DELETE /api/tenant/brands/:id/questions/:qid": {"删除监控搜索词", "删除某条监控搜索词。"},
|
||||
|
||||
"GET /api/tenant/brands/:id/competitors": {"竞品列表", "返回品牌下登记的竞品。"},
|
||||
"POST /api/tenant/brands/:id/competitors": {"新增竞品", "为品牌添加竞品记录。"},
|
||||
|
||||
@@ -689,12 +689,12 @@ func (s *MonitoringService) CollectNow(
|
||||
limitApplied = true
|
||||
}
|
||||
if len(configuredQuestions) == 0 {
|
||||
message := "当前品牌下暂无品牌库问题,未创建采集任务"
|
||||
message := "当前品牌下暂无关键词库(搜索词),未创建采集任务"
|
||||
if keywordID != nil {
|
||||
message = "当前问题集下暂无品牌库问题,未创建采集任务"
|
||||
message = "当前关键词库(搜索词)下暂无搜索词,未创建采集任务"
|
||||
}
|
||||
if questionID != nil {
|
||||
message = "当前问题不可用,未创建采集任务"
|
||||
message = "当前搜索词不可用,未创建采集任务"
|
||||
}
|
||||
return &MonitoringCollectNowResponse{
|
||||
CollectionMode: quota.CollectionMode,
|
||||
|
||||
@@ -23,10 +23,48 @@ func TestBuildQuestionCombinationFillFallback(t *testing.T) {
|
||||
if !reflect.DeepEqual(got.Region, []string{"上海", "华东"}) {
|
||||
t.Fatalf("region = %#v", got.Region)
|
||||
}
|
||||
if len(got.Core) < 3 || got.Core[0] != "GEO" {
|
||||
t.Fatalf("core fallback = %#v", got.Core)
|
||||
wantPrefix := []string{"性价比高的", "口碑好的", "专业的", "靠谱的"}
|
||||
if !reflect.DeepEqual(got.Prefix, wantPrefix) {
|
||||
t.Fatalf("prefix fallback = %#v, want %#v", got.Prefix, wantPrefix)
|
||||
}
|
||||
wantCore := []string{"品牌词", "AI搜索", "获客", "中小企业"}
|
||||
if !reflect.DeepEqual(got.Core, wantCore) {
|
||||
t.Fatalf("core fallback = %#v, want %#v", got.Core, wantCore)
|
||||
}
|
||||
wantIndustry := []string{"GEO优化", "AI搜索优化", "品牌推广", "搜索营销"}
|
||||
if !reflect.DeepEqual(got.Industry, wantIndustry) {
|
||||
t.Fatalf("industry fallback = %#v, want %#v", got.Industry, wantIndustry)
|
||||
}
|
||||
if len(got.Prefix) != 4 || len(got.Industry) != 4 || len(got.Suffix) != 4 {
|
||||
t.Fatalf("expected four hot terms for non-region columns, got %#v", got)
|
||||
}
|
||||
wantSuffix := []string{"哪家好", "怎么选", "推荐", "避坑"}
|
||||
if !reflect.DeepEqual(got.Suffix, wantSuffix) {
|
||||
t.Fatalf("suffix fallback = %#v, want %#v", got.Suffix, wantSuffix)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeQuestionTextRemovesPunctuation(t *testing.T) {
|
||||
got := normalizeQuestionText(" 合肥全屋定制哪家好? ")
|
||||
if got != "合肥全屋定制哪家好" {
|
||||
t.Fatalf("normalizeQuestionText() = %q, want %q", got, "合肥全屋定制哪家好")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompactQuestionCombinationTermsRemovesPunctuation(t *testing.T) {
|
||||
got := compactQuestionCombinationTerms([]string{"官网?", "怎么选?", "推荐!", "对比"}, 4)
|
||||
want := []string{"官网", "怎么选", "推荐", "对比"}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Fatalf("compactQuestionCombinationTerms() = %#v, want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuestionContainsExcludedEntityMatchesCompanyShortName(t *testing.T) {
|
||||
brandName := "安徽海翔家居用品销售有限公司"
|
||||
if !questionContainsExcludedEntity("安徽海翔家居全屋定制口碑怎么样", brandName, nil) {
|
||||
t.Fatal("expected candidate containing company short name to be excluded")
|
||||
}
|
||||
if questionContainsExcludedEntity("合肥全屋定制哪家好", brandName, nil) {
|
||||
t.Fatal("expected generic user search term to be allowed")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,15 +191,10 @@ func (s *QuestionExpansionService) GenerateByCombination(ctx context.Context, br
|
||||
for _, co := range core {
|
||||
for _, in := range industry {
|
||||
for _, sf := range suffix {
|
||||
text := strings.TrimSpace(strings.Join(nonEmptyParts(rg, pf, co, in, sf), ""))
|
||||
text := normalizeQuestionText(strings.Join(nonEmptyParts(rg, pf, co, in, sf), ""))
|
||||
if text == "" {
|
||||
continue
|
||||
}
|
||||
if sf != "" && !strings.HasSuffix(text, "?") && !strings.HasSuffix(text, "?") {
|
||||
if !strings.Contains(sf, "?") && !strings.Contains(sf, "?") {
|
||||
text += "?"
|
||||
}
|
||||
}
|
||||
key := normalizeQuestionKey(text)
|
||||
if _, ok := seen[key]; ok {
|
||||
continue
|
||||
@@ -312,6 +307,9 @@ func (s *QuestionExpansionService) GenerateByAIDistill(ctx context.Context, bran
|
||||
if text == "" {
|
||||
continue
|
||||
}
|
||||
if questionContainsExcludedEntity(text, brandCtx.BrandName, brandCtx.CompetitorNames) {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[key]; ok {
|
||||
continue
|
||||
}
|
||||
@@ -754,11 +752,89 @@ func buildCandidate(text, source string, missingSuffix bool, existing map[string
|
||||
}
|
||||
}
|
||||
|
||||
func questionContainsExcludedEntity(text, brandName string, competitorNames []string) bool {
|
||||
normalized := normalizeQuestionKey(text)
|
||||
for _, entity := range append([]string{brandName}, competitorNames...) {
|
||||
for _, entityKey := range questionEntityExclusionKeys(entity) {
|
||||
if strings.Contains(normalized, entityKey) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func questionEntityExclusionKeys(entity string) []string {
|
||||
base := normalizeQuestionKey(entity)
|
||||
if utf8.RuneCountInString(base) < 2 {
|
||||
return nil
|
||||
}
|
||||
keys := make([]string, 0, 4)
|
||||
addKey := func(value string) {
|
||||
value = strings.TrimSpace(value)
|
||||
if utf8.RuneCountInString(value) < 2 {
|
||||
return
|
||||
}
|
||||
for _, key := range keys {
|
||||
if key == value {
|
||||
return
|
||||
}
|
||||
}
|
||||
keys = append(keys, value)
|
||||
}
|
||||
addKey(base)
|
||||
|
||||
companyName := base
|
||||
for _, suffix := range []string{
|
||||
"有限责任公司",
|
||||
"股份有限公司",
|
||||
"集团有限公司",
|
||||
"控股有限公司",
|
||||
"科技有限公司",
|
||||
"销售有限公司",
|
||||
"用品有限公司",
|
||||
"有限公司",
|
||||
"股份公司",
|
||||
"集团公司",
|
||||
"公司",
|
||||
} {
|
||||
if strings.HasSuffix(companyName, suffix) {
|
||||
companyName = strings.TrimSuffix(companyName, suffix)
|
||||
addKey(companyName)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
descriptorName := companyName
|
||||
for _, suffix := range []string{
|
||||
"用品销售",
|
||||
"产品销售",
|
||||
"销售",
|
||||
"用品",
|
||||
"产品",
|
||||
"服务",
|
||||
"科技",
|
||||
"商贸",
|
||||
"贸易",
|
||||
"网络",
|
||||
"信息",
|
||||
"文化",
|
||||
"传媒",
|
||||
} {
|
||||
if strings.HasSuffix(descriptorName, suffix) {
|
||||
descriptorName = strings.TrimSuffix(descriptorName, suffix)
|
||||
addKey(descriptorName)
|
||||
break
|
||||
}
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func normalizeQuestionParts(values []string) []string {
|
||||
result := make([]string, 0, len(values))
|
||||
seen := map[string]struct{}{}
|
||||
for _, value := range values {
|
||||
trimmed := strings.TrimSpace(value)
|
||||
trimmed := normalizeQuestionText(value)
|
||||
if trimmed == "" {
|
||||
continue
|
||||
}
|
||||
@@ -790,27 +866,27 @@ func buildQuestionCombinationFillFallback(brandCtx *questionBrandContext, region
|
||||
region = compactQuestionCombinationTerms(req.Region, questionCombinationFillMax)
|
||||
}
|
||||
if len(region) == 0 {
|
||||
region = []string{"全国", "本地", "华东"}
|
||||
region = []string{"全国", "合肥", "华东"}
|
||||
}
|
||||
|
||||
prefix := compactQuestionCombinationTerms(req.Prefix, questionCombinationFillMax)
|
||||
if len(prefix) == 0 {
|
||||
prefix = []string{"好用的", "专业的", "靠谱的", "热门的"}
|
||||
prefix = []string{"性价比高的", "口碑好的", "专业的", "靠谱的"}
|
||||
}
|
||||
|
||||
core := compactQuestionCombinationTerms(req.Core, questionCombinationFillMax)
|
||||
if len(core) == 0 {
|
||||
core = questionCombinationCoreFallback(brandName, description)
|
||||
core = questionCombinationPrecisionFallback(brandName, description)
|
||||
}
|
||||
|
||||
industry := compactQuestionCombinationTerms(req.Industry, questionCombinationFillMax)
|
||||
if len(industry) == 0 {
|
||||
industry = []string{category, "平台", "工具", "服务商"}
|
||||
industry = questionCombinationIndustryFallback(category)
|
||||
}
|
||||
|
||||
suffix := compactQuestionCombinationTerms(req.Suffix, questionCombinationFillMax)
|
||||
if len(suffix) == 0 {
|
||||
suffix = []string{"哪家好", "怎么选", "推荐", "多少钱"}
|
||||
suffix = []string{"哪家好", "怎么选", "推荐", "避坑"}
|
||||
}
|
||||
|
||||
return QuestionCombinationFillResult{
|
||||
@@ -1017,21 +1093,40 @@ func chineseMacroRegion(province string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func questionCombinationCoreFallback(brandName, description string) []string {
|
||||
func questionCombinationPrecisionFallback(brandName, description string) []string {
|
||||
text := strings.ToLower(strings.TrimSpace(brandName + " " + description))
|
||||
if strings.Contains(text, "geo") || strings.Contains(text, "ai") || strings.Contains(text, "搜索") || strings.Contains(text, "排名") {
|
||||
return []string{"GEO", "AI搜索优化", "AI搜索排名", "品牌可见度"}
|
||||
return []string{"品牌词", "AI搜索", "获客", "中小企业"}
|
||||
}
|
||||
if strings.Contains(text, "教育") || strings.Contains(text, "培训") || strings.Contains(text, "课程") {
|
||||
return []string{"课程", "培训", "学习", "机构"}
|
||||
return []string{"成人", "少儿", "线上", "入门"}
|
||||
}
|
||||
if strings.Contains(text, "医疗") || strings.Contains(text, "健康") || strings.Contains(text, "诊所") {
|
||||
return []string{"医疗服务", "健康管理", "医生", "诊疗"}
|
||||
return []string{"本地", "复诊", "儿童", "上班族"}
|
||||
}
|
||||
if strings.Contains(text, "家居") || strings.Contains(text, "装修") || strings.Contains(text, "建材") {
|
||||
return []string{"装修", "家居", "建材", "设计"}
|
||||
return []string{"精装", "100平", "小户型", "旧房改造"}
|
||||
}
|
||||
return []string{"企业", "本地", "新手", "中小企业"}
|
||||
}
|
||||
|
||||
func questionCombinationIndustryFallback(category string) []string {
|
||||
switch category {
|
||||
case "营销":
|
||||
return []string{"GEO优化", "AI搜索优化", "品牌推广", "搜索营销"}
|
||||
case "教育":
|
||||
return []string{"培训机构", "在线课程", "教育机构", "学习平台"}
|
||||
case "健康":
|
||||
return []string{"健康管理", "医疗服务", "诊疗机构", "医生服务"}
|
||||
case "家居":
|
||||
return []string{"全屋定制", "家具定制", "家居定制", "定制家装"}
|
||||
case "餐饮":
|
||||
return []string{"餐饮店", "美食店", "连锁餐饮", "餐饮服务"}
|
||||
case "旅游":
|
||||
return []string{"旅游服务", "酒店预订", "旅行社", "旅游攻略"}
|
||||
default:
|
||||
return []string{"服务商", "解决方案", "平台", "公司"}
|
||||
}
|
||||
return []string{strings.TrimSpace(brandName), "解决方案", "服务", "平台"}
|
||||
}
|
||||
|
||||
func inferQuestionCombinationCategory(brandName, description string) string {
|
||||
|
||||
@@ -29,11 +29,20 @@ type ClassifiedQuestion struct {
|
||||
}
|
||||
|
||||
func normalizeQuestionText(text string) string {
|
||||
return strings.TrimSpace(text)
|
||||
trimmed := strings.TrimSpace(text)
|
||||
if trimmed == "" {
|
||||
return ""
|
||||
}
|
||||
return strings.Map(func(r rune) rune {
|
||||
if unicode.IsPunct(r) {
|
||||
return -1
|
||||
}
|
||||
return r
|
||||
}, trimmed)
|
||||
}
|
||||
|
||||
func normalizeQuestionKey(text string) string {
|
||||
return strings.ToLower(strings.TrimSpace(text))
|
||||
return strings.ToLower(normalizeQuestionText(text))
|
||||
}
|
||||
|
||||
func isValidQuestionLayer(value string) bool {
|
||||
|
||||
@@ -72,10 +72,10 @@ func TestNormalizeAnalyzeResultKeepsTenQueryKeywords(t *testing.T) {
|
||||
"全屋定制哪家好",
|
||||
"靠谱的全屋定制品牌有哪些",
|
||||
"口碑好的全屋定制公司推荐",
|
||||
"性价比高的全屋定制怎么选",
|
||||
"专业的全屋定制设计公司哪家好",
|
||||
"全屋定制和木工打柜子哪个更划算",
|
||||
"全屋定制一般多少钱一平米",
|
||||
"全屋定制服务商推荐",
|
||||
"全屋定制官网怎么找",
|
||||
"全屋定制案例怎么看",
|
||||
"全屋定制常用的板材哪种环保",
|
||||
"全屋定制十大品牌排名最新",
|
||||
"全屋定制需要注意哪些坑",
|
||||
|
||||
@@ -20,7 +20,7 @@ func TestBuildPromptContextUsesChineseLabels(t *testing.T) {
|
||||
"- 语言: zh-CN",
|
||||
"- 标题: 测试标题",
|
||||
"- 品牌名: Rankly",
|
||||
"- 品牌主问题: GEO 排名",
|
||||
"- 优化关键词: GEO 排名",
|
||||
"- 已选段落: 引言 > 结论",
|
||||
} {
|
||||
if !strings.Contains(context, expected) {
|
||||
|
||||
@@ -26,9 +26,22 @@ func TestPlatformTemplateSeedsInjectPromptConfig(t *testing.T) {
|
||||
if target == nil {
|
||||
t.Fatal("top_x_article seed not found")
|
||||
}
|
||||
if !strings.Contains(target.PromptTemplate, "经验丰富的行业观察型内容编辑") {
|
||||
if !strings.Contains(target.PromptTemplate, "第三方行业观察型内容编辑") {
|
||||
t.Fatalf("PromptTemplate = %q, want yaml-backed template content", target.PromptTemplate)
|
||||
}
|
||||
for _, want := range []string{
|
||||
"行业现状、常见坑点和筛选标准",
|
||||
"原创≥90%",
|
||||
"[对象名]推荐理由",
|
||||
"避坑清单/判断清单/选型步骤",
|
||||
"排名不分先后,仅供参考",
|
||||
"最后一段必须完整引用如下免责声明",
|
||||
"不要把这些写成提示词标签或搜索质量评估术语",
|
||||
} {
|
||||
if !strings.Contains(target.PromptTemplate, want) {
|
||||
t.Fatalf("PromptTemplate = %q, want master-instruction marker %q", target.PromptTemplate, want)
|
||||
}
|
||||
}
|
||||
|
||||
var payload map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(target.CardConfigJSON), &payload); err != nil {
|
||||
@@ -47,7 +60,7 @@ func TestPlatformTemplateSeedsInjectPromptConfig(t *testing.T) {
|
||||
if !strings.Contains(analyzePrompt, "推荐类文章做品牌与竞品分析") {
|
||||
t.Fatalf("analyze_prompt_template = %q, want yaml-backed analyze prompt", analyzePrompt)
|
||||
}
|
||||
if !strings.Contains(analyzePrompt, "全屋定制哪家好") || !strings.Contains(analyzePrompt, "搜索问题候选") {
|
||||
if !strings.Contains(analyzePrompt, "全屋定制哪家好") || !strings.Contains(analyzePrompt, "搜索词候选") {
|
||||
t.Fatalf("analyze_prompt_template = %q, want question-like long-tail query guidance", analyzePrompt)
|
||||
}
|
||||
if !strings.Contains(titlePrompt, "推荐类文章生成 5 个候选标题") {
|
||||
@@ -58,6 +71,86 @@ func TestPlatformTemplateSeedsInjectPromptConfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlatformTemplatePromptsUseMasterInstructionStructure(t *testing.T) {
|
||||
SetConfigFile("")
|
||||
t.Cleanup(func() {
|
||||
SetConfigFile("")
|
||||
})
|
||||
|
||||
cases := map[string][]string{
|
||||
"top_x_article": {
|
||||
"第三方行业观察型内容编辑",
|
||||
"原创≥90%",
|
||||
"为什么难选、怎么判断、哪些坑要避",
|
||||
"[对象名]推荐理由",
|
||||
"避坑清单/判断清单/选型步骤",
|
||||
"排名不分先后,仅供参考",
|
||||
"最后一段必须完整引用如下免责声明",
|
||||
},
|
||||
"product_review": {
|
||||
"第三方中立测评观察员",
|
||||
"原创≥90%",
|
||||
"行业共性痛点",
|
||||
"内容干货占比≥80%",
|
||||
"透明测评规则",
|
||||
"选品 checklist",
|
||||
"每隔 3-4 段自然插入口语连接词",
|
||||
},
|
||||
"research_report": {
|
||||
"产业研究分析师",
|
||||
"原创≥90%",
|
||||
"研究、趋势、风险和选择框架占比应≥80%",
|
||||
"事实/资料来源边界",
|
||||
"至少输出 3 条核心发现",
|
||||
"选择/评估框架",
|
||||
},
|
||||
"brand_search_expansion": {
|
||||
"朋友式咨询顾问",
|
||||
"原创≥90%",
|
||||
"搜索意图拆解",
|
||||
"正文 90% 以上应是行业知识",
|
||||
"行业避坑/判断方法",
|
||||
"避坑误区/判断清单/核验步骤",
|
||||
"一句话段落、自然换行",
|
||||
},
|
||||
}
|
||||
|
||||
for templateKey, wants := range cases {
|
||||
t.Run(templateKey, func(t *testing.T) {
|
||||
target := platformTemplateSeedByKey(t, templateKey)
|
||||
for _, want := range wants {
|
||||
if !strings.Contains(target.PromptTemplate, want) {
|
||||
t.Fatalf("%s PromptTemplate missing %q:\n%s", templateKey, want, target.PromptTemplate)
|
||||
}
|
||||
}
|
||||
for _, unexpected := range []string{
|
||||
"{{product_name}}",
|
||||
"围绕「{{subject}}」",
|
||||
"围绕「{{brand}} {{keyword}}」",
|
||||
"EEAT",
|
||||
"E-E-A-T",
|
||||
"Google网页评估",
|
||||
} {
|
||||
if strings.Contains(target.PromptTemplate, unexpected) {
|
||||
t.Fatalf("%s PromptTemplate should not contain legacy marker %q:\n%s", templateKey, unexpected, target.PromptTemplate)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func platformTemplateSeedByKey(t *testing.T, key string) PlatformTemplateSeed {
|
||||
t.Helper()
|
||||
seeds := PlatformTemplateSeeds()
|
||||
for _, seed := range seeds {
|
||||
if seed.Key == key {
|
||||
return seed
|
||||
}
|
||||
}
|
||||
t.Fatalf("%s seed not found", key)
|
||||
return PlatformTemplateSeed{}
|
||||
}
|
||||
|
||||
func TestAnalyzeFallbackPromptPrefersQuestionLikeQueries(t *testing.T) {
|
||||
SetConfigFile("")
|
||||
t.Cleanup(func() {
|
||||
@@ -68,7 +161,7 @@ func TestAnalyzeFallbackPromptPrefersQuestionLikeQueries(t *testing.T) {
|
||||
for _, want := range []string{
|
||||
"真实用户会直接搜索的问题型长尾词",
|
||||
"哪家好",
|
||||
"最多返回 6 个竞品和 10 个搜索问题候选",
|
||||
"最多返回 6 个竞品和 10 个搜索词候选",
|
||||
} {
|
||||
if !strings.Contains(prompt, want) {
|
||||
t.Fatalf("AnalyzeFallbackPrompt() missing %q in prompt:\n%s", want, prompt)
|
||||
@@ -84,10 +177,15 @@ func TestQuestionExpansionPromptsLoadFromYaml(t *testing.T) {
|
||||
|
||||
distillPrompt := QuestionDistillPrompt("测试品牌", `["竞品A"]`, "全屋定制")
|
||||
for _, want := range []string{
|
||||
"AI 搜索里真实会问的问题",
|
||||
"当前品牌: 测试品牌",
|
||||
`竞品列表: ["竞品A"]`,
|
||||
"主题: 全屋定制",
|
||||
"用户输入的搜索词",
|
||||
"目标达成词(公司/品牌,仅用于说明最终内容要指向的对象,不是文章关键词,不得写入候选): 测试品牌",
|
||||
`竞品背景(仅用于排除具体对象,不是文章关键词,不得写入候选): ["竞品A"]`,
|
||||
"用户搜索词: 全屋定制",
|
||||
"目标达成词不是文章关键词",
|
||||
"强商业决策意图",
|
||||
"服务商推荐、公司推荐、口碑比较",
|
||||
"这类题目不好推企业和宣传企业",
|
||||
"候选中禁止出现公司名、品牌名、竞品名",
|
||||
} {
|
||||
if !strings.Contains(distillPrompt, want) {
|
||||
t.Fatalf("QuestionDistillPrompt() missing %q in prompt:\n%s", want, distillPrompt)
|
||||
|
||||
@@ -57,7 +57,7 @@ var platformTemplateSeeds = []PlatformTemplateSeed{
|
||||
},
|
||||
"keywords": {
|
||||
"title": "品牌问题",
|
||||
"hint": "品牌主问题必选且只能选一个;补充覆盖问题可选,最多 3 个,只进入文章主体和结尾点题。"
|
||||
"hint": "优化关键词必选且只能选一个;补充关键词可选,最多 3 个,只进入文章主体和结尾点题。"
|
||||
},
|
||||
"template_fields": {
|
||||
"title": "模板字段",
|
||||
@@ -73,7 +73,7 @@ var platformTemplateSeeds = []PlatformTemplateSeed{
|
||||
"cards": {
|
||||
"choose_title": {
|
||||
"title": "选择文章标题",
|
||||
"hint": "AI 会结合品牌主问题和竞品上下文给出 5 个更适合的标题候选,你可以直接选择或改写。"
|
||||
"hint": "AI 会结合优化关键词和竞品上下文给出 5 个更适合的标题候选,你可以直接选择或改写。"
|
||||
},
|
||||
"outline": {
|
||||
"title": "文章结构",
|
||||
@@ -145,7 +145,7 @@ var platformTemplateSeeds = []PlatformTemplateSeed{
|
||||
},
|
||||
"keywords": {
|
||||
"title": "品牌问题",
|
||||
"hint": "品牌主问题控制标题和主线;补充覆盖问题只进入文章主体与结尾点题。"
|
||||
"hint": "优化关键词控制标题和主线;补充关键词只进入文章主体与结尾点题。"
|
||||
},
|
||||
"competitors": {
|
||||
"visible": false
|
||||
@@ -235,7 +235,7 @@ var platformTemplateSeeds = []PlatformTemplateSeed{
|
||||
},
|
||||
"keywords": {
|
||||
"title": "品牌问题",
|
||||
"hint": "品牌主问题控制报告核心视角;补充覆盖问题只进入主体覆盖和结尾点题。"
|
||||
"hint": "优化关键词控制报告核心视角;补充关键词只进入主体覆盖和结尾点题。"
|
||||
},
|
||||
"competitors": {
|
||||
"visible": false
|
||||
@@ -318,7 +318,7 @@ var platformTemplateSeeds = []PlatformTemplateSeed{
|
||||
},
|
||||
"keywords": {
|
||||
"title": "品牌问题",
|
||||
"hint": "品牌主问题参与标题与主线;补充覆盖问题只进入正文主体和结尾点题。"
|
||||
"hint": "优化关键词参与标题与主线;补充关键词只进入正文主体和结尾点题。"
|
||||
},
|
||||
"template_fields": {
|
||||
"title": "模板字段",
|
||||
|
||||
Reference in New Issue
Block a user