框架: parse_llm试拆首轮对症四改——细纲绝对字数上限+超标压缩重试+source机械回填+归型五型均衡纪律(15章实测:scaffold全过/craft偏科待验)
This commit is contained in:
parent
ee372f7ea2
commit
7be76b9ebb
@ -10,6 +10,7 @@
|
||||
"""
|
||||
import json
|
||||
import pathlib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
@ -54,12 +55,15 @@ CONTRACTS = {
|
||||
|
||||
def scaffold_prompt(title, ch, ch_title, text, prev_entities):
|
||||
ents = json.dumps(prev_entities, ensure_ascii=False) if prev_entities else "(第一章,为空)"
|
||||
# 绝对字数上限比抽象比例对 LLM 更可执行(首轮实测 M3 按比例会写到 9.8%–19%)
|
||||
wc = len(text.replace("\n", "").replace(" ", ""))
|
||||
cap = max(60, int(wc * 0.05))
|
||||
return f"""【muse 创作实验台·拆书 2b·脚手架 pass】
|
||||
{IDENTITY}
|
||||
|
||||
【功能指令(parse-book 逐章内环)】
|
||||
对参考书《{title}》第 {ch} 章《{ch_title}》(正文附后):
|
||||
1) 逆推本章细纲:章目标/关键事件/出场角色/伏笔动作(埋·推·收)/章末钩子。字数=章正文的 3–5%(3000字章→100–150字),硬顶 8%,超标会被校验脚本退回。细纲是结构骨架,不是缩写复述。
|
||||
对参考书《{title}》第 {ch} 章《{ch_title}》(正文附后,约 {wc} 字):
|
||||
1) 逆推本章细纲:章目标/关键事件/出场角色/伏笔动作(埋·推·收)/章末钩子。**细纲全文不得超过 {cap} 字**(章正文的 5%;超标会被校验脚本机械退回)。细纲是结构骨架,不是缩写复述——用短语与分号,不写完整句子。
|
||||
2) 抽实体增量(脚手架级索引):{ENTITY_CRITERIA}
|
||||
判重:下方是前文已收录实体,不重报(除非本章给出新身份,则在一句话摘要里并入)。
|
||||
|
||||
@ -83,7 +87,8 @@ def patterns_prompt(title, ch, ch_title, text, outline, existing_cards):
|
||||
{json.dumps(CONTRACTS, ensure_ascii=False)}
|
||||
纪律:
|
||||
- 宁缺毋滥:一章 0–3 张为常态,只收本章表现突出、可跨书复用的写法;平庸章可出 0 张。
|
||||
- 归型走判据;五型之外一律不出卡。
|
||||
- 归型走判据;五型之外一律不出卡。**先按判据定 type,再只用该 type 字段表里的中文 key 填 fields——混用他型字段=机械拒卡**(如 trope 的「公式步骤」不得出现在 craft 卡里)。
|
||||
- **五型都是候选,不要把一切归成 craft**:整场武力对抗→combat;整场情绪戏→emotion;拍卖/谈判/审讯等场景公式→scene_pattern;跨章复用的情节公式→trope;craft 只留给「单点装置」(删去它场景仍成立)。type 值必须与 fields 所用字段表同型。
|
||||
- **脱敏红线**:只写抽象结构与手法归纳,严禁抄录原文;≥15 连续字与原文重合=校验脚本机械拒卡。卡名与字段值用「主角/强敌/导师」等抽象指代,**不得出现书内专名**(人名/地名/机甲名/组织名)——专名只允许出现在 source.anchor 里。
|
||||
- fields 按该型字段合同的中文 key 填;没证据的 key 省略,不编造。
|
||||
- 判重:下方已积累卡名录,不与之重复立同义卡。
|
||||
@ -176,14 +181,24 @@ def main(work_id, from_, to, model):
|
||||
# pass1 脚手架(断点续跑:done 跳过)
|
||||
if s_st != "done" or outline is None:
|
||||
try:
|
||||
data, usage = m3_json(scaffold_prompt(title, ch, ch_title, text, prev), model,
|
||||
("outline", "entities"))
|
||||
p1 = scaffold_prompt(title, ch, ch_title, text, prev)
|
||||
data, usage = m3_json(p1, model, ("outline", "entities"))
|
||||
total_in += usage.get("prompt_tokens", 0)
|
||||
total_out += usage.get("completion_tokens", 0)
|
||||
ok, out = ingest("scaffold", work_id, ch, data)
|
||||
# 比例超标是 M3 高频病:带压缩指令重试 1 次(首轮实测 10/15 章超标)
|
||||
if not ok and "细纲比例" in out:
|
||||
cap = max(60, int(len(re.sub(r"\s", "", text)) * 0.05))
|
||||
data, usage = m3_json(
|
||||
p1 + f"\n\n【重试】上次细纲 {len(data['outline'])} 字超标被退回。"
|
||||
f"压缩到 {cap} 字以内:只留章目标/关键事件/伏笔动作/钩子,删掉一切修饰与过程描述。",
|
||||
model, ("outline", "entities"))
|
||||
total_in += usage.get("prompt_tokens", 0)
|
||||
total_out += usage.get("completion_tokens", 0)
|
||||
ok, out = ingest("scaffold", work_id, ch, data)
|
||||
click.echo(f" {out}")
|
||||
if not ok:
|
||||
continue # 比例超标等已记 task failed,重跑本命令补
|
||||
continue # 已记 task failed,重跑本命令补
|
||||
outline = data["outline"]
|
||||
except RuntimeError as e:
|
||||
click.echo(f" #{ch} 脚手架 M3 失败: {e}")
|
||||
@ -195,6 +210,13 @@ def main(work_id, from_, to, model):
|
||||
("cards",))
|
||||
total_in += usage.get("prompt_tokens", 0)
|
||||
total_out += usage.get("completion_tokens", 0)
|
||||
# source 机械回填:book/chapter 是调用侧确定数据,不依赖 LLM 自觉
|
||||
#(实测 M3 偶发 source=null 整批被拒);anchor 是内容性字段,缺时用 brief 兜底
|
||||
for c in data.get("cards") or []:
|
||||
src = c.get("source") or {}
|
||||
c["source"] = {"book": src.get("book") or title,
|
||||
"chapter": src.get("chapter") or f"第{ch}章 {ch_title}",
|
||||
"anchor": src.get("anchor") or c.get("brief") or ""}
|
||||
_, out = ingest("patterns", work_id, ch, data)
|
||||
click.echo(f" {out}")
|
||||
except RuntimeError as e:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user