Files
PlantAI-rag-new/docs/ARCHITECTURE.md
T
jerryandClaude Fable 5 1e94de7464 PlantAI-rag-new 首次提交:文献知识工作台
- BFF 薄适配层(FastAPI,8090):QA 代理/SSE 中继/Neo4j 直连/抽取代理/会话持久化
- Vue3 前端:五相位检索流水线、文献来源与证据链、知识图谱、提取任务四 tab
- 四档响应式(桌面/笔记本/平板/手机)、深浅主题
- 81 个 FR 全部实现,测试追溯矩阵 81/81,后端 121 测/前端 156 测
- 真实凭据已脱敏,运行时配置在 backend/.env(不入 git)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 20:47:52 +08:00

232 lines
14 KiB
Markdown
Raw 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.
# ARCHITECTURE.md —— PlantAI-rag-new 架构与协作约定
> 版本 1.0 | 作者 PM | 本文件由 PM 独占写入,所有开发/测试 agent **只读**
---
## 1. 项目定位
`PlantAI-rag-new` 是植物基因家族文献 RAG 知识系统的**新一代工作台**。
它**不重写** RAG 算法、检索引擎与论文抽取流水线——那些是现有 `PlantAI-rag` 工程中经真实论文验证的资产。本项目做两件事:
1. **一层薄适配(BFF, Backend-For-Frontend)**:代理并归一化现有运行中的上游服务,补齐上游缺失的能力(会话持久化、图谱直连、统一错误信封)。
2. **一套全新的响应式前端**:严格实现 `plantai-agent-ui-prototype.html` 的视觉系统,并扩展为支持手机的四档自适应布局。
**红线**:不修改 `PlantAI-rag`、`PlantAI-dev`、`rag-qa-v1_1_73` 的任何源文件;不占用其端口;不切换其流量。
---
## 2. 系统拓扑
```
┌────────── 用户浏览器(桌面 / 平板 / 手机)──────────┐
│ │
│ Vue 3 SPA ← 开发期 Vite dev :5180 │
│ 生产期由 BFF 静态托管 │
└───────────────────────┬──────────────────────────────┘
│ /api/* (同源,JSON + SSE)
┌───────────────────────▼──────────────────────────────┐
│ BFF FastAPI + Uvicorn 127.0.0.1:8090 │
│ ┌────────────┬────────────┬───────────┬──────────┐ │
│ │ sessions │ qa │ kg │extraction│ │
│ │ (SQLite) │ (代理+SSE) │(Bolt直连) │ (代理) │ │
│ └────────────┴─────┬──────┴─────┬─────┴────┬─────┘ │
└────────────────────┬┴────────────┴──────────┴────────┘
│ │ │
┌────────────▼──┐ ┌───────▼─────┐ ┌─▼──────────────┐
│ QA V1.1.73 │ │ Neo4j Bolt │ │ Gene Family │
│ 127.0.0.1:7920│ │ 19788/18788 │ │ RAG :8000 │
│ (只读消费) │ │ /17687 │ │ 回落 :7900 │
└───────────────┘ └─────────────┘ └────────────────┘
```
**BFF 的存在理由**(不是无谓的中间层):
| 职责 | 为什么前端不能直连上游 |
|---|---|
| 会话持久化 | 上游 QA 完全无状态,没有会话概念,UI 的历史列表必须有人存 |
| 别名归一化 | 上游同一语义有多个字段名(`answer`/`response`/`message` 等),归一化放前端会污染每个组件 |
| SSE 阶段映射 | 上游推十余个细粒度 stage,UI 只需五阶段;映射放 BFF,前端不需要知道上游阶段名 |
| 图谱直连 | 上游 `/kg/*` 路由指向已死的 7687 端口,必须由 BFF 用 Bolt 驱动绕过 |
| 统一错误信封 | 三个上游三套错误格式,前端只应处理一种 |
| 跨域与凭据 | 上游只绑回环且 Neo4j 需要密码,凭据不能进浏览器 |
---
## 3. 运行时约定
| 项 | 值 |
|---|---|
| BFF 监听 | `127.0.0.1:8090`(占用则退 8091) |
| Vite dev | `127.0.0.1:5180`(占用则退 5181) |
| BFF conda 环境 | `plantai-bff`(Python 3.11,新建,**不复用** `gfpy312`) |
| SQLite 路径 | `backend/data/plantai.db`(WAL 模式) |
| 前端工具链 | Vite **5.4.x** + @vitejs/plugin-vue **5.2.x** + Vue **3.5.x** + Pinia **2.3.x** |
| Node | v18.19.1(已 EOL)——**禁止升级 Vite 至 7**(需 Node 20+),**禁止用 `npm create vite`** |
生产形态:`npm run build` 产出 `frontend/dist`,BFF 用 `StaticFiles` 挂载,单进程从 `:8090` 提供服务。
---
## 4. 开发工作流:本地 staging + rsync
远端机器是**运行与测试环境**,本地是**编辑环境**。原因:agent 在本地能用完整的读/写/编辑工具迭代,通过 SSH 逐行改远端文件既慢又易错。
| 角色 | 路径 |
|---|---|
| 本地编辑(权威源) | `/Users/jerry/haiguji/PlantAI-rag-new/` |
| 远端运行(部署副本) | `/home/xzq/5090/teamWorkspace/zh/PlantAI-rag-new/` |
同步命令(由 `deploy/sync.sh` 封装):
```bash
rsync -az --delete \
--exclude 'node_modules' --exclude '__pycache__' --exclude '.venv' \
--exclude 'backend/data' --exclude 'frontend/dist' --exclude '.pytest_cache' \
/Users/jerry/haiguji/PlantAI-rag-new/ \
100.109.52.26:/home/xzq/5090/teamWorkspace/zh/PlantAI-rag-new/
```
**规则**:
- 所有 agent **只在本地路径写文件**,绝不用 SSH heredoc 改代码。
- 同步由 **PM 统一执行**,agent 不自行 rsync(避免半成品覆盖远端)。
- `backend/data`(数据库)、`node_modules`、`dist` 不同步,属远端运行时产物。
- 文档最终必须在远端 `docs/` 下可查——每次里程碑结束由 PM 同步一次。
---
## 5. Agent 分工与文件归属
**铁律:文件归属严格互斥。任何 agent 不得写入不属于自己的文件。** 需要跨归属改动时,向 PM 提出,由 PM 单点裁决修改。
| Agent | 职责 | 独占路径 |
|---|---|---|
| **PM** | 契约文档、集成、缺陷派发、验收、rsync | `docs/{PRD,API,UI_SPEC,ARCHITECTURE,TEST_PLAN,ACCEPTANCE,CHANGELOG}.md`、`deploy/**`、`src/i18n/labels.js`、`src/config/modes.js`、`backend/mock/**` |
| **D0 探测** | 上游探测与选型 | `docs/DISCOVERY.md` |
| **A1 后端·骨架** | app 工厂、配置、SQLite、会话与消息 CRUD、归一化器、错误信封 | `backend/pyproject.toml`、`backend/run.sh`、`backend/.env.example`、`backend/app/{main,config,db,schemas,upstream}.py`、`backend/app/routers/{health,sessions}.py`、`backend/app/services/normalize.py` |
| **A2 后端·QA** | QA 代理、SSE 中继、阶段映射、重试与看门狗 | `backend/app/routers/qa.py`、`backend/app/services/sse_relay.py` |
| **A3 后端·图谱与抽取** | Neo4j Bolt 直连、抽取代理与回落 | `backend/app/routers/{kg,extraction}.py`、`backend/app/services/{neo4j,extraction}.py` |
| **B1 前端·基础** | 令牌层、AppShell、四档响应式框架、主题、顶栏/底栏、通用 UI、健康轮询 | `frontend/{package.json,vite.config.js,vitest.config.js,index.html}`、`frontend/src/{main.js,App.vue}`、`frontend/src/styles/**`、`frontend/src/components/{layout,ui}/**`、`frontend/src/stores/{theme,health}.js`、`frontend/src/api/http.js`、`tests/frontend/unit/b1/**` |
| **B2 前端·会话与对话** | 会话列表与抽屉、对话区、作曲器、流水线卡、SSE 客户端 | `frontend/src/components/{session,chat}/**`、`frontend/src/stores/{sessions,chat}.js`、`frontend/src/sse/**`、`frontend/src/api/{qa,sessions}.js`、`tests/frontend/unit/b2/**` |
| **B3 前端·工作台** | 右侧四个 tab:检索过程、文献来源、提取任务、知识图谱 | `frontend/src/components/bench/**`、`frontend/src/stores/bench.js`、`frontend/src/api/{kg,extraction}.js`、`tests/frontend/unit/b3/**` |
| **T 测试** | 用例编写与执行、缺陷报告 | `tests/backend/api/**`、`tests/e2e/**`、`playwright.config.js`、`docs/TEST_CASES.md`、`docs/TEST_REPORT_*.md` |
后端各 agent 的单测放在各自归属子树内(`backend/app/**/test_*.py`,随代码一起交付),运行 `pytest backend/app -q`;T 的 L2 接口测试与 L5 e2e 放在 `tests/`。
### 跨归属的接缝
以下文件被多方读取但只有一个写入方,接缝处必须按契约对齐:
| 接缝 | 写入方 | 读取方 | 契约依据 |
|---|---|---|---|
| BFF 接口形态 | A1/A2/A3 | B1/B2/B3、T | `API.md` |
| 设计令牌 CSS 变量 | B1 (`styles/tokens.css`) | B2、B3 | `UI_SPEC.md` §令牌 |
| 组件类名 | B1 定义基础类,B2/B3 复用 | 互相 | `UI_SPEC.md` §组件 |
| 五阶段标签与颜色 | PM (`i18n/labels.js`) | A2(计算 phase)、B2、B3 | `PRD.md` FR-CHAT-009 |
| 模式参数集 | PM (`config/modes.js`) | B2 | `PRD.md` FR-CHAT-006 |
| 块联合结构 | A1(落库)、B2(渲染) | T | `API.md` §块联合 |
---
## 6. 并行解耦:mock server
前端三个 agent **不等待后端**。M0 阶段 PM 产出 `backend/mock/mock_server.py`:
- FastAPI,监听 `127.0.0.1:8099`
- 实现 `API.md` 中**全部**接口,返回 `backend/mock/fixtures/*.json` 里的固定数据
- 包含一条**可回放的 SSE 事件序列**(按真实时序 sleep),让流式 UI 能在无上游时开发
- 支持 `?scenario=` 查询参数切换场景:`normal` / `empty`(空结果)/ `slow`(慢响应)/ `error`(上游故障)/ `degraded`(部分降级)
B 组开发时把 `vite.config.js` 的 proxy 指向 8099;集成阶段由 PM 切回 8090。
**fixtures 是单一事实源**:mock 与真实 BFF 的单元测试共用同一批 fixture 文件,保证契约不漂移。
---
## 7. 集成节奏
```
M0 契约锁定 ──┬─→ A1 A2 A3(对真实上游)──┐
├─→ B1 B2 B3(对 mock) ─┤→ M2 PM 集成 → M3 补齐 → M4 测试循环 → M5 验收
└─→ T 写用例(对 PRD) ─┘
```
- 每一波结束,agent 向 PM 汇报「完成项 + 未决问题 + 对契约的偏差建议」,**不直接改契约**。
- PM 在集成点统一处理契约偏差,必要时更新 `API.md` 并广播给受影响的 agent。
- 缺陷修复一律**批量派发**,禁止边测边改(见 `TEST_PLAN.md` 轮次纪律)。
---
## 8. 目录结构
```
PlantAI-rag-new/
├── docs/ # 全部文档,见第 5 节归属
├── deploy/
│ ├── sync.sh # 本地 → 远端 rsync
│ └── start-dev.sh # 拉起 BFF + vite,打印隧道命令
├── backend/
│ ├── pyproject.toml run.sh .env.example
│ ├── data/ # plantai.db(不入库、不同步)
│ ├── mock/
│ │ ├── mock_server.py
│ │ └── fixtures/*.json
│ └── app/
│ ├── main.py config.py db.py schemas.py upstream.py
│ ├── routers/ health.py sessions.py qa.py kg.py extraction.py
│ └── services/ normalize.py sse_relay.py neo4j.py extraction.py
├── frontend/
│ ├── package.json vite.config.js index.html vitest.config.js
│ └── src/
│ ├── main.js App.vue
│ ├── styles/ tokens.css base.css animations.css responsive.css
│ ├── i18n/labels.js config/modes.js
│ ├── api/ http.js qa.js sessions.js kg.js extraction.js
│ ├── sse/ parser.js
│ ├── stores/ theme.js health.js sessions.js chat.js bench.js
│ └── components/
│ ├── layout/ AppShell 相关、TopBar、StatusBar、AuroraBg、Drawer
│ ├── ui/ StatusBadge、StatusDot、IconButton、Skeleton、EmptyNotice
│ ├── session/ SessionPanel、SessionItem、SessionRail、SearchBox
│ ├── chat/ ChatPanel、MessageList、Composer、PipelineCard、ToolCard …
│ └── bench/ BenchPanel、RetrievalPane、SourcesPane、ExtractionPane、KgPane …
├── tests/
│ ├── backend/ # pytest
│ ├── frontend/ # vitest
│ └── e2e/ # playwright
└── playwright.config.js
```
---
## 9. 编码约定
**后端**
- 全异步(`async def` + httpx.AsyncClient + aiosqlite);不在请求路径上做阻塞 IO。
- 所有对上游的调用集中在 `services/`,`routers/` 只做参数校验与响应组装。
- 不吞异常:上游故障必须转成带 `code` 的错误信封,并在日志里保留原始异常。
- 类型标注齐全,Pydantic v2 模型定义在 `schemas.py`。
**前端**
- Vue 3 `<script setup>` + Composition API;组件单一职责,超过 ~250 行考虑拆分。
- **样式一律用 `--pa-*` 令牌**,禁止硬编码颜色值(令牌表见 `UI_SPEC.md`)。
- 组件内 `<style scoped>`;跨组件复用的类放 `styles/base.css`(B1 归属)。
- 状态跨组件共享一律走 Pinia store,禁止用 provide/inject 传业务状态。
- 所有用户可见文案走 `i18n/labels.js`,组件内不写死中文字符串(错误提示除外,见 `PRD.md` §全局约定)。
**通用**
- 文件编码 UTF-8,LF 换行。
- 提交粒度:一个 FR 一次提交,提交信息含 FR 编号。
---
## 10. 已知的既存故障(不修,仅规避)
| 现象 | 影响 | 我们的对策 |
|---|---|---|
| 默认端口 7687 无 Neo4j,`:8000/api/v1/kg/*` 与 `/v15-graph-qa/*` 报错 | 上游图谱路由不可用 | BFF 用 Bolt 直连非标准端口实例,见 `DISCOVERY.md` |
| PlantAI-dev `.env` 指向 `7925`(空端口),实际 QA 在 `7920` | PlantAI-dev 知识问答当前是坏的 | 与本项目无关,仅记录;本项目指向 7920 |
| 上游 QA 无 token 级流式,答案在终态一次返回 | 无法做真流式打字 | 客户端揭示动画,视觉一致但不伪造数据流 |
| 上游 `max_rounds: 1`,每个提问独立 | 无多轮上下文 | UI 明确提示「每次提问独立检索」,不假装有上下文记忆 |