--- name: LLM 识图审图 Agent —— 架构决策(已定稿) description: cad_mcp_frame + 自研 Agent 的架构决策与分阶段路线——混合式(流水线骨架+受控只读取证子循环)、基座 B 最小集、标准化路线(先 stdio 桥) type: project --- # LLM 识图审图 Agent —— 架构决策(2026-10-13 定稿) ## 决策 1. **Agent 形态:混合式自研**(非纯 ReAct、非纯流水线):确定性流水线骨架 (规划 → 逐图框取证 → 审查 → 汇总)+ 审查阶段给 LLM 一个**受控只读取证工具子循环** (白名单 15 个只读工具,`add_*/delete_*/set_*/draw_*` 一律禁止)。 2. **审查依据**:清单驱动(`review_checklist.json`)+ LLM 自主判断。 3. **输出**:Markdown + JSON 报告 + 可选 CAD 图上批注回写(统一落 `AI_REVIEW` 层)。 4. **基座改造:只做「B 最小集」**——换行分帧(`\n` 为消息边界)、去掉单次 `recv(2048)` 限制、 `isError` 映射、`id` 支持 string/number + 通知不回包;**不做** `initialize`/`ping` 握手。 5. **标准化路线**:先自研 agent 跑通 → 再做 stdio↔TCP 桥 → 远期才考虑 Streamable HTTP。 (**2026-10-14 更新**:stdio 桥**已实现并验证通过**,见 `project_stdio_bridge.md`。 远期仅剩 Streamable HTTP。) **Why(关键结论,非显而易见)**: - 基座是**裸 TCP 自定义传输**。规范虽允许自定义传输,但标准客户端(Claude Desktop / CodeBuddy / MCP Inspector)**只实现 stdio 与 Streamable HTTP**——因此裸 TCP 无论怎么补 生命周期都**无法被标准客户端直连**。"能被标准客户端接入"只有两条路:**stdio 桥** (省力、CAD 侧零改动)或 **Streamable HTTP**(彻底、要在 CAD 内做 HTTP+SSE、最贵)。 - 自研 agent 直接连 TCP,传输是否"标准"**不影响**,故**标准化不是前置条件**。 - `mcp_server.cpp` 原来**单次 `recv` 仅 2048 字节**,请求超 2KB 会被截断成 `-32700`; 这是**服务端**限制、客户端绕不过去 → 必须先改基座。 - image 内容块 `{type:image,data,mimeType}` **本就是 MCP 标准**(`source:{type,mediaType}` 是 Anthropic Messages API 的格式,别混淆),无需改。 **How to apply**:新增审图工具仍走 `cad_mcp_plugins` + `mcp_config.json`;agent 侧工具从 `tools/list` **动态发现**,加工具零代码。日后要做标准客户端接入,**从 stdio 桥起步**。 ## 新增产物 - `dwg_review/`(Python 包):`config.py`(环境变量,无硬编码 Key)、`mcp_client.py` (唯一 TCP 封装:单飞锁 + 换行分帧 + 重试 + 兼容 `error`/`isError`)、`llm_client.py`、 `cad_tools.py`(动态工具表 + 只读白名单 `READ_ONLY_TOOLS`)、`checklist.py`、 `phases/{planning,evidence,review,report}.py`、`annotator.py`、`__main__.py`。 **取代**根目录散落的 `dwg_review_agent.py` / `agent_loop.py` 等重复脚本。 - `verify_mcp_frame.py`:基座改动验证脚本(分帧 / 大报文 / string id / 通知 / isError)。 ## 环境事实 - **Pillow 已安装**(12.3.0)。截图下采样策略(`dwg_review/llm_client.py: downsample_image_b64`): 视觉 token 成本由**像素尺寸**决定而非文件大小 → **只在长边超 `IMAGE_MAX_EDGE`(默认 1280)时才缩放**; 既不需要缩放、格式又没变时**原样返回不重编码**(避免给 CAD 线稿引入无谓压缩损失); 缩放后默认输出**无损 PNG**(`IMAGE_FORMAT=png`,适合线稿),需要更小体积可设 `IMAGE_FORMAT=jpeg`。 缺少 Pillow 时自动降级为原图直传。 - 视觉模型 `deepseek-flash`。 - **`DEEPSEEK_API_KEY` 设在 Windows `Machine`(系统)级**。因新设的系统变量**不会传播到已启动 的进程**,`dwg_review/config.py` 的 `_read_env()` 在进程环境读不到时**回退读注册表** (`HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment` → `HKCU\Environment`)。 否则 CodeBuddy 内的命令永远读不到新设的 Key。 - **AutoCAD 2020 自动加载 ARX(用户配置,不在仓库内)**:在 `bin/Debug-R230/` 下建 `acad.rx`(内容一行 `cad_mcp_frame.arx`),并把该目录加入 CAD 的**搜索路径与信任路径**。 这是 AutoCAD 官方 RX 自动加载机制,比 `acaddoc.lsp` + LISP 更直接。 - AutoCAD 2020 安装于 `C:/Program Files/Autodesk/AutoCAD 2020/`;用户配置目录 `C:/Users/gjm/AppData/Roaming/Autodesk/AutoCAD 2020/R23.1/chs/`(`acaddoc.lsp` 已用于 PDF2CAD,勿覆盖)。 - **改 `cad_mcp_plugins` 后重链接必须先关 CAD**:插件 DLL 被 CAD 进程持有(`LNK1168: cannot open ...dll for writing`)。模板 `cad-mcp-frame.json` 里的 `"hot_reload": true` **只是占位、代码未实现**, `mcp_Tools::clear()`(唯一 `FreeLibrary` 处)仅在 ARX 卸载时调用 → **没有热重载**。 流程:关 CAD → `cmake --build --preset R230 --config Debug` → 重启 `acad.exe`(`acad.rx` 自动加载) → 轮询 `127.0.0.1:8080` 监听。编译阶段可先行(语法错误会被提前暴露,只有链接会因占用失败)。 ## 验证结论(2026-10-13 实测通过) - `verify_mcp_frame.py` 4/4 PASS(换行分帧 / >2KB 报文不截断 / string id 原样回显 / 通知不回包 / isError)。 - `verify_annotate.py` 9/9 PASS(批注工具无回归)。 - `dwg_review --list-tools` = 26 个工具;`--plan-only` 取证正常;全流程跑出报告。 - **受控取证子循环实测生效**:LLM 自主调用了白名单内的 `get_drawing_info`/`get_layers`/ `find_zero_length`/`find_duplicate_entities`/`get_dimensions` 做二次确认。 - 批注回写实测通过;注意 `add_leader_annotation` 的 `points` **必须 ≥2 个点**(首个为箭头)。