装配建模 agent 系统:把自然语言需求转化为可装配的 CAD 模型。
┌──────────────────────────────────────────────────────────────┐
│ LangGraph 编排层(外层 agent) │
│ processor → generator → assembly_worker → validator │
│ 每个节点:从 state 拿任务声明 → 调 runner → 回填结果 │
└──────────────────────────────────────────────────────────────┘
│
▼ runner.run_task(task, workspace)
┌──────────────────────────────────────────────────────────────┐
│ AgentRunner 抽象层(内层 agent) │
│ ┌─────────────────┬─────────────────┬─────────────────┐ │
│ │ ClaudeCodeCLI │ LiteLLMReact │ ClaudeSDKBedrock│ │
│ │ subprocess │ create_react_ │ stub (未实装) │ │
│ │ claude -p │ agent + MooN │ │ │
│ └─────────────────┴─────────────────┴─────────────────┘ │
└──────────────────────────────────────────────────────────────┘
│
▼ 在 workspace/<task>/ 下读写文件
内外层文件系统接口
不同部署阶段的认证 / 计费 / 合规要求差别很大:
| 阶段 | 认证 | 谁付钱 | 合规 | 选 runner |
|---|---|---|---|---|
| 个人开发调试 | 我的 Claude Max OAuth | 订阅免费额度 | 个人 ToS OK | claude_cli |
| Demo / 公司演示 | 公司 MooN 网关 key | 公司网关 | OK | litellm |
| 生产部署 | AWS Bedrock 凭证 | 公司 AWS 账户 | 商用 ToS OK | sdk_bedrock(待实装) |
业务代码(agents/、orchestrator)不需要任何修改——切 RUNNER_MODE 就完事。
调内层 runner 时只传任务声明 + workspace 路径,绝不把外层 message history 塞进内层 prompt。两层之间通过 workspace 目录里的文件交换数据。这样:
- 外层每个节点的 context 干净,不会被内层细节污染
- 内层 agent 看到的也是干净的任务,发挥稳定
- workspace 目录天然成为 trace、复盘、调试的现场
assembleagent/
├── agents/
│ ├── orchestrator.py # LangGraph:build_app() (L0) + build_l05_app() (L0.5)
│ ├── assembly_worker.py # L0 主节点:NL → trimesh code → STL(调 runner)
│ ├── ir_assembler.py # IR-v0.1 placement solver(纯 Python,无 LLM)
│ ├── ir_assembler_node.py # 把 ir_assembler 包成 LangGraph 节点
│ ├── validator_visual.py # ⭐ L0.6 VLM 视觉验收(Gemini-3.1-pro 直调,D2 例外)
│ ├── model_processor.py # TODO 占位
│ ├── model_generator.py # 单零件占位(未接 graph)
│ └── validator.py # 旧 TODO 占位(已被 validator_visual 替代)
├── core/
│ ├── state.py # AssemblyState(含 case_id / candidate_ir_path 等 L0.5 字段)
│ ├── config.py # NODE_MODEL_MAP + get_runner() + BLENDER_EXE_PATH
│ ├── output_naming.py # outputs/<model>_v<n>_<mm_dd>/ 命名
│ ├── llm_factory.py
│ └── runners/
│ ├── base.py # AgentRunner Protocol
│ ├── claude_code_cli.py
│ ├── litellm_react.py
│ └── claude_sdk_bedrock.py # stub
├── tools/
│ ├── blender_render.py # Blender CLI Python 脚本(单 STL 渲染)
│ └── blender_renderer.py # 业务节点用的 helper(封装 Blender CLI + PIL 拼图)
└── tests/test_runners.py
# 仓库顶层
cases/ # eval set:每 case 含 IR yaml + REQUIREMENT.md + verify.py
├── ikea/lack/ # 6 长方体 baseline
├── ikea/poang_1/ # 5 件曲面 + 拓扑跳跃
│ └── _silent_failures/ # 3 个故意 broken IR(mirror/braces/seat),测 visual verifier
└── ikea/gladom/ # 4 件圆桌(X 框架+rim+tray),为 L4 GT 三路径 ablation 实验立
IKEA-Manuals-at-Work-main/ # 上游数据集(CC-BY-4.0,102 件家具 + 4 模态目录,只读)
data_curated/ # 派生视图:37 件按难度分桶 + 立案状态反查(见 docs/concepts/data-curated.md)
workspace/ # runner / ir_assembler 工作目录
outputs/ # 归档:<model>_v<n>_<mm_dd>/(详见 docs/concepts/outputs-naming.md)
docs/ # 知识库(从 docs/index.md 进入)
# 入口脚本
quickstart.py # 单节点冒烟(按 RUNNER_MODE 跑长方体)
run_assembly.py # L0 graph: NL → assembly_worker → STL
run_ir_assembly.py # L0.5 单跑: IR yaml → ir_assembler → GLB(不接 graph)
run_l05_with_validator.py # ⭐ L0.5 graph: ir_assembler → validator_visual(生产用)
run_l06_intent_poc.py # L0.6 意图理解 PoC: VLM 看图 → IR yaml
run_l06_visual_verify_poc.py # L0.6 验收 PoC v1(早期)
run_l06_visual_verify_poc_v2.py # L0.6 验收 PoC v2(中期)
run_l06_visual_verify_poc_v3.py # L0.6 验收 PoC v3(最终版,Sonnet vs Gemini 跨模型 → 后续接进 graph 成 validator_visual)
# 实验入口(自动归档版)
scripts/run_experiment.py # ⭐ 跑 L0.5 graph + 自动把所有产物归档到 outputs/<exp_name>_v<n>_<mm_dd>/
需要 Python 3.11+ 和 Node 18+(claude CLI 的隐性依赖)。
python -m venv .venv
source .venv/Scripts/activate # Windows
# source .venv/bin/activate # macOS / Linux
pip install -r requirements.txt复制 .env.example 为 .env,填入:
LANGSMITH_API_KEY— LangSmith 控制台获取LITELLM_API_KEY— 公司 MooN 网关 key(litellm 模式必填)RUNNER_MODE— 默认litellm,可选claude_cli/sdk_bedrock
# 单节点冒烟:按 RUNNER_MODE 跑长方体(默认 litellm 走 MooN 网关)
python quickstart.py成功后 workspace/quickstart/ 出现 box.py 和 box.stl。
python run_assembly.py "做一张高 50cm 半径 20cm 的圆桌"跑生产 LangGraph,含 ir_assembler → validator_visual:
# baseline(应该 verdict=pass,~35s)
python run_l05_with_validator.py ikea-poang_1
# 故意 broken 的 IR(应该 verdict=fail,~30s)
python run_l05_with_validator.py ikea-poang_1 cases/ikea/poang_1/_silent_failures/broken_seat.yamlvalidator_visual 节点用 Gemini-3.1-pro 多模态对比 baseline 渲染,检测肉眼可见但纯几何 verify 抓不到的 silent failure(左右镜像反 / 前后撑搞错 / 坐垫翻转)。
需要 Blender 5.x(默认路径 Windows C:\Program Files\Blender Foundation\Blender 5.1\blender.exe,环境变量 BLENDER_EXE 可覆盖)。
run_l05_with_validator.py 跑产物分散在 workspace/ + cases/,演示时要打开多个目录。改用 scripts/run_experiment.py 一行命令搞定,所有产物聚到 outputs/<exp_name>_v<n>_<mm_dd>/:
# 跑 baseline + 自动归档
python scripts/run_experiment.py poang_baseline ikea-poang_1 \
--description "POANG baseline 健康检查"
# 跑 candidate IR(测试自动推的 IR yaml 跟人手 baseline 差距)
python scripts/run_experiment.py poang_origin ikea-poang_1 \
--candidate-ir cases/ikea/poang_origin/assembly-relations.yaml \
--description "OBJ 移原点 + Gemini 推 IR 跟人手 baseline 比"输出 outputs/poang_origin_v1_04_30/ 含 GLB / mosaic / 9 单视图 / IR yaml / case 元数据 / _TASK.md / RESULT.md。详见 docs/concepts/outputs-naming.md。
RUNNER_MODE=claude_cli python quickstart.py # 走 claude CLI(需 `claude` 登录)
RUNNER_MODE=litellm python quickstart.py # 走公司 MooN 网关(默认)# 默认只跑 litellm 测试,避免烧 Max 订阅额度
python -m pytest assembleagent/tests/
# 显式开启 claude_cli 测试
RUN_CLAUDE_CLI=1 python -m pytest assembleagent/tests/claude_clirunner 仅供个人开发调试:通过claude -p走开发者本地 OAuth/订阅认证,符合 Anthropic 个人用户 ToS。- 生产部署请切
sdk_bedrockrunner:通过公司 AWS Bedrock 商用凭证,付费、合规、可审计。 litellmrunner 走公司 MooN 网关:公司侧合规由网关方负责。
不要在面向客户的产品里直接用 claude_cli runner——OAuth 凭证不可分发,也不符合商用 ToS。
| Stage | 内容 | 状态 |
|---|---|---|
| L0 | NL → assembly_worker → STL(runner 抽象层就绪) | ✅ 跑通 |
| L0.5 | IR-v0.1 yaml → ir_assembler → 真实 OBJ 装 STL | ✅ 跑通 |
| L0.6 视觉验收 | STL → Blender 渲染 → Gemini-3.1-pro 对比 baseline | ✅ v3 PoC + LangGraph 节点接入(run_l05_with_validator.py) |
| L0.6 意图理解 | manual PNG → VLM → IR yaml | ✅ v3 PoC(5/5 transform 跟 baseline 字面相同) |
| L1 | assembly_worker 失败 → stderr 喂回重试 | TODO |
| L2 | 完整 validator 节点(规则层 + LLM thinking) | 部分(视觉验收已有 Layer 2,规则 layer 待加) |
| L3 | 完整四节点 graph(model_processor → generator → worker → validator) | TODO |
| L4 | 条件边 / 动态分支,真正的 dynamic agent | TODO |
当前活的两条 graph:
- L0 = NL →
assembly_worker(build_app()) - L0.5 = IR yaml →
ir_assembler→validator_visual(build_l05_app())
当天迭代时间线见 docs/log.md;3 分钟 mentor team review 版见 docs/raw/2026-04-28-day1-mvp-snapshot.md;全部知识库从 docs/index.md 进入。