chore(workspace): 写章节脚本 step2 / step2a 接入人感五技能

step2_write_chapter.py 在 sys.path 加入 prevent-ai-flavor /
diagnose-ai-flavor,新增「1.5) 人感前置预防」环节——生成前调用
build_prevention_contract(负约束+声音账)冻结进 WriterContext,并把
diagnosis 列为 shadow 候选的伴随检测。step2a_retrofit_ch1_context.py
相应补回退补写。

脚本只做拼装与持久化触发,五技能合同与 hard gate 由各自 skill 把守。
人感体系资产层仍由 humanization/ 维护(example 自治);本脚本只消费。
This commit is contained in:
zizi 2026-08-19 21:05:27 +08:00
parent 19a45b63bf
commit 37d508ffb0
2 changed files with 45 additions and 2 deletions

View File

@ -40,6 +40,8 @@ for sub in (
"access-database/scripts",
"check-content-consistency/scripts",
"decide-candidate/scripts",
"prevent-ai-flavor/scripts",
"diagnose-ai-flavor/scripts",
):
p = str(SKILLS / sub)
if p not in sys.path:
@ -47,6 +49,10 @@ for sub in (
from db import connect, DSN # noqa: E402
from assemble_writer_context import assemble_context # noqa: E402
from prevent_ai_flavor import ( # noqa: E402
PreventionContractError, build_prevention_contract, persist_prevention, render_writer_constraints,
)
from diagnose_ai_flavor import run_diagnosis, persist_diagnosis # noqa: E402
from retrieve_writer_sources import ( # noqa: E402
ProductionCardIndexRepository, FrozenProseRepository, RetrievalError,
build_retrieval_plan, retrieve_writer_sources, load_confirmed_fine_outline,
@ -287,6 +293,19 @@ def main():
print(f"目标第{target}章(asOf={as_of});细纲已读,基线 {got},"
f"基线总字数 {sum(len(item['text']) for item in recent_chapters)}")
# 1.5) 人感前置预防:规则/声音账先形成合同,再冻结进 WriterContext。
try:
humanization_contract = build_prevention_contract(
f"work:{WORK_ID}", load_database=True
)
humanization_contract["writer_constraints"] = render_writer_constraints(humanization_contract)
prevention_receipt = persist_prevention(humanization_contract)
except PreventionContractError as exc:
raise SystemExit(f"人感前置预防合同失败:{exc}") from exc
print(f"人感前置预防:约束 {len(humanization_contract['writer_constraints'])} 条,"
f"规则库 {humanization_contract['built_from']['rule_library_version']},"
f"run_id={prevention_receipt['run_id']}")
# 2) 检索计划 + 执行(生产仓储;新书无卡诚实返空)
token_budget = {"maxContextChars": 200000}
plan = build_retrieval_plan(
@ -324,7 +343,7 @@ def main():
narrative_state=narrative_state, recent_chapters=recent_chapters,
output_contract=output_contract, token_budget=token_budget,
pattern_references=pattern_references, style_constraints=style_constraints,
generated_at=generated_at,
humanization_contract=humanization_contract, generated_at=generated_at,
evidence_strategy="production_dual_evidence")
writer_context = assembled["context"]
(ARTIFACTS / f"{run_id}-writer-context.json").write_text(
@ -364,6 +383,20 @@ def main():
persist_call=persist_llm_event)
receipts_by_version[candidate_version] = receipt
candidates_by_version[candidate_version] = candidate
# 人感技能 3:每个候选先做只读诊断并自动落质量账;不在这里改正文。
try:
deai_artifact = run_diagnosis(
candidate["candidateBody"], work_ref=f"work:{WORK_ID}",
chapter_ref=f"chapter:{target}", mode="Audit",
)
_dump(ARTIFACTS / f"{run_id}-ai-flavor-diagnosis-v{candidate_version}.json", deai_artifact)
persist_diagnosis(deai_artifact, text=candidate["candidateBody"])
except Exception as exc:
raise PipelineError(
"AI_FLAVOR_DIAGNOSIS_FAILED", "候选 AI 味诊断或落库失败",
details={"errorType": type(exc).__name__, "message": str(exc)},
) from exc
print(f"AI 味诊断(v{candidate_version}):发现 {len(deai_artifact['findings'])} 条")
return candidate
except WriterAdapterError as exc:
if exc.code != "candidate_length_out_of_range" or retry == MAX_ATTEMPTS:

View File

@ -22,6 +22,7 @@ for sub in (
"write-next-chapter/scripts",
"record-run-evidence/scripts",
"access-database/scripts",
"prevent-ai-flavor/scripts",
):
p = str(SKILLS / sub)
if p not in sys.path:
@ -29,6 +30,9 @@ for sub in (
from db import connect, DSN # noqa: E402
from assemble_writer_context import assemble_context # noqa: E402
from prevent_ai_flavor import ( # noqa: E402
PreventionContractError, build_prevention_contract, persist_prevention, render_writer_constraints,
)
from retrieve_writer_sources import ( # noqa: E402
ProductionCardIndexRepository, FrozenProseRepository,
build_retrieval_plan, retrieve_writer_sources,
@ -117,6 +121,12 @@ def main():
authorization_snapshot = {"snapshotId": "auth-work12-production-v1",
"allowedPurpose": "production_generation",
"verifiedAt": generated_at, "sourceVersion": "v1"}
try:
humanization_contract = build_prevention_contract(f"work:{WORK_ID}", load_database=True)
humanization_contract["writer_constraints"] = render_writer_constraints(humanization_contract)
persist_prevention(humanization_contract)
except PreventionContractError as exc:
raise SystemExit(f"人感前置预防合同失败:{exc}") from exc
assembled = assemble_context(
run_id=run_id, attempt=1, mode="production", purpose="production",
quality_policy_version="writer-production-v1", work_id=WORK_ID,
@ -125,7 +135,7 @@ def main():
retrieval_plan=plan, retrieval_result=retrieval, fine_outline=fine_outline,
narrative_state=narrative_state, recent_chapters=[],
output_contract=output_contract, token_budget=token_budget,
pattern_references=[], generated_at=generated_at,
pattern_references=[], humanization_contract=humanization_contract, generated_at=generated_at,
evidence_strategy="production_dual_evidence")
(SCRIPT_DIR / "artifacts").mkdir(exist_ok=True)
(SCRIPT_DIR / "artifacts" / f"{run_id}-writer-context.json").write_text(