Преглед изворни кода

Why 补强:加 why 轻闸(②.7) + 形式往简(为什么/取舍) + 取舍↔how边界

- 新增 prompts/gate_why_refute.txt 单票 refute:废话→drop / 实为what·how→标 inferred 保留 / 真原理放行
- decompose.py drop_fake_whys():分支收窄(仅 实为what/how 标 inferred,矛盾态保守保留),接入主流程 ②.5 之后
- phase1-frame.md:Why 形式从六类合并为「为什么/取舍」两类;加"取舍不是操作步骤、否则是how"边界
- 知识类型.json why payload形态同步;前端 FORM_PLAIN 补"为什么"、名词说明改两类
- 强制取舍保留(创作教学帖输入,无脑补风险,经数据核验 6/6 取舍可追溯原帖)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SamLee пре 3 недеља
родитељ
комит
09dc302093

+ 11 - 0
prompts/gate_why_refute.txt

@@ -0,0 +1,11 @@
+你在审查(带着怀疑核验,但只认事实、命中才算):下面这颗被判为「Why(原理)」的创作知识,是不是**不配单独入库的伪 Why**。
+
+命中下面任一 → not_why=true:
+- 【正确的废话】放之四海皆准、无信息量(如"内容要有价值""标题要吸引人""要懂用户"),没有具体可复用的因果或判断依据。
+- 【其实是 What】只是在**界定某对象 / 列举构成 / 给清单**,并没有解释"为什么这样做 / 为什么会这样"。判据:去掉它,读者少的是"一个定义/清单",而不是"一个道理"。
+- 【其实是 How】本质是一串**可执行的操作步骤/工序**,而非解释道理。判据:它在教"先做 X 再做 Y",不是在讲"为什么 X 有效"。
+
+只有当它**解释了某创作做法/判断背后的道理(为什么成立 / 怎么起作用),且脱离具体语境仍可复用**,才是真 Why → not_why=false。
+
+用户消息含该颗的 主张 + 支撑。如实核验:命中哪条就指出哪条;**一条都不命中,就如实判 not_why=false——别为了挑刺硬凑理由**。
+输出 JSON:{"复述":"...","verdict":"真原理|废话|实为what|实为how","reason":"一句话","not_why":true/false}

+ 28 - 1
scripts/decompose.py

@@ -35,6 +35,7 @@ NORMALIZE = load_prompt("normalize_scope")    # ③前:作用域值名词化
 GATE_HOW_ADMIT = load_prompt("gate_how_admit")        # ②.5 有序性闸:判"真流水线"
 GATE_HOW_REFUTE = load_prompt("gate_how_refute")      # ②.5:挑"假how(离散构成硬串)"
 GATE_HOW_TIEBREAK = load_prompt("gate_how_tiebreak")  # ②.5:分歧裁决(边界倾向假how)
