# 对话场景遍历文档 > 从 `agent/graph.py` 状态图递归遍历生成,覆盖所有用户意图 → 节点路径 → 退出条件。 > 最后更新: 2026-05-24 --- ## 状态图总览 ``` ┌──────────────────────────────────────────────────┐ │ 修正循环 (最多 MAX_RETRY=5 次) │ │ ┌─────────┐ ┌──────────────┐ ┌────────┐ │ │ │ validate │───→│ explain_error│───→│correct │ │ │ └────┬─────┘ └──────────────┘ │_jrxml │ │ │ │ pass └───┬────┘ │ │ ▼ │ │ │ ┌─────────┐ retry<5 │ │ │finalize │◄────────────────────────────────┘ │ │ └─────────┘ retry>=5 │ └──────────────────────────────────────────────────┘ load_session ──→ process_input ──→ manage_context ──→ save_state_snapshot │ ▼ classify_intent │ ┌────────────┬──────────┬────────┬───────────┼───────────┬──────────┐ ▼ ▼ ▼ ▼ ▼ ▼ ▼ retrieve modify_jrxml save_ handle_ handle_ handle_ (兜底) (新建报表) (修改报表) session consult undo reset │ │ (预览) (咨询) (撤销) (重置) ┌────────┴────┐ │ │ │ │ │ ▼ ▼ │ │ │ │ │ generate generate_ │ │ │ │ │ (1-shot) skeleton │ │ │ │ │ │ │ │ │ │ │ │ │ refine_ │ │ │ │ │ │ layout │ │ │ │ │ │ │ │ │ │ │ │ │ map_fields │ │ │ │ │ │ │ │ │ │ │ │ └──────┬──────┘ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ▼ save_session ◄─────┴──────────┘ finalize ◄─── finalize ◄── finalize │ ▲ │ (预览/导出跳过验证) │ ├───────────────────────────────────────┘ │ (其他意图走验证) ▼ validate ──→ explain_error ──→ correct_jrxml ──→ validate (循环) │ pass │ retry>=MAX ▼ ▼ finalize ────────────────────────────────→ finalize ``` --- ## 节点详细清单 每个节点标注了 **代码行号** (`agent/nodes.py` 或 `agent/graph.py`)、**前驱节点** (predecessors)、**后继节点** (successors)。 ### 1. load_session — 加载会话 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:77` | | 前驱 | (入口节点, graph entry_point) | | 后继 | `process_input` (固定边 graph.py:198) | | 功能 | 从 `sessions/{session_id}.json` 磁盘加载状态,注入 agent_state。不从磁盘覆盖 `session_id`。 | | LLM | 否 | ### 2. process_input — 处理用户输入 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:98` | | 前驱 | `load_session` (graph.py:198) | | 后继 | `manage_context` (graph.py:199) | | 功能 | 文件解析(PDF/DOCX/XLSX/图片/文本)→ OCR 字段提取 → 批注检测 → 模板 JRXML 解析。注入 `ocr_extraction_result`、`layout_schema`、`ocr_elements`、`uploaded_template_jrxml`。 | | LLM | 否(OCR 用 PaddleOCR/EasyOCR) | ### 3. manage_context — 上下文管理 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:143` | | 前驱 | `process_input` (graph.py:199) | | 后继 | `save_state_snapshot` (graph.py:200) | | 功能 | Token 计数 → 对话压缩(超限时 LLM 压缩为摘要)→ `compressed_history`。 | | LLM | 是(压缩时调 LLM) | ### 4. save_state_snapshot — 状态快照 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:191` | | 前驱 | `manage_context` (graph.py:200) | | 后继 | `classify_intent` (graph.py:201) | | 功能 | 深拷贝当前状态 → 推入 `history_states` 列表。最多保留 5 个快照。撤销时恢复到最新快照。 | | LLM | 否 | ### 5. classify_intent — 意图分类 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:200` | | 前驱 | `save_state_snapshot` (graph.py:201) | | 后继 | 6 路条件分发 (graph.py:204-215) | | 功能 | LLM 分类用户意图为 8 种之一。prompt: `prompts/intent_classify.md`。 | | LLM | 是 | | 路由函数 | `route_by_intent` (graph.py:67) | **分类逻辑与路由目标**: | 意图值 | 路由目标 | 说明 | |--------|---------|------| | `initial_generation` | → `retrieve` | 新建报表 | | `modify_report` | → `modify_jrxml` | 修改现有报表 | | `preview_report` | → `save_session` | 预览(跳过生成) | | `export_pdf` | → `save_session` | 导出 PDF(跳过生成) | | `export_jrxml` | → `save_session` | 下载 JRXML(跳过生成) | | `consult_question` | → `handle_consult` | 咨询问答 | | `undo_modification` | → `handle_undo` | 撤销 | | `reset_session` | → `handle_reset` | 重置 | | 未知/兜底 | 有 `current_jrxml` → `modify_jrxml`; 无 → `retrieve` | | ### 6. retrieve — RAG/知识库检索 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:442` | | 前驱 | `classify_intent` (graph.py:204-215, intent=initial_generation) | | 后继 | 条件分发: `generate_skeleton` 或 `generate` (graph.py:218-224) | | 功能 | ① ErrorKB 检索历史修正案例 → ② KB 模板检索 → ③ KB 字段定义检索。注入 `retrieved_context`、`kb_template_jrxml`、`kb_fields`。 | | LLM | 否(向量搜索 + 字段匹配) | | 路由函数 | `route_after_retrieve` (graph.py:94) | **路由逻辑** (`route_after_retrieve`, graph.py:94-99): - `layout_schema.total_rows > 0` → `generate_skeleton` (3 阶段) - 否则 → `generate` (1-shot) ### 7. generate — 1-shot 生成 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:578` | | 前驱 | `retrieve` (graph.py:218-224, 无 layout_schema 时) | | 后继 | `save_session` (graph.py:227-231) | | 功能 | LLM 一次生成完整 JRXML。注入 OCR 上下文 + 模板上下文。流式输出。截断时续写(最多 3 轮)。 | | LLM | 是 | | Prompt | `prompts/initial_generation.md` | ### 8. generate_skeleton — 骨架生成(3 阶段-1) | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:657` | | 前驱 | `retrieve` (graph.py:218-224, 有 layout_schema 时) | | 后继 | `refine_layout` (固定边 graph.py:233) | | 功能 | 压缩布局 schema → LLM 生成骨架 JRXML。字段用 `$F{field_N}` 占位。流式输出 + 续写。 | | LLM | 是 | | Prompt | `prompts/skeleton_generation.md` | ### 9. refine_layout — 坐标精调(3 阶段-2) | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:879` | | 前驱 | `generate_skeleton` (graph.py:233) | | 后继 | `map_fields` (固定边 graph.py:234) | | 功能 | ① `decompose_jrxml()` 拆解为 header + bands → ② 每个 band 窗口化(>4000 字符切分)→ ③ 逐窗口 LLM 精调坐标 → ④ `reassemble_jrxml()` 重组 → ⑤ `validate_element_count()` 校验(>10% 回退)。header 完全不发给 LLM。 | | LLM | 是(N 次,N = band 窗口数) | | Prompt | `prompts/refine_layout.md` | ### 10. map_fields — 字段映射(3 阶段-3) | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:978` | | 前驱 | `refine_layout` (graph.py:234) | | 后继 | `save_session` (graph.py:235-239) | | 功能 | 纯程序化正则替换 `$F{field_N}` → OCR 真实字段名。`_sanitize_field_name()` 净化非 ASCII 字符。零 LLM 调用。 | | LLM | 否 | ### 11. modify_jrxml — 修改报表 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:1022` | | 前驱 | `classify_intent` (graph.py:204-215, intent=modify_report) | | 后继 | `save_session` (graph.py:242-246) | | 功能 | 基于现有 JRXML + 用户修改描述 + OCR 上下文 + 模板上下文 → LLM 修改。流式输出 + 续写。空响应守卫。 | | LLM | 是 | | Prompt | `prompts/modification.md` | ### 12. handle_consult — 咨询解答 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:261` | | 前驱 | `classify_intent` (graph.py:204-215, intent=consult_question) | | 后继 | `finalize` (固定边 graph.py:280) | | 功能 | LLM 回答 JasperReports 相关知识问题。回答写入 `conversation_history`。 | | LLM | 是 | | Prompt | `prompts/consult.md` | ### 13. handle_undo — 撤销 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:281` | | 前驱 | `classify_intent` (graph.py:204-215, intent=undo_modification) | | 后继 | `save_session` (graph.py:249-253) | | 功能 | 从 `history_states` 弹出最近快照,恢复 `current_jrxml`、`conversation_history`、`status`。无快照时提示"无可撤销状态"。 | | LLM | 否 | ### 14. handle_reset — 重置 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:309` | | 前驱 | `classify_intent` (graph.py:204-215, intent=reset_session) | | 后继 | `finalize` (固定边 graph.py:281) | | 功能 | 清空所有状态到 `create_initial_state()` 默认值(保留 `session_id`、`session_name`)。 | | LLM | 否 | ### 15. save_session — 保存会话 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:325` | | 前驱 | `generate`、`map_fields`、`modify_jrxml`、`handle_undo`、`classify_intent`(预览/导出) | | 后继 | 条件分发: `validate` 或 `finalize` (graph.py:256-260) | | 功能 | 原子持久化会话 JSON (`tempfile + os.replace`)。序列化 `agent_state` 到 `sessions/{session_id}.json`。 | | LLM | 否 | | 路由函数 | `route_after_save` (graph.py:118) | **路由逻辑** (`route_after_save`, graph.py:118-123): - `intent in (preview_report, export_pdf, export_jrxml)` → `finalize` (跳过验证) - 其他 → `validate` ### 16. validate — 验证 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:1235` | | 前驱 | `save_session` (graph.py:256-260)、`correct_jrxml` (graph.py:273-277) | | 后继 | 条件分发: `finalize` 或 `explain_error` (graph.py:263-267) | | 功能 | ① 结构检查(字段引用一致性/SQL 存在/pageWidth/pageHeight/name)→ ② XSD 校验(可选)→ ③ 像素对比(有上传图片时 Java 渲染 JRXML→PNG + OpenCV SSIM)。 | | LLM | 否 | | 路由函数 | `route_after_validate` (graph.py:127) | **路由逻辑** (`route_after_validate`, graph.py:127-131): - `status == "pass"` → `finalize` - `status == "fail"` → `explain_error` ### 17. explain_error — 错误解释 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:1310` | | 前驱 | `validate` (graph.py:263-267, status=fail) | | 后继 | `correct_jrxml` (graph.py:268-272) | | 功能 | LLM 将编译错误翻译为自然语言解释。注入 `natural_explanation`。 | | LLM | 是 | | Prompt | `prompts/explain_error.md` | ### 18. correct_jrxml — 自动修正 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:1355` | | 前驱 | `explain_error` (graph.py:268-272) | | 后继 | 条件分发: `validate` 或 `finalize` (graph.py:273-277) | | 功能 | 基于错误解释 + OCR 上下文 + 模板上下文 → LLM 修正 JRXML。注入 `last_error_case`。去重检测(输入输出相同则 `retry_count+=2`)。 | | LLM | 是 | | Prompt | `prompts/correction.md` | | 路由函数 | `route_after_correct` (graph.py:139) | **路由逻辑** (`route_after_correct`, graph.py:139-143): - `retry_count >= MAX_RETRY` (默认5) → `finalize` (放弃修正) - `retry_count < MAX_RETRY` → `validate` (重新验证) ### 19. finalize — 最终处理 | 属性 | 值 | |------|-----| | 代码位置 | `agent/nodes.py:1452` | | 前驱 | `validate`(pass)、`correct_jrxml`(retry>=MAX)、`handle_consult`、`handle_reset`、`save_session`(预览/导出) | | 后继 | `END` (graph.py:284) | | 功能 | 记录 `jrxml_versions` 版本历史。验证通过时设置 `final_jrxml`。失败时记录 `pending_failure_context` 供下次输入自动注入。 | | LLM | 否 | --- ## 路由函数索引 | # | 路由函数 | 代码位置 | 条件 | 分支 | |---|---------|---------|------|------| | R1 | `route_by_intent` | `graph.py:67` | `state.intent` | 6 路: retrieve / modify_jrxml / save_session / handle_consult / handle_undo / handle_reset | | R2 | `route_after_retrieve` | `graph.py:94` | `layout_schema.total_rows > 0` | 2 路: generate_skeleton / generate | | R3 | `route_after_generate` | `graph.py:103` | 无条件 | save_session | | R4 | `route_after_modify` | `graph.py:108` | 无条件 | save_session | | R5 | `route_after_undo` | `graph.py:113` | 无条件 | save_session | | R6 | `route_after_save` | `graph.py:118` | `intent in (preview, export)` | 2 路: finalize / validate | | R7 | `route_after_validate` | `graph.py:127` | `status == "pass"` | 2 路: finalize / explain_error | | R8 | `route_after_explain` | `graph.py:133` | 无条件 | correct_jrxml | | R9 | `route_after_correct` | `graph.py:139` | `retry_count >= MAX_RETRY` | 2 路: finalize / validate | --- ## 完整对话场景 ### 场景 1: 新建报表 — 1-shot(无布局 schema) **触发**: `intent=initial_generation` + 无图片/无结构化布局 **用户示例**: "帮我生成一个销售报表"、"生成一个包含客户名和金额的表格" ``` load_session nodes.py:77 → process_input nodes.py:98 → manage_context nodes.py:143 → save_state_snapshot nodes.py:191 → classify_intent nodes.py:200 意图=initial_generation └─ R1: route_by_intent graph.py:67 → retrieve → retrieve nodes.py:442 └─ R2: route_after_retrieve graph.py:94 layout_schema 为空 → generate → generate nodes.py:578 LLM 1-shot 生成完整 JRXML └─ R3: route_after_generate graph.py:103 → save_session → save_session nodes.py:325 持久化到磁盘 └─ R6: route_after_save graph.py:118 intent=initial_generation → validate → validate nodes.py:1235 结构检查 + XSD + 像素对比 └─ R7: route_after_validate graph.py:127 ├─ status=pass → finalize nodes.py:1452 → END ✓ └─ status=fail → explain_error nodes.py:1310 └─ R8 → correct_jrxml nodes.py:1355 └─ R9: retry<5 → validate (循环) retry>=5 → finalize → END ✗ ``` **LLM 调用**: `classify_intent` + `generate` + 最多 5× (`explain_error` + `correct_jrxml`) **退出好结局**: `final_jrxml` 有值, `status=pass` **退出坏结局**: `pending_failure_context` 有值, `retry_count=5` --- ### 场景 2: 新建报表 — 3 阶段分层生成(有布局 schema) **触发**: `intent=initial_generation` + 上传图片 + OCR 提取到 `layout_schema.total_rows > 0` **用户示例**: 上传销售单图片 → "根据这个模板生成报表" ``` load_session nodes.py:77 → process_input nodes.py:98 OCR提取 + 布局分析 → manage_context nodes.py:143 → save_state_snapshot nodes.py:191 → classify_intent nodes.py:200 意图=initial_generation └─ R1: route_by_intent graph.py:67 → retrieve → retrieve nodes.py:442 KB检索模板+字段 └─ R2: route_after_retrieve graph.py:94 layout_schema.total_rows>0 → generate_skeleton → generate_skeleton nodes.py:657 阶段1: 骨架JRXML ($F{field_N}占位) → refine_layout nodes.py:879 阶段2: Band级窗口化坐标精调 → map_fields nodes.py:978 阶段3: 程序化字段映射 └─ R3: route_after_generate graph.py:103 → save_session → save_session nodes.py:325 └─ R6: route_after_save graph.py:118 → validate → validate nodes.py:1235 └─ R7 同场景1的验证循环 ``` **内容保护**: - `refine_layout`: header (field/param/queryString) 完全不发给 LLM - `refine_layout`: 每窗口 ~4000 字符, LLM 无法重写整个报表 - `map_fields`: 纯正则替换, 零 LLM, 100% 确定性 - `validate_element_count()`: 每阶段后校验, >10% 变化回退 **LLM 调用**: `classify_intent` + `generate_skeleton` + N×`refine_layout`(N=band窗口数) + 可能的修正循环 --- ### 场景 3: 修改已有报表 **触发**: `intent=modify_report`(已有 `current_jrxml`) **用户示例**: "把标题字体改大"、"在底部加合计行"、"删除第三列" ``` load_session → process_input → manage_context → save_state_snapshot → classify_intent nodes.py:200 意图=modify_report └─ R1: route_by_intent graph.py:67 → modify_jrxml → modify_jrxml nodes.py:1022 LLM修改现有JRXML └─ R4: route_after_modify graph.py:108 → save_session → save_session nodes.py:325 └─ R6: route_after_save graph.py:118 → validate → (同场景1的验证循环) ``` **特殊逻辑**: `correct_jrxml` 去重检测: 输入输出相同 → `retry_count += 2` --- ### 场景 4: 预览 / 导出(跳过验证) **触发**: `intent in (preview_report, export_pdf, export_jrxml)` **用户示例**: "预览报表"、"导出 PDF"、"下载 JRXML" ``` load_session → process_input → manage_context → save_state_snapshot → classify_intent nodes.py:200 意图=preview/export └─ R1: route_by_intent graph.py:67 → save_session → save_session nodes.py:325 └─ R6: route_after_save graph.py:118 intent=preview/export → finalize → finalize nodes.py:1452 → END ✓ ``` **LLM 调用**: 仅 `classify_intent` (1次) **跳过**: generate / modify_jrxml / validate / correct_jrxml --- ### 场景 5: 咨询问答 **触发**: `intent=consult_question` **用户示例**: "JasperReports 里 $F 和 $P 有什么区别?"、"怎么设置页脚?" ``` load_session → process_input → manage_context → save_state_snapshot → classify_intent nodes.py:200 意图=consult_question └─ R1: route_by_intent graph.py:67 → handle_consult → handle_consult nodes.py:261 LLM回答 → finalize nodes.py:1452 → END ✓ ``` **LLM 调用**: `classify_intent` + `handle_consult` (2次) --- ### 场景 6: 撤销 **触发**: `intent=undo_modification` **用户示例**: "撤销"、"回退"、"恢复到修改前" ``` load_session → process_input → manage_context → save_state_snapshot → classify_intent nodes.py:200 意图=undo_modification └─ R1: route_by_intent graph.py:67 → handle_undo → handle_undo nodes.py:281 恢复history_states快照 └─ R5: route_after_undo graph.py:113 → save_session → save_session nodes.py:325 └─ R6 → validate → (验证循环) ``` **LLM 调用**: 仅 `classify_intent` (1次) **特殊**: 无快照时提示"无可撤销状态",不改变当前状态 --- ### 场景 7: 重置 **触发**: `intent=reset_session` **用户示例**: "重置"、"重新开始"、"清空对话" ``` load_session → process_input → manage_context → save_state_snapshot → classify_intent nodes.py:200 意图=reset_session └─ R1: route_by_intent graph.py:67 → handle_reset → handle_reset nodes.py:309 清空到初始状态 → finalize nodes.py:1452 → END ✓ ``` **LLM 调用**: 仅 `classify_intent` (1次) --- ### 场景 8: 兜底路由(未知意图) **触发**: LLM 分类返回非标准意图 ``` load_session → ... → classify_intent → [未知意图] └─ R1 fallback (graph.py:87-90): ├─ state有current_jrxml → modify_jrxml (走修改路径, →场景3) └─ state无current_jrxml → retrieve (走生成路径, →场景1/2) ``` --- ## AgentState 字段速查 | 字段 | 类型 | 写节点 | 读节点 | |------|------|--------|--------| | `intent` | `str` | classify_intent | R1 route_by_intent, R6 route_after_save | | `current_jrxml` | `str` | generate, generate_skeleton, refine_layout, map_fields, modify_jrxml, correct_jrxml, handle_undo | validate, save_session, finalize | | `user_input` | `str` | process_input | classify_intent, manage_context | | `user_modification_request` | `str` | process_input | modify_jrxml | | `conversation_history` | `list` | process_input, finalize, handle_consult | manage_context, classify_intent, modify_jrxml | | `full_conversation_history` | `list` | process_input | manage_context | | `compressed_history` | `str` | manage_context | modify_jrxml, handle_consult | | `retry_count` | `int` | correct_jrxml, validate | R7 route_after_correct | | `status` | `str` | validate | R7 route_after_validate, finalize | | `error_msg` | `str` | validate | explain_error, finalize | | `natural_explanation` | `str` | explain_error | correct_jrxml | | `final_jrxml` | `str` | finalize | (用户下载) | | `jrxml_versions` | `list` | finalize | (前端展示) | | `last_error_case` | `dict` | correct_jrxml | retrieve | | `pending_failure_context` | `dict` | finalize | process_input (下次) | | `layout_schema` | `dict` | process_input | R2 route_after_retrieve, generate_skeleton | | `ocr_elements` | `list` | process_input | refine_layout, generate_skeleton | | `ocr_extraction_result` | `dict` | process_input | map_fields, modify_jrxml, correct_jrxml | | `history_states` | `list` | save_state_snapshot | handle_undo | | `kb_id` | `str` | process_input | retrieve | | `kb_fields` | `list` | retrieve | generate_skeleton | | `uploaded_template_jrxml` | `str` | process_input | generate, generate_skeleton, modify_jrxml, correct_jrxml | --- ## LLM 调用统计 | 场景 | classify | 生成节点 | 窗口数 | 修正循环 | 总计(最小~最大) | |------|----------|---------|--------|---------|----------------| | 1-shot 生成 | 1 | generate=1 | - | 0~5×2 | 2 ~ 12 | | 3 阶段生成 | 1 | skeleton+refine×N | N | 0~5×2 | 2+N ~ 12+N | | 修改报表 | 1 | modify=1 | - | 0~5×2 | 2 ~ 12 | | 预览/导出 | 1 | - | - | - | 1 | | 咨询 | 1 | consult=1 | - | - | 2 | | 撤销 | 1 | - | - | - | 1 | | 重置 | 1 | - | - | - | 1 | > N = band 窗口数。`销售单.jrxml` (73k 字符) 拆解后 N≈17。 --- ## 修正循环流程 ``` validate ──fail──→ explain_error ──→ correct_jrxml ▲ │ │ retry_count < MAX_RETRY(5) │ └──────────────────────────────────────┘ │ │ retry_count >= 5 ▼ finalize (放弃, 记录pending_failure_context) ``` **修正轮次推进**: 1. `validate` 失败 → `status="fail"`, `error_msg` 有值 2. `explain_error` → LLM 翻译错误 → `natural_explanation` 有值 3. `correct_jrxml` → LLM 修正 → `retry_count += 1`。去重检测:输入输出相同 → `retry_count += 2` 4. `route_after_correct` → retry<5 → 回到 `validate`; retry>=5 → `finalize` **失败上下文** (`pending_failure_context`): 重试耗尽后记录 `{error_msg, bad_jrxml, retry_count, ts}`,下次用户消息时 `process_input` 自动注入到 prompt。 --- ## 边定义索引(graph.py 全部边) | 类型 | 源节点 | 目标节点 | 位置 | |------|--------|---------|------| | 固定边 | load_session | process_input | line 198 | | 固定边 | process_input | manage_context | line 199 | | 固定边 | manage_context | save_state_snapshot | line 200 | | 固定边 | save_state_snapshot | classify_intent | line 201 | | 条件边 | classify_intent | retrieve / modify_jrxml / save_session / handle_consult / handle_undo / handle_reset | lines 204-215 | | 条件边 | retrieve | generate / generate_skeleton | lines 218-224 | | 条件边 | generate | save_session | lines 227-231 | | 固定边 | generate_skeleton | refine_layout | line 233 | | 固定边 | refine_layout | map_fields | line 234 | | 条件边 | map_fields | save_session | lines 235-239 | | 条件边 | modify_jrxml | save_session | lines 242-246 | | 条件边 | handle_undo | save_session | lines 249-253 | | 条件边 | save_session | validate / finalize | lines 256-260 | | 条件边 | validate | finalize / explain_error | lines 263-267 | | 条件边 | explain_error | correct_jrxml | lines 268-272 | | 条件边 | correct_jrxml | validate / finalize | lines 273-277 | | 固定边 | handle_consult | finalize | line 280 | | 固定边 | handle_reset | finalize | line 281 | | 固定边 | finalize | END | line 284 |