feat: add rag backend and review access fixes

This commit is contained in:
wren
2026-05-08 10:58:24 +08:00
parent 1c84209f38
commit 9c86bf59e5
32 changed files with 3877 additions and 23 deletions
+310
View File
@@ -0,0 +1,310 @@
# RAG 后端上线清单
适用范围:
- 仓库:`leaudit-platform`
- 本次上线内容:自有 RAG 聊天后端、`/api/v3/rag/*` 接口、`rag_*` 表结构、`rag:*` 权限
## 1. 上线前确认
- 代码已包含以下变更:
- `fastapi_modules/fastapi_leaudit/controllers/ragChatController.py`
- `fastapi_modules/fastapi_leaudit/services/impl/ragChatServiceImpl.py`
- `fastapi_modules/fastapi_leaudit/services/impl/ragDatasetServiceImpl.py`
- `scripts/schema_add_rag_chat.sql`
- `scripts/user_rbac_seed.sql`
- `pyproject.toml` 已加入 `chromadb`
- 发布分支已经合并到目标部署分支。
- 数据库备份已完成,至少备份:
- `permissions`
- `role_permissions`
- `role_route`
- `sys_routes`
- 全部 `rag_*`
## 2. 配置优先级
后端配置加载顺序见 `fastapi_admin/config/_loader.py`
1. `app.toml`
2. `app.{APP_ENV}.toml`
3. `app.ai.toml`
4. 已存在的环境变量
结论:
- 生产环境如果通过环境变量注入,优先级最高。
- 如果继续使用 TOML,建议把生产密钥放到 `app.ai.toml` 或外部环境变量,不要直接把敏感值写死在默认 `app.toml`
## 3. 必备环境变量 / 配置项
### 3.1 基础服务配置
来自 `fastapi_admin/config/_settings.py`
- `APP_HOST`
- `APP_PORT`
- `JWT_SECRET_KEY`
- `DB_HOST`
- `DB_PORT`
- `DB_NAME`
- `DB_USER`
- `DB_PASSWORD`
- `REDIS_HOST`
- `REDIS_PORT`
- `REDIS_DB`
- `REDIS_PASSWORD`
- `OSS_ENDPOINT`
- `OSS_BASE_URL`
- `OSS_ACCESS_KEY`
- `OSS_SECRET_KEY`
- `OSS_BUCKET`
### 3.2 RAG / LLM 配置
来自 `fastapi_modules/fastapi_leaudit/rag_engine/config.py`
- `LLM_BASE_URL`
- `LLM_MODEL`
- `LLM_API_KEY`
- `RAG_LLM_TEMPERATURE`
- `RAG_LLM_MAX_TOKENS`
- `RAG_LLM_TIMEOUT`
### 3.3 Chroma 配置
二选一:
- 远程 Chroma
- `RAG_CHROMA_HOST`
- `RAG_CHROMA_PORT`
- `RAG_CHROMA_TOKEN`(如有鉴权)
- `RAG_CHROMA_AUTH_HEADER`(默认 `X-Chroma-Token`
- 本地持久化 Chroma
- `RAG_CHROMA_PERSIST_DIR`
说明:
- 如果不配置 `RAG_CHROMA_HOST`,代码会走本地 `PersistentClient`
- 如果 Chroma 依赖缺失或不可用,服务能启动,但检索会退化成“无上下文回答”。
### 3.4 可选检索参数
- `RAG_VECTOR_TOP_K`
- `RAG_RERANK_TOP_K`
- `RAG_BM25_TOP_K`
- `RAG_RRF_K`
- `RAG_QUERY_REWRITING`
- `RAG_HYBRID_SEARCH`
- `RAG_RERANKING`
- `RAG_EMBED_URL`
- `RAG_EMBED_KEY`
- `RAG_EMBED_MODEL`
- `RAG_EMBED_DIM`
- `RAG_EMBED_BATCH_SIZE`
- `RAG_RERANKER_URL`
- `RAG_RERANKER_KEY`
- `RAG_RERANKER_MODEL`
说明:
- 当前聊天主流程已经能工作;即使没有完整 embedding/reranker 配置,只要现有 Chroma 集合可用,也可以先上线基础聊天。
- 更细的召回参数也可以放在 `rag_dataset.retrieval_model` 里按知识库配置。
## 4. 依赖安装
### 4.1 Python 依赖
本次新增依赖:
- `chromadb>=0.5.23`
如果线上使用虚拟环境:
```bash
source .venv/bin/activate
pip install -e .
```
如果只补增量依赖:
```bash
source .venv/bin/activate
pip install chromadb
```
建议最终仍执行一次完整依赖同步,避免环境漂移。
## 5. 数据库执行顺序
### 5.1 先执行结构脚本
```bash
psql -v ON_ERROR_STOP=1 \
-h <DB_HOST> -p <DB_PORT> -U <DB_USER> -d <DB_NAME> \
-f scripts/schema_add_rag_chat.sql
```
作用:
- 创建 `rag_dataset / rag_document / rag_chat_app / rag_conversation / rag_message`
- 对已存在表补字段、补索引、补 `updated_at` 触发器
### 5.2 再执行权限种子
```bash
psql -v ON_ERROR_STOP=1 \
-h <DB_HOST> -p <DB_PORT> -U <DB_USER> -d <DB_NAME> \
-f scripts/user_rbac_seed.sql
```
作用:
-`rag:*` 权限
- 补角色授权
- 同步需要的菜单/路由元数据
### 5.3 当前已验证结果
本地已在目标库执行并验证:
- 已存在 5 张 `rag_*`
- 已存在 7 条 `rag:*` 权限
- `super_admin / provincial_admin / admin / common` 均已获得这 7 条权限
## 6. 重启顺序
推荐顺序如下。
### 步骤 1:停 Celery worker
如果当前有 worker 在跑,先停掉,避免旧代码消费任务:
```bash
pkill -f "celery.*fastapi_admin.celery_app:celery_app" || true
```
如果你们线上是用进程管理器托管 worker,则用对应管理命令停止。
### 步骤 2:更新代码并安装依赖
```bash
git pull
source .venv/bin/activate
pip install -e .
```
### 步骤 3:执行数据库脚本
按“第 5 节”的先后顺序执行:
1. `scripts/schema_add_rag_chat.sql`
2. `scripts/user_rbac_seed.sql`
### 步骤 4:重启 FastAPI 主服务
如果用 `uvicorn` 直接启动,参考 `run.py`
```bash
source .venv/bin/activate
python run.py
```
如果线上不是 `reload=True` 的开发模式,建议使用你们现有的生产启动命令重启主进程,不要直接照抄开发命令。
### 步骤 5:重启 Celery worker
仓库已提供脚本 `scripts/start_worker.sh`
```bash
./scripts/start_worker.sh
```
它会自动读取:
- `LEAUDIT_WORKER_CONCURRENCY`
- `LEAUDIT_WORKER_QUEUE_URGENT`
- `LEAUDIT_WORKER_QUEUE_NORMAL`
### 步骤 6:如有反向代理,再做一次健康检查
- Nginx / 网关 upstream 是否恢复
- 80/443 -> FastAPI upstream 是否正常
## 7. 上线后验证
### 7.1 代码级快速检查
```bash
python -m compileall fastapi_modules/fastapi_leaudit
```
### 7.2 路由检查
已知应存在 10 条 `/v3/rag` 路由:
- `GET /api/v3/rag/apps`
- `GET /api/v3/rag/apps/default`
- `GET /api/v3/rag/datasets/my`
- `GET /api/v3/rag/chat/parameters`
- `POST /api/v3/rag/chat/messages`
- `GET /api/v3/rag/chat/conversations`
- `GET /api/v3/rag/chat/conversations/{ConversationId}/messages`
- `PATCH /api/v3/rag/chat/conversations/{ConversationId}`
- `DELETE /api/v3/rag/chat/conversations/{ConversationId}`
- `POST /api/v3/rag/chat/messages/{MessageId}/feedback`
### 7.3 数据库检查
```sql
SELECT tablename
FROM pg_tables
WHERE schemaname = 'public' AND tablename LIKE 'rag_%'
ORDER BY tablename;
```
```sql
SELECT count(*)
FROM permissions
WHERE permission_key LIKE 'rag:%';
```
```sql
SELECT r.role_key, count(*)
FROM role_permissions rp
JOIN roles r ON r.id = rp.role_id
JOIN permissions p ON p.id = rp.permission_id
WHERE p.permission_key LIKE 'rag:%'
GROUP BY r.role_key
ORDER BY r.role_key;
```
### 7.4 接口联通检查
至少验证这 4 个接口:
1. `GET /api/v3/rag/apps`
2. `GET /api/v3/rag/apps/default`
3. `GET /api/v3/rag/chat/parameters`
4. `POST /api/v3/rag/chat/messages`
关注点:
- 401JWT 或登录态异常
- 403`rag:*` 权限未生效
- 404:控制器未注册 / 网关路径未转发
- 500LLM、Chroma、数据库连接或 JSON 字段异常
## 8. 常见风险
- `chromadb` 未安装:服务启动不一定报错,但首次检索时会退化
- Chroma 集合为空:可以聊天,但没有知识库上下文
- `LLM_BASE_URL / LLM_API_KEY / LLM_MODEL` 配错:流式对话会直接失败
- 只执行权限脚本、不执行结构脚本:接口可能启动,但落库时报错
- 只重启 API、不重启 worker:后台异步任务仍可能跑旧代码
## 9. 建议的最短上线动作
按最快可落地顺序:
1. 备份数据库
2. `git pull`
3. `source .venv/bin/activate && pip install -e .`
4. 执行 `scripts/schema_add_rag_chat.sql`
5. 执行 `scripts/user_rbac_seed.sql`
6. 重启 FastAPI 主服务
7. 重启 `scripts/start_worker.sh`
8. 验证 `/api/v3/rag/apps``/api/v3/rag/chat/messages`
@@ -0,0 +1,852 @@
# 团队 Git 协作完整规范
> 适用对象:个人项目、小项目、大项目
> 版本:v1.0 · 2026-05-07
---
## 一、核心原则
不论团队规模大小,所有 Git 协作都遵守以下 5 条铁律:
1. **主干(main)永远可发布**
2. **凡是会影响他人的操作,事前通知、事中可见、事后可恢复**
3. **分支属于"任务",不属于"人"**(详见第六章)
4. **推送前先同步**`git pull --rebase` 后再 `git push`
5. **重要分支禁止直接 push,必须走 PR**
---
## 二、如何选择工作流
### 决策树
```
你一个人做这个项目吗?
├─ 是 → 【方案 A】个人极简流
└─ 否 → 团队 ≥ 6 人 或 同时维护多版本?
├─ 是 → 【方案 C】Git Flow Lite(带 develop
└─ 否 → 【方案 B】GitHub Flow90% 小项目适用)
```
### 三种方案对比
| 维度 | A·个人 | B·小项目 | C·大项目 |
|------|--------|---------|---------|
| 团队规模 | 1 人 | 2-5 人 | 6+ 人 |
| 主分支 | main | main | main + develop |
| 是否需 develop | ❌ | ❌ | ✅ |
| 是否需 release 分支 | ❌ | ❌ | ✅(可选) |
| 是否需 hotfix 分支 | ❌ | ✅ | ✅ |
| 部署策略 | 手动 / tag | 持续部署 | 阶段部署 |
| 发布周期 | 不固定 | 随时 | 双周 / 月度 |
| PR Review | 自看 | ≥1 人 | ≥2 人 |
| 复杂度 | ★ | ★★ | ★★★★ |
### 升级信号
**A → B**:第二个人加入,立刻配 main 保护 + PR 流程。
**B → C**:满足以下任一即升级
- 同时维护多个版本(v1 还在用,v2 在开发)
- 有专门 QA 阶段,main 不能合并即上线
- 发布周期 ≥ 2 周
- 团队 ≥ 6 人
> ⚠️ **宁可滞后升级,也不要预防性复杂化**。多数团队过度设计,把简单事搞复杂。
---
## 三、方案 A:个人项目工作流
### 分支模型
```
main (主线 + 发布锚点)
└─ feature/* (按需,仅用于实验性大改动)
```
### 日常工作流
**小改动 → 直接上 main**
```bash
git add .
git commit -m "fix: 修复登录按钮样式"
git push
```
**大改动 / 不确定的实验 → 开分支保命**
```bash
git checkout -b feature/重构数据层
# ...开发...
# 没问题 → 合并
git checkout main
git merge --no-ff feature/重构数据层
git push
git branch -d feature/重构数据层
# 实验失败 → 直接丢弃
git checkout main
git branch -D feature/重构数据层
```
### 发布流程
```bash
git tag -a v1.2.0 -m "release: v1.2.0 - 评查详情页上线"
git push --tags
```
**版本号遵循 [SemVer](https://semver.org/)**
- `v主版本.次版本.补丁`
- 主版本:不兼容改动
- 次版本:新功能(向下兼容)
- 补丁:bug 修复
### 个人项目最低纪律
| 习惯 | 价值 |
|------|------|
| 每天 push 到远程 | 硬盘坏了不丢工 |
| commit 信息写人话 | 半年后能看懂 |
| 重大改动前打 tag | 有回滚锚点 |
| README 记录关键决策 | 时间久了不抓瞎 |
| `.gitignore` 配齐 | 不把密钥推上去 |
### 不要做的事
-`git commit -m "update"` / `"修改"` / `"123"`
- ❌ 一周不 push
- ❌ 在 main 上做不确定的实验
- ❌ 把 `.env` 推到远程
---
## 四、方案 B:小项目工作流(GitHub Flow
**适用:2-5 人,持续部署**
### 分支模型
```
main (受保护,PR 合并,自动部署到生产)
├─ feature/评查详情页
├─ fix/登录闪退
└─ hotfix/支付失败 (紧急修生产)
```
**核心思想**
- main 永远可发布
- feature 分支**生命周期短**(1-3 天最佳,最长 1 周)
- 所有改动走 PR
### 日常工作流(每个任务都按这个跑)
```bash
# 1. 开分支前先同步 main
git checkout main
git pull --rebase
# 2. 创建任务分支(任务命名,不要带人名)
git checkout -b feature/评查详情页
# 3. 开发,频繁小步提交,频繁推送
git add .
git commit -m "feat(评查): 新增详情页骨架"
git push -u origin feature/评查详情页
# 4. 推送前同步 main,避免冲突堆积
git fetch origin
git rebase origin/main
# 解决冲突 → 本地测试通过
# 5. 推送(rebase 后需要 force-with-lease
git push --force-with-lease
# 6. 提 PR → Review → 合并 → 自动部署
# 7. 合并后清理本地
git checkout main
git pull
git branch -d feature/评查详情页
```
### PR 流程规范
**提 PR 时**
- 标题:`<type>(<scope>): <简短描述>`,例:`feat(评查): 新增详情页`
- 描述模板:
```markdown
## 改动内容
- ...
## 测试方法
- ...
## 截图(如有 UI 改动)
## 关联 Issue
Closes #123
```
- 自检:lint 通过、测试通过、不含调试代码
**Review 时**
- 24 小时内响应
- 给具体可操作的反馈,不要"建议优化一下"
- Approve 前自己心里跑一遍代码逻辑
### 紧急修复(hotfix
```bash
git checkout main && git pull
git checkout -b hotfix/支付失败
# 修 → 测 → push → PR → 紧急合并 → 立即部署
```
### 仓库一次性配置(落地关键)
**main 分支保护(GitHub/GitLab 后台)**
- ✅ 禁止直接 push
- ✅ 禁止 force push
- ✅ 必须 PR + ≥1 Approve
- ✅ 必须通过 CIlint + test
- ✅ 合并后自动删除分支
---
## 五、方案 C:大项目工作流(Git Flow Lite
**适用:6+ 人 / 多版本并存 / 有 QA 测试期**
### 分支模型
```
main (生产版本,受保护,只接受来自 release/hotfix 的合并)
└─ develop (开发主线,受保护,所有 feature 合并到这里)
├─ feature/评查详情页 (个人功能分支)
├─ feature/登录优化
├─ release/v2.3.0 (准备发布的快照分支)
└─ hotfix/支付失败 (从 main 拉,修完合并回 main + develop)
```
### 各分支角色
| 分支 | 来源 | 合并去向 | 生命周期 |
|------|------|---------|---------|
| `main` | 永久 | — | 永久 |
| `develop` | 永久 | — | 永久 |
| `feature/*` | develop | develop | 任务期 |
| `release/*` | develop | main + develop | 发布周期 |
| `hotfix/*` | main | main + develop | 紧急修复 |
### develop 的角色
- **开发主线**:所有 feature 合并到 develop
- **集成测试环境**QA 在 develop 上测试
- **不直接发布**:发布前从 develop 拉 release 分支封板
### release 分支:发布前的"封板"
```bash
# 1. 从 develop 拉 release 分支(功能冻结)
git checkout develop && git pull
git checkout -b release/v2.3.0
# 2. 在 release 上只修 bug,不加新功能
# QA 测试 → 修 bug → 改版本号 → 写 changelog
# 3. 测试通过,合并到 main 并打 tag
git checkout main && git pull
git merge --no-ff release/v2.3.0
git tag -a v2.3.0 -m "release: v2.3.0"
git push --tags
# 4. 合并回 develop(带上 release 上的 bug 修复)
git checkout develop
git merge --no-ff release/v2.3.0
git push
# 5. 删除 release 分支
git branch -d release/v2.3.0
```
### hotfix 分支:紧急修生产
```bash
# 1. 从 main 拉 hotfix 分支
git checkout main && git pull
git checkout -b hotfix/支付失败
# 2. 修 → 测 → 提 PR
# 3. 合并到 main 并打 patch tag
git checkout main
git merge --no-ff hotfix/支付失败
git tag -a v2.3.1 -m "hotfix: 修复支付失败"
git push --tags
# 4. 必须合并回 develop!否则下次发布 bug 复发
git checkout develop
git merge --no-ff hotfix/支付失败
git push
# 5. 删除 hotfix 分支
git branch -d hotfix/支付失败
```
### 日常 feature 工作流
```bash
# 从 develop(不是 main!)开分支
git checkout develop && git pull --rebase
git checkout -b feature/评查详情页
# 开发 → 推送 → PR 到 develop(不是 main!)
git push -u origin feature/评查详情页
# 提 PRfeature/评查详情页 → develop
```
### 大项目仓库配置
- **main**:禁止 push、禁止 force push、只接受 release/hotfix 合并、必须 ≥2 Approve
- **develop**:禁止 push、必须 PR + ≥1 Approve、必须通过 CI
- **CI 要求**lint + 单元测试 + 集成测试 + 静态分析
---
## 六、为什么禁止使用个人分支【专题】
### 反模式(团队中常见错误)
```
❌ feature/评查详情页-zhangsan
❌ zhangsan-dev
❌ feature/zhangsan/xxx
❌ 张三的分支
❌ wy-dev / wy-test
```
### 5 大问题
#### 1️⃣ 强化"个人所有权",破坏协作精神
分支带人名 → 同事潜意识"这是张三的地盘,我别动" → 协作变独行 → 出问题没人帮看。
**好的协作是任务驱动**:分支属于任务,谁有空谁接手。
#### 2️⃣ 离职、休假、轮岗时难交接
**真实场景**
> 张三休假一周,留下 5 条 `feature/xxx-zhangsan` 分支。李四接手时是改名(影响远程)、还是新开 `feature/xxx-lisi`(造成分裂)?怎么处理都别扭。
如果分支叫 `feature/评查详情页`,李四直接 `git checkout` 接着干,**零摩擦**。
#### 3️⃣ 分支语义模糊,看名字不知道做什么
`zhangsan-dev` 这条分支在做啥?
- 评查模块?
- 登录优化?
- 性能调优?
- 还是张三的"我啥都往这塞"草稿?
**好的分支名 = 一句话任务说明**,看到 `feature/评查详情页` 立刻明白。
#### 4️⃣ 容易堆积成"杂物分支"
人名分支没有边界,张三会把"评查详情页 + 顺手优化的登录 + 试验性能改动"都塞进 `feature/zhangsan-dev`。结果:
- PR 改动巨大,没人能 Review
- 一个 bug 拖延了三个功能
- 不能单独 revert 某项改动
**任务分支天然有边界**`feature/评查详情页` 只装评查相关改动,超出范围就该开新分支。
#### 5️⃣ 多人协作同一功能时命名混乱
**真实场景**
> 评查详情页很大,张三李四王五一起做。分支会变成:
> - `feature/评查详情页-zhangsan`
> - `feature/评查详情页-lisi`
> - `feature/评查详情页-wangwu`
>
> 三人改动如何同步?合并顺序?谁先合谁后合?混乱。
**正确做法**:开一条父分支 `feature/评查详情页`,每人开**子任务分支**
- `feature/评查详情页-头部`
- `feature/评查详情页-列表`
- `feature/评查详情页-筛选`
子任务都合并回父分支,最后父分支整体合到 develop。
---
### 真实案例:人名分支造成的事故
**案例 1:交接黑洞**
> 某团队张三离职前留下 `zhangsan/refactor-payment` 分支,里面有他重构支付的工作(约 60% 完成)。半年后团队想接着做,发现:分支与 main 已差异巨大,无法 rebase;分支内 commit 信息全是"WIP",没人知道每个 commit 在做什么;最终只能放弃,**重做**。
**案例 2:紧急修复无法落地**
> 周五晚上生产支付功能挂了。值班发现修复需要改一个文件,但该文件在 `feature/支付重构-zhangsan` 分支上张三已改了一周。要么强行修生产(与张三的分支冲突会变大),要么等张三周一来。最终用了一个肮脏的 hotfix,**技术债累计**。
**案例 3PR Review 无人能审**
> `feature/zhangsan-dev` 一个 PR 改了 2000 行,包含评查、登录、列表、性能 4 个不相关的改动。Review 同事看了一上午放弃,盖章通过。两天后线上 bug,**无法定位是哪个改动引起的**。
---
### 正确做法
#### ✅ 任务命名规范
```
feature/<任务描述> feature/评查详情页
feature/<issue号>-<描述> feature/PROJ-123-评查详情页
fix/<bug简述> fix/登录闪退
hotfix/<紧急bug> hotfix/支付失败
refactor/<范围> refactor/数据层
```
#### ✅ 任务归属体现在 PR/Issue Assignee
谁负责这个任务 → 在 **PR/Issue 的 Assignee** 字段标记,不要污染分支名。
#### ✅ 分支只与「任务/目标」关联
看到 `feature/评查详情页` 应当能立刻回答:
- 这条分支在做什么
- 合并目标是什么
- 何时该删除
---
### 例外:可以带人名的场景
**仅限以下短期、可丢弃的情况**
#### 1. 个人探索/草稿分支(明确不打算合并)
```
zhangsan/试个性能方案
zhangsan/sandbox
```
用斜线作为"个人 sandbox 命名空间"前缀,与正式 feature 分支区分。
#### 2. Fork 工作流(开源项目常见)
你 fork 仓库到自己账号后,分支名随意,提 PR 时再说。这是**远程 fork 模式**,不属于"单仓库协作"场景。
#### 3. 多人并行试方案的临时区分
```
feature/评查详情页/方案A-zhangsan
feature/评查详情页/方案B-lisi
```
验证完保留赢的方案,删除全部分支,重命名为正式分支。
> **核心:这些场景都是短期、明确不污染主流分支的。**
---
## 七、通用规范
### 分支命名
```
<type>/<description>
<type>/<issue-id>-<description>
```
**type 类型**
- `feature/` 新功能
- `fix/` bug 修复
- `hotfix/` 紧急修复(生产)
- `refactor/` 重构
- `docs/` 文档
- `test/` 测试
- `chore/` 杂项(依赖升级、配置)
- `release/` 发布分支(仅 Git Flow
**示例**
```
feature/评查详情页
feature/PROJ-123-评查详情页
fix/登录闪退
hotfix/v2.3-支付失败
```
**禁止**
- ❌ 人名前缀/后缀
- ❌ 拼音缩写如 `wy-dev`
- ❌ 没有 type 前缀
- ❌ 空格、特殊字符
### 提交信息(Conventional Commits
```
<type>(<scope>): <简短描述>
<可选详细说明>
<可选 footer>
```
**type**
- `feat:` 新功能
- `fix:` 修 bug
- `refactor:` 重构(不改外部行为)
- `perf:` 性能优化
- `test:` 测试
- `docs:` 文档
- `style:` 格式(不改代码逻辑)
- `chore:` 杂项
- `build:` 构建相关
- `ci:` CI 相关
**示例**
```
feat(评查): 新增详情页骨架屏
- 添加加载占位组件
- 实现进入动画
- 适配移动端
Closes #123
```
**禁止**
- ❌ `update`、`fix`、`修改`、`123`
- ❌ 一个 commit 改 N 个不相关的事
- ❌ `WIP`(合并前应 squash 掉)
### 标签(Tag)规范
**版本标签**遵循 [SemVer](https://semver.org/)
```
v1.2.3 正式版
v1.2.3-beta.1 beta 版
v1.2.3-rc.1 发布候选版
```
**打 tag 时机**
- 个人项目:每次发布
- 小项目:每次部署到生产
- 大项目:release 合并到 main 时
### .gitignore 通用模板
```gitignore
# 依赖
node_modules/
__pycache__/
*.pyc
venv/
.venv/
# 环境变量(永远不要提交)
.env
.env.*
!.env.example
# 编辑器
.vscode/
.idea/
*.swp
.DS_Store
# 构建产物
dist/
build/
*.log
coverage/
# 本地配置
.cache/
*.local
```
---
## 八、共享资源协作守则
### 通用原则
> **凡是会影响他人的操作,事前通知、事中可见、事后可恢复。**
### 共享资源守则表
| 共享资源 | 守则 |
|---------|------|
| 共享开发/测试机 | 默认主分支;切换通知;用完还原;优先 `git worktree` |
| 共享数据库 | 不在共用库做破坏性改动;每人独立 schema;测试用 docker 起本地 |
| 共享 API Key / Secret | 用 secret manager;禁止贴 IM/代码/截图 |
| CI/CD pipeline | 改流水线前通知;不在大家忙时触发昂贵任务 |
| 第三方账号 | SSO + 审计;操作记录可追溯 |
| 部署环境 | 部署窗口公告;锁机制(谁部署谁举手) |
### 切换共享资源的标准动作
```
1. 群里通知:"我要 [操作] [资源],预计 [时间]"
2. 操作
3. 用完恢复默认状态
4. 群里告知:"已恢复"
```
### 优先用隔离手段,而不是切换
```bash
# git worktree:在不同目录跑不同分支,主目录不动
git worktree add ../preview-xxx feature/xxx
git worktree remove ../preview-xxx
# Docker:每个分支起独立容器
docker compose -p preview-xxx up
```
### 终极方案:消除"共享"本身
- 每个 PR 自动起一个独立预览环境(Vercel / Netlify / K8s preview
- 每人独立数据库 schema(自动迁移)
- 每人独立云资源(云厂商沙盒账号)
> **根本不需要"共享调试机"。**
---
## 九、常见问题 FAQ
### Q1:合并前应该用 merge 还是 rebase
| 场景 | 推荐 |
|------|------|
| 个人 feature 分支同步 main | `git rebase`(历史干净) |
| 多人协作的分支 | `git merge`(不重写他人 commit |
| 合并 PR 到 main | **Squash and merge**main 历史干净) |
| 已推送的分支 | 谨慎使用 rebase,需 `--force-with-lease` |
### Q2feature 分支多久合并一次?
- **理想**1-3 天
- **可接受**1 周
- **超过 1 周必须警惕**:分支过大 → 拆分;同步频率提高(每天 rebase main
### Q3commit 太多太乱怎么办?
合并到主分支前 squash 整理:
```bash
git rebase -i HEAD~5
# 把第二个开始的 pick 改成 squash 或 fixup
```
或在 PR 合并时选择 **"Squash and merge"**。
### Q4:误推了敏感信息(密钥)怎么办?
1. **立即作废**这个密钥(去后台重新生成)
2. 用 `git filter-repo` 或 BFG 清除历史
3. **强制推送**所有分支
4. **通知所有人**重新 clone
预防:
- `.gitignore` 配齐 `.env`
- 用 secret manager
- 装 `git-secrets` / `gitleaks` pre-commit 钩子
### Q5rebase 时遇到冲突怎么办?
```bash
# 1. 解决冲突文件
# 2. git add <冲突文件>
# 3. git rebase --continue
# 实在搞不定就放弃
git rebase --abort
```
### Q6:误删了分支怎么恢复?
```bash
# 找到最后一次 commit
git reflog
# 恢复
git checkout -b feature/xxx <commit-sha>
```
### Q7`git push` 被拒(rejected
意味着远程分支有新 commit 你本地没有。
```bash
# 同步后再推
git pull --rebase
git push
# 如果是 rebase 后推自己的分支
git push --force-with-lease # 注意是 --force-with-lease,不是 --force
```
> ⚠️ **永远不要对 main / develop 用 `--force`**
### Q8:什么时候删分支?
- 合并到主干后**立即删除**远程和本地
- GitHub/GitLab 可设置"合并后自动删除"
- 本地:`git branch -d feature/xxx`
### Q9:长期废弃的分支能直接删吗?
先 `git log feature/xxx` 看是否有未合并 commit。若有:
- 询问作者是否还需要
- 或导出 patch`git format-patch main..feature/xxx`
### Q10Reviewer 检查清单
审视 PR 是否值得合并:
- [ ] 分支命名规范,无人名
- [ ] 改动只做一件事,与 PR 标题一致
- [ ] 提交信息规范
- [ ] 测试覆盖关键路径
- [ ] CI 全绿
- [ ] 无调试代码(console.log、注释掉的代码)
- [ ] 无敏感信息(API Key、密码)
- [ ] 文档/注释 同步更新
- [ ] 跑过本地测试
---
## 十、配套工具与一键配置
### 全员 Git 配置(每台机器跑一次)
```bash
# pull 默认 rebase(避免无意义 merge commit
git config --global pull.rebase true
# push 自动追踪上游
git config --global push.autoSetupRemote true
# rebase 自动 stash
git config --global rebase.autoStash true
# 默认分支名
git config --global init.defaultBranch main
# 换行符处理
git config --global core.autocrlf input # Mac/Linux
git config --global core.autocrlf true # Windows
```
### 推荐工具
| 类型 | 工具 | 作用 |
|------|------|------|
| 提交检查 | husky + lint-staged | commit 前自动跑 lint/format |
| 提交规范 | commitlint | 强制 Conventional Commits |
| 密钥扫描 | gitleaks / git-secrets | 防止推送密钥 |
| 图形化客户端 | Fork / SourceTree / GitKraken | 新人友好 |
| CLI 增强 | gh / lazygit | 命令行高效操作 |
| CI/CD | GitHub Actions / GitLab CI | 自动测试和部署 |
| PR 预览 | Vercel / Netlify | 每 PR 一个独立环境 |
### 一键安装 husky + lint-staged + commitlintNode 项目)
```bash
bun add -D husky lint-staged @commitlint/cli @commitlint/config-conventional
# 初始化 husky
bunx husky init
# 配置 commitlint
echo "export default { extends: ['@commitlint/config-conventional'] }" > commitlint.config.mjs
# 添加 hooks
echo "bunx commitlint --edit \$1" > .husky/commit-msg
echo "bunx lint-staged" > .husky/pre-commit
```
`package.json` 添加:
```json
{
"lint-staged": {
"*.{js,ts,tsx}": ["eslint --fix", "prettier --write"]
}
}
```
---
## 附录:决策速查表
### 我该开什么类型的分支?
| 我要做的事 | 分支前缀 | 例子 |
|----------|---------|------|
| 新功能 | `feature/` | `feature/评查详情页` |
| 修 bug | `fix/` | `fix/登录闪退` |
| 紧急修生产 | `hotfix/` | `hotfix/支付失败` |
| 重构 | `refactor/` | `refactor/数据层` |
| 写文档 | `docs/` | `docs/api文档` |
| 升级依赖 | `chore/` | `chore/升级react18` |
### 我该写什么 commit type
| 我做了什么 | type |
|----------|------|
| 写了新功能 | `feat` |
| 修 bug | `fix` |
| 重构(不改行为) | `refactor` |
| 性能优化 | `perf` |
| 改文档 | `docs` |
| 改格式(空格、缩进) | `style` |
| 加测试 | `test` |
| 杂项 | `chore` |
### 我该用哪个工作流?
```
1 人 → 方案 Amain + 偶尔 feature
2-5 人 → 方案 BGitHub Flowmain + feature + PR
6+ 人 / 多版本 → 方案 CGit Flow Litemain + develop + ...
```
---
## 附录:一页纸速查(打印贴墙)
```
┌─────────────────────────────────────────────────────────┐
│ 团队 Git 协作 · 一页纸速查 │
├─────────────────────────────────────────────────────────┤
│ 1. 永远从最新主干开任务分支 │
│ git checkout main && git pull --rebase │
│ git checkout -b feature/任务描述 │
│ │
│ 2. 分支命名 = 任务,不带人名! │
│ ✅ feature/评查详情页 │
│ ❌ feature/评查详情页-zhangsan │
│ │
│ 3. commit 写人话 │
│ ✅ feat(评查): 新增详情页骨架 │
│ ❌ update │
│ │
│ 4. 推送前先同步 │
│ git fetch && git rebase origin/main │
│ │
│ 5. 主分支 = PR 入口,禁止直推 │
│ │
│ 6. 共享资源 = 通知 → 操作 → 还原 → 告知 │
│ │
│ 7. 永远不对 main/develop --force │
│ │
│ 8. 合并后立刻删分支 │
└─────────────────────────────────────────────────────────┘
```
---
+493
View File
@@ -0,0 +1,493 @@
# RAG 聊天接口
> 最后整理:2026-05-07
> 对应后端:`fastapi_modules/fastapi_leaudit/controllers/ragChatController.py`
> 统一前缀:`/api/v3/rag`
## 1. 目标与范围
本组接口用于替代旧的 `dify_chat/*` 对话代理,直接提供自有 RAG 聊天能力。
当前已落地能力:
- 获取当前用户可见的 RAG 应用
- 获取默认 RAG 应用
- 获取当前用户可见知识库
- 获取聊天页面参数
- 发起流式对话
- 查询会话列表
- 查询会话消息
- 重命名会话
- 删除会话
- 消息反馈
当前不在本文档范围内:
- 知识库 CRUD 管理
- 文档切分 / 入库任务
- Chroma 集合构建脚本
## 2. 鉴权与权限
### 2.1 鉴权方式
所有接口都要求请求头带:
```http
Authorization: Bearer <access_token>
```
JWT 解析逻辑见:
- `fastapi_common/fastapi_common_security/security.py`
- `fastapi_common/fastapi_common_security/jwtService.py`
JWT payload 至少会被后端消费这些字段:
- `user_id`
- `username`
- `area`
- `user_role`
- `type`,必须为 `access`
### 2.2 权限键
| 接口 | 权限 |
|------|------|
| `GET /api/v3/rag/apps` | `rag:app:read` |
| `GET /api/v3/rag/apps/default` | `rag:app:read` |
| `GET /api/v3/rag/datasets/my` | `rag:dataset:read` |
| `GET /api/v3/rag/chat/parameters` | `rag:chat:use``rag:app:read` 其一即可 |
| `POST /api/v3/rag/chat/messages` | `rag:chat:use` |
| `GET /api/v3/rag/chat/conversations` | `rag:conversation:read` |
| `GET /api/v3/rag/chat/conversations/{ConversationId}/messages` | `rag:conversation:read` |
| `PATCH /api/v3/rag/chat/conversations/{ConversationId}` | `rag:conversation:update` |
| `DELETE /api/v3/rag/chat/conversations/{ConversationId}` | `rag:conversation:delete` |
| `POST /api/v3/rag/chat/messages/{MessageId}/feedback` | `rag:message:feedback` |
说明:
- 权限检查使用 `HasAnyPermission`,即“列表中的任一权限命中即可通过”。
- 具体实现见 `fastapi_modules/fastapi_leaudit/services/impl/permissionServiceImpl.py`
## 3. 通用返回格式
除流式接口外,统一返回:
```json
{
"code": 200,
"msg": "success",
"data": {}
}
```
权限不足时通常返回:
```json
{
"code": 403,
"msg": "当前用户没有对应权限",
"data": null
}
```
## 4. 接口列表
### 4.1 获取可见应用列表
`GET /api/v3/rag/apps`
用途:
- 聊天页面加载应用下拉
- 根据地区 / 省级角色做应用可见性过滤
请求参数:无
成功响应示例:
```json
{
"code": 200,
"msg": "success",
"data": {
"data": [
{
"appId": "1",
"appName": "法务问答",
"description": "默认烟草法务知识问答",
"isDefault": true
}
],
"total": 1
}
}
```
可见性规则:
- `provincial_admin` 可见全部启用应用
- 其他角色仅可见:
- `rag_chat_app.area = 用户 area`
- `rag_chat_app.area = '省级'`
- `rag_chat_app.area = ''`
- 或关联数据集 `rag_dataset.is_public = true`
### 4.2 获取默认应用
`GET /api/v3/rag/apps/default`
用途:
- 聊天页初始化默认应用
请求参数:无
成功响应示例:
```json
{
"code": 200,
"msg": "success",
"data": {
"appId": "1",
"appName": "法务问答",
"description": "默认烟草法务知识问答",
"isDefault": true
}
}
```
补充说明:
- 如果没有显式默认应用,会退回到当前用户可见的第一条应用。
- 如果完全没有可见应用,返回 `data: null`
### 4.3 获取当前用户可见知识库
`GET /api/v3/rag/datasets/my`
用途:
- 聊天页展示“当前可用知识库”时使用
请求参数:无
成功响应示例:
```json
{
"code": 200,
"msg": "success",
"data": {
"data": [
{
"id": 1,
"name": "广东烟草法规库",
"description": "省级法规与制度",
"area": "省级",
"isPublic": true,
"isDefault": true,
"documentCount": 120,
"totalChunks": 8345,
"status": 1
}
],
"total": 1
}
}
```
### 4.4 获取聊天参数
`GET /api/v3/rag/chat/parameters`
查询参数:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `appId` | int | 否 | 指定应用 ID;不传则取默认应用 |
用途:
- 初始化开场白
- 初始化建议问题
- 初始化上传能力配置
成功响应示例:
```json
{
"code": 200,
"msg": "success",
"data": {
"openingStatement": "你好,我可以帮你解答烟草行业法务问题。",
"suggestedQuestions": [
"烟草专卖许可延续的法定条件是什么?",
"行政处罚文书审查重点有哪些?"
],
"userInputForm": [],
"fileUpload": {
"image": {
"enabled": false
}
}
}
}
```
### 4.5 发起流式对话
`POST /api/v3/rag/chat/messages`
请求体:
```json
{
"query": "烟草专卖许可证延续申请的审查要点是什么?",
"conversationId": null,
"appId": 1
}
```
字段说明:
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `query` | string | 是 | 用户问题,不能为空 |
| `conversationId` | string \| null | 否 | 会话 ID;新对话可传 `null` 或不传 |
| `appId` | int \| null | 否 | 应用 ID;不传则自动回退默认应用 |
返回类型:
- `text/event-stream`
SSE 事件 1:流式正文片段
```text
data: {"event":"message","task_id":"...","message_id":"...","conversation_id":"...","answer":"第一段内容","created_at":1746580000}
```
SSE 事件 2:流式结束
```text
data: {"event":"message_end","task_id":"...","message_id":"...","conversation_id":"...","metadata":{"usage":{"total_tokens":1234},"retriever_resources":[...],"suggested_questions":["问题1","问题2"]}}
```
SSE 事件 3:模型异常
```text
data: {"event":"error","task_id":"...","message_id":"...","code":"llm_error","message":"..."}
```
服务端行为说明:
-`conversationId` 为空,会自动创建新会话
- 会先落一条 `role = user` 消息,再流式生成回答
- 流结束后会落一条 `role = assistant` 消息
- 若命中知识库,会把引用结果写入 `sources / metadata`
- 会根据对话内容追加 `suggested_questions`
### 4.6 获取会话列表
`GET /api/v3/rag/chat/conversations`
查询参数:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| `appId` | int | 否 | - | 按应用过滤 |
| `page` | int | 否 | `1` | 页码,从 1 开始 |
| `pageSize` | int | 否 | `20` | 每页数量,最大 100 |
成功响应示例:
```json
{
"code": 200,
"msg": "success",
"data": {
"data": [
{
"id": "b17d3b0b-xxxx-xxxx",
"name": "新对话",
"introduction": "",
"createdAt": 1746580000,
"updatedAt": 1746580066
}
],
"hasMore": false,
"limit": 20
}
}
```
### 4.7 获取会话消息
`GET /api/v3/rag/chat/conversations/{ConversationId}/messages`
路径参数:
| 参数 | 类型 | 说明 |
|------|------|------|
| `ConversationId` | string | 会话 ID |
查询参数:
| 参数 | 类型 | 必填 | 默认值 |
|------|------|------|--------|
| `page` | int | 否 | `1` |
| `pageSize` | int | 否 | `20` |
成功响应示例:
```json
{
"code": 200,
"msg": "success",
"data": {
"data": [
{
"id": "assistant-message-id",
"conversationId": "b17d3b0b-xxxx-xxxx",
"query": "烟草专卖许可证延续申请的审查要点是什么?",
"answer": "先核对主体资格,再核对经营条件……",
"feedback": {
"rating": "like"
},
"retrieverResources": [
{
"position": 1,
"dataset_id": "1",
"dataset_name": "广东烟草法规库",
"document_id": "12",
"document_name": "行政许可审查规范.pdf",
"segment_id": "chunk-1",
"score": 0.9132
}
],
"createdAt": 1746580000
}
],
"hasMore": false,
"limit": 20
}
}
```
说明:
- 返回结构是按“问答对”聚合后的结果,不是底层 `rag_message` 原始逐条结果。
### 4.8 重命名会话
`PATCH /api/v3/rag/chat/conversations/{ConversationId}`
请求体:
```json
{
"name": "许可证延续审查要点"
}
```
成功响应示例:
```json
{
"code": 200,
"msg": "success",
"data": {
"result": "success",
"name": "许可证延续审查要点"
}
}
```
### 4.9 删除会话
`DELETE /api/v3/rag/chat/conversations/{ConversationId}`
成功响应示例:
```json
{
"code": 200,
"msg": "success",
"data": {
"result": "success"
}
}
```
说明:
- 逻辑删除,实际是设置 `rag_conversation.deleted_at`
### 4.10 消息反馈
`POST /api/v3/rag/chat/messages/{MessageId}/feedback`
请求体:
```json
{
"rating": "like"
}
```
可选值:
- `like`
- `dislike`
- `null`
成功响应示例:
```json
{
"code": 200,
"msg": "success",
"data": {
"result": "success"
}
}
```
## 5. 数据表对应关系
| 表 | 用途 |
|----|------|
| `rag_dataset` | 知识库定义、地区可见性、检索参数 |
| `rag_document` | 知识库文档、启停状态、命中次数 |
| `rag_chat_app` | 聊天应用配置、默认应用、应用绑定知识库 |
| `rag_conversation` | 用户会话 |
| `rag_message` | 底层消息落库,包含引用与反馈 |
## 6. 当前实现约束
- 当前只提供 `GET /datasets/my`,不提供知识库管理 CRUD
- `fileUpload.image.enabled` 固定为 `false`
- 检索依赖 Chroma;Chroma 不可用时,接口仍可回答,但会退化成无知识库上下文
- 建议问题 `suggestedQuestions` 由二次模型调用生成,失败时会降级为空数组
## 7. 联调建议
最小联调顺序:
1. `GET /api/v3/rag/apps`
2. `GET /api/v3/rag/apps/default`
3. `GET /api/v3/rag/chat/parameters`
4. `POST /api/v3/rag/chat/messages`
5. `GET /api/v3/rag/chat/conversations`
6. `GET /api/v3/rag/chat/conversations/{ConversationId}/messages`
优先检查:
- 401JWT 是否有效
- 403`rag:*` 权限是否已写入并分配
- 500LLM、数据库、Chroma、知识库配置是否可用
+1
View File
@@ -17,6 +17,7 @@
|------|------|------|
| 首页入口 / 菜单 | `入口模块绑定最终设计方案.md` | 入口模块、文档类型、规则链路绑定模型 |
| 文档上传 / 列表 / 评查 | `文档上传与列表接口分析.md` | 上传、列表、详情、更新、删除、评查触发、数据隔离 |
| RAG 聊天 | `RAG聊天接口.md` | `/api/v3/rag/*` 自有聊天接口、SSE、权限、表结构映射 |
| 文档类型 / 评查组 | `评查点分组目标结构与迁移方案.md` | 文档类型、一级分组、二级分组、规则集与迁移口径 |
| 评查点分组迁移 | `评查点分组目标结构与迁移方案.md` | 新老分组结构对齐方案 |
| 评查点分组迁移 | `评查点分组迁移执行前检查清单.md` | 正式迁移前检查项 |