فهرست منبع

重写四个提示词到参考级严谨度(v2)

参考两份数据工程「元素列提取」提示词的格式/密度/详尽度,对照重写:
- 四个提示词补上:精确定义、范畴互斥与对比、反例(❌→✅)、判别顺序、
  粒度与原子性、工作姿态(以原始素材为准/不编造/不确定标空)、自检
- deconstruct 吸收参考里 实质/形式/作用/意图 的互斥口径;value 必须是具体点而非大类名
- extract 提示词外置到 prompts/extract.txt,与另外三个统一加载;extractor 改 load_prompt
- PROMPT_VERSION v1 -> v2;/api/prompts 的 extract 改读外置文件
- 18 离线测试通过;真机 screen/split/deconstruct/extract smoke 输出合法且更精细

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lisihan 1 ماه پیش
والد
کامیت
5efbf44717
7فایلهای تغییر یافته به همراه156 افزوده شده و 55 حذف شده
  1. 1 2
      creation_knowledge/api.py
  2. 5 15
      creation_knowledge/integrations/extractor.py
  3. 1 1
      creation_knowledge/prompts.py
  4. 36 15
      prompts/deconstruct.txt
  5. 39 0
      prompts/extract.txt
  6. 37 8
      prompts/screen.txt
  7. 37 14
      prompts/split.txt

+ 1 - 2
creation_knowledge/api.py

@@ -71,8 +71,7 @@ def get_prompts() -> dict:
         "version": PROMPT_VERSION,
         "items": [
             {"key": "extract", "label": "多模态提取", "model": s.video_model,
-             "system": extractor_mod._SYSTEM_PROMPT, "user": extractor_mod._USER_TMPL,
-             "note": "文本+图片+视频提取知识;提示词写在 extractor.py,未外置到 prompts/"},
+             "system": extractor_mod._SYSTEM_PROMPT, "user": load_prompt("extract")},
             {"key": "screen", "label": "筛选", "model": s.llm_model,
              "system": screen_stage.SYSTEM, "user": load_prompt("screen")},
             {"key": "split", "label": "拆分", "model": s.llm_model,

+ 5 - 15
creation_knowledge/integrations/extractor.py

@@ -15,6 +15,7 @@ import httpx
 from creation_knowledge.config import load_env_file
 from creation_knowledge.jsonio import extract_json_object, to_bool
 from creation_knowledge.models import ExtractedContent, Post
+from creation_knowledge.prompts import load_prompt
 
 DEFAULT_MODEL = "google/gemini-3-flash-preview"
 DEFAULT_BASE_URL = "https://openrouter.ai/api/v1"
@@ -22,20 +23,9 @@ DEFAULT_TIMEOUT = 90.0
 MAX_IMAGES = 6
 
 _SYSTEM_PROMPT = (
-    "你是创作知识提取助手。给你一篇小红书帖子(标题、正文、图片),"
-    "请提取出其中真正能指导『如何创作内容』的知识。"
-    "知识往往在图片里而不在正文里。只输出一个 JSON 对象,不要任何解释或 markdown。"
-)
-
-_USER_TMPL = (
-    "帖子标题:{title}\n"
-    "话题:{topics}\n"
-    "正文(可能为空或只是话题串,不要只看它):\n{body}\n\n"
-    "请综合图片内容,输出如下 JSON:\n"
-    '{{"text": "把这篇帖子真正讲的创作知识完整、忠实地讲清楚;原文没有的不要编造", '
-    '"from_image": "仅来自图片的知识要点;没有则空字符串", '
-    '"from_video": "仅来自视频的知识要点;没有则空字符串", '
-    '"is_empty": "true 或 false:多模态看完后是否没有任何有效创作知识"}}'
+    "你是创作知识提取助手。从给定的小红书帖子(标题、正文、图片、视频)中,"
+    "提取真正能指导『如何创作内容』的知识;知识常在图片/视频里而非正文。"
+    "忠实提取、不编造。只输出一个 JSON 对象,不要解释或 markdown。"
 )
 
 
@@ -77,7 +67,7 @@ class GeminiExtractor:
         )
 
     def build_messages(self, post: Post) -> list[dict]:
