diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..065a8c0a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,34 @@
+# ============ 日志 ============
+logs/
+
+# ============ 向量库(RAG 检索用) ============
+**/vector_store/
+vector_store/
+
+# ============ 测试脚本的测试结果 ============
+tools/test_validate/validation/
+
+# ============ 生成的图片 ============
+backend_service/generated_visualizations/
+tools/test_validate/validation/**/*.png
+tools/test_validate/validation/**/*.jpg
+
+# ============ Python ============
+__pycache__/
+*.py[cod]
+*$py.class
+*.so
+.Python
+venv/
+.venv/
+env/
+.env/
+
+# ============ 其他常见忽略 ============
+*.log
+.DS_Store
+.idea/
+.vscode/
+*.swp
+*.swo
+*~
diff --git a/backend_service/generated_visualizations/py_tree.png b/backend_service/generated_visualizations/py_tree.png
deleted file mode 100644
index dcfa34eb..00000000
Binary files a/backend_service/generated_visualizations/py_tree.png and /dev/null differ
diff --git a/logs/embedding_model.log b/logs/embedding_model.log
deleted file mode 100644
index 4112bd84..00000000
--- a/logs/embedding_model.log
+++ /dev/null
@@ -1,256 +0,0 @@
-ggml_cuda_init: GGML_CUDA_FORCE_MMQ: no
-ggml_cuda_init: GGML_CUDA_FORCE_CUBLAS: no
-ggml_cuda_init: found 1 CUDA devices:
- Device 0: NVIDIA GeForce RTX 4060 Ti, compute capability 8.9, VMM: yes
-build: 6097 (9515c613) with cc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 for x86_64-linux-gnu
-system info: n_threads = 8, n_threads_batch = 8, total_threads = 16
-
-system_info: n_threads = 8 (n_threads_batch = 8) / 16 | CUDA : ARCHS = 500,610,700,750,800,860,890 | USE_GRAPHS = 1 | PEER_MAX_BATCH_SIZE = 128 | CPU : SSE3 = 1 | SSSE3 = 1 | AVX = 1 | AVX_VNNI = 1 | AVX2 = 1 | F16C = 1 | FMA = 1 | BMI2 = 1 | LLAMAFILE = 1 | OPENMP = 1 | REPACK = 1 |
-
-main: binding port with default address family
-main: HTTP server is listening, hostname: 0.0.0.0, port: 8090, http threads: 15
-main: loading model
-srv load_model: loading model '/home/huangfukk/models/gguf/Qwen3/Qwen3-Embedding-4B/Qwen3-Embedding-4B-Q5_K_M.gguf'
-llama_model_load_from_file_impl: using device CUDA0 (NVIDIA GeForce RTX 4060 Ti) - 15225 MiB free
-llama_model_loader: loaded meta data with 36 key-value pairs and 398 tensors from /home/huangfukk/models/gguf/Qwen3/Qwen3-Embedding-4B/Qwen3-Embedding-4B-Q5_K_M.gguf (version GGUF V3 (latest))
-llama_model_loader: Dumping metadata keys/values. Note: KV overrides do not apply in this output.
-llama_model_loader: - kv 0: general.architecture str = qwen3
-llama_model_loader: - kv 1: general.type str = model
-llama_model_loader: - kv 2: general.name str = Qwen3 Embedding 4B
-llama_model_loader: - kv 3: general.basename str = Qwen3-Embedding
-llama_model_loader: - kv 4: general.size_label str = 4B
-llama_model_loader: - kv 5: general.license str = apache-2.0
-llama_model_loader: - kv 6: general.base_model.count u32 = 1
-llama_model_loader: - kv 7: general.base_model.0.name str = Qwen3 4B Base
-llama_model_loader: - kv 8: general.base_model.0.organization str = Qwen
-llama_model_loader: - kv 9: general.base_model.0.repo_url str = https://huggingface.co/Qwen/Qwen3-4B-...
-llama_model_loader: - kv 10: general.tags arr[str,5] = ["transformers", "sentence-transforme...
-llama_model_loader: - kv 11: qwen3.block_count u32 = 36
-llama_model_loader: - kv 12: qwen3.context_length u32 = 40960
-llama_model_loader: - kv 13: qwen3.embedding_length u32 = 2560
-llama_model_loader: - kv 14: qwen3.feed_forward_length u32 = 9728
-llama_model_loader: - kv 15: qwen3.attention.head_count u32 = 32
-llama_model_loader: - kv 16: qwen3.attention.head_count_kv u32 = 8
-llama_model_loader: - kv 17: qwen3.rope.freq_base f32 = 1000000.000000
-llama_model_loader: - kv 18: qwen3.attention.layer_norm_rms_epsilon f32 = 0.000001
-llama_model_loader: - kv 19: qwen3.attention.key_length u32 = 128
-llama_model_loader: - kv 20: qwen3.attention.value_length u32 = 128
-llama_model_loader: - kv 21: qwen3.pooling_type u32 = 3
-llama_model_loader: - kv 22: tokenizer.ggml.model str = gpt2
-llama_model_loader: - kv 23: tokenizer.ggml.pre str = qwen2
-llama_model_loader: - kv 24: tokenizer.ggml.tokens arr[str,151665] = ["!", "\"", "#", "$", "%", "&", "'", ...
-llama_model_loader: - kv 25: tokenizer.ggml.token_type arr[i32,151665] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
-llama_model_loader: - kv 26: tokenizer.ggml.merges arr[str,151387] = ["Ġ Ġ", "ĠĠ ĠĠ", "i n", "Ġ t",...
-llama_model_loader: - kv 27: tokenizer.ggml.eos_token_id u32 = 151643
-llama_model_loader: - kv 28: tokenizer.ggml.padding_token_id u32 = 151643
-llama_model_loader: - kv 29: tokenizer.ggml.eot_token_id u32 = 151645
-llama_model_loader: - kv 30: tokenizer.ggml.bos_token_id u32 = 151643
-llama_model_loader: - kv 31: tokenizer.ggml.add_eos_token bool = true
-llama_model_loader: - kv 32: tokenizer.ggml.add_bos_token bool = false
-llama_model_loader: - kv 33: tokenizer.chat_template str = {%- if tools %}\n {{- '<|im_start|>...
-llama_model_loader: - kv 34: general.quantization_version u32 = 2
-llama_model_loader: - kv 35: general.file_type u32 = 17
-llama_model_loader: - type f32: 145 tensors
-llama_model_loader: - type q5_K: 216 tensors
-llama_model_loader: - type q6_K: 37 tensors
-print_info: file format = GGUF V3 (latest)
-print_info: file type = Q5_K - Medium
-print_info: file size = 2.68 GiB (5.73 BPW)
-load: printing all EOG tokens:
-load: - 151643 ('<|endoftext|>')
-load: - 151645 ('<|im_end|>')
-load: - 151662 ('<|fim_pad|>')
-load: - 151663 ('<|repo_name|>')
-load: - 151664 ('<|file_sep|>')
-load: special tokens cache size = 22
-load: token to piece cache size = 0.9310 MB
-print_info: arch = qwen3
-print_info: vocab_only = 0
-print_info: n_ctx_train = 40960
-print_info: n_embd = 2560
-print_info: n_layer = 36
-print_info: n_head = 32
-print_info: n_head_kv = 8
-print_info: n_rot = 128
-print_info: n_swa = 0
-print_info: is_swa_any = 0
-print_info: n_embd_head_k = 128
-print_info: n_embd_head_v = 128
-print_info: n_gqa = 4
-print_info: n_embd_k_gqa = 1024
-print_info: n_embd_v_gqa = 1024
-print_info: f_norm_eps = 0.0e+00
-print_info: f_norm_rms_eps = 1.0e-06
-print_info: f_clamp_kqv = 0.0e+00
-print_info: f_max_alibi_bias = 0.0e+00
-print_info: f_logit_scale = 0.0e+00
-print_info: f_attn_scale = 0.0e+00
-print_info: n_ff = 9728
-print_info: n_expert = 0
-print_info: n_expert_used = 0
-print_info: causal attn = 1
-print_info: pooling type = 3
-print_info: rope type = 2
-print_info: rope scaling = linear
-print_info: freq_base_train = 1000000.0
-print_info: freq_scale_train = 1
-print_info: n_ctx_orig_yarn = 40960
-print_info: rope_finetuned = unknown
-print_info: model type = 4B
-print_info: model params = 4.02 B
-print_info: general.name = Qwen3 Embedding 4B
-print_info: vocab type = BPE
-print_info: n_vocab = 151665
-print_info: n_merges = 151387
-print_info: BOS token = 151643 '<|endoftext|>'
-print_info: EOS token = 151643 '<|endoftext|>'
-print_info: EOT token = 151645 '<|im_end|>'
-print_info: PAD token = 151643 '<|endoftext|>'
-print_info: LF token = 198 'Ċ'
-print_info: FIM PRE token = 151659 '<|fim_prefix|>'
-print_info: FIM SUF token = 151661 '<|fim_suffix|>'
-print_info: FIM MID token = 151660 '<|fim_middle|>'
-print_info: FIM PAD token = 151662 '<|fim_pad|>'
-print_info: FIM REP token = 151663 '<|repo_name|>'
-print_info: FIM SEP token = 151664 '<|file_sep|>'
-print_info: EOG token = 151643 '<|endoftext|>'
-print_info: EOG token = 151645 '<|im_end|>'
-print_info: EOG token = 151662 '<|fim_pad|>'
-print_info: EOG token = 151663 '<|repo_name|>'
-print_info: EOG token = 151664 '<|file_sep|>'
-print_info: max token length = 256
-load_tensors: loading model tensors, this can take a while... (mmap = true)
-load_tensors: offloading 36 repeating layers to GPU
-load_tensors: offloaded 36/37 layers to GPU
-load_tensors: CUDA0 model buffer size = 2445.68 MiB
-load_tensors: CPU_Mapped model buffer size = 303.75 MiB
-..........................................................................................
-llama_context: constructing llama_context
-llama_context: n_seq_max = 1
-llama_context: n_ctx = 4096
-llama_context: n_ctx_per_seq = 4096
-llama_context: n_batch = 2048
-llama_context: n_ubatch = 512
-llama_context: causal_attn = 1
-llama_context: flash_attn = 0
-llama_context: kv_unified = false
-llama_context: freq_base = 1000000.0
-llama_context: freq_scale = 1
-llama_context: n_ctx_per_seq (4096) < n_ctx_train (40960) -- the full capacity of the model will not be utilized
-llama_context: CPU output buffer size = 0.59 MiB
-llama_kv_cache_unified: CUDA0 KV buffer size = 576.00 MiB
-llama_kv_cache_unified: size = 576.00 MiB ( 4096 cells, 36 layers, 1/1 seqs), K (f16): 288.00 MiB, V (f16): 288.00 MiB
-llama_context: CUDA0 compute buffer size = 604.96 MiB
-llama_context: CUDA_Host compute buffer size = 17.01 MiB
-llama_context: graph nodes = 1411
-llama_context: graph splits = 4 (with bs=512), 3 (with bs=1)
-common_init_from_params: added <|endoftext|> logit bias = -inf
-common_init_from_params: added <|im_end|> logit bias = -inf
-common_init_from_params: added <|fim_pad|> logit bias = -inf
-common_init_from_params: added <|repo_name|> logit bias = -inf
-common_init_from_params: added <|file_sep|> logit bias = -inf
-common_init_from_params: setting dry_penalty_last_n to ctx_size = 4096
-common_init_from_params: warming up the model with an empty run - please wait ... (--no-warmup to disable)
-srv init: initializing slots, n_slots = 1
-slot init: id 0 | task -1 | new slot n_ctx_slot = 4096
-main: model loaded
-main: chat template, chat_template: {%- if tools %}
- {{- '<|im_start|>system\n' }}
- {%- if messages[0]['role'] == 'system' %}
- {{- messages[0]['content'] }}
- {%- else %}
- {{- 'You are a helpful assistant.' }}
- {%- endif %}
- {{- "\n\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within XML tags:\n" }}
- {%- for tool in tools %}
- {{- "\n" }}
- {{- tool | tojson }}
- {%- endfor %}
- {{- "\n\n\nFor each function call, return a json object with function name and arguments within XML tags:\n\n{\"name\": , \"arguments\": }\n<|im_end|>\n" }}
-{%- else %}
- {%- if messages[0]['role'] == 'system' %}
- {{- '<|im_start|>system\n' + messages[0]['content'] + '<|im_end|>\n' }}
- {%- else %}
- {{- '<|im_start|>system\nYou are a helpful assistant.<|im_end|>\n' }}
- {%- endif %}
-{%- endif %}
-{%- for message in messages %}
- {%- if (message.role == "user") or (message.role == "system" and not loop.first) or (message.role == "assistant" and not message.tool_calls) %}
- {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }}
- {%- elif message.role == "assistant" %}
- {{- '<|im_start|>' + message.role }}
- {%- if message.content %}
- {{- '\n' + message.content }}
- {%- endif %}
- {%- for tool_call in message.tool_calls %}
- {%- if tool_call.function is defined %}
- {%- set tool_call = tool_call.function %}
- {%- endif %}
- {{- '\n\n{"name": "' }}
- {{- tool_call.name }}
- {{- '", "arguments": ' }}
- {{- tool_call.arguments | tojson }}
- {{- '}\n' }}
- {%- endfor %}
- {{- '<|im_end|>\n' }}
- {%- elif message.role == "tool" %}
- {%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != "tool") %}
- {{- '<|im_start|>user' }}
- {%- endif %}
- {{- '\n\n' }}
- {{- message.content }}
- {{- '\n' }}
- {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
- {{- '<|im_end|>\n' }}
- {%- endif %}
- {%- endif %}
-{%- endfor %}
-{%- if add_generation_prompt %}
- {{- '<|im_start|>assistant\n' }}
-{%- endif %}
-, example_format: '<|im_start|>system
-You are a helpful assistant<|im_end|>
-<|im_start|>user
-Hello<|im_end|>
-<|im_start|>assistant
-Hi there<|im_end|>
-<|im_start|>user
-How are you?<|im_end|>
-<|im_start|>assistant
-'
-main: server is listening on http://0.0.0.0:8090 - starting the main loop
-srv update_slots: all slots are idle
-srv log_server_r: request: GET /health 127.0.0.1 200
-slot launch_slot_: id 0 | task 1 | processing task
-slot update_slots: id 0 | task 1 | new prompt, n_ctx_slot = 4096, n_keep = 0, n_prompt_tokens = 9
-slot update_slots: id 0 | task 1 | kv cache rm [0, end)
-slot update_slots: id 0 | task 1 | prompt processing progress, n_past = 9, n_tokens = 9, progress = 1.000000
-slot update_slots: id 0 | task 1 | prompt done, n_past = 9, n_tokens = 9
-slot release: id 0 | task 1 | stop processing: n_past = 9, truncated = 0
-slot launch_slot_: id 0 | task 0 | processing task
-slot update_slots: id 0 | task 0 | new prompt, n_ctx_slot = 4096, n_keep = 0, n_prompt_tokens = 9
-slot update_slots: id 0 | task 0 | need to evaluate at least 1 token for each active slot, n_past = 9, n_prompt_tokens = 9
-slot update_slots: id 0 | task 0 | kv cache rm [8, end)
-slot update_slots: id 0 | task 0 | prompt processing progress, n_past = 9, n_tokens = 1, progress = 0.111111
-slot update_slots: id 0 | task 0 | prompt done, n_past = 9, n_tokens = 1
-srv log_server_r: request: POST /v1/embeddings 127.0.0.1 200
-slot release: id 0 | task 0 | stop processing: n_past = 9, truncated = 0
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/embeddings 127.0.0.1 200
-slot launch_slot_: id 0 | task 4 | processing task
-slot update_slots: id 0 | task 4 | new prompt, n_ctx_slot = 4096, n_keep = 0, n_prompt_tokens = 9
-slot update_slots: id 0 | task 4 | need to evaluate at least 1 token for each active slot, n_past = 9, n_prompt_tokens = 9
-slot update_slots: id 0 | task 4 | kv cache rm [8, end)
-slot update_slots: id 0 | task 4 | prompt processing progress, n_past = 9, n_tokens = 1, progress = 0.111111
-slot update_slots: id 0 | task 4 | prompt done, n_past = 9, n_tokens = 1
-slot release: id 0 | task 4 | stop processing: n_past = 9, truncated = 0
-slot launch_slot_: id 0 | task 6 | processing task
-slot update_slots: id 0 | task 6 | new prompt, n_ctx_slot = 4096, n_keep = 0, n_prompt_tokens = 9
-slot update_slots: id 0 | task 6 | need to evaluate at least 1 token for each active slot, n_past = 9, n_prompt_tokens = 9
-slot update_slots: id 0 | task 6 | kv cache rm [8, end)
-slot update_slots: id 0 | task 6 | prompt processing progress, n_past = 9, n_tokens = 1, progress = 0.111111
-slot update_slots: id 0 | task 6 | prompt done, n_past = 9, n_tokens = 1
-srv log_server_r: request: POST /v1/embeddings 127.0.0.1 200
-slot release: id 0 | task 6 | stop processing: n_past = 9, truncated = 0
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/embeddings 127.0.0.1 200
diff --git a/logs/fastapi.log b/logs/fastapi.log
deleted file mode 100644
index 51f081a3..00000000
--- a/logs/fastapi.log
+++ /dev/null
@@ -1,107 +0,0 @@
-2026-02-26 19:00:57,073 - INFO - Anonymized telemetry enabled. See https://docs.trychroma.com/telemetry for more information.
-2026-02-26 19:00:57,211 - INFO - 成功找到节点定义JSON代码块
-2026-02-26 19:00:57,211 - INFO - 成功解析出动作节点: ['approach_target', 'deliver_payload', 'fly_sequence', 'fly_to_waypoint', 'land', 'loiter', 'manual_confirmation', 'move_direction', 'object_detect', 'return_emergency', 'rotate', 'rotate_search', 'search_pattern', 'system_checks', 'take_photos', 'takeoff', 'track_object']
-2026-02-26 19:00:57,211 - INFO - 成功解析出条件节点: ['at_waypoint', 'object_detected']
-INFO: Started server process [26111]
-INFO: Waiting for application startup.
-2026-02-26 19:00:57,217 - INFO - WebSocket event loop configured.
-INFO: Application startup complete.
-INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
-INFO: 127.0.0.1:46065 - "GET /docs HTTP/1.1" 200 OK
-2026-02-26 19:01:05,074 - INFO - ========== [Stage 1] Task Understanding ==========
-2026-02-26 19:01:05,881 - INFO - HTTP Request: POST http://localhost:8081/v1/chat/completions "HTTP/1.1 200 OK"
-2026-02-26 19:01:05,886 - INFO - Task Understanding Results: mode=scene1, state=in_air, intent=generic_mission, risks=[]
-INFO: 127.0.0.1:46071 - "POST /debug_stage HTTP/1.1" 200 OK
-2026-02-26 19:01:23,412 - INFO - ========== [Stage 1] Task Understanding ==========
-2026-02-26 19:01:23,780 - INFO - HTTP Request: POST http://localhost:8081/v1/chat/completions "HTTP/1.1 200 OK"
-2026-02-26 19:01:23,780 - INFO - Task Understanding Results: mode=scene1, state=in_air, intent=generic_mission, risks=[]
-INFO: 127.0.0.1:44329 - "POST /debug_stage HTTP/1.1" 200 OK
-2026-02-26 19:01:36,748 - INFO - ========== [Stage 1] Task Understanding ==========
-2026-02-26 19:01:37,168 - INFO - HTTP Request: POST http://localhost:8081/v1/chat/completions "HTTP/1.1 200 OK"
-2026-02-26 19:01:37,169 - INFO - Task Understanding Results: mode=scene1, state=in_air, intent=generic_mission, risks=[]
-INFO: 127.0.0.1:44483 - "POST /debug_stage HTTP/1.1" 200 OK
-2026-02-26 19:15:34,050 - INFO - ========== [Stage 1] Task Understanding ==========
-2026-02-26 19:15:34,569 - INFO - HTTP Request: POST http://localhost:8081/v1/chat/completions "HTTP/1.1 200 OK"
-2026-02-26 19:15:34,570 - INFO - Task Understanding Results: mode=scene1, state=in_air, intent=generic_mission, risks=[]
-2026-02-26 19:15:34,570 - INFO - ========== [Stage 2] Context Binding ==========
-2026-02-26 19:15:34,799 - INFO - Context Binding Results: Required Actions=['Selector', 'Sequence', 'fly_to_waypoint', 'land', 'move_direction', 'object_detect', 'object_detected', 'rotate_search', 'take_photos', 'takeoff'], RAG Scopes=['location', 'pattern']
-INFO: 127.0.0.1:47143 - "POST /debug_stage HTTP/1.1" 200 OK
-2026-02-26 19:18:26,812 - INFO - ========== [Stage 1] Task Understanding ==========
-2026-02-26 19:18:27,220 - INFO - HTTP Request: POST http://localhost:8081/v1/chat/completions "HTTP/1.1 200 OK"
-2026-02-26 19:18:27,220 - INFO - Task Understanding Results: mode=scene1, state=in_air, intent=generic_mission, risks=[]
-2026-02-26 19:18:27,220 - INFO - ========== [Stage 2] Context Binding ==========
-2026-02-26 19:18:27,276 - INFO - Context Binding Results: Required Actions=['Selector', 'Sequence', 'fly_to_waypoint', 'land', 'move_direction', 'object_detect', 'object_detected', 'rotate_search', 'take_photos', 'takeoff'], RAG Scopes=['location', 'pattern']
-2026-02-26 19:18:27,276 - INFO - ========== [Stage 3] Macro Planning (Round 1) ==========
-2026-02-26 19:18:27,278 - INFO - [Round 1] System Prompt Preview (first 500 chars):
-任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。
-
-你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:
-1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。
-2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。
-
-**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。
-
-输出格式约定:
-```json
-{
- "macro_tree": { ... 纯结构树 ... },
- "parameter_requests": [
- {
- "node": "节点名称",
- "intent": "对该节点意图的简短描述",
- "extracted_entities": {
- "实体key": "实体value"
- }
- }
- ]
-}
-```
-
-## 一、核心节点定义(裁剪后)
-#### 1. 可用节点定义 (必须遵守...
-2026-02-26 19:18:27,278 - INFO - [Round 1] User Prompt:
-飞到广场东边50米
-
----
-参考知识:
-【地点知识】
-{"property": "location", "information": {"name": "广场", "coordinates": {"x": 100, "y": 260, "z": 0}}}
-
-{"property": "location", "information": {"name": "飞行场地", "coordinates": {"x": 0, "y": 0, "z": 0}}}
-
-{"property": "location", "information": {"name": "大楼外围四个点东南天坐标系坐标", "coordinates": {"A": {"x": -24.0, "y": 241.8, "z": 0}, "B": {"x": -108.5, "y": 241.8, "z": 0}, "C": {"x": -108.5, "y": 289.8, "z": 0}, "D": {"x": -24.0, "y": 292.8, "z": 0}}}}
-
-【任务模式】
-无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。
-
-无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。
-
-地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。
----
-2026-02-26 19:18:36,039 - INFO - HTTP Request: POST http://localhost:8081/v1/chat/completions "HTTP/1.1 200 OK"
-2026-02-26 19:18:36,039 - INFO - [Round 1] Output Macro Tree:
-{
- "root": {
- "type": "Sequence",
- "name": "FlyToSquareEast50",
- "children": [
- {
- "type": "action",
- "name": "fly_to_waypoint"
- }
- ]
- }
-}
-2026-02-26 19:18:36,039 - INFO - [Round 1] Output Parameter Requests:
-[
- {
- "node": "fly_to_waypoint",
- "intent": "前往广场东边50米",
- "extracted_entities": {
- "landmark": "广场",
- "direction": "东",
- "distance": 50.0
- }
- }
-]
-INFO: 127.0.0.1:46185 - "POST /debug_stage HTTP/1.1" 200 OK
diff --git a/logs/inference_model.log b/logs/inference_model.log
deleted file mode 100644
index d58187c8..00000000
--- a/logs/inference_model.log
+++ /dev/null
@@ -1,480 +0,0 @@
-ggml_cuda_init: GGML_CUDA_FORCE_MMQ: no
-ggml_cuda_init: GGML_CUDA_FORCE_CUBLAS: no
-ggml_cuda_init: found 1 CUDA devices:
- Device 0: NVIDIA GeForce RTX 4060 Ti, compute capability 8.9, VMM: yes
-build: 6097 (9515c613) with cc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 for x86_64-linux-gnu
-system info: n_threads = 8, n_threads_batch = 8, total_threads = 16
-
-system_info: n_threads = 8 (n_threads_batch = 8) / 16 | CUDA : ARCHS = 500,610,700,750,800,860,890 | USE_GRAPHS = 1 | PEER_MAX_BATCH_SIZE = 128 | CPU : SSE3 = 1 | SSSE3 = 1 | AVX = 1 | AVX_VNNI = 1 | AVX2 = 1 | F16C = 1 | FMA = 1 | BMI2 = 1 | LLAMAFILE = 1 | OPENMP = 1 | REPACK = 1 |
-
-main: binding port with default address family
-main: HTTP server is listening, hostname: 0.0.0.0, port: 8081, http threads: 15
-main: loading model
-srv load_model: loading model '/home/huangfukk/models/gguf/Qwen3/Qwen3-4B/Qwen3-4B-Q5_K_M.gguf'
-llama_model_load_from_file_impl: using device CUDA0 (NVIDIA GeForce RTX 4060 Ti) - 15225 MiB free
-llama_model_loader: loaded meta data with 28 key-value pairs and 398 tensors from /home/huangfukk/models/gguf/Qwen3/Qwen3-4B/Qwen3-4B-Q5_K_M.gguf (version GGUF V3 (latest))
-llama_model_loader: Dumping metadata keys/values. Note: KV overrides do not apply in this output.
-llama_model_loader: - kv 0: general.architecture str = qwen3
-llama_model_loader: - kv 1: general.type str = model
-llama_model_loader: - kv 2: general.name str = Qwen3 4B Instruct
-llama_model_loader: - kv 3: general.finetune str = Instruct
-llama_model_loader: - kv 4: general.basename str = Qwen3
-llama_model_loader: - kv 5: general.size_label str = 4B
-llama_model_loader: - kv 6: qwen3.block_count u32 = 36
-llama_model_loader: - kv 7: qwen3.context_length u32 = 40960
-llama_model_loader: - kv 8: qwen3.embedding_length u32 = 2560
-llama_model_loader: - kv 9: qwen3.feed_forward_length u32 = 9728
-llama_model_loader: - kv 10: qwen3.attention.head_count u32 = 32
-llama_model_loader: - kv 11: qwen3.attention.head_count_kv u32 = 8
-llama_model_loader: - kv 12: qwen3.rope.freq_base f32 = 1000000.000000
-llama_model_loader: - kv 13: qwen3.attention.layer_norm_rms_epsilon f32 = 0.000001
-llama_model_loader: - kv 14: qwen3.attention.key_length u32 = 128
-llama_model_loader: - kv 15: qwen3.attention.value_length u32 = 128
-llama_model_loader: - kv 16: tokenizer.ggml.model str = gpt2
-llama_model_loader: - kv 17: tokenizer.ggml.pre str = qwen2
-llama_model_loader: - kv 18: tokenizer.ggml.tokens arr[str,151936] = ["!", "\"", "#", "$", "%", "&", "'", ...
-llama_model_loader: - kv 19: tokenizer.ggml.token_type arr[i32,151936] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
-llama_model_loader: - kv 20: tokenizer.ggml.merges arr[str,151387] = ["Ġ Ġ", "ĠĠ ĠĠ", "i n", "Ġ t",...
-llama_model_loader: - kv 21: tokenizer.ggml.eos_token_id u32 = 151645
-llama_model_loader: - kv 22: tokenizer.ggml.padding_token_id u32 = 151643
-llama_model_loader: - kv 23: tokenizer.ggml.bos_token_id u32 = 151643
-llama_model_loader: - kv 24: tokenizer.ggml.add_bos_token bool = false
-llama_model_loader: - kv 25: tokenizer.chat_template str = {%- if tools %}\n {{- '<|im_start|>...
-llama_model_loader: - kv 26: general.quantization_version u32 = 2
-llama_model_loader: - kv 27: general.file_type u32 = 17
-llama_model_loader: - type f32: 145 tensors
-llama_model_loader: - type q5_K: 216 tensors
-llama_model_loader: - type q6_K: 37 tensors
-print_info: file format = GGUF V3 (latest)
-print_info: file type = Q5_K - Medium
-print_info: file size = 2.69 GiB (5.73 BPW)
-load: printing all EOG tokens:
-load: - 151643 ('<|endoftext|>')
-load: - 151645 ('<|im_end|>')
-load: - 151662 ('<|fim_pad|>')
-load: - 151663 ('<|repo_name|>')
-load: - 151664 ('<|file_sep|>')
-load: special tokens cache size = 26
-load: token to piece cache size = 0.9311 MB
-print_info: arch = qwen3
-print_info: vocab_only = 0
-print_info: n_ctx_train = 40960
-print_info: n_embd = 2560
-print_info: n_layer = 36
-print_info: n_head = 32
-print_info: n_head_kv = 8
-print_info: n_rot = 128
-print_info: n_swa = 0
-print_info: is_swa_any = 0
-print_info: n_embd_head_k = 128
-print_info: n_embd_head_v = 128
-print_info: n_gqa = 4
-print_info: n_embd_k_gqa = 1024
-print_info: n_embd_v_gqa = 1024
-print_info: f_norm_eps = 0.0e+00
-print_info: f_norm_rms_eps = 1.0e-06
-print_info: f_clamp_kqv = 0.0e+00
-print_info: f_max_alibi_bias = 0.0e+00
-print_info: f_logit_scale = 0.0e+00
-print_info: f_attn_scale = 0.0e+00
-print_info: n_ff = 9728
-print_info: n_expert = 0
-print_info: n_expert_used = 0
-print_info: causal attn = 1
-print_info: pooling type = -1
-print_info: rope type = 2
-print_info: rope scaling = linear
-print_info: freq_base_train = 1000000.0
-print_info: freq_scale_train = 1
-print_info: n_ctx_orig_yarn = 40960
-print_info: rope_finetuned = unknown
-print_info: model type = 4B
-print_info: model params = 4.02 B
-print_info: general.name = Qwen3 4B Instruct
-print_info: vocab type = BPE
-print_info: n_vocab = 151936
-print_info: n_merges = 151387
-print_info: BOS token = 151643 '<|endoftext|>'
-print_info: EOS token = 151645 '<|im_end|>'
-print_info: EOT token = 151645 '<|im_end|>'
-print_info: PAD token = 151643 '<|endoftext|>'
-print_info: LF token = 198 'Ċ'
-print_info: FIM PRE token = 151659 '<|fim_prefix|>'
-print_info: FIM SUF token = 151661 '<|fim_suffix|>'
-print_info: FIM MID token = 151660 '<|fim_middle|>'
-print_info: FIM PAD token = 151662 '<|fim_pad|>'
-print_info: FIM REP token = 151663 '<|repo_name|>'
-print_info: FIM SEP token = 151664 '<|file_sep|>'
-print_info: EOG token = 151643 '<|endoftext|>'
-print_info: EOG token = 151645 '<|im_end|>'
-print_info: EOG token = 151662 '<|fim_pad|>'
-print_info: EOG token = 151663 '<|repo_name|>'
-print_info: EOG token = 151664 '<|file_sep|>'
-print_info: max token length = 256
-load_tensors: loading model tensors, this can take a while... (mmap = true)
-load_tensors: offloading 36 repeating layers to GPU
-load_tensors: offloaded 36/37 layers to GPU
-load_tensors: CUDA0 model buffer size = 2445.68 MiB
-load_tensors: CPU_Mapped model buffer size = 304.29 MiB
-..........................................................................................
-llama_context: constructing llama_context
-llama_context: n_seq_max = 1
-llama_context: n_ctx = 16384
-llama_context: n_ctx_per_seq = 16384
-llama_context: n_batch = 2048
-llama_context: n_ubatch = 512
-llama_context: causal_attn = 1
-llama_context: flash_attn = 0
-llama_context: kv_unified = false
-llama_context: freq_base = 1000000.0
-llama_context: freq_scale = 1
-llama_context: n_ctx_per_seq (16384) < n_ctx_train (40960) -- the full capacity of the model will not be utilized
-llama_context: CPU output buffer size = 0.58 MiB
-llama_kv_cache_unified: CUDA0 KV buffer size = 2304.00 MiB
-llama_kv_cache_unified: size = 2304.00 MiB ( 16384 cells, 36 layers, 1/1 seqs), K (f16): 1152.00 MiB, V (f16): 1152.00 MiB
-llama_context: CUDA0 compute buffer size = 1086.01 MiB
-llama_context: CUDA_Host compute buffer size = 41.01 MiB
-llama_context: graph nodes = 1410
-llama_context: graph splits = 4 (with bs=512), 3 (with bs=1)
-common_init_from_params: added <|endoftext|> logit bias = -inf
-common_init_from_params: added <|im_end|> logit bias = -inf
-common_init_from_params: added <|fim_pad|> logit bias = -inf
-common_init_from_params: added <|repo_name|> logit bias = -inf
-common_init_from_params: added <|file_sep|> logit bias = -inf
-common_init_from_params: setting dry_penalty_last_n to ctx_size = 16384
-common_init_from_params: warming up the model with an empty run - please wait ... (--no-warmup to disable)
-srv init: initializing slots, n_slots = 1
-slot init: id 0 | task -1 | new slot n_ctx_slot = 16384
-main: model loaded
-main: chat template, chat_template: {%- if tools %}
- {{- '<|im_start|>system\n' }}
- {%- if messages[0].role == 'system' %}
- {{- messages[0].content + '\n\n' }}
- {%- endif %}
- {{- "# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within XML tags:\n" }}
- {%- for tool in tools %}
- {{- "\n" }}
- {{- tool | tojson }}
- {%- endfor %}
- {{- "\n\n\nFor each function call, return a json object with function name and arguments within XML tags:\n\n{\"name\": , \"arguments\": }\n<|im_end|>\n" }}
-{%- else %}
- {%- if messages[0].role == 'system' %}
- {{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' }}
- {%- endif %}
-{%- endif %}
-{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
-{%- for index in range(ns.last_query_index, -1, -1) %}
- {%- set message = messages[index] %}
- {%- if ns.multi_step_tool and message.role == "user" and not('' in message.content and '' in message.content) %}
- {%- set ns.multi_step_tool = false %}
- {%- set ns.last_query_index = index %}
- {%- endif %}
-{%- endfor %}
-{%- for message in messages %}
- {%- if (message.role == "user") or (message.role == "system" and not loop.first) %}
- {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }}
- {%- elif message.role == "assistant" %}
- {%- set content = message.content %}
- {%- set reasoning_content = '' %}
- {%- if message.reasoning_content is defined and message.reasoning_content is not none %}
- {%- set reasoning_content = message.reasoning_content %}
- {%- else %}
- {%- if '' in message.content %}
- {%- set content = message.content.split('')[-1].lstrip('\n') %}
- {%- set reasoning_content = message.content.split('')[0].rstrip('\n').split('')[-1].lstrip('\n') %}
- {%- endif %}
- {%- endif %}
- {%- if loop.index0 > ns.last_query_index %}
- {%- if loop.last or (not loop.last and reasoning_content) %}
- {{- '<|im_start|>' + message.role + '\n\n' + reasoning_content.strip('\n') + '\n\n\n' + content.lstrip('\n') }}
- {%- else %}
- {{- '<|im_start|>' + message.role + '\n' + content }}
- {%- endif %}
- {%- else %}
- {{- '<|im_start|>' + message.role + '\n' + content }}
- {%- endif %}
- {%- if message.tool_calls %}
- {%- for tool_call in message.tool_calls %}
- {%- if (loop.first and content) or (not loop.first) %}
- {{- '\n' }}
- {%- endif %}
- {%- if tool_call.function %}
- {%- set tool_call = tool_call.function %}
- {%- endif %}
- {{- '\n{"name": "' }}
- {{- tool_call.name }}
- {{- '", "arguments": ' }}
- {%- if tool_call.arguments is string %}
- {{- tool_call.arguments }}
- {%- else %}
- {{- tool_call.arguments | tojson }}
- {%- endif %}
- {{- '}\n' }}
- {%- endfor %}
- {%- endif %}
- {{- '<|im_end|>\n' }}
- {%- elif message.role == "tool" %}
- {%- if loop.first or (messages[loop.index0 - 1].role != "tool") %}
- {{- '<|im_start|>user' }}
- {%- endif %}
- {{- '\n\n' }}
- {{- message.content }}
- {{- '\n' }}
- {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
- {{- '<|im_end|>\n' }}
- {%- endif %}
- {%- endif %}
-{%- endfor %}
-{%- if add_generation_prompt %}
- {{- '<|im_start|>assistant\n' }}
- {%- if enable_thinking is defined and enable_thinking is false %}
- {{- '\n\n\n\n' }}
- {%- endif %}
-{%- endif %}, example_format: '<|im_start|>system
-You are a helpful assistant<|im_end|>
-<|im_start|>user
-Hello<|im_end|>
-<|im_start|>assistant
-Hi there<|im_end|>
-<|im_start|>user
-How are you?<|im_end|>
-<|im_start|>assistant
-'
-main: server is listening on http://0.0.0.0:8081 - starting the main loop
-srv update_slots: all slots are idle
-srv log_server_r: request: GET /health 127.0.0.1 200
-srv params_from_: Chat format: Content-only
-slot launch_slot_: id 0 | task 0 | processing task
-slot update_slots: id 0 | task 0 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 423
-slot update_slots: id 0 | task 0 | kv cache rm [0, end)
-slot update_slots: id 0 | task 0 | prompt processing progress, n_past = 423, n_tokens = 423, progress = 1.000000
-slot update_slots: id 0 | task 0 | prompt done, n_past = 423, n_tokens = 423
-slot release: id 0 | task 0 | stop processing: n_past = 429, truncated = 0
-slot print_timing: id 0 | task 0 |
-prompt eval time = 534.22 ms / 423 tokens ( 1.26 ms per token, 791.81 tokens per second)
- eval time = 155.33 ms / 7 tokens ( 22.19 ms per token, 45.07 tokens per second)
- total time = 689.55 ms / 430 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Content-only
-slot launch_slot_: id 0 | task 8 | processing task
-slot update_slots: id 0 | task 8 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 423
-slot update_slots: id 0 | task 8 | kv cache rm [409, end)
-slot update_slots: id 0 | task 8 | prompt processing progress, n_past = 423, n_tokens = 14, progress = 0.033097
-slot update_slots: id 0 | task 8 | prompt done, n_past = 423, n_tokens = 14
-slot release: id 0 | task 8 | stop processing: n_past = 429, truncated = 0
-slot print_timing: id 0 | task 8 |
-prompt eval time = 214.36 ms / 14 tokens ( 15.31 ms per token, 65.31 tokens per second)
- eval time = 146.82 ms / 7 tokens ( 20.97 ms per token, 47.68 tokens per second)
- total time = 361.19 ms / 21 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Content-only
-slot launch_slot_: id 0 | task 16 | processing task
-slot update_slots: id 0 | task 16 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 423
-slot update_slots: id 0 | task 16 | kv cache rm [408, end)
-slot update_slots: id 0 | task 16 | prompt processing progress, n_past = 423, n_tokens = 15, progress = 0.035461
-slot update_slots: id 0 | task 16 | prompt done, n_past = 423, n_tokens = 15
-slot release: id 0 | task 16 | stop processing: n_past = 429, truncated = 0
-slot print_timing: id 0 | task 16 |
-prompt eval time = 270.02 ms / 15 tokens ( 18.00 ms per token, 55.55 tokens per second)
- eval time = 144.12 ms / 7 tokens ( 20.59 ms per token, 48.57 tokens per second)
- total time = 414.14 ms / 22 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Hermes 2 Pro
-slot launch_slot_: id 0 | task 24 | processing task
-slot update_slots: id 0 | task 24 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 422
-slot update_slots: id 0 | task 24 | kv cache rm [400, end)
-slot update_slots: id 0 | task 24 | prompt processing progress, n_past = 422, n_tokens = 22, progress = 0.052133
-slot update_slots: id 0 | task 24 | prompt done, n_past = 422, n_tokens = 22
-slot release: id 0 | task 24 | stop processing: n_past = 596, truncated = 0
-slot print_timing: id 0 | task 24 |
-prompt eval time = 399.30 ms / 22 tokens ( 18.15 ms per token, 55.10 tokens per second)
- eval time = 3861.49 ms / 175 tokens ( 22.07 ms per token, 45.32 tokens per second)
- total time = 4260.79 ms / 197 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Hermes 2 Pro
-slot launch_slot_: id 0 | task 200 | processing task
-slot update_slots: id 0 | task 200 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 426
-slot update_slots: id 0 | task 200 | kv cache rm [417, end)
-slot update_slots: id 0 | task 200 | prompt processing progress, n_past = 426, n_tokens = 9, progress = 0.021127
-slot update_slots: id 0 | task 200 | prompt done, n_past = 426, n_tokens = 9
-slot release: id 0 | task 200 | stop processing: n_past = 436, truncated = 0
-slot print_timing: id 0 | task 200 |
-prompt eval time = 253.59 ms / 9 tokens ( 28.18 ms per token, 35.49 tokens per second)
- eval time = 234.29 ms / 11 tokens ( 21.30 ms per token, 46.95 tokens per second)
- total time = 487.87 ms / 20 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Hermes 2 Pro
-slot launch_slot_: id 0 | task 212 | processing task
-slot update_slots: id 0 | task 212 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 426
-slot update_slots: id 0 | task 212 | need to evaluate at least 1 token for each active slot, n_past = 426, n_prompt_tokens = 426
-slot update_slots: id 0 | task 212 | kv cache rm [425, end)
-slot update_slots: id 0 | task 212 | prompt processing progress, n_past = 426, n_tokens = 1, progress = 0.002347
-slot update_slots: id 0 | task 212 | prompt done, n_past = 426, n_tokens = 1
-slot release: id 0 | task 212 | stop processing: n_past = 436, truncated = 0
-slot print_timing: id 0 | task 212 |
-prompt eval time = 24.00 ms / 1 tokens ( 24.00 ms per token, 41.67 tokens per second)
- eval time = 234.10 ms / 11 tokens ( 21.28 ms per token, 46.99 tokens per second)
- total time = 258.10 ms / 12 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Hermes 2 Pro
-slot launch_slot_: id 0 | task 224 | processing task
-slot update_slots: id 0 | task 224 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 426
-slot update_slots: id 0 | task 224 | need to evaluate at least 1 token for each active slot, n_past = 426, n_prompt_tokens = 426
-slot update_slots: id 0 | task 224 | kv cache rm [425, end)
-slot update_slots: id 0 | task 224 | prompt processing progress, n_past = 426, n_tokens = 1, progress = 0.002347
-slot update_slots: id 0 | task 224 | prompt done, n_past = 426, n_tokens = 1
-slot release: id 0 | task 224 | stop processing: n_past = 436, truncated = 0
-slot print_timing: id 0 | task 224 |
-prompt eval time = 42.68 ms / 1 tokens ( 42.68 ms per token, 23.43 tokens per second)
- eval time = 369.06 ms / 11 tokens ( 33.55 ms per token, 29.81 tokens per second)
- total time = 411.74 ms / 12 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Hermes 2 Pro
-slot launch_slot_: id 0 | task 236 | processing task
-slot update_slots: id 0 | task 236 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 426
-slot update_slots: id 0 | task 236 | need to evaluate at least 1 token for each active slot, n_past = 426, n_prompt_tokens = 426
-slot update_slots: id 0 | task 236 | kv cache rm [425, end)
-slot update_slots: id 0 | task 236 | prompt processing progress, n_past = 426, n_tokens = 1, progress = 0.002347
-slot update_slots: id 0 | task 236 | prompt done, n_past = 426, n_tokens = 1
-slot release: id 0 | task 236 | stop processing: n_past = 436, truncated = 0
-slot print_timing: id 0 | task 236 |
-prompt eval time = 35.69 ms / 1 tokens ( 35.69 ms per token, 28.02 tokens per second)
- eval time = 272.33 ms / 11 tokens ( 24.76 ms per token, 40.39 tokens per second)
- total time = 308.02 ms / 12 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Hermes 2 Pro
-slot launch_slot_: id 0 | task 248 | processing task
-slot update_slots: id 0 | task 248 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 426
-slot update_slots: id 0 | task 248 | need to evaluate at least 1 token for each active slot, n_past = 426, n_prompt_tokens = 426
-slot update_slots: id 0 | task 248 | kv cache rm [425, end)
-slot update_slots: id 0 | task 248 | prompt processing progress, n_past = 426, n_tokens = 1, progress = 0.002347
-slot update_slots: id 0 | task 248 | prompt done, n_past = 426, n_tokens = 1
-slot release: id 0 | task 248 | stop processing: n_past = 436, truncated = 0
-slot print_timing: id 0 | task 248 |
-prompt eval time = 333.94 ms / 1 tokens ( 333.94 ms per token, 2.99 tokens per second)
- eval time = 222.91 ms / 11 tokens ( 20.26 ms per token, 49.35 tokens per second)
- total time = 556.85 ms / 12 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Hermes 2 Pro
-slot launch_slot_: id 0 | task 260 | processing task
-slot update_slots: id 0 | task 260 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 426
-slot update_slots: id 0 | task 260 | need to evaluate at least 1 token for each active slot, n_past = 426, n_prompt_tokens = 426
-slot update_slots: id 0 | task 260 | kv cache rm [425, end)
-slot update_slots: id 0 | task 260 | prompt processing progress, n_past = 426, n_tokens = 1, progress = 0.002347
-slot update_slots: id 0 | task 260 | prompt done, n_past = 426, n_tokens = 1
-slot release: id 0 | task 260 | stop processing: n_past = 436, truncated = 0
-slot print_timing: id 0 | task 260 |
-prompt eval time = 24.23 ms / 1 tokens ( 24.23 ms per token, 41.27 tokens per second)
- eval time = 232.33 ms / 11 tokens ( 21.12 ms per token, 47.35 tokens per second)
- total time = 256.56 ms / 12 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Hermes 2 Pro
-slot launch_slot_: id 0 | task 272 | processing task
-slot update_slots: id 0 | task 272 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 426
-slot update_slots: id 0 | task 272 | need to evaluate at least 1 token for each active slot, n_past = 426, n_prompt_tokens = 426
-slot update_slots: id 0 | task 272 | kv cache rm [425, end)
-slot update_slots: id 0 | task 272 | prompt processing progress, n_past = 426, n_tokens = 1, progress = 0.002347
-slot update_slots: id 0 | task 272 | prompt done, n_past = 426, n_tokens = 1
-slot release: id 0 | task 272 | stop processing: n_past = 436, truncated = 0
-slot print_timing: id 0 | task 272 |
-prompt eval time = 32.14 ms / 1 tokens ( 32.14 ms per token, 31.11 tokens per second)
- eval time = 225.34 ms / 11 tokens ( 20.49 ms per token, 48.82 tokens per second)
- total time = 257.48 ms / 12 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Hermes 2 Pro
-slot launch_slot_: id 0 | task 284 | processing task
-slot update_slots: id 0 | task 284 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 180
-slot update_slots: id 0 | task 284 | kv cache rm [4, end)
-slot update_slots: id 0 | task 284 | prompt processing progress, n_past = 180, n_tokens = 176, progress = 0.977778
-slot update_slots: id 0 | task 284 | prompt done, n_past = 180, n_tokens = 176
-slot release: id 0 | task 284 | stop processing: n_past = 189, truncated = 0
-slot print_timing: id 0 | task 284 |
-prompt eval time = 62.74 ms / 176 tokens ( 0.36 ms per token, 2805.14 tokens per second)
- eval time = 217.64 ms / 10 tokens ( 21.76 ms per token, 45.95 tokens per second)
- total time = 280.39 ms / 186 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Hermes 2 Pro
-slot launch_slot_: id 0 | task 295 | processing task
-slot update_slots: id 0 | task 295 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 180
-slot update_slots: id 0 | task 295 | need to evaluate at least 1 token for each active slot, n_past = 180, n_prompt_tokens = 180
-slot update_slots: id 0 | task 295 | kv cache rm [179, end)
-slot update_slots: id 0 | task 295 | prompt processing progress, n_past = 180, n_tokens = 1, progress = 0.005556
-slot update_slots: id 0 | task 295 | prompt done, n_past = 180, n_tokens = 1
-slot release: id 0 | task 295 | stop processing: n_past = 189, truncated = 0
-slot print_timing: id 0 | task 295 |
-prompt eval time = 24.62 ms / 1 tokens ( 24.62 ms per token, 40.62 tokens per second)
- eval time = 215.17 ms / 10 tokens ( 21.52 ms per token, 46.47 tokens per second)
- total time = 239.79 ms / 11 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Hermes 2 Pro
-slot launch_slot_: id 0 | task 306 | processing task
-slot update_slots: id 0 | task 306 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 180
-slot update_slots: id 0 | task 306 | kv cache rm [164, end)
-slot update_slots: id 0 | task 306 | prompt processing progress, n_past = 180, n_tokens = 16, progress = 0.088889
-slot update_slots: id 0 | task 306 | prompt done, n_past = 180, n_tokens = 16
-slot release: id 0 | task 306 | stop processing: n_past = 189, truncated = 0
-slot print_timing: id 0 | task 306 |
-prompt eval time = 44.44 ms / 16 tokens ( 2.78 ms per token, 360.08 tokens per second)
- eval time = 210.16 ms / 10 tokens ( 21.02 ms per token, 47.58 tokens per second)
- total time = 254.60 ms / 26 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Content-only
-slot launch_slot_: id 0 | task 317 | processing task
-slot update_slots: id 0 | task 317 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 423
-slot update_slots: id 0 | task 317 | kv cache rm [4, end)
-slot update_slots: id 0 | task 317 | prompt processing progress, n_past = 423, n_tokens = 419, progress = 0.990544
-slot update_slots: id 0 | task 317 | prompt done, n_past = 423, n_tokens = 419
-slot release: id 0 | task 317 | stop processing: n_past = 429, truncated = 0
-slot print_timing: id 0 | task 317 |
-prompt eval time = 316.01 ms / 419 tokens ( 0.75 ms per token, 1325.92 tokens per second)
- eval time = 141.87 ms / 7 tokens ( 20.27 ms per token, 49.34 tokens per second)
- total time = 457.88 ms / 426 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Content-only
-slot launch_slot_: id 0 | task 325 | processing task
-slot update_slots: id 0 | task 325 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 423
-slot update_slots: id 0 | task 325 | need to evaluate at least 1 token for each active slot, n_past = 423, n_prompt_tokens = 423
-slot update_slots: id 0 | task 325 | kv cache rm [422, end)
-slot update_slots: id 0 | task 325 | prompt processing progress, n_past = 423, n_tokens = 1, progress = 0.002364
-slot update_slots: id 0 | task 325 | prompt done, n_past = 423, n_tokens = 1
-slot release: id 0 | task 325 | stop processing: n_past = 429, truncated = 0
-slot print_timing: id 0 | task 325 |
-prompt eval time = 256.66 ms / 1 tokens ( 256.66 ms per token, 3.90 tokens per second)
- eval time = 143.27 ms / 7 tokens ( 20.47 ms per token, 48.86 tokens per second)
- total time = 399.92 ms / 8 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
-srv params_from_: Chat format: Content-only
-slot launch_slot_: id 0 | task 333 | processing task
-slot update_slots: id 0 | task 333 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 7547
-slot update_slots: id 0 | task 333 | kv cache rm [3, end)
-slot update_slots: id 0 | task 333 | prompt processing progress, n_past = 2051, n_tokens = 2048, progress = 0.271366
-slot update_slots: id 0 | task 333 | kv cache rm [2051, end)
-slot update_slots: id 0 | task 333 | prompt processing progress, n_past = 4099, n_tokens = 2048, progress = 0.542732
-slot update_slots: id 0 | task 333 | kv cache rm [4099, end)
-slot update_slots: id 0 | task 333 | prompt processing progress, n_past = 6147, n_tokens = 2048, progress = 0.814098
-slot update_slots: id 0 | task 333 | kv cache rm [6147, end)
-slot update_slots: id 0 | task 333 | prompt processing progress, n_past = 7547, n_tokens = 1400, progress = 0.999602
-slot update_slots: id 0 | task 333 | prompt done, n_past = 7547, n_tokens = 1400
-slot release: id 0 | task 333 | stop processing: n_past = 7680, truncated = 0
-slot print_timing: id 0 | task 333 |
-prompt eval time = 4829.54 ms / 7544 tokens ( 0.64 ms per token, 1562.05 tokens per second)
- eval time = 3913.28 ms / 134 tokens ( 29.20 ms per token, 34.24 tokens per second)
- total time = 8742.83 ms / 7678 tokens
-srv update_slots: all slots are idle
-srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200
diff --git a/logs/services.pid b/logs/services.pid
deleted file mode 100644
index 278f77c7..00000000
--- a/logs/services.pid
+++ /dev/null
@@ -1,3 +0,0 @@
-26023
-26024
-26109
diff --git a/logs/services_vllm.pid b/logs/services_vllm.pid
deleted file mode 100644
index 0a3fd610..00000000
--- a/logs/services_vllm.pid
+++ /dev/null
@@ -1,2 +0,0 @@
-43538
-43539
diff --git a/logs/vllm_inference_model.log b/logs/vllm_inference_model.log
deleted file mode 100644
index fe3a57c3..00000000
--- a/logs/vllm_inference_model.log
+++ /dev/null
@@ -1,150 +0,0 @@
-[DEBUG] conda_env=VLLM
-[DEBUG] CONDA_PREFIX=/home/huangfukk/miniconda3/envs/VLLM
-[DEBUG] which python: /home/huangfukk/miniconda3/envs/VLLM/bin/python
-[DEBUG] which vllm: /home/huangfukk/miniconda3/envs/VLLM/bin/vllm
-0.13.0
-[DEBUG] python: 3.12.12 | packaged by Anaconda, Inc. | (main, Oct 21 2025, 20:16:04) [GCC 11.2.0]
-[DEBUG] torch: 2.9.0+cu128 cuda: 12.8 available: True
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:05 [api_server.py:1351] vLLM API server version 0.13.0
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:05 [utils.py:253] non-default args: {'model_tag': '/home/huangfukk/models/AWQ/Qwen3-4B-Instruct-2507', 'host': '0.0.0.0', 'port': 8081, 'uvicorn_log_level': 'debug', 'chat_template': '/home/huangfukk/DronePlanning/tools/vllm_templates/qwen3_xml_tool.jinja', 'chat_template_content_format': 'string', 'enable_auto_tool_choice': True, 'tool_call_parser': 'qwen3_xml', 'model': '/home/huangfukk/models/AWQ/Qwen3-4B-Instruct-2507', 'trust_remote_code': True, 'max_model_len': 16384, 'served_model_name': ['local-model'], 'max_parallel_loading_workers': 4, 'gpu_memory_utilization': 0.5, 'max_num_seqs': 1}
-[0;36m(APIServer pid=43538)[0;0m The argument `trust_remote_code` is to be used with Auto classes. It has no effect here and is ignored.
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:05 [model.py:514] Resolved architecture: Qwen3ForCausalLM
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:05 [model.py:1661] Using max model len 16384
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:05 [awq_marlin.py:162] The model is convertible to awq_marlin during runtime. Using awq_marlin kernel.
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:05 [parallel.py:595] max_parallel_loading_workers is currently not supported and will be ignored.
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:05 [scheduler.py:230] Chunked prefill is enabled with max_num_batched_tokens=2048.
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:06 [interface.py:465] Using 'pin_memory=False' as WSL is detected. This may slow down the performance.
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:10 [core.py:93] Initializing a V1 LLM engine (v0.13.0) with config: model='/home/huangfukk/models/AWQ/Qwen3-4B-Instruct-2507', speculative_config=None, tokenizer='/home/huangfukk/models/AWQ/Qwen3-4B-Instruct-2507', skip_tokenizer_init=False, tokenizer_mode=auto, revision=None, tokenizer_revision=None, trust_remote_code=True, dtype=torch.bfloat16, max_seq_len=16384, download_dir=None, load_format=auto, tensor_parallel_size=1, pipeline_parallel_size=1, data_parallel_size=1, disable_custom_all_reduce=False, quantization=awq_marlin, enforce_eager=False, kv_cache_dtype=auto, device_config=cuda, structured_outputs_config=StructuredOutputsConfig(backend='auto', disable_fallback=False, disable_any_whitespace=False, disable_additional_properties=False, reasoning_parser='', reasoning_parser_plugin='', enable_in_reasoning=False), observability_config=ObservabilityConfig(show_hidden_metrics_for_version=None, otlp_traces_endpoint=None, collect_detailed_traces=None, kv_cache_metrics=False, kv_cache_metrics_sample=0.01, cudagraph_metrics=False, enable_layerwise_nvtx_tracing=False), seed=0, served_model_name=local-model, enable_prefix_caching=True, enable_chunked_prefill=True, pooler_config=None, compilation_config={'level': None, 'mode': , 'debug_dump_path': None, 'cache_dir': '', 'compile_cache_save_format': 'binary', 'backend': 'inductor', 'custom_ops': ['none'], 'splitting_ops': ['vllm::unified_attention', 'vllm::unified_attention_with_output', 'vllm::unified_mla_attention', 'vllm::unified_mla_attention_with_output', 'vllm::mamba_mixer2', 'vllm::mamba_mixer', 'vllm::short_conv', 'vllm::linear_attention', 'vllm::plamo2_mamba_mixer', 'vllm::gdn_attention_core', 'vllm::kda_attention', 'vllm::sparse_attn_indexer'], 'compile_mm_encoder': False, 'compile_sizes': [], 'compile_ranges_split_points': [2048], 'inductor_compile_config': {'enable_auto_functionalized_v2': False, 'combo_kernels': True, 'benchmark_combo_kernel': True}, 'inductor_passes': {}, 'cudagraph_mode': , 'cudagraph_num_of_warmups': 1, 'cudagraph_capture_sizes': [1, 2], 'cudagraph_copy_inputs': False, 'cudagraph_specialize_lora': True, 'use_inductor_graph_partition': False, 'pass_config': {'fuse_norm_quant': False, 'fuse_act_quant': False, 'fuse_attn_quant': False, 'eliminate_noops': True, 'enable_sp': False, 'fuse_gemm_comms': False, 'fuse_allreduce_rms': False}, 'max_cudagraph_capture_size': 2, 'dynamic_shapes_config': {'type': , 'evaluate_guards': False}, 'local_cache_dir': None}
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:11 [parallel_state.py:1203] world_size=1 rank=0 local_rank=0 distributed_init_method=tcp://192.168.31.62:43504 backend=nccl
-[W120 16:25:21.543804205 socket.cpp:209] [c10d] The hostname of the client socket cannot be retrieved. err=-3
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:21 [parallel_state.py:1411] rank 0 in world size 1 is assigned as DP rank 0, PP rank 0, PCP rank 0, TP rank 0, EP rank 0
-[0;36m(EngineCore_DP0 pid=43785)[0;0m WARNING 01-20 16:25:21 [interface.py:465] Using 'pin_memory=False' as WSL is detected. This may slow down the performance.
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:22 [gpu_model_runner.py:3562] Starting to load model /home/huangfukk/models/AWQ/Qwen3-4B-Instruct-2507...
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:22 [cuda.py:351] Using FLASH_ATTN attention backend out of potential backends: ('FLASH_ATTN', 'FLASHINFER', 'TRITON_ATTN', 'FLEX_ATTENTION')
-[0;36m(EngineCore_DP0 pid=43785)[0;0m
Loading safetensors checkpoint shards: 0% Completed | 0/1 [00:00, ?it/s]
-[0;36m(EngineCore_DP0 pid=43785)[0;0m
Loading safetensors checkpoint shards: 100% Completed | 1/1 [00:03<00:00, 3.71s/it]
-[0;36m(EngineCore_DP0 pid=43785)[0;0m
Loading safetensors checkpoint shards: 100% Completed | 1/1 [00:03<00:00, 3.71s/it]
-[0;36m(EngineCore_DP0 pid=43785)[0;0m
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:26 [default_loader.py:308] Loading weights took 2.68 seconds
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:27 [gpu_model_runner.py:3659] Model loading took 2.5630 GiB memory and 3.642749 seconds
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:34 [backends.py:643] Using cache directory: /home/huangfukk/.cache/vllm/torch_compile_cache/d651665fcd/rank_0_0/backbone for vLLM's torch.compile
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:34 [backends.py:703] Dynamo bytecode transform time: 7.23 s
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:39 [backends.py:226] Directly load the compiled graph(s) for compile range (1, 2048) from the cache, took 1.264 s
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:39 [monitor.py:34] torch.compile takes 8.49 s in total
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:40 [gpu_worker.py:375] Available KV cache memory: 5.26 GiB
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:40 [kv_cache_utils.py:1291] GPU KV cache size: 38,288 tokens
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:40 [kv_cache_utils.py:1296] Maximum concurrency for 16,384 tokens per request: 2.34x
-[0;36m(EngineCore_DP0 pid=43785)[0;0m
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE): 0%| | 0/2 [00:00, ?it/s]
Capturing CUDA graphs (mixed prefill-decode, PIECEWISE): 100%|██████████| 2/2 [00:00<00:00, 21.01it/s]
-[0;36m(EngineCore_DP0 pid=43785)[0;0m
Capturing CUDA graphs (decode, FULL): 0%| | 0/1 [00:00, ?it/s]
Capturing CUDA graphs (decode, FULL): 100%|██████████| 1/1 [00:00<00:00, 12.71it/s]
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:40 [gpu_model_runner.py:4587] Graph capturing finished in 1 secs, took 0.02 GiB
-[0;36m(EngineCore_DP0 pid=43785)[0;0m INFO 01-20 16:25:40 [core.py:259] init engine (profile, create kv cache, warmup model) took 13.61 seconds
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:41 [api_server.py:1099] Supported tasks: ['generate']
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] Using supplied chat template: {%- if tools %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] <|im_start|>system
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- if messages[0].role == 'system' -%}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {{ messages[0].content }}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- else -%}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] You are a helpful assistant.
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- endif -%}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312]
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] # Tools
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] You may call one or more functions to assist with the user query.
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] The function signatures are provided below:
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312]
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- for tool in tools %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {{ tool | tojson }}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- endfor %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312]
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312]
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] When you need to call a tool, respond with XML tags in this exact format:
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312]
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312]
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] value1
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] value2
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312]
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312]
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] <|im_end|>
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- else %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- if messages[0].role == 'system' -%}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] <|im_start|>system
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {{ messages[0].content }}<|im_end|>
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- endif -%}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- endif %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312]
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- for message in messages %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- if (message.role == "user") or (message.role == "system" and not loop.first) %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] <|im_start|>{{ message.role }}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {{ message.content }}<|im_end|>
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- elif message.role == "assistant" %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] <|im_start|>assistant
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- if message.content %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {{ message.content }}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- endif %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] <|im_end|>
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- elif message.role == "tool" %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] <|im_start|>user
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312]
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {{ message.content }}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312]
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] <|im_end|>
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- endif %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- endfor %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312]
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- if add_generation_prompt %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] <|im_start|>assistant
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] {%- endif %}
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312]
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [utils.py:312] It is different from official chat template '/home/huangfukk/models/AWQ/Qwen3-4B-Instruct-2507'. This discrepancy may lead to performance degradation.
-[0;36m(APIServer pid=43538)[0;0m WARNING 01-20 16:25:42 [model.py:1487] Default sampling parameters have been overridden by the model's Hugging Face generation config recommended from the model creator. If this is not intended, please relaunch vLLM instance with `--generation-config vllm`.
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [serving_responses.py:201] Using default chat sampling params from model: {'temperature': 0.7, 'top_k': 20, 'top_p': 0.8}
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [serving_engine.py:270] "auto" tool choice has been enabled.
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [serving_engine.py:270] "auto" tool choice has been enabled.
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [serving_chat.py:137] Using default chat sampling params from model: {'temperature': 0.7, 'top_k': 20, 'top_p': 0.8}
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [serving_completion.py:77] Using default completion sampling params from model: {'temperature': 0.7, 'top_k': 20, 'top_p': 0.8}
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [serving_engine.py:270] "auto" tool choice has been enabled.
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [serving_chat.py:137] Using default chat sampling params from model: {'temperature': 0.7, 'top_k': 20, 'top_p': 0.8}
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [api_server.py:1425] Starting vLLM API server 0 on http://0.0.0.0:8081
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:38] Available routes are:
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /openapi.json, Methods: GET, HEAD
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /docs, Methods: GET, HEAD
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /docs/oauth2-redirect, Methods: GET, HEAD
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /redoc, Methods: GET, HEAD
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /scale_elastic_ep, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /is_scaling_elastic_ep, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /tokenize, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /detokenize, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /inference/v1/generate, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /pause, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /resume, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /is_paused, Methods: GET
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /metrics, Methods: GET
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /health, Methods: GET
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /load, Methods: GET
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/models, Methods: GET
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /version, Methods: GET
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/responses, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/responses/{response_id}, Methods: GET
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/responses/{response_id}/cancel, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/messages, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/chat/completions, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/completions, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/audio/transcriptions, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/audio/translations, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /ping, Methods: GET
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /ping, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /invocations, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /classify, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/embeddings, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /score, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/score, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /rerank, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/rerank, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /v2/rerank, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO 01-20 16:25:42 [launcher.py:46] Route: /pooling, Methods: POST
-[0;36m(APIServer pid=43538)[0;0m INFO: Started server process [43538]
-[0;36m(APIServer pid=43538)[0;0m INFO: Waiting for application startup.
-[0;36m(APIServer pid=43538)[0;0m INFO: Application startup complete.
-[0;36m(APIServer pid=43538)[0;0m INFO: 127.0.0.1:46791 - "GET /health HTTP/1.1" 200 OK
-[0;36m(APIServer pid=43538)[0;0m INFO: 127.0.0.1:43619 - "POST /v1/chat/completions HTTP/1.1" 200 OK
-[0;36m(APIServer pid=43538)[0;0m INFO 01-21 20:22:50 [loggers.py:248] Engine 000: Avg prompt throughput: 168.4 tokens/s, Avg generation throughput: 0.6 tokens/s, Running: 0 reqs, Waiting: 0 reqs, GPU KV cache usage: 0.0%, Prefix cache hit rate: 0.0%
-[0;36m(APIServer pid=43538)[0;0m INFO 01-21 20:23:00 [loggers.py:248] Engine 000: Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 0.0 tokens/s, Running: 0 reqs, Waiting: 0 reqs, GPU KV cache usage: 0.0%, Prefix cache hit rate: 0.0%
diff --git a/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/data_level0.bin b/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/data_level0.bin
deleted file mode 100644
index c656b189..00000000
Binary files a/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/data_level0.bin and /dev/null differ
diff --git a/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/header.bin b/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/header.bin
deleted file mode 100644
index e89c5c59..00000000
Binary files a/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/header.bin and /dev/null differ
diff --git a/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/length.bin b/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/length.bin
deleted file mode 100644
index 4fd4818c..00000000
Binary files a/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/length.bin and /dev/null differ
diff --git a/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/link_lists.bin b/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/link_lists.bin
deleted file mode 100644
index e69de29b..00000000
diff --git a/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/data_level0.bin b/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/data_level0.bin
deleted file mode 100644
index c656b189..00000000
Binary files a/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/data_level0.bin and /dev/null differ
diff --git a/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/header.bin b/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/header.bin
deleted file mode 100644
index e89c5c59..00000000
Binary files a/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/header.bin and /dev/null differ
diff --git a/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/length.bin b/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/length.bin
deleted file mode 100644
index 502d41c5..00000000
Binary files a/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/length.bin and /dev/null differ
diff --git a/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/link_lists.bin b/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/link_lists.bin
deleted file mode 100644
index e69de29b..00000000
diff --git a/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/data_level0.bin b/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/data_level0.bin
deleted file mode 100644
index 86568df2..00000000
Binary files a/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/data_level0.bin and /dev/null differ
diff --git a/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/header.bin b/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/header.bin
deleted file mode 100644
index b6867c78..00000000
Binary files a/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/header.bin and /dev/null differ
diff --git a/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/length.bin b/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/length.bin
deleted file mode 100644
index ba4322f2..00000000
Binary files a/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/length.bin and /dev/null differ
diff --git a/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/link_lists.bin b/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/link_lists.bin
deleted file mode 100644
index e69de29b..00000000
diff --git a/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/data_level0.bin b/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/data_level0.bin
deleted file mode 100644
index c656b189..00000000
Binary files a/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/data_level0.bin and /dev/null differ
diff --git a/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/header.bin b/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/header.bin
deleted file mode 100644
index e89c5c59..00000000
Binary files a/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/header.bin and /dev/null differ
diff --git a/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/length.bin b/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/length.bin
deleted file mode 100644
index d832af0a..00000000
Binary files a/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/length.bin and /dev/null differ
diff --git a/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/link_lists.bin b/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/link_lists.bin
deleted file mode 100644
index e69de29b..00000000
diff --git a/tools/rag/vector_store/chroma.sqlite3 b/tools/rag/vector_store/chroma.sqlite3
deleted file mode 100644
index 74687312..00000000
Binary files a/tools/rag/vector_store/chroma.sqlite3 and /dev/null differ
diff --git a/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/data_level0.bin b/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/data_level0.bin
deleted file mode 100644
index c656b189..00000000
Binary files a/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/data_level0.bin and /dev/null differ
diff --git a/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/header.bin b/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/header.bin
deleted file mode 100644
index e89c5c59..00000000
Binary files a/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/header.bin and /dev/null differ
diff --git a/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/length.bin b/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/length.bin
deleted file mode 100644
index cb3e1628..00000000
Binary files a/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/length.bin and /dev/null differ
diff --git a/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/link_lists.bin b/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/link_lists.bin
deleted file mode 100644
index e69de29b..00000000
diff --git a/tools/test_validate/validation/20260203224629/instructions_backup.txt b/tools/test_validate/validation/20260203224629/instructions_backup.txt
deleted file mode 100644
index ec249598..00000000
--- a/tools/test_validate/validation/20260203224629/instructions_backup.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。
-无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。
-无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。
-无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。
-无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。
-无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。
-无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。
-无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。
-无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。
-无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203224629/test_details.csv b/tools/test_validate/validation/20260203224629/test_details.csv
deleted file mode 100644
index 06477161..00000000
--- a/tools/test_validate/validation/20260203224629/test_details.csv
+++ /dev/null
@@ -1,11 +0,0 @@
-instruction,run_id,success,latency,error
-无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。,1,True,13.293935775756836,
-无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。,1,True,10.266583442687988,
-无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。,1,True,11.274949550628662,
-无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。,1,True,1.6364917755126953,
-无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。,1,True,10.27147102355957,
-无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。,1,True,13.89813232421875,
-无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。,1,True,3.24064302444458,
-无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。,1,True,19.873026847839355,
-无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。,1,True,13.099174499511719,
-无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。,1,True,8.792617082595825,
diff --git a/tools/test_validate/validation/20260203224629/test_summary.csv b/tools/test_validate/validation/20260203224629/test_summary.csv
deleted file mode 100644
index 5c49f92e..00000000
--- a/tools/test_validate/validation/20260203224629/test_summary.csv
+++ /dev/null
@@ -1,11 +0,0 @@
-Instruction,Total Runs,Success Runs,Success Rate,Avg Latency
-无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。,1,1,100.0%,13.29s
-无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。,1,1,100.0%,10.27s
-无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。,1,1,100.0%,11.27s
-无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。,1,1,100.0%,1.64s
-无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。,1,1,100.0%,10.27s
-无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。,1,1,100.0%,13.90s
-无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。,1,1,100.0%,3.24s
-无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。,1,1,100.0%,19.87s
-无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。,1,1,100.0%,13.10s
-无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。,1,1,100.0%,8.79s
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json
deleted file mode 100644
index db79db6d..00000000
--- a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "comprehensive"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 10.0
- }
- },
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 10.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的男子"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的男子"
- }
- },
- {
- "type": "action",
- "name": "approach_target",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的男子",
- "stop_distance": 5.0
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的男子",
- "track_time": 10.0
- }
- }
- ]
- },
- "plan_id": "ec05c1a4-720d-4cde-9590-a66f81a72561",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png
deleted file mode 100644
index 9db598be..00000000
Binary files a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.json
deleted file mode 100644
index 4f94b740..00000000
--- a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "root": {
- "type": "action",
- "name": "object_detect",
- "params": {
- "target_class": "person",
- "description": "长头发",
- "count": 1
- }
- },
- "plan_id": "70eb9449-6857-4a27-a99c-7c6708d12db1",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n你是一个无人机简单指令执行规划器。你的任务:当用户给出“简单指令”(单一原子动作即可完成)时,输出一个严格的JSON对象。\n\n输出要求(必须遵守):\n- 只输出一个JSON对象,不要任何解释或多余文本。\n- JSON结构:\n{\"root\":{\"type\":\"action\",\"name\":\"\",\"params\":{...}}}\n- root节点必须是action类型节点,不能是控制流节点。\n\n示例:\n- “起飞到10米” → {\"root\":{\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}}}\n- “移动到(120,80,20)” → {\"root\":{\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":120.0,\"y\":80.0,\"z\":20.0,\"acceptance_radius\":2.0}}}\n- “飞机自检” → {\"root\":{\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}}}\n\n—— 可用节点定义——\n```json\n{\n \"actions\": [\n {\"name\":\"takeoff\",\"params\":{\"altitude\":\"float[1,100],默认2\"}},\n {\"name\":\"land\",\"params\":{\"mode\":\"'current'/'home'\"}},\n {\"name\":\"fly_to_waypoint\",\"params\":{\"x\":\"±10000\",\"y\":\"±10000\",\"z\":\"[1,5000]\",\"acceptance_radius\":\"默认2.0\"}},\n {\"name\":\"fly_sequence\",\"params\":{\"waypoints\":\"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\"coordinate_frame\":\"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\"speed\":\"float,可选\"}},\n {\"name\":\"move_direction\",\"params\":{\"direction\":\"north/south/east/west/forward/backward/left/right/up/down\",\"distance\":\"[1,10000],缺省持续移动\",\"speed\":\"float,可选\"}},\n {\"name\":\"approach_target\",\"params\":{\"target_class\":\"string,要趋近的目标类别\",\"description\":\"string,可选,目标属性描述\",\"stop_distance\":\"float,期望的最终停止距离\",\"speed\":\"float,可选,期望的逼近速度\"}},\n {\"name\":\"rotate\",\"params\":{\"angle\":\"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\"angular_velocity\":\"rad/s,旋转角速度\"}},\n {\"name\":\"rotate_search\",\"params\":{\"target_class\":\"string,要搜寻的目标类别\",\"description\":\"string,可选,目标属性描述\",\"step_angle\":\"float,可选,每一步旋转的角度\",\"total_rotation\":\"float,可选,总共旋转搜索的角度\"}},\n {\"name\":\"manual_confirmation\",\"params\":{}},\n {\"name\":\"loiter\",\"params\":{\"duration\":\"[1,600]秒/until_condition:可选\"}},\n {\"name\":\"object_detect\",\"params\":{\"target_class\":\"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\"description\":\"可选,\",\"count\":\"默认1\"}},\n {\"name\":\"strike_target\",\"params\":{\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"count\":\"默认1\"}},\n {\"name\":\"battle_damage_assessment\",\"params\":{\"target_class\":\"同object_detect\",\"assessment_time\":\"[5,60],默认15\"}},\n {\"name\":\"search_pattern\",\"params\":{\"pattern_type\":\"spiral/grid\",\"center_x\":\"±10000\",\"center_y\":\"±10000\",\"center_z\":\"[1,5000]\",\"radius\":\"[5,1000]\",\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"count\":\"默认1\"}},\n {\"name\":\"track_object\",\"params\":{\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"track_time\":\"[1,600]秒(必传,不可用'duration')\",\"min_confidence\":\"[0.5,1.0]默认0.7\",\"safe_distance\":\"[2,50]默认10\"}},\n {\"name\":\"deliver_payload\",\"params\":{\"payload_type\":\"string\",\"release_altitude\":\"[2,100]默认5\"}},\n {\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic/comprehensive\"}},\n {\"name\":\"return_emergency\",\"params\":{\"reason\":\"string,此节点仅用于【无明确目的地】的立即返航。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"}},\n {\"name\":\"take_photos\",\"params\":{\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"track_time\":\"[1,600]秒(必传,不可用'duration')\",\"min_confidence\":\"[0.5,1.0]默认0.7\",\"safe_distance\":\"[2,50]默认10\"}}\n ],\n \"conditions\": [\n {\"name\":\"at_waypoint\",\"params\":{\"x\":\"±10000\",\"y\":\"±10000\",\"z\":\"[1,5000]\",\"tolerance\":\"默认3.0\"}},\n {\"name\":\"object_detected\",\"params\":{\"target_class\":\"同object_detect(必传)\",\"description\":\"可选,目标属性\",\"count\":\"默认1\"}},\n {\"name\":\"target_destroyed\",\"params\":{\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"confidence\":\"[0.5,1.0]默认0.8\"}},\n {\"name\":\"time_elapsed\",\"params\":{\"duration\":\"[1,2700]秒\"}},\n {\"name\":\"gps_status\",\"params\":{\"min_satellites\":\"int[6,15],必传(如8)\"}}\n ]\n}\n```\n\n—— 参数约束——\n- takeoff.altitude: [1, 100]\n- fly_to_waypoint.z: [1, 5000]\n- fly_to_waypoint.x,y: [-10000, 10000]\n- search_pattern.radius: [5, 1000]\n- move_direction.distance: [1, 10000]\n- 若参考知识提供坐标,必须使用并裁剪到约束范围内\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.png
deleted file mode 100644
index 584d9f92..00000000
Binary files a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.json
deleted file mode 100644
index 4606716c..00000000
--- a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "root": {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 0.0,
- "acceptance_radius": 2.0
- }
- },
- "plan_id": "ee762817-34de-406a-a216-f0ec3e0edb6e",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n你是一个无人机简单指令执行规划器。你的任务:当用户给出“简单指令”(单一原子动作即可完成)时,输出一个严格的JSON对象。\n\n输出要求(必须遵守):\n- 只输出一个JSON对象,不要任何解释或多余文本。\n- JSON结构:\n{\"root\":{\"type\":\"action\",\"name\":\"\",\"params\":{...}}}\n- root节点必须是action类型节点,不能是控制流节点。\n\n示例:\n- “起飞到10米” → {\"root\":{\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}}}\n- “移动到(120,80,20)” → {\"root\":{\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":120.0,\"y\":80.0,\"z\":20.0,\"acceptance_radius\":2.0}}}\n- “飞机自检” → {\"root\":{\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}}}\n\n—— 可用节点定义——\n```json\n{\n \"actions\": [\n {\"name\":\"takeoff\",\"params\":{\"altitude\":\"float[1,100],默认2\"}},\n {\"name\":\"land\",\"params\":{\"mode\":\"'current'/'home'\"}},\n {\"name\":\"fly_to_waypoint\",\"params\":{\"x\":\"±10000\",\"y\":\"±10000\",\"z\":\"[1,5000]\",\"acceptance_radius\":\"默认2.0\"}},\n {\"name\":\"fly_sequence\",\"params\":{\"waypoints\":\"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\"coordinate_frame\":\"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\"speed\":\"float,可选\"}},\n {\"name\":\"move_direction\",\"params\":{\"direction\":\"north/south/east/west/forward/backward/left/right/up/down\",\"distance\":\"[1,10000],缺省持续移动\",\"speed\":\"float,可选\"}},\n {\"name\":\"approach_target\",\"params\":{\"target_class\":\"string,要趋近的目标类别\",\"description\":\"string,可选,目标属性描述\",\"stop_distance\":\"float,期望的最终停止距离\",\"speed\":\"float,可选,期望的逼近速度\"}},\n {\"name\":\"rotate\",\"params\":{\"angle\":\"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\"angular_velocity\":\"rad/s,旋转角速度\"}},\n {\"name\":\"rotate_search\",\"params\":{\"target_class\":\"string,要搜寻的目标类别\",\"description\":\"string,可选,目标属性描述\",\"step_angle\":\"float,可选,每一步旋转的角度\",\"total_rotation\":\"float,可选,总共旋转搜索的角度\"}},\n {\"name\":\"manual_confirmation\",\"params\":{}},\n {\"name\":\"loiter\",\"params\":{\"duration\":\"[1,600]秒/until_condition:可选\"}},\n {\"name\":\"object_detect\",\"params\":{\"target_class\":\"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\"description\":\"可选,\",\"count\":\"默认1\"}},\n {\"name\":\"strike_target\",\"params\":{\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"count\":\"默认1\"}},\n {\"name\":\"battle_damage_assessment\",\"params\":{\"target_class\":\"同object_detect\",\"assessment_time\":\"[5,60],默认15\"}},\n {\"name\":\"search_pattern\",\"params\":{\"pattern_type\":\"spiral/grid\",\"center_x\":\"±10000\",\"center_y\":\"±10000\",\"center_z\":\"[1,5000]\",\"radius\":\"[5,1000]\",\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"count\":\"默认1\"}},\n {\"name\":\"track_object\",\"params\":{\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"track_time\":\"[1,600]秒(必传,不可用'duration')\",\"min_confidence\":\"[0.5,1.0]默认0.7\",\"safe_distance\":\"[2,50]默认10\"}},\n {\"name\":\"deliver_payload\",\"params\":{\"payload_type\":\"string\",\"release_altitude\":\"[2,100]默认5\"}},\n {\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic/comprehensive\"}},\n {\"name\":\"return_emergency\",\"params\":{\"reason\":\"string,此节点仅用于【无明确目的地】的立即返航。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"}},\n {\"name\":\"take_photos\",\"params\":{\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"track_time\":\"[1,600]秒(必传,不可用'duration')\",\"min_confidence\":\"[0.5,1.0]默认0.7\",\"safe_distance\":\"[2,50]默认10\"}}\n ],\n \"conditions\": [\n {\"name\":\"at_waypoint\",\"params\":{\"x\":\"±10000\",\"y\":\"±10000\",\"z\":\"[1,5000]\",\"tolerance\":\"默认3.0\"}},\n {\"name\":\"object_detected\",\"params\":{\"target_class\":\"同object_detect(必传)\",\"description\":\"可选,目标属性\",\"count\":\"默认1\"}},\n {\"name\":\"target_destroyed\",\"params\":{\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"confidence\":\"[0.5,1.0]默认0.8\"}},\n {\"name\":\"time_elapsed\",\"params\":{\"duration\":\"[1,2700]秒\"}},\n {\"name\":\"gps_status\",\"params\":{\"min_satellites\":\"int[6,15],必传(如8)\"}}\n ]\n}\n```\n\n—— 参数约束——\n- takeoff.altitude: [1, 100]\n- fly_to_waypoint.z: [1, 5000]\n- fly_to_waypoint.x,y: [-10000, 10000]\n- search_pattern.radius: [5, 1000]\n- move_direction.distance: [1, 10000]\n- 若参考知识提供坐标,必须使用并裁剪到约束范围内\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.png
deleted file mode 100644
index 44349152..00000000
Binary files a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.json
deleted file mode 100644
index b71864ef..00000000
--- a/tools/test_validate/validation/20260203224629/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.json
+++ /dev/null
@@ -1,63 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "comprehensive"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 10.0
- }
- },
- {
- "type": "action",
- "name": "move_direction",
- "params": {
- "direction": "east",
- "distance": 30.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "person",
- "description": "身穿白色衣服,头戴帽子的男子"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person",
- "description": "身穿白色衣服,头戴帽子的男子"
- }
- },
- {
- "type": "action",
- "name": "manual_confirmation",
- "params": {}
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person",
- "description": "身穿白色衣服,头戴帽子的男子",
- "track_time": 10.0
- }
- }
- ]
- },
- "plan_id": "24122475-d286-4034-b9a5-e7e37aff8564",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.png
deleted file mode 100644
index 866e0c54..00000000
Binary files a/tools/test_validate/validation/20260203224629/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.json
deleted file mode 100644
index 03f0280a..00000000
--- a/tools/test_validate/validation/20260203224629/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": -50.0,
- "y": 0.0,
- "z": 0.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的人"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的人"
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的人",
- "track_time": 5.0
- }
- },
- {
- "type": "action",
- "name": "return_emergency",
- "params": {
- "reason": "任务完成"
- }
- }
- ]
- },
- "plan_id": "3f212bfa-0915-4bc4-a9b1-59266248c05c",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.png
deleted file mode 100644
index a811ad7f..00000000
Binary files a/tools/test_validate/validation/20260203224629/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.json
deleted file mode 100644
index 8db81934..00000000
--- a/tools/test_validate/validation/20260203224629/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 0.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "person",
- "description": "戴帽子的人"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person",
- "description": "戴帽子的人"
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person",
- "description": "戴帽子的人",
- "track_time": 10.0
- }
- }
- ]
- },
- "plan_id": "ad362dde-0c33-435b-9870-9d29beee9278",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.png
deleted file mode 100644
index 4a654bdd..00000000
Binary files a/tools/test_validate/validation/20260203224629/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.json
deleted file mode 100644
index 4267f08b..00000000
--- a/tools/test_validate/validation/20260203224629/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": -50.0,
- "y": 0.0,
- "z": 0.0
- }
- },
- {
- "type": "Parallel",
- "name": "MonitorAndPhoto",
- "params": {
- "policy": "success_on_one"
- },
- "children": [
- {
- "type": "action",
- "name": "loiter",
- "params": {
- "duration": 300
- }
- },
- {
- "type": "decorator",
- "name": "SuccessIsFailure",
- "child": {
- "type": "Sequence",
- "name": "CheckAndPhoto",
- "children": [
- {
- "type": "action",
- "name": "object_detect",
- "params": {
- "target_class": "person"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person"
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person"
- }
- }
- ]
- }
- }
- ]
- },
- {
- "type": "action",
- "name": "return_emergency",
- "params": {
- "reason": "任务完成"
- }
- }
- ]
- },
- "plan_id": "c7382dba-30c3-48b9-b175-ec42cb7f90d8",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.png
deleted file mode 100644
index 4737b375..00000000
Binary files a/tools/test_validate/validation/20260203224629/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.json
deleted file mode 100644
index 9563cfc0..00000000
--- a/tools/test_validate/validation/20260203224629/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "SearchPhotoConfirmReturn",
- "children": [
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的人"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的人"
- }
- },
- {
- "type": "action",
- "name": "manual_confirmation",
- "params": {}
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的人"
- }
- },
- {
- "type": "action",
- "name": "return_emergency",
- "params": {
- "reason": "确认后返航"
- }
- }
- ]
- },
- "plan_id": "00394bf3-1df8-49aa-917a-4d81acb535ec",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.png
deleted file mode 100644
index d72aa331..00000000
Binary files a/tools/test_validate/validation/20260203224629/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.json
deleted file mode 100644
index e01e69cd..00000000
--- a/tools/test_validate/validation/20260203224629/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "approach_target",
- "params": {
- "target_class": "person",
- "description": "白色衣服戴帽子的男子",
- "stop_distance": 3.0
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person",
- "description": "白色衣服戴帽子的男子",
- "track_time": 5.0
- }
- },
- {
- "type": "action",
- "name": "return_emergency",
- "params": {
- "reason": "任务完成"
- }
- }
- ]
- },
- "plan_id": "f31e2045-5987-4aab-8543-31d15fa17704",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.png
deleted file mode 100644
index 35ebf526..00000000
Binary files a/tools/test_validate/validation/20260203224629/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。/1.json
deleted file mode 100644
index fe891f8b..00000000
--- a/tools/test_validate/validation/20260203224629/无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。/1.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "error": "在3次尝试后,仍未能生成一个有效的Pytree。"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203225625/instructions_backup.txt b/tools/test_validate/validation/20260203225625/instructions_backup.txt
deleted file mode 100644
index ec249598..00000000
--- a/tools/test_validate/validation/20260203225625/instructions_backup.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。
-无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。
-无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。
-无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。
-无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。
-无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。
-无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。
-无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。
-无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。
-无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203225625/test_details.csv b/tools/test_validate/validation/20260203225625/test_details.csv
deleted file mode 100644
index 4d9169ae..00000000
--- a/tools/test_validate/validation/20260203225625/test_details.csv
+++ /dev/null
@@ -1,11 +0,0 @@
-instruction,run_id,success,latency,error
-无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。,1,True,14.206302165985107,
-无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。,1,True,9.870139360427856,
-无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。,1,True,11.775025844573975,
-无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。,1,True,10.768753051757812,
-无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。,1,True,10.050657749176025,
-无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。,1,True,13.982521057128906,
-无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。,1,True,12.104306697845459,
-无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。,1,True,21.10497808456421,
-无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。,1,True,11.49827790260315,
-无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。,1,True,9.288247346878052,
diff --git a/tools/test_validate/validation/20260203225625/test_summary.csv b/tools/test_validate/validation/20260203225625/test_summary.csv
deleted file mode 100644
index 52f86c8e..00000000
--- a/tools/test_validate/validation/20260203225625/test_summary.csv
+++ /dev/null
@@ -1,11 +0,0 @@
-Instruction,Total Runs,Success Runs,Success Rate,Avg Latency
-无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。,1,1,100.0%,14.21s
-无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。,1,1,100.0%,9.87s
-无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。,1,1,100.0%,11.78s
-无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。,1,1,100.0%,10.77s
-无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。,1,1,100.0%,10.05s
-无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。,1,1,100.0%,13.98s
-无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。,1,1,100.0%,12.10s
-无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。,1,1,100.0%,21.10s
-无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。,1,1,100.0%,11.50s
-无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。,1,1,100.0%,9.29s
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json
deleted file mode 100644
index e23f0722..00000000
--- a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "comprehensive"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 10.0
- }
- },
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 10.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的男子"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的男子"
- }
- },
- {
- "type": "action",
- "name": "approach_target",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的男子",
- "stop_distance": 5.0
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的男子",
- "track_time": 10.0
- }
- }
- ]
- },
- "plan_id": "e6dd50ed-5ce0-4032-91fa-bb7b9e28233c",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png
deleted file mode 100644
index 9db598be..00000000
Binary files a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.json
deleted file mode 100644
index d95911b0..00000000
--- a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "comprehensive"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 10.0
- }
- },
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 0.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "person",
- "description": "长头发的人"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person",
- "description": "长头发的人"
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person",
- "description": "长头发的人",
- "track_time": 5.0
- }
- }
- ]
- },
- "plan_id": "02ac6a8d-630b-43d7-8374-679cc07f37ed",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.png
deleted file mode 100644
index e959795b..00000000
Binary files a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.json
deleted file mode 100644
index d8e83caf..00000000
--- a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "comprehensive"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 10.0
- }
- },
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 0.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "person",
- "description": "未带帽子"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person",
- "description": "未带帽子"
- }
- },
- {
- "type": "action",
- "name": "approach_target",
- "params": {
- "target_class": "person",
- "description": "未带帽子",
- "stop_distance": 5.0
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person",
- "description": "未带帽子",
- "track_time": 10.0
- }
- }
- ]
- },
- "plan_id": "dca5568f-e062-4d82-b8db-61ef2bed669a",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.png
deleted file mode 100644
index 172bbd21..00000000
Binary files a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.json
deleted file mode 100644
index beb858e7..00000000
--- a/tools/test_validate/validation/20260203225625/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.json
+++ /dev/null
@@ -1,63 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "comprehensive"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 10.0
- }
- },
- {
- "type": "action",
- "name": "move_direction",
- "params": {
- "direction": "east",
- "distance": 30.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "person",
- "description": "身穿白色衣服,头戴帽子的男子"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person",
- "description": "身穿白色衣服,头戴帽子的男子"
- }
- },
- {
- "type": "action",
- "name": "manual_confirmation",
- "params": {}
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person",
- "description": "身穿白色衣服,头戴帽子的男子",
- "track_time": 10.0
- }
- }
- ]
- },
- "plan_id": "046d1b14-1c37-4143-98c5-5a80a61213a1",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.png
deleted file mode 100644
index 866e0c54..00000000
Binary files a/tools/test_validate/validation/20260203225625/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.json
deleted file mode 100644
index 850874f3..00000000
--- a/tools/test_validate/validation/20260203225625/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": -50.0,
- "y": 0.0,
- "z": 0.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的人"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的人"
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的人",
- "track_time": 5.0
- }
- },
- {
- "type": "action",
- "name": "return_emergency",
- "params": {
- "reason": "任务完成"
- }
- }
- ]
- },
- "plan_id": "ded7065b-453b-4b55-8737-1e00388f6a06",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.png
deleted file mode 100644
index a811ad7f..00000000
Binary files a/tools/test_validate/validation/20260203225625/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.json
deleted file mode 100644
index e7df2f0a..00000000
--- a/tools/test_validate/validation/20260203225625/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 0.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "person",
- "description": "戴帽子的人"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person",
- "description": "戴帽子的人"
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person",
- "description": "戴帽子的人",
- "track_time": 10.0
- }
- }
- ]
- },
- "plan_id": "35f56771-b284-4d58-b738-e404f5aa29a1",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.png
deleted file mode 100644
index 4a654bdd..00000000
Binary files a/tools/test_validate/validation/20260203225625/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.json
deleted file mode 100644
index 5fe0d871..00000000
--- a/tools/test_validate/validation/20260203225625/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": -50.0,
- "y": 0.0,
- "z": 0.0
- }
- },
- {
- "type": "Parallel",
- "name": "MonitorAndPhoto",
- "params": {
- "policy": "success_on_one"
- },
- "children": [
- {
- "type": "action",
- "name": "loiter",
- "params": {
- "duration": 300
- }
- },
- {
- "type": "decorator",
- "name": "SuccessIsFailure",
- "child": {
- "type": "Sequence",
- "name": "CheckAndPhoto",
- "children": [
- {
- "type": "action",
- "name": "object_detect",
- "params": {
- "target_class": "person"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person"
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person"
- }
- }
- ]
- }
- }
- ]
- },
- {
- "type": "action",
- "name": "return_emergency",
- "params": {
- "reason": "任务完成"
- }
- }
- ]
- },
- "plan_id": "f54dd51c-b9f5-4a9a-802f-941bba44ca12",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.png
deleted file mode 100644
index 4737b375..00000000
Binary files a/tools/test_validate/validation/20260203225625/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.json
deleted file mode 100644
index 7a38b417..00000000
--- a/tools/test_validate/validation/20260203225625/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "SearchPhotoConfirmReturn",
- "children": [
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的人"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的人"
- }
- },
- {
- "type": "action",
- "name": "manual_confirmation",
- "params": {}
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person",
- "description": "穿红色衣服的人"
- }
- },
- {
- "type": "action",
- "name": "return_emergency",
- "params": {
- "reason": "确认后返航"
- }
- }
- ]
- },
- "plan_id": "642ee3ce-45a3-4c7b-b1a4-b323cc0dbf6b",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.png
deleted file mode 100644
index d72aa331..00000000
Binary files a/tools/test_validate/validation/20260203225625/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.json
deleted file mode 100644
index 879be75b..00000000
--- a/tools/test_validate/validation/20260203225625/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "approach_target",
- "params": {
- "target_class": "person",
- "description": "白色衣服戴帽子的男子",
- "stop_distance": 3.0
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "person",
- "description": "白色衣服戴帽子的男子",
- "track_time": 5.0
- }
- },
- {
- "type": "action",
- "name": "return_emergency",
- "params": {
- "reason": "任务完成"
- }
- }
- ]
- },
- "plan_id": "7e65d4ad-dd23-49ac-80d9-70b648c17cd4",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.png
deleted file mode 100644
index 35ebf526..00000000
Binary files a/tools/test_validate/validation/20260203225625/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。/1.json
deleted file mode 100644
index fe891f8b..00000000
--- a/tools/test_validate/validation/20260203225625/无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。/1.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "error": "在3次尝试后,仍未能生成一个有效的Pytree。"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260221090219/instructions_backup.txt b/tools/test_validate/validation/20260221090219/instructions_backup.txt
deleted file mode 100644
index ec249598..00000000
--- a/tools/test_validate/validation/20260221090219/instructions_backup.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。
-无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。
-无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。
-无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。
-无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。
-无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。
-无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。
-无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。
-无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。
-无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260221090219/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json b/tools/test_validate/validation/20260221090219/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json
deleted file mode 100644
index b9216d96..00000000
--- a/tools/test_validate/validation/20260221090219/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "basic"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 2
- }
- },
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0,
- "y": 0,
- "z": 0,
- "acceptance_radius": 2.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "穿红色衣服的男子",
- "description": "",
- "step_angle": 10.0,
- "total_rotation": 360.0
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "穿红色衣服的男子",
- "description": "",
- "count": 1
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "穿红色衣服的男子",
- "description": "",
- "track_time": 10,
- "min_confidence": 0.7,
- "safe_distance": 10
- }
- }
- ]
- },
- "plan_id": "71b277b7-08d2-482f-bbb7-141c667b2c7d",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260221090219/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png b/tools/test_validate/validation/20260221090219/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png
deleted file mode 100644
index 9c453124..00000000
Binary files a/tools/test_validate/validation/20260221090219/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260224120937/instructions_backup.txt b/tools/test_validate/validation/20260224120937/instructions_backup.txt
deleted file mode 100644
index ec249598..00000000
--- a/tools/test_validate/validation/20260224120937/instructions_backup.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。
-无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。
-无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。
-无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。
-无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。
-无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。
-无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。
-无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。
-无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。
-无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260224120937/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json b/tools/test_validate/validation/20260224120937/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json
deleted file mode 100644
index ce3614b2..00000000
--- a/tools/test_validate/validation/20260224120937/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "basic"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 2.0
- }
- },
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 100.0,
- "acceptance_radius": 2.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "穿红色衣服的男子",
- "description": "",
- "step_angle": 10.0,
- "total_rotation": 360.0
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "穿红色衣服的男子",
- "description": "",
- "count": 1
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "穿红色衣服的男子",
- "description": "",
- "track_time": 10,
- "min_confidence": 0.7,
- "safe_distance": 10
- }
- }
- ]
- },
- "plan_id": "c936a4fc-09d3-4ab4-aae3-34b4e228a798",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260224120937/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png b/tools/test_validate/validation/20260224120937/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png
deleted file mode 100644
index c137bec6..00000000
Binary files a/tools/test_validate/validation/20260224120937/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260224121211/instructions_backup.txt b/tools/test_validate/validation/20260224121211/instructions_backup.txt
deleted file mode 100644
index 5b6dc3d2..00000000
--- a/tools/test_validate/validation/20260224121211/instructions_backup.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。
-无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。
-无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。
-无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。
-无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。
-无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。
-无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。
-无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。
-无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260224121211/test_details.csv b/tools/test_validate/validation/20260224121211/test_details.csv
deleted file mode 100644
index 8a88d711..00000000
--- a/tools/test_validate/validation/20260224121211/test_details.csv
+++ /dev/null
@@ -1,10 +0,0 @@
-instruction,run_id,success,latency,error
-无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。,1,True,16.063878774642944,
-无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。,1,False,16.235912084579468,500 Server Error: Internal Server Error for url: http://127.0.0.1:8000/generate_plan
-无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。,1,True,11.32945990562439,
-无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。,1,False,18.68914246559143,500 Server Error: Internal Server Error for url: http://127.0.0.1:8000/generate_plan
-无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。,1,True,14.857678651809692,
-无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。,1,True,11.974151134490967,
-无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。,1,True,15.218279838562012,
-无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。,1,True,15.252280473709106,
-无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。,1,True,12.335286378860474,
diff --git a/tools/test_validate/validation/20260224121211/test_summary.csv b/tools/test_validate/validation/20260224121211/test_summary.csv
deleted file mode 100644
index a98d404c..00000000
--- a/tools/test_validate/validation/20260224121211/test_summary.csv
+++ /dev/null
@@ -1,10 +0,0 @@
-Instruction,Total Runs,Success Runs,Success Rate,Avg Latency
-无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。,1,1,100.0%,16.06s
-无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。,1,0,0.0%,0.00s
-无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。,1,1,100.0%,11.33s
-无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。,1,0,0.0%,0.00s
-无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。,1,1,100.0%,14.86s
-无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。,1,1,100.0%,11.97s
-无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。,1,1,100.0%,15.22s
-无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。,1,1,100.0%,15.25s
-无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。,1,1,100.0%,12.34s
diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。/1.json b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。/1.json
deleted file mode 100644
index 05a3594c..00000000
--- a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。/1.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "basic"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 2.0
- }
- },
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 100.0,
- "acceptance_radius": 2.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "人",
- "description": "",
- "step_angle": 10.0,
- "total_rotation": 360.0
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "人",
- "description": "",
- "count": 1
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "人",
- "description": "",
- "track_time": 10,
- "min_confidence": 0.7,
- "safe_distance": 10
- }
- }
- ]
- },
- "context": {
- "relative_refs": [
- {
- "anchor": "front_building",
- "relation": "front",
- "distance_m": 12.0
- }
- ]
- },
- "plan_id": "36c0375e-4033-4016-9b0d-a79c5d5ccb35",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。/1.png b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。/1.png
deleted file mode 100644
index 461968e0..00000000
Binary files a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。/1.json b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。/1.json
deleted file mode 100644
index 323fef11..00000000
--- a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。/1.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "basic"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 2.0
- }
- },
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 100.0,
- "acceptance_radius": 2.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "杂物堆积",
- "description": "",
- "step_angle": 10.0,
- "total_rotation": 360.0
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "杂物堆积",
- "description": "",
- "count": 1
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "杂物堆积",
- "description": "",
- "track_time": 10,
- "min_confidence": 0.7,
- "safe_distance": 10
- }
- }
- ]
- },
- "context": {
- "relative_refs": [
- {
- "anchor": "front_building",
- "relation": "front",
- "distance_m": 12.0
- }
- ]
- },
- "plan_id": "cfac2789-64b3-4669-a2e1-8f497ab86330",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。/1.png b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。/1.png
deleted file mode 100644
index 91feffad..00000000
Binary files a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。/1.json b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。/1.json
deleted file mode 100644
index 95d995d6..00000000
--- a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。/1.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "basic"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 2.0
- }
- },
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 100.0,
- "acceptance_radius": 2.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "人",
- "description": "",
- "step_angle": 10.0,
- "total_rotation": 360.0
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "人",
- "description": "",
- "count": 1
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "人",
- "description": "",
- "track_time": 10,
- "min_confidence": 0.7,
- "safe_distance": 10
- }
- }
- ]
- },
- "context": {
- "relative_refs": [
- {
- "anchor": "front_building",
- "relation": "front",
- "distance_m": 12.0
- }
- ]
- },
- "plan_id": "20182393-9686-4473-825f-c4b0a0ee3aab",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。/1.png b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。/1.png
deleted file mode 100644
index 461968e0..00000000
Binary files a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/1.json b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/1.json
deleted file mode 100644
index a15efff1..00000000
--- a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/1.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "basic"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 2.0
- }
- },
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 100.0,
- "acceptance_radius": 2.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "打开的窗户",
- "description": "",
- "step_angle": 10.0,
- "total_rotation": 360.0
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "打开的窗户",
- "description": "",
- "count": 1
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "打开的窗户",
- "description": "",
- "track_time": 10,
- "min_confidence": 0.7,
- "safe_distance": 10
- }
- }
- ]
- },
- "context": {
- "relative_refs": [
- {
- "anchor": "front_building",
- "relation": "front",
- "distance_m": 12.0
- }
- ]
- },
- "plan_id": "b98bf664-f8f6-4330-b22b-179424a135c1",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/1.png b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/1.png
deleted file mode 100644
index da88f4cd..00000000
Binary files a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。/1.json b/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。/1.json
deleted file mode 100644
index df017b11..00000000
--- a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。/1.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0,
- "y": 0,
- "z": 1000,
- "acceptance_radius": 2.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "大楼外围"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "目标类别",
- "description": "",
- "count": 1
- },
- "children": [
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "目标类别",
- "description": "",
- "track_time": 10,
- "min_confidence": 0.7,
- "safe_distance": 10
- }
- }
- ]
- }
- ]
- },
- "plan_id": "d3dd62cb-0ae2-4103-9678-4a057dc93f40",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **in_air(空中)** 时,通常的流程包含:方向移动或直接飞行至目标点 -> (执行任务)。**严禁**使用 `system_checks` 与 `takeoff`。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"},\n {\"type\": \"action\", \"name\": \"rotate_search\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"前往广场中心\",\n \"extracted_entities\": {\n \"landmark\": \"广场中心\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。/1.png b/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。/1.png
deleted file mode 100644
index eba34872..00000000
Binary files a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。/1.json b/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。/1.json
deleted file mode 100644
index 6635e057..00000000
--- a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。/1.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "move_direction",
- "params": {
- "distance": "3米"
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "大楼外围"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "目标类别",
- "count": 1
- },
- "children": [
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "目标类别",
- "track_time": 10,
- "min_confidence": 0.7,
- "safe_distance": 10
- }
- }
- ]
- }
- ]
- },
- "plan_id": "8fb53945-4c01-460e-9219-deb9d21cbe56",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **in_air(空中)** 时,通常的流程包含:方向移动或直接飞行至目标点 -> (执行任务)。**严禁**使用 `system_checks` 与 `takeoff`。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"},\n {\"type\": \"action\", \"name\": \"rotate_search\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"前往广场中心\",\n \"extracted_entities\": {\n \"landmark\": \"广场中心\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。/1.png b/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。/1.png
deleted file mode 100644
index 5e97be50..00000000
Binary files a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260224121211/无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。/1.json b/tools/test_validate/validation/20260224121211/无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。/1.json
deleted file mode 100644
index 4a3dee2a..00000000
--- a/tools/test_validate/validation/20260224121211/无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。/1.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "move_direction",
- "params": {
- "direction": "下",
- "distance": "3米"
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "大楼外围"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "目标类别",
- "count": 1
- },
- "children": [
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "目标类别",
- "track_time": 10,
- "min_confidence": 0.7,
- "safe_distance": 10
- }
- }
- ]
- }
- ]
- },
- "plan_id": "3e1c7b7c-8af1-450a-9981-be2bbb736b13",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **in_air(空中)** 时,通常的流程包含:方向移动或直接飞行至目标点 -> (执行任务)。**严禁**使用 `system_checks` 与 `takeoff`。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"},\n {\"type\": \"action\", \"name\": \"rotate_search\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"前往广场中心\",\n \"extracted_entities\": {\n \"landmark\": \"广场中心\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260224121211/无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。/1.png b/tools/test_validate/validation/20260224121211/无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。/1.png
deleted file mode 100644
index 38d2839f..00000000
Binary files a/tools/test_validate/validation/20260224121211/无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260224125506/instructions_backup.txt b/tools/test_validate/validation/20260224125506/instructions_backup.txt
deleted file mode 100644
index cf77a61d..00000000
--- a/tools/test_validate/validation/20260224125506/instructions_backup.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。
-无人机当前在空中,回到广场,对戴帽子的人进行拍照。
-无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。
-无人机当前在地面,到广场查找绿色公交车,看见了拍个照片。
-无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。
-无人机当前在空中,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航。
-无人机当前在空中,往广场南边飞40米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。
-无人机当前在地面,到广场边上的施工区域内,发现有没带安全帽的飞近后拍照。
-无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。
-无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。
-无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260224125506/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/1.json b/tools/test_validate/validation/20260224125506/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/1.json
deleted file mode 100644
index f20fc89a..00000000
--- a/tools/test_validate/validation/20260224125506/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/1.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "basic"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 2.0
- }
- },
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 0.0,
- "acceptance_radius": 2.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "穿红色衣服的人",
- "description": "",
- "step_angle": 10.0,
- "total_rotation": 360.0
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "穿红色衣服的人",
- "description": "",
- "count": 1
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "穿红色衣服的人",
- "description": "",
- "track_time": 10,
- "min_confidence": 0.7,
- "safe_distance": 10
- }
- }
- ]
- },
- "plan_id": "1c13a764-87bb-426e-a8ec-79739a8e2c1d",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260224125506/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/1.png b/tools/test_validate/validation/20260224125506/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/1.png
deleted file mode 100644
index dcfa34eb..00000000
Binary files a/tools/test_validate/validation/20260224125506/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260224125506/无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。/1.json b/tools/test_validate/validation/20260224125506/无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。/1.json
deleted file mode 100644
index e2ac0b8f..00000000
--- a/tools/test_validate/validation/20260224125506/无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。/1.json
+++ /dev/null
@@ -1,57 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0,
- "y": 0,
- "z": 100,
- "acceptance_radius": 2.0
- }
- },
- {
- "type": "action",
- "name": "object_detect",
- "params": {
- "target_class": "公交车",
- "description": "",
- "count": 1
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "公交车",
- "description": "",
- "count": 1
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "公交车",
- "description": "",
- "track_time": 10,
- "min_confidence": 0.7,
- "safe_distance": 10
- }
- },
- {
- "type": "action",
- "name": "return_emergency",
- "params": {
- "reason": "未检测到目标"
- }
- }
- ]
- },
- "plan_id": "cf3f649f-03e2-4fe3-9d42-75290e00c09d",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **in_air(空中)** 时,通常的流程包含:方向移动或直接飞行至目标点 -> (执行任务)。**严禁**使用 `system_checks` 与 `takeoff`。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"},\n {\"type\": \"action\", \"name\": \"rotate_search\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"前往广场中心\",\n \"extracted_entities\": {\n \"landmark\": \"广场中心\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260224125506/无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。/1.png b/tools/test_validate/validation/20260224125506/无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。/1.png
deleted file mode 100644
index 746e5fe1..00000000
Binary files a/tools/test_validate/validation/20260224125506/无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/20260224125506/无人机当前在空中,回到广场,对戴帽子的人进行拍照。/1.json b/tools/test_validate/validation/20260224125506/无人机当前在空中,回到广场,对戴帽子的人进行拍照。/1.json
deleted file mode 100644
index 9d947429..00000000
--- a/tools/test_validate/validation/20260224125506/无人机当前在空中,回到广场,对戴帽子的人进行拍照。/1.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0,
- "y": 0,
- "z": 1000,
- "acceptance_radius": 2.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "戴帽子的人",
- "description": "",
- "step_angle": 30.0,
- "total_rotation": 180.0
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "戴帽子的人",
- "description": "",
- "count": 1
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "戴帽子的人",
- "description": "",
- "track_time": 10,
- "min_confidence": 0.7,
- "safe_distance": 10
- }
- }
- ]
- },
- "plan_id": "fefcc502-0416-4b7d-979d-973aa5f9173f",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **in_air(空中)** 时,通常的流程包含:方向移动或直接飞行至目标点 -> (执行任务)。**严禁**使用 `system_checks` 与 `takeoff`。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"},\n {\"type\": \"action\", \"name\": \"rotate_search\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"前往广场中心\",\n \"extracted_entities\": {\n \"landmark\": \"广场中心\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在空中,回到广场,对戴帽子的人进行拍照。"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/20260224125506/无人机当前在空中,回到广场,对戴帽子的人进行拍照。/1.png b/tools/test_validate/validation/20260224125506/无人机当前在空中,回到广场,对戴帽子的人进行拍照。/1.png
deleted file mode 100644
index 83ef278d..00000000
Binary files a/tools/test_validate/validation/20260224125506/无人机当前在空中,回到广场,对戴帽子的人进行拍照。/1.png and /dev/null differ
diff --git a/tools/test_validate/validation/temporary/stage1_无人机当前在地面,起飞/response.json b/tools/test_validate/validation/temporary/stage1_无人机当前在地面,起飞/response.json
deleted file mode 100644
index b287d3b3..00000000
--- a/tools/test_validate/validation/temporary/stage1_无人机当前在地面,起飞/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "simple",
- "drone_state": "on_ground",
- "intent_type": "single_action",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "无人机当前在地面,起飞"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到广场/response.json b/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到广场/response.json
deleted file mode 100644
index 6343aa0e..00000000
--- a/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到广场/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "无人机当前在空中,飞到广场"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到广场北边50米/response.json b/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到广场北边50米/response.json
deleted file mode 100644
index 0f7d49d6..00000000
--- a/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到广场北边50米/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "无人机当前在空中,飞到广场北边50米"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到面前的大楼/response.json b/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到面前的大楼/response.json
deleted file mode 100644
index 67d038a6..00000000
--- a/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到面前的大楼/response.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": true,
- "entities": {
- "raw_prompt": "无人机当前在空中,飞到面前的大楼"
- },
- "risk_flags": [
- "relative_reference_detected"
- ],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_无空中,飞到广场/response.json b/tools/test_validate/validation/temporary/stage1_无空中,飞到广场/response.json
deleted file mode 100644
index ab61cf65..00000000
--- a/tools/test_validate/validation/temporary/stage1_无空中,飞到广场/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene4",
- "drone_state": "on_ground",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "无空中,飞到广场"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_起飞/response.json b/tools/test_validate/validation/temporary/stage1_起飞/response.json
deleted file mode 100644
index 19c32ac5..00000000
--- a/tools/test_validate/validation/temporary/stage1_起飞/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "simple",
- "drone_state": "on_ground",
- "intent_type": "single_action",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "起飞"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到南广场/response.json b/tools/test_validate/validation/temporary/stage1_飞到南广场/response.json
deleted file mode 100644
index e35b15f3..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到南广场/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "simple",
- "drone_state": "in_air",
- "intent_type": "single_action",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到南广场"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到大楼/response.json b/tools/test_validate/validation/temporary/stage1_飞到大楼/response.json
deleted file mode 100644
index 4977c55e..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到大楼/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到大楼"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到学校/response.json b/tools/test_validate/validation/temporary/stage1_飞到学校/response.json
deleted file mode 100644
index a3a37645..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到学校/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "simple",
- "drone_state": "in_air",
- "intent_type": "single_action",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到学校"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到学校北边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到学校北边50米/response.json
deleted file mode 100644
index 57dc9d43..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到学校北边50米/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到学校北边50米"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到宿舍/response.json b/tools/test_validate/validation/temporary/stage1_飞到宿舍/response.json
deleted file mode 100644
index 50b0123d..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到宿舍/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "simple",
- "drone_state": "in_air",
- "intent_type": "single_action",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到宿舍"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到宿舍北边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到宿舍北边50米/response.json
deleted file mode 100644
index 1294ba3f..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到宿舍北边50米/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到宿舍北边50米"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到宿舍南边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到宿舍南边50米/response.json
deleted file mode 100644
index 9e09d9c9..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到宿舍南边50米/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到宿舍南边50米"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到宿舍南边60米/response.json b/tools/test_validate/validation/temporary/stage1_飞到宿舍南边60米/response.json
deleted file mode 100644
index 421d47f4..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到宿舍南边60米/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到宿舍南边60米"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到广场/response.json b/tools/test_validate/validation/temporary/stage1_飞到广场/response.json
deleted file mode 100644
index c931498b..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到广场/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "simple",
- "drone_state": "in_air",
- "intent_type": "single_action",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到广场"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到广场北边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到广场北边50米/response.json
deleted file mode 100644
index 7aceb36b..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到广场北边50米/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到广场北边50米"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到广场南边/response.json b/tools/test_validate/validation/temporary/stage1_飞到广场南边/response.json
deleted file mode 100644
index 43f8ad2c..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到广场南边/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到广场南边"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到广场南边40米/response.json b/tools/test_validate/validation/temporary/stage1_飞到广场南边40米/response.json
deleted file mode 100644
index 13db964d..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到广场南边40米/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到广场南边40米"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到广场南边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到广场南边50米/response.json
deleted file mode 100644
index 2fff8e82..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到广场南边50米/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到广场南边50米"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到广场西边/response.json b/tools/test_validate/validation/temporary/stage1_飞到广场西边/response.json
deleted file mode 100644
index 82d4582f..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到广场西边/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到广场西边"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到建筑物A/response.json b/tools/test_validate/validation/temporary/stage1_飞到建筑物A/response.json
deleted file mode 100644
index e524f45d..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到建筑物A/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "simple",
- "drone_state": "in_air",
- "intent_type": "single_action",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到建筑物A"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到建筑物A南边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到建筑物A南边50米/response.json
deleted file mode 100644
index e1f750ae..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到建筑物A南边50米/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到建筑物A南边50米"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到研究所东侧30米/response.json b/tools/test_validate/validation/temporary/stage1_飞到研究所东侧30米/response.json
deleted file mode 100644
index de812b36..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到研究所东侧30米/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "simple",
- "drone_state": "in_air",
- "intent_type": "single_action",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到研究所东侧30米"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到研究所东边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到研究所东边50米/response.json
deleted file mode 100644
index a0352261..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到研究所东边50米/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到研究所东边50米"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到研究所东边60米/response.json b/tools/test_validate/validation/temporary/stage1_飞到研究所东边60米/response.json
deleted file mode 100644
index 4217ceba..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到研究所东边60米/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到研究所东边60米"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到研究所东边60米的施工场所/response.json b/tools/test_validate/validation/temporary/stage1_飞到研究所东边60米的施工场所/response.json
deleted file mode 100644
index 0d4caaa6..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到研究所东边60米的施工场所/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到研究所东边60米的施工场所"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到研究所南边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到研究所南边50米/response.json
deleted file mode 100644
index 89f2f424..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到研究所南边50米/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "scene1",
- "drone_state": "in_air",
- "intent_type": "generic_mission",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到研究所南边50米"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage1_飞到研究院/response.json b/tools/test_validate/validation/temporary/stage1_飞到研究院/response.json
deleted file mode 100644
index 5c880900..00000000
--- a/tools/test_validate/validation/temporary/stage1_飞到研究院/response.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "target_stage": 1,
- "stage_name": "TaskUnderstanding",
- "output": {
- "scene_mode": "simple",
- "drone_state": "in_air",
- "intent_type": "single_action",
- "requires_relative_target": false,
- "entities": {
- "raw_prompt": "飞到研究院"
- },
- "risk_flags": [],
- "constraints": {}
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage2_飞到广场东边50米/response.json b/tools/test_validate/validation/temporary/stage2_飞到广场东边50米/response.json
deleted file mode 100644
index 01db533a..00000000
--- a/tools/test_validate/validation/temporary/stage2_飞到广场东边50米/response.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "target_stage": 2,
- "stage_name": "ContextBinding",
- "output": {
- "location_context": "{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}",
- "pattern_context": "无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。",
- "rules_context": "",
- "citations": {
- "location": [
- "{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}",
- "{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}",
- "{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}"
- ],
- "pattern": [
- "无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。",
- "无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。",
- "地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。"
- ],
- "rules": []
- },
- "resolved_refs": {},
- "precomputed_waypoints": [
- {
- "x": 150.0,
- "y": 260.0,
- "z": 0.0
- }
- ],
- "relative_refs": [],
- "required_actions": [
- "Selector",
- "Sequence",
- "fly_to_waypoint",
- "land",
- "move_direction",
- "object_detect",
- "object_detected",
- "rotate_search",
- "take_photos",
- "takeoff"
- ]
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/stage3_飞到广场东边50米/response.json b/tools/test_validate/validation/temporary/stage3_飞到广场东边50米/response.json
deleted file mode 100644
index cce7602b..00000000
--- a/tools/test_validate/validation/temporary/stage3_飞到广场东边50米/response.json
+++ /dev/null
@@ -1,75 +0,0 @@
-{
- "target_stage": 3,
- "stage_name": "BTDraft",
- "output": {
- "system_prompt": "任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **in_air(空中)** 时,通常的流程包含:方向移动或直接飞行至目标点 -> (执行任务)。**严禁**使用 `system_checks` 与 `takeoff`。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"},\n {\"type\": \"action\", \"name\": \"rotate_search\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"前往广场中心\",\n \"extracted_entities\": {\n \"landmark\": \"广场中心\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n#### 场景 7:空中上升后沿建筑外围侦察(Sequence + Selector)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,无需自检与起飞。先向上移动3米(仅方向+距离,使用`move_direction`)。随后“边飞边判断”:用`Parallel`并行执行`fly_sequence`与持续检测分支。检测分支使用`object_detect` + `object_detected` + `take_photos`,再用`SuccessIsFailure`保证不会提前结束并行;并行策略为`success_on_one`,当巡查飞行完成即结束任务。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndPatrolPerimeter\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"up\",\n \"distance\": 3.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetect\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAndPhotoWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 8:地面起飞到楼前12米高度并沿外围查找杂物(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,需自检后起飞。指令是到具体地点且明确高度,使用`fly_sequence`沿外围巡查,所有航点设置为12米高度(`depth`=12)。为满足“边飞边判断”,使用`Parallel`并行飞行与检测,检测分支持续执行`object_detect` + `object_detected` + `take_photos`,用`SuccessIsFailure`避免提前结束。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 9:地面到12米绕外围查看打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,先自检起飞。随后使用`fly_sequence`沿外围绕飞,航点高度为12米(`depth`=12)。同时并行执行检测分支,发现打开窗户就拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 10:地面到12米沿外围查找打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后使用`fly_sequence`沿外围巡查(`depth`=12),并行持续检测打开的窗户并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAllOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 11:空中上升后绕外围侦察打开窗户(Sequence)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先上升3米。随后并行执行绕飞巡查与检测,发现打开窗户立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndDetectOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"up\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 12:地面到12米绕外围巡视杂物堆积(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测杂物堆积并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbageObserve\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbageObserve\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 13:空中下降后绕外围侦察杂物堆积(Sequence)\n**指令**:“无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先下降3米。随后并行执行绕飞巡查与检测,发现杂物堆积立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"DescendAndDetectGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"down\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 14:地面到12米绕外围查看是否有人(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测人员并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 15:地面到12米沿外围逆时针查找人员(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围逆时针查找所有的人并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后按逆时针顺序巡查外围(示例航点顺序:A→D→C→B→A),并行检测人员与拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterCounterClockwiseAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolCCWAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n## 任务意图标签\n- intent_type: `generic_mission`",
- "user_prompt": "飞到广场东边50米\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n---",
- "allowed_nodes": {
- "actions": [
- "Selector",
- "Sequence",
- "fly_to_waypoint",
- "land",
- "move_direction",
- "object_detect",
- "object_detected",
- "rotate_search",
- "take_photos",
- "takeoff"
- ],
- "conditions": [
- "object_detected"
- ]
- },
- "llm_raw_json": {
- "macro_tree": {
- "root": {
- "type": "Sequence",
- "name": "FlyToSquareEast50",
- "children": [
- {
- "type": "action",
- "name": "fly_to_waypoint"
- }
- ]
- }
- },
- "parameter_requests": [
- {
- "node": "fly_to_waypoint",
- "intent": "前往广场东边50米",
- "extracted_entities": {
- "landmark": "广场",
- "direction": "东",
- "distance": 50.0
- }
- }
- ]
- },
- "macro_tree": {
- "root": {
- "type": "Sequence",
- "name": "FlyToSquareEast50",
- "children": [
- {
- "type": "action",
- "name": "fly_to_waypoint"
- }
- ]
- }
- },
- "parameter_requests": [
- {
- "node": "fly_to_waypoint",
- "intent": "前往广场东边50米",
- "extracted_entities": {
- "landmark": "广场",
- "direction": "东",
- "distance": 50.0
- }
- }
- ],
- "reasoning_text": null,
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **in_air(空中)** 时,通常的流程包含:方向移动或直接飞行至目标点 -> (执行任务)。**严禁**使用 `system_checks` 与 `takeoff`。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"},\n {\"type\": \"action\", \"name\": \"rotate_search\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"前往广场中心\",\n \"extracted_entities\": {\n \"landmark\": \"广场中心\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n#### 场景 7:空中上升后沿建筑外围侦察(Sequence + Selector)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,无需自检与起飞。先向上移动3米(仅方向+距离,使用`move_direction`)。随后“边飞边判断”:用`Parallel`并行执行`fly_sequence`与持续检测分支。检测分支使用`object_detect` + `object_detected` + `take_photos`,再用`SuccessIsFailure`保证不会提前结束并行;并行策略为`success_on_one`,当巡查飞行完成即结束任务。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndPatrolPerimeter\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"up\",\n \"distance\": 3.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetect\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAndPhotoWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 8:地面起飞到楼前12米高度并沿外围查找杂物(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,需自检后起飞。指令是到具体地点且明确高度,使用`fly_sequence`沿外围巡查,所有航点设置为12米高度(`depth`=12)。为满足“边飞边判断”,使用`Parallel`并行飞行与检测,检测分支持续执行`object_detect` + `object_detected` + `take_photos`,用`SuccessIsFailure`避免提前结束。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 9:地面到12米绕外围查看打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,先自检起飞。随后使用`fly_sequence`沿外围绕飞,航点高度为12米(`depth`=12)。同时并行执行检测分支,发现打开窗户就拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 10:地面到12米沿外围查找打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后使用`fly_sequence`沿外围巡查(`depth`=12),并行持续检测打开的窗户并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAllOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 11:空中上升后绕外围侦察打开窗户(Sequence)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先上升3米。随后并行执行绕飞巡查与检测,发现打开窗户立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndDetectOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"up\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 12:地面到12米绕外围巡视杂物堆积(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测杂物堆积并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbageObserve\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbageObserve\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 13:空中下降后绕外围侦察杂物堆积(Sequence)\n**指令**:“无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先下降3米。随后并行执行绕飞巡查与检测,发现杂物堆积立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"DescendAndDetectGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"down\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 14:地面到12米绕外围查看是否有人(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测人员并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 15:地面到12米沿外围逆时针查找人员(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围逆时针查找所有的人并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后按逆时针顺序巡查外围(示例航点顺序:A→D→C→B→A),并行检测人员与拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterCounterClockwiseAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolCCWAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n## 任务意图标签\n- intent_type: `generic_mission`\n\n=== User Prompt ===\n飞到广场东边50米\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n---"
- }
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/plan.png b/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/plan.png
deleted file mode 100644
index dcfa34eb..00000000
Binary files a/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/plan.png and /dev/null differ
diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/process.log b/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/process.log
deleted file mode 100644
index 5e86d323..00000000
--- a/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/process.log
+++ /dev/null
@@ -1,4 +0,0 @@
-Prompt: 无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。
-Status: 200
-Latency: 15.905311346054077
-Response: {"root": {"type": "Sequence", "name": "MainTask", "children": [{"type": "action", "name": "system_checks", "params": {"check_level": "basic"}}, {"type": "action", "name": "takeoff", "params": {"altitude": 2.0}}, {"type": "action", "name": "fly_to_waypoint", "params": {"x": 0.0, "y": 0.0, "z": 0.0, "acceptance_radius": 2.0}}, {"type": "action", "name": "rotate_search", "params": {"target_class": "穿红色衣服的人", "description": "", "step_angle": 10.0, "total_rotation": 360.0}}, {"type": "condition", "name": "object_detected", "params": {"target_class": "穿红色衣服的人", "description": "", "count": 1}}, {"type": "action", "name": "take_photos", "params": {"target_class": "穿红色衣服的人", "description": "", "track_time": 10, "min_confidence": 0.7, "safe_distance": 10}}]}, "plan_id": "4dd158c1-c01d-4ea4-a8a9-ea7759af4185", "visualization_url": "/static/py_tree.png", "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n---"}
diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/response.json b/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/response.json
deleted file mode 100644
index 58f6b74d..00000000
--- a/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/response.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "basic"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 2.0
- }
- },
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 0.0,
- "acceptance_radius": 2.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "穿红色衣服的人",
- "description": "",
- "step_angle": 10.0,
- "total_rotation": 360.0
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "穿红色衣服的人",
- "description": "",
- "count": 1
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "穿红色衣服的人",
- "description": "",
- "track_time": 10,
- "min_confidence": 0.7,
- "safe_distance": 10
- }
- }
- ]
- },
- "plan_id": "4dd158c1-c01d-4ea4-a8a9-ea7759af4185",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/plan.png b/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/plan.png
deleted file mode 100644
index da88f4cd..00000000
Binary files a/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/plan.png and /dev/null differ
diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/process.log b/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/process.log
deleted file mode 100644
index dbc36b36..00000000
--- a/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/process.log
+++ /dev/null
@@ -1,4 +0,0 @@
-Prompt: 无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。
-Status: 200
-Latency: 16.045084238052368
-Response: {"root": {"type": "Sequence", "name": "MainTask", "children": [{"type": "action", "name": "system_checks", "params": {"check_level": "basic"}}, {"type": "action", "name": "takeoff", "params": {"altitude": 2.0}}, {"type": "action", "name": "fly_to_waypoint", "params": {"x": 0.0, "y": 0.0, "z": 100.0, "acceptance_radius": 2.0}}, {"type": "action", "name": "rotate_search", "params": {"target_class": "打开的窗户", "description": "", "step_angle": 10.0, "total_rotation": 360.0}}, {"type": "condition", "name": "object_detected", "params": {"target_class": "打开的窗户", "description": "", "count": 1}}, {"type": "action", "name": "take_photos", "params": {"target_class": "打开的窗户", "description": "", "track_time": 10, "min_confidence": 0.7, "safe_distance": 10}}]}, "context": {"relative_refs": [{"anchor": "front_building", "relation": "front", "distance_m": 12.0}]}, "plan_id": "55402b5a-07e5-41bc-ac73-48e959a512de", "visualization_url": "/static/py_tree.png", "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---"}
diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/response.json b/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/response.json
deleted file mode 100644
index b22795c1..00000000
--- a/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/response.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "basic"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 2.0
- }
- },
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": 0.0,
- "y": 0.0,
- "z": 100.0,
- "acceptance_radius": 2.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "打开的窗户",
- "description": "",
- "step_angle": 10.0,
- "total_rotation": 360.0
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "打开的窗户",
- "description": "",
- "count": 1
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "打开的窗户",
- "description": "",
- "track_time": 10,
- "min_confidence": 0.7,
- "safe_distance": 10
- }
- }
- ]
- },
- "context": {
- "relative_refs": [
- {
- "anchor": "front_building",
- "relation": "front",
- "distance_m": 12.0
- }
- ]
- },
- "plan_id": "55402b5a-07e5-41bc-ac73-48e959a512de",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,起飞/plan.png b/tools/test_validate/validation/temporary/无人机当前在地面,起飞/plan.png
deleted file mode 100644
index f043935c..00000000
Binary files a/tools/test_validate/validation/temporary/无人机当前在地面,起飞/plan.png and /dev/null differ
diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,起飞/process.log b/tools/test_validate/validation/temporary/无人机当前在地面,起飞/process.log
deleted file mode 100644
index 1ee097c1..00000000
--- a/tools/test_validate/validation/temporary/无人机当前在地面,起飞/process.log
+++ /dev/null
@@ -1,4 +0,0 @@
-Prompt: 无人机当前在地面,起飞
-Status: 200
-Latency: 1.738889217376709
-Response: {"root": {"type": "action", "name": "takeoff", "params": {"altitude": 10.0}}, "plan_id": "aad1912a-c27d-4abd-bf62-3179fd61d6aa", "visualization_url": "/static/py_tree.png", "final_prompt": "=== System Prompt (Macro) ===\n你是一个无人机简单指令执行规划器。\n假设输入一定是“单一原子动作即可完成”的简单指令。你的任务是输出一个严格的JSON对象。\n\n输出要求(必须遵守):\n- 只输出一个JSON对象,不要任何解释或多余文本。\n- JSON结构固定为:\n{\"root\":{\"type\":\"action\",\"name\":\"\",\"params\":{...}}}\n- root 节点必须是 action,禁止输出 Sequence/Selector/Parallel 等控制流节点。\n- params 只能包含该动作定义内的字段,禁止自定义字段。\n- 数值请使用数字类型(例如 10.0)。\n\n可用动作(simple 模式只允许从下列动作中选择其一):\n1) takeoff: {\"altitude\": float[1,100]}(仅当地面起飞)\n2) land: {\"mode\": \"current\"|\"home\"}\n3) fly_to_waypoint: {\"x\": number, \"y\": number, \"z\": number, \"acceptance_radius\": number(可选)}\n4) move_direction: {\"direction\": \"north\"|\"south\"|\"east\"|\"west\"|\"forward\"|\"backward\"|\"left\"|\"right\"|\"up\"|\"down\", \"distance\": number}\n5) rotate: {\"angle\": number, \"angular_velocity\": number(可选)}\n6) loiter: {\"duration\": number}\n7) system_checks: {\"check_level\":\"basic\"|\"comprehensive\"}(仅当指令明确在地面且用户要求自检)\n\n示例:\n- “起飞到10米” → {\"root\":{\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}}}\n- “往北飞50米” → {\"root\":{\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"north\",\"distance\":50.0}}}\n- “飞到(120,80,20)” → {\"root\":{\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":120.0,\"y\":80.0,\"z\":20.0,\"acceptance_radius\":2.0}}}\n\n\n=== User Prompt ===\n无人机当前在地面,起飞\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"}
diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,起飞/response.json b/tools/test_validate/validation/temporary/无人机当前在地面,起飞/response.json
deleted file mode 100644
index 02395b01..00000000
--- a/tools/test_validate/validation/temporary/无人机当前在地面,起飞/response.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "root": {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 10.0
- }
- },
- "plan_id": "aad1912a-c27d-4abd-bf62-3179fd61d6aa",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n你是一个无人机简单指令执行规划器。\n假设输入一定是“单一原子动作即可完成”的简单指令。你的任务是输出一个严格的JSON对象。\n\n输出要求(必须遵守):\n- 只输出一个JSON对象,不要任何解释或多余文本。\n- JSON结构固定为:\n{\"root\":{\"type\":\"action\",\"name\":\"\",\"params\":{...}}}\n- root 节点必须是 action,禁止输出 Sequence/Selector/Parallel 等控制流节点。\n- params 只能包含该动作定义内的字段,禁止自定义字段。\n- 数值请使用数字类型(例如 10.0)。\n\n可用动作(simple 模式只允许从下列动作中选择其一):\n1) takeoff: {\"altitude\": float[1,100]}(仅当地面起飞)\n2) land: {\"mode\": \"current\"|\"home\"}\n3) fly_to_waypoint: {\"x\": number, \"y\": number, \"z\": number, \"acceptance_radius\": number(可选)}\n4) move_direction: {\"direction\": \"north\"|\"south\"|\"east\"|\"west\"|\"forward\"|\"backward\"|\"left\"|\"right\"|\"up\"|\"down\", \"distance\": number}\n5) rotate: {\"angle\": number, \"angular_velocity\": number(可选)}\n6) loiter: {\"duration\": number}\n7) system_checks: {\"check_level\":\"basic\"|\"comprehensive\"}(仅当指令明确在地面且用户要求自检)\n\n示例:\n- “起飞到10米” → {\"root\":{\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}}}\n- “往北飞50米” → {\"root\":{\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"north\",\"distance\":50.0}}}\n- “飞到(120,80,20)” → {\"root\":{\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":120.0,\"y\":80.0,\"z\":20.0,\"acceptance_radius\":2.0}}}\n\n\n=== User Prompt ===\n无人机当前在地面,起飞\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/起飞/plan.png b/tools/test_validate/validation/temporary/起飞/plan.png
deleted file mode 100644
index 0da2b820..00000000
Binary files a/tools/test_validate/validation/temporary/起飞/plan.png and /dev/null differ
diff --git a/tools/test_validate/validation/temporary/起飞/process.log b/tools/test_validate/validation/temporary/起飞/process.log
deleted file mode 100644
index c3ec7a15..00000000
--- a/tools/test_validate/validation/temporary/起飞/process.log
+++ /dev/null
@@ -1,4 +0,0 @@
-Prompt: 起飞
-Status: 200
-Latency: 38.906864643096924
-Response: {"root": {"type": "Sequence", "name": "TakeoffAndPatrolBuilding", "children": [{"type": "action", "name": "system_checks", "params": {"check_level": "basic"}}, {"type": "action", "name": "takeoff", "params": {"altitude": 2.0}}, {"type": "Sequence", "name": "FlyAndDetectWindows", "children": [{"type": "action", "name": "fly_to_waypoint", "params": {"x": -24.0, "y": 241.8, "z": 12.0, "acceptance_radius": 2.0}}, {"type": "Parallel", "name": "PatrolAndDetectWindows", "params": {"policy": "success_on_one"}, "children": [{"type": "action", "name": "fly_sequence", "params": {"waypoints": [{"x": -24.0, "y": 241.8, "z": 12.0}, {"x": -108.5, "y": 241.8, "z": 12.0}, {"x": -108.5, "y": 289.8, "z": 12.0}, {"x": -24.0, "y": 292.8, "z": 12.0}, {"x": -24.0, "y": 241.8, "z": 12.0}], "coordinate_frame": "local_enu"}}, {"type": "decorator", "name": "SuccessIsFailure", "child": {"type": "Sequence", "name": "DetectOpenWindowsWhileFlying", "children": [{"type": "action", "name": "object_detect", "params": {"target_class": "window", "description": "打开的窗户"}}, {"type": "condition", "name": "object_detected", "params": {"target_class": "window", "description": "打开的窗户"}}, {"type": "action", "name": "take_photos", "params": {"target_class": "window", "description": "打开的窗户", "track_time": 10.0}}]}}]}]}]}, "plan_id": "e1864626-d71c-49d6-9bc6-fb3d2181dd73", "visualization_url": "/static/py_tree.png", "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n#### 场景 7:空中上升后沿建筑外围侦察(Sequence + Selector)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,无需自检与起飞。先向上移动3米(仅方向+距离,使用`move_direction`)。随后“边飞边判断”:用`Parallel`并行执行`fly_sequence`与持续检测分支。检测分支使用`object_detect` + `object_detected` + `take_photos`,再用`SuccessIsFailure`保证不会提前结束并行;并行策略为`success_on_one`,当巡查飞行完成即结束任务。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndPatrolPerimeter\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"up\",\n \"distance\": 3.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetect\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAndPhotoWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 8:地面起飞到楼前12米高度并沿外围查找杂物(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,需自检后起飞。指令是到具体地点且明确高度,使用`fly_sequence`沿外围巡查,所有航点设置为12米高度(`depth`=12)。为满足“边飞边判断”,使用`Parallel`并行飞行与检测,检测分支持续执行`object_detect` + `object_detected` + `take_photos`,用`SuccessIsFailure`避免提前结束。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 9:地面到12米绕外围查看打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,先自检起飞。随后使用`fly_sequence`沿外围绕飞,航点高度为12米(`depth`=12)。同时并行执行检测分支,发现打开窗户就拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 10:地面到12米沿外围查找打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后使用`fly_sequence`沿外围巡查(`depth`=12),并行持续检测打开的窗户并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAllOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 11:空中上升后绕外围侦察打开窗户(Sequence)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先上升3米。随后并行执行绕飞巡查与检测,发现打开窗户立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndDetectOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"up\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 12:地面到12米绕外围巡视杂物堆积(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测杂物堆积并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbageObserve\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbageObserve\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 13:空中下降后绕外围侦察杂物堆积(Sequence)\n**指令**:“无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先下降3米。随后并行执行绕飞巡查与检测,发现杂物堆积立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"DescendAndDetectGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"down\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 14:地面到12米绕外围查看是否有人(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测人员并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 15:地面到12米沿外围逆时针查找人员(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围逆时针查找所有的人并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后按逆时针顺序巡查外围(示例航点顺序:A→D→C→B→A),并行检测人员与拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterCounterClockwiseAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolCCWAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n## 任务意图标签\n- intent_type: `generic_mission`\n\n=== User Prompt ===\n起飞\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n---"}
diff --git a/tools/test_validate/validation/temporary/起飞/response.json b/tools/test_validate/validation/temporary/起飞/response.json
deleted file mode 100644
index a7cabfe5..00000000
--- a/tools/test_validate/validation/temporary/起飞/response.json
+++ /dev/null
@@ -1,119 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "TakeoffAndPatrolBuilding",
- "children": [
- {
- "type": "action",
- "name": "system_checks",
- "params": {
- "check_level": "basic"
- }
- },
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 2.0
- }
- },
- {
- "type": "Sequence",
- "name": "FlyAndDetectWindows",
- "children": [
- {
- "type": "action",
- "name": "fly_to_waypoint",
- "params": {
- "x": -24.0,
- "y": 241.8,
- "z": 12.0,
- "acceptance_radius": 2.0
- }
- },
- {
- "type": "Parallel",
- "name": "PatrolAndDetectWindows",
- "params": {
- "policy": "success_on_one"
- },
- "children": [
- {
- "type": "action",
- "name": "fly_sequence",
- "params": {
- "waypoints": [
- {
- "x": -24.0,
- "y": 241.8,
- "z": 12.0
- },
- {
- "x": -108.5,
- "y": 241.8,
- "z": 12.0
- },
- {
- "x": -108.5,
- "y": 289.8,
- "z": 12.0
- },
- {
- "x": -24.0,
- "y": 292.8,
- "z": 12.0
- },
- {
- "x": -24.0,
- "y": 241.8,
- "z": 12.0
- }
- ],
- "coordinate_frame": "local_enu"
- }
- },
- {
- "type": "decorator",
- "name": "SuccessIsFailure",
- "child": {
- "type": "Sequence",
- "name": "DetectOpenWindowsWhileFlying",
- "children": [
- {
- "type": "action",
- "name": "object_detect",
- "params": {
- "target_class": "window",
- "description": "打开的窗户"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "window",
- "description": "打开的窗户"
- }
- },
- {
- "type": "action",
- "name": "take_photos",
- "params": {
- "target_class": "window",
- "description": "打开的窗户",
- "track_time": 10.0
- }
- }
- ]
- }
- }
- ]
- }
- ]
- }
- ]
- },
- "plan_id": "e1864626-d71c-49d6-9bc6-fb3d2181dd73",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n#### 场景 7:空中上升后沿建筑外围侦察(Sequence + Selector)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,无需自检与起飞。先向上移动3米(仅方向+距离,使用`move_direction`)。随后“边飞边判断”:用`Parallel`并行执行`fly_sequence`与持续检测分支。检测分支使用`object_detect` + `object_detected` + `take_photos`,再用`SuccessIsFailure`保证不会提前结束并行;并行策略为`success_on_one`,当巡查飞行完成即结束任务。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndPatrolPerimeter\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"up\",\n \"distance\": 3.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetect\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAndPhotoWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 8:地面起飞到楼前12米高度并沿外围查找杂物(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,需自检后起飞。指令是到具体地点且明确高度,使用`fly_sequence`沿外围巡查,所有航点设置为12米高度(`depth`=12)。为满足“边飞边判断”,使用`Parallel`并行飞行与检测,检测分支持续执行`object_detect` + `object_detected` + `take_photos`,用`SuccessIsFailure`避免提前结束。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 9:地面到12米绕外围查看打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,先自检起飞。随后使用`fly_sequence`沿外围绕飞,航点高度为12米(`depth`=12)。同时并行执行检测分支,发现打开窗户就拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 10:地面到12米沿外围查找打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后使用`fly_sequence`沿外围巡查(`depth`=12),并行持续检测打开的窗户并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAllOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 11:空中上升后绕外围侦察打开窗户(Sequence)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先上升3米。随后并行执行绕飞巡查与检测,发现打开窗户立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndDetectOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"up\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 12:地面到12米绕外围巡视杂物堆积(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测杂物堆积并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbageObserve\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbageObserve\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 13:空中下降后绕外围侦察杂物堆积(Sequence)\n**指令**:“无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先下降3米。随后并行执行绕飞巡查与检测,发现杂物堆积立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"DescendAndDetectGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"down\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 14:地面到12米绕外围查看是否有人(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测人员并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 15:地面到12米沿外围逆时针查找人员(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围逆时针查找所有的人并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后按逆时针顺序巡查外围(示例航点顺序:A→D→C→B→A),并行检测人员与拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterCounterClockwiseAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolCCWAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n## 任务意图标签\n- intent_type: `generic_mission`\n\n=== User Prompt ===\n起飞\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n---"
-}
\ No newline at end of file
diff --git a/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/plan.png b/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/plan.png
deleted file mode 100644
index 639983a5..00000000
Binary files a/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/plan.png and /dev/null differ
diff --git a/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/process.log b/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/process.log
deleted file mode 100644
index a470a2da..00000000
--- a/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/process.log
+++ /dev/null
@@ -1,4 +0,0 @@
-Prompt: 起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航
-Status: 200
-Latency: 12.107423305511475
-Response: {"root": {"type": "Sequence", "name": "MainTask", "children": [{"type": "action", "name": "takeoff", "params": {"altitude": 1.0}}, {"type": "action", "name": "move_direction", "params": {"direction": "forward", "distance": 1.0}}, {"type": "action", "name": "rotate_search", "params": {"target_class": "person", "description": "穿迷彩衣服的人"}}, {"type": "condition", "name": "object_detected", "params": {"target_class": "person", "description": "穿迷彩衣服的人"}}, {"type": "action", "name": "approach_target", "params": {"target_class": "person", "description": "穿迷彩衣服的人", "stop_distance": 5.0}}, {"type": "action", "name": "return_emergency", "params": {"reason": "任务完成"}}]}, "plan_id": "fd63525f-41b0-46e4-8405-09278be536ac", "visualization_url": "/static/py_tree.png", "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"}
diff --git a/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/response.json b/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/response.json
deleted file mode 100644
index 132f8050..00000000
--- a/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/response.json
+++ /dev/null
@@ -1,58 +0,0 @@
-{
- "root": {
- "type": "Sequence",
- "name": "MainTask",
- "children": [
- {
- "type": "action",
- "name": "takeoff",
- "params": {
- "altitude": 1.0
- }
- },
- {
- "type": "action",
- "name": "move_direction",
- "params": {
- "direction": "forward",
- "distance": 1.0
- }
- },
- {
- "type": "action",
- "name": "rotate_search",
- "params": {
- "target_class": "person",
- "description": "穿迷彩衣服的人"
- }
- },
- {
- "type": "condition",
- "name": "object_detected",
- "params": {
- "target_class": "person",
- "description": "穿迷彩衣服的人"
- }
- },
- {
- "type": "action",
- "name": "approach_target",
- "params": {
- "target_class": "person",
- "description": "穿迷彩衣服的人",
- "stop_distance": 5.0
- }
- },
- {
- "type": "action",
- "name": "return_emergency",
- "params": {
- "reason": "任务完成"
- }
- }
- ]
- },
- "plan_id": "fd63525f-41b0-46e4-8405-09278be536ac",
- "visualization_url": "/static/py_tree.png",
- "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"
-}
\ No newline at end of file
diff --git a/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/data_level0.bin b/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/data_level0.bin
deleted file mode 100644
index c656b189..00000000
Binary files a/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/data_level0.bin and /dev/null differ
diff --git a/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/header.bin b/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/header.bin
deleted file mode 100644
index e89c5c59..00000000
Binary files a/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/header.bin and /dev/null differ
diff --git a/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/length.bin b/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/length.bin
deleted file mode 100644
index cb3e1628..00000000
Binary files a/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/length.bin and /dev/null differ
diff --git a/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/link_lists.bin b/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/link_lists.bin
deleted file mode 100644
index e69de29b..00000000
diff --git a/tools/vector_store/chroma.sqlite3 b/tools/vector_store/chroma.sqlite3
deleted file mode 100644
index 8972f8b3..00000000
Binary files a/tools/vector_store/chroma.sqlite3 and /dev/null differ