Files
cad-agent/dwg_review/checklist.py
T
gjm f7fa8f14d9 feat(review): 审查结论改为结构化 JSON,移除二次 LLM 抽取
- checklist.py:系统提示加入结构化输出契约(只输出 {summary, issues[]},
  引用 handle 必须真实存在、不得编造)
- review.py:review_frame 返回 {summary, issues, raw};仅在「不再请求工具」的回合
  解析结论,中间工具回合的 content 永不解析;强制收口那次 chat 不传 tools
- report.py:删除 extract_issues 与 _EXTRACT_SYSTEM(不再需要第二次 LLM 调用);
  新增 format_finding(用 .get,顺带修复缺 frame 键 KeyError);save_report 的
  issues 省略时从 findings 拍平
- __main__.py:主流程改为 确定性检查 → review_frame → build_finding(合并+校验),
  issues 由 flatten_issues 派生

顺带修复既有 gap:summarize 硬下标 KeyError、extract_issues 单行围栏解析失败。
2026-10-14 19:53:41 +08:00

94 lines
4.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""审查清单加载 + 系统提示构建(清单驱动)。"""
import json
from . import config
DEFAULT_CHECKLIST = {
"name": "内置通用清单",
"categories": [
{"title": "图层规范性", "severity": "medium",
"checks": ["图元是否在正确图层", "是否存在空图层/命名异常图层"]},
{"title": "文字", "severity": "medium",
"checks": ["空文字", "错别字", "字高异常", "文字重叠"]},
{"title": "标注", "severity": "high",
"checks": ["关键尺寸缺失", "标注值异常"]},
{"title": "几何", "severity": "medium",
"checks": ["零长度/退化实体", "重复重叠实体", "未闭合轮廓"]},
{"title": "图面整体", "severity": "low",
"checks": ["图面完整性", "内容是否超出图框"]},
],
}
def load_checklist(path=None):
"""加载审查清单 JSON;失败时回退内置默认清单。"""
path = path or config.CHECKLIST_PATH
try:
with open(path, "r", encoding="utf-8") as f:
data = json.load(f)
if isinstance(data, dict) and data.get("categories"):
return data
print(f"[Warn] 审查清单 {path} 结构异常,使用内置默认清单。")
except Exception as exc: # noqa: BLE001
print(f"[Warn] 无法加载审查清单 {path}: {exc},使用内置默认清单。")
return DEFAULT_CHECKLIST
def build_system_prompt(checklist, *, allow_tools=True):
"""根据审查清单动态生成 LLM 系统提示词。"""
lines = [
"你是一名资深建筑与工业厂房图纸审查专家。",
"你将逐张收到某个图框(一张图纸)的:结构化图元数据、文字内容,以及该图框的视口截图。",
"",
f"请依据审查清单《{checklist.get('name', '审查清单')}》逐项审查,"
"指出**具体问题**(尽量引用实体 handle 或文字内容),并标注严重程度:",
"",
]
for cat in checklist.get("categories", []):
lines.append(f"【{cat.get('title', '')}】(严重度:{cat.get('severity', 'medium')})")
for chk in cat.get("checks", []):
lines.append(f" - {chk}")
lines.append("")
if allow_tools:
lines += [
"你可以调用**只读**取证工具进一步确认细节(例如放大局部、查实体详情、查重复实体)。",
"当结构化数据不足以判断时,先调用工具取证,再下结论。",
"",
]
lines += [
"要求:",
"- 只报告你**有依据**的问题,不要臆测;数据与截图冲突时以数据为准。",
"- 按清单条目组织结论,未命中的条目可省略。",
"- 不要复述输入数据。",
"",
"输出格式(**必须严格遵守**):",
"在你完成全部取证、准备给出该图框的最终结论时,**只输出一个 JSON 对象**,"
"不要输出任何解释文字,也不要用 markdown 代码块包裹。结构如下:",
"{",
' "summary": "<该图框的一句话整体结论;若未发现问题,写“未发现明显问题”>",',
' "issues": [',
" {",
' "category": "<图层/文字/标注/几何/图面整体 之一>",',
' "severity": "<high|medium|low>",',
' "message": "<问题描述,简洁具体>",',
' "handle": "<该问题对应的实体句柄;无法定位到具体实体时省略此字段>"',
" }",
" ]",
"}",
"其中 `handle` 必须是你**在取证数据或工具返回里真实见过**的句柄,不要编造;"
"无法确定具体实体时省略 `handle`,该问题仍会被记录。",
]
if allow_tools:
lines.append("(需要进一步确认时先调用工具;拿到结果后,最终再输出上述 JSON。)")
return "\n".join(lines)
def checklist_summary(checklist):
"""用于规划阶段的一句话摘要。"""
cats = checklist.get("categories", [])
return f"{checklist.get('name', '清单')}({len(cats)} 类:" + \
"、".join(c.get("title", "") for c in cats) + ")"