feat: layered precise generation for A4 report images

3-phase pipeline to solve LLM prompt overflow from too many OCR elements:
Phase 1 (generate_skeleton): compressed layout schema → skeleton JRXML
Phase 2 (refine_layout): sampled coordinates → pixel-level position tuning
Phase 3 (map_fields): OCR field names → replace $F{field_N} placeholders

Only triggered when layout_schema.total_rows > 0 on initial_generation intent.
Text requests and all other intents are unaffected (zero behavior change).
This commit is contained in:
2026-05-21 08:34:32 +08:00
parent 9bb011e429
commit 43a0542a11
14 changed files with 882 additions and 81 deletions
+26 -6
View File
@@ -41,7 +41,10 @@ agent/graph.py (LangGraph 状态机)
│ 节点流程:
│ load_session → process_input → manage_context → save_state_snapshot
│ → classify_intent (8种意图路由)
│ ├─ retrieve → generate → save_session → validate → ... → finalize
│ ├─ retrieve → route_after_retrieve
│ ├─ [有布局schema] generate_skeleton → refine_layout → map_fields
│ └─ [无布局schema] generate
├─ generate/map_fields → save_session → validate → ... → finalize
│ ├─ modify_jrxml → save_session → validate → ... → finalize
│ ├─ handle_consult / handle_undo / handle_reset → finalize
│ └─ preview/export → save_session → finalize (跳过验证)
@@ -50,7 +53,7 @@ agent/graph.py (LangGraph 状态机)
│ ▲ │
│ └──────── (retry < MAX_RETRY=3) ───────────────────┘
├──► prompts/loader.py Prompt 外部化:7 个 .md 文件热重载
├──► prompts/loader.py Prompt 外部化:10 个 .md 文件热重载
├──► backend/llm.py LLM 工厂: Anthropic SDK / OpenAI / Ollama (统一 stream/invoke)
├──► backend/logger.py 集中日志: JSON + trace_id + llm.log/app.log 分离
├──► backend/rag_adapter.py 语义搜索: ChromaDB + SentenceTransformer
@@ -69,17 +72,17 @@ agent/graph.py (LangGraph 状态机)
| 文件 | 职责 | 修改频率 |
|------|------|---------|
| `app.py` | Streamlit UI 入口,聊天界面 + 侧边栏 + 下载 + 文件上传 | **高** |
| `agent/state.py` | AgentState 类型定义(~26 字段,含 pending_failure_context / annotation_result | 低 |
| `agent/nodes.py` | 14 个工作流节点 + 流式生成 + 错误记录 | **高** |
| `agent/state.py` | AgentState 类型定义(~28 字段,含 layout_schema / annotation_result | 低 |
| `agent/nodes.py` | 18 个工作流节点 + 流式生成 + 错误记录 | **高** |
| `agent/graph.py` | 状态图编译 + 路由函数(预览跳过验证) | 中 |
| `prompts/loader.py` | Prompt 加载器(从 .md 文件热重载) | 低 |
| `prompts/*.md` | 7 个独立 Prompt 模板 | **高** |
| `prompts/*.md` | 10 个独立 Prompt 模板 | **高** |
| `backend/llm.py` | LLM 工厂,统一 `_BaseLLM` 接口(invoke + stream+ `_LLMLoggingWrapper` | 中 |
| `backend/logger.py` | 集中日志模块:JSON 格式化 + trace_id + 独立 llm.log | 低 |
| `backend/rag_adapter.py` | RAGSearcher 单例,语义搜索接口 | 中 |
| `backend/error_kb.py` | ErrorKB — 错误指纹去重 + ChromaDB 持久化 + 语义检索 | 中 |
| `backend/file_parser.py` | 文件解析: PDF/DOCX/XLSX/XLS/DOC/图片(EasyOCR→PaddleOCR回退)/文本 | 中 |
| `backend/layout_analyzer.py` | A4模板分析: 比例检测/EasyOCR→PaddleOCR元素提取/行分组/JRXML行匹配 | 中 |
| `backend/layout_analyzer.py` | A4模板分析: 比例检测/EasyOCR→PaddleOCR元素提取/行分组/JRXML行匹配/布局schema提取 | 中 |
| `backend/ocr_extractor.py` | OCR字段精确提取: 4策略(exact→kv_pair→regex→table_match) + 置信度 | 中 |
| `backend/annotation_detector.py` | 批注检测: 圈选(cv2 HoughCircles) + 箭头(HoughLinesP聚类) + OCR关联 + LLM格式化 | 中 |
| `backend/embeddings.py` | 嵌入模型工厂 (HuggingFace/OpenAI) | 低 |
@@ -115,6 +118,9 @@ agent/graph.py (LangGraph 状态机)
| `prompts/explain_error.md` | 错误转人话 |
| `prompts/compression.md` | 对话压缩摘要 |
| `prompts/consult.md` | 咨询解答 |
| `prompts/skeleton_generation.md` | 分层生成-骨架 |
| `prompts/refine_layout.md` | 分层生成-精调 |
| `prompts/field_mapping.md` | 分层生成-字段映射 |
## 新增功能 (v2)
@@ -191,6 +197,19 @@ agent/graph.py (LangGraph 状态机)
- `modify_jrxml` 节点 — 将 OCR 上下文注入 modification prompt
- OCR 上下文包含: 结构化字段、全部文本元素(含坐标)、批注检测结果
## 新增功能 (v5)
### 分层精确生成
- 解决 A4 报表图片 OCR 元素过多(数百个)导致 LLM prompt 超长的问题
- **3 阶段管线**(仅对 `initial_generation` + 有布局 schema 时触发):
1. `generate_skeleton` — 压缩的布局 schema → 骨架 JRXML (`$F{field_N}` 占位)
2. `refine_layout` — 采样坐标(表头+首行数据+末行)→ 像素级位置精调
3. `map_fields` — OCR 字段名 → 替换占位符
- `backend/layout_analyzer.py` — 新增 `extract_layout_schema()`: 列聚类 + 区域分类 + schema_text
- `agent/graph.py` — 新增 `route_after_retrieve()`: 有 schema 走 3 阶段,无 schema 走原有 1-shot
- `prompts/` — 新增 `skeleton_generation.md`, `refine_layout.md`, `field_mapping.md`
- 文本请求和所有其他意图零行为变更
## 已知注意点
- **Anthropic SDK**: 使用原始 `anthropic` 包(非 `langchain-anthropic`),因为需要直连 MiniMax 兼容端点。API Key 优先读 `ANTHROPIC_API_KEY`fallback `OPENAI_API_KEY`。Anthropic SDK 会自动将 key 放入 `x-api-key` header。
@@ -207,3 +226,4 @@ agent/graph.py (LangGraph 状态机)
- **opencv-python-headless**: 批注检测(圈选/箭头)依赖,通过 `pip install -r requirements.txt` 安装。
- **st-multimodal-chatinput**: Streamlit 聊天输入增强组件,替代 `st.chat_input`,支持粘贴/拖拽文件。返回 base64 编码文件内容。
- **xlwt**: 仅在测试中使用(生成 .xls 测试文件)。
- **分层精确生成**: 3 阶段管线仅在 `layout_schema.total_rows > 0` 时触发。文本请求和 `modify_report` 等意图不受影响,走原有 `generate` 节点。中间阶段(骨架/精调)跳过验证,只有最终 mapped 结果进入 `validate`