跳转至

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/ unittestIsolatedAsyncioTestCase 为主的聚焦测试

核心业务实现定位:

业务域 路由入口 核心实现
用户与短信 app/routes/v1/users/ app/core/security.pyapp/services/sms/
通用文件与 OSS app/routes/v1/files.py app/services/file_upload_service.pyapp/services/oss_service.py
标书 CRUD app/routes/v1/tenders/main.py app/services/tender/service.pyreference_service.py
招标文件解析 app/routes/v1/tenders/document.pyparser.py app/services/tender/markdown_parse.pyapp/services/parse/
目录与编写思路 outline.pysub_outline.pywriting_hint.py app/services/generation/outline_service.pyapp/services/parse/outline/
正文与全文生成 section.pygeneration_runs.py app/services/generation/section_service.pyrun_service.pycontext_assembler.py
清单附件 app/routes/v1/tenders/checklist_file.py app/services/tender/checklist_file_service.pychecklist_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_*.pyapp/routes/v1/tenders/prompt.py app/services/prompt_template_service.pyprompt_scene_binding_service.pyprompt_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.pyingestion_task_log_service.py
Worker 无直接 HTTP 入口 app/worker/*_jobs.pyapp/services/arq_queue_service.py

这是“模块化单体 + 独立 Worker 进程”,不是微服务拆分:API 与 Worker 共享同一套模型、Service、配置和数据库。

3. 应用启动、请求与数据隔离

3.1 启动与关闭

FastAPI lifespan 启动时会依次执行:

  1. 初始化 SQLModel 表。
  2. 检查 Redis 连通性。
  3. 迁移旧版 AI 对话 Redis key。
  4. 校验对象存储配置。
  5. 恢复或终止因进程重启遗留的运行中任务。
  6. 将中断的标书任务同步为失败状态,避免永久卡在处理中。

关闭时会取消本进程跟踪的本地异步任务并关闭 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

当前代码有两个需要认知清楚的权限事实:

  1. /admin/internal/tenders/*/admin/prompts/scenes 当前只要求已登录,不要求管理员角色。
  2. 用户角色修改接口支持“系统尚无管理员时,第一个用户自助提升为管理员”;之后只有管理员可改角色,并禁止降级最后一个管理员。

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_overviewscoring_criteria Prompt。
  • 调用解析 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_skeleton Prompt 生成一二级目录。
  • 创建自定义目录。
  • 导入目录;导入内容不完整时可调用 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。
  • 重新解析与重建索引。

当前确认上传会创建默认目录、知识文件与解析任务。知识解析链路:

  1. Worker 在隔离子进程提取文档内容。
  2. 文本切块。
  3. 调用 OpenAI 兼容 Embedding 接口。
  4. 写入 Qdrant 或 DashVector。
  5. 保存文件内容、chunk 元数据、版本和进度。
  6. 新版本完整可用后原子切换 active_version
  7. 清理旧 chunk 和旧向量。

并发与恢复机制包括:

  • 文件 version 乐观并发控制。
  • 候选版本与当前活跃版本隔离。
  • CAS fencing,旧 Worker 不可覆盖新任务状态。
  • 每 5 分钟清理/协调异常解析任务。
  • reparse 与 reindex 分别覆盖重新提取和只重建向量。

知识库语义检索目前作为内部服务使用,供正文生成和知识库助手调用;公开 /search 路由已移除。

知识库助手包括:

  • bootstrap 返回知识库就绪状态和可用信息。
  • SSE 对话。
  • 可选查询改写。
  • 按 top-k、最低分数和上下文长度限制检索。
  • 输出引用来源、片段和参考文件信息。
  • 记录检索、首 token、总耗时和模型 usage。

当前知识库目录 CRUD 代码仍存在,但目录 router 没有挂载到应用;外部 API 只暴露知识库与文件树,不提供目录增删改接口。

4.10 企业产品库

产品库功能:

  • 创建、列表、更新、软删除产品库。
  • 创建、查询、更新、删除单个产品。
  • 批量删除产品。
  • 用户级产品库与产品访问隔离。

产品表格导入:

  • 查询上传规则。
  • XLS/XLSX 预签名上传。
  • 确认上传并创建解析任务。
  • SSE 订阅解析进度。
  • 取消解析。
  • 并发入场限制,防止单用户占满解析资源。

产品解析是分阶段编排:

  1. 提取表格文本。
  2. 提取嵌入图片。
  3. 识别产品字段。
  4. AI 图片分类。
  5. 将图片关联到产品。
  6. 上传处理后的图片。
  7. 批量持久化或更新产品。
  8. 完成任务与清理中间数据。

每一阶段有独立审计记录,任务使用版本 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 个业务场景:

  1. document_parse
  2. project_overview
  3. scoring_criteria
  4. outline_skeleton
  5. writing_hint
  6. writing_hint_chapter
  7. writing_hint_custom_outline
  8. chapter_outline_from_writing_hint
  9. writing_hint_goods_manufacturer
  10. writing_hint_goods_distributor
  11. writing_hint_service
  12. writing_hint_engineering
  13. section_content
  14. image_analysis

app/prompts/ 当前没有承担主要运行时模板资产;内部 Prompt 文件工具只有目录中实际存在文件时才有内容可管理。

4.14 订阅套餐、订单与支付

