Files
DronePlanning/PIPELINE_GUIDE.md
2026-02-26 19:37:55 +08:00

608 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 PlanningRound 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 FillingRound 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` 可完成入库(或输出可定位错误)