vinsblack/production-ai-document-backend
GitHub: vinsblack/production-ai-document-backend
一个基于 FastAPI 的生产级 AI 文档处理后端,提供异步发票提取、确定性验证、任务恢复机制及完整的可观测性与身份验证体系。
Stars: 0 | Forks: 0
# 生产级 AI 文档后端
一个面向生产环境的 FastAPI 服务,提供经过身份验证的、异步的发票提取和确定性验证。PostgreSQL 是唯一事实来源,Redis 和 ARQ 提供后台交付支持,每个请求都可以通过 API、worker、provider、持久化、恢复和可选的 webhook 阶段进行追踪。
## 架构
```
flowchart LR
C["User or service"] -->|"JWT or X-API-Key"| A["FastAPI + RBAC"]
A --> L["Redis rate limiter"]
A -->|"document + QUEUED job"| P[("PostgreSQL")]
A -->|"job ID + correlation/trace context"| Q[("Redis / ARQ")]
Q --> W["ARQ worker"]
W --> V["AI provider"]
V --> D["Deterministic validator"]
W --> P
W -. "terminal webhook" .-> H["External consumer"]
A --> AU[("Append-only audit events")]
A --> M["Prometheus metrics"]
A -. "OpenTelemetry" .-> O["OTLP collector (optional)"]
W -. "OpenTelemetry" .-> O
```
Redis 绝不承载文档内容。数据库约束、条件声明、持久化的尝试记录以及过期任务恢复机制,共同保护了从 PostgreSQL 到 Redis 的交接过程以及 worker 的执行。请参阅[架构](docs/architecture.md)、[异步处理](docs/async-processing.md)和[运维](docs/operations.md)。
## 技术
Python 3.12、FastAPI、Pydantic Settings、SQLAlchemy asyncio、Alembic、PostgreSQL、Redis、ARQ、HTTPX、PyJWT、通过 pwdlib 实现的 Argon2、Prometheus、OpenTelemetry、Docker Compose、Ruff、Pytest 以及 GitHub Actions。
## 快速开始
```
python -m venv .venv
# 激活 virtual environment
python -m pip install -e ".[dev]"
cp .env.example .env
alembic upgrade head
python -m app.cli create-user --email admin@example.com --role admin
uvicorn app.main:app --reload
```
在另一个终端中运行 worker:
```
python -m app.workers.document_worker
```
Swagger 位于 。仅用于开发的 `mock` provider 可离线工作。系统故意没有提供公开的注册 endpoint;初始管理员会在数据库迁移后通过交互式 CLI 进行配置。
## 身份验证与授权
```
sequenceDiagram
participant Client
participant API
participant DB as PostgreSQL
Client->>API: POST /api/v1/auth/token (email + password)
API->>DB: verify active user and Argon2 hash
API-->>Client: short access token + refresh token
Client->>API: Bearer access token
API->>DB: validate active subject
API->>API: enforce admin/operator/service role
Client->>API: POST /api/v1/auth/refresh
API->>DB: rotate persisted token digest
API-->>Client: new token pair
```
Access token 默认有效期为 15 分钟。Refresh token 默认有效期为七天,仅以 SHA-256 摘要的形式存储,并在轮换时撤销。Token 会验证签名、签发者、受众、类型、有效期、主体以及活跃用户状态。JWT payload 仅包含身份标识和授权声明。
角色划分经过刻意精简:
- `admin`:API key 管理、审计读取以及所有文档操作;
- `operator`:文档操作和手动重试;
- `service`:常规的文档和任务操作。
受信任的集成可以使用 `X-API-Key`。密钥仅在创建时返回,使用 `API_KEY_PEPPER` 作为 HMAC-SHA256 摘要进行持久化,与活跃的所有者和角色相关联,并支持撤销和最后使用时间追踪。
```
curl -X POST http://localhost:8000/api/v1/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=admin@example.com&password=YOUR_PASSWORD"
curl -X POST http://localhost:8000/api/v1/api-keys \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"invoice-ingestor","role":"service"}'
```
## API 与处理
在受保护的路由上使用 `Authorization: Bearer ...` 或 `X-API-Key: ...`。
```
curl -F "file=@examples/valid_invoice.txt;type=text/plain" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "X-Correlation-ID: client-operation-123" \
http://localhost:8000/api/v1/documents
curl -H "Authorization: Bearer ACCESS_TOKEN" \
http://localhost:8000/api/v1/jobs/JOB_UUID
curl -H "Authorization: Bearer ACCESS_TOKEN" \
http://localhost:8000/api/v1/documents/DOCUMENT_UUID
```
提交请求会返回 `202 Accepted`。文档的生命周期为 `RECEIVED → PROCESSING → COMPLETED`、`NEEDS_REVIEW` 或 `FAILED`;任务的生命周期还增加了 `QUEUED`、`RETRY_SCHEDULED` 和 `CANCELLED`。临时的 Redis 交接失败会将任务保持为可恢复的 `QUEUED` 状态,并将文档保持为 `RECEIVED` 状态。
```
sequenceDiagram
participant Client
participant API
participant DB as PostgreSQL
participant Redis
participant Worker
Client->>API: authenticated upload + X-Correlation-ID
API->>DB: commit document and QUEUED job
API->>Redis: job ID + correlation ID + trace context
API-->>Client: 202 + X-Correlation-ID
Redis->>Worker: backward-compatible payload
Worker->>DB: conditional claim; increment attempt
Worker->>Worker: AI extraction + deterministic validation
Worker->>DB: persist result and terminal state
```
只有在成功声明数据库记录时,worker 才会递增 `attempt_count`。`QUEUED` 恢复永远不会消耗尝试次数,也不会将文档标记为失败。请参阅 [provider 集成](docs/provider-integration.md)和 [webhook](docs/webhooks.md)。
## 限流、关联追踪与审计
登录和刷新操作受源 IP 限制。受保护的路由则根据用户或 API key 的身份分别进行限制。Redis 的键基于环境划分命名空间,并包含经过哈希处理的身份标识。默认策略被刻意设定为**故障开放 (fail-open)**:Redis 宕机不会导致限流器演变成全局 API 宕机;该事件会被记录下来,但就绪检查依然会失败。拒绝请求会返回 HTTP 429 和 `Retry-After`。
系统接受有效的传入 `X-Correlation-ID`;否则 API 会自动生成一个。该 ID 会同时作为 `X-Correlation-ID` 和旧版的 `X-Request-ID` 返回,通过 `contextvars` 绑定,持久化到任务中,通过 ARQ 和出站调用进行传递,并在 worker 日志中恢复。启用 tracing 时,W3C trace context 会单独进行传递。
涉及安全和业务关键的操作会被存储在 `audit_events` 中。涵盖范围包括登录、刷新、API key 管理、文档提交/重试以及过期恢复。审计写入作为尽力而为的事务发生在业务事务之后;如果审计写入失败,系统会记录日志并进行计量,但不会回滚已提交的业务状态。密码、token、原始 API key、文档内容以及 provider payload 绝不会作为审计元数据。
## 健康检查与可观测性
- `GET /health/live`:仅检查进程存活状态;不检查依赖项。
- `GET /health/ready`:检查 PostgreSQL 和 Redis 就绪状态;失败时返回 HTTP 503。
- `GET /health`:结构化的 `healthy`、`degraded` 或 `unhealthy` 组件状态。
- `GET /metrics`:带有有限标签的 Prometheus 指标。
出于向后兼容性考虑,旧版的 `/api/v1/health`、`/api/v1/ready` 和 `/api/v1/readiness` 依然可用。
OpenTelemetry 是可选启用的,需设置 `OTEL_TRACING_ENABLED=true`。FastAPI、SQLAlchemy、Redis、HTTPX、worker 执行、任务排队、声明、提取、持久化、恢复以及 webhook 交付都会被追踪。将 `OTEL_EXPORTER_OTLP_ENDPOINT` 设置为 OTLP/HTTP trace endpoint;如果留空,则会将 tracing 保持在本地,且不需要部署 collector。
出站 trace URL 仅保留网络源信息;身份验证 header、文档正文、用作指标标签的 ID 以及密钥均不会被记录。
Prometheus 包含身份验证/API key 失败、限流拒绝、就绪检查和审计写入失败、HTTP 延迟、worker 处理延迟,以及任务、provider 和 webhook 的结果。任何用户、文档、任务、关联标识、邮箱、URL 或异常消息的值都不会用作指标标签。
## Docker Compose
```
docker compose up --build
```
Compose 是一个带有演示性凭证的开发技术栈,用于启动 API、worker、PostgreSQL 和持久化的 Redis。PostgreSQL 和 Redis 保持在私有网络中。在生产部署中,请替换所有凭证,选择真实的 provider,设置 `ENVIRONMENT=production`,并提供唯一的 JWT/API key 密钥。生产环境的验证机制会拒绝 SQLite、调试模式、mock provider、缺失的 provider 密钥以及开发专用的密钥。
## 配置
每个设置项都在 [.env.example](.env.example) 中列出,并在[配置参考](docs/configuration.md)中进行了文档说明。重要的配置组包括:
- 身份认证:`JWT_*`、access/refresh 生命周期、`API_KEY_PEPPER`;
- 滥用控制:匿名/已认证用户限制、时间窗口、故障开放策略;
- 持久化/队列:数据库和 Redis URL、任务超时和恢复阈值;
- Tracing:启用标志、服务名称、可选的 OTLP endpoint;
- Provider/Webhook:provider 密钥/模型、超时时间、重试边界;
- 应用程序:环境、日志记录、API 前缀、上传/验证边界。
`JOB_QUEUED_STALE_AFTER_SECONDS` 刻意不同于 `JOB_STALE_AFTER_SECONDS`;后者必须大于 `JOB_TIMEOUT_SECONDS`。在启动不安全的生产环境应用程序或 worker 之前,如果设置存在问题,系统会快速失败。
## 迁移、测试与 CI
```
ruff check .
pytest --cov=app --cov-report=term-missing
alembic upgrade head
alembic downgrade -1
alembic upgrade head
docker compose config --quiet
```
CI 提供了两个互补级别的验证:
- **离线验证**:在 Python 3.12 环境下运行,使用 SQLite、mock 的 HTTP、模拟的 Redis 和队列实现,以及内存中的 OpenTelemetry exporter。这些测试是确定性的,并且不会连接外部的 AI provider。
- **集成验证**:在真实的 PostgreSQL 16 和 Redis 7 服务上运行。它用于验证 Alembic 迁移、refresh token 并发、Redis Lua 脚本、TTL 行为,以及与部署中使用的基础设施的兼容性。
没有任何测试需要外部 AI provider,因此完整的 pipeline 依然可以完全复现。
## 安全考量与已知的权衡
密码使用 Argon2,且不存储原始的服务密钥。结构化日志会对常见的 token/key/password 格式进行脱敏处理,错误会被净化,上传大小受到限制,并且远程 provider 凭证使用 header 而非查询字符串传递。
当前刻意保留的限制已在[安全](docs/security.md)文档中记录:webhook URL 检查无法提供完整的 SSRF 防护;限流采用的是固定窗口且故障开放模式;审计交付属于尽力而为,而非外部不可变账本;JWT 签名目前使用的是对称密钥;文档字节依然保留在 PostgreSQL 中;而 webhook HMAC 签名、恶意软件扫描、OCR、对象存储以及 Kubernetes 均不包含在本次迭代范围内。
标签:AI文档处理, AV绕过, FastAPI, PostgreSQL, Redis, 发票抽取, 后端开发, 异步任务队列, 搜索引擎查询, 测试用例, 版权保护, 用户代理, 自定义请求头