流程节点完善

This commit is contained in:
2026-02-26 19:37:55 +08:00
parent 5d8412bcb6
commit c7f6a0da17
3059 changed files with 4975 additions and 71239 deletions

View File

@@ -7,7 +7,62 @@ class APIClient:
self.base_url = base_url
self.endpoint = "/generate_plan"
def send_request(self, prompt, timeout=60):
def send_debug_stage(
self, prompt: str, drone_state: str = "on_ground", target_stage: int = 1, timeout=120
):
"""
Stage 分阶段调试请求。
target_stage: 1-6
Returns: 同 send_request 结构data 为 debug 端返回的 {target_stage, stage_name, output}
"""
url = f"{self.base_url}/debug_stage"
payload = {
"user_prompt": prompt,
"drone_state": drone_state,
"target_stage": target_stage,
}
headers = {"Content-Type": "application/json"}
start_time = time.time()
try:
response = requests.post(url, json=payload, headers=headers, timeout=timeout)
latency = time.time() - start_time
response.raise_for_status()
try:
data = response.json()
if "error" in data and len(data) == 1:
return {
"success": False,
"data": data,
"latency": latency,
"error": data["error"],
"http_status": response.status_code,
}
return {
"success": True,
"data": data,
"latency": latency,
"error": None,
"http_status": response.status_code,
}
except json.JSONDecodeError:
return {
"success": False,
"data": None,
"latency": latency,
"error": f"Invalid JSON: {response.text[:200]}",
"http_status": response.status_code,
}
except requests.exceptions.RequestException as e:
latency = time.time() - start_time
return {
"success": False,
"data": None,
"latency": latency,
"error": str(e),
"http_status": getattr(e.response, "status_code", None) if hasattr(e, "response") and e.response is not None else None,
}
def send_request(self, prompt, drone_state="on_ground", timeout=60):
"""
Sends a request to the API and returns a structured result.
Returns:
@@ -20,7 +75,7 @@ class APIClient:
}
"""
url = f"{self.base_url}{self.endpoint}"
payload = {"user_prompt": prompt}
payload = {"user_prompt": prompt, "drone_state": drone_state}
headers = {"Content-Type": "application/json"}
start_time = time.time()

View File

