Files
X-Financial/docs/superpowers/plans/2026-04-24-ai-reimbursement-mvp.md
WIN-JHFT4D3SIVT\caoxiaozhu 7141e1d11a feat: refactor monolithic App.vue into modular Vue component architecture
- Extract 711-line App.vue into 15+ focused files across 5 directories
- Add data layer (icons, metrics, policies, auditTrail, requests)
- Add composables (useNavigation, useRequests, useChat, useToast)
- Add layout components (SidebarRail, TopBar, FilterBar)
- Add shared components (PanelHead, InfoRow, ToastNotification)
- Add business component (RequestTable) and 5 view components
- Extract global CSS to assets/styles/global.css
- Add start.sh with WSL/Windows cross-platform support
- Add .gitignore for node_modules, dist, and IDE dirs
2026-04-28 17:20:52 +08:00

1603 lines
46 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AI 报销预审中台 MVP 实施计划
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 在 8 周内完成 AI 报销预审中台的 MVP跑通「上传材料 → OCR 识别 → 草稿生成 → 规则预审 → 补件交互 → 用户确认 → 模拟同步」完整闭环,优先支持差旅报销场景。
**Architecture:** 采用模块化单体架构,前端 Vue3 + Ant Design Vue后端 Python FastAPI数据库 PostgreSQL + Redis文件存储 MinIOOCR 先用百度/腾讯云 API 封装。Agent 编排用自研轻量状态机 + LangGraph可选规则引擎自研 JSON Rule Engine。6 层架构:用户入口 → AI 操作层 → Agent 层 → 影子账本 → Policy & Evidence → System Adapter。
**Tech Stack:**
- 前端Vue 3 + TypeScript + Ant Design Vue + Vite + Pinia
- 后端Python 3.11+ / FastAPI + SQLAlchemy + Alembic + Pydantic v2
- 数据库PostgreSQL 15 + Redis 7
- 文件存储MinIOS3 兼容)
- OCR百度云 OCR API增值税发票、火车票、机票行程单
- 规则引擎:自研 JSON Rule Engine
- Agent自研 Orchestrator 状态机 + 大模型 APIOpenAI / 国内模型)
- 部署Docker Compose
---
## 团队分工建议3-5 人)
| 角色 | 人数 | 职责 |
|---|---|---|
| 后端工程师 A | 1 | 核心后端任务管理、影子账本、Agent 编排、规则引擎 |
| 后端工程师 B | 1 | OCR 集成、文件服务、适配器层、审计日志 |
| 前端工程师 | 1-2 | 所有页面与组件(可拆分为两人并行) |
| 全栈/Agent 工程师 | 1 | Agent Prompt 设计、大模型集成、规则配置 |
---
## 总体里程碑
| 周 | 里程碑 | 核心交付 |
|---|---|---|
| W1 | 项目基建 + 数据模型 | 项目骨架、数据库 schema、开发环境 |
| W2-W3 | 后端核心服务 | 任务/票据/OCR/规则引擎 API |
| W3-W4 | Agent 编排 + 影子账本 | Orchestrator 状态机、5 个 Agent |
| W4-W5 | 前端核心页面 | 入口/上传/草稿/预审/补件/确认 |
| W5-W6 | 前后端联调 + 规则配置 | 完整流程跑通 |
| W7-W8 | 集成测试 + 打磨 + 部署 | E2E 测试、修复、演示 Demo |
---
## Phase 1: 项目基建W1
### Task 1.1: 后端项目骨架搭建
**Files:**
- Create: `backend/app/__init__.py`
- Create: `backend/app/main.py`
- Create: `backend/app/core/config.py`
- Create: `backend/app/core/database.py`
- Create: `backend/app/core/dependencies.py`
- Create: `backend/app/api/__init__.py`
- Create: `backend/app/api/v1/__init__.py`
- Create: `backend/app/api/v1/router.py`
- Create: `backend/app/models/__init__.py`
- Create: `backend/app/schemas/__init__.py`
- Create: `backend/app/services/__init__.py`
- Create: `backend/requirements.txt`
- Create: `backend/pyproject.toml`
- Create: `backend/Dockerfile`
- Create: `backend/alembic.ini`
- Create: `backend/alembic/env.py`
- Test: `backend/tests/__init__.py`
- Test: `backend/tests/conftest.py`
- Test: `backend/tests/test_health.py`
- [ ] **Step 1: 初始化后端项目结构**
创建 FastAPI 项目骨架,使用以下目录结构:
```
backend/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI 应用入口
│ ├── core/
│ │ ├── config.py # SettingsPydantic BaseSettings
│ │ ├── database.py # SQLAlchemy async engine + session
│ │ └── dependencies.py # 通用依赖注入db session, 当前用户等)
│ ├── api/
│ │ └── v1/
│ │ ├── __init__.py
│ │ ├── router.py # v1 路由聚合
│ │ ├── tasks.py # 报销任务 API
│ │ ├── documents.py # 票据附件 API
│ │ ├── precheck.py # 预审结果 API
│ │ └── supplements.py # 补件 API
│ ├── models/ # SQLAlchemy ORM models
│ │ ├── __init__.py
│ │ ├── task.py
│ │ ├── reimbursement.py
│ │ ├── document.py
│ │ ├── rule.py
│ │ └── audit.py
│ ├── schemas/ # Pydantic schemas
│ │ ├── __init__.py
│ │ ├── task.py
│ │ ├── reimbursement.py
│ │ ├── document.py
│ │ └── rule.py
│ ├── services/ # 业务逻辑层
│ │ ├── __init__.py
│ │ ├── task_service.py
│ │ ├── document_service.py
│ │ ├── ocr_service.py
│ │ ├── rule_engine.py
│ │ └── sync_service.py
│ └── agents/ # Agent 编排层
│ ├── __init__.py
│ ├── orchestrator.py
│ ├── intake_agent.py
│ ├── parse_agent.py
│ ├── rule_check_agent.py
│ ├── explain_agent.py
│ └── sync_agent.py
├── alembic/
│ ├── env.py
│ └── versions/
├── alembic.ini
├── requirements.txt
├── pyproject.toml
├── Dockerfile
└── tests/
├── __init__.py
├── conftest.py
└── test_health.py
```
- [ ] **Step 2: 编写核心配置文件**
`backend/app/core/config.py` 使用 Pydantic BaseSettings
```python
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
# App
APP_NAME: str = "AI Reimbursement Agent"
APP_VERSION: str = "0.1.0"
DEBUG: bool = True
# Database
DATABASE_URL: str = "postgresql+asyncpg://postgres:postgres@localhost:5432/x_financial"
# Redis
REDIS_URL: str = "redis://localhost:6379/0"
# MinIO / S3
MINIO_ENDPOINT: str = "localhost:9000"
MINIO_ACCESS_KEY: str = "minioadmin"
MINIO_SECRET_KEY: str = "minioadmin"
MINIO_BUCKET: str = "reimbursement"
# OCR
OCR_PROVIDER: str = "baidu" # baidu | tencent | mock
BAIDU_OCR_API_KEY: str = ""
BAIDU_OCR_SECRET_KEY: str = ""
# LLM
LLM_PROVIDER: str = "openai"
LLM_API_KEY: str = ""
LLM_MODEL: str = "gpt-4o-mini"
LLM_BASE_URL: str = ""
class Config:
env_file = ".env"
settings = Settings()
```
- [ ] **Step 3: 编写数据库连接和 FastAPI 入口**
`backend/app/core/database.py`:
```python
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
from sqlalchemy.orm import DeclarativeBase
from app.core.config import settings
engine = create_async_engine(settings.DATABASE_URL, echo=settings.DEBUG)
async_session = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
class Base(DeclarativeBase):
pass
async def get_db() -> AsyncSession:
async with async_session() as session:
yield session
```
`backend/app/main.py`:
```python
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.core.config import settings
from app.api.v1.router import api_router
app = FastAPI(title=settings.APP_NAME, version=settings.APP_VERSION)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(api_router, prefix="/api/v1")
@app.get("/health")
async def health():
return {"status": "ok", "version": settings.APP_VERSION}
```
- [ ] **Step 4: 编写 requirements.txt**
```
fastapi==0.115.0
uvicorn[standard]==0.30.0
sqlalchemy[asyncio]==2.0.35
asyncpg==0.30.0
alembic==1.13.0
pydantic==2.9.0
pydantic-settings==2.5.0
python-multipart==0.0.9
httpx==0.27.0
redis==5.1.0
minio==7.2.9
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4
pytest==8.3.0
pytest-asyncio==0.24.0
httpx # for TestClient
```
- [ ] **Step 5: 编写健康检查测试**
`backend/tests/conftest.py`:
```python
import pytest
from httpx import AsyncClient, ASGITransport
from app.main import app
@pytest.fixture
async def client():
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as ac:
yield ac
```
`backend/tests/test_health.py`:
```python
import pytest
@pytest.mark.asyncio
async def test_health(client):
response = await client.get("/health")
assert response.status_code == 200
data = response.json()
assert data["status"] == "ok"
```
- [ ] **Step 6: 运行测试确认骨架可用**
Run: `cd backend && pip install -r requirements.txt && pytest tests/test_health.py -v`
Expected: PASS
- [ ] **Step 7: Commit**
```bash
git add backend/
git commit -m "feat: 初始化后端项目骨架FastAPI + SQLAlchemy + Alembic"
```
---
### Task 1.2: 数据库 Schema + 迁移
**Files:**
- Create: `backend/app/models/base.py`
- Create: `backend/app/models/task.py`
- Create: `backend/app/models/reimbursement.py`
- Create: `backend/app/models/document.py`
- Create: `backend/app/models/rule.py`
- Create: `backend/app/models/audit.py`
- Create: `backend/app/models/enums.py`
- Modify: `backend/app/models/__init__.py`
- Test: `backend/tests/test_models.py`
- [ ] **Step 1: 定义枚举类型**
`backend/app/models/enums.py`:
```python
import enum
class TaskStatus(str, enum.Enum):
CREATED = "created"
MATERIAL_COLLECTING = "material_collecting"
PARSING = "parsing"
DRAFT_GENERATED = "draft_generated"
PRECHECKING = "prechecking"
NEED_SUPPLEMENT = "need_supplement"
PENDING_USER_CONFIRM = "pending_user_confirm"
SUBMITTING = "submitting"
SYNCED = "synced"
SYNC_FAILED = "sync_failed"
CLOSED = "closed"
class ExpenseType(str, enum.Enum):
TRAVEL_TRANSPORT = "travel_transport"
TRAVEL_HOTEL = "travel_hotel"
TRAVEL_MEAL = "travel_meal"
LOCAL_TRANSPORT = "local_transport"
BUSINESS_MEAL = "business_meal"
OFFICE_SUPPLY = "office_supply"
COMMUNICATION = "communication"
OTHER = "other"
class DocumentType(str, enum.Enum):
VAT_INVOICE = "vat_invoice"
TRAIN_TICKET = "train_ticket"
FLIGHT_ITINERARY = "flight_itinerary"
TAXI_RECEIPT = "taxi_receipt"
HOTEL_BILL = "hotel_bill"
PAYMENT_SCREENSHOT = "payment_screenshot"
TRAVEL_ORDER = "travel_order"
OTHER_ATTACHMENT = "other_attachment"
class RiskLevel(str, enum.Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
BLOCKED = "blocked"
class RuleAction(str, enum.Enum):
PASS = "pass"
WARN = "warn"
REQUIRE_EXPLANATION = "require_explanation"
REQUIRE_ATTACHMENT = "require_attachment"
REQUIRE_APPROVAL = "require_approval"
BLOCK = "block"
class SyncStatus(str, enum.Enum):
SUCCESS = "success"
FAILED = "failed"
RETRYING = "retrying"
PENDING = "pending"
```
- [ ] **Step 2: 定义所有 ORM 模型**
`backend/app/models/base.py`:
```python
import uuid
from datetime import datetime
from sqlalchemy import String, DateTime, func
from sqlalchemy.orm import Mapped, mapped_column
def generate_id():
return str(uuid.uuid4())
class TimestampMixin:
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
class IDMixin:
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=generate_id)
```
`backend/app/models/task.py` — 包含 `ReimbursementTask`,字段按文档 5.2.1 节:
```python
from sqlalchemy import String, Text, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.models.base import IDMixin, TimestampMixin, Base
from app.models.enums import TaskStatus
class ReimbursementTask(IDMixin, TimestampMixin, Base):
__tablename__ = "reimbursement_task"
user_id: Mapped[str] = mapped_column(String(36), index=True)
company_id: Mapped[str] = mapped_column(String(36), index=True)
task_type: Mapped[str] = mapped_column(String(50), default="travel_expense")
status: Mapped[TaskStatus] = mapped_column(default=TaskStatus.CREATED)
user_intent: Mapped[str | None] = mapped_column(Text, nullable=True)
current_agent: Mapped[str | None] = mapped_column(String(50), nullable=True)
# relationships
documents = relationship("ExpenseDocument", back_populates="task", lazy="selectin")
reimbursement = relationship("ShadowReimbursement", back_populates="task", uselist=False, lazy="selectin")
```
`backend/app/models/reimbursement.py` — 包含 `ShadowReimbursement`, `ReimbursementItem`, `SupplementRequest`, `SyncRecord`,字段按文档 5.2.2 ~ 5.2.4, 5.2.7, 5.2.8 节定义。
`backend/app/models/document.py``ExpenseDocument`,字段按文档 5.2.4 节。
`backend/app/models/rule.py``ExpenseRule`, `RuleHit`,字段按文档 5.2.5, 5.2.6 节。
`backend/app/models/audit.py``AuditLog`(通用审计日志表,记录所有关键操作)。
- [ ] **Step 3: 更新 `models/__init__.py` 导出所有模型**
```python
from app.models.task import ReimbursementTask
from app.models.reimbursement import ShadowReimbursement, ReimbursementItem, SupplementRequest, SyncRecord
from app.models.document import ExpenseDocument
from app.models.rule import ExpenseRule, RuleHit
from app.models.audit import AuditLog
from app.models.base import Base
__all__ = [
"ReimbursementTask", "ShadowReimbursement", "ReimbursementItem",
"ExpenseDocument", "ExpenseRule", "RuleHit",
"SupplementRequest", "SyncRecord", "AuditLog", "Base",
]
```
- [ ] **Step 4: 生成 Alembic 迁移**
Run: `cd backend && alembic revision --autogenerate -m "init schema"`
Run: `cd backend && alembic upgrade head`
- [ ] **Step 5: 编写模型测试**
验证所有表能正确创建和插入数据。
- [ ] **Step 6: Commit**
```bash
git add backend/
git commit -m "feat: 完成所有数据模型定义和数据库迁移"
```
---
### Task 1.3: 前端项目骨架搭建
**Files:**
- Create: 使用 Vite 初始化 Vue3 + TypeScript 项目
- Create: `frontend/src/router/index.ts`
- Create: `frontend/src/stores/` — Pinia stores
- Create: `frontend/src/api/` — API 调用封装
- Create: `frontend/src/views/` — 页面
- Create: `frontend/src/components/` — 组件
- Create: `frontend/src/layouts/` — 布局
- Test: `frontend/src/App.vue`
- [ ] **Step 1: 初始化 Vue3 项目**
```bash
npm create vite@latest frontend -- --template vue-ts
cd frontend
npm install ant-design-vue @ant-design/icons-vue vue-router pinia axios dayjs
```
目录结构:
```
frontend/
├── src/
│ ├── api/ # API 调用
│ │ ├── index.ts # axios 实例
│ │ ├── task.ts # 报销任务 API
│ │ ├── document.ts # 票据 API
│ │ └── precheck.ts # 预审 API
│ ├── components/ # 通用组件
│ │ ├── FileUpload.vue
│ │ ├── ExpenseTable.vue
│ │ └── RuleHitCard.vue
│ ├── layouts/
│ │ └── MainLayout.vue
│ ├── router/
│ │ └── index.ts
│ ├── stores/
│ │ ├── task.ts
│ │ └── user.ts
│ ├── views/
│ │ ├── HomeView.vue # 报销入口
│ │ ├── UploadView.vue # 票据上传
│ │ ├── DraftView.vue # 报销草稿
│ │ ├── PrecheckView.vue # 预审结果
│ │ ├── SupplementView.vue # 补件交互
│ │ ├── ConfirmView.vue # 提交确认
│ │ └── AuditView.vue # 审计日志
│ ├── App.vue
│ └── main.ts
├── index.html
├── vite.config.ts
├── tsconfig.json
└── package.json
```
- [ ] **Step 2: 配置路由和布局**
`frontend/src/router/index.ts`:
```typescript
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{ path: '/', name: 'home', component: () => import('@/views/HomeView.vue') },
{ path: '/task/:taskId/upload', name: 'upload', component: () => import('@/views/UploadView.vue') },
{ path: '/task/:taskId/draft', name: 'draft', component: () => import('@/views/DraftView.vue') },
{ path: '/task/:taskId/precheck', name: 'precheck', component: () => import('@/views/PrecheckView.vue') },
{ path: '/task/:taskId/supplement', name: 'supplement', component: () => import('@/views/SupplementView.vue') },
{ path: '/task/:taskId/confirm', name: 'confirm', component: () => import('@/views/ConfirmView.vue') },
{ path: '/audit', name: 'audit', component: () => import('@/views/AuditView.vue') },
]
export default createRouter({ history: createWebHistory(), routes })
```
- [ ] **Step 3: 配置 API 封装**
`frontend/src/api/index.ts`:
```typescript
import axios from 'axios'
const api = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000/api/v1',
timeout: 30000,
})
export default api
```
- [ ] **Step 4: 确认前端能正常启动**
Run: `cd frontend && npm run dev`
Expected: 浏览器访问 http://localhost:5173 能看到页面
- [ ] **Step 5: Commit**
```bash
git add frontend/
git commit -m "feat: 初始化前端项目骨架Vue3 + TypeScript + Ant Design Vue"
```
---
### Task 1.4: Docker Compose 开发环境
**Files:**
- Create: `docker-compose.yml`
- Create: `backend/Dockerfile`
- Create: `frontend/Dockerfile`
- Create: `.env.example`
- Create: `backend/init.sql`(初始数据)
- [ ] **Step 1: 编写 docker-compose.yml**
```yaml
version: "3.8"
services:
postgres:
image: postgres:15
environment:
POSTGRES_DB: x_financial
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
minio:
image: minio/minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_data:/data
volumes:
pgdata:
minio_data:
```
- [ ] **Step 2: 编写 .env.example**
按 config.py 中的字段列出所有环境变量,标注必填/选填。
- [ ] **Step 3: 验证环境启动**
Run: `docker-compose up -d`
Run: `docker-compose ps`
Expected: postgres, redis, minio 均为 running
- [ ] **Step 4: Commit**
```bash
git add docker-compose.yml .env.example backend/Dockerfile frontend/Dockerfile
git commit -m "feat: 添加 Docker Compose 开发环境PostgreSQL + Redis + MinIO"
```
---
## Phase 2: 后端核心服务W2-W3
### Task 2.1: 报销任务管理 API
**Files:**
- Create: `backend/app/schemas/task.py`
- Create: `backend/app/services/task_service.py`
- Create: `backend/app/api/v1/tasks.py`
- Modify: `backend/app/api/v1/router.py`
- Test: `backend/tests/test_task_api.py`
- [ ] **Step 1: 定义 Pydantic schemas**
`backend/app/schemas/task.py` — 包含 `TaskCreateRequest`, `TaskResponse`, `TaskListResponse` 等请求/响应模型,字段按文档第 8 节 API 定义。
- [ ] **Step 2: 实现 TaskService 业务逻辑**
包含方法:
- `create_task(user_id, company_id, user_intent)` → 创建任务,状态设为 `CREATED`
- `get_task(task_id)` → 查询任务详情
- `list_tasks(user_id, status, page, size)` → 分页查询
- `update_status(task_id, status, current_agent)` → 更新任务状态
- [ ] **Step 3: 实现 API 路由**
`POST /api/v1/reimbursement/tasks` — 创建报销任务(对应文档 8.1
`GET /api/v1/reimbursement/tasks/{task_id}` — 查询任务详情
`GET /api/v1/reimbursement/tasks` — 列表查询
- [ ] **Step 4: 编写测试**
```python
@pytest.mark.asyncio
async def test_create_task(client):
response = await client.post("/api/v1/reimbursement/tasks", json={
"user_id": "U001",
"company_id": "C001",
"user_intent": "我要报这次北京出差的费用",
"entry_channel": "web"
})
assert response.status_code == 201
data = response.json()
assert "task_id" in data
assert data["status"] == "material_collecting"
```
- [ ] **Step 5: Commit**
```bash
git add backend/
git commit -m "feat: 实现报销任务管理 API创建/查询/列表)"
```
---
### Task 2.2: 文件上传与票据管理 API
**Files:**
- Create: `backend/app/schemas/document.py`
- Create: `backend/app/services/document_service.py`
- Create: `backend/app/services/storage_service.py`
- Create: `backend/app/api/v1/documents.py`
- Modify: `backend/app/api/v1/router.py`
- Test: `backend/tests/test_document_api.py`
- [ ] **Step 1: 实现 MinIO 存储服务**
`storage_service.py` — 封装 MinIO 操作:
- `upload_file(bucket, file_name, file_data, content_type)` → 上传文件
- `get_file_url(bucket, file_name)` → 获取文件 URL
- `delete_file(bucket, file_name)` → 删除文件
- [ ] **Step 2: 实现文档服务**
`document_service.py`:
- `upload_document(task_id, file, document_type)` → 保存文件到 MinIO创建 DB 记录
- `get_documents(task_id)` → 查询任务下所有票据
- `update_ocr_result(document_id, ocr_result)` → 更新 OCR 识别结果
- [ ] **Step 3: 实现 API 路由**
`POST /api/v1/reimbursement/tasks/{task_id}/documents` — 上传票据(对应文档 8.2
`GET /api/v1/reimbursement/tasks/{task_id}/documents` — 查询票据列表
支持 multipart/form-data 文件上传。
- [ ] **Step 4: 编写测试**
使用 mock MinIO测试文件上传和记录创建。
- [ ] **Step 5: Commit**
```bash
git add backend/
git commit -m "feat: 实现文件上传与票据管理 APIMinIO 存储)"
```
---
### Task 2.3: OCR 服务集成
**Files:**
- Create: `backend/app/services/ocr_service.py`
- Create: `backend/app/services/ocr_providers/base.py`
- Create: `backend/app/services/ocr_providers/baidu.py`
- Create: `backend/app/services/ocr_providers/mock.py`
- Test: `backend/tests/test_ocr_service.py`
- [ ] **Step 1: 定义 OCR Provider 抽象接口**
`ocr_providers/base.py`:
```python
from abc import ABC, abstractmethod
from dataclasses import dataclass
@dataclass
class OCRResult:
document_type: str # 识别出的票据类型
raw_text: str # 原始文字
fields: dict # 结构化字段
confidence: float # 整体置信度
provider: str # 提供商
class OCRProvider(ABC):
@abstractmethod
async def recognize(self, file_url: str, document_type: str | None = None) -> OCRResult:
...
```
- [ ] **Step 2: 实现 Mock OCR Provider开发测试用**
`mock.py` — 根据文件名/类型返回预定义的结构化数据,用于开发阶段不依赖真实 OCR。
- [ ] **Step 3: 实现百度 OCR Provider**
`baidu.py` — 调用百度云 OCR API支持
- 增值税发票识别
- 火车票识别
- 机票行程单识别
- 通用票据识别(兜底)
将百度返回结果标准化为 `OCRResult`
- [ ] **Step 4: 实现 OCR Service 门面**
`ocr_service.py`:
- `recognize(file_url, document_type)` → 根据 `config.OCR_PROVIDER` 选择 provider
- 自动识别票据类型(如果未指定)
- 返回标准化 `OCRResult`
- 更新 document 表的 `ocr_status``extracted_json`
- [ ] **Step 5: 编写测试**
使用 Mock Provider 测试完整流程。
- [ ] **Step 6: Commit**
```bash
git add backend/
git commit -m "feat: 实现 OCR 服务(百度云 + Mock Provider"
```
---
### Task 2.4: 规则引擎
**Files:**
- Create: `backend/app/services/rule_engine.py`
- Create: `backend/app/schemas/rule.py`
- Create: `backend/app/api/v1/rules.py`
- Create: `backend/app/services/rule_checkers/__init__.py`
- Create: `backend/app/services/rule_checkers/required_fields.py`
- Create: `backend/app/services/rule_checkers/attachment_check.py`
- Create: `backend/app/services/rule_checkers/duplicate_invoice.py`
- Create: `backend/app/services/rule_checkers/amount_limit.py`
- Create: `backend/app/services/rule_checkers/date_validity.py`
- Create: `backend/app/services/rule_checkers/expense_type_match.py`
- Test: `backend/tests/test_rule_engine.py`
- [ ] **Step 1: 定义规则引擎核心接口**
`rule_engine.py``RuleEngine` 类:
```python
class RuleCheckResult:
rule_code: str
severity: RiskLevel
action: RuleAction
message: str
suggestion: str
policy_ref: str
hit_detail: dict
class RuleEngine:
def __init__(self, db: AsyncSession):
self.db = db
self.checkers: dict[str, RuleChecker] = {}
async def run_precheck(self, reimbursement_id: str) -> PrecheckResult:
"""执行完整预审"""
...
async def run_single_rule(self, rule_code: str, context: dict) -> RuleCheckResult | None:
"""执行单条规则"""
...
```
- [ ] **Step 2: 实现 MVP 阶段的 6 条核心规则检查器**
每条规则是一个 `RuleChecker` 类,接收报销数据上下文,返回 `RuleCheckResult | None`
1. `RequiredFieldsChecker` — 必填字段校验
2. `AttachmentCheckChecker` — 附件完整性校验(如住宿费必须上传酒店流水)
3. `DuplicateInvoiceChecker` — 重复发票检查invoice_code + invoice_number + amount 去重)
4. `AmountLimitChecker` — 金额超标校验(按城市/职级/费用类型检查标准)
5. `DateValidityChecker` — 日期合理性校验(费用日期在出差期间内)
6. `ExpenseTypeMatchChecker` — 费用类型与票据类型匹配校验
- [ ] **Step 3: 实现规则管理 API**
- `GET /api/v1/rules` — 列出所有规则
- `POST /api/v1/rules` — 创建规则
- `PUT /api/v1/rules/{rule_id}` — 更新规则
- `PATCH /api/v1/rules/{rule_id}/toggle` — 启用/禁用规则
- [ ] **Step 4: 种子数据**
`backend/alembic/seed/rules.sql` — 预置文档 7.2 节的 3 条示例规则 + 金额标准表。
- [ ] **Step 5: 编写测试**
对每条规则编写单元测试,使用 mock 数据验证命中/未命中场景。
- [ ] **Step 6: Commit**
```bash
git add backend/
git commit -m "feat: 实现规则引擎6 条核心规则 + 管理 API + 种子数据)"
```
---
### Task 2.5: 影子报销账本 CRUD
**Files:**
- Create: `backend/app/schemas/reimbursement.py`
- Create: `backend/app/services/ledger_service.py`
- Create: `backend/app/api/v1/ledger.py`
- Modify: `backend/app/api/v1/router.py`
- Test: `backend/tests/test_ledger_api.py`
- [ ] **Step 1: 定义 Pydantic schemas**
包含:`ReimbursementDraftResponse`, `ReimbursementItemCreate`, `ReimbursementItemResponse`, `PrecheckResultResponse`
- [ ] **Step 2: 实现 LedgerService**
核心方法:
- `create_shadow_reimbursement(task_id, data)` → 创建影子报销记录
- `get_draft(reimbursement_id)` → 获取报销草稿
- `get_draft_by_task(task_id)` → 通过任务 ID 获取草稿
- `update_precheck_result(reimbursement_id, result)` → 更新预审结果
- `add_item(reimbursement_id, item_data)` → 添加报销明细
- [ ] **Step 3: 实现 API 路由**
`GET /api/v1/reimbursement/tasks/{task_id}/draft` — 获取报销草稿(对应文档 8.4
`GET /api/v1/reimbursement/tasks/{task_id}/precheck-result` — 获取预审结果(对应文档 8.5
- [ ] **Step 4: 编写测试**
- [ ] **Step 5: Commit**
```bash
git add backend/
git commit -m "feat: 实现影子报销账本 CRUD API"
```
---
### Task 2.6: 补件与提交 API
**Files:**
- Create: `backend/app/api/v1/supplements.py`
- Create: `backend/app/services/supplement_service.py`
- Create: `backend/app/services/sync_service.py`
- Modify: `backend/app/api/v1/router.py`
- Test: `backend/tests/test_supplement_api.py`
- [ ] **Step 1: 实现补件服务**
`supplement_service.py`:
- `create_supplement_request(reimbursement_id, items)` → 创建补件请求
- `respond_supplement(request_id, response_text, document_ids)` → 用户补件响应
- `get_supplement_requests(task_id)` → 查询补件请求列表
- [ ] **Step 2: 实现同步服务MVP 阶段为模拟)**
`sync_service.py`:
- `mock_sync_to_backend(reimbursement_id)` → 模拟后端同步,生成假的 backend_bill_id
- `get_sync_status(task_id)` → 查询同步状态
- [ ] **Step 3: 实现 API 路由**
`POST /api/v1/reimbursement/tasks/{task_id}/supplements` — 用户补件(对应文档 8.6
`POST /api/v1/reimbursement/tasks/{task_id}/submit` — 用户确认提交(对应文档 8.7
`GET /api/v1/reimbursement/tasks/{task_id}/sync-status` — 查询同步状态(对应文档 8.8
- [ ] **Step 4: 编写测试**
- [ ] **Step 5: Commit**
```bash
git add backend/
git commit -m "feat: 实现补件与提交确认 API含模拟同步"
```
---
## Phase 3: Agent 编排W3-W4
### Task 3.1: Agent Orchestrator 状态机
**Files:**
- Create: `backend/app/agents/orchestrator.py`
- Create: `backend/app/agents/state.py`
- Create: `backend/app/api/v1/agent.py`
- Modify: `backend/app/api/v1/router.py`
- Test: `backend/tests/test_orchestrator.py`
- [ ] **Step 1: 定义 Agent 状态和上下文**
`agents/state.py`:
```python
from dataclasses import dataclass, field
from app.models.enums import TaskStatus
@dataclass
class AgentContext:
task_id: str
status: TaskStatus
user_intent: str | None = None
current_agent: str | None = None
ocr_results: list[dict] = field(default_factory=list)
reimbursement_data: dict | None = None
precheck_result: dict | None = None
supplement_requests: list[dict] = field(default_factory=list)
error_message: str | None = None
retry_count: int = 0
```
- [ ] **Step 2: 实现 Orchestrator 状态机**
`agents/orchestrator.py` — 核心编排逻辑:
状态转换图(对应文档 4.2 节):
```
CREATED → MATERIAL_COLLECTING → PARSING → DRAFT_GENERATED → PRECHECKING
→ NEED_SUPPLEMENT → MATERIAL_COLLECTING循环
→ PENDING_USER_CONFIRM → SUBMITTING → SYNCED
→ SYNC_FAILED → SUBMITTING重试
```
方法:
- `run(task_id, start_from)` → 启动编排
- `_transition_to(context, new_status, agent_name)` → 状态转换
- `_run_agent(context, agent_name)` → 执行单个 Agent
- `_handle_agent_result(context, result)` → 处理 Agent 返回结果
- [ ] **Step 3: 实现 Agent 启动 API**
`POST /api/v1/reimbursement/tasks/{task_id}/agent/run` — 启动 Agent 处理(对应文档 8.3
- [ ] **Step 4: 编写状态机转换测试**
覆盖所有正常路径和异常路径(解析失败、预审需补件、同步失败重试等)。
- [ ] **Step 5: Commit**
```bash
git add backend/
git commit -m "feat: 实现 Agent Orchestrator 状态机编排"
```
---
### Task 3.2: 5 个 Agent 实现
**Files:**
- Create: `backend/app/agents/base_agent.py`
- Create: `backend/app/agents/intake_agent.py`
- Create: `backend/app/agents/parse_agent.py`
- Create: `backend/app/agents/rule_check_agent.py`
- Create: `backend/app/agents/explain_agent.py`
- Create: `backend/app/agents/sync_agent.py`
- Test: `backend/tests/test_agents.py`
- [ ] **Step 1: 定义 Agent 基类**
`agents/base_agent.py`:
```python
from abc import ABC, abstractmethod
from app.agents.state import AgentContext
class AgentResult:
success: bool
data: dict
next_action: str | None # 继续编排 / 等待用户 / 需要补件
error: str | None
class BaseAgent(ABC):
name: str
@abstractmethod
async def execute(self, context: AgentContext, db: AsyncSession) -> AgentResult:
...
```
- [ ] **Step 2: 实现受理 AgentIntakeAgent**
职责:理解用户意图,收集上下文。
- 分析 user_intent 文本,提取报销类型、出差信息
- 调用 LLM 做 intent classification
- 返回结构化的任务信息
- [ ] **Step 3: 实现单据解析 AgentParseAgent**
职责:调用 OCR生成报销草稿。
- 遍历任务下的所有 document调用 ocr_service
- 将 OCR 结果汇总为报销明细
- 创建 ShadowReimbursement + ReimbursementItem
- 自动识别费用类型
- [ ] **Step 4: 实现规则校验 AgentRuleCheckAgent**
职责:调用规则引擎完成预审。
- 从 DB 加载所有 enabled 规则
- 传入报销数据上下文执行规则引擎
- 收集所有 RuleHit
- 计算 overall risk_level
- 更新预审状态
- [ ] **Step 5: 实现解释与补件 AgentExplainAgent**
职责:将规则命中结果转化为用户可理解的解释。
- 遍历 rule_hits使用 LLM 生成自然语言解释
- 创建 supplement_requests缺件类型的自动创建补件请求
- 生成修改建议
- [ ] **Step 6: 实现同步执行 AgentSyncAgent**
职责:生成标准报销单,调用后端同步。
- 将 ShadowReimbursement 数据映射为标准报销单格式
- 调用 sync_service.mock_sync_to_backend
- 记录 SyncRecord
- 处理同步失败重试
- [ ] **Step 7: 编写每个 Agent 的单元测试**
使用 mock DB 和 mock OCR/LLM 测试每个 Agent 的输入输出。
- [ ] **Step 8: Commit**
```bash
git add backend/
git commit -m "feat: 实现 5 个 Agent受理/解析/规则校验/解释补件/同步)"
```
---
### Task 3.3: LLM 集成层
**Files:**
- Create: `backend/app/services/llm_service.py`
- Create: `backend/app/services/llm_prompts/__init__.py`
- Create: `backend/app/services/llm_prompts/intent_classification.py`
- Create: `backend/app/services/llm_prompts/risk_explanation.py`
- Create: `backend/app/services/llm_prompts/expense_type_mapping.py`
- Test: `backend/tests/test_llm_service.py`
- [ ] **Step 1: 实现 LLM Service 封装**
`llm_service.py`:
- `chat(system_prompt, user_message, json_mode)` → 调用 LLM API
- 支持多 providerOpenAI 兼容接口,适配国内模型)
- 统一错误处理和重试
- 响应解析JSON mode
- [ ] **Step 2: 编写 Prompt 模板**
3 个核心 Prompt
- `intent_classification` — 分析用户意图,识别报销类型
- `risk_explanation` — 将规则命中结果转为自然语言解释
- `expense_type_mapping` — 根据 OCR 结果匹配费用类型
- [ ] **Step 3: 编写测试(使用 mock LLM 响应)**
- [ ] **Step 4: Commit**
```bash
git add backend/
git commit -m "feat: 实现 LLM 集成层(多 Provider + Prompt 模板)"
```
---
### Task 3.4: 审计日志
**Files:**
- Create: `backend/app/services/audit_service.py`
- Create: `backend/app/api/v1/audit.py`
- Test: `backend/tests/test_audit.py`
- [ ] **Step 1: 实现 AuditService**
核心方法:
- `log(action, actor, target_type, target_id, detail)` → 记录审计日志
- `query_logs(target_type, target_id, actor, date_range)` → 查询日志
需要记录的动作(对应文档 12.1 节文件上传、OCR 识别、Agent 调用、规则命中、用户补件、用户确认、后端同步。
- [ ] **Step 2: 在所有关键路径埋点**
在 task_service、document_service、ocr_service、rule_engine、orchestrator 的关键操作中调用 `audit_service.log()`
- [ ] **Step 3: 实现审计日志查询 API**
`GET /api/v1/audit/logs` — 查询审计日志(支持按 target_type、target_id、date_range 过滤)
- [ ] **Step 4: 编写测试**
- [ ] **Step 5: Commit**
```bash
git add backend/
git commit -m "feat: 实现审计日志服务(记录 + 查询 API"
```
---
## Phase 4: 前端核心页面W4-W5
### Task 4.1: 报销入口页 + 上传组件
**Files:**
- Create: `frontend/src/views/HomeView.vue`
- Create: `frontend/src/views/UploadView.vue`
- Create: `frontend/src/components/FileUpload.vue`
- Create: `frontend/src/stores/task.ts`
- Create: `frontend/src/api/task.ts`
- Create: `frontend/src/api/document.ts`
- [ ] **Step 1: 实现 API 调用层**
`api/task.ts`:
```typescript
import api from './index'
export const createTask = (data: { userId: string; companyId: string; userIntent: string }) =>
api.post('/reimbursement/tasks', data)
export const getTask = (taskId: string) =>
api.get(`/reimbursement/tasks/${taskId}`)
export const runAgent = (taskId: string, startFrom = 'intake') =>
api.post(`/reimbursement/tasks/${taskId}/agent/run`, { start_from: startFrom, mode: 'precheck' })
```
`api/document.ts`:
```typescript
export const uploadDocument = (taskId: string, file: File, documentType: string) => {
const formData = new FormData()
formData.append('file', file)
formData.append('document_type', documentType)
return api.post(`/reimbursement/tasks/${taskId}/documents`, formData)
}
```
- [ ] **Step 2: 实现报销入口页 HomeView**
按文档 9.2 节:
- 对话输入框(用户输入报销意图)
- 上传按钮
- 最近任务列表
- 常用报销类型快捷按钮("报差旅"、"看发票能不能报"等)
- 智能引导提示
交互流程:用户输入意图 → 调用 createTask → 跳转到上传页
- [ ] **Step 3: 实现文件上传组件 FileUpload**
- 支持拖拽上传
- 支持多文件
- 文件类型校验PDF、JPG、PNG
- 文件大小限制
- 上传进度条
- 预览缩略图
- [ ] **Step 4: 实现票据上传页 UploadView**
- 引用 FileUpload 组件
- 选择票据类型下拉框(增值税发票、火车票、机票行程单等)
- 已上传文件列表
- "开始识别" 按钮 → 调用 runAgent → 跳转到草稿页
- [ ] **Step 5: Commit**
```bash
git add frontend/
git commit -m "feat: 实现报销入口页和票据上传页"
```
---
### Task 4.2: 报销草稿页
**Files:**
- Create: `frontend/src/views/DraftView.vue`
- Create: `frontend/src/components/ExpenseTable.vue`
- Create: `frontend/src/api/precheck.ts`
- [ ] **Step 1: 实现报销草稿页 DraftView**
按文档 9.3 节展示:
- 报销人信息(姓名、部门、成本中心、项目)
- 报销事由
- 费用明细表格ExpenseTable 组件)
- 票据附件缩略图列表
- AI 自动识别结果标注
- 可编辑字段(金额、事由等可修改)
- 预审状态指示器
- "预审" 按钮 → 跳转到预审结果页
- [ ] **Step 2: 实现 ExpenseTable 组件**
- Ant Design Table 展示费用明细
- 列:费用类型、金额、税额、发生日期、城市、商户、风险等级标签
- 支持行内编辑
- 风险等级彩色标签(绿/黄/橙/红)
- [ ] **Step 3: Commit**
```bash
git add frontend/
git commit -m "feat: 实现报销草稿页和费用明细表格组件"
```
---
### Task 4.3: 预审结果页 + 补件交互页
**Files:**
- Create: `frontend/src/views/PrecheckView.vue`
- Create: `frontend/src/views/SupplementView.vue`
- Create: `frontend/src/components/RuleHitCard.vue`
- [ ] **Step 1: 实现预审结果页 PrecheckView**
按文档 9.4 节:
- 总体结论卡片(通过/需补件/有风险)
- 风险等级指示(彩色徽章)
- 通过项列表(绿色勾选)
- 风险项列表RuleHitCard 组件)
- 缺件项列表(橙色提示)
- 每条规则命中显示:问题说明、制度依据、修改建议
- "一键补件" 按钮 → 跳转到补件页
- "确认提交" 按钮(仅预审通过时可用)
- [ ] **Step 2: 实现 RuleHitCard 组件**
- 规则名称和编码
- 风险等级标签
- 问题描述
- 制度依据链接
- 修改建议
- 展开详情
- [ ] **Step 3: 实现补件交互页 SupplementView**
- 显示待补件清单
- 每个补件项:类型(补充附件/补充说明/修改字段)、提示文案
- 上传附件(调用 FileUpload
- 文本回复输入框
- 提交补件 → 调用 supplement API → 跳转回预审页
- [ ] **Step 4: Commit**
```bash
git add frontend/
git commit -m "feat: 实现预审结果页和补件交互页"
```
---
### Task 4.4: 提交确认页 + 审计日志页
**Files:**
- Create: `frontend/src/views/ConfirmView.vue`
- Create: `frontend/src/views/AuditView.vue`
- Create: `frontend/src/api/audit.ts`
- [ ] **Step 1: 实现提交确认页 ConfirmView**
- 最终报销单摘要(不可编辑)
- 总金额确认
- 费用明细汇总
- 附件清单
- 同步目标系统选择MVP 默认 expense_system
- "确认提交" 按钮 → 调用 submit API
- 同步状态轮询展示(提交中 → 已同步/同步失败)
- [ ] **Step 2: 实现审计日志页 AuditView**
按文档 9.5 节(简化版):
- 时间线展示所有操作记录
- 筛选:按任务、操作类型、时间范围
- 每条日志:时间、操作人、操作类型、详情
- [ ] **Step 3: Commit**
```bash
git add frontend/
git commit -m "feat: 实现提交确认页和审计日志页"
```
---
## Phase 5: 联调与集成W5-W6
### Task 5.1: 前后端联调
**Files:**
- Modify: 多个前后端文件(修复联调问题)
- [ ] **Step 1: 启动前后端全栈**
后端:`cd backend && uvicorn app.main:app --reload`
前端:`cd frontend && npm run dev`
- [ ] **Step 2: 跑通完整报销流程**
按文档 3.1 节的 10 步流程:
1. 在首页创建报销任务
2. 上传 2-3 张模拟票据(增值税发票、火车票、酒店流水)
3. 点击"开始识别" → Agent 启动
4. 查看草稿页 → 确认自动识别结果
5. 执行预审 → 查看预审结果
6. 如有缺件/风险 → 补件
7. 确认提交 → 查看同步状态
8. 查看审计日志
- [ ] **Step 3: 修复联调过程中发现的问题**
API 响应格式不一致、字段缺失、前后端类型不匹配等。
- [ ] **Step 4: Commit**
```bash
git add .
git commit -m "fix: 前后端联调修复"
```
---
### Task 5.2: 规则配置与种子数据
**Files:**
- Create: `backend/alembic/seed/expense_policies.sql`
- Create: `backend/alembic/seed/expense_rules.sql`
- Create: `backend/alembic/seed/city_levels.sql`
- Create: `backend/alembic/seed/hotel_limits.sql`
- [ ] **Step 1: 编写差旅报销制度种子数据**
按典型企业差旅报销制度配置:
- 城市等级(一线/二线/三线)
- 住宿标准(按城市等级 × 职级)
- 交通标准(高铁/飞机按职级)
- 餐补标准
- 必须上传的附件类型映射
- [ ] **Step 2: 编写规则种子数据**
至少配置文档 7.2 节的 3 条示例规则 + MVP 需要的 6 条核心规则。
- [ ] **Step 3: 编写数据初始化脚本**
`backend/scripts/seed_data.py` — 一键初始化所有种子数据。
- [ ] **Step 4: Commit**
```bash
git add backend/
git commit -m "feat: 添加差旅报销制度和规则种子数据"
```
---
## Phase 6: 测试与打磨W7-W8
### Task 6.1: 后端集成测试
**Files:**
- Create: `backend/tests/test_integration_flow.py`
- Create: `backend/tests/conftest.py`(更新,添加测试数据库 fixture
- [ ] **Step 1: 编写完整流程集成测试**
```python
@pytest.mark.asyncio
async def test_full_reimbursement_flow(db, client):
# 1. 创建任务
task = await create_task(client, user_id="U001", intent="报北京出差费用")
assert task["status"] == "material_collecting"
# 2. 上传票据
doc1 = await upload_document(client, task["task_id"], "vat_invoice", "invoice.pdf")
doc2 = await upload_document(client, task["task_id"], "train_ticket", "train.pdf")
# 3. 启动 Agent
result = await run_agent(client, task["task_id"])
assert result["status"] in ["draft_generated", "prechecking"]
# 4. 获取草稿
draft = await get_draft(client, task["task_id"])
assert len(draft["items"]) > 0
# 5. 获取预审结果
precheck = await get_precheck_result(client, task["task_id"])
assert "risk_level" in precheck
# 6. 如果需要补件
if precheck["precheck_status"] == "need_supplement":
supplements = precheck["rule_hits"]
for s in supplements:
if s["action"] == "require_attachment":
await respond_supplement(client, task["task_id"], s["id"], "已补充")
# 重新预审
await run_agent(client, task["task_id"], start_from="precheck")
# 7. 确认提交
submit = await submit_task(client, task["task_id"])
assert submit["status"] == "submitting"
# 8. 检查同步状态
sync = await get_sync_status(client, task["task_id"])
assert sync["sync_status"] == "success"
```
- [ ] **Step 2: 确保所有测试通过**
Run: `cd backend && pytest tests/ -v --tb=short`
Expected: All PASS
- [ ] **Step 3: Commit**
```bash
git add backend/
git commit -m "test: 添加完整报销流程集成测试"
```
---
### Task 6.2: 前端 E2E 测试(可选)
**Files:**
- Create: `frontend/e2e/reimbursement.spec.ts`(如选用 Playwright
- [ ] **Step 1: 安装 Playwright**
```bash
cd frontend && npm install -D @playwright/test
npx playwright install
```
- [ ] **Step 2: 编写核心流程 E2E 测试**
模拟用户从创建任务到提交确认的完整操作。
- [ ] **Step 3: 确保测试通过**
- [ ] **Step 4: Commit**
```bash
git add frontend/
git commit -m "test: 添加前端 E2E 测试"
```
---
### Task 6.3: Bug 修复与 UI 打磨
- [ ] **Step 1: 走查所有页面,修复视觉和交互问题**
- 响应式布局适配
- Loading 状态
- 错误提示
- 空状态
- 表单校验
- [ ] **Step 2: 添加 Demo 数据展示效果**
- [ ] **Step 3: Commit**
```bash
git add .
git commit -m "fix: UI 打磨和 Bug 修复"
```
---
### Task 6.4: 部署与文档
**Files:**
- Create: `docker-compose.prod.yml`
- Modify: `README.md`
- Create: `docs/api.md`
- Create: `docs/deployment.md`
- [ ] **Step 1: 编写生产 Docker Compose**
包含前后端 + DB + Redis + MinIO + Nginx 反向代理。
- [ ] **Step 2: 编写部署文档**
环境要求、配置说明、启动步骤、常用运维命令。
- [ ] **Step 3: 编写 API 文档**
FastAPI 自动生成 Swagger补充说明和示例。
- [ ] **Step 4: 更新 README**
项目简介、架构图、快速启动、开发指南。
- [ ] **Step 5: Commit**
```bash
git add .
git commit -m "docs: 添加部署文档和 README"
```
---
## 任务总览
| Phase | 周数 | 任务数 | 可并行 |
|---|---|---|---|
| Phase 1: 项目基建 | W1 | 4 | 前端骨架 + 后端骨架 + Docker 可并行 |
| Phase 2: 后端核心 | W2-W3 | 6 | 任务API + 文件上传 + OCR 可并行 |
| Phase 3: Agent 编排 | W3-W4 | 4 | Orchestrator → Agents → LLM → 审计(部分串行) |
| Phase 4: 前端页面 | W4-W5 | 4 | 草稿/预审/补件/确认页可并行 |
| Phase 5: 联调集成 | W5-W6 | 2 | 联调 + 种子数据 |
| Phase 6: 测试打磨 | W7-W8 | 4 | 测试 + 修复 + 部署 |
| **总计** | **8 周** | **26 个任务** | |
---
## 风险与缓解
| 风险 | 影响 | 缓解措施 |
|---|---|---|
| OCR 识别准确率不够 | 草稿数据错误 | 允许用户手动修改,低置信度高亮提示 |
| LLM 响应慢或幻觉 | 用户体验差 | Prompt 严格约束输出格式,超时 fallback |
| 规则引擎复杂度超预期 | 延期 | MVP 先做 6 条硬编码规则JSON 配置化后续迭代 |
| 前后端联调问题多 | 延期 | W5 提前开始联调,边开发边对齐 API |
| 3-5 人不够 | 交付延期 | 优先砍规则管理页和审计页W8 补) |
---
## 验收标准
MVP 完成的标志:
- [x] 用户能通过 Web 界面创建差旅报销任务
- [x] 上传 3 种以上票据类型(增值税发票、火车票、酒店流水)
- [x] OCR 自动识别票据信息并生成报销草稿
- [x] 规则引擎执行 6 条核心预审规则
- [x] 预审结果以可视化方式展示(风险等级、命中规则、修改建议)
- [x] 用户能补件并重新预审
- [x] 用户确认后模拟同步成功
- [x] 影子报销账本完整记录业务数据
- [x] 审计日志记录所有关键操作
- [x] 完整流程端到端测试通过