Files
Auto-Finance/.agents/docs/guides/项目架构全景图.md
wandering 1b35f07fd7 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
2026-07-02 18:36:19 +08:00

15 KiB
Raw Permalink Blame History

项目架构全景图

最后更新: 2026-06-15 用途: 理解项目整体结构、模块职责、依赖关系和数据流


一、分层架构总览

src/
├── agent/          Agent 调度层(协调提取-校验-修正循环,状态机管理)
├── core/           核心业务层(纯逻辑,零框架依赖)
├── infra/          基础设施层浏览器、文档、LLM 提示词)
├── web/            Web 界面层Flask + SSE
├── pipeline.py     CLI 流程编排
├── pipeline_core.py CLI/Web 公共管道逻辑
├── main.py         CLI 入口
├── config.py       配置加载
└── exceptions.py   异常定义

依赖方向

graph TD
    classDef entry fill:#e8eaf6,stroke:#3f51b5,color:#1a237e
    classDef orchestrate fill:#e0f2f1,stroke:#00897b,color:#004d40
    classDef agent fill:#fff8e1,stroke:#ff8f00,color:#3e2723
    classDef core fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
    classDef infra fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20

    subgraph 入口层
        CLI["main.py"]:::entry
        WEB["web/app.py"]:::entry
    end

    subgraph 编排层
        PIPE["pipeline.py"]:::orchestrate
        PIPE_WEB["web/pipeline_web.py"]:::orchestrate
        PIPE_CORE["pipeline_core.py"]:::orchestrate
    end

    subgraph Agent调度层
        AGENT["agent/orchestrator.py"]:::agent
        SESSION["agent/session.py"]:::agent
        EVENTS["agent/events.py"]:::agent
    end

    subgraph 核心业务层
        EXTRACT["core/extraction/"]:::core
        MATCH["core/matching/"]:::core
        VALID["core/validation/"]:::core
    end

    subgraph 基础设施层
        BROWSER["infra/browser/"]:::infra
        DOCS["infra/documents/"]:::infra
        LLM["infra/llm/"]:::infra
    end

    CLI --> PIPE
    WEB --> PIPE_WEB
    PIPE --> PIPE_CORE
    PIPE --> EXTRACT
    PIPE --> BROWSER
    PIPE_WEB --> AGENT
    PIPE_WEB --> PIPE_CORE
    PIPE_WEB --> EXTRACT
    AGENT --> EXTRACT
    AGENT --> VALID
    AGENT --> LLM
    AGENT --> PIPE_CORE
    EXTRACT --> MATCH
    EXTRACT --> DOCS
    EXTRACT --> LLM
    MATCH --> DOCS
    BROWSER --> DOCS

关键约束

  • infra 不依赖 coreagent,只提供工具能力
  • core 零外部依赖,不依赖 Flask、Playwright 等框架
  • agent 依赖 coreinfra,作为调度中枢编排各模块
  • 所有跨层调用均通过 __init__.py 导出的稳定接口

二、模块清单

2.1 Agent 调度层 (src/agent/)

文件 职责
coordinator.py 核心协调逻辑:提取-校验-修正循环(最多 3 次重试)、用户补充处理、强制提交
session.py 会话状态:AgentState 枚举、AgentSession 数据类、状态持久化(原子写入)
events.py SSE 事件发射:事件去重、事件日志追加、事件读取
orchestrator.py 兼容层:从子模块重新导出所有符号,保持旧导入路径可用

对外接口AgentSession, AgentState, run_agent_round(), force_submit(), add_supplement(), process_user_text_supplement(), load_agent_state(), save_agent_state()

2.2 核心业务层 (src/core/)

