Files
EPEEAIKit/.cursor/pitfalls/pitfalls.md
2026-04-20 21:52:35 +08:00

7.0 KiB
Raw Permalink Blame History

Pitfall Journal

开发过程中踩过的坑,按时间倒序排列。 Agent 进入 Debug mode 或遇到运行时错误时自动检索匹配。


[PF-20260420-1600] firtoz/trellis Replicate 部署版 schema 与 README 及官方 API 文档不一致

  • 症状: (1) 按 Replicate README example 用 input={"image": uri} 传单数 image → 422 Input validation failed: input: images is required。改成 images: [uri] 后模型能跑,产出 model_file/combined_video/gaussian_ply/no_background_images。(2) 尽管 generate_color=True + generate_normal=True 都开,输出字典里 color_videonormal_video 字段恒为 null,只有 combined_video 这个"color 和 normal 左右并排的 mp4"才真正可用。
  • 根因: firtoz/trellis:e8f6c45206993f297372f5436b90350817bd9b4a0d52d2a76df50c1c8afa2b3c 这个 Replicate 部署版的实际输入/输出 schema 与 firtoz 在 Replicate README 里贴的 example、以及 microsoft/TRELLIS 官方仓库的 Python API 都不一样——输入字段是 images(数组)而不是 image(字符串),输出字段虽然声明了 color_videonormal_video 但该部署版恒给 null只填 combined_video。很可能是部署者在包装层做了合并(省带宽/对象存储开销)但没同步 README。
  • 解法: (1) 输入字段固定传 images: [uri] 数组,即使只有 1 张图;(2) Phase 2 抽帧的数据源从 combined_video 切——每一帧的左半 = color、右半 = normal用 PIL crop 即可;(3) 不要相信 Replicate README 上的 Python example永远以 该版本 ID 的 OpenAPI schema 为准(虽然 firtoz/trellis 这个 README 也看不到精确 schema所以只能实测
  • 防御: 接 Replicate 新模型前先用 1 美元额度做一次最小输入测试,打印 output 的原始 dict 结构 + 每个 key 的值类型;不要假设 README 的 example 与实际部署版本一致。mesh_generator.py 里已经做了"把 raw_output_keys 和每个字段的 None 警告都打印"的防御日志。
  • 关联: Replicate, firtoz/trellis, Mesh Pipeline, view_transform, Trellis, 3D 重建, schema, OpenAPI, mesh_generator.py

[PF-20260420-1501] Windows uvicorn --reload 缺 watchfiles 退化为轮询,代码改动不被热重载

  • 症状: 代码已修好git diff / Read 看源文件都是新版但后端运行时行为仍是旧代码。具体表现CL-20260420-1212 修好 Zero123++ 切图后(cols=2/rows=3 + 自动纠错),前端再触发一次转视角,切出的 view 图仍是 213×480= 640/3 × 960/2旧的 cols=3,rows=2 逻辑),而独立用当前代码调用 _split_grid_image 能正确切出 320×320。进程启动时间 11:55改动时间 12:12观察时间 15:00期间未 reload 过任何改动。
  • 根因: uvicorn --reload 在未安装 watchfileswatchdog 时 fallback 到 StatReload基于轮询。Windows 文件系统事件语义本就弱,加上深层子目录(app/services/+ 新建文件(view_transform.py 在仓库里是新增 untracked 文件),几个因素叠加让 StatReload 漏通知/响应极慢,表现为"启动后改什么代码都不会重载"。venv 里 watchfileswatchdog 双双 MISSING 是核心证据。
  • 解法: (1) pip install watchfiles==0.24.0uvicorn 官方首选 reloader(2) 写入 requirements.txtrequirements-lock.txt,避免其他设备重装环境时再次踩坑;(3) kill 当前 uvicorn 进程重启一次——新进程才会用上 WatchFiles reloader并同步加载最新代码。仅装依赖不重启不会生效因为当前进程已经加载了 StatReload。
  • 防御: Windows 上只要 uvicorn 带 --reloadwatchfiles 就是硬依赖,不是可选项。启动后首屏日志如果看到 WatchFiles detected changesStarted reloader process [xxx] using WatchFiles 才算正常;如果只有 Started reloader process [xxx] using StatReload 就是退化状态。可以额外传 --reload-dir app 显式指定监控范围更保险。任何"改了代码不生效"的诡异现象,第一时间先确认进程是否已经重载(看日志里的文件变更提醒,或对比进程启动时间 vs 文件 mtime再排查代码逻辑。
  • 关联: uvicorn, --reload, watchfiles, StatReload, FastAPI, Windows, 热重载, requirements.txt, view_transform.py, Zero123++

[PF-20260420-1212] Zero123++ 输出 grid 布局被文档措辞"3×2"误导

  • 症状: Zero123++ 视角变换后切出的 6 张图严重错位,每张子图呈窄长条(宽:高 约 1:2画面里上下拼着两个教堂边缘大量留白。拼接图原图视觉正常。
  • 根因: Zero123++ 官方 README 写 "output is a 3×2 grid of 6 views",但 jd7h/zero123plusplus 这个 Replicate 部署版本实际输出的是 2 列 × 3 行(高图,如 640×960而 config.py 里按"3 列 × 2 行"配置了 grid_layout。切图时 cell_w = 640//3 = 213, cell_h = 960//2 = 480,每个切片横跨了真实 grid 中两行的一部分,于是每张图都拼着两个视角的局部。
  • 解法: (1) config.pyVIEW_TRANSFORM_MODELS["zero123plus"].grid_layout 改为 {"cols": 2, "rows": 3}(2) view_transform._split_grid_image 加入"按实际图像长宽比 vs 配置 ratio 自动纠正"——假定每个单视角为正方形,真实 aspect ratio 应等于 cols/rows,若配置 ratio 与实际差异 >20% 就自动交换 cols/rows 并打 warning。
  • 防御: 任何涉及"grid 拼接图切分"的场景,不要完全相信模型文档的"A×B"措辞A 是列还是行常有歧义),必须用实际图像长宽比做健壮性检查;最稳妥的做法是让 split 函数本身能根据单视角正方形假设自动推断布局,不信任硬编码。更激进的方案是直接用 PIL 探测内容块边界(但对有微量白边的模型不稳定)。
  • 关联: Zero123++, Replicate, jd7h/zero123plusplus, grid 切图, PIL, view_transform.py, config.py, Novel View Synthesis

[PF-20260412-1530] Python load_dotenv 默认不覆盖已有环境变量 + 模块级变量在 import 时固化

  • 症状: 修改 .env 切换 API 供应商后,后端仍报旧供应商的错误(如 DeepSeek 报 "Model Not Exist",实际发送的模型名是 OpenAI 的 gpt-4o-mini
  • 根因: 两层叠加:(1) load_dotenv() 默认 override=False,如果进程/系统中已有同名环境变量,.env 中的新值不会生效;(2) config.py 使用模块级常量 LLM_MODEL = os.getenv(...) 在 import 时就求值固化,而 main.py 的 import 链在 load_dotenv() 之前就触发了 config.py 的加载
  • 解法: (1) load_dotenv(override=True) 并提到所有业务 import 之前;(2) config.py 改为函数式 get_llm_model(),运行时才读取
  • 防御: 任何 Python 项目使用 dotenv 时,始终 override=True + 放在文件最顶部(仅在 import osfrom dotenv import load_dotenv 之后);配置值用函数或属性包装,不要用模块级常量
  • 关联: Python, dotenv, FastAPI, uvicorn, 环境变量, 配置管理, OpenAI SDK