refactor: 架构重组 — doc/bot → core/infra,新增 Agent 调度模块

- src/doc/ 拆分为 src/core/extraction/, matching/, validation/(核心业务逻辑)
- src/bot/ 重命名为 src/infra/browser/(浏览器自动化基础设施)
- fill_consumable_doc.py → src/infra/documents/consumable.py
- 新增 Agent 调度模块:coordinator.py, events.py, session.py,重构 orchestrator.py
- 更新 AGENTS.md、README.md 及所有子目录 README
This commit is contained in:
wandering
2026-07-02 18:36:19 +08:00
parent 7c137c5214
commit 1b35f07fd7
69 changed files with 2965 additions and 1548 deletions

View File

@@ -0,0 +1,225 @@
# 项目架构分析与重构建议
## 一、当前架构总览
```
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*