套餐:

  • 查询可购买套餐。
  • 管理员创建、查看、更新、删除套餐。
  • 月付、年付、充值包等类型。
  • 立即发放与按月调度发放方式。
  • 订单创建时冻结套餐名称、价格、额度和规则快照。
  • 管理员手工给用户发放套餐。

订单:

  • 创建支付订单。
  • 查询订单状态和详情。
  • 查询当前用户支付记录和最近支付记录。
  • 支持核销码抵扣。
  • 在调用支付供应商前先提交待支付订单,避免外部成功但本地无单。

支付宝:

  • 支持 Native/页面支付入口。
  • 验证异步通知签名。
  • 核对 seller、app、金额和支付状态。
  • 锁定订单并保证幂等。

微信支付:

  • 支持 Native 支付。
  • 验证平台签名并解密回调资源。
  • 核对商户、app、金额和支付状态。
  • 锁定订单并保证幂等。

支付成功后在事务内:

  1. 更新订单。
  2. 创建支付记录。
  3. 按订单快照发放订阅或充值额度。
  4. 防止重复回调重复发放。
  5. 对“已支付但当前业务规则不允许自动发放”的情况标记人工复核。

回调同时保留 /webhook/*/v1/webhook/* 两组兼容路径。

4.15 字数额度、预占与订阅维护

额度来源:

  • 永久额度。
  • 月付/年付订阅的有限额度。
  • 不限量订阅。
  • 年付套餐的按月额度调度。

扣减顺序:

  1. 活跃不限量订阅。
  2. 有限套餐额度,优先扣最早到期项。
  3. 永久额度。

全文生成使用“预占 -> 实际结算”:

  • 创建运行时按估算字数预占。
  • 完成后按实际字数结算。
  • 释放未使用预占。
  • 实际超出估算时补扣。
  • 额度不足的差额记录为系统补贴,避免已生成内容无法收口。

单章生成也执行额度检查和扣减。所有变动写入 character_transactions

订阅有效期使用北京时间的排他截止:

  • valid_until > 当前时间 才算有效。
  • 到达 valid_until 时立即失去权益。
  • Subscription Worker 每天北京时间 00:00 执行维护,并在 Worker 启动时补跑。
  • 维护会过期订阅、清空有限套餐剩余额度、取消调度、为年付套餐发放新周期额度、清理上一周期未用额度。
  • 每次维护写入 subscription_maintenance_logs,管理员可查看摘要与明细。

4.16 通用异步任务与 SSE

通用任务接口支持:

  • 分页查询任务。
  • 查询任务日志。
  • 查询单个任务状态。
  • SSE 订阅任务事件。
  • 取消任务。

IngestionTaskIngestionTaskLog 为多个解析场景提供统一任务状态、错误、阶段、指标和日志能力。

系统的 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)

  • users
  • system_configs
  • operation_logs
  • sms_verification_whitelists

5.2 通用任务(2)

  • ingestion_tasks
  • ingestion_task_logs

5.3 标书、目录、正文与生成(16)

  • tenders
  • tender_contents
  • tender_scoring
  • tender_requirements
  • tender_outline_writing_hints
  • tender_outline_node_histories
  • tender_section_contents
  • generation_runs
  • generation_section_jobs
  • tender_checklist_files
  • tender_checklist_parse_jobs
  • tender_knowledge_base_references
  • tender_knowledge_references
  • tender_product_references
  • tender_image_references
  • document_styles

5.4 知识库(6)

  • knowledges
  • knowledge_dirs
  • knowledge_files
  • knowledge_file_parse_jobs
  • knowledge_file_contents
  • knowledge_file_chunks

5.5 产品库(5)

  • product_libraries
  • products
  • product_parse_jobs
  • product_parse_stage_runs
  • product_parse_images

5.6 图库(2)

  • image_galleries
  • image_files

5.7 Prompt 平台(3)

  • prompt_templates
  • prompt_template_versions
  • prompt_scene_bindings

5.8 订阅、额度与支付(8)

  • subscription_plans
  • user_subscriptions
  • subscription_quota_schedules
  • character_transactions
  • orders
  • payment_records
  • redeem_codes
  • subscription_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 等聚焦逻辑。

测试风格以 unittestIsolatedAsyncioTestCase 和 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. 当前已知接口契约与架构注意点

  1. 前端仍有“修改密码、绑定手机号、公开知识库搜索、旧 multipart 上传、解析历史、整体替换目录”等后端不存在的残留封装,详见接口总览。
  2. 管理路由的真实权限必须看依赖,不能只看 /admin 前缀。
  3. 知识库目录表与 Service 存在,但目录 API 未启用。
  4. Tender Source Index Worker 仍被部署,但已不执行外部索引逻辑。
  5. /health/ready 未覆盖向量库和 OSS。
  6. 支付回调保留两组路径,生产支付平台应只配置确定的一组。
  7. 应用启动仍会执行 SQLModel create_all 类初始化,同时仓库又使用 Alembic;数据库结构变更必须以审查后的 migration 为准。
  8. 后台/admin 场景若绕过租户过滤,必须同时保证显式用户边界。
  9. 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:从“非当前能力”移入正式功能清单。
  • 变更权限依赖:更新认证章节和管理后台注意点。
  • 变更外部依赖或健康检查:同步更新运维章节。