100 lines
3.6 KiB
Python
100 lines
3.6 KiB
Python
# -*- coding: utf-8 -*-
|
||||
|
|
"""四份交付文档 · 跨文档一致性自检。仅读取,不改文件。"""
|
|||
|
|
import re
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
D = Path(r"D:\桌面\金融\客服agent")
|
|||
|
|
OUT = Path(r"D:\桌面\金融\_consistency.txt")
|
|||
|
|
|
|||
|
|
FILES = {
|
|||
|
|
"需求": D / "D2.2-客服Agent需求文档.html",
|
|||
|
|
"计划": D / "D2.3-客服Agent开发计划.html",
|
|||
|
|
"Todo": D / "D2.1-客服Agent执行Todolist.md",
|
|||
|
|
"知识库": D / "D2.4-客服Agent知识库设计方案.html",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
texts = {}
|
|||
|
|
lines = []
|
|||
|
|
|
|||
|
|
lines.append("== 一、文件基本情况 ==")
|
|||
|
|
for name, p in FILES.items():
|
|||
|
|
if p.exists():
|
|||
|
|
t = p.read_text(encoding="utf-8")
|
|||
|
|
texts[name] = t
|
|||
|
|
lines.append(f" {name:4s} {p.name} {t.count(chr(10)) + 1} 行 / {len(t)} 字符")
|
|||
|
|
else:
|
|||
|
|
lines.append(f" [MISSING] {p}")
|
|||
|
|
|
|||
|
|
lines.append("")
|
|||
|
|
lines.append("== 二、关键事实在各文档中的出现次数(0 = 遗漏)==")
|
|||
|
|
FACTS = [
|
|||
|
|
("功能需求 48 条", r"48 条"),
|
|||
|
|
("FR-CS-048", r"FR-CS-048"),
|
|||
|
|
("非功能需求 21 条", r"21 条"),
|
|||
|
|
("NFR-CS-021", r"NFR-CS-021"),
|
|||
|
|
("51 项", r"51 项"),
|
|||
|
|
("7 批次 / 7 个批次", r"7 个?批次"),
|
|||
|
|
("12 步", r"12 步"),
|
|||
|
|
("6 文件 / 六文件", r"(六文件|6 个?文件)"),
|
|||
|
|
("组 2 四文件", r"组 2|组2"),
|
|||
|
|
("三集合", r"三集合"),
|
|||
|
|
("阈值 0.75", r"0\.75"),
|
|||
|
|
("阈值 0.70", r"0\.70"),
|
|||
|
|
("阈值 0.65", r"0\.65"),
|
|||
|
|
("over-fetch", r"over-fetch"),
|
|||
|
|
("不变量", r"不变量"),
|
|||
|
|
("actor.py", r"actor\.py"),
|
|||
|
|
("knowledge_tier.py", r"knowledge_tier\.py"),
|
|||
|
|
("三条红线", r"三条红线"),
|
|||
|
|
("subject_type", r"subject_type"),
|
|||
|
|
("零 DDL", r"零 ?DDL"),
|
|||
|
|
]
|
|||
|
|
hdr = " " + "事实".ljust(26) + "".join(n.center(8) for n in FILES)
|
|||
|
|
lines.append(hdr)
|
|||
|
|
for label, pat in FACTS:
|
|||
|
|
row = " " + label.ljust(26)
|
|||
|
|
for name in FILES:
|
|||
|
|
t = texts.get(name, "")
|
|||
|
|
row += str(len(re.findall(pat, t))).center(8)
|
|||
|
|
lines.append(row)
|
|||
|
|
|
|||
|
|
lines.append("")
|
|||
|
|
lines.append("== 三、投顾残留检查(应全部出现在「已清除/作废」语境)==")
|
|||
|
|
for name, t in texts.items():
|
|||
|
|
if name == "知识库":
|
|||
|
|
continue
|
|||
|
|
hits = [m.start() for m in re.finditer("投顾", t)]
|
|||
|
|
bad = []
|
|||
|
|
for h in hits:
|
|||
|
|
ctx = t[max(0, h - 60): h + 60].replace("\n", " ")
|
|||
|
|
if not re.search(r"已(整体)?清除|作废|不再|已删除|清除后|已移除|已下架|原|投顾模块已", ctx):
|
|||
|
|
bad.append(ctx)
|
|||
|
|
lines.append(f" {name}: 命中 {len(hits)} 处,其中疑似「仍在依赖」{len(bad)} 处")
|
|||
|
|
for b in bad[:5]:
|
|||
|
|
lines.append(f" ⚠ …{b}…")
|
|||
|
|
|
|||
|
|
lines.append("")
|
|||
|
|
lines.append("== 四、HTML 锚点自检(TOC href vs 正文 id)==")
|
|||
|
|
for name in ("需求", "计划", "知识库"):
|
|||
|
|
t = texts.get(name, "")
|
|||
|
|
hrefs = set(re.findall(r'class="toc-item" href="#([^"]+)"', t))
|
|||
|
|
ids = set(re.findall(r'<h[1-4] id="([^"]+)"', t))
|
|||
|
|
missing = sorted(hrefs - ids)
|
|||
|
|
lines.append(f" {name}: TOC {len(hrefs)} 条 / 正文 id {len(ids)} 个 / 失效 {len(missing)}")
|
|||
|
|
for m in missing:
|
|||
|
|
lines.append(f" ⚠ 失效锚点: {m}")
|
|||
|
|
|
|||
|
|
lines.append("")
|
|||
|
|
lines.append("== 五、四文档交叉引用检查 ==")
|
|||
|
|
EXPECT = {
|
|||
|
|
"需求": ["客服Agent开发计划", "客服Agent执行Todolist", "客服Agent知识库设计方案"],
|
|||
|
|
"计划": ["客服Agent需求文档", "客服Agent执行Todolist", "客服Agent知识库设计方案"],
|
|||
|
|
"知识库": ["客服Agent需求文档"],
|
|||
|
|
}
|
|||
|
|
for name, refs in EXPECT.items():
|
|||
|
|
t = texts.get(name, "")
|
|||
|
|
for r in refs:
|
|||
|
|
lines.append(f" {name} → {r}: {'✅' if r in t else '❌ 缺'}")
|
|||
|
|
|
|||
|
|
OUT.write_text("\n".join(lines), encoding="utf-8")
|