Files
AIRegulation-DocAnalysis/docs/architecture/backend-project-architecture.md
ash66 091a02c522 Add AgentSessionService and refactor agent routes
Move session-related responsibilities into a new application-layer AgentSessionService (and AgentSessionFeedbackResult dataclass), provide a bootstrap factory (get_agent_session_service), and update agent API routes to call the service instead of accessing ConversationStore directly. Routes now translate ValueError into 404 responses and use service methods for get/list/history/delete/feedback. Also update package exports and docs/READMEs to declare the backend architecture authority, enforce api -> application -> domain ports -> infrastructure boundaries, and call out legacy services/workflows as migration-only. These changes centralize session logic in the application layer and tighten architecture guidance for future backend work.
2026-05-22 09:50:30 +08:00

904 lines
29 KiB
Markdown
Raw Permalink 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.

# Backend Project Architecture
## 1. Purpose
本文档定义当前 backend 的目标态架构,用于在保持单服务部署的前提下,将系统整理为职责清晰、边界稳定、可替换实现的模块化结构。本文档的重点不是描述理想化分层,而是基于当前真实代码形态,明确后续重构时必须遵守的模块职责、依赖方向、内部稳定接口和替换边界。
本文档与 `docs/rfc/backend-api-parsing-embedding-migration-requirements.md` 的关系如下:
- RFC 负责冻结本轮迁移需求、范围、风险和约束。
- 本文档负责冻结目标模块边界、依赖规则和实现组织方式。
- 后续任何代码重构、能力替换或底座升级,都应同时满足 RFC 与本文档。
## 1.1 Document Status And Authority
本文档不是仅供参考的“目标态草案”,而是当前 backend 持续开发的强制架构基线。
- 新增 backend 功能默认必须遵守本文档定义的模块边界与依赖方向。
- 历史实现、迁移中代码和兼容 façade 的存在,不构成继续偏离本文档的理由。
- 当现状与本文档冲突时,新增代码按本文档落位;旧代码按迁移计划逐步收口,但不允许继续扩大 legacy 边界。
- 评审、重构验收和后续架构讨论,均以本文档作为 backend 内部结构的 authority。
## 1.2 Authoritative Scope
本文档约束的 backend 范围包括:
- `backend/app/api/*`
- `backend/app/application/*`
- `backend/app/domain/*`
- `backend/app/infrastructure/*`
- `backend/app/shared/*`
说明:
- `backend/app/services/*``backend/app/workflows/*` 当前属于迁移期 legacy 目录,不是新增业务逻辑的默认落点。
- `backend/app/api/routes/docs.py``backend/app/api/routes/rag.py` 视为遗留或非主入口,除迁移、兼容或下线动作外,不应继续扩展。
- `backend/app/api/routes/compliance.py` 当前仍对外暴露,但尚未完全满足本文档约束;在迁移到 application service 之前,应视为受控 legacy 入口,而不是新的架构样板。
## 2. Current-State Problems
基于当前代码,后端已经具备以下能力:
- 文档上传、下载、列表
- 文档解析与切片
- 向量化与 Milvus 入库
- 检索
- 基于 RAG 的 Agent 问答 workflow
但这些能力当前主要是“可运行”,还不是“结构清晰、便于替换、便于演进”的状态。核心问题如下。
### 2.0 Current-State Verdict
基于当前仓库,现状裁决如下:
- 已基本符合:`documents` 上传/查询主链路已经通过 `DocumentCommandService``DocumentQueryService` 收口。
- 已基本符合:`knowledge` 检索已经通过 `KnowledgeRetrievalService` 统一对外暴露。
- 已基本符合:`agent` 问答主链路已经通过 `AgentConversationService` 收口,`shared/bootstrap.py` 已承担 composition root 角色。
- 部分符合Agent session 详情、历史、删除、反馈等接口曾经直接访问 `ConversationStore`,需要继续收口到 application service。
- 未完全符合:`compliance` 路由仍直接处理文件落盘、任务状态和 mock 结果,不符合 `api -> application -> domain ports -> infrastructure`
- 未完全符合:部分 `infrastructure` adapter 仍依赖 `services/*` 内的 legacy 实现,说明迁移尚未彻底完成。
- 未完全符合:`api/main.py` 的生命周期预热逻辑仍直接依赖旧 LLM factory尚未完全回到统一 wiring 边界。
### 2.1 `DocumentProcessor` 责任过载
现状判断:
- `backend/app/services/document_processor.py` 已经不再是当前主要编排点
- 上传、查询和问答的核心组织逻辑已经明显下沉到 `backend/app/application/*` 以及 `backend/app/shared/bootstrap.py`
- `DocumentProcessor` 当前更接近一个兼容旧调用路径的 legacy façade
其历史上曾集中承载过以下职责:
- 文档解析
- 摘要生成
- 分块
- 向量化
- Milvus 入库
- 检索入口
当前真正还需要收口的问题不是“继续拆这个大类”,而是把文档元数据、解析、分块、向量化和索引写入的稳定边界进一步收束到 application service 与端口接口中,避免后续重构继续围绕旧实现形态做判断。
### 2.2 检索逻辑缺少稳定边界
现状判断:
- `backend/app/services/rag/retriever.py` 已经明显退化为兼容层
- 真正承担检索编排的是 `KnowledgeRetrievalService``shared/bootstrap` 中的 wiring
- `Retriever` 应被视为业务侧端口,而不是当前主编排单元
其历史上曾集中承载过以下职责:
- embedder 初始化
- Milvus 连接与 collection lifecycle
- 检索执行
- 结果映射
所以这里的重点不是把旧 retriever 当成未来架构核心,而是确认检索能力的稳定边界已经迁移到 application 层,并继续清理仍然残留的 provider-specific 细节。
### 2.3 `QAAgent` 责任过载
现状判断:
- `backend/app/services/agent/qa_agent.py` 已经不是当前主要问答编排点
- 当前实际的问答编排已经主要落到 `AgentConversationService`
- `QAAgent` 当前更接近向后兼容的 legacy façade
其历史上曾集中承载过以下职责:
- 检索调用
- 上下文构建
- Prompt 选择
- LLM 调用
- SSE 流式问答流程
- 会话 workflow 编排
剩余风险不在于“它还很大”,而在于仍有少量 API 入口和 session 读写没有完全收口到 application service导致目标边界和现状之间还存在断点。
### 2.4 API 层直接编排具体服务
当前 API 路由主要在:
- `backend/app/api/routes/documents.py`
- `backend/app/api/routes/knowledge.py`
- `backend/app/api/routes/agent.py`
这些路由直接实例化具体服务类,例如 `DocumentProcessor``QAAgent``MinIOClient`。这意味着:
- API 层不仅处理 transport concerns也在做业务编排
- 路由层知道过多内部实现细节
- 后续如果内部模块调整,路由层也要跟着改
现状里这条判断需要修正:大部分主流程已经通过 `backend/app/shared/bootstrap.py` 统一装配,并由 application service 承担编排;真正还没有完全收口的是 `backend/app/api/routes/agent.py` 中的 session/history/feedback 这类接口,它们仍直接访问 `ConversationStore`
因此,当前问题不是“路由层仍然是主编排中心”,而是“少数会话管理接口还没有通过 application service 统一封装”,这会持续打破 API 只做 transport concerns 的边界。
### 2.5 文档元数据与对象存储组织方式耦合
当前文档列表与下载逻辑高度依赖 MinIO 对象命名方式和对象遍历结果。对象存储目前承担了部分“业务真相”的角色,但对象存储只适合作为文件二进制载体,不适合作为完整文档元数据和状态管理的唯一来源。
### 2.6 `knowledge` 与 `agent` 共享检索底座的边界不清晰
当前 `/knowledge/*``/agent/*` 都依赖检索能力,但共享方式不够清晰:
- `knowledge` 通过 `DocumentProcessor.search()` 访问检索
- `agent` 通过 `Retriever` 访问检索
这条问题描述需要更新。现在检索主链路已经被 `KnowledgeRetrievalService` 统一收束,`knowledge``agent` 的共享底座比过去清晰得多。
当前仍未完全收口的是 Agent 的 session 相关能力:公开 API 里还存在 `/agent/session/{id}``/agent/session/{id}/history``/agent/sessions``/agent/feedback` 等接口直接读写 `ConversationStore`,这意味着“问答编排统一了,但会话管理还没有统一入口”。
## 3. Architecture Goals
本项目后端的目标态架构必须满足以下目标。
### 3.1 单服务部署
系统继续保持单服务部署,不拆分为多个微服务。架构治理发生在单服务内部,通过清晰模块边界实现高内聚低耦合,而不是通过进程级拆分回避设计问题。
### 3.2 高内聚、低耦合优先级最高
后续模块设计以“一个模块只承载一类稳定职责”为原则。跨能力流程统一在编排层组织,不允许继续把 parser、embedding、storage、retrieval、LLM workflow 堆进同一个服务类。
### 3.3 外部 API 尽量保持兼容
现有前端与外部调用方依赖的主接口保持不变优先,包括但不限于:
- `/api/v1/documents/*`
- `/api/v1/knowledge/*`
- `/api/v1/agent/*`
内部可以重组,但外部接口不应因为内部重构而被迫大改。
### 3.4 关键能力必须可替换
以下能力必须通过稳定端口隔离实现细节:
- 文档解析
- 分块构建
- 向量化
- 向量索引
- 检索
- LLM 回答生成
- 会话存储
- 原始文件存储
后续替换方案时,只允许替换实现,不允许穿透影响其他模块。
### 3.5 `knowledge` 与 `agent` 共用同一检索底座
检索必须被视为独立的业务能力,由统一的 retrieval application service 对外暴露。`knowledge``agent` 必须复用同一个 retrieval 底座,避免两套召回策略、两套元数据模型、两套 adapter。
### 3.6 依赖必须单向流动
系统必须形成稳定的单向依赖关系:
- `api -> application -> domain`
- `application -> domain ports`
- `composition root -> application + infrastructure bindings`
- `infrastructure -> external systems`
不允许出现基础设施实现反向驱动业务编排,也不允许 domain 依赖 Web 或第三方 SDK。
## 4. Target Module Layout
目标目录结构如下:
```text
backend/app/
api/
application/
documents/
knowledge/
agent/
domain/
documents/
retrieval/
conversation/
infrastructure/
storage/
vectorstore/
parser/
embedding/
llm/
session/
shared/
```
该结构是本项目 backend 的目标态模块布局。后续实现可以渐进迁移,但职责边界不能偏离。
### 4.1 `api`
职责:
- HTTP 路由注册
- 请求参数校验
- 响应模型映射
- 异常转换
- SSE 事件格式输出
非职责:
- 不直接组织完整业务流程
- 不直接访问 MinIO、Milvus、Parser SDK、LLM SDK
- 不直接 new 具体基础设施客户端
### 4.2 `application`
职责:
- 用例编排
- 跨领域能力协作
- 业务流程统一入口
- workflow 级别的状态推进
非职责:
- 不直接依赖第三方 SDK
- 不承担具体存储、向量库、解析器实现细节
### 4.3 `domain`
职责:
- 核心业务对象
- 领域术语
- 稳定端口接口
- 统一元数据模型
- 检索结果模型
- 会话消息模型
非职责:
- 不依赖 FastAPI
- 不依赖 MinIO、Milvus、LLM SDK
- 不依赖路由请求响应模型
### 4.4 `infrastructure`
职责:
- 外部系统适配器实现
- 第三方 SDK 封装
- provider-specific 配置适配
- 数据格式转换
包含但不限于:
- MinIO binary store
- Milvus vector index
- Aliyun / local parser adapter
- OpenAI-compatible embedding adapter
- DeepSeek / Qwen LLM adapter
- in-memory / Redis session store
### 4.5 `shared`
职责:
- 配置
- 日志
- 通用异常
- 通用工具
- 公共基础设施无关组件
- composition root 与依赖装配
- 运行时共享的 wiring 辅助入口
非职责:
- 不承载业务编排
- 不变成新的 `services` 大杂烩目录
说明:
- `shared` 不是业务层,但它是本项目当前明确的装配层。
- `backend/app/shared/bootstrap.py` 是现阶段的 composition root负责把端口实现、基础设施适配器和 application service 连接起来。
- 后续如果新增 wiring 入口,应继续保持在同一类装配边界内,不要把依赖装配拆回各个路由或 service 构造函数中。
## 5. Module Responsibilities
### 5.1 `api`
`api` 是 transport 层,只关心请求进来和响应出去的表达方式。它应该把请求转换为 application service 的输入,把 application service 的结果转换为 HTTP 响应。
`api` 不应该知道:
- MinIO bucket 怎么组织
- Milvus collection 怎么建
- parser 是本地还是阿里云
- embedding 是本地模型还是 API
- session 是内存还是 Redis
### 5.2 `application`
`application` 是业务编排层,是系统内唯一允许跨模块组织完整流程的层。它应该定义稳定的用例服务,而不是把流程散落在路由或基础设施实现中。
本项目至少固定以下 4 类 application service
- `DocumentCommandService`
- `DocumentQueryService`
- `KnowledgeRetrievalService`
- `AgentConversationService`
说明:
- 这 4 类是当前已经明确成型的核心用例服务,但不是 application 的全部上限。
- 现有 Agent session 管理接口所需的会话查询、历史读取、删除和反馈归档能力,后续应补入 application 层的明确用例服务或子服务,而不是继续让 API 直连 `ConversationStore`
### 5.3 `domain`
`domain` 层定义系统内部真正稳定的概念,例如:
- `Document`
- `DocumentStatus`
- `ParsedDocument`
- `Chunk`
- `RetrievalQuery`
- `RetrievedChunk`
- `ConversationSession`
- `ConversationMessage`
- `AnswerSource`
这些对象必须脱离具体技术实现,成为 parser、embedding、vector index、agent workflow 之间的公共契约。
### 5.4 `infrastructure`
`infrastructure` 只负责“怎么接某个外部系统”,不负责“业务上应该先做什么后做什么”。例如:
- MinIO adapter 负责上传和下载文件
- Milvus adapter 负责 upsert/search/delete
- Qwen / DeepSeek adapter 负责生成回答
- Aliyun parser adapter 负责把解析结果映射成统一 `ParsedDocument`
### 5.5 `shared`
`shared` 只放横切能力。任何和文档 ingest、检索、问答编排直接相关的业务逻辑都不应该放进 `shared`
## 6. Stable Internal Ports
以下端口是系统内部稳定契约。后续方案替换时,只能替换实现,不允许改动上层 application service 的调用方式,也不允许影响 sibling 模块。
### 6.1 `DocumentRepository`
职责:
- 管理文档元数据
- 管理文档状态
- 管理统计字段,例如 chunk 数、索引状态、摘要状态
说明:
- 列表和状态查询应以 `DocumentRepository` 为主,而不是直接遍历对象存储。
### 6.2 `DocumentBinaryStore`
职责:
- 保存原始文件
- 下载原始文件
- 删除原始文件
- 处理对象存储相关细节
说明:
- 替换 MinIO 或对象存储方案时,只替换该实现。
### 6.3 `DocumentParser`
职责:
- 输入原始文件
- 输出统一结构化解析结果
说明:
- 本地 PDF/MinerU 或阿里云解析只能作为实现差异,不能外溢到业务流程层。
### 6.4 `ChunkBuilder`
职责:
- 输入统一解析结果
- 输出统一 chunk 模型
说明:
- chunk 规则变化只能影响该端口实现,不应影响 retrieval、agent 或 API。
### 6.5 `EmbeddingProvider`
职责:
- 输入文本列表
- 输出 embedding 向量结果
说明:
- 从本地模型切到 OpenAI-compatible embedding只替换该实现。
### 6.6 `VectorIndex`
职责:
- upsert chunks
- delete by document
- search by query vector
- 管理索引内部 schema
说明:
- Milvus schema 或向量库替换,只能影响该层。
### 6.7 `Retriever`
职责:
- 基于 query、filter、top_k 返回统一检索结果
说明:
- `Retriever` 是业务侧的检索端口,不应再直接持有 embedder、Milvus lifecycle 和 provider-specific 逻辑。
### 6.8 `AnswerGenerator`
职责:
- 基于 query 与 context 生成最终回答
- 屏蔽具体 LLM provider 差异
说明:
- DeepSeek、Qwen 或其他模型切换时,只替换该实现。
### 6.9 `ConversationStore`
职责:
- 创建和读取 session
- 持久化消息历史
- 管理会话生命周期
说明:
- 从内存实现切到 Redis 或数据库实现时,只替换该实现。
## 7. Application Services
### 7.1 `DocumentCommandService`
职责:
- 接收文档上传命令
- 生成 `doc_id`
- 保存原始文件
- 触发解析、分块、向量化、入库
- 更新文档状态和统计信息
- 返回最终处理结果
说明:
- 当前 `DocumentProcessor` 的“流程编排”职责在目标态应迁移到这里。
- parser、chunker、embedder、vector index 的具体实现不应继续塞进一个大类里统一管理。
### 7.2 `DocumentQueryService`
职责:
- 文档列表
- 文档下载
- 文档状态查询
- 文档管理视图查询
说明:
- 列表和状态查询应基于 `DocumentRepository`
- 下载应通过 `DocumentBinaryStore`
- 不再依赖 MinIO 对象结构作为业务视图主来源
### 7.3 `KnowledgeRetrievalService`
职责:
- 对外提供统一检索能力
- 管理 retrieval query 到 retrieval result 的业务转换
-`/knowledge/*` 和 Agent workflow 共用
说明:
- 当前 `knowledge``agent` 必须统一依赖这一层,不允许各自再维护一套检索流程。
### 7.4 `AgentConversationService`
职责:
- 统一管理问答 workflow
- 读取或创建会话
- 调用 `KnowledgeRetrievalService`
- 构建问答上下文
- 调用 `AnswerGenerator`
- 保存回答和引用来源
说明:
- 当前 `QAAgent` 的 workflow 编排职责在目标态应迁移到这里,或被其吸收后只保留 façade 角色。
- SSE 与普通问答必须共用这一层,不允许复制业务编排逻辑。
### 7.5 `AgentSessionService`
职责:
- 读取会话详情
- 读取会话历史
- 列出会话
- 删除会话
- 记录会话反馈
说明:
- 这类能力目前仍散落在 `backend/app/api/routes/agent.py`,并直接依赖 `ConversationStore`
- 目标态应把它们收口到 application 层,保证 API 只处理 transport concerns而不是继续承担 session 级业务访问。
## 8. Core Workflows
### 8.1 文档上传入库链路
目标流程如下:
1. `api/documents` 接收上传请求并完成输入校验。
2. `DocumentCommandService` 生成 `doc_id`,初始化文档记录和状态。
3. `DocumentBinaryStore` 保存原始文件。
4. `DocumentParser` 对原始文件执行解析,输出统一结构化结果。
5. `ChunkBuilder` 将解析结果转换为统一 chunk 集合。
6. `EmbeddingProvider` 为 chunks 生成向量。
7. `VectorIndex` 将 chunks 与 vectors 写入索引。
8. `DocumentRepository` 更新文档状态、chunk 数量、索引状态、元数据。
9. API 返回处理结果。
约束:
- 上传处理链路的主编排必须只存在于 `DocumentCommandService`
- 不允许再由 route 或基础设施类直接组织全流程
### 8.2 文档查询链路
目标流程如下:
1. `api/documents` 调用 `DocumentQueryService`
2. 文档列表与状态查询通过 `DocumentRepository`
3. 文档下载通过 `DocumentBinaryStore`
4. 对象存储命名规则只作为实现细节,不作为最终业务真相
约束:
- 文档“存在、状态、统计信息”必须有稳定元数据模型
- 不允许继续通过对象存储遍历结果拼出全部业务语义
### 8.3 Agent 问答链路
目标流程如下:
1. `api/agent` 接收问答请求
2. `AgentConversationService` 读取或创建 session
3. `KnowledgeRetrievalService` 统一执行检索
4. `AnswerGenerator` 基于 query 和 retrieval context 生成回答
5. `ConversationStore` 保存消息历史和引用来源
6. API 将结果以普通 JSON 或 SSE 格式输出
约束:
- 普通问答和 SSE 问答只允许输出形式不同
- 业务编排链必须完全复用
- 检索能力必须来自同一 `KnowledgeRetrievalService`
### 8.4 Agent Session 管理链路
目标流程如下:
1. `api/agent/session/*``api/agent/sessions` 接收会话管理请求
2. `AgentSessionService` 读取、列出、删除或归档反馈
3. `ConversationStore` 负责持久化与会话生命周期细节
4. API 输出 session 详情、历史、列表或反馈结果
约束:
- 会话详情、历史、列表和反馈接口不属于问答编排本身,应由独立的 session application service 处理。
- 这部分能力不应继续直接暴露 `ConversationStore` 给路由层。
## 9. Dependency Rules
系统内部依赖方向固定如下:
```text
api -> application -> domain
application -> domain ports
composition root -> application + infrastructure bindings
infrastructure -> external systems
```
具体规则如下:
- `api` 可以依赖 `application` 和 API 自己的 request/response models
- `application` 只能依赖 `domain`、端口接口,以及通过 composition root 注入进来的实现实例
- `domain` 不能依赖 `api``infrastructure`
- `infrastructure` 可以依赖 `domain` 定义的端口和数据模型,但不能反向驱动 application 逻辑
- `api/main.py` 这类应用入口可以保留轻量 startup/shutdown 生命周期代码,但不应长期直接依赖 legacy service factory预热与装配逻辑应逐步收口到明确的 wiring 边界
说明:
- 端口绑定发生在 `shared/bootstrap.py` 这类 composition root而不是 application 层内部。
- application 只能接收已装配好的依赖实例,不能反向“依赖某个 infrastructure 实现类”作为其设计前提。
## 10. Migration Mapping From Current Code
当前关键代码到目标模块的映射如下。
### 10.0 旧 facade 存续策略
当前仓库里仍保留若干旧 facade / 兼容入口,包括但不限于:
- `backend/app/services/document_processor.py`
- `backend/app/services/rag/retriever.py`
- `backend/app/services/agent/qa_agent.py`
这些类的定位是“兼容现有调用方的过渡入口”,不是目标态的主要编排层。它们在迁移完成前应继续保留,直到对应的调用方、测试和 API 入口都迁移到 application service 或新的适配层为止。
约束:
- 不允许因为目标架构已经定义,就在没有替换调用方的情况下直接删除这些 facade。
- 任何清理旧 `services` 的动作,都必须先确认是否还存在非 HTTP 的内部调用、测试依赖或临时适配依赖。
- 这些 facade 可以逐步瘦身,但在迁移窗口内应优先保持行为兼容,而不是追求“文件级清零”。
### 10.1 文档处理
当前:
- `backend/app/services/document_processor.py`
目标:
- 其流程编排职责迁移到 `application/documents/DocumentCommandService`
- 解析、分块、向量、入库分别通过端口接入
- 检索入口从该类中剥离,不再由 ingest orchestration 承担 search 职责
- 迁移期间该类作为兼容 facade 保留,直到所有直接调用点收口完成
### 10.2 检索
当前:
- `backend/app/services/rag/retriever.py`
目标:
- `domain/retrieval` 中定义 `Retriever` 端口和统一检索结果模型
- `infrastructure/vectorstore` 中承载具体检索实现
- `application/knowledge/KnowledgeRetrievalService` 作为统一检索用例入口
- 迁移期间该类作为兼容 facade 保留,避免影响现有检索调用方
### 10.3 Agent Workflow
当前:
- `backend/app/services/agent/qa_agent.py`
目标:
- workflow 编排职责迁移到 `application/agent/AgentConversationService`
- 具体 LLM 调用走 `AnswerGenerator`
- 具体 session 读写走 `ConversationStore`
- 检索统一走 `KnowledgeRetrievalService`
- 迁移期间该类作为兼容 facade 保留,避免影响现有问答和测试调用点
### 10.4 存储
当前:
- `backend/app/services/storage/minio_client.py`
- `backend/app/services/storage/milvus_client.py`
目标:
- MinIO 迁移到 `infrastructure/storage`
- Milvus 迁移到 `infrastructure/vectorstore`
### 10.5 解析
当前:
- `backend/app/services/parser/*`
- `backend/app/services/parser/mineru_parser.py`
目标:
- 全部迁移到 `infrastructure/parser`
- 对外只暴露统一 `DocumentParser` 端口实现
### 10.6 向量化
当前:
- `backend/app/services/embedding/*`
目标:
- 迁移到 `infrastructure/embedding`
- 对外只暴露统一 `EmbeddingProvider`
### 10.7 LLM
当前:
- `backend/app/services/llm/*`
目标:
- 迁移到 `infrastructure/llm`
-`AnswerGenerator` 屏蔽 provider 差异
### 10.8 会话
当前:
- `backend/app/services/agent/session_manager.py`
目标:
- 迁移到 `infrastructure/session`
- 对外通过 `ConversationStore` 暴露
### 10.9 API 模型与内部模型
当前:
- `backend/app/api/models/*`
- `backend/app/schemas/*`
目标:
- 对外 request/response model 保留在 `api`
- 内部 DTO / VO / domain object 收敛到 `application``domain`
- 不允许 API model 直接渗透到 domain
### 10.10 应用入口与启动生命周期
当前:
- `backend/app/api/main.py`
目标:
- 保留 FastAPI app、middleware 和 lifespan 入口职责
- 逐步去除对 legacy LLM factory 的直接依赖
- 预热、清理和依赖装配应保持在明确的 wiring / bootstrap 边界内,而不是继续把旧 service factory 固化为应用入口依赖
### 10.11 Compliance 路由
当前:
- `backend/app/api/routes/compliance.py`
目标:
- 如继续保留该能力,应迁移到独立的 application service 与稳定端口
- 在迁移完成前,该路由视为受控 legacy 入口,可修 bug但不应继续扩展业务编排职责
### 10.12 遗留路由入口
当前:
- `backend/app/api/routes/docs.py`
- `backend/app/api/routes/rag.py`
目标:
- 作为遗留或演示入口逐步归档、下线或迁移
- 不再作为新增 backend 能力的开发入口
### 10.13 Legacy Workflow 与 Service 目录
当前:
- `backend/app/workflows/*`
- `backend/app/services/*`
目标:
- 保留迁移期兼容价值,但不再承载新的长期业务编排
- 若某个 legacy 实现仍被 `infrastructure` adapter 间接复用,应视为过渡依赖,后续逐步迁入 `infrastructure` 或更稳定的底层支撑模块
- 任何新增 backend 业务能力,都不应再以这些目录作为默认落点
## 11. Technology Replacement Boundaries
### 11.1 本地解析 / MinerU -> 阿里云文档解析
替换原则:
- 只替换 `DocumentParser` adapter
- `DocumentCommandService` 不应感知解析提供商差异
- `ChunkBuilder` 只接收统一解析结果模型
### 11.2 BGE-M3 -> OpenAI-compatible embedding
替换原则:
- 只替换 `EmbeddingProvider`
- `KnowledgeRetrievalService``DocumentCommandService` 不应感知 embedding 来源变化
### 11.3 Milvus `1024 + sparse` -> `1536 dense-only`
替换原则:
- 只替换 `VectorIndex` 实现
- collection schema、index 参数、dense-only search 属于 index 内部实现细节
- 上层 retrieval 和 agent workflow 不应因为 schema 变化而改业务接口
### 11.4 DeepSeek / Qwen 切换
替换原则:
- 只替换 `AnswerGenerator` 背后的 provider adapter
- 上层 conversation workflow 不应直接依赖具体模型 SDK
### 11.5 内存 session -> Redis / DB session
替换原则:
- 只替换 `ConversationStore`
- API 和 application service 不应感知 session 持久化细节
## 12. Guardrails
后续所有 backend 重构和新增功能必须遵守以下规则:
- 禁止 `api/routes` 直接实例化 parser、embedder、Milvus、MinIO、LLM client
- 禁止 `application` 层直接 import 第三方 SDK
- 禁止 `domain` 层依赖 FastAPI、Pydantic route model、MinIO SDK、Milvus SDK、LLM SDK
- 禁止 SSE 和普通问答各自维护独立 workflow
- 禁止把对象存储命名规则作为唯一业务元数据来源
- 禁止新建第二个“大一统流程类”替代 `DocumentProcessor`
- 禁止 `knowledge``agent` 各自维护独立检索实现
- 禁止 parser、embedding、vector index、llm provider 的替换穿透到 API 层
- 禁止新增 route 直接访问 `ConversationStore`
- 禁止新增代码把 `backend/app/services/*``backend/app/workflows/*` 作为默认业务落点
- 禁止新增 `infrastructure -> services/*` 的过渡依赖;已有依赖只允许在迁移窗口内逐步消除,不允许继续扩散
- 禁止在 README、开发说明或评审结论中把 legacy 目录描述为当前 backend 的主结构
## 13. Architecture Review Checklist
后续评审和重构验收时,至少核对以下问题:
1. 上传、下载、列表、解析、切片、向量、入库、检索、Agent Workflow 是否都映射到了明确模块。
2. 系统是否仍保持单服务,而不是被动演化成伪微服务结构。
3. 是否存在唯一、清晰的目标目录结构。
4. 是否定义了稳定端口列表。
5. 是否定义了文档上传入库、文档查询、Agent 问答三条核心 workflow。
6. 是否定义了单向依赖方向。
7. 是否明确列出了架构禁令。
8. 是否定义了当前关键代码到目标模块的映射。
9. 是否明确定义了 parser、embedding、vector index、LLM、session store 的替换边界。
10. 是否明确 `knowledge``agent` 共用同一 retrieval 底座。
11. 是否明确 API 层只负责 transport concerns不再直接承担业务编排。
12. 是否保证后续替换方案时,上层 application service 与外部 API 契约不被迫变化。
13. 是否仍存在 route 直接访问 `ConversationStore`、文件系统、对象存储或任务状态存储。
14. 是否新增了 `infrastructure -> services/*` 依赖。
15. 是否把新的 backend 业务逻辑写进了 `services/*``workflows/*`
16. README、backend README 与协作说明是否仍与当前 authoritative architecture 保持一致。