@@ -0,0 +1,259 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Stage 分阶段调试模块:支持单条指令调试与批量指令调试。
"""
import os
import json
import csv
import time
import shutil
from datetime import datetime
from .api_client import APIClient
from .visualizer import generate_visualization, sanitize_filename
# Stage 名称映射
STAGE_NAMES = {
1: "Stage1 任务理解 (TaskUnderstanding)",
2: "Stage2 上下文绑定 (ContextBinding)",
3: "Stage3 宏观规划 (BTDraft)",
4: "Stage4 中间层解析 (MiddlewareResolution)",
5: "Stage5 微观填参 (MicroFilling)",
6: "Stage6 校验与后处理 (ValidateAndPostprocess)",
}
def _select_stage():
"""交互式选择调试 stage"""
print("\n可选 Stage:")
for k, v in STAGE_NAMES.items():
print(f" {k}. {v}")
while True:
try:
choice = int(input("请选择 Stage [1-6]: ").strip())
if 1 <= choice <= 6:
return choice
except ValueError:
pass
print("❌ 请输入 1-6 之间的数字")
def _infer_drone_state_from_prompt(prompt: str) -> str:
"""从指令中简单推断 drone_state批量模式下若未单独指定则用此"""
if "在空中" in prompt or "已起飞" in prompt:
return "in_air"
return "on_ground"
def run_stage_debug_single():
"""单条指令 Stage 调试"""
client = APIClient()
print("\n🚀 进入 Stage 分阶段调试 - 单条模式 (输入 'exit''q' 退出)")
while True:
try:
prompt = input("\n请输入测试指令: ").strip()
if prompt.lower() in ("exit", "q"):
break
if not prompt:
continue
target_stage = _select_stage()
drone_state = input("无人机状态 [on_ground/in_air回车默认根据指令推断]: ").strip()
if not drone_state:
drone_state = _infer_drone_state_from_prompt(prompt)
print(f"\n⏳ 运行至 {STAGE_NAMES[target_stage]}...")
result = client.send_debug_stage(
prompt=prompt,
drone_state=drone_state,
target_stage=target_stage,
)
if result["success"]:
print(f"✅ 请求成功 (耗时: {result['latency']:.2f}s)")
data = result["data"]
output = data.get("output", data)
print("\n" + "=" * 60)
print(json.dumps(output, ensure_ascii=False, indent=2))
print("=" * 60)
# 保存到 validation/temporary
base_dir = os.path.dirname(os.path.dirname(__file__))
safe_name = sanitize_filename(prompt)[:80]
out_dir = os.path.join(
base_dir, "validation", "temporary", f"stage{target_stage}_{safe_name}"
)
os.makedirs(out_dir, exist_ok=True)
out_path = os.path.join(out_dir, "response.json")
with open(out_path, "w", encoding="utf-8") as f:
json.dump(result["data"], f, indent=2, ensure_ascii=False)
print(f"\n📂 结果已保存: {out_path}")
# Stage 6 输出含 root 时生成可视化
if target_stage == 6 and isinstance(output, dict) and "root" in output:
png_path = os.path.join(out_dir, "plan.png")
if generate_visualization(output["root"], png_path):
print(f"🖼️ 可视化: {png_path}")
else:
print(f"❌ 请求失败: {result['error']}")
except KeyboardInterrupt:
print("\n已取消")
break
print("\n已返回 Stage 调试菜单")
def run_stage_debug_batch():
"""批量指令 Stage 调试(参考 batch_runner"""
base_dir = os.path.dirname(os.path.dirname(__file__))
instr_dir = os.path.join(base_dir, "instructions")
files = [f for f in os.listdir(instr_dir) if f.endswith(".txt")]
if not files:
print("❌ 未在 instructions 目录下找到 .txt 文件")
return
print("\n请选择测试指令文件:")
for i, f in enumerate(files):
print(f" {i+1}. {f}")
try:
idx = int(input("请输入序号: ").strip()) - 1
if idx < 0 or idx >= len(files):
print("❌ 无效序号")
return
selected_file = os.path.join(instr_dir, files[idx])
except ValueError:
print("❌ 输入无效")
return
target_stage = _select_stage()
drone_state_override = input(
"无人机状态 [回车=每条根据指令推断, on_ground/in_air=全局固定]: "
).strip()
if drone_state_override and drone_state_override not in ("on_ground", "in_air"):
drone_state_override = ""
try:
iterations = int(input("每条指令测试次数 (默认1): ").strip() or "1")
except ValueError:
iterations = 1
# 输出目录
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
output_dir = os.path.join(
base_dir, "validation", f"stage{target_stage}_debug_{timestamp}"
)
os.makedirs(output_dir, exist_ok=True)
shutil.copy(selected_file, os.path.join(output_dir, "instructions_backup.txt"))
with open(selected_file, "r", encoding="utf-8") as f:
instructions = [
line.strip()
for line in f
if line.strip() and not line.startswith("#")
]
print(
f"\n🚀 开始批量 Stage{target_stage} 调试 (共 {len(instructions)} 条, 每条 {iterations} 次)"
)
print(f"📂 输出: {output_dir}\n")
client = APIClient()
detailed_results = []
summary_stats = {}
for i, prompt in enumerate(instructions, 1):
drone_state = (
drone_state_override
if drone_state_override
else _infer_drone_state_from_prompt(prompt)
)
print(f"[{i}/{len(instructions)}] {prompt[:40]}... (state={drone_state})")
safe_name = sanitize_filename(prompt)
instr_out_dir = os.path.join(output_dir, safe_name)
os.makedirs(instr_out_dir, exist_ok=True)
success_count = 0
total_latency = 0
for k in range(1, iterations + 1):
print(f" - 第 {k} 次...", end="", flush=True)
result = client.send_debug_stage(
prompt=prompt,
drone_state=drone_state,
target_stage=target_stage,
)
detailed_results.append(
{
"instruction": prompt,
"run_id": k,
"success": result["success"],
"latency": result["latency"],
"error": result.get("error") or "",
}
)
if result["success"]:
print(f" ✅ ({result['latency']:.2f}s)")
success_count += 1
total_latency += result["latency"]
out_path = os.path.join(instr_out_dir, f"{k}.json")
with open(out_path, "w", encoding="utf-8") as f:
json.dump(result["data"], f, indent=2, ensure_ascii=False)
# Stage6 且含 root 时生成可视化
data = result["data"]
output = data.get("output", data) if isinstance(data, dict) else {}
if (
target_stage == 6
and isinstance(output, dict)
and "root" in output
):
generate_visualization(
output["root"],
os.path.join(instr_out_dir, f"{k}.png"),
)
else:
print(f"{result.get('error', 'Unknown')}")
time.sleep(0.5)
avg_lat = total_latency / success_count if success_count > 0 else 0
summary_stats[prompt] = {
"total_runs": iterations,
"success_runs": success_count,
"success_rate": f"{(success_count / iterations) * 100:.1f}%",
"avg_latency": f"{avg_lat:.2f}s",
}
# 报告
with open(os.path.join(output_dir, "test_details.csv"), "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(
f, fieldnames=["instruction", "run_id", "success", "latency", "error"]
)
writer.writeheader()
writer.writerows(detailed_results)
with open(os.path.join(output_dir, "test_summary.csv"), "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(
["Instruction", "Total Runs", "Success Runs", "Success Rate", "Avg Latency"]
)
for prompt, stats in summary_stats.items():
writer.writerow(
[
prompt,
stats["total_runs"],
stats["success_runs"],
stats["success_rate"],
stats["avg_latency"],
]
)
print(f"\n✅ Stage{target_stage} 批量调试完成! 报告: {output_dir}")

View File

@@ -12,6 +12,7 @@ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from modules.interactive_test import run_interactive_test
from modules.batch_runner import run_batch_test
from modules.json_visualizer import run_json_visualization
from modules.stage_debugger import run_stage_debug_single, run_stage_debug_batch
def clear_screen():
os.system('cls' if os.name == 'nt' else 'clear')
@@ -51,6 +52,34 @@ def run_legacy_module(module_name, args=None):
input("\n按回车键返回菜单...")
def _run_stage_debug_menu():
"""Stage 分阶段调试子菜单"""
while True:
print_header()
print("Stage 分阶段调试")
print("-" * 60)
print("1. 单条指令调试 - 输入指令,选择 Stage查看该 Stage 输出")
print("2. 批量指令调试 - 从文件读取指令,批量运行到选定 Stage")
print("0. 返回主菜单")
print("-" * 60)
sub = input("请选择 [0-2]: ").strip()
if sub == "1":
try:
run_stage_debug_single()
except Exception as e:
print(f"❌ 运行出错: {e}")
input("\n按回车键返回...")
elif sub == "2":
try:
run_stage_debug_batch()
except Exception as e:
print(f"❌ 运行出错: {e}")
input("\n按回车键返回...")
elif sub == "0":
break
else:
print("❌ 无效选项")
def menu_drone_upload():
print("\n[3] 上传任务到无人机")
print("说明: 将生成的任务文件上传到无人机 (Ground Station Client)。")
@@ -84,10 +113,12 @@ def main():
print("3. 上传任务到无人机 (Drone Uploader)")
print("4. LLM 服务连通性测试 (LLM Tester)")
print("5. JSON 文件可视化 (Visualize JSON File)")
print("6. Stage 分阶段调试 (Stage Debug)")
print(" - 单条/批量运行到指定 Stage查看中间输出")
print("0. 退出")
print("-" * 60)
choice = input("请输入选项 [0-5]: ").strip()
choice = input("请输入选项 [0-6]: ").strip()
if choice == '1':
try:
@@ -111,7 +142,10 @@ def main():
elif choice == '5':
run_json_visualization()
elif choice == '6':
_run_stage_debug_menu()
elif choice == '0':
print("\n👋 再见!")
break

View File

@@ -0,0 +1,10 @@
无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。
无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。
无人机当前在空中去飞行场地西边50米对过往穿红色衣服的人拍张照然后返航。
无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。
无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。
无人机当前在空中往飞行场地西边飞50米持续监控5分钟发现人就拍照告诉我到时间可以返航。
无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。
无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。
无人机当前在地面快速去往东边30米有身穿白色衣服头戴帽子的男子在挟持他人对其进行拍照。
无人机当前在空中离白色衣服戴帽子的人太远了照片看不清贴近到3米距离拍拍完可以直接返航。

View File

@@ -0,0 +1,10 @@
无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。
无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。
无人机当前在空中去飞行场地西边50米对过往穿红色衣服的人拍张照然后返航。
无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。
无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。
无人机当前在空中往飞行场地西边飞50米持续监控5分钟发现人就拍照告诉我到时间可以返航。
无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。
无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。
无人机当前在地面快速去往东边30米有身穿白色衣服头戴帽子的男子在挟持他人对其进行拍照。
无人机当前在空中离白色衣服戴帽子的人太远了照片看不清贴近到3米距离拍拍完可以直接返航。

View File

@@ -0,0 +1,9 @@
无人机当前在地面去面前大楼的12米高处绕着外围看有没有打开的窗户发现则进行拍照。
无人机当前在地面去面前大楼的12米高处沿着外围查找所有打开的窗户并拍照。
无人机当前在空中再往上飞3米接着绕这栋楼外围侦察有没有打开的窗户看到了就拍照传回来。
无人机当前在地面去面前大楼的12米高处绕着外围巡视杂物堆积现象发现则进行拍照。
无人机当前在地面去面前大楼的12米高处沿着外围查找所有的杂物堆积并拍照。
无人机当前在空中往下飞3米接着绕这栋楼外围侦察有没有杂物堆积看到了就拍照传回来。
无人机当前在地面去面前大楼的12米高处绕着外围看有没有人发现则进行拍照。
无人机当前在地面去面前大楼的12米高处沿着外围查找所有的人并拍照。
无人机当前在空中再往上飞3米接着绕这栋楼外围侦察有没有人看到了就拍照传回来。

View File

@@ -0,0 +1,10 @@
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,
1 instruction run_id success latency error
2 无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。 1 True 16.063878774642944
3 无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。 1 False 16.235912084579468 500 Server Error: Internal Server Error for url: http://127.0.0.1:8000/generate_plan
4 无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。 1 True 11.32945990562439
5 无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。 1 False 18.68914246559143 500 Server Error: Internal Server Error for url: http://127.0.0.1:8000/generate_plan
6 无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。 1 True 14.857678651809692
7 无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。 1 True 11.974151134490967
8 无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。 1 True 15.218279838562012
9 无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。 1 True 15.252280473709106
10 无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。 1 True 12.335286378860474

View File

@@ -0,0 +1,10 @@
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
1 Instruction Total Runs Success Runs Success Rate Avg Latency
2 无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。 1 1 100.0% 16.06s
3 无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。 1 0 0.0% 0.00s
4 无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。 1 1 100.0% 11.33s
5 无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。 1 0 0.0% 0.00s
6 无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。 1 1 100.0% 14.86s
7 无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。 1 1 100.0% 11.97s
8 无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。 1 1 100.0% 15.22s
9 无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。 1 1 100.0% 15.25s
10 无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。 1 1 100.0% 12.34s

View File

@@ -0,0 +1,11 @@
无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。
无人机当前在空中,回到广场,对戴帽子的人进行拍照。
无人机当前在空中去广场南边40米对过往的公交车拍张照然后返航。
无人机当前在地面,到广场查找绿色公交车,看见了拍个照片。
无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。
无人机当前在空中,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航。
无人机当前在空中往广场南边飞40米持续监控5分钟发现人就拍照告诉我到时间可以返航。
无人机当前在地面,到广场边上的施工区域内,发现有没带安全帽的飞近后拍照。
无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。
无人机当前在地面快速去往东边60米有身穿白色衣服头戴帽子的男子在挟持他人对其进行拍照。
无人机当前在空中离白色衣服戴帽子的人太远了照片看不清贴近到3米距离拍拍完可以直接返航。

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,17 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,15 @@
{
"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": {}
}
}

View File

@@ -0,0 +1,43 @@
{
"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"
]
}
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@@ -0,0 +1,4 @@
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\":\"<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---"}

View File

@@ -0,0 +1,12 @@
{
"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\":\"<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---"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long