Files
meida/docs/开发任务包/T17-报告文案与校验.md

7.4 KiB
Raw Permalink Blame History

T17 · 报告流水线·LLM 文案与生成后校验

对应任务:T-P3-10(文案结论与诊断值一致,无自相矛盾)、T-P3-11 🔴(硬性禁忌违反数 = 0;贬损词零通过)、架构 §7.1 步骤 17~19(「生成后校验不可跳过:校验失败最多重试 2 次,仍失败降级为规则直出模板文案,绝不放行违规内容」)| 分支:task/t17-report-copy | worktree:/home/xsl/meida_backend-t17 先读《README.md(协作规程)》,遵守全部纪律。第四批拼流水线:T15 定 Stage 接口,你供文案与校验两个阶段,文件名与类名已定死。

2. 你要创建的文件(挂点,禁差分毫)

文件 导出 流水线 dotted path
packages/report/copy.py 纯逻辑:结论→文案素材、模板降级渲染 —
packages/report/copy_stage.py class CopyStage packages.report.copy_stage:CopyStage
packages/report/validation.py 纯逻辑:贬损词表、一致性校验器 —
packages/report/validation_stage.py class ValidationStage packages.report.validation_stage:ValidationStage

Stage 接口以协调提交 packages/report/pipeline.py 骨架为准;ctx.gateway 是 T15 注入的 LLMGateway(集成测试可换 FakeProvider——参考 tests/integration/test_vertical_slice.py 的做法)。

3. LLM 文案(copy.py + copy_stage.py)

  1. Prompt:prompts/report_copy/v1.txt(你新建,版本化目录规则见 prompts/README.md——[system] 段不许含任何变量(缓存前缀纪律,validate_cache_prefix 会拦);[user] 段放 {dimensions_json})。system 定角色:形象顾问报告文案;红线写进 system:描述而非评判、不用绝对化用语、不出现贬损词、结论只能复述给定诊断值不得新增维度结论、简体中文。
  2. 结构化输出:gateway.complete(scene=Scene.REPORT_COPY, prompt_vars={...}, schema=ReportCopy, user_id=..., ref_type="report", ref_id=str(report_id))——先读 packages/llm/gateway.py 的 complete 签名与 Scene 枚举、packages/llm/routing.py 里 REPORT_COPY 场景现有配置(temperature/prompt_id 指向你的 v1)。ReportCopy(BaseModel):summary: str、sections: list[Section](Section:title/paragraphs: list[str])——schema 宽进严出的取舍写注释(字段越少结构化成功率越高,文案主体自由度放 sections 内)。
  3. 素材组装(纯函数 build_prompt_material(result_diagnosis) -> str):从 T16 的 result["diagnosis"]["dimensions"] 取 status=ok 的维度(skipped 不进 prompt——LLM 看不到缺失维度就不会编造它,这是防幻觉的第一道闸);序列化成紧凑 JSON(key+value+evidence,舍 confidence 小数位)。总长控制:拼好后若超 ~6000 字符,按 basic_coverage 优先级裁剪维度并记录 dropped_keys(对齐架构 §7.2 的裁剪思想:低重要度先丢,硬结论永不丢)。
  4. CopyStage(name="copy"):无 diagnosis 产物 → 抛错(流水线顺序错);调 gateway → result["copy"] = {"summary": ..., "sections": [...], "model": completion.model, "prompt_version": ..., "dropped_keys": [...]}。这里不做校验——校验是下一阶段的独立职责(T-P3-10 的"生成后校验"是流水线步骤 18,不是文案函数的内嵌断言)。

