fix(writer): 无子节章剔除 LLM 自造 heading 块

- writer_agent: prompt【小节约束】明确空结构时不得输出 heading 块
- writer_agent: generate_chapter 程序化强制——template_marker.sub_headings
  为空的章,剔除生成结果中全部 type=heading 的内容块(LLM 遵循度不完美,
  以模板结构为准做确定性兜底)
- 真实试运行验证:自造与章同名 H2 清零、H2 总数 14→6(仅模板定义子节)、
  内容引用不受影响
This commit is contained in:
lhl
2026-08-24 13:19:11 +08:00
parent 0a498e4f7a
commit 5091125fbc
3 changed files with 55 additions and 1 deletions
+6 -1
View File
@@ -27,7 +27,8 @@ WRITER_PROMPT_TEMPLATE = (
"请输出符合 schema 的章节内容 JSON。\n"
"【小节约束】若上方「本章小节结构」非空,必须按该小节顺序组织内容,"
"每个小节以 type=heading、level=2 的内容块开头(标题使用小节原文),随后为该小节的内容块;"
"不得遗漏或新增小节。为空时按章节主题自行组织。\n"
"不得遗漏或新增小节。若「本章小节结构」为空,则不得输出任何 type=heading 的内容块"
"(章节标题已由模板提供),仅以 paragraph/table/list/note 块组织内容。\n"
"【主题约束】本章必须且仅围绕标题「{{title}}」所对应的主题撰写,"
"严格以「参考资料(本章对应数据)」中的要件定义数据和「影响调查上下文」为核心依据;"
"禁止输出与本章无关的系统整体架构、通用设计说明等内容,禁止套用其他章节的主题。"
@@ -143,6 +144,10 @@ class WriterAgent:
except (KeyError, TypeError, ValueError) as e:
last_err = e
continue
# 模板结构为准(design §6.5):无子节结构的章,剔除 LLM 自造的
# heading 块(prompt 约束为尽力而为,此处程序化强制)
if not (getattr(context.template_marker, "sub_headings", None) or []):
content.blocks = [b for b in content.blocks if b.type != "heading"]
self.state.record_success(content)
return content
raise WriterGenerationError(f"章节 {context.chapter_id} 重试耗尽: {last_err}")