Files
cad-agent/ai.memory/reference_environment.md
T
gjm b757892c67 feat(review): agent 侧虚拟工具 inspect_region —— 按可读分辨率放大指定区域
解决三个缺口:① 放大没复用标定/瓦片数学(LLM 一次 zoom 只出一张,宽区域仍读不清);
②「看清没」由 VLM 自评(易过度自信/幻觉);③ 只能按 handle / 手算 bbox 指认,
图上看到但没 handle 的东西指认不了。

核心思路:把「放大」升级成一个语义化工具——LLM 只指认「要看哪里」,由 agent 复用
tiling.py 的标定数学算出该切几张、每张覆盖多大,用构造保证可读。

新增 dwg_review/inspect.py(agent 侧,不编 DLL):
- TOOL_SCHEMA:inspect_region(target, purpose);target 三形态 {handle} / {window} /
  {label,cx,cy,span},purpose = text(8px) / line(6px)。
- InspectState:单图框内「截图标签 → 世界可见范围」登记表,支持逐级下钻
  (返回的 inspect-N 可继续作为 label 指认)。
- resolve_target / _point_box:label+cx+cy → WCS。cy 是图像坐标(上→下),
  世界 y 必须翻转(y = y2 - cy*H)——单测专门钉住。
- plan_tiles:复用 world_per_px + tiles_for_box + subdivide;超 INSPECT_MAX_TILES(4)
  则硬失败并给出「缩小 target / 分多次请求」的指引(不静默降级);拿不到比例/像素
  则退回单张并如实告知。

关键几何:CAD 的 _.ZOOM _W 是等比适配(不拉伸),故「截图上的归一化坐标」必须按
max(W/ew, H/eh) 反算真实可见范围(新增 tiling.visible_box)——直接用送进去的窗口会偏。
zoom_to_window 返回的 view 是「加过 margin 的窗口」,不是可见范围,不能混用。

证据层配套:evidence_model.make_image(..., window=) 记录每张图的可见世界范围;
capture_images 用 view_px(overall 图原始像素)+ visible_box 逐张登记。

子循环接入:_run_readonly_tool 在只读白名单校验之前拦截 inspect_region(它不在
READ_ONLY_TOOLS 里,内部只调白名单内的只读 MCP 工具);_review_tools 启用时用
inspect_region 取代三个裸视口工具;inspect_region 计入 _VIEW_TOOLS → 结束复位视口。
配置:INSPECT_ENABLED(True) / INSPECT_MAX_TILES(4)。

端到端实测(真实图纸 1 图框):取证与审查两阶段均在最大化态、结束精确还原(4 项 PASS);
LLM 的 11 次取证调用里 2 次是 inspect_region,且都显式给 window + purpose:"text"
(x[20000,115000] y[-6500,3000],即 A0 图框底部横条=标题栏所在)。
验收口径达成:报告报出标题栏乱码 ???????????????,而 get_text_content 对全图返回 0 条文字
(本图文字全在块/自定义实体内)→ 块内文字是被视觉放大读出来的。
pytest 343 passed。
2026-10-16 19:15:32 +08:00