+GATE_WHY_REFUTE = load_prompt("gate_why_refute")      # ②.7 why 轻闸:单票 refute(废话/实为what/实为how)
 
 # ① 窄表确定性兜底:只放无歧义裸动作动词(绝不放 营造/引导/表达 等名词语素)
 _STRIP_VERBS = ("寻找", "定位", "推导", "核验", "提取", "挖掘", "捕捉",
@@ -226,6 +227,32 @@ def fix_fake_hows(knowledges: list[dict]) -> list[dict]:
     return out
 
 
+# ---------- ②.7 why 轻闸:单票 refute(废话→drop;实为what/how→标 inferred 保留,不丢内容)----------
+def drop_fake_whys(knowledges: list[dict]) -> list[dict]:
+    out = []
+    for k in knowledges:
+        if k.get("type") == "why":
+            payload = json.dumps({"主张": k.get("主张"),
+                                  "支撑": [{"小标题": b.get("小标题"), "内容": b.get("内容")}
+                                          for b in k.get("支撑", [])]}, ensure_ascii=False)
+            try:
+                r = chat_json(GATE_WHY_REFUTE, payload, timeout=90)
+                not_why, verdict, reason = bool(r.get("not_why")), r.get("verdict", ""), r.get("reason", "")
+            except Exception:
+                not_why, verdict, reason = False, "", "API错误→保留"   # 兜底:保留,避免误杀
+            if not_why:
+                if verdict == "废话":   # 正确的废话:无复用价值,直接 drop
+                    print(f"  ②.7 why闸:drop 废话「{k.get('title')}」({reason})")
+                    continue
+                if verdict in ("实为what", "实为how"):  # 误分类:保留但标 inferred,待人工看,不丢内容
+                    k["inferred"] = True
+                    k["inferred_reason"] = f"why闸疑似{verdict}:{reason}"
+                    print(f"  ②.7 why闸:标记「{k.get('title')}」({verdict}:{reason})")
+                # 其它(not_why 与 verdict 自相矛盾/空)→ 保守保留、不扣帽子
+        out.append(k)
+    return out
+
+
 # ---------- ③ 作用域候选 + 定位 ----------
 def _slim(knowledges: list[dict]) -> list[dict]:
     slim = []
@@ -418,7 +445,7 @@ def main() -> None:
             posts_out.append({**meta, "no_knowledge": True, "knowledges": []})
             continue
         print(f"  ① 读懂 {len(read)} 字({media['type']})· ①.5 闸:创作({gate_why})")
-        knowledges = fix_fake_hows(shape(post, read))   # ② 拆颗 → ②.5 假how根治(假how重拆为 what/why)
+        knowledges = drop_fake_whys(fix_fake_hows(shape(post, read)))   # ② 拆颗 → ②.5 假how根治 → ②.7 why轻闸
         how_ids = {k.get("id") for k in knowledges if k.get("type") == "how"}
         how_titles = {k.get("id"): k.get("title") for k in knowledges if k.get("type") == "how"}
         for k in knowledges:

+ 4 - 7
web/index.html

@@ -187,7 +187,7 @@ how 工序每一步命中其中**一个**;不在这 5 个里的值会被代码
 
 (区别于「动作」:动作是模型从帖子里实时抽的、不固定;创作阶段是定死的 5 选 1。)`;
 // 把提示词里的"黑话"形式标签换成大白话(找不到就原样显示)
-const FORM_PLAIN={"取舍":"怎么用","依据":"为什么对","机制":"怎么起作用","平台逻辑":"平台规则","读者心理":"读者心理","例证":"例子","反例":"反例","判据":"判断标准","对照":"对比","清单":"清单","分类":"分类","定义":"定义","维度":"方面"};
+const FORM_PLAIN={"取舍":"怎么用","为什么":"为什么对","依据":"为什么对","机制":"怎么起作用","平台逻辑":"平台规则","读者心理":"读者心理","例证":"例子","反例":"反例","判据":"判断标准","对照":"对比","清单":"清单","分类":"分类","定义":"定义","维度":"方面"};
 const plainForm=f=>FORM_PLAIN[f]||f;
 const GLOSSARY=`## 一篇帖子能拆出三种知识(平级的)
 这三种各帮你做一个不同的决定,没有谁更重要。
@@ -205,12 +205,9 @@ const GLOSSARY=`## 一篇帖子能拆出三种知识(平级的)
 - **序列**:几个部件**都要、且有前后位置**(例:故事五部分、黄金三段式)。只是位置顺序——后段若**消费**前段产出、换序就崩,那就成 how 工序了。
 
 ## 「为什么」里每条道理的小标签
-说明这条是哪种支撑:
-- **怎么用**(原"取舍"):这条道理落到创作上——该多写什么、砍什么。**最重要,每条「为什么」都有**。
-- **为什么对**(原"依据"):这条说法凭什么成立。
-- **怎么起作用**(原"机制"):它是怎么运转、起效果的。
-- **平台规则 / 读者心理**:从平台算法、或读者角度的解释。
-- 例子 / 反例 / …:举例支撑(这些标签是开放的,可能还有别的)。`;
+说明这条是哪种支撑(现在只两类):
+- **怎么用**(原"取舍"):这条道理落到创作上——该多写什么、砍什么、何时适用。**最重要,每条「为什么」都有**。
+- **为什么对**(原"为什么/依据/机制"):这条原理为什么成立、怎么起作用(依据、机制、平台规则、读者心理、例证都归这一类)。`;
 
 const STEPS=[
   {key:"read",label:"读懂帖子",desc:"把图、视频读成文字",

+ 4 - 3
创作知识提取-skill/extraction/phase1-frame.md

@@ -96,8 +96,9 @@
 
 ### Why(为什么)— role 主 或 组件
 `主张`(**唯一必填**,核心观点/原理,做锚点)+ `支撑`:**1..N 个自由小节**,每节 `{小标题, 形式?, 内容?, 条目?}`。无 steps。+ 颗级 `出处`。
-- **决策落点必填**:`支撑` 里**必须有一节 `形式:取舍`**——写「**这条原理对创作的取舍含义**:所以该多写什么 / 砍什么 / 侧重什么 / 何时适用」。这是 Why 的命根(官方:why 影响取舍判断);只讲原理不落取舍 = 半成品。
-- 其余 `形式` 自由:依据 / 机制 / 平台逻辑 / 读者心理 / 例证 / 反例…(有几条写几条)。
+- **形式只有两类**(往简):`为什么`(解释这条原理**为什么成立 / 怎么起作用**——依据、机制、平台逻辑、读者心理、例证/反例**全归这一类,不再细分**);`取舍`(对创作的取舍含义)。
+- **决策落点必填**:`支撑` 里**必须有一节 `形式:取舍`**——写「**这条原理对创作的取舍含义**:所以该多写什么 / 砍什么 / 侧重什么 / 何时适用」。这是 Why 的命根(why 影响取舍判断);只讲原理不落取舍 = 半成品。
+- ⚠️ **取舍 ↔ how 边界**:取舍写的是**原则层的"该往哪偏 / 何时适用"(决策倾向)**,**不是手把手操作步骤**。一旦写成"第一步…第二步…"的可执行流程,那就是 how 不是 why——回去拆 how,或只留原则性的取舍判断。
 > 组件 why:对应某 how 的某一步(那步的依据/原理),但本身是独立一颗、可单独复用。不对应任何步 → 就是单独的一条(role=主)。
 > ⚠️ 取舍必须从原帖逻辑推得、忠实;原帖只给原理没明说取舍 → 据原理写出**最直接**的一条创作含义,别过度发挥。
 
@@ -176,7 +177,7 @@
       "title": "<原理名>", "业务阶段": ["<…>"], "出处": ["<这颗来自哪些卡片>"],
       "主张": "<核心观点/原理(必填)>",
       "支撑": [
-        {"小标题":"<为什么成立>","形式":"依据","内容":"<原理/平台逻辑/读者心理>"},
+        {"小标题":"<为什么成立/起作用>","形式":"为什么","内容":"<依据/机制/平台逻辑/读者心理/例证>"},
         {"小标题":"<对创作的取舍(必填,命根)>","形式":"取舍","内容":"<所以创作时该多写/砍/侧重什么、何时适用>"}
       ],
       "作用域": []

+ 1 - 1
创作知识提取-skill/taxonomy/知识类型.json

@@ -22,7 +22,7 @@
     {
       "分类名称": "why",
       "dim_attributes值": "why原理",
-      "payload形态": "简化(主张 + 依据 + 对创作的影响,无 steps)",
+      "payload形态": "简化(主张 + 为什么 + 取舍,无 steps;形式只两类:为什么/取舍)",
       "分类说明": "这颗知识是『为什么』——解释某种创作做法/判断背后的原理、依据、平台逻辑、读者心理。典型:为什么标题决定打开率、为什么先写冲突、为什么这种结构传播好。判别口诀:读完主要收获是『理解了某件事为什么这样做』,是解释性/原理性的,较少具体步骤。注意:why 始终是独立一颗——定死两态:要么单独的一条(role=主),要么对应某 how 的某一步而成组件颗(role=组件,parent={how_id,step})。二者皆可,不存在『写进步骤指引、不单独成颗』;与 what 完全对称。",
       "分类性质": "原理"
     }