子模块 职责 对外接口
extraction/extractor.py 编排入口:扫描目录 → 逐文件提取 → 分类 → 金额匹配 extract_invoices(), extract_document()
extraction/llm_extractor.py LLM 多模态提取核心:统一文档提取、差旅/普通信息提取、缓存管理、SSE 流式事件 llm_query_text(), extract_travel_info(), extract_normal_info(), load_cache()
matching/matcher.py 发票与支付记录按金额匹配(一对一 / 一对多贪心,相对容差 3% match_invoices_to_cards()
validation/validator.py 声明式规则校验引擎,规则从 JSON 配置文件加载 validate_extracted_info(), ValidationReport

2.3 基础设施层 (src/infra/)

子模块 职责 对外接口
browser/base.py BaseBot 基类Playwright 浏览器生命周期、登录、导航、截图 内部基类
browser/travel.py 差旅报销填报:基本信息 → 明细 → 支付 → 补助 → 附件上传 内部流程
browser/normal.py 普通报销填报:基本信息 → 总明细 → 支付 → 附件上传 内部流程
browser/__init__.py 浏览器入口:类型路由和流程调度 run_bot(), run_bot_web()
documents/invoice.py 发票数据模型、CSV/JSON 读写、发票分类 load_csv(), save_csv(), save_invoice_csv(), classify_invoice_batch()
documents/pdf.py PDF 渲染为图片PyMuPDF render_pdf_to_images()
documents/consumable.py 易耗品出库单填写CSV → Word 模板 fill_consumable_doc()
llm/prompt.py LLM 提示词加载 build_invoice_system_prompt(), build_travel_info_system_prompt(), build_normal_info_system_prompt()

2.4 Web 界面层 (src/web/)

文件/目录 职责
app.py Flask 应用入口,注册蓝图和模板
routes.py 路由定义会话管理、文件上传、配置、SSE 日志流、Agent 交互 API
pipeline_web.py Web 管道逻辑:发票提取 + 出库单生成 + 财务提交
sse_handler.py SSE 日志收集器、日志转义、文件轮询
templates/ index.htmlPC 端主界面)、mobile_upload.html(移动端上传)
static/js/ 前端逻辑(按加载顺序):state.jsutils.jschat.jsupload.jsconfig.jsprocess.jssync.jsindex.js

三、CLI 模式数据流

graph TD
    CLI_ENTRY["main.py --step all"] --> PIPE["pipeline.py run_pipeline()"]

    subgraph Step1["Step 1: 发票提取"]
        PIPE --> EXT["core/extraction/extractor.py extract_invoices()"]
        EXT --> DOC["逐文件提取"]
        DOC --> LLM["LLM 多模态识别 (infra/llm)"]
        LLM --> CLASS["分类: train/hotel/general/payment/application"]
        CLASS --> MATCH["core/matching/matcher.py 金额匹配"]
        MATCH --> SAVE["infra/documents/ CSV/JSON 保存"]
    end

    subgraph Step2["Step 2: 信息提取"]
        SAVE --> TYPE{"判断报销类型"}
        TYPE -->|差旅| TRAVEL["提取差旅信息 → travel_info.json"]
        TYPE -->|普通| NORMAL["提取普通发票信息 → normal_info.json"]
    end

    subgraph Step3["Step 3: 浏览器填报"]
        TRAVEL --> BOT["infra/browser/ 填报"]
        NORMAL --> BOT
        BOT -->|差旅| BOT_T["browser/travel.py"]
        BOT -->|普通| BOT_N["browser/normal.py"]
    end

关键文件输出

文件 来源 说明
payment_records.csv Step 1 支付记录级别(每笔刷卡记录一行)
invoice_summary.csv Step 1 发票级别(每张发票一行)
travel_applications.json Step 1 出差事前申请单
invoice_groups.json Step 1 发票分类结果
travel_info.json Step 2 差旅信息:交通/住宿明细、补贴、附件清单
normal_info.json Step 2 普通发票信息:报销说明、发票总数、总金额、附件清单

四、Web 模式数据流

