diff --git a/README.md b/README.md index 71bbf3d..022fb40 100644 --- a/README.md +++ b/README.md @@ -15,14 +15,17 @@ CodeMind 是一个面向计算机知识学习场景的 RAG(Retrieval-Augmented - 在线 LLM RAG 回答和来源编号校验 - 文档库、原始文档预览、片段查看与来源跳转 - 问答历史列表、详情查看和历史来源快照 -- 知识库思维导图异步生成、进度展示和历史管理 -- 思维导图节点追问、节点扩展和画布交互 +- 知识地图异步生成、分阶段进度、失败恢复和历史版本管理 +- 总览、章节、概念、细节四类节点,以及关键记忆点和学习建议 +- 节点来源核对、针对性追问、AI 分支扩展和相关资料检索 +- 节点搜索定位、路径导航、本机掌握进度和继续学习入口 +- 画布缩放、布局、撤销重做、分支折叠、全屏及 PNG/SVG/JSON/Markdown 导出 - 文档、向量、原始文件和知识库级联清理 - Docker Compose 本地及服务器部署 后续计划: -- 用户反馈持久化和管理员反馈页面 +- 用户反馈持久化、管理员反馈页面和相应自动化测试 - 基于固定测试集的相似度阈值评估 - RAG 问答与思维导图的真实模型端到端测试 - 前端产物体积优化和项目成果物整理 @@ -50,7 +53,9 @@ flowchart LR Backend --> Uploads[("上传文件")] Backend --> Embedding["Embedding API"] Backend --> LLM["在线 LLM API"] - Backend --> MindMap["RAG 回答与思维导图生成"] + Backend --> RAG["RAG 问答"] + Backend --> MindMap["知识地图任务与历史"] + RAG --> LLM MindMap --> LLM ``` @@ -236,7 +241,8 @@ Get-Content -Raw database\migrations\20260711_preserve_qa_source_snapshots.sql | 6. 查看回答中的来源片段和相关度。 7. 点击“查看片段”或进入“文档库”核对原文。 8. 在“问答历史”中回看回答;原文被删除后仍保留来源快照。 -9. 进入“知识地图”异步生成思维导图,并对节点追问或继续扩展。 +9. 进入“知识地图”异步生成学习结构,并查看节点类型、记忆点、学习建议和原文覆盖率。 +10. 搜索或定位节点,标记本机掌握状态,对节点追问、扩展分支或导出地图。 如果检索不到资料,请先确认文档处理状态、Embedding 配置和相似度阈值。阈值与 Embedding 模型及切分粒度有关,更换模型后必须重新评估。 @@ -269,6 +275,7 @@ Authorization: Bearer | `GET` | `/api/qa-records/{id}` | 问答历史详情 | | `POST` | `/api/mind-maps/jobs` | 创建导图生成任务 | | `GET` | `/api/mind-maps/jobs/{id}` | 查询任务进度 | +| `POST` | `/api/mind-maps/generate` | 同步生成导图(调试接口) | | `POST` | `/api/mind-maps/ask` | 对导图节点追问 | | `POST` | `/api/mind-maps/expand` | 扩展导图节点 | | `GET/POST` | `/api/mind-maps/histories` | 查询或保存导图历史 | @@ -286,7 +293,7 @@ python -m pip install pytest==8.3.5 python -m pytest -q ``` -当前后端测试共 46 项,覆盖认证、权限、文档处理、删除清理、检索降级、Prompt、LLM 异常、RAG 编排、问答历史和思维导图服务。 +当前后端测试共 53 项,覆盖认证、权限、文档处理、删除清理、检索降级、Prompt、LLM 异常、RAG 编排、问答历史,以及知识地图生成、并发控制、任务、历史和接口权限。 前端生产构建检查: @@ -356,6 +363,12 @@ Docker Compose 使用三个命名卷: 确认知识库中存在 `completed` 文档,并检查相似度阈值。不要直接把其他 Embedding 模型下的阈值用于当前模型。 +### 知识地图无法生成或一直等待 + +知识地图必须配置在线 LLM。先查看 `docker compose logs -f backend`,确认任务是否进入 `failed`,再检查 LLM 模型、超时和网络。前端会在页面切换后恢复同一知识库的未完成任务,并逐步降低轮询频率。 + +知识地图节点的 `node_type`、`key_points` 和 `learning_tip` 保存在历史记录的 JSON 中,不需要新增数据库列;旧历史缺少这些字段时会使用兼容默认值。 + ### 修改 schema.sql 后数据库没有变化 初始化脚本不会作用于已有数据卷。请执行对应的 `database/migrations/*.sql`,不要为了应用结构变化直接删除生产数据卷。 @@ -371,10 +384,15 @@ $OutputEncoding = [System.Text.Encoding]::UTF8 ## 项目文档 +- [文档导航与实现状态](docs/README.md) +- [前端开发说明](frontend/README.md) +- [后端开发说明](backend/README.md) - [需求分析](docs/需求分析.md) - [API 接口设计](docs/API接口设计.md) - [生成侧接口约定](docs/生成侧接口约定.md) +- [GitHub Wiki 首页草稿](docs/wiki/Home.md) - [数据库结构](database/schema.sql) +- [数据库与迁移说明](database/README.md) ## 安全说明 @@ -386,3 +404,7 @@ $OutputEncoding = [System.Text.Encoding]::UTF8 ## License 本项目用于课程实训。若后续需要公开发布或允许外部复用,请由项目组补充正式开源许可证。 + +--- + +文档状态:已按 `main` 提交 `839890b`(合并 PR #11)同步,更新时间为 2026-07-13。 diff --git a/backend/README.md b/backend/README.md index 0bfc908..94501c6 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1,25 +1,104 @@ # CodeMind Backend -FastAPI 后端负责提供文档管理、RAG 问答、问答历史和系统管理接口。 +FastAPI 后端负责认证、知识库与文档管理、Embedding 入库、Chroma 检索、RAG 问答、问答历史和知识地图服务。 -## 开发命令 +## 模块结构 + +| 目录或文件 | 职责 | +| --- | --- | +| `app/api/routes.py` | REST API 与 HTTP 错误转换 | +| `app/core/config.py` | `.env` 配置读取和路径解析 | +| `app/db/session.py` | SQLAlchemy Engine 与 Session | +| `app/services/document_service.py` | 上传、后台解析、入库、重建和删除 | +| `app/services/retrieval_service.py` | 问题重写、Embedding、Chroma 召回、过滤与 rerank | +| `app/services/rag_service.py` | 检索、Prompt、LLM、历史保存的问答编排 | +| `app/services/mind_map_service.py` | 知识地图结构生成、节点追问和分支扩展 | +| `app/services/mind_map_job_service.py` | 异步任务状态、进度和结果持久化 | +| `app/services/mind_map_history_service.py` | 地图历史版本和画布状态持久化 | +| `tests/` | 后端自动化测试 | + +## 环境配置 + +在 `backend/` 下创建 `.env`。字段模板位于仓库根目录 `.env.example`,至少配置: + +```dotenv +MYSQL_HOST=localhost +MYSQL_PORT=3306 +MYSQL_USER=root +MYSQL_PASSWORD=replace_with_database_password +MYSQL_DATABASE=codemind + +LLM_API_KEY=replace_with_llm_key +LLM_BASE_URL=https://provider.example.com/v1 +LLM_MODEL=replace_with_chat_model + +EMBEDDING_API_KEY=replace_with_embedding_key +EMBEDDING_BASE_URL=https://provider.example.com/v1 +EMBEDDING_MODEL=replace_with_embedding_model + +JWT_SECRET_KEY=replace_with_a_long_random_secret +``` + +Embedding 未配置时,文档入库和检索会明确失败;普通 RAG 问答在 LLM 未配置时保留本地演示回答。知识地图依赖结构化 LLM 输出,因此必须配置在线 LLM。 + +## 原生开发 + +Windows PowerShell: + +```powershell +cd backend +E:\Python\python.exe -m pip install -r requirements.txt +E:\Python\python.exe -m uvicorn app.main:app --reload +``` + +Linux、macOS 或 WSL: ```bash -python -m venv .venv -.venv/Scripts/activate -pip install -r requirements.txt -uvicorn app.main:app --reload +cd backend +python3 -m venv .venv +source .venv/bin/activate +python -m pip install -r requirements.txt +python -m uvicorn app.main:app --reload ``` -默认服务地址: +默认地址: + +- API:`http://localhost:8000` +- Swagger:`http://localhost:8000/docs` +- 健康检查:`http://localhost:8000/api/health` -```text -http://localhost:8000 +除健康检查、注册和登录外,业务接口需要: + +```http +Authorization: Bearer ``` -接口文档地址: +## 知识地图说明 + +- `POST /api/mind-maps/jobs` 创建后台任务,`GET /api/mind-maps/jobs/{job_id}` 查询进度。 +- 任务会分批提炼资料,再合并为总览、章节、概念和细节节点。 +- 每个节点可包含 `key_points`、`learning_tip`、原文来源和子节点。 +- 同一后端实例的知识地图 LLM 调用并发上限为 3;分批调用失败时会取消剩余请求。 +- 自动生成结果会保存历史版本;前端也可创建、更新和删除版本。 +- 新增节点学习字段位于历史 JSON 中,旧数据可使用默认值读取,不需要数据库迁移。 -```text -http://localhost:8000/docs +## 运行测试 + +```bash +cd backend +python -m pytest -q ``` +当前基线为 `53 passed`。测试使用 SQLite 和替身服务覆盖主要业务,不等同于真实 MySQL、Chroma 和在线模型端到端验证。 + +## Docker 运行 + +完整环境建议从仓库根目录启动: + +```bash +docker compose up -d --build +docker compose logs -f backend +``` + +已有数据库升级时还需按根目录 README 执行 `database/migrations/` 中尚未应用的脚本。 + diff --git a/database/README.md b/database/README.md new file mode 100644 index 0000000..4e8085e --- /dev/null +++ b/database/README.md @@ -0,0 +1,53 @@ +# CodeMind Database + +CodeMind 使用 MySQL 保存结构化业务数据,使用 Chroma 保存文档片段向量。两者承担不同职责,不能互相替代。 + +## MySQL 表 + +| 表 | 用途 | +| --- | --- | +| `users` | 用户、密码哈希、角色和状态 | +| `knowledge_bases` | 私人知识库和用户归属 | +| `documents` | 文件信息、处理状态、错误和片段数量 | +| `document_chunks` | 文本片段、位置、页码和 `vector_id` | +| `qa_records` | 问题、重写问题、回答和来源数量 | +| `qa_sources` | 历史来源快照和可空的原文关联 | +| `feedbacks` | 反馈目标表;当前业务接口尚未持久化 | +| `mind_map_histories` | 地图结果 JSON、节点数和画布状态 | +| `mind_map_jobs` | 地图后台任务、阶段、进度、结果和错误 | + +新数据库由 `schema.sql` 初始化。Docker 中该脚本只会在 `mysql_data` 数据卷第一次创建时运行。 + +## 已有数据库迁移 + +| 脚本 | 用途 | +| --- | --- | +| `migrations/20260711_add_document_error_message.sql` | 增加文档处理失败原因 | +| `migrations/20260711_preserve_qa_source_snapshots.sql` | 删除原文后保留问答来源快照 | +| `migrations/20260712_create_mind_map_tables.sql` | 创建地图历史和后台任务表 | + +生产数据库执行迁移前必须备份。迁移脚本按说明执行一次,不要通过删除 Docker 数据卷来替代迁移。 + +Linux、macOS 或 WSL 示例: + +```bash +docker compose exec -T mysql sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE"' \ + < database/migrations/.sql +``` + +Windows PowerShell 示例: + +```powershell +Get-Content -Raw database\migrations\.sql | + docker compose exec -T mysql sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE"' +``` + +## Chroma 关联 + +`document_chunks.vector_id` 与 Chroma 记录 ID 一一对应。Chroma metadata 至少包含用户、知识库、文档、片段序号、文件名、页码和偏移信息,以便权限过滤和来源反查。 + +更换 Embedding 模型或向量维度后,旧向量不能与新向量混用。应停止写入、备份数据、清空或重建 Chroma 索引,并对现有文档重新入库;MySQL 用户和业务记录不应随向量重建一起删除。 + +## 知识地图字段兼容 + +`node_type`、`key_points` 和 `learning_tip` 位于 `mind_map_histories.result_json`,不是独立数据库列。新增字段由后端模型提供默认值,因此 PR #11 不需要额外数据库迁移,旧地图历史可以继续读取。 diff --git "a/docs/API\346\216\245\345\217\243\350\256\276\350\256\241.md" "b/docs/API\346\216\245\345\217\243\350\256\276\350\256\241.md" index 115ada7..01cdd7c 100644 --- "a/docs/API\346\216\245\345\217\243\350\256\276\350\256\241.md" +++ "b/docs/API\346\216\245\345\217\243\350\256\276\350\256\241.md" @@ -5,8 +5,7 @@ - 基础路径:`/api` - 数据格式:除文件上传外,请求和响应均使用 `application/json` - 文件上传:`multipart/form-data` -- 正式认证:受保护接口使用 `Authorization: Bearer ` -- 当前后端参考代码:临时使用 `X-User-Id` 表示当前用户,后续由 JWT 鉴权替换 +- 认证:除健康检查、注册和登录外,受保护接口使用 `Authorization: Bearer ` - 时间格式:ISO 8601 字符串 - 相似度分数:余弦相似度范围为 `[-1, 1]`,默认过滤阈值为 `0.77` @@ -34,6 +33,7 @@ | 文档 | GET | `/api/documents` | 查询文档列表 | | 文档 | POST | `/api/documents/upload` | 上传文档 | | 文档 | GET | `/api/documents/{document_id}` | 查询文档详情 | +| 文档 | GET | `/api/documents/{document_id}/content` | 内联读取原始文档 | | 文档 | DELETE | `/api/documents/{document_id}` | 删除文档和向量索引 | | 文档 | POST | `/api/documents/{document_id}/reindex` | 重新入库文档 | | 文档 | GET | `/api/documents/{document_id}/chunks` | 查询文档片段 | @@ -41,6 +41,16 @@ | 文档 | GET | `/api/chunks/{chunk_id}` | 查询单个片段 | | 检索 | POST | `/api/search` | 语义检索或文档直接检索 | | 问答 | POST | `/api/chat` | RAG 问答 | +| 知识地图 | POST | `/api/mind-maps/generate` | 同步生成地图(调试) | +| 知识地图 | POST | `/api/mind-maps/jobs` | 创建后台生成任务 | +| 知识地图 | GET | `/api/mind-maps/jobs/{job_id}` | 查询任务进度和结果 | +| 知识地图 | POST | `/api/mind-maps/ask` | 针对节点来源提问 | +| 知识地图 | POST | `/api/mind-maps/expand` | 根据来源扩展节点 | +| 知识地图 | GET | `/api/mind-maps/histories` | 查询地图历史 | +| 知识地图 | POST | `/api/mind-maps/histories` | 保存地图历史 | +| 知识地图 | GET | `/api/mind-maps/histories/{history_id}` | 查询地图历史详情 | +| 知识地图 | PUT | `/api/mind-maps/histories/{history_id}` | 更新地图和画布状态 | +| 知识地图 | DELETE | `/api/mind-maps/histories/{history_id}` | 删除地图历史 | | 历史 | GET | `/api/qa-records` | 查询问答历史 | | 历史 | GET | `/api/qa-records/{qa_record_id}` | 查询问答详情 | | 反馈 | POST | `/api/qa-records/{qa_record_id}/feedback` | 提交回答反馈 | @@ -216,7 +226,16 @@ GET /api/documents?knowledge_base_id=1&parse_status=completed 响应为 `DocumentRead[]`,字段同上传文档响应。 -### 5.3 重新入库文档 +### 5.3 查询文档详情和原文件 + +```text +GET /api/documents/{document_id} +GET /api/documents/{document_id}/content +``` + +第一个接口返回 `DocumentRead`。第二个接口校验文档归属后以内联方式返回原文件,支持 PDF、DOCX、Markdown 和 TXT;原文件不存在时返回 `404`。前端文档预览页使用该接口,不应绕过 JWT 直接访问上传目录。 + +### 5.4 重新入库文档 ```text POST /api/documents/{document_id}/reindex @@ -231,7 +250,7 @@ POST /api/documents/{document_id}/reindex } ``` -### 5.4 查询文档片段 +### 5.5 查询文档片段 ```text GET /api/documents/{document_id}/chunks @@ -356,9 +375,140 @@ POST /api/chat } ``` -## 8. 历史与反馈接口 +## 8. 知识地图接口 + +知识地图必须配置在线 LLM。前端正式流程使用后台任务接口,避免长时间同步请求阻塞页面;同步接口主要用于 Swagger 调试和后端联调。 + +### 8.1 创建并查询生成任务 + +```text +POST /api/mind-maps/jobs +GET /api/mind-maps/jobs/{job_id} +``` + +创建请求: + +```json +{ + "knowledge_base_id": 1, + "document_id": null, + "max_depth": 3, + "max_nodes": 38 +} +``` + +- `document_id=null` 表示使用知识库内全部已完成解析的文档。 +- `max_depth` 范围为 2 至 4。 +- `max_nodes` 范围为 8 至 60。 + +创建成功返回 `202 Accepted`: + +```json +{ + "job_id": "e1f0b8f4d6d84dbe8db3f8cf15a1f08b", + "status": "queued", + "stage": "queued", + "progress": 0, + "message": "任务已创建,正在等待处理", + "result": null, + "error_message": null, + "created_at": "2026-07-13T10:00:00", + "updated_at": "2026-07-13T10:00:00" +} +``` + +任务状态为 `queued`、`processing`、`completed` 或 `failed`。处理中可出现 `collecting`、`preparing`、`extracting`、`merging`、`validating` 和 `assembling` 阶段。完成后 `result` 为 `MindMapResponse`;失败时读取 `error_message`。 + +同步接口使用同一请求模型: + +```text +POST /api/mind-maps/generate +``` + +### 8.2 地图节点结构 + +`MindMapResponse.root` 是递归节点: + +```json +{ + "id": "mind-node-0-0", + "title": "进程与线程", + "summary": "说明两种并发抽象的定义、作用和关系。", + "node_type": "concept", + "key_points": ["进程拥有独立资源", "线程共享进程资源"], + "learning_tip": "画表比较资源、调度和切换成本", + "depth": 2, + "sources": [ + { + "chunk_id": 10, + "document_id": 1, + "file_name": "操作系统笔记.pdf", + "chunk_index": 3, + "page_no": 12, + "source_text": "进程拥有独立地址空间……", + "jump_url": "/documents/1/chunks/10" + } + ], + "children": [] +} +``` + +`node_type` 只能为 `overview`、`chapter`、`concept` 或 `detail`;`key_points` 最多 3 条。新增字段都有兼容默认值,旧历史 JSON 可以继续读取。 + +### 8.3 节点提问 + +```text +POST /api/mind-maps/ask +``` + +```json +{ + "knowledge_base_id": 1, + "node_title": "进程与线程", + "question": "两者最容易混淆的地方是什么?", + "source_chunk_ids": [10, 11] +} +``` + +后端只允许使用当前用户、当前知识库且已完成解析的片段,最多 8 个。响应包含回答和实际使用的来源列表。 + +### 8.4 节点扩展 + +```text +POST /api/mind-maps/expand +``` + +```json +{ + "knowledge_base_id": 1, + "node_title": "进程与线程", + "node_summary": "并发执行的基本抽象", + "source_chunk_ids": [10, 11], + "child_count": 4 +} +``` + +`child_count` 范围为 2 至 8。后端根据给定真实来源生成子结构,并返回一个 `MindMapNode`。无效来源返回 `404`;缺少 LLM 配置返回 `503`;模型未返回有效 JSON 返回 `502`。 + +### 8.5 地图历史 + +```text +GET /api/mind-maps/histories?knowledge_base_id=1 +POST /api/mind-maps/histories +GET /api/mind-maps/histories/{history_id} +PUT /api/mind-maps/histories/{history_id} +DELETE /api/mind-maps/histories/{history_id} +``` + +- 列表响应不携带完整 `result`,详情响应包含完整地图。 +- 创建和更新时可传 `view_state`,用于保存节点坐标及折叠状态。 +- `document_id` 必须属于同一用户和同一知识库。 +- 自动生成成功后后端会保存一个历史版本。 +- 节点掌握状态当前保存在浏览器 `localStorage`,不属于历史接口字段。 + +## 9. 历史与反馈接口 -### 8.1 查询问答历史 +### 9.1 查询问答历史 ```text GET /api/qa-records?knowledge_base_id=1 @@ -382,7 +532,7 @@ GET /api/qa-records?knowledge_base_id=1 ] ``` -### 8.2 查询问答详情 +### 9.2 查询问答详情 ```text GET /api/qa-records/{qa_record_id} @@ -390,7 +540,9 @@ GET /api/qa-records/{qa_record_id} 响应为单个 `QaRecordRead`,应包含完整 `sources` 列表。 -### 8.3 提交反馈 +历史来源中的 `document_id` 和 `chunk_id` 可以为空。删除原文后仍返回文件名、片段序号、页码、分数和文本快照,但 `jump_url` 为 `null`。 + +### 9.3 提交反馈 ```text POST /api/qa-records/{qa_record_id}/feedback @@ -405,7 +557,9 @@ POST /api/qa-records/{qa_record_id}/feedback } ``` -响应: +当前状态:该接口只返回演示响应,没有查询问答归属,也没有写入 `feedbacks` 表;管理员列表当前返回空数组。前端尚未接入,不能作为已完成的持久化功能。 + +演示响应: ```json { @@ -418,7 +572,7 @@ POST /api/qa-records/{qa_record_id}/feedback } ``` -## 9. 字段一致性要求 +## 10. 字段一致性要求 | API 字段 | MySQL 字段或 Chroma metadata | 说明 | | ---------------------- | -------------------------------------------------------------------- | ---------------------------------------- | @@ -430,5 +584,12 @@ POST /api/qa-records/{qa_record_id}/feedback | `qa_record_id` | `qa_records.id`、`qa_sources.qa_record_id` | 问答历史和来源引用关联 | | `source_text` | `qa_sources.source_text`、Chroma document | 来源片段快照 | | `score` | `qa_sources.score` | 检索相似度或 rerank 分数,范围 `[-1, 1]` | +| `job_id` | `mind_map_jobs.id` | 地图后台任务编号 | +| `history_id` | `mind_map_histories.id` | 地图历史版本编号 | +| `node_type` | `mind_map_histories.result_json` | 地图节点类型,不单独占数据库列 | + +后端实现位于 `backend/app/api/routes.py`、`backend/app/services/` 和 `backend/app/schemas/contracts.py`。当前已接入 JWT、MySQL、Chroma、Embedding、在线 LLM、问答历史和知识地图;反馈持久化、真实模型端到端测试和检索评估仍需继续完善。 + +--- -后端实现位于 `backend/app/api/routes.py`、`backend/app/services/` 和 `backend/app/schemas/contracts.py`。当前已接入 MySQL、Chroma、Embedding 与在线 LLM API;认证、反馈管理和更完整的检索评估仍需继续完善。 +文档状态:已按 `main` 提交 `839890b` 同步,更新时间为 2026-07-13。 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..6c7dd93 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,49 @@ +# CodeMind 文档导航 + +本文档记录 `main` 分支当前实现与项目文档之间的对应关系。最后核对提交:`839890b`(2026-07-13,合并 PR #11)。 + +## 文档目录 + +| 文档 | 用途 | +| --- | --- | +| [项目 README](../README.md) | 快速开始、部署、迁移、测试和常见问题 | +| [后端 README](../backend/README.md) | 后端模块、原生开发、配置和测试 | +| [前端 README](../frontend/README.md) | 页面路由、知识地图交互、构建和安全说明 | +| [需求分析](需求分析.md) | 角色、功能需求、数据需求和当前实现状态 | +| [API 接口设计](API接口设计.md) | JWT、请求响应、知识地图和接口状态 | +| [生成侧接口约定](生成侧接口约定.md) | RAG 生成链路、检索契约、历史来源和知识地图 LLM 边界 | +| [Wiki 首页草稿](wiki/Home.md) | 面向团队的完整项目设计与进度说明 | +| [数据库结构](../database/schema.sql) | 新数据库初始化结构 | +| [数据库说明](../database/README.md) | 表职责、迁移、Chroma 和地图 JSON 兼容 | +| [数据库迁移](../database/migrations/) | 已有数据库升级脚本 | + +## 当前实现快照 + +已完成: + +- JWT 注册登录和用户资源隔离。 +- 私人知识库增删改查。 +- PDF、DOCX、Markdown、TXT 上传、解析、切分、Embedding 和 Chroma 入库。 +- 文档库、原文预览、片段查看、重建索引和级联删除。 +- 语义检索、问题重写、阈值过滤、rerank、RAG 回答和来源校验。 +- 问答历史页面与删除原文后的来源快照保留。 +- 知识地图异步任务、历史版本、节点追问、分支扩展、学习结构和画布交互。 +- Docker Compose 本地与 VPS 部署基础能力。 +- 后端自动化测试基线:53 项。 + +尚未完整完成: + +- 反馈接口目前只返回演示响应,尚未写入 `feedbacks` 表;管理员接口当前返回空列表。 +- 缺少基于真实 MySQL、Chroma 和在线模型的稳定端到端测试记录。 +- 固定 RAG 测试集、阈值评估和质量指标仍需由对应负责人推进。 +- 前端生产构建仍存在较大 chunk 警告。 +- 项目报告、PPT、演示视频等实训成果物仍在整理。 + +## 文档维护规则 + +1. 合并功能 PR 时同步更新 README、需求、API 和 Wiki 中的实现状态。 +2. “需求”与“已实现”分开描述,演示接口不能标记为持久化完成。 +3. API 字段以 `backend/app/schemas/contracts.py` 为准,路由以 `backend/app/api/routes.py` 为准。 +4. 测试数量以实际执行 `python -m pytest -q` 的结果为准。 +5. 数据库结构改变时同时提交 `schema.sql` 和已有数据库迁移脚本。 +6. 文档、日志、截图和 Wiki 中不得出现 API Key、密码、Token 或完整 `.env`。 diff --git a/docs/wiki/Home.md b/docs/wiki/Home.md new file mode 100644 index 0000000..25accea --- /dev/null +++ b/docs/wiki/Home.md @@ -0,0 +1,583 @@ +# CodeMind 项目设计与开发说明 + +> CodeMind 是一个面向计算机知识学习场景的 RAG 知识库问答系统。 +> +> 文档依据:《CodeMind 项目设计报告》及当前 `main` 分支实现整理。 + +## 1. 项目简介 + +CodeMind 支持用户上传课程资料、实验文档和技术文档,将资料解析、切分并转换为向量后写入知识库。用户可以在指定知识库中进行语义检索、通过自然语言获得带来源引用的回答,还可以把资料生成带原文依据的知识地图。 + +项目希望解决以下问题: + +- 个人计算机学习资料分散,查找效率较低。 +- 普通关键词检索难以理解自然语言问题的真实含义。 +- 通用大模型可能脱离用户资料生成缺少依据的回答。 +- 回答缺少来源时,用户难以核对内容是否可靠。 + +CodeMind 通过 RAG(Retrieval-Augmented Generation,检索增强生成)将语义检索与在线大模型结合,使回答尽量来源于用户上传的资料,并提供可核对的文档片段。 + +## 2. 项目目标 + +- 支持多用户注册、登录和数据隔离。 +- 支持创建、维护和删除个人知识库。 +- 支持 PDF、DOCX、Markdown 和 TXT 文档上传。 +- 支持文档解析、文本切分、Embedding 和向量入库。 +- 支持按知识库进行语义检索和文档片段查看。 +- 支持基于检索结果生成带来源引用的 RAG 回答。 +- 支持保存问题、回答和来源快照,供用户查看历史记录。 +- 支持生成可追溯的知识地图,对节点追问、扩展、搜索、导航和复习。 +- 支持 Docker Compose 本地部署和 VPS 部署。 + +## 3. 技术选型 + +| 层次 | 技术 | 主要用途 | +| --- | --- | --- | +| 前端 | Vue 3、Vite、Element Plus、AntV G6、Axios | 页面、路由、知识地图画布和接口调用 | +| 后端 | FastAPI、Pydantic、SQLAlchemy | REST API、业务编排、参数校验和数据库访问 | +| 业务数据库 | MySQL 8.0 | 用户、知识库、文档、片段、历史和反馈 | +| 向量数据库 | Chroma | 文档片段向量存储和相似度召回 | +| 模型服务 | OpenAI 兼容在线 API | LLM 回答生成和 Embedding | +| 认证 | JWT Bearer Token | 登录状态和受保护接口访问 | +| 部署 | Docker、Docker Compose、Nginx | 服务构建、编排和前端反向代理 | + +## 4. 系统角色 + +| 角色 | 主要能力 | +| --- | --- | +| 普通用户 | 注册登录、管理知识库、上传资料、语义检索、RAG 提问、查看来源和历史、生成知识地图 | +| 管理员 | 查看系统反馈和运行数据;反馈持久化与管理页面仍待完成 | +| 外部模型服务 | 提供文本向量、问题重写、rerank 和回答生成能力 | + +## 5. 系统架构 + +```mermaid +flowchart LR + U["用户浏览器"] --> F["Vue 3 前端"] + F -->|"/api + JWT"| B["FastAPI 后端"] + + subgraph Backend["后端业务模块"] + A["认证与权限"] + K["知识库管理"] + D["文档处理"] + R["语义检索"] + G["RAG 生成"] + MM["知识地图"] + H["历史与反馈"] + end + + B --> A + B --> K + B --> D + B --> R + B --> G + B --> MM + B --> H + + A --> M[("MySQL")] + K --> M + D --> M + H --> M + D --> S[("原始文件")] + D --> C[("Chroma")] + R --> C + R --> E["Embedding / Rerank API"] + G --> L["在线 LLM API"] + MM --> L + MM --> M +``` + +系统将数据分为三类: + +- MySQL 保存结构化业务数据、用户归属和权限信息。 +- Chroma 保存片段向量、片段文本和检索 metadata。 +- 上传目录保存用户上传的原始文件。 + +这种划分使业务数据、向量数据和原始资料彼此独立,便于维护、备份和替换模型服务。 + +## 6. 功能模块 + +### 6.1 用户认证与权限 + +- 用户可以使用用户名、邮箱和密码注册。 +- 密码以哈希形式保存,不保存明文密码。 +- 登录成功后返回 JWT Access Token。 +- 前端通过 `Authorization: Bearer ` 访问受保护接口。 +- 后端根据 Token 中的用户身份校验知识库、文档和历史记录归属。 +- 用户只能访问自己的私人数据。 + +### 6.2 知识库管理 + +- 创建、查询、修改和删除知识库。 +- 保存知识库名称、描述、可见范围和所属用户。 +- 当前仅开放私人知识库。 +- 同一用户不能创建重名知识库。 +- 删除知识库时,同时清理关联文档、片段、向量和原始文件。 + +### 6.3 文档上传与处理 + +- 支持 PDF、DOCX、Markdown 和 TXT。 +- 校验文件类型、文件名、文件大小和空文件。 +- 保存原始文件并在 MySQL 中创建文档记录。 +- 记录 `pending`、`processing`、`completed`、`failed` 处理状态。 +- 提取文本并按自然边界切分片段。 +- 调用 Embedding API 生成片段向量。 +- 将片段写入 MySQL,将向量及 metadata 写入 Chroma。 +- 支持重新构建文档索引和删除文档。 + +### 6.4 语义检索 + +- 将用户问题转换为向量。 +- 按 `owner_id` 和 `knowledge_base_id` 限定检索范围。 +- 使用 Chroma 进行余弦相似度召回。 +- 支持 `top_k`、相似度阈值、问题重写和 rerank 参数。 +- 返回文档、片段、页码、相关度、原文和跳转地址。 + +相似度阈值与 Embedding 模型和切分粒度密切相关。更换模型后应使用项目测试集重新评估阈值,不能直接沿用旧模型参数。 + +### 6.5 RAG 问答 + +- 获取检索侧返回的候选来源。 +- 将原始问题、重写问题和来源片段组装为 Prompt。 +- 限制单条来源和总上下文长度。 +- 要求模型只依据知识库资料回答。 +- 要求关键结论使用 `[来源N]` 标注。 +- 清理不存在或格式错误的引用编号。 +- 没有足够资料时,明确返回“知识库中未找到足够依据”。 +- 对模型认证、限流、超时和服务异常返回明确错误。 + +### 6.6 来源引用与原文跳转 + +每条来源至少包括: + +| 字段 | 说明 | +| --- | --- | +| `document_id` | 来源文档编号 | +| `chunk_id` | 来源片段编号 | +| `file_name` | 文件名 | +| `chunk_index` | 片段在文档中的顺序 | +| `page_no` | 页码,无法识别时为空 | +| `score` | 语义相似度或综合排序分数 | +| `source_text` | 作为回答依据的片段快照 | +| `jump_url` | 文档片段查看地址 | + +用户可以从回答来源打开对应文档片段,核对回答依据。 + +### 6.7 问答历史与反馈 + +- 保存用户问题、重写问题、回答、来源数量和创建时间。 +- 保存来源顺序、分数和片段快照。 +- 支持按知识库查询历史列表。 +- 支持查看单条历史记录及其来源。 +- 删除原文后仍保留来源文件名、位置和文本快照,失效跳转会隐藏。 +- 问答历史前端列表和详情页已经完成。 +- 反馈目标为支持 1 至 5 分评分和文字评价;当前反馈接口仅返回演示数据,尚未持久化。 + +### 6.8 知识地图 + +- 可选择整个知识库或单个已完成解析的文档生成地图。 +- 后端以后台任务执行,记录排队、读取、分批提炼、合并、校验和组装进度。 +- 分批分析共享并发限制,失败时取消剩余模型请求。 +- 节点分为总览、章节、概念和细节,可包含摘要、关键记忆点、学习建议和真实来源。 +- 支持针对节点来源提问,以及根据来源扩展子节点。 +- 自动生成后保存历史,用户也可以新建、更新、打开和删除地图版本。 +- 前端支持学习概览、知识层级、叶子节点、原文覆盖率、本机掌握进度和继续学习入口。 +- 画布支持搜索定位、知识路径、缩放、适应画布、重新布局、撤销重做、位置锁定、分支折叠和全屏。 +- 支持导出 PNG、SVG、JSON 和包含记忆点、学习建议的 Markdown 大纲。 + +最近合并的 PR #11 增加了 `node_type`、`key_points` 和 `learning_tip`。这些字段保存在地图历史 JSON 中并提供默认值,旧历史不需要数据库迁移即可读取。 + +## 7. 核心业务流程 + +### 7.1 文档入库流程 + +```mermaid +sequenceDiagram + actor User as 用户 + participant Web as Vue 前端 + participant API as FastAPI + participant File as 文件存储 + participant DB as MySQL + participant Embed as Embedding API + participant Vector as Chroma + + User->>Web: 选择知识库并上传文档 + Web->>API: POST /api/documents/upload + API->>File: 保存原始文件 + API->>DB: 创建 pending 文档记录 + API-->>Web: 返回文档编号和处理状态 + API->>DB: 更新为 processing + API->>File: 读取并解析文档 + API->>API: 文本切分并生成 metadata + API->>Embed: 批量生成向量 + Embed-->>API: 返回片段向量 + API->>DB: 保存 document_chunks + API->>Vector: 写入向量、文本和 metadata + API->>DB: 更新为 completed +``` + +任一步骤失败时,系统应回滚可回滚的数据、清理已写入向量,并将文档状态更新为 `failed`。 + +### 7.2 RAG 问答流程 + +```mermaid +sequenceDiagram + actor User as 用户 + participant Web as Vue 前端 + participant API as FastAPI + participant Retrieve as 检索服务 + participant Vector as Chroma + participant LLM as 在线 LLM + participant DB as MySQL + + User->>Web: 输入问题 + Web->>API: POST /api/chat + API->>API: 校验 JWT 和知识库归属 + API->>Retrieve: 问题重写、向量化和召回 + Retrieve->>Vector: topK 相似度检索 + Vector-->>Retrieve: 返回候选片段 + Retrieve->>Retrieve: 阈值过滤和 rerank + Retrieve-->>API: 返回来源列表 + alt 找到有效来源 + API->>API: 组装问题、来源和引用规则 + API->>LLM: 请求生成回答 + LLM-->>API: 返回回答文本 + API->>API: 清理和校验引用编号 + else 没有有效来源 + API->>API: 生成资料依据不足提示 + end + API->>DB: 保存问答记录和来源快照 + API-->>Web: 返回回答、来源和历史记录编号 +``` + +### 7.3 知识地图生成流程 + +```mermaid +sequenceDiagram + actor User as 用户 + participant Web as Vue 前端 + participant API as FastAPI + participant Job as 地图任务服务 + participant LLM as 在线 LLM + participant DB as MySQL + + User->>Web: 选择知识库、范围和深度 + Web->>API: POST /api/mind-maps/jobs + API->>DB: 创建 queued 任务 + API-->>Web: 返回 job_id + Job->>DB: 读取已完成解析的片段 + Job->>LLM: 并发受限的分批提炼 + LLM-->>Job: 返回主题与真实来源编号 + Job->>LLM: 合并学习层次 JSON + Job->>Job: 校验节点、深度、数量和来源 + Job->>DB: 保存地图历史与任务结果 + loop 逐步降频轮询 + Web->>API: GET /api/mind-maps/jobs/{job_id} + API-->>Web: 返回阶段、进度或结果 + end +``` + +## 8. 数据库设计 + +### 8.1 数据关系 + +```mermaid +erDiagram + USERS ||--o{ KNOWLEDGE_BASES : owns + USERS ||--o{ DOCUMENTS : uploads + USERS ||--o{ QA_RECORDS : asks + USERS ||--o{ FEEDBACKS : submits + KNOWLEDGE_BASES ||--o{ DOCUMENTS : contains + KNOWLEDGE_BASES ||--o{ DOCUMENT_CHUNKS : groups + KNOWLEDGE_BASES ||--o{ QA_RECORDS : scopes + DOCUMENTS ||--o{ DOCUMENT_CHUNKS : splits + QA_RECORDS ||--o{ QA_SOURCES : cites + QA_RECORDS ||--o{ FEEDBACKS : receives + DOCUMENTS ||--o{ QA_SOURCES : referenced_by + DOCUMENT_CHUNKS ||--o{ QA_SOURCES : referenced_by + USERS ||--o{ MIND_MAP_HISTORIES : owns + USERS ||--o{ MIND_MAP_JOBS : starts + KNOWLEDGE_BASES ||--o{ MIND_MAP_HISTORIES : scopes + KNOWLEDGE_BASES ||--o{ MIND_MAP_JOBS : scopes +``` + +### 8.2 主要数据表 + +| 表名 | 用途 | +| --- | --- | +| `users` | 用户名、邮箱、密码哈希、角色和状态 | +| `knowledge_bases` | 知识库名称、描述、范围和用户归属 | +| `documents` | 文件信息、存储路径、处理状态和片段数量 | +| `document_chunks` | 片段文本、位置、页码和 Chroma `vector_id` | +| `qa_records` | 问题、重写问题、回答和来源数量 | +| `qa_sources` | 回答引用的片段、顺序、分数和文本快照 | +| `feedbacks` | 用户评分和文字反馈 | +| `mind_map_histories` | 地图结果 JSON、标题、节点数和画布状态 | +| `mind_map_jobs` | 生成任务状态、阶段、进度、结果和失败原因 | + +### 8.3 Chroma metadata + +每条向量至少保存: + +- `owner_id` +- `knowledge_base_id` +- `document_id` +- `chunk_id` +- `chunk_index` +- `file_name` +- `page_no` +- `start_offset` +- `end_offset` + +`document_chunks.vector_id` 与 Chroma 向量编号一一对应,用于结构化数据和向量数据之间的关联。 + +## 9. API 概览 + +除健康检查、注册和登录外,受保护接口都需要 JWT Bearer Token。 + +| 模块 | 方法与路径 | 说明 | 当前状态 | +| --- | --- | --- | --- | +| 健康检查 | `GET /api/health` | 检查后端状态 | 已实现 | +| 认证 | `POST /api/auth/register` | 注册用户 | 已实现 | +| 认证 | `POST /api/auth/login` | 登录并获取 Token | 已实现 | +| 认证 | `GET /api/auth/me` | 获取当前用户 | 已实现 | +| 知识库 | `GET /api/knowledge-bases` | 查询个人知识库 | 已实现 | +| 知识库 | `POST /api/knowledge-bases` | 创建知识库 | 已实现 | +| 知识库 | `PATCH /api/knowledge-bases/{id}` | 修改知识库 | 已实现 | +| 知识库 | `DELETE /api/knowledge-bases/{id}` | 删除知识库及关联数据 | 已实现 | +| 文档 | `POST /api/documents/upload` | 上传并处理文档 | 已实现 | +| 文档 | `GET /api/documents` | 查询文档列表 | 已实现 | +| 文档 | `GET /api/documents/{id}` | 查询文档详情 | 已实现 | +| 文档 | `DELETE /api/documents/{id}` | 删除文档、向量和文件 | 已实现 | +| 文档 | `POST /api/documents/{id}/reindex` | 重建文档索引 | 已实现 | +| 文档 | `GET /api/documents/{id}/chunks` | 查询文档片段 | 已实现 | +| 检索 | `POST /api/search` | 直接语义检索 | 已实现 | +| 问答 | `POST /api/chat` | RAG 问答 | 已实现 | +| 历史 | `GET /api/qa-records` | 查询问答历史 | 已实现 | +| 历史 | `GET /api/qa-records/{id}` | 查询历史详情 | 已实现 | +| 知识地图 | `POST /api/mind-maps/jobs` | 创建后台生成任务 | 已实现 | +| 知识地图 | `GET /api/mind-maps/jobs/{id}` | 查询任务进度和结果 | 已实现 | +| 知识地图 | `POST /api/mind-maps/ask` | 节点追问 | 已实现 | +| 知识地图 | `POST /api/mind-maps/expand` | 节点扩展 | 已实现 | +| 知识地图 | `/api/mind-maps/histories` | 地图历史增删改查 | 已实现 | +| 反馈 | `POST /api/qa-records/{id}/feedback` | 返回演示反馈,未持久化 | 演示接口 | +| 管理 | `GET /api/admin/feedbacks` | 当前返回空列表 | 待实现 | + +完整交互文档可在后端运行后访问:`http://localhost:8000/docs`。 + +## 10. 安全设计 + +- 用户密码只保存哈希值。 +- 使用 JWT 校验登录身份。 +- 知识库、文档、片段和历史查询都校验用户归属。 +- 上传文件限制扩展名、文件大小并处理危险文件名字符。 +- API Key、JWT Secret 和数据库密码通过环境变量配置。 +- 前端代码、Git 仓库、Wiki、截图和演示视频中不得出现真实密钥。 +- 知识库片段被视为不可信数据,Prompt 明确禁止执行片段中的指令。 +- 模型返回的来源编号需要经过后端校验和清理。 + +## 11. 本地部署 + +### 11.1 准备环境变量 + +在仓库根目录执行: + +```bash +cp .env.example .env +cp .env.example backend/.env +``` + +Windows PowerShell: + +```powershell +Copy-Item .env.example .env +Copy-Item .env.example backend/.env +``` + +Docker Compose 使用根目录 `.env` 做变量替换,后端容器读取 `backend/.env`。两份文件中的 `MYSQL_PASSWORD` 必须保持一致;模型、JWT 等后端配置填写在 `backend/.env`: + +```dotenv +MYSQL_HOST=mysql +MYSQL_PORT=3306 +MYSQL_USER=root +MYSQL_PASSWORD=replace_with_database_password +MYSQL_DATABASE=codemind + +LLM_API_KEY=replace_with_llm_key +LLM_BASE_URL=https://provider.example.com/v1 +LLM_MODEL=replace_with_chat_model + +EMBEDDING_API_KEY=replace_with_embedding_key +EMBEDDING_BASE_URL=https://provider.example.com/v1 +EMBEDDING_MODEL=replace_with_embedding_model + +JWT_SECRET_KEY=replace_with_a_long_random_secret +JWT_ALGORITHM=HS256 +JWT_EXPIRE_MINUTES=180 +``` + +不要将 `.env`、`backend/.env`、API Key、JWT Secret 或数据库密码提交到 Git。 + +### 11.2 启动服务 + +```bash +docker compose up -d --build +docker compose ps +``` + +默认访问地址: + +| 服务 | 地址 | +| --- | --- | +| 前端 | `http://localhost:8080` | +| 后端 API | `http://localhost:8000` | +| Swagger | `http://localhost:8000/docs` | +| MySQL | `localhost:3306` | + +### 11.3 查看日志 + +```bash +docker compose logs -f backend +docker compose logs -f frontend +docker compose logs -f mysql +``` + +### 11.4 停止服务 + +```bash +docker compose down +``` + +普通停止不会删除 MySQL、上传文件和 Chroma 数据卷。只有明确需要清空数据时才可执行带 `-v` 的删除命令。 + +## 12. 测试与验收 + +### 12.1 自动化测试 + +后端测试覆盖: + +- 应用启动和健康检查。 +- 注册、登录、密码哈希和 JWT。 +- 文档处理和失败回滚。 +- 文档、向量和知识库删除。 +- Prompt 组装和引用编号清理。 +- LLM 错误转换。 +- RAG 有来源和无来源流程。 +- 问答历史保存、查询、事务回滚和用户隔离。 +- 删除文档后来源快照保留。 +- 知识地图生成、来源校验、并发限制和失败取消。 +- 知识地图任务、历史事务和文档归属校验。 + +当前后端自动化测试基线为 53 项。 + +### 12.2 核心验收流程 + +1. 注册并登录用户。 +2. 创建私人知识库。 +3. 上传测试文档。 +4. 等待文档状态变为 `completed`。 +5. 查询文档片段并验证片段数量。 +6. 使用资料中的问题进行语义检索。 +7. 提交 RAG 问题并检查回答和来源。 +8. 点击来源跳转到对应文档片段。 +9. 查看问答历史及来源快照。 +10. 生成知识地图并观察任务进度、节点来源、关键记忆点和学习建议。 +11. 测试节点搜索、追问、扩展、历史保存和导出。 +12. 删除文档或知识库,检查 MySQL、Chroma、文件和历史快照行为。 +13. 使用另一个用户验证资源不能被越权访问。 + +### 12.3 回答质量评估 + +建议建立固定测试集,至少包含: + +- 资料中可以直接回答的问题。 +- 需要多个片段综合回答的问题。 +- 表述不同但语义相同的问题。 +- 资料中不存在答案的问题。 +- 可能诱导模型脱离资料回答的问题。 +- 文档中包含提示词注入内容的问题。 + +评估指标包括检索召回率、来源匹配度、回答正确性、拒答合理性和响应时间。 + +## 13. 非功能性要求 + +### 13.1 性能 + +- 普通业务查询应保持较短响应时间。 +- 文档处理使用状态字段反馈进度,避免用户误判。 +- 模型调用设置超时、有限重试和明确错误提示。 +- 实训规模下应支持多用户资料管理和连续问答测试。 + +### 13.2 可维护性 + +- 前后端请求字段、数据库字段和文档保持一致。 +- MySQL、Chroma、文件存储和模型服务职责清晰。 +- 模型、阈值和 Prompt 参数应集中管理。 +- 数据库结构更新需要迁移脚本,不能只修改初始化建表文件。 + +### 13.3 可追溯性 + +- 回答返回真实来源,不生成不存在的来源编号。 +- 历史记录保存来源片段快照。 +- 原文仍存在时支持跳转核对。 +- 原文被删除后仍应保留历史快照,并明确标记原文不可用。 + +## 14. 当前进度与后续计划 + +### 14.1 已完成 + +- 前后端基础工程和 Docker Compose 部署。 +- JWT 注册、登录和资源权限校验。 +- 知识库及文档管理。 +- PDF、DOCX、Markdown、TXT 解析和切分。 +- Embedding 与 Chroma 入库。 +- 问题重写、相似度过滤和 rerank 流程。 +- RAG Prompt、在线 LLM 调用和来源引用。 +- 问答历史后端保存及查询。 +- 问答历史前端页面和删除原文后的来源快照。 +- 文档和知识库删除业务。 +- 知识地图异步任务、历史版本、节点追问和节点扩展。 +- 知识地图学习层次、记忆点、学习建议、掌握进度、搜索导航和导出。 + +### 14.2 待完成或待优化 + +- 使用固定测试集重新评估相似度阈值。 +- 完成反馈持久化和管理员反馈查询。 +- 增加真实 MySQL、Chroma 和在线模型端到端测试及质量评估记录。 +- 优化前端构建包体积。 +- 完成项目报告、PPT、演示视频和部署文档。 + +## 15. 小组分工 + +| 方向 | 负责人 | 主要职责 | +| --- | --- | --- | +| 前端与数据库设计 | 李翰坤 | Vue 页面、交互、路由、接口对接、MySQL 表结构和 Chroma metadata | +| 后端入库流程 | 龚仕豪 | 文件上传、解析、切分、Embedding、向量入库和处理状态 | +| 提问流程检索侧 | 李竺桓 | 问题重写、问题向量化、topK 检索、阈值过滤和 rerank | +| 提问流程生成侧 | 王瀚铖 | 上下文组装、Prompt、LLM 回答、来源引用和问答历史 | +| 用户、文档访问与整合测试 | 邓智元 | 注册登录、权限、直接搜索、引用跳转和接口联调 | + +模块负责人负责本模块实现和测试,同时需要共同完成接口联调、部署、文档和最终答辩。 + +## 16. 仓库导航 + +- [项目仓库](https://github.com/Attacker687/CodeMind) +- [后端代码](https://github.com/Attacker687/CodeMind/tree/main/backend) +- [前端代码](https://github.com/Attacker687/CodeMind/tree/main/frontend) +- [数据库结构](https://github.com/Attacker687/CodeMind/blob/main/database/schema.sql) +- [需求分析](https://github.com/Attacker687/CodeMind/blob/main/docs/%E9%9C%80%E6%B1%82%E5%88%86%E6%9E%90.md) +- [API 接口设计](https://github.com/Attacker687/CodeMind/blob/main/docs/API%E6%8E%A5%E5%8F%A3%E8%AE%BE%E8%AE%A1.md) +- [生成侧接口约定](https://github.com/Attacker687/CodeMind/blob/main/docs/%E7%94%9F%E6%88%90%E4%BE%A7%E6%8E%A5%E5%8F%A3%E7%BA%A6%E5%AE%9A.md) +- [文档导航与实现状态](https://github.com/Attacker687/CodeMind/blob/main/docs/README.md) + +## 17. 文档维护约定 + +- 功能、接口或数据库发生变化时,同步更新 Wiki。 +- 已实现和规划中的功能必须明确区分。 +- 不在 Wiki 中粘贴密码、Token、API Key 或完整 `.env`。 +- 测试结果应注明测试日期、代码提交和模型配置。 +- 重要架构决策通过 GitHub Issue 讨论并保留记录。 + +--- + +最后更新:2026 年 7 月 13 日;实现基线:`main` 提交 `839890b`(合并 PR #11)。 diff --git "a/docs/\347\224\237\346\210\220\344\276\247\346\216\245\345\217\243\347\272\246\345\256\232.md" "b/docs/\347\224\237\346\210\220\344\276\247\346\216\245\345\217\243\347\272\246\345\256\232.md" index 7ca20de..ab834fe 100644 --- "a/docs/\347\224\237\346\210\220\344\276\247\346\216\245\345\217\243\347\272\246\345\256\232.md" +++ "b/docs/\347\224\237\346\210\220\344\276\247\346\216\245\345\217\243\347\272\246\345\256\232.md" @@ -1,26 +1,32 @@ # CodeMind 生成侧接口约定 -负责人:王瀚铖 +本文档描述 RAG 生成侧与检索侧、历史服务和知识地图 LLM 能力之间的当前约定。实现基线:`main` 提交 `839890b`,更新时间 2026-07-13。 -## 1. 职责边界 +## 1. RAG 生成侧职责 -生成侧负责 `/api/chat` 的后半段流程: +`POST /api/chat` 的完整链路为: ```text -接收用户问题 -→ 调用检索侧获得 rewritten_question 和 sources -→ 组装 RAG Prompt -→ 调用在线 LLM API 或本地降级生成 -→ 组织回答与来源引用 -→ 保存问答历史 -→ 返回 ChatResponse 给前端 +JWT 用户与知识库归属校验 +→ 检索侧返回 rewritten_question、sources 和空结果原因 +→ 生成侧组装受长度限制的 RAG Prompt +→ 调用在线 LLM 或本地演示回答 +→ 校验和清理来源编号 +→ 在同一事务保存问答记录与来源快照 +→ 返回 ChatResponse ``` -生成侧不负责文档上传、解析、切分、Embedding 入库和 Chroma 检索实现。 +生成侧不负责上传、解析、切分、Embedding 入库和 Chroma 查询实现,但依赖检索侧提供结构稳定、用户隔离正确的来源数据。 -## 2. 前端调用 `/api/chat` +## 2. HTTP 契约 -请求: +请求需要 JWT: + +```http +POST /api/chat +Authorization: Bearer +Content-Type: application/json +``` ```json { @@ -34,14 +40,6 @@ } ``` -临时用户身份: - -```text -X-User-Id: 1 -``` - -正式登录完成后,`X-User-Id` 应替换为 JWT 鉴权得到的当前用户编号。 - 响应: ```json @@ -50,7 +48,7 @@ X-User-Id: 1 "knowledge_base_id": 1, "question": "操作系统中的进程和线程有什么区别?", "rewritten_question": "操作系统中进程与线程的区别是什么?", - "answer": "进程负责资源分配,线程负责 CPU 调度。 [来源1]", + "answer": "进程拥有独立地址空间,线程共享进程资源。[来源1]", "sources": [ { "document_id": 1, @@ -66,83 +64,127 @@ X-User-Id: 1 } ``` -## 3. 李竺桓检索侧需要提供的接口 - -代码位置: +临时 `X-User-Id` 已废弃,调用方不得再发送或依赖该请求头。 -```text -backend/app/services/retrieval_service.py -``` +## 3. 检索侧契约 -约定方法: +实现位置:`backend/app/services/retrieval_service.py`。 ```python -async def retrieve_for_chat(request: ChatRequest, user_id: int = 1) -> RetrievalResult: +async def retrieve_for_chat(request: ChatRequest, user_id: int) -> RetrievalResult: ... ``` -返回类型: +`RetrievalResult` 至少提供: -```python -class RetrievalResult(BaseModel): - rewritten_question: str | None = None - sources: list[SourceReference] = [] -``` - -`sources` 每个元素必须符合 `SourceReference`: - -```python -class SourceReference(BaseModel): - document_id: int - chunk_id: int - file_name: str - chunk_index: int - page_no: int | None = None - score: float | None = None - source_text: str - jump_url: str -``` +- `rewritten_question: str | None` +- `sources: list[SourceReference]` +- `empty_reason: str | None` +- `empty_message: str | None` -字段要求: +`SourceReference` 字段: -| 字段 | 说明 | +| 字段 | 约定 | | --- | --- | | `document_id` | MySQL `documents.id` | | `chunk_id` | MySQL `document_chunks.id` | -| `file_name` | 来源文件名 | -| `chunk_index` | 文档内片段序号 | -| `page_no` | 页码或位置,没有可传 `null` | -| `score` | Chroma 相似度或 rerank 分数 | -| `source_text` | 片段文本快照,用于 Prompt 和历史来源 | -| `jump_url` | 前端点击来源时跳转的路径,例如 `/documents/1/chunks/10` | +| `file_name` | 用户可识别的来源文件名 | +| `chunk_index` | 文档内从 0 开始的片段序号 | +| `page_no` | 页码或 `null` | +| `score` | 相似度或 rerank 分数 | +| `source_text` | 进入 Prompt 并写入历史的文本快照 | +| `jump_url` | `/documents/{document_id}/chunks/{chunk_id}` | -## 4. 生成侧内部模块 +检索必须同时按 `owner_id` 和 `knowledge_base_id` 隔离。Embedding 服务、Chroma 或模型重写不可用时,应抛出带 HTTP 状态语义的 `RetrievalServiceError`,不能返回伪造向量或伪造来源。 -| 文件 | 职责 | -| --- | --- | -| `backend/app/services/rag_service.py` | 串联检索、Prompt、LLM、历史保存 | -| `backend/app/services/prompt_builder.py` | 组装 RAG Prompt | -| `backend/app/services/llm_client.py` | 调用在线 LLM API,管理超时、重试和服务异常;未配置 API 时返回本地演示回答 | -| `backend/app/services/qa_history_service.py` | 使用 MySQL 事务保存 `qa_records` 与 `qa_sources`,并提供历史列表和详情查询 | -| `backend/app/services/retrieval_service.py` | 使用 Embedding 与 Chroma 检索,并按用户、知识库、阈值和 rerank 规则组织来源 | +## 4. Prompt 与回答规则 -## 5. 当前实现状态 +实现位置:`backend/app/services/prompt_builder.py`。 -当前实现已完成 `/api/chat` 的生成侧闭环: +- 来源按 `[来源1]`、`[来源2]` 编号。 +- 单条来源和总上下文都有字符预算,避免 Prompt 无限制增长。 +- 文档片段属于不可信数据,Prompt 明确禁止执行片段内指令。 +- 模型只能根据提供的资料回答;依据不足时必须明确说明。 +- 输出后清理不存在、残缺或超出范围的来源编号。 +- 模型未主动给出引用时,系统追加有效参考资料列表。 +- 重复尾部和不完整引用会在返回前清理。 -- 有匹配片段时,组装受长度限制的 RAG Prompt,并返回可跳转来源。 -- 没有匹配片段时,返回“知识库中未找到足够依据”。 -- 未配置在线 LLM API 时,使用本地演示回答;已配置但服务异常时返回明确的 502/503 错误。 -- 回答中的无效或残缺来源编号会被清理;模型未给出引用时追加有效参考资料列表。 -- 问答记录和来源快照在同一 MySQL 事务中写入 `qa_records` 与 `qa_sources`。 -- `GET /api/qa-records` 支持按当前用户和知识库查询历史列表。 -- `GET /api/qa-records/{qa_record_id}` 返回完整回答和历史来源快照。 +## 5. LLM 错误与降级 -在线 LLM 可通过以下环境变量控制: +实现位置:`backend/app/services/llm_client.py`。 -```text +| 场景 | 当前行为 | +| --- | --- | +| 未配置 `LLM_API_KEY` 或 `LLM_MODEL` | 普通 RAG 返回基于检索片段的本地演示回答 | +| API Key 无效 | 转换为明确的 502 错误 | +| 限流、网络或超时 | 返回 503 语义的可重试错误 | +| 服务端异常或空回答 | 返回 502 | + +可配置项: + +```dotenv LLM_TIMEOUT_SECONDS=45 LLM_MAX_RETRIES=1 LLM_MAX_TOKENS=600 ``` +知识地图不使用普通 RAG 的本地演示降级;缺少在线 LLM 配置时直接返回 `503`。 + +## 6. 问答历史契约 + +实现位置:`backend/app/services/qa_history_service.py`。 + +- `qa_records` 与 `qa_sources` 在同一事务写入,任一来源失败时整体回滚。 +- 保存文件名、片段序号、页码、分数和 `source_text` 快照。 +- 删除文档时,`qa_sources.document_id` 和 `chunk_id` 置空,快照继续保留。 +- 历史详情中的失效来源 `jump_url=null`,前端不应再提供原文跳转。 +- `GET /api/qa-records` 按当前 JWT 用户查询列表,可按知识库过滤。 +- `GET /api/qa-records/{id}` 返回完整来源快照,并校验用户归属。 + +## 7. 知识地图 LLM 边界 + +知识地图也使用 `LlmClient`,但由 `mind_map_service.py` 单独组织结构化 Prompt: + +```text +读取已完成解析的片段 +→ 采样并按每 3 条片段分批提炼 +→ 合并为层次化 JSON +→ 校验节点、深度、数量和真实来源编号 +→ 保存历史版本 +``` + +当前结构约定: + +- 节点类型为 `overview`、`chapter`、`concept` 或 `detail`。 +- `key_points` 最多 3 条,`learning_tip` 为具体学习动作。 +- 非根节点优先绑定真实来源;未知 `chunk_id` 被丢弃。 +- 生成、节点提问和节点扩展共享服务级并发限制 3。 +- 某一批失败时取消未完成请求,避免失败后继续消耗 API。 +- 后台任务记录阶段、进度、结果和错误;前端通过轮询恢复任务。 +- 节点学习字段保存在 `mind_map_histories.result_json`,无需新增数据库列,旧 JSON 通过默认值兼容。 + +相关接口: + +| 接口 | 用途 | +| --- | --- | +| `POST /api/mind-maps/jobs` | 创建后台生成任务 | +| `GET /api/mind-maps/jobs/{job_id}` | 查询进度和结果 | +| `POST /api/mind-maps/ask` | 使用节点来源回答问题 | +| `POST /api/mind-maps/expand` | 使用节点来源扩展子结构 | +| `/api/mind-maps/histories` | 管理历史版本 | + +## 8. 当前实现状态 + +已完成: + +- RAG 有来源、无来源、检索异常和 LLM 异常闭环。 +- 来源编号校验、Prompt 注入防护和上下文预算。 +- 问答历史事务保存和删除原文后的来源快照。 +- 问答历史前端列表、详情和原文可用性展示。 +- 知识地图异步生成、历史、追问、扩展和学习节点结构。 + +仍需完善: + +- 基于真实在线模型的固定测试集和质量评估。 +- 模型耗时、Token 消耗和错误率的持续记录。 +- 反馈持久化和管理员反馈页面。 diff --git "a/docs/\351\234\200\346\261\202\345\210\206\346\236\220.md" "b/docs/\351\234\200\346\261\202\345\210\206\346\236\220.md" index 9bac4e1..ccb7744 100644 --- "a/docs/\351\234\200\346\261\202\345\210\206\346\236\220.md" +++ "b/docs/\351\234\200\346\261\202\345\210\206\346\236\220.md" @@ -2,16 +2,16 @@ ## 1. 项目定位 -CodeMind 是面向计算机知识学习场景的 RAG 知识库问答系统。系统支持用户上传课程资料、实验文档、技术文档等计算机相关内容,经过文本解析、切分、Embedding 向量化和 Chroma 入库后,用户可以通过自然语言提问或直接检索查看文档片段,并获得带来源依据的回答。 +CodeMind 是面向计算机知识学习场景的 RAG 知识库系统。系统支持用户上传课程资料、实验文档和技术文档,经过文本解析、切分、Embedding 向量化和 Chroma 入库后,用户可以进行语义检索、获得带来源依据的回答,并把资料整理为可追溯的知识地图。 -系统采用前后端分离结构:前端负责登录、文档管理、问答、历史和反馈等交互;后端负责认证、文档处理、知识库管理、语义检索、RAG 问答和业务数据管理;MySQL 保存结构化业务数据,Chroma 保存文本片段向量和检索元数据,原始文件保存在本地 `storage/uploads` 目录。 +系统采用前后端分离结构:前端负责登录、文档管理、问答、历史和知识地图交互;后端负责认证、文档处理、知识库管理、语义检索、RAG 问答、知识地图任务和业务数据管理;MySQL 保存结构化业务数据,Chroma 保存文本片段向量和检索元数据,原始文件保存在上传目录或 Docker 命名卷中。 ## 2. 用户角色 | 角色 | 说明 | 主要操作 | | --- | --- | --- | -| 普通用户 | 使用系统管理学习资料并进行知识问答的学习者 | 注册登录、创建知识库、上传文档、查看处理状态、直接检索文档、RAG 提问、查看来源引用、查看历史、提交反馈 | -| 管理员 | 维护系统用户、文档状态和反馈数据的管理者 | 用户状态维护、文档异常处理、反馈查看、测试评估结果查看 | +| 普通用户 | 使用系统管理学习资料并进行知识问答的学习者 | 注册登录、创建知识库、上传文档、检索与提问、核对来源、查看历史、生成和学习知识地图 | +| 管理员 | 维护系统用户、异常和反馈数据的管理者 | 用户状态维护、文档异常处理、反馈查看、测试评估结果查看;部分管理能力仍属规划 | | 外部模型服务 | 在线 LLM API 与 Embedding API | 接收后端请求,返回文本向量或回答内容 | ## 3. 功能需求 @@ -76,12 +76,26 @@ CodeMind 是面向计算机知识学习场景的 RAG 知识库问答系统。系 - 系统保存用户问题、重写问题、回答、来源数量、创建时间和来源引用。 - 用户可以按知识库查看历史问答列表。 - 用户可以进入某条问答记录查看完整回答和引用来源。 +- 删除原文后,历史记录仍需保留文件名、片段序号、页码和文本快照;失效的原文跳转应置空。 -### 3.9 用户反馈与测试评估 +### 3.9 知识地图 + +- 用户可以选择整个知识库或单个已完成解析的文档生成知识地图。 +- 生成过程以后台任务执行,并返回排队、读取资料、整理上下文、分批提炼、合并结构、校验来源和组装画布等进度。 +- 系统应限制同一后端实例对 LLM 的并发调用;某批调用失败时取消其余调用,避免继续消耗 API。 +- 地图节点分为 `overview`、`chapter`、`concept` 和 `detail`,可包含摘要、1 至 3 条关键记忆点、学习建议、来源和子节点。 +- 节点引用的片段必须属于当前用户和知识库,模型返回的未知片段编号必须丢弃。 +- 用户可以针对节点来源提问,也可以让 AI 根据节点来源扩展子节点。 +- 用户可以创建、打开、更新和删除地图历史版本,系统保存地图 JSON 和画布状态。 +- 前端应支持节点搜索、路径导航、相关资料检索、画布缩放与布局、分支折叠、全屏和多格式导出。 +- 前端可在浏览器本机记录节点掌握状态,并显示掌握进度和继续学习入口;该状态不作为跨设备同步数据。 + +### 3.10 用户反馈与测试评估 - 用户可以对某条回答提交 1 到 5 分评分和文字反馈。 - 同一用户对同一条回答只能提交一次反馈。 - 管理员或测试人员可查看反馈数据,用于评估回答准确性、来源匹配度和检索质量。 +- 当前反馈路由仅提供演示响应,持久化和管理查询仍需实现,不能作为已完成能力验收。 ## 4. 数据需求 @@ -98,6 +112,8 @@ MySQL 保存结构化业务数据,建表脚本位于 `database/schema.sql`, | `qa_records` | 用户问题、重写问题、回答和来源数量 | | `qa_sources` | 回答引用的来源片段快照、排序和相似度 | | `feedbacks` | 用户对回答的评分和文字反馈 | +| `mind_map_histories` | 知识地图结果 JSON、标题、节点数和画布状态 | +| `mind_map_jobs` | 地图后台任务、阶段、进度、结果和失败原因 | ### 4.2 Chroma metadata @@ -123,3 +139,24 @@ Chroma 每条向量记录应至少保存以下 metadata: - 性能要求:普通业务查询应保持较短响应时间;实训规模下语义检索应在合理时间内返回候选片段。 - 可维护性:MySQL、Chroma、原始文件和外部模型服务职责清晰,后续可替换模型服务或优化检索策略。 - 一致性:API 字段命名、后端请求/响应模型和数据库字段应保持一致,避免历史记录模型出现多套并存。 +- 兼容性:知识地图新增节点字段必须提供默认值,使旧历史 JSON 可以继续读取。 +- 并发控制:知识地图分批分析和节点操作共享 LLM 并发限制,避免多个任务叠加压垮模型服务。 +- 可恢复性:前端切换页面后可以恢复未完成的知识地图任务,并忽略旧任务迟到的轮询响应。 +- 可观测性:后台处理失败原因应写入文档或任务记录,并能通过接口和日志定位。 + +## 6. 当前实现状态 + +截至 `main` 提交 `839890b`(2026-07-13): + +| 能力 | 状态 | 说明 | +| --- | --- | --- | +| 用户认证与资源隔离 | 已实现 | JWT、密码哈希、知识库/文档/历史归属校验 | +| 知识库和文档管理 | 已实现 | 上传、后台处理、原文预览、片段、重建和删除 | +| Embedding 与 Chroma | 已实现 | 只使用在线 Embedding,不提供本地模拟向量 | +| 语义检索与 RAG 问答 | 已实现 | 重写、过滤、rerank、来源校验和历史保存 | +| 问答历史来源快照 | 已实现 | 删除文档后保留快照,原文跳转失效 | +| 知识地图基础闭环 | 已实现 | 后台任务、进度、历史、追问和扩展 | +| 知识地图学习体验 | 已实现 | 节点类型、记忆点、学习建议、掌握进度、搜索、导航和导出 | +| 反馈持久化与管理 | 未完成 | 当前接口返回演示数据或空列表 | +| 固定测试集与阈值评估 | 待推进 | 需要真实模型和标注数据 | +| 完整端到端验收 | 待完善 | 当前后端自动化测试基线为 53 项 | diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..d091e45 --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,75 @@ +# CodeMind Frontend + +Vue 3 前端提供认证、知识库管理、文档处理、RAG 问答、问答历史和知识地图界面。 + +## 技术栈 + +- Vue 3 与 Vue Router +- Vite +- Element Plus +- Axios +- AntV G6 知识地图画布 +- Mammoth、Marked 与 DOMPurify 文档预览 + +## 页面路由 + +| 路径 | 页面 | 说明 | +| --- | --- | --- | +| `/` | `HomeView` | RAG 问答和来源展示 | +| `/documents` | `DocumentUploadView` | 上传、进度和处理状态 | +| `/library` | `DocumentLibraryView` | 文档筛选、重建和删除 | +| `/documents/:id/view` | `DocumentViewerView` | 原始文档预览 | +| `/documents/:id/chunks/:chunkId` | `DocumentDetailView` | 片段查看和定位 | +| `/history` | `QaHistoryView` | 问答历史和来源快照 | +| `/mind-map` | `MindMapView` | 知识地图生成与学习 | +| `/me` | `MeView` | 用户和知识库管理 | +| `/login`、`/register` | 认证页面 | 登录和注册 | + +除首页和认证页面的公开外观外,业务路由通过用户 Store 和 JWT 状态保护;后端仍会独立校验所有资源归属。 + +## 本地开发 + +```bash +cd frontend +npm ci +npm run dev +``` + +默认开发地址为 `http://localhost:5173`。接口根地址由 `VITE_API_BASE_URL` 控制;Docker 前端通过 Nginx 将 `/api` 代理到后端。 + +生产构建: + +```bash +npm run build +``` + +当前构建可以完成,但 AntV G6、Element Plus 和文档预览相关产物仍会触发大于 500 kB 的 chunk 警告,后续可通过更细的动态导入和 `manualChunks` 优化。 + +## 知识地图交互 + +当前 `MindMapView` 与 `MindMapCanvas` 已支持: + +- 创建后台生成任务、显示阶段和逐步降频轮询。 +- 页面切换后恢复同一知识库中的未完成任务,并丢弃旧任务迟到响应。 +- 展示节点类型、摘要、关键记忆点、学习建议、知识路径和来源。 +- 节点相关资料检索、针对性提问和 AI 分支扩展。 +- 搜索标题、摘要和关键记忆点并定位节点。 +- 画布缩放、适应、重新布局、撤销重做、拖拽锁定、折叠和全屏。 +- 地图历史创建、更新、打开和删除。 +- PNG、SVG、JSON 和 Markdown 导出。 +- 使用 `localStorage` 保存本机节点掌握状态;该状态不会跨浏览器或设备同步。 + +知识地图正式生成流程调用 `/api/mind-maps/jobs` 和 `/api/mind-maps/jobs/{job_id}`。节点追问和扩展接口最长可等待 300 秒,前端请求超时设置为 6 分钟。 + +## 文档上传与预览 + +- 上传接口超时为 5 分钟,并通过 Axios 事件显示真实上传进度。 +- 若上传响应超时,先到文档库确认是否已创建记录,避免重复提交。 +- 状态轮询遇到临时网络错误会继续重试。 +- 原文预览通过受保护的 `/api/documents/{id}/content` 获取,不直接公开上传目录。 + +## 安全注意事项 + +- 不在前端环境变量中放置 LLM、Embedding、数据库或 JWT 签名密钥。 +- `VITE_` 变量会进入浏览器构建产物,只能用于公开配置。 +- 文档预览生成的 HTML 必须经过 DOMPurify 清理。