Stage B2(CAD 实测标定)与收尾:
- 新增 verify_text_resolution.py:临时加字(字高 200 图形单位 = 1:100 纸面 2mm)+
平行线对,按目标像素换算 zoom 窗口 → 截图 → 问 VLM;测完 delete_entities 清理不保存。
- 标定结论:
* **可读下限与字体强相关**——离线合成(Consolas 抗锯齿填充字体)12px;
真实 CAD 单线体 .shx(描边字体)6px 即可读对(3/3,两轮)。
* 线条「1 条 vs 2 条」:2/3/4px 失败,5/8/12px 成功 → R_line ≈ 5px。
* **必须用 ACI 7 白字**:实测红字(ACI 1)12px 因对比度不足完全读不出。
- config 定稿:TEXT_READABLE_PX=8(折中)、LINE_READABLE_PX=6、
EVIDENCE_MAX_IMAGES=12(原 5 会把规划结果截到只剩 4 张瓦片)。
- 新增 heatmap.occupied_boxes:占用格的**世界 bbox**。
- tiling.plan_regions 新增 keep 谓词;evidence._plan_tiles 按占用格剔除**空瓦片**
(簇 bbox 是包围盒,L 形/斜向分布含大片空白,实测有效)。
- 测试:test_heatmap 补 occupied_boxes;test_tiling 补 keep 过滤;全量 286 项全绿。
- 真实图纸端到端验证:A0 图框出 12 张(1 整体 + 11 瓦片),单框审查 1m38s 通过。
- 记忆库同步:工具语义坑(type_filter 必须传列表 / layer_filter 是通配字符串 /
add_* 返回句柄在 created 键)、标定结论与默认值。
132 lines
8.6 KiB
Markdown
132 lines
8.6 KiB
Markdown
---
|
||
name: Agent 路线与多源架构(2026-10-15)
|
||
description: dwg_review agent 的总目标、多源图纸分层架构(视觉为最大公约数)、工具层与 agent 层的正交分工、多源证据层、截图去 UI、grounding 实测、热力图 + 自适应瓦片规划 + VLM 分辨率标定与后续路线
|
||
type: project
|
||
---
|
||
|
||
# Agent 路线与多源架构
|
||
|
||
## 总目标(用户 2026-10-15 明确)
|
||
|
||
实现 **AI 自动识别 + 评审 DWG 图纸**。分阶段:**先 MCP(已完成),再 agent(进行中)**。
|
||
最终要支持的图纸来源**不限于自家自定义实体**:
|
||
|
||
1. 自家软件的自定义实体 DWG;
|
||
2. **其他软件出的 DWG**(各种自定义实体);
|
||
3. 将来 **PDF** 图纸;
|
||
4. 将来**纯图片**图纸。
|
||
|
||
## 架构分层(用户认可)
|
||
|
||
**核心洞察:视觉模型(VLM)是"最大公约数"**。DWG 自定义实体 / PDF / 图片本质是
|
||
"拿不到结构化数据时靠视觉理解"的同一件事——**任何图纸只要能渲染成图,VLM 就能审**。
|
||
所以结构化数据(ARX 读普通实体)是**增强**,视觉是**兜底**。
|
||
|
||
```
|
||
Agent 推理层(审查逻辑 / 清单 / 规则)
|
||
▲ 统一 evidence schema
|
||
感知适配层(能力从高到低降级)
|
||
CAD结构化(ARX) → CAD几何 → 离线解析(DWG/PDF) → 视觉(VLM)
|
||
```
|
||
|
||
- **MCP 工具层只管 CAD**(进程内能力);**PDF / 图片在 agent 侧**(PyMuPDF / Pillow),
|
||
**不塞进 MCP**、不编 DLL。
|
||
- **统一证据模型 + 多源适配 + 能力降级**;agent 推理层不关心来源格式。
|
||
|
||
**How to apply**:新增"支持某格式"时,优先在 agent 侧感知层加适配器;只有"CAD 进程内的
|
||
正交感知能力"才考虑加 MCP 工具。
|
||
|
||
## 第一步已落地(2026-10-15,提交 `1c9fc72`)
|
||
|
||
**取证层多源化 + 视觉多图**:
|
||
|
||
- 新增 `dwg_review/evidence_model.py`:统一证据模型(`source_type` +
|
||
`images:[{b64,mime,label}]`),访问器 `evidence_images()` 兼容旧 `image_b64/image_mime`
|
||
单图字段(历史 evidence.json 仍可读)。
|
||
- `phases/evidence.py`:`collect()` 多源分发 seam(当前仅 CAD)、`capture_images()`
|
||
整体 + 等分象限多图(结束**复位视口**)、`sub_windows()`。
|
||
- 默认 `EVIDENCE_DETAIL_TILES=4` / `EVIDENCE_MAX_IMAGES=5`(每图框 5 图,**默认开启**)。
|
||
- 实测:真实 Plant 3D 图纸上多图让审查更细(多报出线型误用 `CENTER2`、图签块属性为空、
|
||
按 handle 定位的图层混用等)。
|
||
|
||
## 截图去 CAD 界面元素(2026-10-15,提交 `f8bd12d`)
|
||
|
||
`get_viewport_screenshot` 原先截 `adsw_acadDocWnd()` 客户区,含视口控件、ViewCube、滚动条,
|
||
污染截图并**误导 VLM**(曾把视口标签当成"需放大的内容")。已修复:
|
||
|
||
- 改用 **`acedGetAcadDwgView()`** 只截图形区(排除滚动条/状态栏)。
|
||
- 截图期间临时置 **`NAVVCUBEDISPLAY=0`**(关 ViewCube)与 **`VPCONTROL=0`**(关视口控件),
|
||
用 RAII 守卫(`TempSysVarOff`)自动恢复原值,**不影响用户 CAD 界面设置**;
|
||
配合 `RedrawWindow(RDW_UPDATENOW)` 同步重绘。
|
||
- 实测:三项 UI 均消失,VLM 不再提界面元素。
|
||
|
||
**残留(无解,已知)**:绘图区右上角仍有**绘图窗口**的最小化/最大化/关闭按钮——由 AutoCAD
|
||
画在图形区内的固有 UI,**无系统变量可关**。它很小且在角落,实测未影响 VLM。
|
||
(区别于应用窗口的按钮;用户最初要清的是 视口控件/ViewCube/滚动条,不含此项。)
|
||
|
||
## grounding 实测(2026-10-15)
|
||
|
||
用 `verify_grounding.py` 拿真实截图问 `deepseek-flash`"哪里要放大":**grounding 可用**——
|
||
给出的归一化坐标**区域级定位准确**(放大后确实套住目标,如图签栏、图框角),
|
||
但**语义描述略有偏差**(把图签栏说成"状态栏")。结论:可支撑"按区域放大",但**位置对、语义别全信**。
|
||
|
||
## 后续路线(未做)
|
||
|
||
1. **VLM 主动放大(自适应取证)**:复用受控只读取证子循环,让 VLM 请求放大看不清处。
|
||
- 两条路径:① 按实体 `zoom_to_entity(handle)`(可靠);② 按区域(把 VLM 归一化坐标映射成
|
||
WCS)——**grounding 已实测可用**(见上节)。
|
||
- 必须设**迭代上限 + 兜底**;**不把"看清没"完全交给 VLM**(会过度自信/幻觉)。
|
||
- 现有 `zoom_to_window`/`zoom_to_entity`/`get_viewport_screenshot` 已在只读白名单,
|
||
**无需新增工具**。
|
||
2. **PDF / 图片源**:在 `phases/evidence.collect()` 加分支,产出**同形** evidence
|
||
(`window=None`、结构化空信封、`images` 带 label);规划阶段抽象"审查单元"
|
||
(CAD=图框 / PDF=页 / 图片=单);批注对非 CAD 源降级(`annotator` 已天然跳过无 handle 的 issue)。
|
||
3. **审图规范接入**:清单升级为规范库。
|
||
|
||
## 热力图 → 自适应瓦片规划 → VLM 分辨率标定(2026-10-15,进行中)
|
||
|
||
**动机**:固定「整体 + 2x2 象限」截图对 A0/A1 大图幅读不清。用户拍板:**驱动信号是实体分布
|
||
(热力图),不是文字**(有的图没有文字),且**实际工况下实体占据图框大部分**,稀疏/稠密都要能处理。
|
||
用户方案:图框类型 → 纸张真实尺寸 + 比例 → CAD 世界尺寸 → 换算像素 → 知道 VLM 分辨率 →
|
||
算出**一个图框要截几张、截哪里**。
|
||
|
||
**用户已拍板的关键决定**:
|
||
- 热力图在 **Python 侧(agent 层)** 算(派生量,工具层只给原始事实)。密集图若受
|
||
`query_entities` 的 `limit≤1000` / 帧上限拉不全 → **给现有 `query_entities` 加 `brief` 模式**
|
||
(只回 handle/type/bbox、放开 limit),**而不是新增"热力图工具"**。
|
||
- `CollisionDetection.h/cpp`(用户写的 BVH)**本步不用**,留作后续**几何相交/干涉检查**引擎。
|
||
其按质心中位分割 → 节点框**可能重叠**,不适合铺屏瓦片;瓦片切分用四叉树/网格(空间不相交)。
|
||
- 标定判据:**同时测「读出文字」与「分辨线细节」**;标定字高 **200 图形单位**(1:100 = 纸面 2mm,国标最小)。
|
||
|
||
**已落地(提交 `9b8a232` 热力图;`cba05b0` 瓦片规划 + 离线标定)**:
|
||
- `dwg_review/heatmap.py`(纯函数):`entity_boxes` / `build_grid`(counts+coverage)/
|
||
`cluster_cells`(4-连通,可选膨胀)/ `grid_to_windows` / `grid_stats` / `render_overlay`。
|
||
**`drop_oversized`**:丢掉 bbox 占满图框的实体(实测每框恰 1 个,即图框块),否则热力图全满。
|
||
- `dwg_review/tiling.py`(纯函数):`frame_scale`(`sheet_scale>0` 用之;否则由 bbox/纸张**反算**;
|
||
否则 default)/ `world_per_px` / `is_text_type` / `plan_regions`(文字簇优先、空白区不出图、
|
||
`max_tiles` 截断、窗口夹到图框)。
|
||
- `phases/evidence.capture_images`:先截整体图并**测绘图区像素** → 规划成功用规划窗口,
|
||
否则退回 `sub_windows`(行为零变化);**任一信封 `total>returned`(截断)→ 退回固定策略**。
|
||
- `verify_heatmap.py`(不耗 token,出 PNG + bbox 缓存)、`verify_vlm_resolution_offline.py`、
|
||
`verify_text_resolution.py`(CAD 实测)。
|
||
|
||
**标定结论**:
|
||
- **该模型无法可靠计数线条**(6 条线在 2~10px 间距下答 4/10/4/5/4/4)→ 线条判据改用
|
||
**「1 条 vs 2 条」二选一**。
|
||
- **可读下限与字体强相关**:离线合成(Consolas 抗锯齿填充字体)**12px**(白底 10px);
|
||
真实 CAD **单线体 .shx(描边字体)6px 就能读对**(3/3,两轮)。
|
||
- 真实 CAD 线条:**2/3/4px 失败,5/8/12px 成功** → R_line ≈ **5px**。
|
||
- **标定必须用 ACI 7(白/黑自适应)**:实测**红字(ACI 1)12px 完全读不出**——否则把
|
||
"对比度不足"误当"分辨率不足"。
|
||
- 实测绘图区 **2110×462** → 有效 **1280×280**(长边 1280),视口宽高比 **4.567**。
|
||
|
||
**用户拍板的默认值(2026-10-15)**:`TEXT_READABLE_PX=8`(折中,兼顾描边与 TrueType)、
|
||
`LINE_READABLE_PX=6`、`EVIDENCE_MAX_IMAGES=12`(原 5 会把规划结果截到只剩 4 张瓦片)。
|
||
|
||
**瓦片粒度内容过滤**:簇 bbox 是**包围盒**,L 形/斜向分布(如管道走向)含大片空白 →
|
||
`plan_regions(keep=...)` 按 `heatmap.occupied_boxes` 剔除**空瓦片**(实测有效)。
|
||
|
||
**已知局限**:本图纸的文字在**块 / 自定义实体**内,`get_text_content` 检不到 → 该簇会按
|
||
**线条判据**出图(6px),块内文字可能读不清。要更保险可把 `LINE_READABLE_PX` 调到 8
|
||
(等价于全用文字判据,代价是同样预算下覆盖面积减半)。
|