Files
Uni-Lab-OS/.cursor/skills/edit-experiment-graph/reference.md
2026-03-06 16:54:31 +08:00

7.3 KiB
Raw Blame History

实验图高级参考

本文件是 SKILL.md 的补充,包含 ResourceDict 完整 schema、Handle 验证、GraphML 格式、Pose 标准化规则和复杂图文件结构。Agent 在需要处理这些场景时按需阅读。


1. ResourceDict 完整字段

unilabos/resources/resource_tracker.py 中定义的节点数据模型:

字段 类型 别名 说明
id str 节点唯一标识
uuid str 全局唯一标识
name str 显示名称
description str 描述(默认 ""
resource_schema Dict[str, Any] schema 资源 schema
model Dict[str, Any] 3D 模型信息
icon str 图标(默认 ""
parent_uuid Optional[str] 父节点 UUID
parent Optional[ResourceDict] 父节点引用(序列化时 exclude
type Union[Literal["device"], str] 节点类型
klass str class 注册表类名
pose ResourceDictPosition 位姿信息
config Dict[str, Any] 配置参数
data Dict[str, Any] 运行时数据
extra Dict[str, Any] 扩展数据

Pose 完整结构ResourceDictPosition

字段 类型 默认值 说明
size {width, height, depth} {0,0,0} 节点尺寸
scale {x, y, z} {1,1,1} 缩放比例
layout "2d"/"x-y"/"z-y"/"x-z" "x-y" 布局方向
position {x, y, z} {0,0,0} 2D 位置
position3d {x, y, z} {0,0,0} 3D 位置
rotation {x, y, z} {0,0,0} 旋转角度
cross_section_type "rectangle"/"circle"/"rounded_rectangle" "rectangle" 横截面形状

2. Position / Pose 标准化规则

图文件中的 position 有多种写法,加载时自动标准化。

输入格式兼容

// 格式 A: 直接 {x, y, z}(最常用)
"position": {"x": 100, "y": 200, "z": 0}

// 格式 B: 嵌套 position
"position": {"position": {"x": 100, "y": 200, "z": 0}}

// 格式 C: 使用 pose 字段
"pose": {"position": {"x": 100, "y": 200, "z": 0}}

// 格式 D: 顶层 x, y, z无 position 字段)
"x": 100, "y": 200, "z": 0

标准化流程

  1. graphio.py canonicalize_nodes_data:若 position 不是 dict从节点顶层提取 x/y/z 填入 pose.position
  2. resource_tracker.py get_resource_instance_from_dict:若 position.x 存在(旧格式),转为 {"position": {"x":..., "y":..., "z":...}}
  3. pose.sizeconfig.size_x/size_y/size_z 自动填充

3. Handle 验证

启动时系统验证 link 中的 sourceHandle / targetHandle 是否在注册表的 handles 中定义。

# unilabos/app/main.py (约 449-481 行)
source_handler_keys = [
    h["handler_key"] for h in materials[source_node.klass]["handles"]
    if h["io_type"] == "source"
]
target_handler_keys = [
    h["handler_key"] for h in materials[target_node.klass]["handles"]
    if h["io_type"] == "target"
]
if source_handle not in source_handler_keys:
    print_status(f"节点 {source_node.id} 的source端点 {source_handle} 不存在", "error")
    resource_edge_info.pop(...)  # 移除非法 link

Handle 定义在注册表 YAML 中:

my_device:
  handles:
  - handler_key: access
    io_type: target
    data_type: fluid
    side: NORTH
    label: access

大多数简单设备不定义 handles此验证仅对有 sourceHandle/targetHandle 的 link 生效。


4. GraphML 格式支持

除 JSON 外,系统也支持 GraphML 格式(unilabos/resources/graphio.py::read_graphml)。

与 JSON 的关键差异

特性 JSON GraphML
父子关系 parent/children 字段 :: 分隔的节点 IDstation::pump_1
加载后 直接解析 nx.read_graphml 再转 JSON 格式
输出 不生成副本 自动生成等价的 .json 文件

GraphML 转换流程

nx.read_graphml(file)
    ↓ 用 label 重映射节点名
    ↓ 从 "::" 推断 parent_relation
nx.relabel_nodes + nx.node_link_data
    ↓ canonicalize_nodes_data + canonicalize_links_ports
    ↓ 写出等价 JSON 文件
physical_setup_graph + handle_communications

5. 复杂图文件结构示例

外部系统工作站完整 config

reaction_station_bioyond.json 为例,工作站 config 中的关键字段:

{
    "config": {
        "api_key": "DE9BDDA0",
        "api_host": "http://172.21.103.36:45388",

        "workflow_mappings": {
            "scheduler_start": {"workflow": "start", "params": {}},
            "create_order": {"workflow": "create_order", "params": {}}
        },

        "material_type_mappings": {
            "BIOYOND_PolymerStation_Reactor": ["反应器", "type-uuid-here"],
            "BIOYOND_PolymerStation_1BottleCarrier": ["试剂瓶", "type-uuid-here"]
        },

        "warehouse_mapping": {
            "堆栈1左": {
                "uuid": "warehouse-uuid-here",
                "site_uuids": {
                    "A01": "site-uuid-1",
                    "A02": "site-uuid-2"
                }
            }
        },

        "http_service_config": {
            "enabled": true,
            "host": "0.0.0.0",
            "port": 45399,
            "routes": ["/callback/workflow", "/callback/material"]
        },

        "deck": {
            "data": {
                "_resource_child_name": "Bioyond_Deck",
                "_resource_type": "unilabos.resources.bioyond.decks:BIOYOND_PolymerReactionStation_Deck"
            }
        },

        "size_x": 2700.0,
        "size_y": 1080.0,
        "size_z": 2500.0,
        "protocol_type": [],
        "data": {}
    }
}

子设备 Reactor 节点

{
    "id": "reactor_1",
    "name": "reactor_1",
    "parent": "reaction_station_bioyond",
    "type": "device",
    "class": "bioyond_reactor",
    "position": {"x": 1150, "y": 300, "z": 0},
    "config": {
        "reactor_index": 0,
        "bioyond_workflow_key": "reactor_1"
    },
    "data": {}
}

Deck 节点

{
    "id": "Bioyond_Deck",
    "name": "Bioyond_Deck",
    "parent": "reaction_station_bioyond",
    "type": "deck",
    "class": "BIOYOND_PolymerReactionStation_Deck",
    "position": {"x": 0, "y": 0, "z": 0},
    "config": {
        "type": "BIOYOND_PolymerReactionStation_Deck",
        "setup": true,
        "rotation": {"x": 0, "y": 0, "z": 0, "type": "Rotation"}
    },
    "data": {}
}

graphio.py::canonicalize_links_ports 处理 port 字段的多种格式:

# 输入: 字符串格式 "(A,B)"
"port": "(pump_1, valve_1)"
# 输出: 字典格式
"port": {"source_id": "pump_1", "target_id": "valve_1"}

# 输入: 已是字典
"port": {"pump_1": "port", "serial_1": "port"}
# 保持不变

# 输入: 无 port 字段
# 自动补充空 port

7. 关键路径

内容 路径
ResourceDict 模型 unilabos/resources/resource_tracker.py
图加载 + 标准化 unilabos/resources/graphio.py
Handle 验证 unilabos/app/main.py (449-481 行)
反应站图文件 unilabos/test/experiments/reaction_station_bioyond.json
配液站图文件 unilabos/test/experiments/dispensing_station_bioyond.json
用户文档 docs/user_guide/graph_files.md