# DronePlanning 处理 Pipeline 说明 本文档说明当前后端从自然语言输入到计划 JSON 输出的完整处理流程,以及可自定义修改点。 ## 1. 总体流程 入口为 `POST /generate_plan`,主链路由 `GenerationOrchestrator` 编排: ```mermaid flowchart LR api[main.py /generate_plan] --> gen[py_tree_generator.generate] gen --> orch[GenerationOrchestrator] orch --> s1[Stage1 TaskUnderstanding] orch --> s2[Stage2 ContextBinding] orch --> s3[Stage3 MacroPlanning] s3 --> simple{simple?} simple -->|是| s6[Stage6 Validate] simple -->|否| s4[Stage4 Middleware] s4 --> s5[Stage5 MicroFilling] s5 --> s6 s6 --> out[返回 py_tree JSON] ``` 对应代码: - `backend_service/src/main.py` - `backend_service/src/py_tree_generator.py` - `backend_service/src/pipeline/orchestrator.py` - `backend_service/src/pipeline/stages.py` ### 1.1 各 Stage 提示词模板一览 | Stage | 是否调用 LLM | System 模板/片段(按组合顺序) | User 内容 | |-------|----------------|--------------------------------|------------| | Stage1 | 是 | `prompts/scene_classifier_prompt.txt` | 原始 `user_prompt` | | Stage2 | 否 | — | — | | Stage3 | 是 | **simple**:`simple_mode_prompt.txt`;**complex**:`macro_header.txt` → 裁剪的 `core_nodes.json` → `template_ground.txt` / `template_air.txt` → `common_rules.txt` → 可选 `system_extra_examples.txt` → 意图标签 | `user_prompt` + 参考知识(地点/模式/规则) | | Stage4 | 否 | — | — | | Stage5 | 是 | `micro_header.txt` → macro_tree JSON → resolved_data JSON → 裁剪的 `atomic/nodes_schema.json` | 固定句:「请直接输出完整的带有 params 参数的 JSON 树结构。」 | | Stage6 | 否 | — | — | 各阶段模板的详细组合顺序与条件见对应小节(如 2.3、3.3、4.3、5.3、6.3、7.3)。 ### 1.2 提示词分配流程图 下图按 Stage 标出各阶段使用的提示词模板及组合关系(仅含涉及 LLM 的 Stage): ```mermaid flowchart TB subgraph S1["Stage1 任务理解"] direction TB P1_sys["system: scene_classifier_prompt.txt"] P1_usr["user: user_prompt"] end subgraph S2["Stage2 上下文绑定"] P2["无 LLM / 无提示词"] end subgraph S3["Stage3 宏观规划"] direction TB P3a["simple: system = simple_mode_prompt.txt"] P3b["complex: system = macro_header → core_nodes → template_ground/air → common_rules → 可选 system_extra_examples → 意图标签"] P3_usr["user: user_prompt + 参考知识"] end subgraph S4["Stage4 中间层解析"] P4["无 LLM / 无提示词"] end subgraph S5["Stage5 微观填参"] direction TB P5_sys["system: micro_header → macro_tree JSON → resolved_data JSON → atomic/nodes_schema 裁剪"] P5_usr["user: 固定句"] end subgraph S6["Stage6 校验与后处理"] P6["无 LLM / 无提示词"] end S1 --> S2 --> S3 S3 --> S4 --> S5 --> S6 ``` - **Stage1 / Stage3 / Stage5** 会调用 LLM,其 System/User 内容由上图对应框内模板或片段组合而成。 - **Stage2 / Stage4 / Stage6** 不调用 LLM,无提示词分配。 --- ## 2. Stage1:任务理解(TaskUnderstanding) 功能: - 场景分类:`simple / scene1 / scene4` - 意图推断:`intent_type` - 风险标记:`risk_flags`(例如是否需要人工确认、是否涉及相对方位) 核心代码: - `backend_service/src/llm/gateway.py::classify_scene()` - `backend_service/src/pipeline/stages.py::_infer_intent_type()` - `backend_service/src/pipeline/stages.py::_extract_risk_flags()` - 数据契约:`backend_service/src/pipeline/contracts.py::TaskUnderstanding` 说明: - 分类模型可启用 thinking(由 `STAGE1_ENABLE_THINKING` 控制)。 - 该阶段不依赖节点字典,避免循环依赖。 ### 2.1 输入格式 `stage1_task_understanding(user_prompt: str)` 仅接受原始用户指令字符串。 示例输入: ```json { "user_prompt": "无人机当前在地面,到广场查找绿色公交车,找到后拍照。" } ``` ### 2.2 输出格式(TaskUnderstanding) ```json { "scene_mode": "scene4", "intent_type": "search_and_photo", "requires_relative_target": false, "entities": { "raw_prompt": "无人机当前在地面,到广场查找绿色公交车,找到后拍照。" }, "risk_flags": [], "constraints": {} } ``` 字段说明: - `scene_mode`: `simple | scene1 | scene4` - `intent_type`: 当前规则推导出的任务意图标签 - `requires_relative_target`: 是否检测到相对方位需求 - `entities`: 当前为轻量占位(最小包含 `raw_prompt`) - `risk_flags`: 风险标记列表(如 `needs_manual_confirmation`) - `constraints`: 约束占位(当前为空对象) ### 2.3 本阶段组合的提示词模板 | 角色 | 模板文件 | 路径 | 说明 | |--------|----------|------|------| | system | 场景分类 | `prompts/scene_classifier_prompt.txt` | 唯一 system 提示词,定义 simple/scene1/scene4 判定规则与示例 | | user | 用户原文 | 调用方传入的 `user_prompt` | 不做拼接,直接作为 user 消息 | 组合方式:`messages = [ { "role": "system", "content": scene_classifier_prompt }, { "role": "user", "content": user_prompt } ]`。分类结果解析为 `scene_mode`,其余 `intent_type`、`risk_flags` 由本阶段规则函数从 `user_prompt` 推断,不读模板。 ## 3. Stage2:上下文绑定(ContextBinding) 功能: - 按场景动态决定检索范围(location/pattern/rules) - 从多知识库并行检索并汇总 - 相对目标提取(`relative_refs`) - 预计算航点(`precomputed_waypoints`,MVP) - 基于意图与风险推导 `required_actions` 核心代码: - `backend_service/src/retrieval/retriever.py::UnifiedRetriever` - `backend_service/src/retrieval/adapters/chroma_adapter.py` - `backend_service/src/llm/tool_runtime.py` - `backend_service/src/pipeline/stages.py::stage2_context_binding()` - 数据契约:`backend_service/src/pipeline/contracts.py::ContextBinding` 多知识库策略: - 主集合:`location_kb`、`pattern_kb`、`rules_kb` - 兼容集合:`drone_docs` - 若主集合无结果,会尝试从 `drone_docs` + `kb_type` 过滤回退查询 ### 3.1 输入格式 该阶段接收: - `user_prompt: str` - Stage1 输出 `TaskUnderstanding` 示例输入: ```json { "user_prompt": "无人机当前在空中,去广场南边40米,持续监控5分钟,发现人就拍照。", "understanding": { "scene_mode": "scene4", "intent_type": "patrol_or_monitor", "requires_relative_target": false, "risk_flags": [], "entities": {"raw_prompt": "无人机当前在空中,去广场南边40米,持续监控5分钟,发现人就拍照。"}, "constraints": {} } } ``` ### 3.2 输出格式(ContextBinding) ```json { "location_context": "地点:广场,坐标(x=120,y=30,z=0)...", "pattern_context": "示例:先到达命名地点,再监控,再条件触发拍照...", "rules_context": "", "citations": { "location": ["..."], "pattern": ["..."], "rules": [] }, "resolved_refs": {}, "precomputed_waypoints": [ {"x": 160.0, "y": 30.0, "z": 10.0} ], "relative_refs": [], "required_actions": [ "Sequence", "fly_to_waypoint", "loiter", "object_detect", "object_detected", "take_photos" ] } ``` 字段说明: - `*_context`: 分知识域拼接后的文本上下文 - `citations`: 每个知识域的原始命中文档片段 - `precomputed_waypoints`: Stage2 静态可解析时的预计算坐标 - `relative_refs`: 相对目标结构化描述 - `required_actions`: 后续用于节点裁剪注入的动作白名单 ### 3.3 本阶段组合的提示词模板 本阶段**不调用 LLM**,无提示词模板。仅做检索(Location/Pattern/Rules)、规则推导(`required_actions`、`relative_refs`)、预计算航点。 --- ## 4. Stage3:宏观规划(Macro Planning,Round 1) 功能: - 组装 prompt(骨架 + 节点裁剪 + 模板 + 规则 + 检索结果) - 调用对应模型生成宏观树(及可选的 parameter_requests) - 解析模型响应(含 reasoning 提取) 核心代码: - `backend_service/src/prompting/composer.py::PromptComposer.compose_macro()` - `backend_service/src/llm/gateway.py::generate_json()` - `backend_service/src/pipeline/stages.py::stage3_macro_planning()` - 数据契约:`backend_service/src/pipeline/contracts.py::BTDraft` 关键行为: - simple 模式与复杂模式使用不同客户端/模型配置;Stage3 强制关闭 thinking,强制 `response_format=json_object`;节点定义采用裁剪注入(非全量注入)。 ### 4.1 输入格式(Stage3) 该阶段接收: - `user_prompt: str` - `TaskUnderstanding` - `ContextBinding` 核心输入(示例): ```json { "scene_mode": "scene4", "intent_type": "search_and_photo", "required_actions": ["Sequence", "fly_to_waypoint", "rotate_search", "object_detected", "take_photos"], "risk_flags": [], "context_blocks": { "location": "地点:广场...", "pattern": "示例:先到达再搜索...", "rules": "" } } ``` ### 4.2 输出格式(BTDraft) ```json { "system_prompt": "...(裁剪后的系统提示词)...", "user_prompt": "原始指令 + 参考知识增强段", "allowed_nodes": { "actions": ["fly_to_waypoint", "rotate_search", "take_photos"], "conditions": ["object_detected"] }, "llm_raw_json": { "root": { "type": "Sequence", "name": "Sequence", "children": [ {"type": "action", "name": "fly_to_waypoint", "params": {"x": 120, "y": 30, "z": 10, "acceptance_radius": 2}}, {"type": "action", "name": "rotate_search", "params": {"target_class": "bus"}}, {"type": "condition", "name": "object_detected", "params": {"target_class": "bus"}}, {"type": "action", "name": "take_photos", "params": {"target_class": "bus", "track_time": 8}} ] } }, "reasoning_text": null, "final_prompt": "=== System Prompt === ... === User Prompt === ..." } ``` 字段说明: - `system_prompt/user_prompt`: 实际发给模型的提示词 - `allowed_nodes`: 节点裁剪结果(用于调试与复盘) - `llm_raw_json`: 模型返回并解析后的原始计划 JSON - `reasoning_text`: 可选推理文本(若模型返回) - `final_prompt`: 完整组合记录(便于离线排查) ### 4.3 本阶段组合的提示词模板 **simple 模式**(单轮,直接出最终树): | 角色 | 模板/内容 | 路径 | 说明 | |--------|------------|------|------| | system | 简单模式全文 | `prompts/simple_mode_prompt.txt` | 直接作为 system,无拼接 | | user | 用户原文 + 参考知识 | 动态 | `user_prompt` + `_build_user_augmentation(context_blocks)` | **复杂模式**(scene1/scene4,宏观树 Round 1): System 按**顺序**拼接以下内容(来自 `prompting/composer.py::compose_macro()`): | 顺序 | 模板/内容 | 路径 | 说明 | |------|-----------|------|------| | 1 | 宏观任务头 | `prompts/partials/macro_header.txt` | 任务定义与输出要求 | | 2 | 节点定义(裁剪后) | `prompts/partials/core_nodes.json` | 按 `required_actions` + `risk_flags` 裁剪,最多 30 个 action/condition,格式化为「## 一、核心节点定义」+ JSON 代码块 | | 3 | 任务模板(二选一) | `prompts/partials/template_ground.txt` 或 `prompts/partials/template_air.txt` | 由 `drone_state`(on_ground / in_air)决定 | | 4 | 通用规则 | `prompts/partials/common_rules.txt` | 若文件存在则追加 | | 5 | 额外示例(可选) | `prompts/partials/system_extra_examples.txt` | 仅当 `intent_type == "generic_mission"` 时追加 | | 6 | 意图标签 | 代码生成 | 固定段落:`## 任务意图标签\n- intent_type: \`{intent_type}\`` | User 消息: - 内容 = `user_prompt` + 参考知识增强段。 - 参考知识增强段由 `_build_user_augmentation(context_blocks)` 生成:若 `context_blocks` 中 `location` / `pattern` / `rules` 非空,则按顺序拼接为「【地点知识】…」「【任务模式】…」「【规则知识】…」,整体包在 `---\n参考知识:\n…\n---` 中。 --- ## 5. Stage4:中间层解析(Middleware Resolution) 功能: - 读取 Stage3 输出的 `parameter_requests` - 对含 `landmark` 等实体的请求做位置检索与航点预计算,写入 `resolved_data` - 其他实体透传为 `{node}_entities`,供 Stage5 使用 核心代码: - `backend_service/src/pipeline/stages.py::stage4_middleware_resolution()` - 复用 `retriever.retrieve(scopes=["location"])` 与 `tool_runtime.build_precomputed_waypoint()` ### 5.3 本阶段组合的提示词模板 本阶段**不调用 LLM**,无提示词模板。仅做依赖解析与数据绑定。 --- ## 6. Stage5:微观参数填空(Micro Parameter Filling,Round 2) 功能: - 从 `prompts/atomic/nodes_schema.json` 按宏观树中用到的节点名裁剪出 `atomic_schema` - 调用 `PromptComposer.compose_micro()` 组装 Round 2 的 system 提示词 - 再次调用模型,输出带完整 `params` 的 JSON 树 核心代码: - `backend_service/src/prompting/composer.py::compose_micro()` - `backend_service/src/pipeline/stages.py::stage5_micro_filling()` ### 6.3 本阶段组合的提示词模板 | 角色 | 模板/内容 | 路径 | 说明 | |--------|------------|------|------| | system | 微观任务头 | `prompts/partials/micro_header.txt` | 第一段 | | system | 宏观骨架树 | 运行时 | `## 1. 原宏观骨架树 (macro_tree)` + `draft.macro_tree` 的 JSON | | system | 确切数据字典 | 运行时 | `## 2. 确切数据字典 (resolved_data)` + Stage4 输出的 `resolved_data` JSON | | system | 原子节点规范 | `prompts/atomic/nodes_schema.json`(按需裁剪) | `## 3. 原子节点规范 (atomic_schema)`;仅保留宏观树中出现的 action/condition 的 schema | | user | 固定指令 | 代码写死 | `"请直接输出完整的带有 params 参数的 JSON 树结构。"` | 组合方式:system = 上述四段用 `\n\n` 拼接;user = 固定字符串。Round 2 不再注入 RAG 检索块。 --- ## 7. Stage6:校验与后处理(ValidateAndPostprocess) 功能: - JSON Schema 校验(simple / complex) - 注入 `plan_id`、`visualization_url`、`final_prompt` - 保存推理链与历史记录 - 在复杂场景下注入 `context.relative_refs`(及可选 `context.resolved_refs`) 核心代码: - `backend_service/src/validation/validator.py` - `backend_service/src/validation/schema_provider.py` - `backend_service/src/pipeline/stages.py::stage6_validate_and_postprocess()` - `backend_service/src/py_tree_generator.py::render_visualization()` - `backend_service/src/py_tree_generator.py::_save_history()` ### 7.1 输入格式 该阶段接收: - `user_prompt: str` - `TaskUnderstanding` - `ContextBinding` - `BTDraft` - 复杂模式下还有 Stage5 的 `final_tree`;simple 模式下为 `draft.llm_raw_json` ### 7.2 输出格式(最终 API 返回) 复杂模式示例: ```json { "root": { "type": "Sequence", "name": "Sequence", "children": [ {"type": "action", "name": "fly_to_waypoint", "params": {"x": 120, "y": 30, "z": 10, "acceptance_radius": 2}}, {"type": "action", "name": "rotate_search", "params": {"target_class": "bus"}}, {"type": "condition", "name": "object_detected", "params": {"target_class": "bus"}}, {"type": "action", "name": "take_photos", "params": {"target_class": "bus", "track_time": 8}} ] }, "context": { "relative_refs": [ {"anchor": "front_building", "relation": "left", "distance_m": 20.0} ], "resolved_refs": { "strategy": "backend_static_resolution", "waypoints": [{"x": 120.0, "y": 30.0, "z": 10.0}] } }, "plan_id": "6a924d0d-f1a7-4ef1-a9fa-31f73f3115ce", "visualization_url": "/static/py_tree.png", "final_prompt": "=== System Prompt === ... === User Prompt === ..." } ``` simple 模式示例: ```json { "root": { "type": "action", "name": "move_direction", "params": {"direction": "north", "distance": 50} }, "plan_id": "0f0e5e5f-b9a2-4e6f-95f5-c95e9e6280a5", "visualization_url": "/static/py_tree.png", "final_prompt": "=== System Prompt === ... === User Prompt === ..." } ``` 字段说明: - `root`: 通过 schema 校验后的行为树根节点 - `context`: 仅在复杂模式且命中相对目标时追加 - `plan_id`: 每次生成唯一 ID - `visualization_url`: 最新可视化图访问路径 - `final_prompt`: 生成时使用的完整提示词记录 ### 7.3 本阶段组合的提示词模板 本阶段**不调用 LLM**,无提示词模板。仅做校验、注入元数据与写盘。 --- ## 8. 数据入库(RAG Ingestion)逻辑 入库脚本: - `tools/rag/ingest.py` 行为: - 扫描 `tools/rag/knowledge_base/` - 根据子目录推断 `kb_type`(location/pattern/rules) - 同时写入: - `drone_docs`(兼容) - `location_kb` / `pattern_kb` / `rules_kb`(新检索路径) ## 9. 可自定义修改点(推荐按优先级) ### 9.1 场景与意图逻辑 可改文件: - `backend_service/src/pipeline/stages.py` 可改内容: - `_infer_intent_type()`:扩展意图类别 - `_extract_risk_flags()`:新增风险规则 - `_derive_required_actions()`:调整规则推导的动作集合 ### 9.2 Prompt 策略 可改文件: - `backend_service/src/prompting/composer.py` - `backend_service/src/prompts/prompt_manifest.yaml` - `backend_service/src/prompts/partials/*` 可改内容: - 骨架片段选择 - 节点裁剪规则(当前上限 30) - 示例注入策略(何时注入 extra examples) - 用户侧检索增强格式 ### 9.3 模型路由与推理参数 可改文件: - `backend_service/src/llm/gateway.py` 可改内容: - 分类模型与生成模型分流策略 - `temperature`、`max_tokens`、重试次数 - thinking 开关策略(Stage1/Stage3) ### 9.4 检索策略 可改文件: - `backend_service/src/retrieval/retriever.py` - `backend_service/src/retrieval/adapters/chroma_adapter.py` - `tools/rag/ingest.py` 可改内容: - 检索并发策略与 `top_k` - 回退策略(主集合与兼容集合) - kb_type 划分方式 - 文档切分与 metadata 设计 ### 9.5 相对目标解析 可改文件: - `backend_service/src/pipeline/stages.py` - `backend_service/src/llm/tool_runtime.py` 可改内容: - `relative_refs` 抽取规则 - 静态解析能力(何时生成 `resolved_refs`) - 与 UAV 端协议字段兼容策略 ### 9.6 校验与输出协议 可改文件: - `backend_service/src/validation/validator.py` - `backend_service/src/validation/schema_provider.py` - `backend_service/src/py_tree_generator.py`(schema 来源) 可改内容: - simple/complex schema 约束强度 - 顶层 `context` 字段的可选校验 - 失败错误信息与恢复策略 ## 10. 关键环境变量 - `ORIN_IP` - `OPENAI_API_KEY` - `CLASSIFIER_MODEL` / `SIMPLE_MODEL` / `COMPLEX_MODEL` - `CLASSIFIER_BASE_URL` / `SIMPLE_BASE_URL` / `COMPLEX_BASE_URL` - `STAGE1_ENABLE_THINKING` - `ENABLE_REASONING_CAPTURE` - `REASONING_PREVIEW_LINES` ## 11. 自定义改造建议(实践顺序) 1. 先改 Stage1 规则推导(低风险,收益快) 2. 再改 PromptComposer 的裁剪与注入(控制长度与稳定性) 3. 再改检索策略(top_k、回退、metadata) 4. 最后改 schema 与输出协议(需联动执行端) ## 12. 变更后最小回归清单 每次改造后至少验证: 1. simple 指令:返回 `root.action`,且无 children 2. scene4 指令:有复合树结构,JSON 可解析 3. relative 指令:复杂模式下出现 `context.relative_refs` 4. `/generate_plan` 不变更接口字段(兼容外部调用) 5. `python tools/rag/ingest.py` 可完成入库(或输出可定位错误)