-        user_text = _USER_TMPL.format(
+        user_text = load_prompt("extract").format(
             title=post.title or "(无)",
             topics="、".join(post.topic_list) or "(无)",
             body=post.body_text or "(空)",

+ 1 - 1
creation_knowledge/prompts.py

@@ -6,7 +6,7 @@ from pathlib import Path
 PROMPTS_DIR = Path(__file__).resolve().parent.parent / "prompts"
 
 # 提示词版本:改提示词时手动 +1,写进 ck 记录便于回溯
-PROMPT_VERSION = "v1"
+PROMPT_VERSION = "v2"
 
 
 def load_prompt(name: str) -> str:

+ 36 - 15
prompts/deconstruct.txt

@@ -1,22 +1,43 @@
-你在做"创作知识"解构:给一个知识片段补上【阶段】和【作用域】
+你在做「创作知识解构」:给一条已经拆好的知识片段,标注它的【阶段】和【作用域】。本步不改动知识内容本身
 
-阶段(创作 = 灵感 + 选题 + 脚本,可多选):
-- 灵感:帮助发现方向、素材、切口、洞察
-- 选题:帮助判断写什么、拍什么、从哪个角度切入
-- 脚本:帮助组织表达顺序、文案、镜头、结构
+## 1. 阶段(创作 = 灵感 + 选题 + 脚本,可多选)
+判断这条知识能服务创作的哪个/哪些环节:
+- **灵感**:帮助发现方向、素材、切口、洞察("从哪找内容")。
+- **选题**:帮助判断写什么/拍什么、从哪个角度切入("做哪个题")。
+- **脚本**:帮助组织表达顺序、文案、镜头、结构("怎么写/怎么拍")。
 
-作用域(五棵分类树,可多选;value 要填具体标签,不是大类名):
-- substance(实质):内容真正讲的对象、主题、事实、问题
-- form(形式):结构、模板、公式、表达形式
-- feeling(感受):用户情绪、体验、氛围、感知
-- effect(作用):解决什么创作问题、带来什么效果
-- intent(意图):创作者目的、传播目的、商业目标
+一条知识可同时服务多个阶段(如"评论区选题法"既给选题、也能改写成脚本切入点);只标它**真正**服务的阶段,不要硬凑。
 
-知识片段:
+## 2. 作用域(五棵分类树,可多选;每条含 大类 + 具体的点)
+判断这条知识落在哪几棵树上。五棵树范畴互斥,定义如下:
+- **substance(实质)**:内容真正讲的对象、主题、事实、问题本身 —— "讲了什么"。
+- **form(形式)**:表达结构、模板、公式、套路、载体、呈现形态 —— "怎么呈现 / 什么结构"。
+- **feeling(感受)**:观众的情绪、体验、氛围、感知 —— "让观众怎么觉得"。
+- **effect(作用)**:解决什么**创作问题**、带来什么**效果** —— "对创作有什么用"。
+- **intent(意图)**:创作者目的、传播目的、商业目标 —— "为了达成什么结果"。
+
+互斥提示(最容易混):
+- form 是"怎么呈现",substance 是"呈现了什么"。
+- effect 是"解决的创作问题/产生的功效",intent 是"创作者/传播/商业上想要的结果"。如"生成选题"是 effect,"涨粉变现"是 intent。
+
+## 3. value(具体的点)的要求
+- `value` 必须是**具体标签**,不是大类名本身。
+  - ❌ 错:{{"scope_type": "form", "value": "形式"}}(value 写成了大类名)
+  - ✅ 对:{{"scope_type": "form", "value": "评论区选题流程"}}、{{"scope_type": "effect", "value": "生成选题"}}
+- `value` 尽量短、是一个独立语义点,可作为标签复用;不要用连接词拼接多个点。
+- 同一条知识可命中多棵树,一棵树下也可有多个 value;**只标真正命中的**,不要为凑满五棵树而硬填。
+
+## 4. 不应做的事(反例)
+- ❌ value 写成大类名("形式"/"作用")。
+- ❌ 为铺满而给不相关的 scope。
+- ❌ 把 effect 和 intent 混用("生成选题"=effect;"涨粉变现"=intent)。
+- ❌ stage 硬凑(一条纯脚本技巧硬标上"灵感")。
+
+## 输入(一条知识片段)
 {item}
 
-输出 JSON:
-{{"stages": ["灵感" 和/或 "选题" 和/或 "脚本"],
-  "scopes": [{{"scope_type": "substance/form/feeling/effect/intent", "value": "具体标签"}}],
+## 输出(只输出一个 JSON 对象,不要解释或 markdown)
+{{"stages": ["灵感 和/或 选题 和/或 脚本,只列真正服务的"],
+  "scopes": [{{"scope_type": "substance/form/feeling/effect/intent", "value": "具体的点"}}],
   "stage_reason": "为什么是这些阶段",
   "scope_reason": "为什么是这些作用域"}}

+ 39 - 0
prompts/extract.txt

@@ -0,0 +1,39 @@
+你正在从一篇社交媒体帖子里提取「创作知识」。本步只做一件事:把帖子真正讲的、能指导"如何创作内容"的知识,完整、忠实地提取出来。本步不判断好坏(那是筛选步骤),也不拆分归类。
+
+## 1. 什么是创作知识
+创作知识 = 能迁移、能复用、能指导别人"怎么做内容"的方法、原理、认知或清单。
+它回答"做内容时该怎么想、怎么选、怎么写",而不是某一条具体作品本身。
+
+- ✅ 是创作知识:选题方法、爆款结构公式、起号逻辑、脚本要素清单、为什么某种开头更抓人、镜头/文案技巧……
+- ❌ 不是创作知识:一段具体文案、一张图的 AI 出图提示词、一个具体选题标题、纯展示型内容(风景/产品/生活记录)。这类是"作品本身",不是教你怎么创作的方法。
+
+注意:作品本身里有时也夹带可迁移方法(如一条爆款视频顺带讲了它的选题逻辑)。有方法就提方法,没有就如实标空——不要把"作品"硬当成"知识"。
+
+## 2. 工作姿态(重要)
+1. 知识常常在图片或视频里,不在正文里。小红书图文笔记的正文往往只是话题串(如 "#短剧编剧# #写作#"),真正的知识在图片上。**必须看图、看视频,不能只读正文。**
+2. 以原始素材(图片/视频/正文)为准,逐一识别它们承载了哪些创作知识。
+3. 忠实转述:不编造、不补全、不拔高。原素材没有的绝不添加;有的尽量提全,不要漏。
+4. 把零散知识点组织清楚,便于后续拆分;但不要替作者总结它没说的结论。
+
+## 3. 分模态提取
+- text:综合所有模态后,把这篇帖子讲的创作知识完整讲清楚(主产物)。
+- from_image:只填图片承载的知识要点;图片无有效知识则填 ""。
+- from_video:只填视频承载的知识要点;无则填 ""。
+
+## 4. is_empty 判别
+- 多模态都看完,确实没有任何可迁移的创作知识(纯作品/纯展示/纯无关)→ is_empty=true,其余字段尽量留空。
+- 只要有一点可迁移的方法/原理/清单 → is_empty=false。
+- 不确定算不算知识 → 先如实提取进 text,把好坏交给后续筛选,不要在本步直接丢弃。
+
+## 输入
+帖子标题:{title}
+话题:{topics}
+正文(可能为空或只是话题串,不要只看它):
+{body}
+(图片与视频已作为多模态输入一并给你,请务必查看)
+
+## 输出(只输出一个 JSON 对象,不要解释或 markdown)
+{{"text": "把这篇帖子真正讲的创作知识完整、忠实地讲清楚;原素材没有的不要编造",
+  "from_image": "仅来自图片的知识要点;没有则空字符串",
+  "from_video": "仅来自视频的知识要点;没有则空字符串",
+  "is_empty": false}}

+ 37 - 8
prompts/screen.txt

@@ -1,15 +1,44 @@
-你在做"创作知识"筛选:判断一篇帖子是否值得提取为能指导内容创作的知识
+你在做「创作知识筛选」:判断一篇帖子值不值得被提取、入库为"能指导内容创作的知识"。本步只做通过/淘汰,不做拆分和归类
 
-判断依据的是【多模态提取后的内容】,不是原始正文。通过需同时满足:
-1. 不是空内容(多模态提取后仍有有效内容)。
-2. 和"内容创作"相关(教人怎么选题/写脚本/起号/表达等),而不是一篇作品本身(如一段文案、一张图的出图提示词、一条纯展示内容)。
-3. 至少包含一点 What(是什么/有哪些)/ Why(为什么有效)/ How(怎么做)。
-4. 至少能拆出一个知识片段。
+判断对象是【多模态提取后的内容】,不是原始正文(知识可能只在图片/视频里)。
 
+## 1. 通过标准(4 条必须同时满足)
+1. **不是空内容**:多模态提取后仍有实际内容,不是纯话题串、纯无关。
+2. **是"方法知识"而不是"作品本身"**:讲的是"怎么做内容"的方法/原理/经验/清单,能迁移到别的创作上;而不是一条具体作品(一段文案、一张图、一个具体选题、纯展示内容)。
+3. **至少含一点 What / Why / How**:是什么/有哪些(What)、为什么有效(Why)、怎么做(How),三者有其一即可。
+4. **至少能拆出一条可用的创作知识**。
+
+## 2. 核心边界:方法知识 vs 作品本身(最容易错,重点判断)
+✅ 通过(方法知识):
+- "7 种编剧常用叙事结构" —— 可复用的结构清单(What)。
+- "评论区选题法:收集高赞评论 → 归类 → 改标题" —— 可迁移的做法(How)。
+- "真正能爆的选题往往让你写完感到羞耻,因为它撕裂了大众共识" —— 原理(Why)。
+
+❌ 淘汰(作品本身):
+- "夏日雨后彩虹草原…" 配一段 AI 出图提示词 —— 这是某张图的提示词,是作品产物,不是教你怎么创作。
+- 一条写好的具体文案、一个具体选题标题、一段纯生活/风景展示。
+
+判别窍门:问自己"看完这帖,别人能不能学到一个可以用到**自己**创作上的做法/道理?" —— 能 → 方法知识;只能得到一件成品 → 作品本身。
+
+## 3. 判别顺序(按序)
+1. 多模态提取后是否为空?空 → 淘汰。
+2. 是方法知识还是作品本身?作品本身 → 淘汰。
+3. 是否和"内容创作"相关(选题/脚本/起号/表达/运营等)?无关 → 淘汰。
+4. 是否至少含一点 What/Why/How、能拆出至少一条知识?不能 → 淘汰。
+5. 以上都过 → 通过。
+
+## 4. 评分(0-10,给运营一个强弱参考)
+- 8-10:方法清晰、可直接照做、迁移性强(明确的 How,或成体系的 What)。
+- 5-7:有价值但偏零散/偏泛,或只有 Why 没有落地做法。
+- 1-4:勉强沾边,方法含糊。
+- 0:作品本身或与创作无关。
+(评分只作强弱参考;passed 仍以第 1 节 4 条硬标准为准。)
+
+## 输入
 帖子标题:{title}
 话题:{topics}
 多模态提取内容:
 {content}
 
-输出 JSON:
-{{"passed": true 或 false, "score": 0-10 的整数, "reason": "一句话理由"}}
+## 输出(只输出一个 JSON 对象,不要解释或 markdown)
+{{"passed": true 或 false, "score": 0 到 10 的整数, "reason": "一句话说明为什么通过/淘汰,点明是方法知识还是作品本身"}}

+ 37 - 14
prompts/split.txt

@@ -1,25 +1,48 @@
-你在做"创作知识"拆分:把一篇帖子拆成一个或多个知识片段
+你在做「创作知识拆分」:把一篇帖子(多模态提取后的内容)拆成一条或多条知识片段,每条标好它的 What / Why / How。本步不判断好坏(已筛选过),也不归类阶段/作用域(那是解构步骤)
 
-知识类型只有三种:
-- what:是什么 / 有哪些 / 由什么组成(类型、分类、要素、清单、特征、模板)
-- why:为什么这样做 / 为什么有效(原理、底层逻辑、机制、依据)
-- how:具体怎么做 / 怎么用(方法、步骤、技巧、流程、公式框架、实操)
+## 1. 三种知识类型的定义
+- **what(是什么 / 有哪些)**:类型、分类、构成要素、清单、特征、模板。回答"它是什么、由哪些部分组成"。
+- **why(为什么 / 凭什么有效)**:原理、底层逻辑、机制、依据、原因。回答"为什么这样做、为什么管用"。
+- **how(怎么做 / 怎么用)**:方法、步骤、技巧、流程、公式框架、可操作做法。回答"具体怎么落地"。
 
-规则:
-1. 原文(含图片/视频提取内容)有哪个就提哪个,没有的填 null,绝不为结构完整而编造。
-2. knowledge_types 必须与非空的 what/why/how 完全一致。
-3. 若 what/why/how 在讲同一个知识对象,放进同一个片段;若有多个独立知识对象,拆成多个片段。
-4. evidence 填原文中支持该片段的句子(可多条)。
+对比(避免混淆):
+- "短视频脚本含 标题/地点/分镜 等 10 个要素" → what(构成清单),不是 how。
+- "逐个把这 10 个要素填好" → how(做法)。
+- "要素齐全,是因为能让观众一眼看懂故事" → why(原理)。
 
+## 2. 一条知识片段 = 一个知识对象
+- 若 what/why/how 都在讲**同一个知识对象**(如"评论区选题法"的 是什么+为什么+怎么做),放进**同一条**片段。
+- 若帖子里有**多个相互独立的知识对象**(如"叙事结构"和"起号逻辑"是两回事),拆成**多条**片段。
+- 不要把无关知识硬塞进一条;也不要把同一个知识的 what/why/how 拆成三条。
+
+## 3. 忠实与原子
+1. **原文有什么提什么**:原素材里没有的类型一律填 null,绝不为凑齐 what/why/how 而编造。
+2. **knowledge_types 必须与非空字段一致**:哪几个字段非空,就列哪几个(顺序 what→why→how)。
+3. **title** 用能概括这条知识的具体短语,不要用泛词(如"技巧"、"方法"、"干货")。
+4. **evidence**:填多模态提取内容里**支持这条知识的原句/原话**(可多条),必须来自素材,不要自己编。
+
+## 4. 不应做的事(反例)
+- ❌ 把"作品本身"当知识:把一条具体文案原样塞进 how。
+- ❌ 把帖子主题复述成知识:how 写成"讲了短视频脚本"(这是在描述帖子,不是可迁移做法)。
+- ❌ 为结构完整编造:原文没讲 why,却硬编一个原理。
+- ❌ 过度合并:把"叙事结构"和"运镜技巧"合成一条。
+- ❌ 过度拆分:把"评论区选题法"的步骤拆成 5 条各自独立的片段。
+
+## 5. 拆完自检
+- 每条 knowledge_types 是否与非空 what/why/how 完全一致?
+- 是否有编造内容?有 → 删。
+- 是否每条都是一个独立、可复用的知识对象?
+
+## 输入
 帖子标题:{title}
 话题:{topics}
 多模态提取内容:
 {content}
 
-输出 JSON:
+## 输出(只输出一个 JSON 对象,不要解释或 markdown)
 {{"items": [
-  {{"title": "片段标题",
-    "knowledge_types": ["what" 和/或 "why" 和/或 "how"],
+  {{"title": "片段标题(具体短语)",
+    "knowledge_types": ["what 和/或 why 和/或 how,与非空字段一致"],
     "what": "内容或 null", "why": "内容或 null", "how": "内容或 null",
-    "evidence": ["支撑句", "..."]}}
+    "evidence": ["来自素材的支持原句", "..."]}}
 ]}}