103 lines
6.4 KiB
Markdown
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.
---
name: 环境与外部资源
description: CadProject 的构建/运行要点、CAD SDK 路径、测试分层(pytest 快层 + verify_* 慢层)等外部资源指引
type: reference
---
# 环境与外部资源
## 构建
- 系统:**CMake + vcpkg + Visual Studio 生成器**,通过 CMake Presets 区分 CAD 版本。
- 产物:`bin/<Config>-<TAG>/` 与 `lib/<Config>-<TAG>/`。
- 命令:`cmake --preset R230` → `cmake --build --preset R230 --config Debug`。
- 可用 preset:`R180`–`R260`(AutoCAD,ARX 18–26)、`Z2023`–`Z2026`(ZWCAD,ZRX)。
- 前置:需要 `VCPKG_ROOT`;必需 cache 变量 `CAD_SDK_ROOT`、`DEP_LIB_ROOT`、`DEP_INC_ROOT`、
`CAD_SDK_VERSION`(AutoCAD 还需 `CAD_SDK_SUBVERSION`)。
## CAD SDK 路径
- AutoCAD:仓库同级 `../envi-code/Arx`
- ZWCAD:仓库同级 `../envi-code/Zrx`
- 在 `cmakepresets.json` 的 `CAD_SDK_ROOT` 中配置。
## 运行 / 联调
- 先启动 **已加载插件的 CAD**,确认 `127.0.0.1:8080` 在监听。
- 脚本通过 TCP 连接 `127.0.0.1:8080` 收发 JSON-RPC。
## 测试(两层,互不替代)
**快层 —— pytest 离线单元测试**(`tests/`,假 LLM + 假基座,无需 CAD、不联网、秒级):
- `pip install -r requirements-dev.txt` → `python -m pytest`。
- 配置:`pytest.ini`(`testpaths = tests`)、根 `conftest.py`(加 `sys.path` + `RENDER_WAIT=0` / `REPORT_DIR=tmp` fixture)。
- 陷阱:`dwg_review.config` 常量导入期定值,改 `os.environ` 无效,须 `monkeypatch.setattr(config, ...)`。
**慢层 —— 端到端冒烟脚本**(根目录 `verify_*.py`,需 CAD 在线且 `127.0.0.1:8080` 监听):
| 脚本 | 作用 |
| --- | --- |
| `verify_mcp_frame.py` | 基座最小集:分帧 / id / isError 映射 |
| `verify_mcp_tcp_hardening.py` | TCP 收发路径加固(超长帧 / 粘包 / 半关闭) |
| `verify_mcp_fault_injection.py` | 工具异常保护(类型错误不再崩 CAD) |
| `verify_stdio_bridge.py` | stdio ↔ TCP 桥(协议协商 / 转发 / 通知) |
| `verify_annotate.py` | 批注工具运行时验证(绘制/校验/改属性/清理);`--keep` 保留批注 |
| `verify_heatmap.py` | 实体分布热力图(占用网格 + 聚类 + PNG),**不耗 token**,缓存 bbox JSON 供离线调参 |
| `verify_vlm_resolution_offline.py` | **离线**(纯 PIL 合成)标定 VLM 读图下限 `R_text`/`R_line`,`--dry-run` 只出图 |
| `verify_text_resolution.py` | **CAD 实测**标定(临时加字 + 平行线,测完 `delete_entities` 清理);`--keep` 保留 |
| `verify_drawing_area.py` | 绘图区最大化验收:基线 → `set_drawing_area(max)` → `restore`,断言窗口矩形/最大化态/绘图区尺寸全回位(实测 3.68×) |
| `verify_review_maximized.py` | 审查全链路验收:在 `collect`/`review_frame` 入口各采一次窗口矩形,断言**取证与审查两阶段都在最大化态**、结束精确还原;并统计子循环 zoom/截图次数 + 记录 LLM 实际调用的取证工具(含虚拟工具 `inspect_region`) |
> 历史:根目录 `test.py` / `test_autoagent.py` / `countOfCircle.py` / `agent_loop.py` /
> `dwg_review_agent.py` 五个遗留调试脚本已于 2026-10-14 删除(前三个含硬编码 API Key,
> 后两个是重复实现)。`test_screenshot.png` 是 `test_autoagent.py` 的残留产物。
## 两个构建目标
| 目标 | 产物 | 作用 |
| --- | --- | --- |
| `src/cad_mcp_frame` | `cad_mcp_frame.arx`(ZWCAD 下 `.zrx`) | MCP **基座**:起 TCP、解析配置、路由执行 |
| `src/cad_mcp_plugins` | `cad_mcp_plugins.dll` | 示例 **C++ 工具插件**,ABI 动态加载 |
## 三种工具后端(`backend.type`)
- `lisp_inline`:`{占位符}` 替换后 `sendStringToExecute`(**异步**)。
- `lisp_file`:`(load "文件" nil)` 后执行 `call_template`。
- `c++_dll`:`LoadLibrary`(**同一 DLL 只加载一次**)+ 工厂/销毁函数(**同步**,可返回图像)。
版本校验与「写库需文档锁」两个坑见 [MCP 基座 c++_dll 加载与执行的坑](project_mcp_frame_dll_loader.md)。
## 工具语义坑:`query_entities` 的两个 filter(2026-10-15 实测)
- **`type_filter` 必须是「数组」**(精确类型名列表,如 `["TEXT"]`)。
传**字符串**会被**静默忽略**——`typeMatches` 对「非数组」一律 `return true`(全通过),
于是你以为筛了文字,实际把 LINE 等全带回来了(踩过:标定脚本因此把窗口中心算到无文字处)。
- **`layer_filter` 是「字符串 + 通配」**(`wildcardMatch`),**不是**列表。
传列表会被忽略 → 通配为空 → **匹配所有图层**(清理类操作慎用)。
- 另有 `space`(模型/图纸空间)、`limit`(**硬钳 1..1000**)、`offset`(分页)。
- 相关工具返回体:`add_text` / `add_line` 等返回 `{"ok":true,"count":1,"created":[{handle,layer,type}]}`
—— 句柄在 **`created`** 键下(不是 `items`)。
## 远程仓库
- 现状(2026-10-08 起):`CadProject` 已从「某仓库的子目录」**独立为单独仓库**。
- `origin` = `ssh://git@39.107.55.179:222/gjm/cad-agent.git`
- 当前分支 `home-ai-dev`;服务器只保留 `main`,采用 **PR 流程**
(`home-ai-dev` → `main`,合并后源分支被删除,故本地 `home-ai-dev` 的 upstream 显示 `[gone]`)。
- 历史已被重写/重新初始化(哈希全新)。
- 历史参考(旧):`new-start.git` = `ssh://gjm@47.93.46.28:1216/srv/git/new-start.git`
- **SSH 密钥(2026-10-08 变更)**:服务器已改用新密钥
`~/.ssh/id_ed25519_guojianming`(注释 `guojianming.go@gmail.com`);
旧密钥 `~/.ssh/id_ed25519`(`deploy@aly-db`)已被服务器移除,会 `Permission denied (publickey)`。
本仓库已设置 `git config core.sshCommand "ssh -i ~/.ssh/id_ed25519_guojianming -o IdentitiesOnly=yes"`。
换机器时需补该配置或加入 `~/.ssh/config`。
## 真实测试图纸(2026-10-15)
- 图纸:`e:\desktop\agent_test.dwg`(用户制作的真实 Plant 3D 图纸:3 个图框 A0/A1/A2,
86 个实体:`AECDBEWFITTING` 40 / `AECDBEWPIPE` 29 / `AECDBEWEQUIPMENT` 14 / `INSERT` 3)。
- **启动方式**:`acad.exe /p SHS-ENVI2026 e:\desktop\agent_test.dwg`
—— 必须带 `/p SHS-ENVI2026` profile,否则**自定义实体无法显示**(该 profile 自动加载
用户写的显示插件)。
- 实测:`python -m dwg_review --frames 1` 端到端可跑通并出报告。