sequenceDiagram
    participant F as 前端 (浏览器)
    participant API as routes.py
    participant PW as pipeline_web.py
    participant AG as agent/orchestrator.py
    participant EX as core/extraction/
    participant VA as core/validation/
    participant SSE as SSE 轮询

    F->>API: POST /api/session → 创建 session
    F->>API: POST /api/upload/:sid → 上传文件
    F->>API: POST /api/agent/process/:sid
    API-->>F: {status: "started"}
    F->>SSE: GET /api/logs/:sid (SSE 长连接)

    Note over API: 后台 daemon 线程启动

    API->>PW: extract_invoices(session_dir)
    PW->>EX: 发票提取 + 分类 + 匹配
    EX-->>PW: payment_records, applications, groups

    API->>AG: run_agent_round(session_dir, session)
    loop 校验-修正循环 (最多 3 次)
        AG->>EX: llm_query_text() 提取信息
        AG->>VA: validate_extracted_info() 规则校验
        alt 校验失败
            AG->>AG: 构建修正提示
        end
    end
    AG-->>API: session (READY 或 AWAITING_SUPPLEMENT)

    SSE-->>F: file_progress, llm_stream, agent_state_change, agent_ready/agent_request_supplement

    API->>API: 写入 result.json
    SSE-->>F: done (携带 result)
    F->>F: 关闭 SSE, 展示结果

Web 模式特有的 Agent 调度

CLI 模式中 pipeline.py 直接调用 extract_invoices()infra/browser/,不经过 Agent 层。

Web 模式中 routes.py 启动后台线程,调用 agent/orchestrator.py 作为调度中枢:

run_agent_round()
├── 1. load_cache() — 检查缓存
├── 2. _do_extraction_with_validation() — 提取-校验-修正循环
│   ├── llm_query_text() — LLM 提取结构化信息
│   ├── validate_extracted_info() — 规则校验
│   └── 校验失败 → 构建修正提示 → 再次调用 LLM (最多 3 次)
├── 3. 判断 can_submit 字段
│   ├── true → READY → 自动触发财务提交
│   └── false → AWAITING_SUPPLEMENT → 等待用户补充
├── 4. 用户补充处理
│   ├── add_supplement() — 记录补充文件
│   └── process_user_text_supplement() — LLM 解析文字补充
└── 5. save_agent_state() — 持久化状态

五、Agent 状态机

stateDiagram-v2
    [*] --> IDLE: 会话创建

    IDLE --> EXTRACTING: POST /api/agent/process
    IDLE --> EXTRACTING: POST /api/agent/supplement
    IDLE --> EXTRACTING: POST /api/agent/user-supplement

    EXTRACTING --> READY: can_submit == true
    EXTRACTING --> AWAITING_SUPPLEMENT: can_submit == false
    EXTRACTING --> ERROR: 异常 / 轮次超限

    READY --> SUBMITTING: _emit_ready_and_submit()
    SUBMITTING --> DONE: 财务提交完成

    AWAITING_SUPPLEMENT --> EXTRACTING: 用户补充文件/文字
    AWAITING_SUPPLEMENT --> READY: 用户强制提交

    note right of EXTRACTING
        LLM 提取 + validator 校验
        最多 3 次重试
    end note

终态保护

以下状态为终态,再次触发 run_agent_round() 会被跳过:

  • DONE — 提交完成
  • SUBMITTING — 提交中
  • READY — 准备提交

轮次保护

默认最多 5 轮(AgentSession.max_rounds),超限后进入 ERROR 状态,用户可选择强制提交。


六、SSE 事件通信机制

graph LR
    subgraph 后端写入
        AGENT[agent/orchestrator.py] -->|追加写入| AE[agent_events.log]
        LLM[LLM 回调] -->|追加写入| LS[llm_stream.log]
        PW[pipeline_web.py] -->|追加写入| FE[file_events.log]
        SH[sse_handler.py] -->|追加写入| SL[session.log]
        RT[_run_agent_task] -->|finally 原子写入| RJ[result.json]
    end

    subgraph SSE 轮询 (0.5s)
        POLL[SSE 端点] -->|读取| AE
        POLL -->|读取| LS
        POLL -->|读取| FE
        POLL -->|读取| SL
        POLL -->|检测| RJ
    end

    POLL -->|event: agent_*| FRONT[前端 agent.js]
    POLL -->|event: llm_stream| FRONT
    POLL -->|event: file_progress| FRONT
    POLL -->|event: done| FRONT

