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, 发票抽取, 后端开发, 异步任务队列, 搜索引擎查询, 测试用例, 版权保护, 用户代理, 自定义请求头