Files
Auto-Finance/README.md
T
wandering 821822a408 docs: 全面体检并更新文档,工具参考改为从运行时 schema 生成
先体检再动手:44 个 Markdown,相对链接 0 处失效,逐份分辨「现状文档」与「历史记录」。
历史记录(error-experience/*、架构分析、已过时的全景图)保留原貌只加指路,不重写。

- 新增 scripts/gen_mcp_docs.py:起 stdio 子进程 list_tools 后整段重生成 docs/MCP.md 的「工具参考」
  (291 行 / 25 个工具,占这份文档四分之三,手工维护必漂)。--check 漂移退出码 1,--diff 打印差异;
  GROUPS 是刻意闸门——加了工具没登记就报错,防止「有工具没文档」。接进 make mcp-docs / docs-check
  与 tasks.py 同名任务
- 生成时抓到两处真实漂移:invoice_type 线上是 string/null 且默认 null,文档手写成 null/string 无默认;
  case_list 无参数在旧文档里写成一句散文。现已与线上一字不差
- 过期说法清理:src/README 的「browser_* 与 submit_* 尚未实现」(browser 早已联机验通、submit 定案不做);
  tests/README 的「当前 107 例」(现 148)与缺 test_mcp_browser.py 一行、「Playwright 填报不进单测」
  (现在选择器分支/状态判定/错误路径有单测,只有真实页面需要联机);.agents/README 的「Cursor Agent」;
  plans/README 里还写着「提交加确认 token」;scripts/data/README 表格有一行跑到正文后面
- 工程实践指南里把已删除的 CLI 入口当例子:mypy src/main.py、make run、python src/main.py 全部改为现状
  (mypy src / 唯一入口 python -m src.mcp.server),并补上「任务必须透传退出码」这条本轮踩到的坑
- README:「还没做完」重写为「边界与未完事项」——把刻意不做(提交、submit_* 整类、删除、撤回)与
  真的未完(科目/项目/人员固定取第 N 行,待业务口径)分开写;开发命令补 mcp-docs / docs-check / skill-install
- 操作指南:7.3 经济科目与项目从「要改就改索引」改成「已知限制,等口径,填报后务必人工核对」;
  相关命令补齐新目标;MCP.md 标准流程补上填报与「到此为止,提交由人」两步,并改掉与新纪律矛盾的
  「把截图报给用户」表述
- AGENTS:命令表加两行;测试段给出改工具后的固定顺序(mcp-smoke → mcp-docs → 重连宿主);提交纪律
  补「make check 之外还有 docs-check / skill-check 两道专项门禁」;截图产物改标注为排查证据
- install_skill.py:拿不到主目录时退出码改 4,别和「漂移」的 1 混成一类
- 已核对:submit_execute / src/main.py 在文档里的残留都是禁止性表述或「已删除」清单项,不是现状描述

验证:ruff / format --check / mypy src / deptry / pytest 148 passed / mcp-smoke 25 工具 /
docs-check 与 skill-check 均退出码 0。--no-verify 提交并手跑等价检查。
2026-10-20 23:12:46 +08:00

7.0 KiB
Raw Blame History

last_reviewed
last_reviewed
2026-10-20

财务报销自动化(MCP 服务器)

把发票、支付截图、出差申请单变成财务系统要的结构化数据,顺带生成低值易耗品申购单。

它不是一个应用,而是一个 MCP 服务器:读图、判断、决定下一步交给宿主 Agent(如 DSH), 本项目只做确定性的活——PDF 渲染转正、金额匹配、规则校验、Excel 产物、浏览器填报。

为什么改:原来自带一整套前端 + 内置 LLM + 手写状态机(提取-校验-修正循环、轮次上限、SSE 事件流)。 灵活性太差——想换个模型、加一类票据、改流程都得动代码。2026-10-19 起全部交给宿主 Agent 编排。

它做什么

环节 谁做
看发票、判断类型、抽字段 宿主 Agent(多模态模型)
页面渲染、PDF 文本层、自动转正 本项目(PyMuPDF)
发票与刷卡记录金额匹配 本项目(确定性贪心 + 业务约束,输出待复核清单)
完整性校验 本项目(config/validation_rules.json 声明式规则)
申购单 Excel、财务系统填报 本项目(COM / Playwright)
流程编排、缺料追问、要不要提交 宿主 Agent

快速开始

uv sync                                  # 依赖(要求 Python >= 3.12)
uv run playwright install chromium       # 浏览器填报要用

配好 scripts/data/config.json(参考 config.example.json:工号、密码、默认报销人、公务卡号、人员编号、上传 PIN)。 该目录整体在 .gitignore 里,别提交。

把服务器注册到宿主(DSH profile patch):

- insert:
    - id: mcp-arb
      name: '@deepseek-ai/dsh-mcp-client'
      config:
        serverName: arb
        transport: stdio
        command: '<项目根>/.venv/Scripts/python.exe'
        args: ['-m', 'src.mcp.server']
        cwd: '<项目根>'

自检(真的起一个子进程走 stdio 握手):

make mcp-smoke        # 或 python tasks.py mcp-smoke

手机扫码上传材料(独立进程,必须单独起):

make upload           # 默认 0.0.0.0:5055;--local 只监听 127.0.0.1;--pin 加访问码

case_create 会返回带令牌的手机页地址,上传落 cases/<id>/inbox/,之后由 Agent 收取。 上传服务是只写不读的:没有列表也没有下载接口,扩展名白名单 + 25MB + 每会话 200 个文件封顶。

一次报销长什么样

case_create → case_add_files → case_render_pages → case_read_text / 读 PNG
   → case_save_extraction(逐张)→ match_payments(处理 review_required)
   → info_skeleton → save_info → doc_requisition
   →(可选)browser_open → browser_login → browser_new_form → browser_fill × 步骤 → browser_page_state

提交动作不在工具能力范围内,也永远不会是:本项目不提供点提交的工具,填完由本人在财务系统里核对并亲自提交。

25 个工具的参数表与返回约定:docs/MCP.md。操作步骤(财务口径):docs/报销操作指南.md。

项目结构

src/
├── mcp/            工具与协议层(server.py 注册;tools/ 分材料·抽取交接·分析·文档)
├── cases.py        会话目录 cases/<id>/ 的唯一实现:阶段由产物推导,无状态机
├── upload/         扫码上传收件器(独立进程,绝不由 MCP 子进程拉起)
├── core/           确定性内核:extraction(缓存·渲染·转正)matching validation
├── infra/          browser(Playwright 填报)documents(CSV·申购单 COM)
├── config.py       scripts/data/config.json + 环境变量
└── exceptions.py   异常定义(MCP 层转成 ok:false 信封,不抛穿协议)
.agents/skills/reimbursement/    宿主侧操作手册与字段判读参考(从旧 LLM 提示词迁移)
docs/MCP.md                      工具契约
config/validation_rules.json     声明式校验规则
templates/低值易耗品申购.xls         申购单空白模板(可用 REQUISITION_TEMPLATE 覆盖)
cases/                           会话产物(gitignore,含个人信息)

开发

make install      # uv sync + pre-commit
make check        # ruff check + format --check + mypy src + deptry
make test         # pytest + 覆盖率(148 例,不需要网络与真实账号)
make mcp-smoke    # stdio 自检:真起子进程握手、列工具
make mcp-docs     # 由线上 schema 重新生成 docs/MCP.md 的工具参考
make docs-check   # 工具文档漂移检测(退出码 1 即不一致)
make skill-install # 把报销技能装到用户级目录,跨项目可用
make upload       # 上传收件器(手机扫码,独立进程)

测试覆盖:配置加载、发票分类与 CSV、金额匹配、会话与分析工具、骨架与规则一致性、申购单取值, 以及分步填报的步骤顺序、续填找回、附件提交校验(用假页面跑真实逻辑,不碰 Playwright 与账号)。

平台与风险

  • Windows-only:申购单依赖 Microsoft Excel + pywin32 COM;并发驱动 Office 会互抢, 所以 COM 调用统一排队在单线程 actor(src/infra/com_thread.py)
  • 填报会打开 Chromium,自动化期间别手动点
  • cases/ 与 scripts/data/ 含身份证号、卡号、凭据,已在 .gitignore;发布前请自查历史
  • 提交前务必手动跑门禁:本仓库 pre-commit 只跑 ruff,但它会 stash 未暂存改动, 中途中断会把工作区文件回滚成 HEAD(本项目改造过程中真发生过,见方案文档 §11)

边界与未完事项

刻意不做:提交、提交前预览(submit_* 整类)、删除、撤回——都由本人在财务系统里做, 工具层不给这些动作开口子(错一条要写情况说明,不可逆的动作不交给自动化)。填报完成就是终点, 把单据编号与会话目录告诉用户即可。

已知未完(截至 2026-10-20):

  • 经济科目固定取弹窗第 3 行、项目固定取第 1 行、补助人员取查询结果第一行:会静默填出财务上 不正确的数据,等用户给业务口径后改成可配置 + 唯一匹配
  • Word 版易耗品出库单永久下线(模板自 2026-08-31 起不在仓库,此前该路径一直静默失败)

文档索引

文档 内容
docs/MCP.md 25 个工具的参数、返回信封、会话目录、注册方法
docs/报销操作指南.md 财务侧口径与材料准备要求
AGENTS.md 给 Agent 的项目操作指南(开发命令、约束、坑)
.agents/skills/reimbursement/SKILL.md 宿主 Agent 的操作纪律(可装到用户级跨项目用)
.agents/docs/plans/MCP化改造方案-2026-10-19.md 改造决策、实测数据、踩坑记录、各项定案