修改简单模式验证
This commit is contained in:
@@ -337,7 +337,9 @@ def _generate_pytree_schema(allowed_actions: set, allowed_conditions: set) -> di
|
||||
|
||||
def _generate_simple_mode_schema(allowed_actions: set) -> dict:
|
||||
"""
|
||||
生成简单模式JSON Schema:{"mode":"simple","action":{...}}
|
||||
生成简单模式JSON Schema:{"root":{"type":"action","name":"...","params":{...}}}
|
||||
简单模式与复杂模式使用相同的格式(root字段),但要求root必须是action类型且没有children。
|
||||
严格按照提示词要求:root节点必须是action类型节点,不能是控制流节点(即不能有children)。
|
||||
仅校验动作名称在允许集合内,以及基本结构完整性;参数按对象形状放宽,由上游提示词与运行时再约束。
|
||||
"""
|
||||
schema = {
|
||||
@@ -345,19 +347,20 @@ def _generate_simple_mode_schema(allowed_actions: set) -> dict:
|
||||
"title": "SimpleMode",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"mode": {"type": "string", "const": "simple"},
|
||||
"action": {
|
||||
"root": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string", "enum": sorted(list(allowed_actions))},
|
||||
"params": {"type": "object"}
|
||||
"type": {"type": "string", "const": "action"}, # 必须是action类型,不能是控制流节点(Sequence/Selector/Parallel)
|
||||
"name": {"type": "string", "enum": sorted(list(allowed_actions))}, # 动作名称必须在允许列表中
|
||||
"params": {"type": "object"} # params是对象,具体参数由提示词和运行时约束
|
||||
},
|
||||
"required": ["name"],
|
||||
"additionalProperties": True
|
||||
"required": ["type", "name"], # type和name是必需的,params可选
|
||||
"additionalProperties": True # 允许root节点有其他属性(如额外的元数据)
|
||||
# 注意:children字段的检查在验证后手动进行,因为JSON Schema的not/allOf在检查不存在字段时可能有问题
|
||||
}
|
||||
},
|
||||
"required": ["mode", "action"],
|
||||
"additionalProperties": False
|
||||
"required": ["root"], # 顶层必须有root字段
|
||||
"additionalProperties": False # 顶层只能有root字段,不能有其他字段(如mode等)
|
||||
}
|
||||
return schema
|
||||
|
||||
@@ -777,6 +780,13 @@ class PyTreeGenerator:
|
||||
if mode == "simple":
|
||||
try:
|
||||
jsonschema.validate(instance=pytree_dict, schema=self.simple_schema)
|
||||
# 手动检查:简单模式的root节点不能有children(或children必须是空数组)
|
||||
root_node = pytree_dict.get('root', {})
|
||||
if 'children' in root_node:
|
||||
children = root_node.get('children', [])
|
||||
if isinstance(children, list) and len(children) > 0:
|
||||
logging.warning(f"❌ 简单模式验证失败: root节点不能有children,但发现 {len(children)} 个子节点")
|
||||
continue
|
||||
logging.info("✅ 简单模式JSON Schema验证成功")
|
||||
except jsonschema.ValidationError as e:
|
||||
logging.warning(f"❌ 简单模式验证失败: {e.message}")
|
||||
@@ -784,16 +794,13 @@ class PyTreeGenerator:
|
||||
# 附加元信息并生成简单可视化(单动作)
|
||||
plan_id = str(uuid.uuid4())
|
||||
pytree_dict['plan_id'] = plan_id
|
||||
# 简单模式可视化:构造一个简化节点图
|
||||
# 简单模式可视化:使用root节点(已经是action类型)
|
||||
try:
|
||||
vis_filename = "py_tree.png"
|
||||
vis_path = os.path.join(self.vis_dir, vis_filename)
|
||||
simple_node = {
|
||||
"type": "action",
|
||||
"name": pytree_dict.get('action', {}).get('name', 'action'),
|
||||
"params": pytree_dict.get('action', {}).get('params', {})
|
||||
}
|
||||
_visualize_pytree(simple_node, os.path.splitext(vis_path)[0])
|
||||
# 简单模式的root节点就是action节点,直接使用
|
||||
root_node = pytree_dict.get('root', {})
|
||||
_visualize_pytree(root_node, os.path.splitext(vis_path)[0])
|
||||
pytree_dict['visualization_url'] = f"/static/{vis_filename}"
|
||||
except Exception as e:
|
||||
logging.warning(f"简单模式可视化失败: {e}")
|
||||
@@ -820,46 +827,49 @@ class PyTreeGenerator:
|
||||
pytree_dict['final_prompt'] = final_prompt
|
||||
return pytree_dict
|
||||
|
||||
# 复杂模式回退:若模型误返回简单结构,则自动包装为含安全监控的行为树
|
||||
if mode == "complex" and isinstance(pytree_dict, dict) and 'root' not in pytree_dict:
|
||||
try:
|
||||
jsonschema.validate(instance=pytree_dict, schema=self.simple_schema)
|
||||
logging.warning("⚠️ 复杂模式生成了简单结构,触发自动包装为完整行为树的回退逻辑。")
|
||||
simple_action_obj = pytree_dict.get('action') or {}
|
||||
action_name = simple_action_obj.get('name')
|
||||
action_params = simple_action_obj.get('params') if isinstance(simple_action_obj.get('params'), dict) else {}
|
||||
# 复杂模式回退:若模型误返回简单结构(root是单个action),则自动包装为含安全监控的行为树
|
||||
if mode == "complex" and isinstance(pytree_dict, dict) and 'root' in pytree_dict:
|
||||
root_node = pytree_dict.get('root', {})
|
||||
# 检查是否是简单结构(root是单个action节点,没有children)
|
||||
if (root_node.get('type') == 'action' and
|
||||
('children' not in root_node or not root_node.get('children'))):
|
||||
try:
|
||||
jsonschema.validate(instance=pytree_dict, schema=self.simple_schema)
|
||||
logging.warning("⚠️ 复杂模式生成了简单结构(单个action),触发自动包装为完整行为树的回退逻辑。")
|
||||
action_name = root_node.get('name')
|
||||
action_params = root_node.get('params') if isinstance(root_node.get('params'), dict) else {}
|
||||
|
||||
safety_selector = {
|
||||
"type": "Selector",
|
||||
"name": "SafetyMonitor",
|
||||
"params": {"memory": True},
|
||||
"children": [
|
||||
{"type": "condition", "name": "battery_above", "params": {"threshold": 0.3}},
|
||||
{"type": "condition", "name": "gps_status", "params": {"min_satellites": 8}},
|
||||
{"type": "Sequence", "name": "EmergencyHandler", "children": [
|
||||
{"type": "action", "name": "emergency_return", "params": {"reason": "safety_breach"}},
|
||||
{"type": "action", "name": "land", "params": {"mode": "home"}}
|
||||
]}
|
||||
]
|
||||
}
|
||||
safety_selector = {
|
||||
"type": "Selector",
|
||||
"name": "SafetyMonitor",
|
||||
"params": {"memory": True},
|
||||
"children": [
|
||||
{"type": "condition", "name": "battery_above", "params": {"threshold": 0.3}},
|
||||
{"type": "condition", "name": "gps_status", "params": {"min_satellites": 8}},
|
||||
{"type": "Sequence", "name": "EmergencyHandler", "children": [
|
||||
{"type": "action", "name": "emergency_return", "params": {"reason": "safety_breach"}},
|
||||
{"type": "action", "name": "land", "params": {"mode": "home"}}
|
||||
]}
|
||||
]
|
||||
}
|
||||
|
||||
main_children = [{"type": "action", "name": action_name, "params": action_params}]
|
||||
if action_name != "land":
|
||||
main_children.append({"type": "action", "name": "land", "params": {"mode": "home"}})
|
||||
main_children = [{"type": "action", "name": action_name, "params": action_params}]
|
||||
if action_name != "land":
|
||||
main_children.append({"type": "action", "name": "land", "params": {"mode": "home"}})
|
||||
|
||||
root_parallel = {
|
||||
"type": "Parallel",
|
||||
"name": "MissionWithSafety",
|
||||
"params": {"policy": "all_success"},
|
||||
"children": [
|
||||
{"type": "Sequence", "name": "MainTask", "children": main_children},
|
||||
safety_selector
|
||||
]
|
||||
}
|
||||
pytree_dict = {"root": root_parallel}
|
||||
except jsonschema.ValidationError:
|
||||
# 不符合简单结构,按正常复杂验证继续
|
||||
pass
|
||||
root_parallel = {
|
||||
"type": "Parallel",
|
||||
"name": "MissionWithSafety",
|
||||
"params": {"policy": "all_success"},
|
||||
"children": [
|
||||
{"type": "Sequence", "name": "MainTask", "children": main_children},
|
||||
safety_selector
|
||||
]
|
||||
}
|
||||
pytree_dict = {"root": root_parallel}
|
||||
except jsonschema.ValidationError:
|
||||
# 不符合简单结构,按正常复杂验证继续
|
||||
pass
|
||||
if _validate_pytree_with_schema(pytree_dict, self.schema):
|
||||
logging.info("✅ 成功生成并验证了Pytree")
|
||||
plan_id = str(uuid.uuid4())
|
||||
|
||||
Reference in New Issue
Block a user