4. 生成后校验(validation.py + validation_stage.py)

  1. 贬损词表初版(validation.py 模块常量 PEJORATIVE_TERMS,来源:G:\meida\docs\合规与安全方案.md §3「内容伦理红线」——开工先读该节,把"描述而非评判/不使用缺陷框架"翻译成具体词表:胖/丑/矮小/缺陷/土气/难看/显老/失败 等约 20~40 词 + 简单变形("有点胖"命中"胖"即可,不做词干)。词表带注释:这是初版内嵌版,正式版归合规词库任务(T-P0-07)。
  2. 一致性校验(纯函数):
    • check_pejorative(text) -> list[str](命中词列表);
    • check_conclusion_consistency(copy: ReportCopy, dimensions: list[dict]) -> list[str](不一致清单):初版三条规则——① 文案中出现的体型/脸型/季型枚举词必须是诊断值同款(诊断说 H 型、文案写 A 型 → 不一致);② 文案提到具体色值 #RRGGBB 必须在色板维度 value 集合内;③ 出现"建议"句式却无对应 rule_hits 支撑的维度结论 → 标记(宽松口径,注释说明误报代价 vs 漏报代价的取舍)。
    • check_absolute_claims(text):绝对化用语(最/第一/彻底/百分百——prompt 禁了,校验兜底)。
  3. ValidationStage(name="validation"):取 copy + diagnosis → 全部校验 →
    • 全过:result["validation"] = {"passed": true, "checks": {...计数}};
    • 有违规:重试一次——把违规清单作为修正指令追加(messages 上下文,参考 gateway 的结构化重试机制但不能用它内部的重试——那是解析层,这是语义层,两层独立)再生成 → 再校验 → 仍违规 → 降级模板:render_fallback_copy(dimensions, rule_hits)(纯函数:按维度 evidence + rule explanation 拼模板文案,零 LLM)→ result["validation"] = {"passed": true, "degraded": true, "violations_first_pass": [...]}。任何出口 passed 必须为 true 或阶段抛错——绝不放行未过校验的文案(T-P3-11 红线)。
  4. 校验产物同段落库(result["validation"]),报告查询侧能看到是否降级。

5. 测试要求

  • 单测 tests/unit/test_report_copy.py:素材组装(skipped 不进、超长裁剪记录 dropped、硬结论不裁)、模板降级渲染(有 rule_hits 时含 explanation)。
  • 单测 tests/unit/test_report_validation.py:词表命中(含"有点胖"变形)、一致性三条规则各一正一反、绝对化用语、重试后仍违规 → 降级路径纯函数级验证。
  • 集成 tests/integration/test_report_copy_stage.py(新文件,FakeProvider 替换 gateway——参考 test_vertical_slice):
    1. 干净 LLM(Fake 返回合规文案)→ copy + validation 两阶段 passed=true;
    2. 脏 LLM(Fake 第一次返回含"微胖/最合适",修正后干净)→ 第一轮 violations 非空 → 重试通过;
    3. 持续脏 LLM(恒返贬损词)→ 降级模板 passed=true degraded=true,最终文案零贬损词(T-P3-11 的黄金断言)。
  • 不测整条流水线(T15 集成已覆盖编排);只直接构造 ctx 调你的阶段。

6. 禁改清单

通用禁改之外:packages/report/ 除你四个文件 + prompts/report_copy/** 外全部、apps/**、全部已有测试。prompts/report_copy/v1.txt 归你(新目录不与他人冲突)。

7. 验收标准(T-P3-10/11)

  1. 校验不可跳过:任何出口要么 passed 要么抛错;
  2. 贬损词零通过(含持续脏 LLM 的降级路径断言);
  3. 文案-结论一致性三条规则生效;
  4. LLM 看不到 skipped 维度(防幻觉得到结构保证);
  5. 全部检查绿(mypy 范围同 T15 + 你的文件)。

8. 提交信息

feat(report): LLM copy generation with mandatory post-validation and fallback

report_copy/v1 prompt(系统段零变量)+ 结构化 ReportCopy + 素材组装
(skipped 不进 prompt/超长裁剪)+ 贬损词表/一致性/绝对化三重校验 +
重试一次后降级规则直出模板(T-P3-10/11)。

偏差说明:<如有写在这里,无则写"无">