信号文件生命周期

阶段 result.json llm_stream.log agent_events.log file_events.log session.log
会话创建 不存在 不存在 不存在 不存在 不存在
后台线程启动 已删除 已删除 已删除 保持 保持
文件提取中 不存在 不存在 不存在 持续追加 持续追加
LLM 提取中 不存在 持续追加 持续追加 保持 持续追加
校验中 不存在 保持 持续追加 保持 持续追加
任务完成 已写入 保持 保持 保持 保持
SSE done 事件 保持 保持 保持 保持 保持

七、发票类型路由

graph TD
    INPUT["上传文件 (PDF/图片)"] --> EXT["LLM 多模态识别"]
    EXT --> TYPE{"invoice_type?"}

    TYPE -->|train| TRAVEL["差旅报销流程"]
    TYPE -->|hotel| TRAVEL
    TYPE -->|general| NORMAL["普通报销流程"]
    TYPE -->|payment| MATCH["参与金额匹配"]
    TYPE -->|application| APP["存储为 JSON"]

    TRAVEL --> TRAVEL_INFO["提取差旅信息<br/>travel_info.json"]
    TRAVEL_INFO --> TRAVEL_BOT["browser/travel.py<br/>填报差旅报销单"]

    NORMAL --> NORMAL_INFO["提取普通发票信息<br/>normal_info.json"]
    NORMAL_INFO --> NORMAL_BOT["browser/normal.py<br/>填报普通报销单"]
    NORMAL_INFO --> CONSUMABLE["生成易耗品出库单<br/>(仅普通报销)"]

    MATCH --> MERGE["合并到对应发票组"]

    style TRAVEL fill:#cfe2ff,stroke:#0d6efd
    style NORMAL fill:#f8d7da,stroke:#dc3545
    style MATCH fill:#d1e7dd,stroke:#198754
    style APP fill:#fff3cd,stroke:#ffc107
发票类型 invoice_type 报销流程 生成出库单
高铁票/火车票 train 差旅报销
酒店住宿 hotel 差旅报销
普通发票 general 普通报销
支付记录 payment 参与匹配
出差申请单 application 单独存储

差旅发票和普通发票不支持混报,混合时系统按普通报销处理。


八、设计原则

原则 说明
Agent 是调度中枢 校验-修正循环由 Agent 编排,不内嵌在 llm_extractor
模块职责单一 llm_extractor 只管提取,validator 只管校验Agent 负责编排
core 零外部依赖 不依赖 Flask、Playwright 等框架
infra 不依赖业务 基础设施层只提供工具能力,不包含业务逻辑
缓存优先 信息提取优先读取 .invoice_cache,避免重复调用 LLM
轮次保护 默认 5 轮上限,校验-修正循环最多重试 3 次
终态保护 DONE/SUBMITTING/READY 状态下不再重复处理
容错降级 规则校验 3 次重试后返回最佳结果,不阻断流程
原子写入 状态文件先写 .tmprename(),防止读取不完整数据

九、关键文件索引

文件 职责
src/main.py CLI 入口
src/web/app.py Web 入口
src/pipeline.py CLI 流程编排
src/pipeline_core.py CLI/Web 公共管道逻辑
src/web/pipeline_web.py Web 管道逻辑 + 财务提交
src/web/routes.py Web 路由 + 后台线程启动
src/agent/coordinator.py Agent 核心协调逻辑
src/agent/session.py 会话状态定义与持久化
src/agent/events.py SSE 事件发射
src/core/extraction/extractor.py 发票提取编排入口
src/core/extraction/llm_extractor.py LLM 多模态提取核心
src/core/matching/matcher.py 金额匹配
src/core/validation/validator.py 声明式规则校验
src/infra/browser/base.py 浏览器自动化基类
src/infra/documents/invoice.py 发票数据模型
src/web/sse_handler.py SSE 日志收集器
src/web/static/js/process.js 前端主提交流程
src/web/static/js/agent.js 前端 Agent 交互处理
config.json 项目配置