Tender Service 系统架构与完整功能清单¶
代码盘点日期:2026-07-23 适用仓库:
Tender/tender-service事实来源:当前app/、migrations/、tests/、Makefile、Docker Compose 与部署脚本。 文档定位:描述“当前代码实际具备什么”,不把历史设计稿、未注册路由或未来计划当成现行能力。
1. 盘点结论¶
Tender Service 是一个以 FastAPI 为入口、PostgreSQL 为主存储、Redis + ARQ 为异步任务基础设施、S3 兼容对象存储管理文件、LLM/Embedding/向量库提供 AI 能力的模块化单体后端。
当前代码规模与对外能力如下:
| 项目 | 当前数量或状态 |
|---|---|
| FastAPI 已注册业务路由 | 168 个 |
| SQLModel 数据表 | 46 张 |
| 部署配置中的独立 ARQ Worker | 8 类 |
| 测试文件 | 19 个 |
| Alembic 当前 head | f0e1d2c3b4a5 |
| 主要业务域 | 用户、文件、标书、目录、正文、知识库、产品库、图库、Prompt、任务、订阅、额度、支付、管理后台 |
已注册路由分布:
| 路由域 | 数量 |
|---|---|
管理后台 /admin |
40 |
标书 /v1/tenders |
60 |
知识库 /v1/knowledges |
15 |
图库 /v1/image-galleries |
14 |
产品库 /v1/product-libraries |
14 |
用户 /v1/users |
8 |
通用任务 /v1/tasks |
5 |
| 订阅与支付 | 5 |
| 支付回调 | 4 |
通用文件 /v1/files |
2 |
| 健康检查 | 2 |
| 合计 | 169 |
每个已注册路径的用途与接入状态见 MVP v1 接口总览。
2. 总体架构¶
flowchart LR
Client["Web / 管理后台 / 第三方回调"]
API["FastAPI API<br/>路由、鉴权、校验、SSE"]
Services["领域 Service<br/>业务编排与事务"]
DB[("PostgreSQL<br/>46 张业务表")]
Redis[("Redis<br/>ARQ、SSE、缓存、锁")]
OSS[("S3 兼容 OSS<br/>文档与图片")]
Workers["8 类 ARQ Worker"]
LLM["OpenAI 兼容 LLM<br/>解析、生成、对话、图片理解"]
Vector[("Qdrant / DashVector<br/>知识向量")]
External["短信 / 支付宝 / 微信支付"]
Client --> API
API --> Services
Services --> DB
Services --> Redis
Services --> OSS
Services --> LLM
Services --> Vector
Services --> External
API -->|轻量任务 ID| Redis
Redis --> Workers
Workers --> Services
Workers --> DB
Workers --> OSS
Workers --> LLM
Workers --> Vector
Workers -->|进度事件| Redis
Redis -->|SSE / 状态| API
系统采用 route -> service -> model/schema 的主分层:
| 目录 | 职责 |
|---|---|
app/main.py |
创建应用、安装中间件和异常处理器、执行启动恢复、注册路由 |
app/routes/ |
HTTP/SSE 接口、认证依赖、请求响应转换 |
app/services/ |
领域逻辑、任务编排、外部系统调用、持久化协调 |
app/models/ |
SQLModel 数据模型;由 app/models/__init__.py 集中导入 |
app/schemas/ |
Pydantic API DTO、内部传输对象、枚举 |
app/core/ |
配置、数据库、认证、额度、LLM、文档提取、租户上下文等基础设施 |
app/worker/ |
各 ARQ 队列的 WorkerSettings、任务入口和 cron |
app/utils/ |
目录树、文件、文本、价格、Redis DSN 等共享工具 |
migrations/ |
Alembic 数据库迁移 |
tests/ |
以 unittest、IsolatedAsyncioTestCase 为主的聚焦测试 |
核心业务实现定位:
| 业务域 | 路由入口 | 核心实现 |
|---|---|---|
| 用户与短信 | app/routes/v1/users/ |
app/core/security.py、app/services/sms/ |
| 通用文件与 OSS | app/routes/v1/files.py |
app/services/file_upload_service.py、app/services/oss_service.py |
| 标书 CRUD | app/routes/v1/tenders/main.py |
app/services/tender/service.py、reference_service.py |
| 招标文件解析 | app/routes/v1/tenders/document.py、parser.py |
app/services/tender/markdown_parse.py、app/services/parse/ |
| 目录与编写思路 | outline.py、sub_outline.py、writing_hint.py |
app/services/generation/outline_service.py、app/services/parse/outline/ |
| 正文与全文生成 | section.py、generation_runs.py |
app/services/generation/section_service.py、run_service.py、context_assembler.py |
| 清单附件 | app/routes/v1/tenders/checklist_file.py |
app/services/tender/checklist_file_service.py、checklist_parse_service.py |
| 知识库与 RAG | app/routes/v1/knowledges/ |
app/services/knowledge/、app/services/vector_store/ |
| 产品库 | app/routes/v1/product_library/main.py |
app/services/product_library/service.py |
| 图库与图片理解 | app/routes/v1/images/ |
app/services/image/ |
| Prompt 平台 | app/routes/admin/prompt_*.py、app/routes/v1/tenders/prompt.py |
app/services/prompt_template_service.py、prompt_scene_binding_service.py、prompt_preview_service.py |
| 订阅、额度、支付 | app/routes/v1/billing/、app/routes/admin/、app/routes/webhook.py |
app/services/billing/、app/services/subscription/、app/core/security.py |
| 通用任务 | app/routes/tasks.py |
app/services/task_service.py、ingestion_task_log_service.py |
| Worker | 无直接 HTTP 入口 | app/worker/*_jobs.py、app/services/arq_queue_service.py |
这是“模块化单体 + 独立 Worker 进程”,不是微服务拆分:API 与 Worker 共享同一套模型、Service、配置和数据库。
3. 应用启动、请求与数据隔离¶
3.1 启动与关闭¶
FastAPI lifespan 启动时会依次执行:
- 初始化 SQLModel 表。
- 检查 Redis 连通性。
- 迁移旧版 AI 对话 Redis key。
- 校验对象存储配置。
- 恢复或终止因进程重启遗留的运行中任务。
- 将中断的标书任务同步为失败状态,避免永久卡在处理中。
关闭时会取消本进程跟踪的本地异步任务并关闭 Redis 连接池。
数据库正式结构仍由 Alembic 管理;migrations/env.py 与应用读取同一个 ENV_FILE 对应配置。
3.2 统一返回与异常¶
- 路由主要返回统一成功/失败响应结构。
- 业务异常由全局异常处理器包装。
- 未认证会转换为统一的 token 无效响应。
- Pydantic 请求校验错误会转换为统一失败响应。
- CORS 来源来自配置,并暴露下载文件名、目录标识等业务响应头。
- SSE 接口不使用普通 JSON 响应,而是持续输出事件。
3.3 认证、权限与多租户¶
- 登录 token 为 JWT,通过
Authorization: Bearer ...读取。 - SSE 场景额外支持 query 参数中的
access_token。 - 密码摘要使用 PBKDF2-SHA256。
- 当前用户依赖会把
user_id写入 ContextVar。 - SQLModel Session 的 ORM 执行钩子会给带
user_id的模型自动追加租户过滤条件。 - 后台任务和管理员跨用户查询必须显式设置租户上下文或使用
skip_tenant_filter。 - 关键资源路由通常还会再次校验资源所有权,形成“全局租户过滤 + 显式所有权检查”两层保护。
- 管理员路由通常使用
require_admin。
当前代码有两个需要认知清楚的权限事实:
/admin/internal/tenders/*与/admin/prompts/scenes当前只要求已登录,不要求管理员角色。- 用户角色修改接口支持“系统尚无管理员时,第一个用户自助提升为管理员”;之后只有管理员可改角色,并禁止降级最后一个管理员。
4. 完整功能清单¶
4.1 用户、登录与短信验证¶
现有能力:
- 发送短信验证码。
- 手机验证码登录;手机号首次登录时自动注册。
- 手机号与密码登录。
- 获取当前用户。
- 查询和修改个人资料。
- 查询永久额度、套餐额度、总可用额度与订阅摘要。
- 修改用户角色,并处理首位管理员引导与最后一位管理员保护。
- 管理员维护短信验证码白名单。
验证码链路包括:
- Redis 保存验证码、冷却时间、当日发送次数和失败尝试次数。
- 默认 60 秒发送冷却、每日 10 次上限、5 次验证失败上限。
- 支持阿里云短信或开发环境 mock。
- 支持数据库白名单免真实短信。
- 支持管理号码与固定验证码配置。
自动注册会生成 ITB_* 用户名并授予默认永久字数额度。JWT 默认有效期为 7 天。
当前没有已注册的“修改密码”和“绑定手机号”后端接口。
4.2 通用文件与对象存储¶
对象存储通过异步 S3 兼容客户端统一封装,覆盖:
- 获取预签名 PUT URL。
- 客户端直传 OSS。
- 上传确认与对象存在性校验。
- 下载、流式读取、删除、复制、生成临时访问 URL。
- 按用户、标书、知识库、图库划分对象 key。
文件入口包括通用文件、招标文件、清单附件、知识库文件、产品表格和图库图片。
上传格式按业务入口分别限制:
- 招标文件:PDF、DOC、DOCX。
- 清单附件:PDF、DOC、DOCX、XLS、XLSX。
- 产品导入:XLS、XLSX。
- 图库:受支持的图片 MIME。
- 知识库:由知识文件解析能力接受的文档格式。
4.3 标书基础信息与生命周期¶
标书域支持:
- 创建、分页列表、详情、更新、软删除。
- 服务、货物、工程三种行业类型。
- 货物类制造商、经销商角色区分。
- 项目名称、编号、采购人、地区、行业、角色等基础信息。
- 关联知识库、历史知识文件、产品、图库或具体图片。
- 配置清单附件、目录来源、文档样式和生成选项。
ANALYSIS -> OUTLINE -> CONTENT工作步骤切换。- 草稿、解析中、生成中、已完成、失败等任务状态。
删除使用软删除,租户过滤与资源所有权校验共同限制跨用户访问。
4.4 招标文件上传与两阶段解析¶
sequenceDiagram
participant C as 客户端
participant A as API
participant O as OSS
participant R as Redis/ARQ
participant W as TenderParseWorker
participant D as PostgreSQL
participant L as Parser LLM
C->>A: 获取预签名 URL
C->>O: 直传招标文件
C->>A: confirm-parse
A->>D: 创建/锁定 IngestionTask,标书设为 PARSING
A->>R: 入队 parse_markdown
W->>O: 下载文件
W->>W: 隔离子进程提取 Markdown
W->>D: 保存 source_markdown,完成文档提取
C->>A: 订阅 parse-events
A->>R: 确保 quick_parse_stream 唯一执行
W->>D: 读取已发布 Prompt
W->>L: 项目概况与评分标准结构化解析
W->>D: 保存概况、需求、评分条款
W->>R: 发布 SSE 增量和最终事件
R-->>A: Pub/Sub
A-->>C: SSE
第一阶段为文档提取:
- 确认上传时创建或复用
IngestionTask,绑定标书与 OSS 对象。 TenderParseWorker下载文件,并在隔离子进程执行文档提取,避免 Office/PDF 解析阻塞 Worker。- 支持取消轮询。
- 提取后的 Markdown 写入
TenderContent.source_markdown。 - 第一阶段完成后任务进入可继续结构化解析的状态。
第二阶段为快速结构化解析:
- 客户端订阅
parse-events时确保快速解析任务存在。 - Redis claim 防止同一个解析任务被并发重复执行。
- 从数据库解析已发布的
project_overview、scoring_criteriaPrompt。 - 调用解析 LLM,持续通过 Redis Pub/Sub 推送 SSE。
- 保存项目概况、需求条目、评分标准和解析指标。
- 失败、取消和成功都会收口任务与标书状态。
解析结果支持:
- 查询项目概况、原始 Markdown、需求和评分条款。
- 人工 PATCH 修正结构化结果,不再次调用 LLM。
- 清空解析结果,并按接口参数决定是否隐藏文件信息。
底层统一文档解析服务可处理 PDF、DOC、DOCX、XLS、XLSX:
- PDF/DOCX/XLSX 直接解析。
- 旧版 DOC/XLS 通过 LibreOffice
soffice转换。 - 对 OOXML 内容进行文件类型嗅探,避免只信任扩展名。
- 部分调用方可使用
build/doc_parse_cache磁盘缓存。
4.5 目录骨架、节点与编写思路¶
目录能力覆盖从一二级骨架到多级子目录的完整编辑:
- 使用
outline_skeletonPrompt 生成一二级目录。 - 创建自定义目录。
- 导入目录;导入内容不完整时可调用 LLM 补全并标准化。
- 查询目录状态、完整目录树和 Word 目录文件。
- 创建、删除、重命名目录节点。
- 修改标题、页数、预计字数、编写思路和子节点。
- 调整一级章节顺序和二级节点全局顺序。
- 批量保存页数/字数预估。
- AI 预览候选章节,再由用户确认应用。
- 根据指定节点的编写思路预览子目录。
- 创建节点并立即流式生成子目录。
编写思路能力包括:
- 独立存储节点级编写思路及结构化 block。
- 查询已保存编写思路。
- 按标题预览生成。
- 同步生成并按参数决定是否直接应用。
- 子目录 SSE 同时输出元信息、编写思路增量和目录增量。
- 使用稳定
node_uid关联目录、编写思路、正文与历史,目录编号变化不破坏关联。 - 保存目录节点历史,支持追踪关键结构变化。
4.6 单章正文与一键全文生成¶
单章能力:
- 查询单章正文。
- 手工更新正文。
- SSE 生成或重生成单章。
- 查询正文统计和已完成章节集合。
生成上下文由 ContextAssembler 统一组装:
- 当前节点标题、面包屑和兄弟节点。
- 节点编写思路。
- V3 评分项与目录节点关联。
- 人工输入清单。
- 已解析并确认的清单附件文本。
- 知识库语义检索片段。
- 关联产品信息。
- 图库图片及其 AI 分析信息。
正文使用场景 Prompt section_content 与写作模型流式生成,并在完成后持久化。
一键全文生成采用持久化运行模型:
flowchart TD
Create["创建 GenerationRun"]
Estimate["按叶子章节估算字数"]
Reserve["预占用户额度"]
Jobs["创建 GenerationSectionJob"]
Queue["只把 run/job ID 放入 ARQ"]
Load["Worker 从数据库加载完整上下文"]
Generate["流式生成并持久化章节"]
Heartbeat["租约、心跳、重试、恢复"]
Events["Redis SSE + DB 轮询兜底"]
Settle["按实际字数结算,释放剩余额度"]
Final["收口 run、标书和章节状态"]
Create --> Estimate --> Reserve --> Jobs --> Queue --> Load --> Generate
Generate --> Heartbeat
Heartbeat --> Generate
Generate --> Events
Generate --> Settle --> Final
完整运行能力包括:
- 创建全文生成任务。
- 每个叶子章节创建独立持久化 job。
- 分批、按目录顺序调度。
- 队列只传轻量 ID,Worker 从数据库加载上下文。
- 字数额度预占,防止并发超支。
- job 租约、心跳、失败重试、进程重启恢复。
- 查询当前活跃任务。
- Redis 事件流与数据库轮询双路径 SSE。
- 用户取消。
- 按实际生成字数结算,释放未用预占额度。
- 实际超出预估时补扣;额度不足时记录补贴差额。
- 全部章节结束后统一收口标书与运行状态。
代码中仍保留较早的直接全文生成实现,但当前主接口使用 GenerationRun + GenerationSectionJob + ARQ 持久化链路。
4.7 Word 导出与文档样式¶
系统支持:
- 文档样式创建、查询、更新、删除。
- 单独下载目录 Word。
- 导出完整标书 DOCX。
- 生成封面、项目名称、项目编号和系统免责声明。
- 按目录层级输出章节标题与正文。
- 解析 Markdown 标题、段落、列表、表格、富文本和图片。
- 应用默认样式、标书保存样式或用户选择样式。
- 在正文适当位置处理引用信息和图片。
系统免责声明来自 system_configs,导出时属于强制内容。
4.8 清单附件¶
清单附件功能包括:
- 获取预签名 URL 与确认上传。
- 查询标书已绑定附件。
- PDF、DOC、DOCX、XLS、XLSX 解析为 Markdown。
- 独立
ChecklistParseWorker执行解析。 - 查询解析任务和订阅 SSE。
- 重新解析。
- 删除附件。
- 未绑定标书的临时附件默认保留 24 小时。
- Worker 每小时清理过期临时附件。
- 已确认解析文本进入正文生成上下文。
4.9 知识库、向量索引与助手¶
知识库管理:
- 创建、列表、树形查询、更新、删除知识库。
- 查询知识库文件。
- 预签名上传、确认上传。
- 修改文件名或备注。
- 删除文件。
- 查询文件解析 SSE。
- 重新解析与重建索引。
当前确认上传会创建默认目录、知识文件与解析任务。知识解析链路:
- Worker 在隔离子进程提取文档内容。
- 文本切块。
- 调用 OpenAI 兼容 Embedding 接口。
- 写入 Qdrant 或 DashVector。
- 保存文件内容、chunk 元数据、版本和进度。
- 新版本完整可用后原子切换
active_version。 - 清理旧 chunk 和旧向量。
并发与恢复机制包括:
- 文件
version乐观并发控制。 - 候选版本与当前活跃版本隔离。
- CAS fencing,旧 Worker 不可覆盖新任务状态。
- 每 5 分钟清理/协调异常解析任务。
- reparse 与 reindex 分别覆盖重新提取和只重建向量。
知识库语义检索目前作为内部服务使用,供正文生成和知识库助手调用;公开 /search 路由已移除。
知识库助手包括:
- bootstrap 返回知识库就绪状态和可用信息。
- SSE 对话。
- 可选查询改写。
- 按 top-k、最低分数和上下文长度限制检索。
- 输出引用来源、片段和参考文件信息。
- 记录检索、首 token、总耗时和模型 usage。
当前知识库目录 CRUD 代码仍存在,但目录 router 没有挂载到应用;外部 API 只暴露知识库与文件树,不提供目录增删改接口。
4.10 企业产品库¶
产品库功能:
- 创建、列表、更新、软删除产品库。
- 创建、查询、更新、删除单个产品。
- 批量删除产品。
- 用户级产品库与产品访问隔离。
产品表格导入:
- 查询上传规则。
- XLS/XLSX 预签名上传。
- 确认上传并创建解析任务。
- SSE 订阅解析进度。
- 取消解析。
- 并发入场限制,防止单用户占满解析资源。
产品解析是分阶段编排:
- 提取表格文本。
- 提取嵌入图片。
- 识别产品字段。
- AI 图片分类。
- 将图片关联到产品。
- 上传处理后的图片。
- 批量持久化或更新产品。
- 完成任务与清理中间数据。
每一阶段有独立审计记录,任务使用版本 fencing 防止旧任务覆盖新任务。解析使用专门的产品字段模型和图片分类模型配置。
4.11 图库、图片理解与文档抽图¶
图库管理:
- 创建、查询、更新、删除图库。
- 获取图片预签名 URL。
- 确认图片上传。
- 查询图片列表与详情。
- 修改图片元数据。
- 删除图片。
图片理解:
- 上传确认后可自动加入
ImageAnalysisWorker。 - 支持对单图重新分析。
- 使用
image_analysis场景 Prompt。 - 保存标题、描述、标签、分类、适用场景、建议章节和 OCR 文本。
- Redis 维护批次进度,前端通过 SSE 订阅。
文档抽图:
- 支持从 PDF、DOC、DOCX 预览抽取图片。
- 按最小尺寸、最大数量和内容 hash 去重。
- 抽取结果先存临时 OSS。
- Redis 保存 1 小时 extraction session。
- 用户确认后插入图库,并可选择自动执行图片理解。
4.12 标书 AI 对话¶
标书详情内支持:
- SSE AI 对话。
- 清空当前标书会话。
- Redis 保存会话历史,key 按用户与标书隔离。
- 配置历史 TTL、最大消息数和最大字符数。
- 应用启动时迁移旧版嵌套历史 key。
- AI Chat 模型失败时按配置回退。
- 模型返回结构化回复后,按片段输出 SSE。
- 记录操作日志、模型使用量和错误。
4.13 Prompt 模板、版本和场景绑定¶
Prompt 不以代码目录中的 Markdown 文件作为主要运行时来源,而是通过数据库管理:
- Prompt 模板 CRUD。
- 模板版本新建、查询、更新、删除。
- 草稿、已发布、已归档状态。
- 每个模板只允许一个已发布版本。
- Markdown 上传、导入和替换。
- 场景绑定 CRUD。
- 按场景、行业、货物角色和优先级匹配。
- 运行时先选最具体绑定,再回退到通用绑定。
- 标书侧可预览全部场景或解析单个场景的最终 Prompt。
当前定义 14 个业务场景:
document_parseproject_overviewscoring_criteriaoutline_skeletonwriting_hintwriting_hint_chapterwriting_hint_custom_outlinechapter_outline_from_writing_hintwriting_hint_goods_manufacturerwriting_hint_goods_distributorwriting_hint_servicewriting_hint_engineeringsection_contentimage_analysis
app/prompts/ 当前没有承担主要运行时模板资产;内部 Prompt 文件工具只有目录中实际存在文件时才有内容可管理。
4.14 订阅套餐、订单与支付¶
套餐:
- 查询可购买套餐。
- 管理员创建、查看、更新、删除套餐。
- 月付、年付、充值包等类型。
- 立即发放与按月调度发放方式。
- 订单创建时冻结套餐名称、价格、额度和规则快照。
- 管理员手工给用户发放套餐。
订单:
- 创建支付订单。
- 查询订单状态和详情。
- 查询当前用户支付记录和最近支付记录。
- 支持核销码抵扣。
- 在调用支付供应商前先提交待支付订单,避免外部成功但本地无单。
支付宝:
- 支持 Native/页面支付入口。
- 验证异步通知签名。
- 核对 seller、app、金额和支付状态。
- 锁定订单并保证幂等。
微信支付:
- 支持 Native 支付。
- 验证平台签名并解密回调资源。
- 核对商户、app、金额和支付状态。
- 锁定订单并保证幂等。
支付成功后在事务内:
- 更新订单。
- 创建支付记录。
- 按订单快照发放订阅或充值额度。
- 防止重复回调重复发放。
- 对“已支付但当前业务规则不允许自动发放”的情况标记人工复核。
回调同时保留 /webhook/* 和 /v1/webhook/* 两组兼容路径。
4.15 字数额度、预占与订阅维护¶
额度来源:
- 永久额度。
- 月付/年付订阅的有限额度。
- 不限量订阅。
- 年付套餐的按月额度调度。
扣减顺序:
- 活跃不限量订阅。
- 有限套餐额度,优先扣最早到期项。
- 永久额度。
全文生成使用“预占 -> 实际结算”:
- 创建运行时按估算字数预占。
- 完成后按实际字数结算。
- 释放未使用预占。
- 实际超出估算时补扣。
- 额度不足的差额记录为系统补贴,避免已生成内容无法收口。
单章生成也执行额度检查和扣减。所有变动写入 character_transactions。
订阅有效期使用北京时间的排他截止:
valid_until > 当前时间才算有效。- 到达
valid_until时立即失去权益。 - Subscription Worker 每天北京时间 00:00 执行维护,并在 Worker 启动时补跑。
- 维护会过期订阅、清空有限套餐剩余额度、取消调度、为年付套餐发放新周期额度、清理上一周期未用额度。
- 每次维护写入
subscription_maintenance_logs,管理员可查看摘要与明细。
4.16 通用异步任务与 SSE¶
通用任务接口支持:
- 分页查询任务。
- 查询任务日志。
- 查询单个任务状态。
- SSE 订阅任务事件。
- 取消任务。
IngestionTask 与 IngestionTaskLog 为多个解析场景提供统一任务状态、错误、阶段、指标和日志能力。
系统的 SSE 主要有两种数据源:
- Redis Pub/Sub:实时增量、低延迟。
- 数据库状态轮询:全文生成等关键流程的断线或事件丢失兜底。
任务通常将轻量 ID 放入 Redis,Worker 再从 PostgreSQL 加载完整上下文,避免大型 payload 长期驻留队列。
4.17 管理后台¶
已注册管理能力共 40 个路由:
- 全站字数交易流水。
- 注册与支付日报。
- 工作台访问与关键业务成功用户数报表。
- 全站支付流水。
- 手工发放订阅。
- 套餐 CRUD。
- 核销码查询。
- 用户、角色、额度和订阅摘要查询。
- 订阅维护日志与明细查询。
- 短信白名单查询和新增。
- Prompt 场景元数据。
- Prompt 模板与版本管理。
- Prompt 场景绑定管理。
- 内部测试标书创建与详情。
- 内部单文件快速解析。
- 本地 Prompt 文件查询、读取和修改。
需要特别区分:位于 /admin 前缀不自动代表管理员权限,实际权限取决于路由依赖;内部标书工具与 /admin/prompts/scenes 当前只检查登录态。
4.18 健康检查与运行可观测性¶
/health/live:轻量存活检查。/health/ready:检查 PostgreSQL、Redis 和写作模型客户端。- 任务日志:保存阶段、消息、错误与指标。
- 生成运行/job:保存进度、租约、心跳、重试和结算信息。
- 产品解析阶段记录:保存分阶段耗时与结果。
- 操作日志:记录部分用户与 AI 操作。
- 订阅维护日志:记录定时维护摘要与明细。
- Loguru:应用、Worker 和外部调用统一日志。
当前就绪检查不覆盖 Qdrant 和 OSS,因此“/health/ready 正常”不等于全部外部依赖可用。
5. 数据架构¶
当前 SQLModel metadata 共包含 46 张表。
5.1 用户与系统(4)¶
userssystem_configsoperation_logssms_verification_whitelists
5.2 通用任务(2)¶
ingestion_tasksingestion_task_logs
5.3 标书、目录、正文与生成(16)¶
tenderstender_contentstender_scoringtender_requirementstender_outline_writing_hintstender_outline_node_historiestender_section_contentsgeneration_runsgeneration_section_jobstender_checklist_filestender_checklist_parse_jobstender_knowledge_base_referencestender_knowledge_referencestender_product_referencestender_image_referencesdocument_styles
5.4 知识库(6)¶
knowledgesknowledge_dirsknowledge_filesknowledge_file_parse_jobsknowledge_file_contentsknowledge_file_chunks
5.5 产品库(5)¶
product_librariesproductsproduct_parse_jobsproduct_parse_stage_runsproduct_parse_images
5.6 图库(2)¶
image_galleriesimage_files
5.7 Prompt 平台(3)¶
prompt_templatesprompt_template_versionsprompt_scene_bindings
5.8 订阅、额度与支付(8)¶
subscription_plansuser_subscriptionssubscription_quota_schedulescharacter_transactionsorderspayment_recordsredeem_codessubscription_maintenance_logs
6. Worker 与定时任务¶
| Worker | 队列 | 主要任务 | 定时/恢复 |
|---|---|---|---|
| Section Generation | tender_generation |
单章、全文章节生成 | 启动时协调遗留 generation job |
| Tender Parse | tender_parse |
文档提取、快速结构化解析 | 任务恢复由应用/服务共同处理 |
| Tender Source Index | tender_source_index |
历史兼容入口 | 当前实现为 no-op |
| Product Parse | tender_product_parse |
产品表格分阶段解析 | 版本 fencing 与任务恢复 |
| Knowledge Parse | tender_knowledge_parse |
提取、切块、Embedding、向量入库 | 每 5 分钟清理/协调 |
| Checklist Parse | tender_checklist_parse |
清单附件解析 | 每小时清理过期临时附件 |
| Image Analysis | tender_image_analysis |
图片理解与批次进度 | 依任务触发 |
| Subscription | tender_subscription |
订阅过期与周期额度维护 | 北京时间每日 00:00,启动时补跑 |
Makefile 的聚合 worker/worker-test 会启动解析、生成、知识、产品、清单、图片等主要 Worker;订阅 Worker 有独立启动目标。Docker Compose 业务栈包含 API、迁移容器和全部 8 类 Worker。
7. 外部依赖与配置¶
7.1 持久化与基础设施¶
- PostgreSQL:主业务数据库。
- Redis:ARQ 队列、SSE Pub/Sub、分布式 claim/锁、验证码、会话和临时状态。
- S3 兼容 OSS:文档、图片和临时抽图文件。
- Qdrant:默认知识向量库。
- DashVector:可选知识向量库。
- LibreOffice:旧版 DOC/XLS 转换。
7.2 AI 能力¶
- OpenAI 兼容 LLM 客户端。
- 独立的写作、目录骨架、AI Chat、解析、产品字段、产品图片分类、图片理解模型配置。
- OpenAI 兼容 Embedding。
- 模型限流、重试、超时和 key pool。
- 数据库 Prompt 解析与场景匹配。
7.3 业务外部系统¶
- 阿里云短信。
- 支付宝支付。
- 微信支付。
7.4 配置来源¶
app/core/config.py 为统一 Pydantic Settings,覆盖:
- 数据库、Redis、JWT。
- LLM、Embedding、模型 profile 与限流。
- 文档解析与任务资源限制。
- Qdrant/DashVector 与 RAG。
- OSS。
- 图片、产品解析。
- 支付宝、微信支付。
- 阿里云短信。
- CORS。
- ARQ 队列与 Worker 并发。
应用默认读取 ENV_FILE 指向的文件,缺省为 .env.dev。Makefile 开发/测试命令优先使用 Vault 导出的环境变量,再回退本地 env。Docker 业务容器默认 ENV_FILE=/dev/null,依赖部署时外部注入配置。
8. 部署与运维¶
make dev:启动开发 API。make test:运行仓库全部 pytest 测试,可通过PYTEST_ARGS追加参数。make serve-test:按测试环境配置启动 API。make worker*:启动聚合或单类 Worker。make migrate-dev:升级开发数据库。make docker-infra-up:启动 Redis 基础设施。make docker-app-up:启动 API 与业务 Worker。make docker-up-all:启动基础设施和业务栈。
Dockerfile 使用 Python 3.12 多阶段构建,运行镜像安装 LibreOffice Writer/Calc。Compose 为 API 和 Worker 配置健康检查与资源限制,并通过独立 migration profile 执行迁移。
部署脚本会:
- 从 Vault 获取指定环境配置。
- 创建或复用内部 Docker 网络。
- 非交互执行 Alembic 迁移。
- 重建 API 和 Worker。
- 输出 API、Worker 运行状态和健康信息。
任何环境检查都不应打印密钥值,只应验证关键配置是否存在。
9. 测试现状¶
tests/ 当前 19 个测试文件,主要覆盖:
- 目录解析、子目录、顺序、节点标识与预估。
- 编写思路持久化。
- 全文生成 SSE 数据库兜底。
- 额度安全与核销码。
- 短信验证码。
- 产品库解析。
- 图库、图片文件和文档抽图。
- 清单附件。
- Word 富文本和图片。
- Prompt 场景作用域。
- 标书列表用户隔离。
- 解析结果人工 PATCH。
- 模型 usage 等聚焦逻辑。
测试风格以 unittest、IsolatedAsyncioTestCase 和 collaborator patch 为主,尽量避免真实数据库、LLM 和支付调用。pyproject.toml 当前没有配置 lint 或静态类型检查工具。
10. 现存但不是当前对外能力的代码¶
以下代码容易在阅读时被误判为现行功能,应单独标识:
| 代码或路径 | 当前状态 |
|---|---|
| 知识库目录 CRUD router | 文件存在,但未在知识库 router 注册 |
| 招标文件解析历史 route | 由 if False 关闭 |
| 图库旧更新、自动标注、multipart 上传 route | 历史代码已注释,未注册 |
services/ingestion/* 旧逐页摄取链路 |
不是当前招标文件主解析链路 |
Cloudflare Vectorize 旧 vector_service |
当前知识生成/RAG 主链路不使用 |
generation/pdf_to_markdown.py |
有导出但未发现当前主流程调用 |
| Tender Source Index Worker | Compose/Worker 入口保留,Service 明确为 no-op,当前未发现入队调用 |
app/worker/parser_jobs.py 通用 ParseWorker |
兼容/共享实现;当前 Makefile 与 Compose 使用各领域专用 Worker |
| 早期直接全文生成实现 | 保留兼容,主接口使用持久化 GenerationRun 链路 |
app/prompts/ 文件目录 |
不是当前主要 Prompt 来源,运行时以数据库已发布版本为准 |
11. 当前已知接口契约与架构注意点¶
- 前端仍有“修改密码、绑定手机号、公开知识库搜索、旧 multipart 上传、解析历史、整体替换目录”等后端不存在的残留封装,详见接口总览。
- 管理路由的真实权限必须看依赖,不能只看
/admin前缀。 - 知识库目录表与 Service 存在,但目录 API 未启用。
- Tender Source Index Worker 仍被部署,但已不执行外部索引逻辑。
/health/ready未覆盖向量库和 OSS。- 支付回调保留两组路径,生产支付平台应只配置确定的一组。
- 应用启动仍会执行 SQLModel
create_all类初始化,同时仓库又使用 Alembic;数据库结构变更必须以审查后的 migration 为准。 - 后台/admin 场景若绕过租户过滤,必须同时保证显式用户边界。
- LLM 成功调用、支付回调、短信和 OSS 需要真实外部环境验证,静态测试只能证明本地编排逻辑。
12. 现有设计文档地图¶
本文件作为当前总入口;专题细节继续参考:
| 文档 | 主题 |
|---|---|
| intelligent_tender_system_architecture_design.md | 面向方案评审的业务与技术架构设计 |
| mvp_v1_api_inventory.md | 全部已注册接口、未注册接口和前端契约残留 |
| tender_flow.md | 历史标书流程说明;部分摄取和向量描述需以本文件及当前代码为准 |
| full_generation_run_worker_design.md | 一键全文生成运行与 Worker |
| knowledge_assistant_api_design.md | 知识库助手 |
| knowledge_file_parse_technical_plan.md | 知识文件解析 |
| knowledge_ingestion_rag_technical_plan.md | 知识切块、Embedding 与 RAG |
| product_library_parse_technical_design.md | 产品库导入 |
| subscription_worker_technical_plan.md | 订阅定时维护 |
| oss_large_file_technical_plan.md | OSS 大文件直传 |
| tender_upload_to_parse_queue_product_flow.md | 上传到解析队列流程 |
| product_parse_worker_orchestration_design.md | 产品解析 Worker 编排 |
| llm_gateway_key_pool_rate_limit_design.md | LLM key pool 与限流 |
专题设计稿可能包含历史方案或未落地内容。发生冲突时,以当前路由注册、Service 调用链、模型定义和本文件标注为准。
13. 后续维护规则¶
为避免总文档再次过时,建议在以下变更合并时同步更新:
- 新增/删除路由:更新本文件路由统计和
mvp_v1_api_inventory.md。 - 新增/删除 SQLModel:更新 46 表清单,并确认 Alembic migration。
- 新增/删除 Worker 或 cron:更新 Worker 表和 Compose/Makefile 说明。
- 修改主流程:更新对应功能段和 Mermaid 流程。
- 启用历史 router:从“非当前能力”移入正式功能清单。
- 变更权限依赖:更新认证章节和管理后台注意点。
- 变更外部依赖或健康检查:同步更新运维章节。