总原则(UX 安全)
全部改动落在离线质量脚本 + prompt 层 + 判定输出结构,不触碰交互路径延迟:
/submit、/feedback、/assess/stream的耗时零增加(判定→再生只发生在离线脚本run_quality_test.py)- 工作流重试改造是同延迟更聪明(同样的 9 次 LLM 调用,但带上诊断 hint),不加调用
阶段一 ②:判定幻觉 → 携带诊断的定向再生(最高优先级)
1.1 _generate_one 支持修正 hint(content_generator.py)
_build_generation_prompt(node, theory_level, content_type, correction_hint="")新增可选参数;非空时 system 消息追加"【上轮判定修正要求】{hint}。重点修正上述问题,其余保持原结构。"_generate_one(node, theory_level, content_type, correction_hint="")透传
1.2 新文件 backend/app/agents/quality_regen.py
python
def regenerate_flagged(resources, hallucination_result, kg) -> dict:
# verdict=="hallucinated" 的资源 → kg.get_node(target_node_id) 取节点
# → adaptation_profile 反映射 theory_level (beginner→2/intermediate→3/advanced→5)
# → _generate_one(node, level, content_type, correction_hint=verdict.reason)
# → 原位替换(保持顺序),节点缺失/生成失败保留原资源
# ThreadPoolExecutor 并行 (min(CONTENT_GEN_CONCURRENCY, n))
# 返回 {resources, regenerated_count, regen_indexes, failures}
1.3 工作流盲重试 → 定向重试(content_generator.py)
_node_body 开头:
python
retry_hint = ""
if state.get("content_phase_entered") and isinstance(state.get("review_results"), dict):
retry_hint = (state["review_results"].get("retry_hint") or "").strip()
tasks 元组带上 hint 传入 _generate_one(reviewer 产出的 retry_hint 首次被消费;首轮 content_phase_entered=False 不注入,语义安全)
1.4 离线脚本闭环(scripts/run_quality_test.py)
measure_one 里 judge 后:hallucinated > 0 → regenerate_flagged → 只对被替换资源重跑 judge → 汇总:
python
independent = {
"hallucination": <第一轮>,
"regen": {"regenerated": n, "reasons": [...], "after": {rate, hallucinated, total}} | None,
"adaptation": ...
}
--no-regen开关(默认开);artifacts 的 resources 更新为再生后(--judge-only 复跑看到的是修复后状态)aggregate()增加 independent 再生聚合(before_rate / after_rate)write_markdown增加"幻觉定向再生闭环"小节(before→after 对比表)
1.5 测试
- 新
backend/tests/test_quality_regen.py:只替换 flagged / hint 透传捕获 / 节点缺失保原 / 无幻觉 no-op / 非 dict 资源跳过 - 扩展
test_content_generator_unit.py:correction_hint 注入 prompt;retry_hint 状态流(state 带 content_phase_entered+retry_hint → _generate_one 收到 hint;首轮不注入)
阶段二 ①:生成时认识状态标记(unverified_claims)
_build_generation_prompt/_generate_feedback_one的 JSON schema 增加:"unverified_claims": ["图谱事实之外的类比/背景性陈述, 每条一句; 完全锚定为空数组"]system 说明:自声明用于定向审计(类比允许,但要浮出水面),不是禁止_generate_one/_generate_feedback_one:data.setdefault("unverified_claims", [])+ 非 list 强转[]judge_hallucination:_build_hallucination_prompt(content, facts_text, unverified=None)追加"## 资源自声明待验证补充"块;从r.get("unverified_claims")读run_quality_test.py:per_run + aggregate 统计unverified_claims总数(审计覆盖率证据)- 测试:setdefault 兜底、prompt 含字段、judge prompt 含自声明块、空数组不追加
阶段三 ③:先锚定后展开(bridge-before-conclusion)
_build_generation_promptsystem 增加: "【先锚定后展开】资源的第一小节必须先用 1-3 句复述节点 summary/key_points 已给事实(不加新信息),随后的展开只能阐释已锚定事实;结论不得先于其图谱依据出现。"- correction_hint 再生路径天然强化(修正要求 + 先锚定)
- 同步
data/prompts/04_content_generator_agent.txt设计稿(新增同名小节) - 测试:prompt 字符串含规则;04 spec 文件含小节
阶段四 ④:验证方式 + 覆盖双记录
-
data/prompts/judge_hallucination.txt输出 JSON 增加"coverage": "full|partial|none"(内容对节点 key_points 的锚定覆盖度) -
quality_judge.py:verdict dict 读入evidence_node_ids(现在被忽略)+coverage(非法值兜底 "none") -
quality_metrics.py新纯函数:python
def compute_anchor_coverage(verdicts) -> {"full": n, "partial": n, "none": n, "rate_full": float} -
run_quality_test.py:independent 聚合带 coverage 统计;markdown 判定表加"锚定覆盖"行;verdicts 留档 evidence_node_ids(验证依据可追溯) -
测试:judge 读入两字段、非法兜底、compute_anchor_coverage 纯函数
