# PCB轴向磁通电机自动化仿真系统 — 全量代码评审报告 | 项 | 内容 | |---|---| | 报告版本 | V1.0 | | 评审日期 | 2026-08-28 | | 评审范围 | `src/`、`scripts/`、`web/backend/`、`web/frontend/src/`、部署配置(Dockerfile / docker-compose.yml / nginx.conf / deploy.ps1 / .gitignore)、文档-代码一致性 | | 排除范围 | `axial_mag_pull-master/`、`torqrippswap-master/`(第三方参考案例)、`DRSS V16.html`(参考文件) | | 评审方法 | 10 个并行分区静态评审 + 只读检查命令(ASCII 扫描、git ls-files / check-ignore、密钥模式搜索、端点逐一核对)。**未启动 Motor-CAD、未运行动态仿真** | | 评审重点 | ① 核心闭环(边界条件→方案→仿真→结果→AI分析→经验库)正确性;② GUI 稳定性 / 美观度 / 交互逻辑(本地 PySide6 + Web 前端) | --- ## 一、总体结论 **项目骨架是健康的**:双系统解耦架构清晰,本地端↔Web端 17 个 API 端点逐一核实全部真实存在且签名匹配;工程纪律(纯 ASCII、参数回读校验、每点基线重载、逐点落盘、生成物不入库)在 `src/` 主链路上基本逐条落地;`src/solver_core.py`、`src/scan_engine.py`、`scripts/robust_motorcad.py` 的工程素养中上。 **但存在三类系统性问题,与"Phase 1/2/3 全部完成"的宣称有明确差距:** 1. **核心闭环"通而数据错"**:多处双份硬编码契约已发生漂移(指标 key 清单、状态枚举、保真度语义),不报错、只产错数据;`task_executor.py` 会在仿真失败时静默注入 mock 假数据并标记 `status="ok"` 上报——一旦触发,经验库和 AI 分析闭环被污染且无任何告警。 2. **AI 相关页面/模块明显未经验证**:Web 前端 8 个 AI 页面中,7 个页面中文 UI 全是 `\uXXXX` 字面乱码、8 处 axios 响应未取 `.data` 导致功能全废——任何一次手工冒烟都会暴露,说明这批代码写完即提交、零联调;后端 AI 闭环的"六类收敛判据"实际只执行四类、转矩目标比较方向写反、L0 预筛选在最常见输入下"空跑即通过"。 3. **稳定性短板集中在长时运行路径**:后端 BatchScheduler 存在必现死锁(调用取消接口即冻结整个后端);本地 GUI 运行中关窗即崩、求解无超时无断线重连;自适应闭环状态全在内存、重启即丢。 **建议**:先按第八章 P0 清单修复(约 15 项,多数改动机械、收益巨大),再将 README/设计文档的状态描述校准到可验证的实现现状。 --- ## 二、🔴 错误 / 必须修复(28 项) ### A. 核心闭环数据完整性(最优先) | # | 位置 | 问题 | 建议 | |---|---|---|---| | A1 | `web/backend/app/routers/plans.py:200-205` vs `src/solver_core.py:32-159` | **upload-results 指标清单双份硬编码已漂移**:后端硬编码的 `tmax_nm/tmin_nm/ripple_abs_nm/power_factor` 在本地端 METRIC_KEYS 中不存在(死配置);本地端实际产出的 `ripple_nm/back_emf_thd_pct/em_power_w/shaft_speed_rpm` 不在后端清单中,上传时被误分类为 **params**——4 项指标静默丢失、参数表被污染,经验库和相似检索基于错位数据运行 | 消除双份硬编码:以 `solver_core.METRIC_KEYS` 为单一事实源生成后端常量,或上传时在 CSV/manifest 中声明列语义 | | A2 | `scripts/task_executor.py:282-289` | **仿真失败后静默回退 mock 假数据并标 `status="ok"`**:`_run_simulation_point` 捕获任何异常后调用父类 mock 实现,伪造的 `tavg_nm/efficiency_pct` 通过 report_results 上报 Web 端,与真实数据无法区分——电机没算,经验库却记了一条"成功"结果 | 失败必须标 `status="failed"` 并记录真实错误;mock 仅由显式开关启用并在结果中强制标注 `source:"mock"` | | A3 | `scripts/task_executor.py:291-323` | **Motor-CAD 实例管理三大铁律全违反**:`MotorCAD()` 未传 `open_new_instance=True`、无 `set_visible(True)`、扫描点之间不重载基线(参数跨点污染)、无弹窗抑制 | 该类应直接复用 `RobustMotorCADSolver`,不要另写裸 pymotorcad 调用 | | A4 | `scripts/task_executor.py:304-311` | **回读校验被 `except Exception: pass` 完全架空**:set→get→比对不一致抛出的 RuntimeError 被静默吞掉,执行流继续求解。比不写校验更危险——给人"已做校验"的假象,实际零防护 | 去掉外层 try/except,让 mismatch 异常上传播并标记该点 failed | | A5 | `scripts/task_executor.py:299` 附带 | `_run_motorcad` 用 `get_variable("Torque_Avg"/"Efficiency"/"Total_Losses")` 取结果——这三个变量名在全仓库(知识库、solver_core、探测记录)无任何出处,几乎必然抛异常(然后触发 A2 的 mock 回退) | 结果提取复用 solver_core 的导出文件解析路径 | | A6 | `web/backend/app/routers/adaptive.py` + 全仓库 | **自适应闭环缺本地执行桥**:README 宣称"AI驱动自适应仿真闭环就绪",但「拿批次点→驱动 Motor-CAD→回传结果」在仓库中没有任何执行者(api_client / GUI / task_executor 均不感知 `/api/adaptive`),闭环只能人工逐步调 API;且 loop 状态存于内存 dict(`adaptive_loop.py:368`),后端重启即全部丢失 | 本地端增加 adaptive 模式执行器(轮询 next-batch → ScanEngine 执行 → report-results);loop 状态持久化到 SQLite | | A7 | `src/gui/main.py:296, 565-600, 655-660, 723-729` | **GUI 的 `self._plan` 从不更新**:`_start_scan` 里 `plan = self._build_plan()` 是局部变量,从未回写。`_on_finished` 写经验库时 plan_id/topology/model_path 永远是启动默认值——用户改了模型改了方案,经验库记录全部挂在默认方案名下,静默污染"经验库积累"核心闭环 | `_start_scan` 校验通过后 `self._plan = plan`;或改用 worker 携带的 plan | | A8 | `src/api_client.py:153-155`(根源 `_request()` :52-53) | **`delete_experience()` 删除成功时必然抛异常**:后端 DELETE 返回 204 空响应体,`_request()` 对所有成功响应无条件 `json.loads(resp.read())`,空 body 抛 JSONDecodeError 且不被现有 except 捕获——每次成功删除都以异常告终 | `_request()` 先读 body,为空返回 None:`raw = resp.read(); return json.loads(raw) if raw else None` | ### B. 稳定性 / 崩溃 | # | 位置 | 问题 | 建议 | |---|---|---|---| | B1 | `web/backend/app/services/batch_scheduler.py:69-71, 106-115, 158-159` | **BatchScheduler 必现死锁**:`get_next_task()`/`cancel_task()` 在 `with self._lock` 内调 `_notify_callbacks()`,后者第一行调 `get_statistics()` 再次 `with self._lock`——`threading.Lock()` 非可重入,永久死锁,**即使没有任何回调注册也触发**。该路径经 `POST /api/monitor/cancel/{task_id}` 暴露,死锁发生在事件循环线程上,整个后端冻结 | `_notify_callbacks()` 移到锁外(参考 `complete_task` 的正确写法),或改用 `threading.RLock()` | | B2 | `src/gui/main.py`(无 `closeEvent`)+ `:790` | **扫描运行中关闭窗口 → QThread 被强制销毁崩溃 + 无退出路径**:关窗时 worker 仍在运行则 `QThread: Destroyed while thread is still running` 直接 terminate 崩溃、Motor-CAD 进程被遗弃;`setQuitOnLastWindowClosed(False)` 且无托盘/退出菜单——关窗后进程变无界面僵尸,只能任务管理器强杀 | 重写 `closeEvent`:worker 运行中弹确认框,`worker.cancel()` + `worker.wait(超时)` 后再关;移除 `setQuitOnLastWindowClosed(False)` 或补托盘退出入口 | | B3 | `src/gui/main.py:156-160, 464, 508-520` | **变量表格输入非数字即触发全局崩溃弹窗**:`get_variables()` 对单元格直接 `float(text)` 无 try/except,而 `itemChanged` 在每次按键编辑完成时触发 `_update_estimate()`——用户输入 `"1."`、`"abc"` 等中间态时 ValueError 一路抛到全局 excepthook,**正常打字就反复收到"程序错误"弹窗** | `get_variables()` 逐行 try/except 并带行号报错;`_update_estimate` 解析失败显示 "Points: (invalid input)";`_start_scan` 先捕获解析异常用 QMessageBox 指出具体单元格 | | B4 | `src/gui/main.py:85-107` | **GUI 路径 Motor-CAD 进程泄漏**:`ScanWorker.run()` 中 `solver.disconnect()` 只在成功路径执行;ScanEngine 的 FATAL 异常 re-raise 后 disconnect 被跳过,Motor-CAD 进程(含 license 占用)可能长期残留。对比 `run_scan.py:191-193`、`run_single.py:145-147` 都正确使用了 finally,GUI 主链路反而没有 | connect 之后的逻辑包入 `try/finally`,finally 中调 `disconnect()` | | B5 | `scripts/robust_motorcad.py:608-612` | **`run_single_point` 提前 return 导致失败点不落盘、不进结果集**:采样点/网格组合不兼容时函数在 try 块内直接 `return result`,跳过第 680-681 行的 `_all_results.append` 和 `_write_result_to_disk`——该失败点彻底消失,违反"失败点记录错误并继续、结果逐点落盘"纪律 | 提前 return 改为设置状态后走正常收尾路径,保证 append/落盘必达 | | B6 | `scripts/robust_motorcad.py:336-345` | **`point_timeout` 参数是死代码**:构造函数接收 `point_timeout=300` 但全文无使用;`do_magnetic_calculation()` 同步阻塞,Motor-CAD 卡死则脚本永久阻塞,重试机制不会触发。docstring 宣称"Per-point timeout + retry",属于宣称的安全特性缺失 | 用子线程+join(timeout) 或 Job Object 实现真实超时;或删除参数并修正文档 | | B7 | `scripts/task_executor.py:66-79, 242-262` | **本地文件兜底模式下任务被无限重复执行**:`requests` 未安装时走 `_scan_local_task_files`,`execute_task` 完成后不删除/重命名文件也不回写状态——下一个轮询周期(5 秒后)同一批任务再次执行,无限循环 | 执行后重命名为 `*_task.done.json` 或回写 `status:"completed"` 并扫描时过滤 | ### C. AI 闭环逻辑错误(宣称功能失真) | # | 位置 | 问题 | 建议 | |---|---|---|---| | C1 | `web/backend/app/services/result_analyst.py:355-360` | **转矩目标比较方向写反**:"越高越好"用子串匹配 `"torque" in metric`,但实际指标键是 `tavg_nm`(不含 "torque")→ 转矩被当作"越低越好",取 min 作为 best 且 `min <= target` 几乎恒真——**转矩目标比较永远 pass 且展示最差值**,闭环验收判据失真 | 建立显式 metric→direction 映射表(可复用 analytics.py 的 METRIC_DEFS),不要用子串猜测 | | C2 | `web/backend/app/services/result_analyst.py:369-395` | **"六类收敛判据"只有四类真正执行**:`check_optimum_stability` 和 `check_surrogate_error` 全仓库无调用方。后果:① 4 项通过即报 "converged"(2 项从未评估);② 置信评分按 total=6 折算,收敛贡献上限被压到 4/6,A 级在数学上更难达到,置信等级被系统性低估。API 文档宣称 "Six convergence criteria checks" 与实现不符 | 真正接入另两个判据,或把 total 改为 4 并修正文档 | | C3 | `web/backend/app/services/l0_prescreening.py:368-376` | **L0 预筛选"空跑即通过"**:`feasible = failed == 0`,而所有检查项都以 `if params.get("xxx") is not None` 触发——典型输入(speed_rpm/current_a/target_torque_nm)下 0 项检查运行、total_checks=0、却返回 feasible=True。**L0 作为闭环第一道闸门在最常见场景下形同虚设** | 增加最低覆盖判定(如 `total_checks >= 3`)或覆盖率字段,覆盖率为 0 时标记"未知"并转 warning | | C4 | `web/backend/app/services/feasibility_search.py:303` | **信任域锚点无视优化方向**:激活信任域时恒取 `max(...)`,`objective_direction="minimize"`(损耗/成本类目标)时信任域锚定在**最差**可行点上,70% 候选围绕最差点采样 | 按 objective_direction 选 max/min | | C5 | `web/backend/app/services/feasibility_search.py:398-426` | **信任域中心不随新最优点迁移**:`report_result` 更新 best_feasible_point 但从不更新 trust_region_center,中心永久锚定在激活时的旧最优点 | `is_better` 为真且信任域已激活时同步迁移中心(经典信任域标准做法) | ### D. Web 前端致命缺陷(详见第六章专题) | # | 位置 | 问题 | 建议 | |---|---|---|---| | D1 | `TaskManager.vue:6`、`PlanGenerator.vue:6,14,18`、`L0Prescreen.vue`、`AdaptiveOptimize.vue`、`ResultAnalysis.vue`、`FidelityCalibration.vue`、`ExperienceEnhance.vue`、`ConfidenceBadge.vue:3`(共 8 文件) | **Vue 模板中大量使用 `\uXXXX` 转义,浏览器原样显示为字面乱码**——这是把"`.py` 必须纯 ASCII"的纪律错误套用到 `.vue` 模板上(模板文本节点不做 JS 字符串转义)。7 个 AI 页面的全部中文 UI 文本都是乱码。注意:`{{ }}` 插值和绑定表达式里的转义是 JS 求值,**那些是对的,可保留** | ASCII 纪律仅针对 `.py`/`.ps1`;`.vue` 直接写 UTF-8 中文,把模板静态文本中的 `\uXXXX` 全部还原 | | D2 | `api/index.ts:3-7` + 8 处调用点 | **axios 响应未取 `.data`,半数页面拿不到数据**:无响应拦截器,以下页面直接把响应包装对象当业务数据用——TaskManager(任务列表永远为空)、MonitorDashboard(统计卡片恒为 0)、L0Prescreen(恒显示"不可行"+渲染抛 TypeError)、PlanGenerator、ResultAnalysis、FidelityCalibration、AdaptiveOptimize(创建后状态卡不显示)、ExperienceEnhance(后续 URL 变成 `/loops/undefined/...` 必失败)。这些页面功能上完全不可用 | 根治:api/index.ts 加响应拦截器 `r => r.data` 并全库统一写法;或逐处补 `.data`。二选一,必须统一 | | D3 | `AdvancedVisualization.vue:209-213` | **ECharts 动态导入写错**:`mod.default` 在 ECharts 5(纯 ESM)中为 undefined,`echarts` 恒 undefined,四个图表永远不渲染且无任何用户可见报错 | 改为 `echarts = mod` 或像 Dashboard.vue 一样静态 `import * as echarts`;导入失败应 ElMessage 提示 | | D4 | `AdvancedVisualization.vue:308-333, 243-272` | **「参数敏感性热力图」和「收敛轨迹」是伪造数据**:热力图 X/Y 轴硬编码 P1..P6/Q1..Q5,数据按取模随意填格,与真实扫描参数毫无关系,标题却写"参数敏感性热力图";收敛轨迹把任意数据机械分组模拟出并不存在的"优化收敛过程"——**在仿真优化工具里属于产生错误结论的图表** | 热力图改为真实参数轴+指标分桶聚合(Dashboard 的敏感性图是正确做法可复用);收敛轨迹接真实 adaptive 批次数据或显著标注"示意图" | ### E. 部署 / 安全 | # | 位置 | 问题 | 建议 | |---|---|---|---| | E1 | `Dockerfile:16` + 根目录无 `.dockerignore` | **含真实密钥的 `.env` 会被烤入 Docker 镜像层**:`COPY web/backend/ .` 把 `web/backend/.env`(内含真实 KIMI_API_KEY)复制进镜像,密钥永久存在于镜像层。同时整个仓库(.git、node_modules、5 份 .mot)都进构建上下文 | 新增 `.dockerignore`(至少含 `.env`、`.git`、`node_modules`、`output/`、`*.mot`、`*.db`);**已构建过的镜像应视为已泄露,建议轮换 API Key** | | E2 | `docker-compose.yml:19` + `web/backend/app/config.py:17` | **`KIMI_API_KEY` 空值屏蔽挂载 .env 中的真实密钥**:宿主机未设该变量时 compose 注入空字符串环境变量;config.py 的加载逻辑 `if key and key not in os.environ` 把空字符串也算"已存在"——挂载的 .env 真实密钥永远不会被加载,Docker 部署下 AI 功能静默失效 | 删除 compose 中该行完全依赖挂载 .env,或改为 `${KIMI_API_KEY:?must be set}`;同时 config.py 跳过空值环境变量 | | E3 | `Dockerfile:22` + `docker-compose.yml:17` | **容器内 SQLite 无持久化卷**:数据库落在容器内 `/app/afm_sim.db`,compose 只挂载了 output/ 和 models/——`docker-compose down` 或重建后经验案例、任务记录、AI 调用日志全部丢失,这恰恰是项目核心资产 | 增加卷映射(如 `./web/backend/data:/app/data`)并将 DB 路径指向挂载点 | | E4 | `web/backend/app/main.py:9-37` + `deploy.ps1:117` + `Dockerfile:34` | **API 完全无认证,且部署脚本引导绑定 0.0.0.0**:13 个路由(任务下发、AI 调用、删除、报告下载)无鉴权;`/api/ai/chat` 是开放的 Kimi 付费 API 代理且 `ChatRequest` 对 max_tokens 无上限。默认 127.0.0.1 安全,但 deploy.ps1 和 Dockerfile 均为 `--host 0.0.0.0`——局域网任何机器可调用付费接口、取消任务、删除数据 | 至少加共享 Token 中间件(`X-API-Key`);ChatRequest 加 max_tokens 上界;文档明确绑定边界 | ### F. 功能缺陷 / 纪律冲突 | # | 位置 | 问题 | 建议 | |---|---|---|---| | F1 | `src/scan_engine.py:170-183` | **断点续扫(checkpoint resume)是死代码**:`run()` 每次用毫秒时间戳生成全新 run_dir 和 CSV 文件名,随后 `_load_completed_indices(csv_path)` 读的是刚生成名字、必然不存在的文件——completed 永远为空,"跳过已完成点"逻辑永远不会触发。8 小时扫描第 7 小时崩溃时将全部重来 | 增加 `resume_from: Path` 参数,恢复时定位已有 `scan_results_*.csv` 读取完成索引并追加写入 | | F2 | `web/backend/app/models/simulation_plan.py:27` + `routers/projects.py:88-96` + `database.py:8-12` | **删除项目不产生级联,留下孤儿数据**:docstring 承诺"Delete a project and all its plans/results",但 backref 无 `delete-orphan` 级联,且 SQLite 未开 `PRAGMA foreign_keys=ON`——删除项目后其 plans/results 全部残留,仍可访问、下载、上传结果 | relationship 显式配置 `cascade="all, delete-orphan"`;engine 加 event listener 开启外键 | | F3 | `web/backend/app/services/plan_generator.py:36,60,62,269,271`、`result_analyst.py:274,444`、`experience_enhancer.py:41,65` | **3 个 web 端 .py 文件内嵌中文字符串,违反纯 ASCII 铁律**(AGENTS.md 硬性约束第 1 条"违者返工")。src/ 和 scripts/ 全部合规,唯独这 3 个文件违规(plan_generator 达 117 处) | 中文 prompt 抽取到 `web/backend/prompts/` 模板文件(代码已有 `_load_prompt()` 外置机制),或做 `\uXXXX` 转义 | | F4 | `src/gui/main.py:572-589` | **Git preflight 与工程纪律直接冲突**:AGENTS.md 要求"不满足时拒绝启动扫描",实现却是弹窗"Continue anyway?"可绕过;`except Exception: pass` 还把"非 Git 仓库/HEAD 无效/git 不存在"全部静默放行 | 项目层面裁决:改代码为硬拒绝(推荐),或改纪律并在 manifest 记录 git HEAD + dirty 标志保证可追溯 | | F5 | `web/backend/app/routers/plans.py:145-171` | **GET 请求带写副作用**:两个 download 端点在 GET 中把 status 改为 `executing` 并 commit——前端预览、浏览器重试、健康探测都可能意外推动状态机,且无回退路径 | 状态迁移改为显式 `POST /{plan_id}/start-execution`,download 只读 | --- ## 三、🟡 风险 / 需注意(按子系统分组,共 40+ 项) ### 3.1 Motor-CAD 仿真核心(src/solver_core.py、scan_engine.py) 1. **求解无超时、无断线重连**(`solver_core.py:393-399`):`do_magnetic_calculation()` 无超时,一次挂死整个扫描永久卡住,GUI 取消无效;Motor-CAD 进程中途崩溃后扫描会"带病跑完"产出大量无意义 FAILED。`scripts/robust_motorcad.py:379-382` 已有现成重建实例逻辑未回流。**建议**:单点看门狗超时 + 连续 N 点同阶段失败时触发重连。 2. **回读校验容差严于 float32 精度**(`solver_core.py:380`):`rel_tol=1e-8` 小于 float32 机器精度(1.19e-7),大绝对值参数(3000 rpm、150 A)可能间歇性误判 FAILED。合规但接近物理极限,建议按值量级分档容差并在失败日志输出绝对/相对偏差。 3. **`pick_metric` 前缀模糊匹配可能静默绑错字段**(`solver_core.py:268-276`):双向 startswith 宽松匹配 + dict 序遍历 section,命中顺序不稳定,必需指标"存在但数值错误"仍标 OK 进经验库。建议模糊命中打标 `metrics_source="fuzzy"` 并显式警告,或收紧为单向匹配+section 优先级。 4. **编码回退链 latin-1 永不失败**(`solver_core.py:208-216`):cp1252 文件若字节序列恰好合法 GBK 会先被误解码,字段名静默乱码。建议解码后做启发式校验(是否出现 `;` 分隔和可 float 行),全乱码继续尝试下一编码。 5. **环境变量回退未检查 `ANSYSLMD_LICENSE_FILE`**(`solver_core.py:326-342`):知识库记载其缺失导致 ~30s 静默退出,建议 connect 前探测并提前明确报错。 6. **manifest 未记录 git commit hash**(`scan_engine.py:188-202`):建议写入 `git rev-parse HEAD`,保证运行目录可追溯到确切代码版本。 ### 3.2 方案 Schema / 经验库 / API 客户端(src/) 7. **`upload_results` 会静默清空该方案全部已有结果**(`plans.py:192-193`):后端先 DELETE 再插入,客户端无提示——误传部分结果 CSV 会覆盖丢失完整历史。建议支持 `mode=replace|append`,且**先完整解析校验再删除旧数据**(当前顺序:先删后解析,坏 CSV 抛 ValueError 时旧数据已清)。 8. **`find_similar` 对目标值为 0 的参数维度静默跳过**(`experience_db.py:185-189`):0 是斜极角等参数的合法常见取值,`skew_angle=15` 的案例会被误判"相似"。 9. **`recommend_next_round` 建议区间下界被强制钳到 0**(`experience_db.py:297`):对可取负值的参数(电流角、斜极角)错误截断负向探索空间。 10. **本地与 Web 端相似案例算法语义不一致**(`experience_db.py:160-196` vs `analytics.py:119-159`):同一组参数两端检索结果和排序不同,闭环结论无法互相印证。建议以 Web 端为权威。 11. **SQLite 连接管理脆弱**(`experience_db.py:55-58`):无 WAL、无 timeout、无线程保护;GUI 长写入可致同步脚本 `database is locked`。建议开 WAL + `timeout=30`。 12. **本地经验库无去重**(`experience_db.py:71-136`):同一 CSV 导入两次产生双份记录,扭曲统计推荐。 13. **`validate()` 不查变量重名**(`plan_schema.py:195-210`):同名 ScanVariable 后者静默覆盖前者,产出大量参数完全相同的冗余点,浪费每点数分钟的求解时间。`from_dict` 对未知/拼错字段静默丢弃(`"toplogy"` 拼错静默回落默认值)。 14. **`cases` 字段定义并序列化但全项目无人消费**(`plan_schema.py:79-98`):Web 端若按契约下发多工况 cases,本地端静默忽略——下发方以为仿真了多工况,实际只扫变量笛卡尔积,契约语义断裂。 15. **api_client 无重试、超时写死 30s**(`api_client.py:26,51-58`):结果回传单点失败即断链;URL 查询参数未编码(f-string 拼接);错误处理假设响应恒为 JSON/UTF-8。 16. **plan_id 秒级时间戳可能碰撞**(`plan_schema.py:119` + `plans.py:19-20`):`SP-%Y%m%d-%H%M%S` 同秒创建两个方案即撞唯一键,客户端收到裸 500。AI 批量闭环同秒多方案是现实可能。建议追加随机后缀 + 全局 IntegrityError→409 处理器。 ### 3.3 本地脚本与测试(scripts/) 17. **`robust_motorcad.py` 是孤岛代码**:除测试外无任何模块 import 它,850 行健壮性投入(重试/重连/preflight/弹窗恢复)空转,实际仿真全走 `solver_core`——两套求解器并行演化必然发散。**建议二选一合并**。 18. **preflight 把"非管理员"和"非默认安装路径"判为硬失败**(`robust_motorcad.py:503-514`):硬编码 `C:\ANSYS_Motor-CAD`,而本机装在 D 盘——preflight 在本机必然 FAIL。应降级为 warning。 19. **`_parse_export` 宣称"E-Magnetics 优先"实为"行序先到先得"**(`robust_motorcad.py:740-786`):无 section 概念;且 `replace(",", ".")` 会把千分位 `"1,234.5"` 变成 `"1.234.5"` 静默丢弃数值。 20. **重试策略对确定性错误也重试 3 次**(`robust_motorcad.py:650-667`):变量名不存在、写回 mismatch 每次结果必然相同仍重试;`float(val)` 强转使字符串型参数(材料名等)直接判失败。 21. **CSV 表头按第一个点的 params 动态生成**(`robust_motorcad.py:792-818`):后续点参数集不同则列错位。建议预生成键并集表头或 DictWriter。 22. **三个 test 文件全是"展示性"测试**:`test_api_client.py` 在 pytest 收集期就发真实网络请求且恒报 PASSED 无任何断言;`test_p4_acceptance.py` 约 2/3 是"文件存在"假测试且 pytest 下失败不上报;`test_robust_solver.py` 无论成败都返回 0。**真实断言覆盖率接近零**——最该补的是 `_parse_export` 用样例 CSV 的离线单元测试。 23. **`run_scan.py` 的 `--skip-git-check` 是纪律后门**:bypass 时无任何痕迹留存,建议在 manifest/log 显式记录。 24. **`scan_airgap.json` 相对路径按 CWD 解析**:从项目根以外目录执行即报"Model file not found",应相对配置文件所在目录解析。 ### 3.4 Web 后端 API 层 25. **Session 泄漏**:`routers/ai.py:50-55,71-79` 手动管理会话无 try/finally;`task_manager.py` 7 处 `db = next(get_db())` 从不关闭——且 CPython 下生成器被 GC 回收后 finally 立刻执行 close,后续 ORM 操作实际运行在已关闭 Session 上(SQLAlchemy 静默重开连接,"碰巧能用")。统一改 `with SessionLocal() as db:`。 26. **内存态全局对象无淘汰无锁**:`routers/search.py:12-13` 的 `_search_instances`、`adaptive_loop.py` 的 `_loops`——进程重启全丢、只增不减(内存泄漏)、线程池并发读写无锁。建议容量上限+LRU+Lock,中期落盘。 27. **`experience.py` 用裸 dict 接收请求体**:`tags` 传字符串时 `",".join` 逐字符拼接成 `"t,a,g,1,,,..."` 静默损坏数据;应定义 Pydantic 模型。 28. **upload-results 输入防护缺失**:文件无大小限制(内存 DoS);非数值行抛 ValueError 裸 500;上传后**无条件置 plan.status="completed"**(全部行 FAILED 也标完成)。 29. **状态字段自由字符串无枚举**:`PlanUpdate.status` 任意字符串可写入,状态机因拼写差异静默失效。建议 `Literal[...]` 约束。 30. **裸 `except Exception` 把内部错误原文回客户端**(adaptive/tasks/ai_plan/analysis 十余处):暴露文件路径、SQL 片段、Kimi 错误细节。 31. **N+1 查询**:`list_projects`/`list_plans` 列表页 50 条产生 50~100 次额外 SQL 往返。 32. **列表分页参数无上限 + analytics 全表加载**:`/analytics/experience/stats`、`/experience/similar` 全表载入内存,经验库增长后单请求 O(n) 内存。 33. **任务通道结果不进 SimulationResult**(`task_manager.py:191-209`):report_results 只写 task 目录 results.json,analytics/经验导入/AI 分析全部看不到任务通道数据——双通道数据割裂。 34. **结果状态约定两个子系统不一致**:scan_engine 用 `"OK"/"FAILED"`、task_executor 用 `"ok"/"failed"`、experience_enhancer 用 `feasible` 布尔;analytics 只认大写 `"OK"`——闭环结果流入分析时被静默过滤,前端得到空图。**全仓库统一状态枚举**。 35. **report_generator 数据形状与 TaskManager 输出不匹配**(`report_generator.py:60,74,88`):"参数"与"逐点结果"章节恒为空表。 36. **失败点污染分析样本**(`adaptive_loop.py:215-223`):status≠ok 的点仍进入 min/max/mean、收敛判据、AI 输入统计。 37. **闭环收敛完全依赖信任域收缩**(`adaptive_loop.py:295-314`):result_analyst 算出的收敛判据/置信等级只用于展示,不影响循环终止;信任域未激活时只能靠预算耗尽停止。 38. **task_name 直接拼目录路径**(`task_manager.py:60`):`"../x"` 可路径穿越;同秒同名任务目录互相覆盖。 39. **调度器总进度可超 100%**(`batch_scheduler.py:124-131`):分母不含已完成任务点数。 40. **report_results/update_progress 无状态机防护**:已取消任务可被"复活"为 completed;progress_data 读-改-写无锁存在丢失更新。 ### 3.5 AI 闭环算法(services/) 41. **规则引擎与 L0 物理限值互相矛盾**(`rule_engine.py:48` vs `l0_prescreening.py:82`):气隙 0.2 vs 0.3mm、磁钢 40 vs 20mm——两个模块各自维护一份"物理事实",规则引擎推荐的范围注定被 L0 判不可行。**硬限值应收敛到单一事实源**。 42. **L0 限值与设计方案文档不一致**:设计文档写"电流密度 ≤ 12 A/mm²"代码用 15;"磁钢厚度 ≤ 轴向长度×0.4"约束完全缺失;`min_via_diameter_mm` 是死限值(定义了从不检查)。 43. **`_validate_plan` 不校验扫描变量名**(`plan_generator.py:196-225`):web 侧 `magnet_thickness_mm`(示例 3-8mm,显然是轴向厚度)与 Motor-CAD 的 `Magnet_Thickness`(径向深度 13mm)语义歧义——若下游按名字字面映射会把 3-8mm 写进径向深度,几何直接错误且回读校验能过。**校验层需要变量名白名单+轴向/径向语义标注**。 44. **扫描点数估算在 min≥max 时产生非正 total_points**(`plan_generator.py:217-222`):追加了 issue 但没 continue,后续预算告警全部基于错误数字。 45. **select_next_batch 返回空批次时不置停滞状态**(`feasibility_search.py:340-396`):上层可能无限空转。连续 N 次空批次应置 `"stalled"`。 46. **"checkpoint support"只有导出没有恢复**(`feasibility_search.py:474-503`):无 import_state;导出还缺 objective_metric/direction、rng 内部状态——断点续跑无法实现,种子可复现性在恢复点断裂。 47. **保真度等级语义三方矛盾**(`schema_v2.py:25-31` vs `result_analyst.py:20-26` vs `README.md:68`):result_analyst 把 L3 标为"3D FEA (Motor-CAD)"——概念错误,Motor-CAD 不是 3D FEA 工具;bias_pct 按错误映射参与校准,修正值物理上不可信。README 宣称 L2/L3/L4 已完成,但全仓库无任何 Maxwell/JMAG 集成代码,属过度宣称。 48. **Kimi API 客户端细节**(`ai_client.py`):对 400 也退避重试;429 不读 Retry-After;`data.get("choices",[{}])[0]` 空列表时 IndexError;硬约束解析遇 `"efficiency_pct >= 92%"` 这类非数值抛 ValueError 未捕获。 --- ## 四、🟢 优化建议(精选) **代码卫生** - 清理未使用 import:`solver_core.py:17-18`(csv/json)、`scan_engine.py:17`(time)、`gui/main.py:24-31`(QTimer/QFont/QComboBox 等 7 项)。 - `gui/main.py:275` 死代码(恒为 black 的 placeholder + 函数体内 import QColor)。 - `solver_core.py:351-364` disconnect 前重载基线是多余开销(quit 本就不保存)。 - `main.py:40` `@app.on_event("startup")` 已 deprecated,改 lifespan;`datetime.utcnow` 全面弃用改 `datetime.now(timezone.utc)`。 - `experience_db.py:129-135` 逐行 commit 改单事务批量;`plan_id` 前后端统一加随机后缀。 **经验库 / 分析** - 本地 `experience/experience.db` 默认路径锚定项目根而非 CWD(`experience_db.py:52`、`plan_schema.py:200-201`)。 - `feasibility_search.py:443` 收敛阈值 0.001 是绝对量纲,换 objective_metric 后灵敏度完全不同,改相对阈值。 - `experience_enhancer.py:107` 注释声称 "random 10" 抽样未实现。 - `batch_scheduler.py:166-174` 每点全量写 JSON 状态文件,磁盘 IO 频繁,建议节流。 **部署** - Dockerfile 无 `USER` 指令(root 运行);compose 残留死配置(`version:"3.8"` 废弃、未使用的 named volume);nginx 缺安全响应头(`X-Content-Type-Options`、`client_max_body_size`)。 - `deploy.ps1:103` 生成的 .env 带 UTF-8 BOM,config.py 用 `utf-8`(非 `utf-8-sig`)解析——首行 key 静默损坏的定时炸弹,两边都修。 - `.gitignore` 建议加全局 `*.db` + `*.db-journal`;明确 `书籍与论文/`、`MotorCAD软件教程及故障处理防范/` 两个大目录的入库策略;根目录与 `models/` 重复的 .mot 模型(共 5 份 526KB)只保留一份。 - `reports.py:47` 文件名未 `os.path.basename` 净化(当前被路由挡住,纵深防御);`:32` 把服务器绝对路径返回客户端。 **文档** - README 项目结构清单过时(routers 列 5 个实际 13 个,scripts 缺 task_executor/robust_motorcad)。 - 设计方案第 5 章接口契约与实现漂移(§5.3 写 POST 实际 GET;§5.1 富结构 vs 实现扁平 V1 子集)——建议增加"实现现状 vs 目标契约"对照表。 --- ## 五、文档-代码一致性专项 | # | 位置 | 矛盾 | |---|---|---| | 1 | `README.md:99` | **快速开始命令直接报错**:写 `python scripts/run_scan.py --plan ...`,脚本只接受 `--config`/`--var`,新用户照抄第一条命令即失败 | | 2 | `README.md:41-62` vs `:244-247` | **同一文件自相矛盾**:里程碑表标 P2-M3/M4/M5、P3-M1~M5 全部 ✅ 完成,末尾路线图同一批项标 🔲 待开始 | | 3 | `README.md:68` + `:10` | **能力过度宣称**:L2(2D FEA)/L3/L4 列为已完成核心能力,全仓库无任何 Maxwell/JMAG 集成;"自适应闭环就绪"但无本地执行桥(A6) | | 4 | `docs/P3-评审响应与更新计划.md` vs `result_analyst.py` | 宣称"六类收敛判据"实际四类生效(C2) | | 5 | `plans.py` 注释 | docstring 示例 `SP-20260827-001`(带序号)实现无序号 | **闭环链路核验结论**:主链路(plans 通道)接口骨架成立——download→plan_schema 解析→扫描→upload→入库各环节端点真实存在、CSV 编码契约(utf-8-sig)一致、download 多余字段被 from_dict 正确忽略。**但有三个断点**:指标 key 清单漂移(A1)、任务通道数据不进 SimulationResult(3.4-33)、自适应闭环无本地执行桥(A6)。 --- ## 六、重点专题:GUI 评审(本地 PySide6 + Web 前端) ### 6.1 本地 GUI(src/gui/main.py,801 行) **总体**:结构清晰、分层合理(Worker/表格/日志/主窗分离),线程模型主干正确(Motor-CAD 全部在 QThread 子线程,通信全走 Signal/Slot),样式表做工在工业软件里属中上。但有 4 个必须修的问题(A7、B2、B3、F4,见上)和以下交互/稳定性风险: **交互逻辑风险** - `ScanWorker._cancel` 标志设置了却从未被读取(`main.py:77-107`):connect 阶段(30s+)点 Stop 无效,扫描照常全量执行。 - Stop 后状态机不完整(:613-617):stop_btn 仍可重复点击,状态栏停在 "Stopping...";若 engine 挂死永不返回,按钮状态机永久卡死。 - 失败弹窗直接展示完整 traceback(:673-675):几十行 Python 堆栈弹给电机工程师看。弹窗应只给摘要,traceback 留日志区或折叠 "Show Details"。 - Git preflight 在主线程同步 `subprocess.check_output` 无超时(:576-579):git 挂起则整个 GUI 冻结。加 `timeout=10`。 - 无扫描点数爆炸保护(:508-520):多变量笛卡尔积可轻易产生数千点(数天),只有估算时间显示,无超阈值确认。 - 删除变量行后估算标签不刷新(:464 只连了 itemChanged,removeRow 不触发)。 **美观度与细节** - 结果表表头用内部 key(`tavg_nm`)而非友好标签——`METRIC_LABELS` import 了却全文未用(:38, 188)。 - 三个彩色按钮各自内联重复样式表(:376-411),建议抽常量/统一 QSS。 - `resize(1400,900)` 未设 minimumSize,拖小后表格列挤没;splitter 比例硬编码,建议 QSettings 保存/恢复窗口几何。 - 结果表无排序、无"导出 CSV / 打开输出目录"按钮(结果 CSV 实际已落盘,可达性差)。 - 全英文 UI 是 ASCII 纪律的合理结果;如需中文界面建议走 Qt `.ts` 翻译文件而非硬编码。 ### 6.2 Web 前端(web/frontend/src,约 20 文件) **总体**:路由/布局/API 分层清晰,Element Plus + ECharts 选型得当,`Dashboard.vue` 是质量标杆(图表生命周期、空态、加载态、联动都正确)。但 4 个 🔴(D1-D4)证明 AI 相关 8 个页面**从未真正跑通过**。修复 D1/D2 后还必须处理: **交互逻辑** - AI 接口 30s 超时很可能不够(`api/index.ts:5`):方案生成/结果分析/经验提取都是 LLM 调用,建议 AI 类请求单独 `timeout: 120000`。 - 错误提示只显示 `e.message`:FastAPI 的 detail 被吞,用户只见 "Request failed with status code: 500"。响应拦截器统一提取 `err.response?.data?.detail`。 - 顶栏「后端已连接」硬编码假状态(`MainLayout.vue:65`):后端挂了也显示绿色。应轮询 health 接口。 - TaskManager 无自动刷新(:210):盯执行的核心页面全靠手动刷新,而 MonitorDashboard 已有 5s 轮询范式——有活跃任务时应启动轮询。 - 经验库搜索框每次击键都发请求且关键词根本没发给后端(`ExperienceList.vue:48`):请求纯属浪费,客户端 computed 过滤已是响应式的。 - 路由无 404 catch-all;菜单高亮在详情页丢失(精确匹配应改前缀匹配)。 - **假成功按钮**:PlanGenerator `savePlan` 是 stub 却弹"方案已保存(开发中)"成功提示(ExperienceEnhance 同样)——未实现功能应禁用或标"即将上线",不能给成功反馈。 - Dashboard 清空方案选择后图表渲染到已卸载 DOM(`Dashboard.vue:233-243`):再次选择时图表空白。selectedPlan 变 null 时 dispose 并置 null。 - AdvancedVisualization 4 个 ECharts 实例从不 dispose 无 resize 监听(内存泄漏,同项目 Dashboard 做法正确,两种标准)。 **美观度** - 中英混杂:ProjectDetail `Create Plan ({{estimatedPoints}} points)`、ExperienceList 编辑弹窗全英文、`Imported x cases`——P2 补丁做过全面中文化,这批 AI 页面又退化了。 - 字体栈缺中文回退(`style.css:9` 无 PingFang SC / Microsoft YaHei)。 - 响应式缺失:侧栏固定 220px 不可折叠;el-row 固定 `:span` 未配 `:xs/:sm/:md`,窄屏严重挤压。 - PlanDetail 结果表列硬编码 8 个指标,新指标无法显示——应按 `results[0].metrics` 动态生成列。 - TypeScript 类型安全形同虚设:`ref`/`res: any` 泛滥让 vue-tsc 完全拦不住字段错误——D2 那种低级 bug 正是 any 的直接后果。至少为核心实体定义 interface。 --- ## 七、已验证合规项(正面结论) - **ASCII 合规**:`src/`、`scripts/`、web 后端 routers/schemas/models、deploy.ps1 全部纯 ASCII ✅(仅 3 个 services 文件违规,见 F3;`.vue` 文件的"合规"方式用错了,见 D1) - **仓库卫生**:`git ls-files` 确认无 `.env`、`*.db`、`dist/`、`output/`、`node_modules`、`*.log` 被跟踪;`.gitignore` 覆盖全面 ✅(**此前怀疑的 .env 入库不成立**——.env 未入 Git,但会进 Docker 镜像,见 E1) - **硬编码密钥**:全仓搜索 sk-/Bearer/password/secret/token 模式,未发现真实密钥;API Key 统一走环境变量 ✅ - **SQL 注入 / 命令注入**:web 后端全部走 SQLAlchemy 参数化,无拼接 SQL、无 subprocess 调用;`experience_db.py` 全部参数化绑定 ✅ - **Motor-CAD 纪律(src 主链路)**:open_new_instance=True、set_visible(True)、MessageDisplayState=2、每点 load_from_file、回读校验抛 RuntimeError 标 FAILED 继续、逐点 writerow+flush、原始 .mot 只读(全文件无 save 调用)✅ - **参数语义**:rule_engine 注册表中 Magnet_Length=轴向厚度、Magnet_Thickness=径向深度(特意标注 "NOT radial depth")、RMSCurrent 口径,与知识库完全一致;全 src/ 未发现写 PeakCurrent ✅ - **API 契约骨架**:api_client 调用的 17 个端点在后端逐一核实全部存在,HTTP 方法/路径/参数/请求体/multipart 字段名/响应键均匹配 ✅;README "32 个 P3 API 端点"实测恰好 32 ✅ - **算法数学正确性**:LHS 采样(区间分配+维内打乱+种子固定 42)、Pearson(var=0 保护)、Pareto 支配逻辑、相似案例归一化距离、预算记账(L0 拒绝不占预算)均实现正确 ✅ - **前端部分页面**:Dashboard 图表 dispose/resize/空态/加载态正确;删除操作均有确认框;vite 代理配置正确 ✅ --- ## 八、修复优先级路线图 ### P0 — 立即修(阻断核心闭环正确性 / 数据完整性 / 必现崩溃) | 顺序 | 项 | 预估工作量 | |---|---|---| | 1 | A2+A3+A4+A5 task_executor 重构(复用 RobustMotorCADSolver,禁 mock 静默回退) | 0.5 天 | | 2 | A1 upload-results 指标清单单一事实源 | 0.5 天 | | 3 | A7 GUI `self._plan` 不更新 | 10 分钟 | | 4 | A8 api_client 204 空响应 | 10 分钟 | | 5 | B1 BatchScheduler 死锁 | 30 分钟 | | 6 | D1+D2 前端乱码 + axios .data(改动机械、收益巨大) | 0.5 天 | | 7 | C1 转矩方向映射表、C2 收敛判据接入或改 total、C3 L0 覆盖率判定 | 1 天 | | 8 | B3 输入校验崩溃、B4 GUI finally disconnect | 0.5 天 | ### P1 — 本周内(稳定性与部署) - B2 closeEvent + 退出路径;B5 robust 提前 return;B6/B7 超时死代码与无限重复执行 - F2 级联删除 + SQLite 外键;F5 GET 写副作用拆分 - E1 `.dockerignore` + **轮换已泄露的 API Key**;E2 空值屏蔽;E3 SQLite 持久卷;E4 共享 Token - F3 中文 prompt 外置;F4 Git preflight 裁决(改代码或改纪律,二选一) - C4/C5 信任域两个 bug;D3/D4 前端图表修复;3.1-1 求解超时+重连 - A6 自适应闭环本地执行桥(决定"闭环就绪"是否名副其实) - 3.4-34 状态枚举全仓库统一;3.4-25 Session 管理统一 ### P2 — 迭代打磨 - 其余 🟡 项(契约对齐、去重、分页上限、N+1、checkpoint 真正实现) - 测试体系重建:`_parse_export` 离线单测优先,三个假测试文件改写 - 文档校准:README 路线图/快速开始/能力宣称、设计方案第 5 章契约对照表 - 前端:类型定义、轮询、404、响应式、中文化补齐 --- ## 九、给项目决策层的三个问题 1. **Git preflight 到底"拒绝"还是"提醒"?** AGENTS.md 写拒绝、GUI 实现是可绕过——改代码还是改纪律,需要裁决(建议:硬拒绝 + manifest 记录 HEAD/dirty)。 2. **`robust_motorcad.py` 与 `solver_core.py` 两套求解器谁合并谁?** 850 行健壮性投入目前空转,task_executor 又在写第三套裸调用——建议收敛为一套。 3. **ASCII 纪律是否豁免 web/backend?** 3 个 services 文件已大量违规(内嵌中文 prompt)。建议不豁免、走 prompts 外置;若豁免需修改 AGENTS.md 并加 CI 检查边界。注意:此纪律**不适用于 `.vue` 文件**,前端的乱码恰恰是误用的结果。 --- > 本报告所有发现均有代码位置证据支撑;评审为静态分析,未运行动态仿真,涉及 Motor-CAD 实际行为的结论以知识库与代码逻辑推断为准。修复后建议对每个 P0 项做针对性验证(尤其是 D1/D2 修复后对 8 个 AI 页面做一次完整手工联调)。