# 项目架构分析与重构建议 ## 一、当前架构总览 ``` src/ ├── main.py # CLI 入口 ├── pipeline.py # CLI 管道编排 ├── pipeline_core.py # CLI/Web 公共管道逻辑 ├── config.py # 配置加载 ├── exceptions.py # 异常定义 │ ├── doc/ # 文档处理模块(职责过重) │ ├── extractor.py # 发票提取编排 │ ├── llm_extractor.py # LLM 提取核心 │ ├── invoice.py # 发票数据模型 + CSV 工具 │ ├── matcher.py # 发票匹配逻辑 │ ├── validator.py # 信息校验规则 │ ├── prompt.py # 提示词加载 │ ├── pdf.py # PDF 渲染 │ ├── fill_consumable_doc.py # 出库单填写 │ └── prompts/ # LLM 提示词模板 │ ├── agent/ # Agent 调度模块 │ └── orchestrator.py # 校验-修正循环调度 │ ├── bot/ # 浏览器自动化模块 │ ├── base.py # 浏览器基类 │ ├── travel.py # 差旅填报 │ └── normal.py # 普通报销填报 │ └── web/ # Web 界面模块 ├── app.py # Flask 应用 ├── routes.py # 路由定义 ├── pipeline_web.py # Web 管道逻辑(与 pipeline_core 重复) ├── sse_handler.py # SSE 日志流处理 └── static/templates/ # 前端资源 ``` --- ## 二、问题分析 ### 2.1 职责不清(高耦合) | 问题 | 位置 | 说明 | |------|------|------| | **doc 模块职责过重** | `src/doc/` | 同时负责:提取、匹配、校验、提示词、PDF渲染、出库单填写、CSV操作 | | **Web 层重复逻辑** | `pipeline_web.py` vs `pipeline_core.py` | 两者的 `is_travel_invoice`、`extract_and_cache_*` 逻辑重复 | | **提示词与校验耦合** | `validator.py` | 校验规则直接引用提示词相关函数,缺乏分层 | | **bot 模块位置** | `src/bot/` | 浏览器自动化属于基础设施,却被放在 src 根目录而非独立模块 | ### 2.2 逻辑混乱 1. **`src/doc/validator.py`** 的问题: - 校验规则(`TRAVEL_VALIDATION_RULES`)硬编码在模块中,修改需改代码 - `FieldRule` 和 `ArrayRule` 类与校验逻辑紧耦合 - 数组元素字段支持简单格式和详细格式两种配置,增加了理解成本 2. **`src/doc/prompt.py`** 的问题: - 简单的文件读取包装,但调用方分散 - `build_invoice_system_prompt()` 和 `build_travel_info_system_prompt()` 分别调用,但结构相似 3. **`src/agent/orchestrator.py`** 的问题: - 校验循环与提取逻辑混合在 `_do_extraction_with_validation` - SSE 事件发射逻辑(`_emit_agent_event`)与业务逻辑混杂 - 状态机转换逻辑分散 ### 2.3 分层不合理 ``` 当前分层(按目录): main.py → pipeline.py → doc/ + bot/ ↓ pipeline_web.py → web/ 建议分层(按职责): 应用层: main.py, pipeline.py, pipeline_web.py 业务层: agent/orchestrator.py, doc/validator.py, doc/matcher.py 提取层: doc/extractor.py, doc/llm_extractor.py 基础设施层: bot/, web/, doc/pdf.py, doc/fill_consumable_doc.py ``` --- ## 三、重构建议 ### 3.1 目录重组 ``` src/ ├── main.py # CLI 入口 ├── config.py # 配置加载 ├── exceptions.py # 异常定义 │ ├── apps/ # 应用层(管道编排) │ ├── cli/ # CLI 应用 │ │ └── pipeline.py │ └── web/ # Web 应用 │ ├── app.py │ ├── routes.py │ ├── pipeline.py # Web 专用管道 │ └── sse.py │ ├── core/ # 核心业务逻辑 │ ├── agent/ # Agent 调度 │ │ ├── orchestrator.py │ │ └── session.py │ ├── validation/ # 校验模块 │ │ ├── validator.py │ │ └── rules/ # 校验规则(可配置化) │ ├── matching/ # 匹配模块 │ │ └── matcher.py │ └── extraction/ # 提取模块 │ ├── extractor.py │ └── llm.py │ ├── infra/ # 基础设施层 │ ├── browser/ # 浏览器自动化 │ │ ├── base.py │ │ ├── travel.py │ │ └── normal.py │ ├── documents/ # 文档处理 │ │ ├── invoice.py │ │ ├── pdf.py │ │ └── consumable.py │ └── llm/ # LLM 接口 │ └── prompts/ # 提示词模板 │ └── shared/ # 共享工具 ├── logging.py └── cache.py ``` ### 3.2 关键重构点 #### 3.2.1 doc 模块拆分 | 职责 | 建议移动位置 | |------|-------------| | `validator.py` | `core/validation/` | | `matcher.py` | `core/matching/` | | `llm_extractor.py` | `core/extraction/` | | `extractor.py` | `core/extraction/` | | `invoice.py` | `infra/documents/` | | `pdf.py` | `infra/documents/` | | `fill_consumable_doc.py` | `infra/documents/` | | `prompt.py` + `prompts/` | `infra/llm/` | #### 3.2.2 消除重复逻辑 **问题**: `pipeline_web.py` 和 `pipeline_core.py` 都有相似逻辑: - `is_travel_invoice()` - `extract_and_cache_travel_info()` - `extract_and_cache_normal_info()` **建议**: 将这些公共逻辑统一到 `core/pipeline/` 目录,两个入口调用同一模块。 #### 3.2.3 Validator 重构 **当前问题**: - 校验规则硬编码 - `FieldRule` 和 `ArrayRule` 类过于复杂 **建议**: - 将校验规则外部化为 JSON/YAML 配置文件 - 简化 `FieldRule` 为单一数据结构 - 统一顶层字段和数组元素字段的校验方式 #### 3.2.4 Agent 拆分 **当前问题**: - `orchestrator.py` 包含:状态机、SSE 事件、校验循环、提取逻辑 **建议**: ``` agent/ ├── session.py # 状态机定义 + 会话数据模型 ├── coordinator.py # 校验-修正循环 ├── events.py # SSE 事件发射 └── orchestrator.py # 总调度入口 ``` ### 3.3 接口契约强化 | 模块 | 依赖关系 | 接口契约 | |------|----------|----------| | `core/extraction` | 被 `apps/*` 调用 | 返回 `(payment_records, applications, groups)` | | `core/validation` | 被 `agent/*` 调用 | `validate(info, rules) -> ValidationReport` | | `core/matching` | 被 `extraction` 调用 | `match(invoices, cards) -> List[Dict]` | | `infra/browser` | 被 `apps/*` 调用 | `run(bot, info) -> None` | | `infra/llm` | 被 `core/extraction` 调用 | `extract_document(file) -> dict` | --- ## 四、优先重构顺序 ### 第一阶段(降低耦合) 1. 将 `doc/` 拆分为 `core/` + `infra/` 2. 消除 `pipeline_web.py` 和 `pipeline_core.py` 的重复逻辑 3. 将 `bot/` 移动到 `infra/browser/` ### 第二阶段(职责清晰化) 4. 拆分 `agent/orchestrator.py` 为多个模块 5. 外部化 `validator.py` 的校验规则为配置文件 6. 统一 SSE 事件处理接口 ### 第三阶段(可维护性) 7. 完善 `__init__.py` 的接口导出 8. 添加模块间依赖注入机制 9. 建立跨模块调用规范 --- ## 五、当前项目优点 1. **日志规范**: 统一的 `get_logger()` 方式,全局日志管理 2. **异常体系**: 清晰的 `ReimbursementError` 异常层次 3. **SSE 事件协议**: 良好的实时反馈机制 4. **缓存设计**: `llm_extractor.py` 的缓存加载逻辑完善 5. **声明式校验**: `validator.py` 的规则配置思路正确 --- *生成时间: 2026-06-15*