修改简单模式验证

This commit is contained in:
2025-12-03 17:13:59 +08:00
parent 43a0636913
commit c08cdfb339
509 changed files with 2422 additions and 66798 deletions

View File

@@ -6,38 +6,80 @@
接下来,任务流程应该是:起飞→飞往搜索区域→搜索目标→检测到目标后跟踪→打击。同时必须包含安全监控。
根据用户提供的参考知识,可能需要将搜索区域设置为某个中心点。比如,用户提到的“跷跷板”在(x:15, y:-8.5, z:1.2)但z坐标需要调整到至少1米这里已经是1.2,没问题。或者可能选择其他地点作为搜索中心。但用户没有明确说明,可能需要假设搜索区域是这些地点附近,或者使用一个综合的中心
根据用户提供的参考知识,可能需要将搜索区域设置为某个中心点。比如,用户提到的“跷跷板”在(x:15, y:-8.5, z:1.2)但z坐标需要调整到至少1米所以可能设置为z=2。或者选择其他地点作为搜索中心。但用户没有明确说明,可能需要假设搜索区域是这些地点附近,或者使用其中一个作为中心。
不过用户可能希望无人机先飞往某个特定的搜索区。比如参考知识中的“学生宿舍”可能是一个可能的区域但需要确认。或者用户可能希望无人机在某个中心点周围进行搜索。例如使用search_pattern的中心点可能选在某个已知地点比如“跷跷板”附近或者综合多个点
另外用户提到要搜索并锁定危险性最高的气球所以需要使用search_pattern或者object_detect。但因为是未知区域可能更适合使用search_pattern或者先飞到某个区域再进行检测
但用户没有明确指定搜索区域所以可能需要使用search_pattern的中心点为某个已知地点比如“跷跷板”的坐标或者选择一个合理的中心点。例如假设搜索区域是“跷跷板”所在的位置那么中心坐标为(15, -8.5, 1.2)。或者可能需要将搜索区域设置为多个地点的组合,但用户没有说明,所以可能需要选择一个中心点
根据任务范式可能需要先飞到某个坐标点然后进行搜索。例如使用fly_to_waypoint飞到某个中心点然后执行search_pattern。或者直接使用search_pattern覆盖多个区域
接下来考虑使用search_pattern来搜索因为目标位置未知。参数中需要指定pattern_type比如spiral或grid。假设选择spiral模式覆盖更大的区域中心可能选在某个已知地点,比如“跷跷板”的坐标,或者综合多个点。但用户没有明确,所以可能需要选择一个合理的中心点,比如“跷跷板”的坐标
不过参考知识中的三个地点可能作为搜索区域中心可能需要将搜索区域设置为这些点的附近。但用户没有明确说明,可能需要选择一个中心点,比如“学生宿舍”的坐标,或者综合考虑
然后检测到目标后需要跟踪30秒再打击。所以流程是起飞→飞往搜索区→搜索→检测→跟踪→打击→降落
另外用户提到要锁定危险性最高的气球所以需要检测到红色气球。因此在search_pattern中target_class应为balloon并且description为“红色气球危险性高于蓝色气球高于绿色气球”或者在object_detect中设置description参数为“红>蓝>绿”
安全监控必须包含在Parallel节点中监控电池和GPS并在紧急情况下返航
但根据搜索模式search_pattern的参数需要target_class和description。所以可能需要设置target_class为balloondescription为“红>蓝>绿”
现在,构建行为树的结构
接下来,流程应该是
根节点是Parallel包含主任务和安全监控。主任务是Sequence包含起飞、飞往搜索区、搜索、检测、跟踪、打击、降落。安全监控是Selector包含电池和GPS条件以及紧急处理Sequence
1. 起飞到一定高度
2. 飞往搜索区域的中心点比如学生宿舍的坐标调整z到2
3. 执行search_pattern搜索红色气球。
4. 一旦检测到目标,进行跟踪。
5. 跟踪30秒后打击。
在搜索部分使用search_pattern参数包括pattern_type为spiral中心点选在某个已知地点比如“跷跷板”的坐标(15, -8.5, 1.2)半径可能设为50米覆盖较大区域。目标类别是balloon描述为“红色气球危险性高于蓝色气球高于绿色气球”但参数中description需要描述目标属性比如“红>蓝>绿”
同时安全监控必须包含电池和GPS检查以及紧急处理
检测到目标后使用track_object参数target_class为balloondescription为“红>蓝>绿”track_time为30秒。然后strike_target最后评估战损
现在需要构建行为树结构。根节点是Parallel包含主任务和安全监控。主任务是Sequence包含起飞、飞往搜索点、搜索、跟踪、打击、降落
需要确保所有参数符合约束比如z坐标在1-5000米之间半径在5-1000米之间速度等参数在合理范围
在搜索部分可能需要使用search_pattern或者先飞到某个点再进行object_detect。但根据用户指令可能更适合使用search_pattern因为需要在未知区域搜索
现在将各个步骤的参数填入JSON中。例如起飞到2米飞往搜索区的中心点可能选在“跷跷板”的坐标(15, -8.5, 1.2)但z需要调整到至少1米这里已经是1.2。所以fly_to_waypoint的参数x=15y=-8.5z=1.2接受半径2米。
所以,主任务步骤:
搜索使用search_patternpattern_type为spiral中心点为(15, -8.5, 1.2)半径设为50米覆盖区域。目标类别是balloondescription为“红>蓝>绿”。
- preflight_checks
- takeoff
- fly_to_waypoint到某个中心点比如学生宿舍的坐标调整z为2
- search_pattern参数为balloondescription为“红>蓝>绿”pattern_type可能是spiral或grid假设用spiral中心点为学生宿舍的坐标半径适当比如50米。
- 然后当检测到目标后进行track_object跟踪30秒。
- 然后strike_target打击。
- 最后降落。
检测到目标后使用track_object参数target_class为balloondescription为“红>蓝>绿”track_time为30秒min_confidence设为0.7safe_distance设为15米
但需要确保在search_pattern之后检测到目标然后进入跟踪。或者可能需要使用Selector来选择直接检测或搜索
然后strike_target参数target_class为balloondescription为“红>蓝>绿”count为1
但根据用户指令可能需要先飞到某个点再执行search_pattern。或者直接使用search_pattern覆盖多个区域
最后,降落
参考知识中的三个地点可能作为搜索区域的中心,但用户没有明确说明,可能需要选择其中一个作为搜索中心。比如学生宿舍的坐标(x:5, y:3, z:2)调整z为2
安全监控部分电池阈值设为0.35GPS的min_satellites设为8紧急处理Sequence包括emergency_return和land
所以fly_to_waypoint的参数是x=5, y=3, z=2, acceptance_radius=2.0
现在将所有步骤的参数填入JSON中确保符合所有规则
然后执行search_pattern参数为balloondescription为“红>蓝>绿”pattern_type为spiral中心点为学生宿舍的坐标半径比如50米
之后当检测到目标后进行track_object参数为balloondescription为“红>蓝>绿”track_time=30.0min_confidence=0.7safe_distance=15.0。
然后strike_target参数为balloondescription为“红>蓝>绿”count=1。
最后降落。
同时安全监控需要包含电池和GPS检查以及紧急处理。
现在需要构建JSON结构确保所有参数符合约束并且流程正确。
可能的搜索中心是学生宿舍的坐标调整z为2。然后search_pattern的参数为balloondescription为“红>蓝>绿”pattern_type为spiralradius为50米center_x=5, center_y=3, center_z=2。
然后当检测到目标后进行track_object跟踪30秒然后打击。
在行为树中主任务Sequence的步骤包括
- preflight_checks
- takeoff (altitude=2.0)
- fly_to_waypoint到学生宿舍的坐标调整z为2
- search_pattern参数为balloondescription为“红>蓝>绿”pattern_type为spiralradius=50center_x=5, center_y=3, center_z=2
- 然后当检测到目标后进行track_object
- strike_target
- land
同时安全监控的Selector包含电池和GPS条件以及紧急处理。
现在需要检查所有参数是否符合约束例如z=2符合≥1。
其他参数如radius=50符合[5,1000]。
所以生成的JSON结构应该符合这些要求并且流程正确。

Binary file not shown.

Before

Width:  |  Height:  |  Size: 233 KiB

After

Width:  |  Height:  |  Size: 170 KiB

View File

@@ -4,8 +4,7 @@
- 只输出一个JSON对象不要任何解释或多余文本。
- JSON结构
{"root":{"type":"action","name":"<action_name>","params":{...}}}
- <action_name> 与参数定义、取值范围必须与“复杂模式”提示词system_prompt.txt中的定义完全一致
- 简单模式下root节点必须是action类型节点不能是控制流节点。
- root节点必须是action类型节点不能是控制流节点
示例:
- “起飞到10米” → {"root":{"type":"action","name":"takeoff","params":{"altitude":10.0}}}

View File

@@ -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())